Skip to content

Commit

Permalink
Merge branch 'net-neigh-rcu'
Browse files Browse the repository at this point in the history
Eric Dumazet says:

====================
neighbour: convert neigh_dump_info() to RCU

Remove RTNL requirement for "ip neighbour show" command.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
David S. Miller committed Apr 19, 2024
2 parents 9fc31a9 + ba0f780 commit 4cad4ef
Showing 1 changed file with 36 additions and 32 deletions.
68 changes: 36 additions & 32 deletions net/core/neighbour.c
Original file line number Diff line number Diff line change
Expand Up @@ -1771,7 +1771,7 @@ static void neigh_parms_destroy(struct neigh_parms *parms)

static struct lock_class_key neigh_table_proxy_queue_class;

static struct neigh_table *neigh_tables[NEIGH_NR_TABLES] __read_mostly;
static struct neigh_table __rcu *neigh_tables[NEIGH_NR_TABLES] __read_mostly;

void neigh_table_init(int index, struct neigh_table *tbl)
{
Expand Down Expand Up @@ -1828,13 +1828,19 @@ void neigh_table_init(int index, struct neigh_table *tbl)
tbl->last_flush = now;
tbl->last_rand = now + tbl->parms.reachable_time * 20;

neigh_tables[index] = tbl;
rcu_assign_pointer(neigh_tables[index], tbl);
}
EXPORT_SYMBOL(neigh_table_init);

/*
* Only called from ndisc_cleanup(), which means this is dead code
* because we no longer can unload IPv6 module.
*/
int neigh_table_clear(int index, struct neigh_table *tbl)
{
neigh_tables[index] = NULL;
RCU_INIT_POINTER(neigh_tables[index], NULL);
synchronize_rcu();

/* It is not clean... Fix it to unload IPv6 module safely */
cancel_delayed_work_sync(&tbl->managed_work);
cancel_delayed_work_sync(&tbl->gc_work);
Expand Down Expand Up @@ -1866,10 +1872,10 @@ static struct neigh_table *neigh_find_table(int family)

switch (family) {
case AF_INET:
tbl = neigh_tables[NEIGH_ARP_TABLE];
tbl = rcu_dereference_rtnl(neigh_tables[NEIGH_ARP_TABLE]);
break;
case AF_INET6:
tbl = neigh_tables[NEIGH_ND_TABLE];
tbl = rcu_dereference_rtnl(neigh_tables[NEIGH_ND_TABLE]);
break;
}

Expand Down Expand Up @@ -2333,7 +2339,7 @@ static int neightbl_set(struct sk_buff *skb, struct nlmsghdr *nlh,
ndtmsg = nlmsg_data(nlh);

for (tidx = 0; tidx < NEIGH_NR_TABLES; tidx++) {
tbl = neigh_tables[tidx];
tbl = rcu_dereference_rtnl(neigh_tables[tidx]);
if (!tbl)
continue;
if (ndtmsg->ndtm_family && tbl->family != ndtmsg->ndtm_family)
Expand Down Expand Up @@ -2521,7 +2527,7 @@ static int neightbl_dump_info(struct sk_buff *skb, struct netlink_callback *cb)
for (tidx = 0; tidx < NEIGH_NR_TABLES; tidx++) {
struct neigh_parms *p;

tbl = neigh_tables[tidx];
tbl = rcu_dereference_rtnl(neigh_tables[tidx]);
if (!tbl)
continue;

Expand Down Expand Up @@ -2709,15 +2715,14 @@ static int neigh_dump_table(struct neigh_table *tbl, struct sk_buff *skb,
{
struct net *net = sock_net(skb->sk);
struct neighbour *n;
int rc, h, s_h = cb->args[1];
int err = 0, h, s_h = cb->args[1];
int idx, s_idx = idx = cb->args[2];
struct neigh_hash_table *nht;
unsigned int flags = NLM_F_MULTI;

if (filter->dev_idx || filter->master_idx)
flags |= NLM_F_DUMP_FILTERED;

rcu_read_lock();
nht = rcu_dereference(tbl->nht);

for (h = s_h; h < (1 << nht->hash_shift); h++) {
Expand All @@ -2731,23 +2736,19 @@ static int neigh_dump_table(struct neigh_table *tbl, struct sk_buff *skb,
if (neigh_ifindex_filtered(n->dev, filter->dev_idx) ||
neigh_master_filtered(n->dev, filter->master_idx))
goto next;
if (neigh_fill_info(skb, n, NETLINK_CB(cb->skb).portid,
cb->nlh->nlmsg_seq,
RTM_NEWNEIGH,
flags) < 0) {
rc = -1;
err = neigh_fill_info(skb, n, NETLINK_CB(cb->skb).portid,
cb->nlh->nlmsg_seq,
RTM_NEWNEIGH, flags);
if (err < 0)
goto out;
}
next:
idx++;
}
}
rc = skb->len;
out:
rcu_read_unlock();
cb->args[1] = h;
cb->args[2] = idx;
return rc;
return err;
}

static int pneigh_dump_table(struct neigh_table *tbl, struct sk_buff *skb,
Expand All @@ -2756,7 +2757,7 @@ static int pneigh_dump_table(struct neigh_table *tbl, struct sk_buff *skb,
{
struct pneigh_entry *n;
struct net *net = sock_net(skb->sk);
int rc, h, s_h = cb->args[3];
int err = 0, h, s_h = cb->args[3];
int idx, s_idx = idx = cb->args[4];
unsigned int flags = NLM_F_MULTI;

Expand All @@ -2774,11 +2775,11 @@ static int pneigh_dump_table(struct neigh_table *tbl, struct sk_buff *skb,
if (neigh_ifindex_filtered(n->dev, filter->dev_idx) ||
neigh_master_filtered(n->dev, filter->master_idx))
goto next;
if (pneigh_fill_info(skb, n, NETLINK_CB(cb->skb).portid,
cb->nlh->nlmsg_seq,
RTM_NEWNEIGH, flags, tbl) < 0) {
err = pneigh_fill_info(skb, n, NETLINK_CB(cb->skb).portid,
cb->nlh->nlmsg_seq,
RTM_NEWNEIGH, flags, tbl);
if (err < 0) {
read_unlock_bh(&tbl->lock);
rc = -1;
goto out;
}
next:
Expand All @@ -2787,12 +2788,10 @@ static int pneigh_dump_table(struct neigh_table *tbl, struct sk_buff *skb,
}

read_unlock_bh(&tbl->lock);
rc = skb->len;
out:
cb->args[3] = h;
cb->args[4] = idx;
return rc;

return err;
}

static int neigh_valid_dump_req(const struct nlmsghdr *nlh,
Expand Down Expand Up @@ -2880,8 +2879,9 @@ static int neigh_dump_info(struct sk_buff *skb, struct netlink_callback *cb)

s_t = cb->args[0];

rcu_read_lock();
for (t = 0; t < NEIGH_NR_TABLES; t++) {
tbl = neigh_tables[t];
tbl = rcu_dereference(neigh_tables[t]);

if (!tbl)
continue;
Expand All @@ -2897,9 +2897,10 @@ static int neigh_dump_info(struct sk_buff *skb, struct netlink_callback *cb)
if (err < 0)
break;
}
rcu_read_unlock();

cb->args[0] = t;
return skb->len;
return err;
}

static int neigh_valid_get_req(const struct nlmsghdr *nlh,
Expand Down Expand Up @@ -3145,14 +3146,15 @@ int neigh_xmit(int index, struct net_device *dev,
const void *addr, struct sk_buff *skb)
{
int err = -EAFNOSUPPORT;

if (likely(index < NEIGH_NR_TABLES)) {
struct neigh_table *tbl;
struct neighbour *neigh;

tbl = neigh_tables[index];
if (!tbl)
goto out;
rcu_read_lock();
tbl = rcu_dereference(neigh_tables[index]);
if (!tbl)
goto out_unlock;
if (index == NEIGH_ARP_TABLE) {
u32 key = *((u32 *)addr);

Expand All @@ -3168,6 +3170,7 @@ int neigh_xmit(int index, struct net_device *dev,
goto out_kfree_skb;
}
err = READ_ONCE(neigh->output)(neigh, skb);
out_unlock:
rcu_read_unlock();
}
else if (index == NEIGH_LINK_TABLE) {
Expand Down Expand Up @@ -3891,7 +3894,8 @@ static int __init neigh_init(void)
{
rtnl_register(PF_UNSPEC, RTM_NEWNEIGH, neigh_add, NULL, 0);
rtnl_register(PF_UNSPEC, RTM_DELNEIGH, neigh_delete, NULL, 0);
rtnl_register(PF_UNSPEC, RTM_GETNEIGH, neigh_get, neigh_dump_info, 0);
rtnl_register(PF_UNSPEC, RTM_GETNEIGH, neigh_get, neigh_dump_info,
RTNL_FLAG_DUMP_UNLOCKED);

rtnl_register(PF_UNSPEC, RTM_GETNEIGHTBL, NULL, neightbl_dump_info,
0);
Expand Down

0 comments on commit 4cad4ef

Please sign in to comment.