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

Configure Feed

Select the types of activity you want to include in your feed.

Merge branch 'neighbour-convert-rtm_getneigh-to-rcu-and-make-pneigh-rtnl-free'

Kuniyuki Iwashima says:

====================
neighbour: Convert RTM_GETNEIGH to RCU and make pneigh RTNL-free.

This is kind of v3 of the series below [0] but without NEIGHTBL patches.

Patch 1 ~ 4 and 9 come from the series to convert RTM_GETNEIGH to RCU.

Other patches clean up pneigh_lookup() and convert the pneigh code to
RCU + private mutex so that we can easily remove RTNL from RTM_NEWNEIGH
in the later series.

[0]: https://lore.kernel.org/netdev/20250418012727.57033-1-kuniyu@amazon.com/

v2: https://lore.kernel.org/20250712203515.4099110-1-kuniyu@google.com
v1: https://lore.kernel.org/20250711191007.3591938-1-kuniyu@google.com
====================

Link: https://patch.msgid.link/20250716221221.442239-1-kuniyu@google.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>

+210 -213
+11 -6
include/net/neighbour.h
··· 176 176 }; 177 177 178 178 struct pneigh_entry { 179 - struct pneigh_entry *next; 179 + struct pneigh_entry __rcu *next; 180 180 possible_net_t net; 181 181 struct net_device *dev; 182 182 netdevice_tracker dev_tracker; 183 + union { 184 + struct list_head free_node; 185 + struct rcu_head rcu; 186 + }; 183 187 u32 flags; 184 188 u8 protocol; 185 189 bool permanent; ··· 240 236 unsigned long last_rand; 241 237 struct neigh_statistics __percpu *stats; 242 238 struct neigh_hash_table __rcu *nht; 243 - struct pneigh_entry **phash_buckets; 239 + struct mutex phash_lock; 240 + struct pneigh_entry __rcu **phash_buckets; 244 241 }; 245 242 246 243 static inline int neigh_parms_family(struct neigh_parms *p) ··· 381 376 void pneigh_enqueue(struct neigh_table *tbl, struct neigh_parms *p, 382 377 struct sk_buff *skb); 383 378 struct pneigh_entry *pneigh_lookup(struct neigh_table *tbl, struct net *net, 384 - const void *key, struct net_device *dev, 385 - int creat); 386 - struct pneigh_entry *__pneigh_lookup(struct neigh_table *tbl, struct net *net, 387 - const void *key, struct net_device *dev); 379 + const void *key, struct net_device *dev); 380 + int pneigh_create(struct neigh_table *tbl, struct net *net, const void *key, 381 + struct net_device *dev, u32 flags, u8 protocol, 382 + bool permanent); 388 383 int pneigh_delete(struct neigh_table *tbl, struct net *net, const void *key, 389 384 struct net_device *dev); 390 385
+193 -197
net/core/neighbour.c
··· 28 28 #include <net/neighbour.h> 29 29 #include <net/arp.h> 30 30 #include <net/dst.h> 31 + #include <net/ip.h> 31 32 #include <net/sock.h> 32 33 #include <net/netevent.h> 33 34 #include <net/netlink.h> ··· 54 53 static void __neigh_notify(struct neighbour *n, int type, int flags, 55 54 u32 pid); 56 55 static void neigh_update_notify(struct neighbour *neigh, u32 nlmsg_pid); 57 - static int pneigh_ifdown_and_unlock(struct neigh_table *tbl, 58 - struct net_device *dev, 59 - bool skip_perm); 56 + static void pneigh_ifdown(struct neigh_table *tbl, struct net_device *dev, 57 + bool skip_perm); 60 58 61 59 #ifdef CONFIG_PROC_FS 62 60 static const struct seq_operations neigh_stat_seq_ops; ··· 436 436 { 437 437 write_lock_bh(&tbl->lock); 438 438 neigh_flush_dev(tbl, dev, skip_perm); 439 - pneigh_ifdown_and_unlock(tbl, dev, skip_perm); 439 + write_unlock_bh(&tbl->lock); 440 + 441 + pneigh_ifdown(tbl, dev, skip_perm); 440 442 pneigh_queue_purge(&tbl->proxy_queue, dev ? dev_net(dev) : NULL, 441 443 tbl->family); 442 444 if (skb_queue_empty_lockless(&tbl->proxy_queue)) ··· 721 719 return hash_val; 722 720 } 723 721 724 - static struct pneigh_entry *__pneigh_lookup_1(struct pneigh_entry *n, 725 - struct net *net, 726 - const void *pkey, 727 - unsigned int key_len, 728 - struct net_device *dev) 722 + struct pneigh_entry *pneigh_lookup(struct neigh_table *tbl, 723 + struct net *net, const void *pkey, 724 + struct net_device *dev) 729 725 { 726 + struct pneigh_entry *n; 727 + unsigned int key_len; 728 + u32 hash_val; 729 + 730 + key_len = tbl->key_len; 731 + hash_val = pneigh_hash(pkey, key_len); 732 + n = rcu_dereference_check(tbl->phash_buckets[hash_val], 733 + lockdep_is_held(&tbl->phash_lock)); 734 + 730 735 while (n) { 731 736 if (!memcmp(n->key, pkey, key_len) && 732 737 net_eq(pneigh_net(n), net) && 733 738 (n->dev == dev || !n->dev)) 734 739 return n; 735 - n = n->next; 740 + 741 + n = rcu_dereference_check(n->next, lockdep_is_held(&tbl->phash_lock)); 736 742 } 743 + 737 744 return NULL; 738 745 } 746 + EXPORT_IPV6_MOD(pneigh_lookup); 739 747 740 - struct pneigh_entry *__pneigh_lookup(struct neigh_table *tbl, 741 - struct net *net, const void *pkey, struct net_device *dev) 742 - { 743 - unsigned int key_len = tbl->key_len; 744 - u32 hash_val = pneigh_hash(pkey, key_len); 745 - 746 - return __pneigh_lookup_1(tbl->phash_buckets[hash_val], 747 - net, pkey, key_len, dev); 748 - } 749 - EXPORT_SYMBOL_GPL(__pneigh_lookup); 750 - 751 - struct pneigh_entry * pneigh_lookup(struct neigh_table *tbl, 752 - struct net *net, const void *pkey, 753 - struct net_device *dev, int creat) 748 + int pneigh_create(struct neigh_table *tbl, struct net *net, 749 + const void *pkey, struct net_device *dev, 750 + u32 flags, u8 protocol, bool permanent) 754 751 { 755 752 struct pneigh_entry *n; 756 - unsigned int key_len = tbl->key_len; 757 - u32 hash_val = pneigh_hash(pkey, key_len); 753 + unsigned int key_len; 754 + u32 hash_val; 755 + int err = 0; 758 756 759 - read_lock_bh(&tbl->lock); 760 - n = __pneigh_lookup_1(tbl->phash_buckets[hash_val], 761 - net, pkey, key_len, dev); 762 - read_unlock_bh(&tbl->lock); 757 + mutex_lock(&tbl->phash_lock); 763 758 764 - if (n || !creat) 765 - goto out; 759 + n = pneigh_lookup(tbl, net, pkey, dev); 760 + if (n) 761 + goto update; 766 762 767 - ASSERT_RTNL(); 768 - 763 + key_len = tbl->key_len; 769 764 n = kzalloc(sizeof(*n) + key_len, GFP_KERNEL); 770 - if (!n) 765 + if (!n) { 766 + err = -ENOBUFS; 771 767 goto out; 768 + } 772 769 773 770 write_pnet(&n->net, net); 774 771 memcpy(n->key, pkey, key_len); ··· 777 776 if (tbl->pconstructor && tbl->pconstructor(n)) { 778 777 netdev_put(dev, &n->dev_tracker); 779 778 kfree(n); 780 - n = NULL; 779 + err = -ENOBUFS; 781 780 goto out; 782 781 } 783 782 784 - write_lock_bh(&tbl->lock); 783 + hash_val = pneigh_hash(pkey, key_len); 785 784 n->next = tbl->phash_buckets[hash_val]; 786 - tbl->phash_buckets[hash_val] = n; 787 - write_unlock_bh(&tbl->lock); 785 + rcu_assign_pointer(tbl->phash_buckets[hash_val], n); 786 + update: 787 + WRITE_ONCE(n->flags, flags); 788 + n->permanent = permanent; 789 + WRITE_ONCE(n->protocol, protocol); 788 790 out: 789 - return n; 791 + mutex_unlock(&tbl->phash_lock); 792 + return err; 790 793 } 791 - EXPORT_SYMBOL(pneigh_lookup); 792 794 795 + static void pneigh_destroy(struct rcu_head *rcu) 796 + { 797 + struct pneigh_entry *n = container_of(rcu, struct pneigh_entry, rcu); 798 + 799 + netdev_put(n->dev, &n->dev_tracker); 800 + kfree(n); 801 + } 793 802 794 803 int pneigh_delete(struct neigh_table *tbl, struct net *net, const void *pkey, 795 804 struct net_device *dev) 796 805 { 797 - struct pneigh_entry *n, **np; 798 - unsigned int key_len = tbl->key_len; 799 - u32 hash_val = pneigh_hash(pkey, key_len); 806 + struct pneigh_entry *n, __rcu **np; 807 + unsigned int key_len; 808 + u32 hash_val; 800 809 801 - write_lock_bh(&tbl->lock); 802 - for (np = &tbl->phash_buckets[hash_val]; (n = *np) != NULL; 810 + key_len = tbl->key_len; 811 + hash_val = pneigh_hash(pkey, key_len); 812 + 813 + mutex_lock(&tbl->phash_lock); 814 + 815 + for (np = &tbl->phash_buckets[hash_val]; 816 + (n = rcu_dereference_protected(*np, 1)) != NULL; 803 817 np = &n->next) { 804 818 if (!memcmp(n->key, pkey, key_len) && n->dev == dev && 805 819 net_eq(pneigh_net(n), net)) { 806 - *np = n->next; 807 - write_unlock_bh(&tbl->lock); 820 + rcu_assign_pointer(*np, n->next); 821 + 822 + mutex_unlock(&tbl->phash_lock); 823 + 808 824 if (tbl->pdestructor) 809 825 tbl->pdestructor(n); 810 - netdev_put(n->dev, &n->dev_tracker); 811 - kfree(n); 826 + 827 + call_rcu(&n->rcu, pneigh_destroy); 812 828 return 0; 813 829 } 814 830 } 815 - write_unlock_bh(&tbl->lock); 831 + 832 + mutex_unlock(&tbl->phash_lock); 816 833 return -ENOENT; 817 834 } 818 835 819 - static int pneigh_ifdown_and_unlock(struct neigh_table *tbl, 820 - struct net_device *dev, 821 - bool skip_perm) 836 + static void pneigh_ifdown(struct neigh_table *tbl, struct net_device *dev, 837 + bool skip_perm) 822 838 { 823 - struct pneigh_entry *n, **np, *freelist = NULL; 839 + struct pneigh_entry *n, __rcu **np; 840 + LIST_HEAD(head); 824 841 u32 h; 842 + 843 + mutex_lock(&tbl->phash_lock); 825 844 826 845 for (h = 0; h <= PNEIGH_HASHMASK; h++) { 827 846 np = &tbl->phash_buckets[h]; 828 - while ((n = *np) != NULL) { 847 + while ((n = rcu_dereference_protected(*np, 1)) != NULL) { 829 848 if (skip_perm && n->permanent) 830 849 goto skip; 831 850 if (!dev || n->dev == dev) { 832 - *np = n->next; 833 - n->next = freelist; 834 - freelist = n; 851 + rcu_assign_pointer(*np, n->next); 852 + list_add(&n->free_node, &head); 835 853 continue; 836 854 } 837 855 skip: 838 856 np = &n->next; 839 857 } 840 858 } 841 - write_unlock_bh(&tbl->lock); 842 - while ((n = freelist)) { 843 - freelist = n->next; 844 - n->next = NULL; 859 + 860 + mutex_unlock(&tbl->phash_lock); 861 + 862 + while (!list_empty(&head)) { 863 + n = list_first_entry(&head, typeof(*n), free_node); 864 + list_del(&n->free_node); 865 + 845 866 if (tbl->pdestructor) 846 867 tbl->pdestructor(n); 847 - netdev_put(n->dev, &n->dev_tracker); 848 - kfree(n); 868 + 869 + call_rcu(&n->rcu, pneigh_destroy); 849 870 } 850 - return -ENOENT; 851 871 } 852 872 853 873 static inline void neigh_parms_put(struct neigh_parms *parms) ··· 1805 1783 WARN_ON(tbl->entry_size % NEIGH_PRIV_ALIGN); 1806 1784 1807 1785 rwlock_init(&tbl->lock); 1786 + mutex_init(&tbl->phash_lock); 1808 1787 1809 1788 INIT_DEFERRABLE_WORK(&tbl->gc_work, neigh_periodic_work); 1810 1789 queue_delayed_work(system_power_efficient_wq, &tbl->gc_work, ··· 2022 1999 if (tb[NDA_PROTOCOL]) 2023 2000 protocol = nla_get_u8(tb[NDA_PROTOCOL]); 2024 2001 if (ndm_flags & NTF_PROXY) { 2025 - struct pneigh_entry *pn; 2026 - 2027 2002 if (ndm_flags & (NTF_MANAGED | NTF_EXT_VALIDATED)) { 2028 2003 NL_SET_ERR_MSG(extack, "Invalid NTF_* flag combination"); 2029 2004 goto out; 2030 2005 } 2031 2006 2032 - err = -ENOBUFS; 2033 - pn = pneigh_lookup(tbl, net, dst, dev, 1); 2034 - if (pn) { 2035 - pn->flags = ndm_flags; 2036 - pn->permanent = !!(ndm->ndm_state & NUD_PERMANENT); 2037 - if (protocol) 2038 - pn->protocol = protocol; 2039 - err = 0; 2040 - } 2007 + err = pneigh_create(tbl, net, dst, dev, ndm_flags, protocol, 2008 + !!(ndm->ndm_state & NUD_PERMANENT)); 2041 2009 goto out; 2042 2010 } 2043 2011 ··· 2657 2643 u32 neigh_flags, neigh_flags_ext; 2658 2644 struct nlmsghdr *nlh; 2659 2645 struct ndmsg *ndm; 2646 + u8 protocol; 2660 2647 2661 2648 nlh = nlmsg_put(skb, pid, seq, type, sizeof(*ndm), flags); 2662 2649 if (nlh == NULL) 2663 2650 return -EMSGSIZE; 2664 2651 2665 - neigh_flags_ext = pn->flags >> NTF_EXT_SHIFT; 2666 - neigh_flags = pn->flags & NTF_OLD_MASK; 2652 + neigh_flags = READ_ONCE(pn->flags); 2653 + neigh_flags_ext = neigh_flags >> NTF_EXT_SHIFT; 2654 + neigh_flags &= NTF_OLD_MASK; 2667 2655 2668 2656 ndm = nlmsg_data(nlh); 2669 2657 ndm->ndm_family = tbl->family; ··· 2679 2663 if (nla_put(skb, NDA_DST, tbl->key_len, pn->key)) 2680 2664 goto nla_put_failure; 2681 2665 2682 - if (pn->protocol && nla_put_u8(skb, NDA_PROTOCOL, pn->protocol)) 2666 + protocol = READ_ONCE(pn->protocol); 2667 + if (protocol && nla_put_u8(skb, NDA_PROTOCOL, protocol)) 2683 2668 goto nla_put_failure; 2684 2669 if (neigh_flags_ext && nla_put_u32(skb, NDA_FLAGS_EXT, neigh_flags_ext)) 2685 2670 goto nla_put_failure; ··· 2787 2770 if (filter->dev_idx || filter->master_idx) 2788 2771 flags |= NLM_F_DUMP_FILTERED; 2789 2772 2790 - read_lock_bh(&tbl->lock); 2791 - 2792 2773 for (h = s_h; h <= PNEIGH_HASHMASK; h++) { 2793 2774 if (h > s_h) 2794 2775 s_idx = 0; 2795 - for (n = tbl->phash_buckets[h], idx = 0; n; n = n->next) { 2776 + for (n = rcu_dereference(tbl->phash_buckets[h]), idx = 0; 2777 + n; 2778 + n = rcu_dereference(n->next)) { 2796 2779 if (idx < s_idx || pneigh_net(n) != net) 2797 2780 goto next; 2798 2781 if (neigh_ifindex_filtered(n->dev, filter->dev_idx) || ··· 2801 2784 err = pneigh_fill_info(skb, n, NETLINK_CB(cb->skb).portid, 2802 2785 cb->nlh->nlmsg_seq, 2803 2786 RTM_NEWNEIGH, flags, tbl); 2804 - if (err < 0) { 2805 - read_unlock_bh(&tbl->lock); 2787 + if (err < 0) 2806 2788 goto out; 2807 - } 2808 2789 next: 2809 2790 idx++; 2810 2791 } 2811 2792 } 2812 2793 2813 - read_unlock_bh(&tbl->lock); 2814 2794 out: 2815 2795 cb->args[3] = h; 2816 2796 cb->args[4] = idx; ··· 2924 2910 return err; 2925 2911 } 2926 2912 2927 - static int neigh_valid_get_req(const struct nlmsghdr *nlh, 2928 - struct neigh_table **tbl, 2929 - void **dst, int *dev_idx, u8 *ndm_flags, 2930 - struct netlink_ext_ack *extack) 2913 + static struct ndmsg *neigh_valid_get_req(const struct nlmsghdr *nlh, 2914 + struct nlattr **tb, 2915 + struct netlink_ext_ack *extack) 2931 2916 { 2932 - struct nlattr *tb[NDA_MAX + 1]; 2933 2917 struct ndmsg *ndm; 2934 2918 int err, i; 2935 2919 2936 2920 ndm = nlmsg_payload(nlh, sizeof(*ndm)); 2937 2921 if (!ndm) { 2938 2922 NL_SET_ERR_MSG(extack, "Invalid header for neighbor get request"); 2939 - return -EINVAL; 2923 + return ERR_PTR(-EINVAL); 2940 2924 } 2941 2925 2942 2926 if (ndm->ndm_pad1 || ndm->ndm_pad2 || ndm->ndm_state || 2943 2927 ndm->ndm_type) { 2944 2928 NL_SET_ERR_MSG(extack, "Invalid values in header for neighbor get request"); 2945 - return -EINVAL; 2929 + return ERR_PTR(-EINVAL); 2946 2930 } 2947 2931 2948 2932 if (ndm->ndm_flags & ~NTF_PROXY) { 2949 2933 NL_SET_ERR_MSG(extack, "Invalid flags in header for neighbor get request"); 2950 - return -EINVAL; 2934 + return ERR_PTR(-EINVAL); 2935 + } 2936 + 2937 + if (!(ndm->ndm_flags & NTF_PROXY) && !ndm->ndm_ifindex) { 2938 + NL_SET_ERR_MSG(extack, "No device specified"); 2939 + return ERR_PTR(-EINVAL); 2951 2940 } 2952 2941 2953 2942 err = nlmsg_parse_deprecated_strict(nlh, sizeof(struct ndmsg), tb, 2954 2943 NDA_MAX, nda_policy, extack); 2955 2944 if (err < 0) 2956 - return err; 2957 - 2958 - *ndm_flags = ndm->ndm_flags; 2959 - *dev_idx = ndm->ndm_ifindex; 2960 - *tbl = neigh_find_table(ndm->ndm_family); 2961 - if (*tbl == NULL) { 2962 - NL_SET_ERR_MSG(extack, "Unsupported family in header for neighbor get request"); 2963 - return -EAFNOSUPPORT; 2964 - } 2945 + return ERR_PTR(err); 2965 2946 2966 2947 for (i = 0; i <= NDA_MAX; ++i) { 2967 - if (!tb[i]) 2968 - continue; 2969 - 2970 2948 switch (i) { 2971 2949 case NDA_DST: 2972 - if (nla_len(tb[i]) != (int)(*tbl)->key_len) { 2973 - NL_SET_ERR_MSG(extack, "Invalid network address in neighbor get request"); 2974 - return -EINVAL; 2950 + if (!tb[i]) { 2951 + NL_SET_ERR_ATTR_MISS(extack, NULL, NDA_DST); 2952 + return ERR_PTR(-EINVAL); 2975 2953 } 2976 - *dst = nla_data(tb[i]); 2977 2954 break; 2978 2955 default: 2956 + if (!tb[i]) 2957 + continue; 2958 + 2979 2959 NL_SET_ERR_MSG(extack, "Unsupported attribute in neighbor get request"); 2980 - return -EINVAL; 2960 + return ERR_PTR(-EINVAL); 2981 2961 } 2982 2962 } 2983 2963 2984 - return 0; 2964 + return ndm; 2985 2965 } 2986 2966 2987 2967 static inline size_t neigh_nlmsg_size(void) ··· 2989 2981 + nla_total_size(1); /* NDA_PROTOCOL */ 2990 2982 } 2991 2983 2992 - static int neigh_get_reply(struct net *net, struct neighbour *neigh, 2993 - u32 pid, u32 seq) 2994 - { 2995 - struct sk_buff *skb; 2996 - int err = 0; 2997 - 2998 - skb = nlmsg_new(neigh_nlmsg_size(), GFP_KERNEL); 2999 - if (!skb) 3000 - return -ENOBUFS; 3001 - 3002 - err = neigh_fill_info(skb, neigh, pid, seq, RTM_NEWNEIGH, 0); 3003 - if (err) { 3004 - kfree_skb(skb); 3005 - goto errout; 3006 - } 3007 - 3008 - err = rtnl_unicast(skb, net, pid); 3009 - errout: 3010 - return err; 3011 - } 3012 - 3013 2984 static inline size_t pneigh_nlmsg_size(void) 3014 2985 { 3015 2986 return NLMSG_ALIGN(sizeof(struct ndmsg)) ··· 2997 3010 + nla_total_size(1); /* NDA_PROTOCOL */ 2998 3011 } 2999 3012 3000 - static int pneigh_get_reply(struct net *net, struct pneigh_entry *neigh, 3001 - u32 pid, u32 seq, struct neigh_table *tbl) 3002 - { 3003 - struct sk_buff *skb; 3004 - int err = 0; 3005 - 3006 - skb = nlmsg_new(pneigh_nlmsg_size(), GFP_KERNEL); 3007 - if (!skb) 3008 - return -ENOBUFS; 3009 - 3010 - err = pneigh_fill_info(skb, neigh, pid, seq, RTM_NEWNEIGH, 0, tbl); 3011 - if (err) { 3012 - kfree_skb(skb); 3013 - goto errout; 3014 - } 3015 - 3016 - err = rtnl_unicast(skb, net, pid); 3017 - errout: 3018 - return err; 3019 - } 3020 - 3021 3013 static int neigh_get(struct sk_buff *in_skb, struct nlmsghdr *nlh, 3022 3014 struct netlink_ext_ack *extack) 3023 3015 { 3024 3016 struct net *net = sock_net(in_skb->sk); 3017 + u32 pid = NETLINK_CB(in_skb).portid; 3018 + struct nlattr *tb[NDA_MAX + 1]; 3025 3019 struct net_device *dev = NULL; 3026 - struct neigh_table *tbl = NULL; 3020 + u32 seq = nlh->nlmsg_seq; 3021 + struct neigh_table *tbl; 3027 3022 struct neighbour *neigh; 3028 - void *dst = NULL; 3029 - u8 ndm_flags = 0; 3030 - int dev_idx = 0; 3023 + struct sk_buff *skb; 3024 + struct ndmsg *ndm; 3025 + void *dst; 3031 3026 int err; 3032 3027 3033 - err = neigh_valid_get_req(nlh, &tbl, &dst, &dev_idx, &ndm_flags, 3034 - extack); 3035 - if (err < 0) 3036 - return err; 3028 + ndm = neigh_valid_get_req(nlh, tb, extack); 3029 + if (IS_ERR(ndm)) 3030 + return PTR_ERR(ndm); 3037 3031 3038 - if (dev_idx) { 3039 - dev = __dev_get_by_index(net, dev_idx); 3032 + if (ndm->ndm_flags & NTF_PROXY) 3033 + skb = nlmsg_new(neigh_nlmsg_size(), GFP_KERNEL); 3034 + else 3035 + skb = nlmsg_new(pneigh_nlmsg_size(), GFP_KERNEL); 3036 + if (!skb) 3037 + return -ENOBUFS; 3038 + 3039 + rcu_read_lock(); 3040 + 3041 + tbl = neigh_find_table(ndm->ndm_family); 3042 + if (!tbl) { 3043 + NL_SET_ERR_MSG(extack, "Unsupported family in header for neighbor get request"); 3044 + err = -EAFNOSUPPORT; 3045 + goto err_unlock; 3046 + } 3047 + 3048 + if (nla_len(tb[NDA_DST]) != (int)tbl->key_len) { 3049 + NL_SET_ERR_MSG(extack, "Invalid network address in neighbor get request"); 3050 + err = -EINVAL; 3051 + goto err_unlock; 3052 + } 3053 + 3054 + dst = nla_data(tb[NDA_DST]); 3055 + 3056 + if (ndm->ndm_ifindex) { 3057 + dev = dev_get_by_index_rcu(net, ndm->ndm_ifindex); 3040 3058 if (!dev) { 3041 3059 NL_SET_ERR_MSG(extack, "Unknown device ifindex"); 3042 - return -ENODEV; 3060 + err = -ENODEV; 3061 + goto err_unlock; 3043 3062 } 3044 3063 } 3045 3064 3046 - if (!dst) { 3047 - NL_SET_ERR_MSG(extack, "Network address not specified"); 3048 - return -EINVAL; 3049 - } 3050 - 3051 - if (ndm_flags & NTF_PROXY) { 3065 + if (ndm->ndm_flags & NTF_PROXY) { 3052 3066 struct pneigh_entry *pn; 3053 3067 3054 - pn = pneigh_lookup(tbl, net, dst, dev, 0); 3068 + pn = pneigh_lookup(tbl, net, dst, dev); 3055 3069 if (!pn) { 3056 3070 NL_SET_ERR_MSG(extack, "Proxy neighbour entry not found"); 3057 - return -ENOENT; 3071 + err = -ENOENT; 3072 + goto err_unlock; 3058 3073 } 3059 - return pneigh_get_reply(net, pn, NETLINK_CB(in_skb).portid, 3060 - nlh->nlmsg_seq, tbl); 3074 + 3075 + err = pneigh_fill_info(skb, pn, pid, seq, RTM_NEWNEIGH, 0, tbl); 3076 + if (err) 3077 + goto err_unlock; 3078 + } else { 3079 + neigh = neigh_lookup(tbl, dst, dev); 3080 + if (!neigh) { 3081 + NL_SET_ERR_MSG(extack, "Neighbour entry not found"); 3082 + err = -ENOENT; 3083 + goto err_unlock; 3084 + } 3085 + 3086 + err = neigh_fill_info(skb, neigh, pid, seq, RTM_NEWNEIGH, 0); 3087 + neigh_release(neigh); 3088 + if (err) 3089 + goto err_unlock; 3061 3090 } 3062 3091 3063 - if (!dev) { 3064 - NL_SET_ERR_MSG(extack, "No device specified"); 3065 - return -EINVAL; 3066 - } 3092 + rcu_read_unlock(); 3067 3093 3068 - neigh = neigh_lookup(tbl, dst, dev); 3069 - if (!neigh) { 3070 - NL_SET_ERR_MSG(extack, "Neighbour entry not found"); 3071 - return -ENOENT; 3072 - } 3073 - 3074 - err = neigh_get_reply(net, neigh, NETLINK_CB(in_skb).portid, 3075 - nlh->nlmsg_seq); 3076 - 3077 - neigh_release(neigh); 3078 - 3094 + return rtnl_unicast(skb, net, pid); 3095 + err_unlock: 3096 + rcu_read_unlock(); 3097 + kfree_skb(skb); 3079 3098 return err; 3080 3099 } 3081 3100 ··· 3288 3295 3289 3296 state->flags |= NEIGH_SEQ_IS_PNEIGH; 3290 3297 for (bucket = 0; bucket <= PNEIGH_HASHMASK; bucket++) { 3291 - pn = tbl->phash_buckets[bucket]; 3298 + pn = rcu_dereference(tbl->phash_buckets[bucket]); 3299 + 3292 3300 while (pn && !net_eq(pneigh_net(pn), net)) 3293 - pn = pn->next; 3301 + pn = rcu_dereference(pn->next); 3294 3302 if (pn) 3295 3303 break; 3296 3304 } ··· 3309 3315 struct neigh_table *tbl = state->tbl; 3310 3316 3311 3317 do { 3312 - pn = pn->next; 3318 + pn = rcu_dereference(pn->next); 3313 3319 } while (pn && !net_eq(pneigh_net(pn), net)); 3314 3320 3315 3321 while (!pn) { 3316 3322 if (++state->bucket > PNEIGH_HASHMASK) 3317 3323 break; 3318 - pn = tbl->phash_buckets[state->bucket]; 3324 + 3325 + pn = rcu_dereference(tbl->phash_buckets[state->bucket]); 3326 + 3319 3327 while (pn && !net_eq(pneigh_net(pn), net)) 3320 - pn = pn->next; 3328 + pn = rcu_dereference(pn->next); 3321 3329 if (pn) 3322 3330 break; 3323 3331 } ··· 3883 3887 {.msgtype = RTM_NEWNEIGH, .doit = neigh_add}, 3884 3888 {.msgtype = RTM_DELNEIGH, .doit = neigh_delete}, 3885 3889 {.msgtype = RTM_GETNEIGH, .doit = neigh_get, .dumpit = neigh_dump_info, 3886 - .flags = RTNL_FLAG_DUMP_UNLOCKED}, 3890 + .flags = RTNL_FLAG_DOIT_UNLOCKED | RTNL_FLAG_DUMP_UNLOCKED}, 3887 3891 {.msgtype = RTM_GETNEIGHTBL, .dumpit = neightbl_dump_info}, 3888 3892 {.msgtype = RTM_SETNEIGHTBL, .doit = neightbl_set}, 3889 3893 };
+2 -4
net/ipv4/arp.c
··· 864 864 (arp_fwd_proxy(in_dev, dev, rt) || 865 865 arp_fwd_pvlan(in_dev, dev, rt, sip, tip) || 866 866 (rt->dst.dev != dev && 867 - pneigh_lookup(&arp_tbl, net, &tip, dev, 0)))) { 867 + pneigh_lookup(&arp_tbl, net, &tip, dev)))) { 868 868 n = neigh_event_ns(&arp_tbl, sha, &sip, dev); 869 869 if (n) 870 870 neigh_release(n); ··· 1089 1089 if (mask) { 1090 1090 __be32 ip = ((struct sockaddr_in *)&r->arp_pa)->sin_addr.s_addr; 1091 1091 1092 - if (!pneigh_lookup(&arp_tbl, net, &ip, dev, 1)) 1093 - return -ENOBUFS; 1094 - return 0; 1092 + return pneigh_create(&arp_tbl, net, &ip, dev, 0, 0, false); 1095 1093 } 1096 1094 1097 1095 return arp_req_set_proxy(net, dev, 1);
+1 -1
net/ipv6/ip6_output.c
··· 563 563 564 564 /* XXX: idev->cnf.proxy_ndp? */ 565 565 if (READ_ONCE(net->ipv6.devconf_all->proxy_ndp) && 566 - pneigh_lookup(&nd_tbl, net, &hdr->daddr, skb->dev, 0)) { 566 + pneigh_lookup(&nd_tbl, net, &hdr->daddr, skb->dev)) { 567 567 int proxied = ip6_forward_proxy_check(skb); 568 568 if (proxied > 0) { 569 569 /* It's tempting to decrease the hop limit
+3 -5
net/ipv6/ndisc.c
··· 768 768 struct pneigh_entry *n; 769 769 int ret = -1; 770 770 771 - read_lock_bh(&nd_tbl.lock); 772 - n = __pneigh_lookup(&nd_tbl, dev_net(dev), pkey, dev); 771 + n = pneigh_lookup(&nd_tbl, dev_net(dev), pkey, dev); 773 772 if (n) 774 - ret = !!(n->flags & NTF_ROUTER); 775 - read_unlock_bh(&nd_tbl.lock); 773 + ret = !!(READ_ONCE(n->flags) & NTF_ROUTER); 776 774 777 775 return ret; 778 776 } ··· 1098 1100 if (lladdr && !memcmp(lladdr, dev->dev_addr, dev->addr_len) && 1099 1101 READ_ONCE(net->ipv6.devconf_all->forwarding) && 1100 1102 READ_ONCE(net->ipv6.devconf_all->proxy_ndp) && 1101 - pneigh_lookup(&nd_tbl, net, &msg->target, dev, 0)) { 1103 + pneigh_lookup(&nd_tbl, net, &msg->target, dev)) { 1102 1104 /* XXX: idev->cnf.proxy_ndp */ 1103 1105 goto out; 1104 1106 }