Skip to content

Commit 4cad4ef

Browse files
committedApr 19, 2024
Merge branch 'net-neigh-rcu'
Eric Dumazet says: ==================== neighbour: convert neigh_dump_info() to RCU Remove RTNL requirement for "ip neighbour show" command. ==================== Signed-off-by: David S. Miller <[email protected]>
2 parents 9fc31a9 + ba0f780 commit 4cad4ef

File tree

1 file changed

+36
-32
lines changed

1 file changed

+36
-32
lines changed
 

‎net/core/neighbour.c

+36-32
Original file line numberDiff line numberDiff line change
@@ -1771,7 +1771,7 @@ static void neigh_parms_destroy(struct neigh_parms *parms)
17711771

17721772
static 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

17761776
void 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
}
18331833
EXPORT_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+
*/
18351839
int 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-
}
27412744
next:
27422745
idx++;
27432746
}
27442747
}
2745-
rc = skb->len;
27462748
out:
2747-
rcu_read_unlock();
27482749
cb->args[1] = h;
27492750
cb->args[2] = idx;
2750-
return rc;
2751+
return err;
27512752
}
27522753

27532754
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,
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;
27912791
out:
27922792
cb->args[3] = h;
27932793
cb->args[4] = idx;
2794-
return rc;
2795-
2794+
return err;
27962795
}
27972796

27982797
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)
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

29052906
static 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

Comments
 (0)
Please sign in to comment.