@@ -1771,7 +1771,7 @@ static void neigh_parms_destroy(struct neigh_parms *parms)
1771
1771
1772
1772
static struct lock_class_key neigh_table_proxy_queue_class ;
1773
1773
1774
- static struct neigh_table * neigh_tables [NEIGH_NR_TABLES ] __read_mostly ;
1774
+ static struct neigh_table __rcu * neigh_tables [NEIGH_NR_TABLES ] __read_mostly ;
1775
1775
1776
1776
void neigh_table_init (int index , struct neigh_table * tbl )
1777
1777
{
@@ -1828,13 +1828,19 @@ void neigh_table_init(int index, struct neigh_table *tbl)
1828
1828
tbl -> last_flush = now ;
1829
1829
tbl -> last_rand = now + tbl -> parms .reachable_time * 20 ;
1830
1830
1831
- neigh_tables [index ] = tbl ;
1831
+ rcu_assign_pointer ( neigh_tables [index ], tbl ) ;
1832
1832
}
1833
1833
EXPORT_SYMBOL (neigh_table_init );
1834
1834
1835
+ /*
1836
+ * Only called from ndisc_cleanup(), which means this is dead code
1837
+ * because we no longer can unload IPv6 module.
1838
+ */
1835
1839
int neigh_table_clear (int index , struct neigh_table * tbl )
1836
1840
{
1837
- neigh_tables [index ] = NULL ;
1841
+ RCU_INIT_POINTER (neigh_tables [index ], NULL );
1842
+ synchronize_rcu ();
1843
+
1838
1844
/* It is not clean... Fix it to unload IPv6 module safely */
1839
1845
cancel_delayed_work_sync (& tbl -> managed_work );
1840
1846
cancel_delayed_work_sync (& tbl -> gc_work );
@@ -1866,10 +1872,10 @@ static struct neigh_table *neigh_find_table(int family)
1866
1872
1867
1873
switch (family ) {
1868
1874
case AF_INET :
1869
- tbl = neigh_tables [NEIGH_ARP_TABLE ];
1875
+ tbl = rcu_dereference_rtnl ( neigh_tables [NEIGH_ARP_TABLE ]) ;
1870
1876
break ;
1871
1877
case AF_INET6 :
1872
- tbl = neigh_tables [NEIGH_ND_TABLE ];
1878
+ tbl = rcu_dereference_rtnl ( neigh_tables [NEIGH_ND_TABLE ]) ;
1873
1879
break ;
1874
1880
}
1875
1881
@@ -2333,7 +2339,7 @@ static int neightbl_set(struct sk_buff *skb, struct nlmsghdr *nlh,
2333
2339
ndtmsg = nlmsg_data (nlh );
2334
2340
2335
2341
for (tidx = 0 ; tidx < NEIGH_NR_TABLES ; tidx ++ ) {
2336
- tbl = neigh_tables [tidx ];
2342
+ tbl = rcu_dereference_rtnl ( neigh_tables [tidx ]) ;
2337
2343
if (!tbl )
2338
2344
continue ;
2339
2345
if (ndtmsg -> ndtm_family && tbl -> family != ndtmsg -> ndtm_family )
@@ -2521,7 +2527,7 @@ static int neightbl_dump_info(struct sk_buff *skb, struct netlink_callback *cb)
2521
2527
for (tidx = 0 ; tidx < NEIGH_NR_TABLES ; tidx ++ ) {
2522
2528
struct neigh_parms * p ;
2523
2529
2524
- tbl = neigh_tables [tidx ];
2530
+ tbl = rcu_dereference_rtnl ( neigh_tables [tidx ]) ;
2525
2531
if (!tbl )
2526
2532
continue ;
2527
2533
@@ -2709,15 +2715,14 @@ static int neigh_dump_table(struct neigh_table *tbl, struct sk_buff *skb,
2709
2715
{
2710
2716
struct net * net = sock_net (skb -> sk );
2711
2717
struct neighbour * n ;
2712
- int rc , h , s_h = cb -> args [1 ];
2718
+ int err = 0 , h , s_h = cb -> args [1 ];
2713
2719
int idx , s_idx = idx = cb -> args [2 ];
2714
2720
struct neigh_hash_table * nht ;
2715
2721
unsigned int flags = NLM_F_MULTI ;
2716
2722
2717
2723
if (filter -> dev_idx || filter -> master_idx )
2718
2724
flags |= NLM_F_DUMP_FILTERED ;
2719
2725
2720
- rcu_read_lock ();
2721
2726
nht = rcu_dereference (tbl -> nht );
2722
2727
2723
2728
for (h = s_h ; h < (1 << nht -> hash_shift ); h ++ ) {
@@ -2731,23 +2736,19 @@ static int neigh_dump_table(struct neigh_table *tbl, struct sk_buff *skb,
2731
2736
if (neigh_ifindex_filtered (n -> dev , filter -> dev_idx ) ||
2732
2737
neigh_master_filtered (n -> dev , filter -> master_idx ))
2733
2738
goto next ;
2734
- if (neigh_fill_info (skb , n , NETLINK_CB (cb -> skb ).portid ,
2735
- cb -> nlh -> nlmsg_seq ,
2736
- RTM_NEWNEIGH ,
2737
- flags ) < 0 ) {
2738
- rc = -1 ;
2739
+ err = neigh_fill_info (skb , n , NETLINK_CB (cb -> skb ).portid ,
2740
+ cb -> nlh -> nlmsg_seq ,
2741
+ RTM_NEWNEIGH , flags );
2742
+ if (err < 0 )
2739
2743
goto out ;
2740
- }
2741
2744
next :
2742
2745
idx ++ ;
2743
2746
}
2744
2747
}
2745
- rc = skb -> len ;
2746
2748
out :
2747
- rcu_read_unlock ();
2748
2749
cb -> args [1 ] = h ;
2749
2750
cb -> args [2 ] = idx ;
2750
- return rc ;
2751
+ return err ;
2751
2752
}
2752
2753
2753
2754
static int pneigh_dump_table (struct neigh_table * tbl , struct sk_buff * skb ,
@@ -2756,7 +2757,7 @@ static int pneigh_dump_table(struct neigh_table *tbl, struct sk_buff *skb,
2756
2757
{
2757
2758
struct pneigh_entry * n ;
2758
2759
struct net * net = sock_net (skb -> sk );
2759
- int rc , h , s_h = cb -> args [3 ];
2760
+ int err = 0 , h , s_h = cb -> args [3 ];
2760
2761
int idx , s_idx = idx = cb -> args [4 ];
2761
2762
unsigned int flags = NLM_F_MULTI ;
2762
2763
@@ -2774,11 +2775,11 @@ static int pneigh_dump_table(struct neigh_table *tbl, struct sk_buff *skb,
2774
2775
if (neigh_ifindex_filtered (n -> dev , filter -> dev_idx ) ||
2775
2776
neigh_master_filtered (n -> dev , filter -> master_idx ))
2776
2777
goto next ;
2777
- if (pneigh_fill_info (skb , n , NETLINK_CB (cb -> skb ).portid ,
2778
- cb -> nlh -> nlmsg_seq ,
2779
- RTM_NEWNEIGH , flags , tbl ) < 0 ) {
2778
+ err = pneigh_fill_info (skb , n , NETLINK_CB (cb -> skb ).portid ,
2779
+ cb -> nlh -> nlmsg_seq ,
2780
+ RTM_NEWNEIGH , flags , tbl );
2781
+ if (err < 0 ) {
2780
2782
read_unlock_bh (& tbl -> lock );
2781
- rc = -1 ;
2782
2783
goto out ;
2783
2784
}
2784
2785
next :
@@ -2787,12 +2788,10 @@ static int pneigh_dump_table(struct neigh_table *tbl, struct sk_buff *skb,
2787
2788
}
2788
2789
2789
2790
read_unlock_bh (& tbl -> lock );
2790
- rc = skb -> len ;
2791
2791
out :
2792
2792
cb -> args [3 ] = h ;
2793
2793
cb -> args [4 ] = idx ;
2794
- return rc ;
2795
-
2794
+ return err ;
2796
2795
}
2797
2796
2798
2797
static int neigh_valid_dump_req (const struct nlmsghdr * nlh ,
@@ -2880,8 +2879,9 @@ static int neigh_dump_info(struct sk_buff *skb, struct netlink_callback *cb)
2880
2879
2881
2880
s_t = cb -> args [0 ];
2882
2881
2882
+ rcu_read_lock ();
2883
2883
for (t = 0 ; t < NEIGH_NR_TABLES ; t ++ ) {
2884
- tbl = neigh_tables [t ];
2884
+ tbl = rcu_dereference ( neigh_tables [t ]) ;
2885
2885
2886
2886
if (!tbl )
2887
2887
continue ;
@@ -2897,9 +2897,10 @@ static int neigh_dump_info(struct sk_buff *skb, struct netlink_callback *cb)
2897
2897
if (err < 0 )
2898
2898
break ;
2899
2899
}
2900
+ rcu_read_unlock ();
2900
2901
2901
2902
cb -> args [0 ] = t ;
2902
- return skb -> len ;
2903
+ return err ;
2903
2904
}
2904
2905
2905
2906
static int neigh_valid_get_req (const struct nlmsghdr * nlh ,
@@ -3145,14 +3146,15 @@ int neigh_xmit(int index, struct net_device *dev,
3145
3146
const void * addr , struct sk_buff * skb )
3146
3147
{
3147
3148
int err = - EAFNOSUPPORT ;
3149
+
3148
3150
if (likely (index < NEIGH_NR_TABLES )) {
3149
3151
struct neigh_table * tbl ;
3150
3152
struct neighbour * neigh ;
3151
3153
3152
- tbl = neigh_tables [index ];
3153
- if (!tbl )
3154
- goto out ;
3155
3154
rcu_read_lock ();
3155
+ tbl = rcu_dereference (neigh_tables [index ]);
3156
+ if (!tbl )
3157
+ goto out_unlock ;
3156
3158
if (index == NEIGH_ARP_TABLE ) {
3157
3159
u32 key = * ((u32 * )addr );
3158
3160
@@ -3168,6 +3170,7 @@ int neigh_xmit(int index, struct net_device *dev,
3168
3170
goto out_kfree_skb ;
3169
3171
}
3170
3172
err = READ_ONCE (neigh -> output )(neigh , skb );
3173
+ out_unlock :
3171
3174
rcu_read_unlock ();
3172
3175
}
3173
3176
else if (index == NEIGH_LINK_TABLE ) {
@@ -3891,7 +3894,8 @@ static int __init neigh_init(void)
3891
3894
{
3892
3895
rtnl_register (PF_UNSPEC , RTM_NEWNEIGH , neigh_add , NULL , 0 );
3893
3896
rtnl_register (PF_UNSPEC , RTM_DELNEIGH , neigh_delete , NULL , 0 );
3894
- rtnl_register (PF_UNSPEC , RTM_GETNEIGH , neigh_get , neigh_dump_info , 0 );
3897
+ rtnl_register (PF_UNSPEC , RTM_GETNEIGH , neigh_get , neigh_dump_info ,
3898
+ RTNL_FLAG_DUMP_UNLOCKED );
3895
3899
3896
3900
rtnl_register (PF_UNSPEC , RTM_GETNEIGHTBL , NULL , neightbl_dump_info ,
3897
3901
0 );
0 commit comments