@@ -1771,7 +1771,7 @@ static void neigh_parms_destroy(struct neigh_parms *parms)
17711771
17721772static struct lock_class_key neigh_table_proxy_queue_class ;
17731773
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 ;
17751775
17761776void neigh_table_init (int index , struct neigh_table * tbl )
17771777{
@@ -1828,13 +1828,19 @@ void neigh_table_init(int index, struct neigh_table *tbl)
18281828 tbl -> last_flush = now ;
18291829 tbl -> last_rand = now + tbl -> parms .reachable_time * 20 ;
18301830
1831- neigh_tables [index ] = tbl ;
1831+ rcu_assign_pointer ( neigh_tables [index ], tbl ) ;
18321832}
18331833EXPORT_SYMBOL (neigh_table_init );
18341834
1835+ /*
1836+ * Only called from ndisc_cleanup(), which means this is dead code
1837+ * because we no longer can unload IPv6 module.
1838+ */
18351839int neigh_table_clear (int index , struct neigh_table * tbl )
18361840{
1837- neigh_tables [index ] = NULL ;
1841+ RCU_INIT_POINTER (neigh_tables [index ], NULL );
1842+ synchronize_rcu ();
1843+
18381844 /* It is not clean... Fix it to unload IPv6 module safely */
18391845 cancel_delayed_work_sync (& tbl -> managed_work );
18401846 cancel_delayed_work_sync (& tbl -> gc_work );
@@ -1866,10 +1872,10 @@ static struct neigh_table *neigh_find_table(int family)
18661872
18671873 switch (family ) {
18681874 case AF_INET :
1869- tbl = neigh_tables [NEIGH_ARP_TABLE ];
1875+ tbl = rcu_dereference_rtnl ( neigh_tables [NEIGH_ARP_TABLE ]) ;
18701876 break ;
18711877 case AF_INET6 :
1872- tbl = neigh_tables [NEIGH_ND_TABLE ];
1878+ tbl = rcu_dereference_rtnl ( neigh_tables [NEIGH_ND_TABLE ]) ;
18731879 break ;
18741880 }
18751881
@@ -2333,7 +2339,7 @@ static int neightbl_set(struct sk_buff *skb, struct nlmsghdr *nlh,
23332339 ndtmsg = nlmsg_data (nlh );
23342340
23352341 for (tidx = 0 ; tidx < NEIGH_NR_TABLES ; tidx ++ ) {
2336- tbl = neigh_tables [tidx ];
2342+ tbl = rcu_dereference_rtnl ( neigh_tables [tidx ]) ;
23372343 if (!tbl )
23382344 continue ;
23392345 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)
25212527 for (tidx = 0 ; tidx < NEIGH_NR_TABLES ; tidx ++ ) {
25222528 struct neigh_parms * p ;
25232529
2524- tbl = neigh_tables [tidx ];
2530+ tbl = rcu_dereference_rtnl ( neigh_tables [tidx ]) ;
25252531 if (!tbl )
25262532 continue ;
25272533
@@ -2709,15 +2715,14 @@ static int neigh_dump_table(struct neigh_table *tbl, struct sk_buff *skb,
27092715{
27102716 struct net * net = sock_net (skb -> sk );
27112717 struct neighbour * n ;
2712- int rc , h , s_h = cb -> args [1 ];
2718+ int err = 0 , h , s_h = cb -> args [1 ];
27132719 int idx , s_idx = idx = cb -> args [2 ];
27142720 struct neigh_hash_table * nht ;
27152721 unsigned int flags = NLM_F_MULTI ;
27162722
27172723 if (filter -> dev_idx || filter -> master_idx )
27182724 flags |= NLM_F_DUMP_FILTERED ;
27192725
2720- rcu_read_lock ();
27212726 nht = rcu_dereference (tbl -> nht );
27222727
27232728 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,
27312736 if (neigh_ifindex_filtered (n -> dev , filter -> dev_idx ) ||
27322737 neigh_master_filtered (n -> dev , filter -> master_idx ))
27332738 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 )
27392743 goto out ;
2740- }
27412744next :
27422745 idx ++ ;
27432746 }
27442747 }
2745- rc = skb -> len ;
27462748out :
2747- rcu_read_unlock ();
27482749 cb -> args [1 ] = h ;
27492750 cb -> args [2 ] = idx ;
2750- return rc ;
2751+ return err ;
27512752}
27522753
27532754static 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,
27562757{
27572758 struct pneigh_entry * n ;
27582759 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 ];
27602761 int idx , s_idx = idx = cb -> args [4 ];
27612762 unsigned int flags = NLM_F_MULTI ;
27622763
@@ -2774,11 +2775,11 @@ static int pneigh_dump_table(struct neigh_table *tbl, struct sk_buff *skb,
27742775 if (neigh_ifindex_filtered (n -> dev , filter -> dev_idx ) ||
27752776 neigh_master_filtered (n -> dev , filter -> master_idx ))
27762777 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 ) {
27802782 read_unlock_bh (& tbl -> lock );
2781- rc = -1 ;
27822783 goto out ;
27832784 }
27842785 next :
@@ -2787,12 +2788,10 @@ static int pneigh_dump_table(struct neigh_table *tbl, struct sk_buff *skb,
27872788 }
27882789
27892790 read_unlock_bh (& tbl -> lock );
2790- rc = skb -> len ;
27912791out :
27922792 cb -> args [3 ] = h ;
27932793 cb -> args [4 ] = idx ;
2794- return rc ;
2795-
2794+ return err ;
27962795}
27972796
27982797static 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)
28802879
28812880 s_t = cb -> args [0 ];
28822881
2882+ rcu_read_lock ();
28832883 for (t = 0 ; t < NEIGH_NR_TABLES ; t ++ ) {
2884- tbl = neigh_tables [t ];
2884+ tbl = rcu_dereference ( neigh_tables [t ]) ;
28852885
28862886 if (!tbl )
28872887 continue ;
@@ -2897,9 +2897,10 @@ static int neigh_dump_info(struct sk_buff *skb, struct netlink_callback *cb)
28972897 if (err < 0 )
28982898 break ;
28992899 }
2900+ rcu_read_unlock ();
29002901
29012902 cb -> args [0 ] = t ;
2902- return skb -> len ;
2903+ return err ;
29032904}
29042905
29052906static int neigh_valid_get_req (const struct nlmsghdr * nlh ,
@@ -3145,14 +3146,15 @@ int neigh_xmit(int index, struct net_device *dev,
31453146 const void * addr , struct sk_buff * skb )
31463147{
31473148 int err = - EAFNOSUPPORT ;
3149+
31483150 if (likely (index < NEIGH_NR_TABLES )) {
31493151 struct neigh_table * tbl ;
31503152 struct neighbour * neigh ;
31513153
3152- tbl = neigh_tables [index ];
3153- if (!tbl )
3154- goto out ;
31553154 rcu_read_lock ();
3155+ tbl = rcu_dereference (neigh_tables [index ]);
3156+ if (!tbl )
3157+ goto out_unlock ;
31563158 if (index == NEIGH_ARP_TABLE ) {
31573159 u32 key = * ((u32 * )addr );
31583160
@@ -3168,6 +3170,7 @@ int neigh_xmit(int index, struct net_device *dev,
31683170 goto out_kfree_skb ;
31693171 }
31703172 err = READ_ONCE (neigh -> output )(neigh , skb );
3173+ out_unlock :
31713174 rcu_read_unlock ();
31723175 }
31733176 else if (index == NEIGH_LINK_TABLE ) {
@@ -3891,7 +3894,8 @@ static int __init neigh_init(void)
38913894{
38923895 rtnl_register (PF_UNSPEC , RTM_NEWNEIGH , neigh_add , NULL , 0 );
38933896 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 );
38953899
38963900 rtnl_register (PF_UNSPEC , RTM_GETNEIGHTBL , NULL , neightbl_dump_info ,
38973901 0 );
0 commit comments