Skip to content

Commit 24894bc

Browse files
committed
Merge branch 'neigh-get-support'
Roopa Prabhu says: ==================== neigh get support This series adds support for neigh get similar to route and recently added fdb get. v2: fix key len check. and some other fixes ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
2 parents 4ab0ede + 8deecf3 commit 24894bc

File tree

4 files changed

+248
-23
lines changed

4 files changed

+248
-23
lines changed

include/net/neighbour.h

+1
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,7 @@ static inline void *neighbour_priv(const struct neighbour *n)
255255
#define NEIGH_UPDATE_F_ISROUTER 0x40000000
256256
#define NEIGH_UPDATE_F_ADMIN 0x80000000
257257

258+
extern const struct nla_policy nda_policy[];
258259

259260
static inline bool neigh_key_eq16(const struct neighbour *n, const void *pkey)
260261
{

net/core/neighbour.c

+193-11
Original file line numberDiff line numberDiff line change
@@ -1751,6 +1751,18 @@ static struct neigh_table *neigh_find_table(int family)
17511751
return tbl;
17521752
}
17531753

1754+
const struct nla_policy nda_policy[NDA_MAX+1] = {
1755+
[NDA_DST] = { .type = NLA_BINARY, .len = MAX_ADDR_LEN },
1756+
[NDA_LLADDR] = { .type = NLA_BINARY, .len = MAX_ADDR_LEN },
1757+
[NDA_CACHEINFO] = { .len = sizeof(struct nda_cacheinfo) },
1758+
[NDA_PROBES] = { .type = NLA_U32 },
1759+
[NDA_VLAN] = { .type = NLA_U16 },
1760+
[NDA_PORT] = { .type = NLA_U16 },
1761+
[NDA_VNI] = { .type = NLA_U32 },
1762+
[NDA_IFINDEX] = { .type = NLA_U32 },
1763+
[NDA_MASTER] = { .type = NLA_U32 },
1764+
};
1765+
17541766
static int neigh_delete(struct sk_buff *skb, struct nlmsghdr *nlh,
17551767
struct netlink_ext_ack *extack)
17561768
{
@@ -2711,6 +2723,186 @@ static int neigh_dump_info(struct sk_buff *skb, struct netlink_callback *cb)
27112723
return skb->len;
27122724
}
27132725

2726+
static int neigh_valid_get_req(const struct nlmsghdr *nlh,
2727+
struct neigh_table **tbl,
2728+
void **dst, int *dev_idx, u8 *ndm_flags,
2729+
struct netlink_ext_ack *extack)
2730+
{
2731+
struct nlattr *tb[NDA_MAX + 1];
2732+
struct ndmsg *ndm;
2733+
int err, i;
2734+
2735+
if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(*ndm))) {
2736+
NL_SET_ERR_MSG(extack, "Invalid header for neighbor get request");
2737+
return -EINVAL;
2738+
}
2739+
2740+
ndm = nlmsg_data(nlh);
2741+
if (ndm->ndm_pad1 || ndm->ndm_pad2 || ndm->ndm_state ||
2742+
ndm->ndm_type) {
2743+
NL_SET_ERR_MSG(extack, "Invalid values in header for neighbor get request");
2744+
return -EINVAL;
2745+
}
2746+
2747+
if (ndm->ndm_flags & ~NTF_PROXY) {
2748+
NL_SET_ERR_MSG(extack, "Invalid flags in header for neighbor get request");
2749+
return -EINVAL;
2750+
}
2751+
2752+
err = nlmsg_parse_strict(nlh, sizeof(struct ndmsg), tb, NDA_MAX,
2753+
nda_policy, extack);
2754+
if (err < 0)
2755+
return err;
2756+
2757+
*ndm_flags = ndm->ndm_flags;
2758+
*dev_idx = ndm->ndm_ifindex;
2759+
*tbl = neigh_find_table(ndm->ndm_family);
2760+
if (*tbl == NULL) {
2761+
NL_SET_ERR_MSG(extack, "Unsupported family in header for neighbor get request");
2762+
return -EAFNOSUPPORT;
2763+
}
2764+
2765+
for (i = 0; i <= NDA_MAX; ++i) {
2766+
if (!tb[i])
2767+
continue;
2768+
2769+
switch (i) {
2770+
case NDA_DST:
2771+
if (nla_len(tb[i]) != (int)(*tbl)->key_len) {
2772+
NL_SET_ERR_MSG(extack, "Invalid network address in neighbor get request");
2773+
return -EINVAL;
2774+
}
2775+
*dst = nla_data(tb[i]);
2776+
break;
2777+
default:
2778+
NL_SET_ERR_MSG(extack, "Unsupported attribute in neighbor get request");
2779+
return -EINVAL;
2780+
}
2781+
}
2782+
2783+
return 0;
2784+
}
2785+
2786+
static inline size_t neigh_nlmsg_size(void)
2787+
{
2788+
return NLMSG_ALIGN(sizeof(struct ndmsg))
2789+
+ nla_total_size(MAX_ADDR_LEN) /* NDA_DST */
2790+
+ nla_total_size(MAX_ADDR_LEN) /* NDA_LLADDR */
2791+
+ nla_total_size(sizeof(struct nda_cacheinfo))
2792+
+ nla_total_size(4) /* NDA_PROBES */
2793+
+ nla_total_size(1); /* NDA_PROTOCOL */
2794+
}
2795+
2796+
static int neigh_get_reply(struct net *net, struct neighbour *neigh,
2797+
u32 pid, u32 seq)
2798+
{
2799+
struct sk_buff *skb;
2800+
int err = 0;
2801+
2802+
skb = nlmsg_new(neigh_nlmsg_size(), GFP_KERNEL);
2803+
if (!skb)
2804+
return -ENOBUFS;
2805+
2806+
err = neigh_fill_info(skb, neigh, pid, seq, RTM_NEWNEIGH, 0);
2807+
if (err) {
2808+
kfree_skb(skb);
2809+
goto errout;
2810+
}
2811+
2812+
err = rtnl_unicast(skb, net, pid);
2813+
errout:
2814+
return err;
2815+
}
2816+
2817+
static inline size_t pneigh_nlmsg_size(void)
2818+
{
2819+
return NLMSG_ALIGN(sizeof(struct ndmsg))
2820+
+ nla_total_size(MAX_ADDR_LEN); /* NDA_DST */
2821+
+ nla_total_size(1); /* NDA_PROTOCOL */
2822+
}
2823+
2824+
static int pneigh_get_reply(struct net *net, struct pneigh_entry *neigh,
2825+
u32 pid, u32 seq, struct neigh_table *tbl)
2826+
{
2827+
struct sk_buff *skb;
2828+
int err = 0;
2829+
2830+
skb = nlmsg_new(pneigh_nlmsg_size(), GFP_KERNEL);
2831+
if (!skb)
2832+
return -ENOBUFS;
2833+
2834+
err = pneigh_fill_info(skb, neigh, pid, seq, RTM_NEWNEIGH, 0, tbl);
2835+
if (err) {
2836+
kfree_skb(skb);
2837+
goto errout;
2838+
}
2839+
2840+
err = rtnl_unicast(skb, net, pid);
2841+
errout:
2842+
return err;
2843+
}
2844+
2845+
static int neigh_get(struct sk_buff *in_skb, struct nlmsghdr *nlh,
2846+
struct netlink_ext_ack *extack)
2847+
{
2848+
struct net *net = sock_net(in_skb->sk);
2849+
struct net_device *dev = NULL;
2850+
struct neigh_table *tbl = NULL;
2851+
struct neighbour *neigh;
2852+
void *dst = NULL;
2853+
u8 ndm_flags = 0;
2854+
int dev_idx = 0;
2855+
int err;
2856+
2857+
err = neigh_valid_get_req(nlh, &tbl, &dst, &dev_idx, &ndm_flags,
2858+
extack);
2859+
if (err < 0)
2860+
return err;
2861+
2862+
if (dev_idx) {
2863+
dev = __dev_get_by_index(net, dev_idx);
2864+
if (!dev) {
2865+
NL_SET_ERR_MSG(extack, "Unknown device ifindex");
2866+
return -ENODEV;
2867+
}
2868+
}
2869+
2870+
if (!dst) {
2871+
NL_SET_ERR_MSG(extack, "Network address not specified");
2872+
return -EINVAL;
2873+
}
2874+
2875+
if (ndm_flags & NTF_PROXY) {
2876+
struct pneigh_entry *pn;
2877+
2878+
pn = pneigh_lookup(tbl, net, dst, dev, 0);
2879+
if (!pn) {
2880+
NL_SET_ERR_MSG(extack, "Proxy neighbour entry not found");
2881+
return -ENOENT;
2882+
}
2883+
return pneigh_get_reply(net, pn, NETLINK_CB(in_skb).portid,
2884+
nlh->nlmsg_seq, tbl);
2885+
}
2886+
2887+
if (!dev) {
2888+
NL_SET_ERR_MSG(extack, "No device specified");
2889+
return -EINVAL;
2890+
}
2891+
2892+
neigh = neigh_lookup(tbl, dst, dev);
2893+
if (!neigh) {
2894+
NL_SET_ERR_MSG(extack, "Neighbour entry not found");
2895+
return -ENOENT;
2896+
}
2897+
2898+
err = neigh_get_reply(net, neigh, NETLINK_CB(in_skb).portid,
2899+
nlh->nlmsg_seq);
2900+
2901+
neigh_release(neigh);
2902+
2903+
return err;
2904+
}
2905+
27142906
void neigh_for_each(struct neigh_table *tbl, void (*cb)(struct neighbour *, void *), void *cookie)
27152907
{
27162908
int chain;
@@ -3118,16 +3310,6 @@ static const struct seq_operations neigh_stat_seq_ops = {
31183310
};
31193311
#endif /* CONFIG_PROC_FS */
31203312

3121-
static inline size_t neigh_nlmsg_size(void)
3122-
{
3123-
return NLMSG_ALIGN(sizeof(struct ndmsg))
3124-
+ nla_total_size(MAX_ADDR_LEN) /* NDA_DST */
3125-
+ nla_total_size(MAX_ADDR_LEN) /* NDA_LLADDR */
3126-
+ nla_total_size(sizeof(struct nda_cacheinfo))
3127-
+ nla_total_size(4) /* NDA_PROBES */
3128-
+ nla_total_size(1); /* NDA_PROTOCOL */
3129-
}
3130-
31313313
static void __neigh_notify(struct neighbour *n, int type, int flags,
31323314
u32 pid)
31333315
{
@@ -3511,7 +3693,7 @@ static int __init neigh_init(void)
35113693
{
35123694
rtnl_register(PF_UNSPEC, RTM_NEWNEIGH, neigh_add, NULL, 0);
35133695
rtnl_register(PF_UNSPEC, RTM_DELNEIGH, neigh_delete, NULL, 0);
3514-
rtnl_register(PF_UNSPEC, RTM_GETNEIGH, NULL, neigh_dump_info, 0);
3696+
rtnl_register(PF_UNSPEC, RTM_GETNEIGH, neigh_get, neigh_dump_info, 0);
35153697

35163698
rtnl_register(PF_UNSPEC, RTM_GETNEIGHTBL, NULL, neightbl_dump_info,
35173699
0);

net/core/rtnetlink.c

-12
Original file line numberDiff line numberDiff line change
@@ -3460,18 +3460,6 @@ void rtmsg_ifinfo_newnet(int type, struct net_device *dev, unsigned int change,
34603460
new_nsid, new_ifindex);
34613461
}
34623462

3463-
static const struct nla_policy nda_policy[NDA_MAX+1] = {
3464-
[NDA_DST] = { .type = NLA_BINARY, .len = MAX_ADDR_LEN },
3465-
[NDA_LLADDR] = { .type = NLA_BINARY, .len = MAX_ADDR_LEN },
3466-
[NDA_CACHEINFO] = { .len = sizeof(struct nda_cacheinfo) },
3467-
[NDA_PROBES] = { .type = NLA_U32 },
3468-
[NDA_VLAN] = { .type = NLA_U16 },
3469-
[NDA_PORT] = { .type = NLA_U16 },
3470-
[NDA_VNI] = { .type = NLA_U32 },
3471-
[NDA_IFINDEX] = { .type = NLA_U32 },
3472-
[NDA_MASTER] = { .type = NLA_U32 },
3473-
};
3474-
34753463
static int nlmsg_populate_fdb_fill(struct sk_buff *skb,
34763464
struct net_device *dev,
34773465
u8 *addr, u16 vid, u32 pid, u32 seq,

tools/testing/selftests/net/rtnetlink.sh

+54
Original file line numberDiff line numberDiff line change
@@ -1007,6 +1007,59 @@ kci_test_fdb_get()
10071007
echo "PASS: bridge fdb get"
10081008
}
10091009

1010+
kci_test_neigh_get()
1011+
{
1012+
dstmac=de:ad:be:ef:13:37
1013+
dstip=10.0.2.4
1014+
dstip6=dead::2
1015+
ret=0
1016+
1017+
ip neigh help 2>&1 |grep -q 'ip neigh get'
1018+
if [ $? -ne 0 ];then
1019+
echo "SKIP: fdb get tests: iproute2 too old"
1020+
return $ksft_skip
1021+
fi
1022+
1023+
# ipv4
1024+
ip neigh add $dstip lladdr $dstmac dev "$devdummy" > /dev/null
1025+
check_err $?
1026+
ip neigh get $dstip dev "$devdummy" 2> /dev/null | grep -q "$dstmac"
1027+
check_err $?
1028+
ip neigh del $dstip lladdr $dstmac dev "$devdummy" > /dev/null
1029+
check_err $?
1030+
1031+
# ipv4 proxy
1032+
ip neigh add proxy $dstip dev "$devdummy" > /dev/null
1033+
check_err $?
1034+
ip neigh get proxy $dstip dev "$devdummy" 2>/dev/null | grep -q "$dstip"
1035+
check_err $?
1036+
ip neigh del proxy $dstip dev "$devdummy" > /dev/null
1037+
check_err $?
1038+
1039+
# ipv6
1040+
ip neigh add $dstip6 lladdr $dstmac dev "$devdummy" > /dev/null
1041+
check_err $?
1042+
ip neigh get $dstip6 dev "$devdummy" 2> /dev/null | grep -q "$dstmac"
1043+
check_err $?
1044+
ip neigh del $dstip6 lladdr $dstmac dev "$devdummy" > /dev/null
1045+
check_err $?
1046+
1047+
# ipv6 proxy
1048+
ip neigh add proxy $dstip6 dev "$devdummy" > /dev/null
1049+
check_err $?
1050+
ip neigh get proxy $dstip6 dev "$devdummy" 2>/dev/null | grep -q "$dstip6"
1051+
check_err $?
1052+
ip neigh del proxy $dstip6 dev "$devdummy" > /dev/null
1053+
check_err $?
1054+
1055+
if [ $ret -ne 0 ];then
1056+
echo "FAIL: neigh get"
1057+
return 1
1058+
fi
1059+
1060+
echo "PASS: neigh get"
1061+
}
1062+
10101063
kci_test_rtnl()
10111064
{
10121065
kci_add_dummy
@@ -1032,6 +1085,7 @@ kci_test_rtnl()
10321085
kci_test_ipsec
10331086
kci_test_ipsec_offload
10341087
kci_test_fdb_get
1088+
kci_test_neigh_get
10351089

10361090
kci_del_dummy
10371091
}

0 commit comments

Comments
 (0)