Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

+248 -23
+1
include/net/neighbour.h
··· 255 255 #define NEIGH_UPDATE_F_ISROUTER 0x40000000 256 256 #define NEIGH_UPDATE_F_ADMIN 0x80000000 257 257 258 + extern const struct nla_policy nda_policy[]; 258 259 259 260 static inline bool neigh_key_eq16(const struct neighbour *n, const void *pkey) 260 261 {
+193 -11
net/core/neighbour.c
··· 1751 1751 return tbl; 1752 1752 } 1753 1753 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 + 1754 1766 static int neigh_delete(struct sk_buff *skb, struct nlmsghdr *nlh, 1755 1767 struct netlink_ext_ack *extack) 1756 1768 { ··· 2723 2711 return skb->len; 2724 2712 } 2725 2713 2714 + static int neigh_valid_get_req(const struct nlmsghdr *nlh, 2715 + struct neigh_table **tbl, 2716 + void **dst, int *dev_idx, u8 *ndm_flags, 2717 + struct netlink_ext_ack *extack) 2718 + { 2719 + struct nlattr *tb[NDA_MAX + 1]; 2720 + struct ndmsg *ndm; 2721 + int err, i; 2722 + 2723 + if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(*ndm))) { 2724 + NL_SET_ERR_MSG(extack, "Invalid header for neighbor get request"); 2725 + return -EINVAL; 2726 + } 2727 + 2728 + ndm = nlmsg_data(nlh); 2729 + if (ndm->ndm_pad1 || ndm->ndm_pad2 || ndm->ndm_state || 2730 + ndm->ndm_type) { 2731 + NL_SET_ERR_MSG(extack, "Invalid values in header for neighbor get request"); 2732 + return -EINVAL; 2733 + } 2734 + 2735 + if (ndm->ndm_flags & ~NTF_PROXY) { 2736 + NL_SET_ERR_MSG(extack, "Invalid flags in header for neighbor get request"); 2737 + return -EINVAL; 2738 + } 2739 + 2740 + err = nlmsg_parse_strict(nlh, sizeof(struct ndmsg), tb, NDA_MAX, 2741 + nda_policy, extack); 2742 + if (err < 0) 2743 + return err; 2744 + 2745 + *ndm_flags = ndm->ndm_flags; 2746 + *dev_idx = ndm->ndm_ifindex; 2747 + *tbl = neigh_find_table(ndm->ndm_family); 2748 + if (*tbl == NULL) { 2749 + NL_SET_ERR_MSG(extack, "Unsupported family in header for neighbor get request"); 2750 + return -EAFNOSUPPORT; 2751 + } 2752 + 2753 + for (i = 0; i <= NDA_MAX; ++i) { 2754 + if (!tb[i]) 2755 + continue; 2756 + 2757 + switch (i) { 2758 + case NDA_DST: 2759 + if (nla_len(tb[i]) != (int)(*tbl)->key_len) { 2760 + NL_SET_ERR_MSG(extack, "Invalid network address in neighbor get request"); 2761 + return -EINVAL; 2762 + } 2763 + *dst = nla_data(tb[i]); 2764 + break; 2765 + default: 2766 + NL_SET_ERR_MSG(extack, "Unsupported attribute in neighbor get request"); 2767 + return -EINVAL; 2768 + } 2769 + } 2770 + 2771 + return 0; 2772 + } 2773 + 2774 + static inline size_t neigh_nlmsg_size(void) 2775 + { 2776 + return NLMSG_ALIGN(sizeof(struct ndmsg)) 2777 + + nla_total_size(MAX_ADDR_LEN) /* NDA_DST */ 2778 + + nla_total_size(MAX_ADDR_LEN) /* NDA_LLADDR */ 2779 + + nla_total_size(sizeof(struct nda_cacheinfo)) 2780 + + nla_total_size(4) /* NDA_PROBES */ 2781 + + nla_total_size(1); /* NDA_PROTOCOL */ 2782 + } 2783 + 2784 + static int neigh_get_reply(struct net *net, struct neighbour *neigh, 2785 + u32 pid, u32 seq) 2786 + { 2787 + struct sk_buff *skb; 2788 + int err = 0; 2789 + 2790 + skb = nlmsg_new(neigh_nlmsg_size(), GFP_KERNEL); 2791 + if (!skb) 2792 + return -ENOBUFS; 2793 + 2794 + err = neigh_fill_info(skb, neigh, pid, seq, RTM_NEWNEIGH, 0); 2795 + if (err) { 2796 + kfree_skb(skb); 2797 + goto errout; 2798 + } 2799 + 2800 + err = rtnl_unicast(skb, net, pid); 2801 + errout: 2802 + return err; 2803 + } 2804 + 2805 + static inline size_t pneigh_nlmsg_size(void) 2806 + { 2807 + return NLMSG_ALIGN(sizeof(struct ndmsg)) 2808 + + nla_total_size(MAX_ADDR_LEN); /* NDA_DST */ 2809 + + nla_total_size(1); /* NDA_PROTOCOL */ 2810 + } 2811 + 2812 + static int pneigh_get_reply(struct net *net, struct pneigh_entry *neigh, 2813 + u32 pid, u32 seq, struct neigh_table *tbl) 2814 + { 2815 + struct sk_buff *skb; 2816 + int err = 0; 2817 + 2818 + skb = nlmsg_new(pneigh_nlmsg_size(), GFP_KERNEL); 2819 + if (!skb) 2820 + return -ENOBUFS; 2821 + 2822 + err = pneigh_fill_info(skb, neigh, pid, seq, RTM_NEWNEIGH, 0, tbl); 2823 + if (err) { 2824 + kfree_skb(skb); 2825 + goto errout; 2826 + } 2827 + 2828 + err = rtnl_unicast(skb, net, pid); 2829 + errout: 2830 + return err; 2831 + } 2832 + 2833 + static int neigh_get(struct sk_buff *in_skb, struct nlmsghdr *nlh, 2834 + struct netlink_ext_ack *extack) 2835 + { 2836 + struct net *net = sock_net(in_skb->sk); 2837 + struct net_device *dev = NULL; 2838 + struct neigh_table *tbl = NULL; 2839 + struct neighbour *neigh; 2840 + void *dst = NULL; 2841 + u8 ndm_flags = 0; 2842 + int dev_idx = 0; 2843 + int err; 2844 + 2845 + err = neigh_valid_get_req(nlh, &tbl, &dst, &dev_idx, &ndm_flags, 2846 + extack); 2847 + if (err < 0) 2848 + return err; 2849 + 2850 + if (dev_idx) { 2851 + dev = __dev_get_by_index(net, dev_idx); 2852 + if (!dev) { 2853 + NL_SET_ERR_MSG(extack, "Unknown device ifindex"); 2854 + return -ENODEV; 2855 + } 2856 + } 2857 + 2858 + if (!dst) { 2859 + NL_SET_ERR_MSG(extack, "Network address not specified"); 2860 + return -EINVAL; 2861 + } 2862 + 2863 + if (ndm_flags & NTF_PROXY) { 2864 + struct pneigh_entry *pn; 2865 + 2866 + pn = pneigh_lookup(tbl, net, dst, dev, 0); 2867 + if (!pn) { 2868 + NL_SET_ERR_MSG(extack, "Proxy neighbour entry not found"); 2869 + return -ENOENT; 2870 + } 2871 + return pneigh_get_reply(net, pn, NETLINK_CB(in_skb).portid, 2872 + nlh->nlmsg_seq, tbl); 2873 + } 2874 + 2875 + if (!dev) { 2876 + NL_SET_ERR_MSG(extack, "No device specified"); 2877 + return -EINVAL; 2878 + } 2879 + 2880 + neigh = neigh_lookup(tbl, dst, dev); 2881 + if (!neigh) { 2882 + NL_SET_ERR_MSG(extack, "Neighbour entry not found"); 2883 + return -ENOENT; 2884 + } 2885 + 2886 + err = neigh_get_reply(net, neigh, NETLINK_CB(in_skb).portid, 2887 + nlh->nlmsg_seq); 2888 + 2889 + neigh_release(neigh); 2890 + 2891 + return err; 2892 + } 2893 + 2726 2894 void neigh_for_each(struct neigh_table *tbl, void (*cb)(struct neighbour *, void *), void *cookie) 2727 2895 { 2728 2896 int chain; ··· 3310 3118 }; 3311 3119 #endif /* CONFIG_PROC_FS */ 3312 3120 3313 - static inline size_t neigh_nlmsg_size(void) 3314 - { 3315 - return NLMSG_ALIGN(sizeof(struct ndmsg)) 3316 - + nla_total_size(MAX_ADDR_LEN) /* NDA_DST */ 3317 - + nla_total_size(MAX_ADDR_LEN) /* NDA_LLADDR */ 3318 - + nla_total_size(sizeof(struct nda_cacheinfo)) 3319 - + nla_total_size(4) /* NDA_PROBES */ 3320 - + nla_total_size(1); /* NDA_PROTOCOL */ 3321 - } 3322 - 3323 3121 static void __neigh_notify(struct neighbour *n, int type, int flags, 3324 3122 u32 pid) 3325 3123 { ··· 3693 3511 { 3694 3512 rtnl_register(PF_UNSPEC, RTM_NEWNEIGH, neigh_add, NULL, 0); 3695 3513 rtnl_register(PF_UNSPEC, RTM_DELNEIGH, neigh_delete, NULL, 0); 3696 - rtnl_register(PF_UNSPEC, RTM_GETNEIGH, NULL, neigh_dump_info, 0); 3514 + rtnl_register(PF_UNSPEC, RTM_GETNEIGH, neigh_get, neigh_dump_info, 0); 3697 3515 3698 3516 rtnl_register(PF_UNSPEC, RTM_GETNEIGHTBL, NULL, neightbl_dump_info, 3699 3517 0);
-12
net/core/rtnetlink.c
··· 3460 3460 new_nsid, new_ifindex); 3461 3461 } 3462 3462 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 - 3475 3463 static int nlmsg_populate_fdb_fill(struct sk_buff *skb, 3476 3464 struct net_device *dev, 3477 3465 u8 *addr, u16 vid, u32 pid, u32 seq,
+54
tools/testing/selftests/net/rtnetlink.sh
··· 1007 1007 echo "PASS: bridge fdb get" 1008 1008 } 1009 1009 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 + 1010 1063 kci_test_rtnl() 1011 1064 { 1012 1065 kci_add_dummy ··· 1085 1032 kci_test_ipsec 1086 1033 kci_test_ipsec_offload 1087 1034 kci_test_fdb_get 1035 + kci_test_neigh_get 1088 1036 1089 1037 kci_del_dummy 1090 1038 }