Commit 4cad4efa authored by David S. Miller's avatar David S. Miller

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: default avatarDavid S. Miller <davem@davemloft.net>
parents 9fc31a92 ba0f7806
...@@ -1771,7 +1771,7 @@ static void neigh_parms_destroy(struct neigh_parms *parms) ...@@ -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 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) void neigh_table_init(int index, struct neigh_table *tbl)
{ {
...@@ -1828,13 +1828,19 @@ void neigh_table_init(int index, struct neigh_table *tbl) ...@@ -1828,13 +1828,19 @@ void neigh_table_init(int index, struct neigh_table *tbl)
tbl->last_flush = now; tbl->last_flush = now;
tbl->last_rand = now + tbl->parms.reachable_time * 20; 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); 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) 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 */ /* It is not clean... Fix it to unload IPv6 module safely */
cancel_delayed_work_sync(&tbl->managed_work); cancel_delayed_work_sync(&tbl->managed_work);
cancel_delayed_work_sync(&tbl->gc_work); cancel_delayed_work_sync(&tbl->gc_work);
...@@ -1866,10 +1872,10 @@ static struct neigh_table *neigh_find_table(int family) ...@@ -1866,10 +1872,10 @@ static struct neigh_table *neigh_find_table(int family)
switch (family) { switch (family) {
case AF_INET: case AF_INET:
tbl = neigh_tables[NEIGH_ARP_TABLE]; tbl = rcu_dereference_rtnl(neigh_tables[NEIGH_ARP_TABLE]);
break; break;
case AF_INET6: case AF_INET6:
tbl = neigh_tables[NEIGH_ND_TABLE]; tbl = rcu_dereference_rtnl(neigh_tables[NEIGH_ND_TABLE]);
break; break;
} }
...@@ -2333,7 +2339,7 @@ static int neightbl_set(struct sk_buff *skb, struct nlmsghdr *nlh, ...@@ -2333,7 +2339,7 @@ static int neightbl_set(struct sk_buff *skb, struct nlmsghdr *nlh,
ndtmsg = nlmsg_data(nlh); ndtmsg = nlmsg_data(nlh);
for (tidx = 0; tidx < NEIGH_NR_TABLES; tidx++) { for (tidx = 0; tidx < NEIGH_NR_TABLES; tidx++) {
tbl = neigh_tables[tidx]; tbl = rcu_dereference_rtnl(neigh_tables[tidx]);
if (!tbl) if (!tbl)
continue; continue;
if (ndtmsg->ndtm_family && tbl->family != ndtmsg->ndtm_family) 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,7 +2527,7 @@ static int neightbl_dump_info(struct sk_buff *skb, struct netlink_callback *cb)
for (tidx = 0; tidx < NEIGH_NR_TABLES; tidx++) { for (tidx = 0; tidx < NEIGH_NR_TABLES; tidx++) {
struct neigh_parms *p; struct neigh_parms *p;
tbl = neigh_tables[tidx]; tbl = rcu_dereference_rtnl(neigh_tables[tidx]);
if (!tbl) if (!tbl)
continue; continue;
...@@ -2709,7 +2715,7 @@ static int neigh_dump_table(struct neigh_table *tbl, struct sk_buff *skb, ...@@ -2709,7 +2715,7 @@ static int neigh_dump_table(struct neigh_table *tbl, struct sk_buff *skb,
{ {
struct net *net = sock_net(skb->sk); struct net *net = sock_net(skb->sk);
struct neighbour *n; 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]; int idx, s_idx = idx = cb->args[2];
struct neigh_hash_table *nht; struct neigh_hash_table *nht;
unsigned int flags = NLM_F_MULTI; unsigned int flags = NLM_F_MULTI;
...@@ -2717,7 +2723,6 @@ static int neigh_dump_table(struct neigh_table *tbl, struct sk_buff *skb, ...@@ -2717,7 +2723,6 @@ static int neigh_dump_table(struct neigh_table *tbl, struct sk_buff *skb,
if (filter->dev_idx || filter->master_idx) if (filter->dev_idx || filter->master_idx)
flags |= NLM_F_DUMP_FILTERED; flags |= NLM_F_DUMP_FILTERED;
rcu_read_lock();
nht = rcu_dereference(tbl->nht); nht = rcu_dereference(tbl->nht);
for (h = s_h; h < (1 << nht->hash_shift); h++) { 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,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) || if (neigh_ifindex_filtered(n->dev, filter->dev_idx) ||
neigh_master_filtered(n->dev, filter->master_idx)) neigh_master_filtered(n->dev, filter->master_idx))
goto next; goto next;
if (neigh_fill_info(skb, n, NETLINK_CB(cb->skb).portid, err = neigh_fill_info(skb, n, NETLINK_CB(cb->skb).portid,
cb->nlh->nlmsg_seq, cb->nlh->nlmsg_seq,
RTM_NEWNEIGH, RTM_NEWNEIGH, flags);
flags) < 0) { if (err < 0)
rc = -1;
goto out; goto out;
}
next: next:
idx++; idx++;
} }
} }
rc = skb->len;
out: out:
rcu_read_unlock();
cb->args[1] = h; cb->args[1] = h;
cb->args[2] = idx; cb->args[2] = idx;
return rc; return err;
} }
static int pneigh_dump_table(struct neigh_table *tbl, struct sk_buff *skb, 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,7 +2757,7 @@ static int pneigh_dump_table(struct neigh_table *tbl, struct sk_buff *skb,
{ {
struct pneigh_entry *n; struct pneigh_entry *n;
struct net *net = sock_net(skb->sk); 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]; int idx, s_idx = idx = cb->args[4];
unsigned int flags = NLM_F_MULTI; unsigned int flags = NLM_F_MULTI;
...@@ -2774,11 +2775,11 @@ static int pneigh_dump_table(struct neigh_table *tbl, struct sk_buff *skb, ...@@ -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) || if (neigh_ifindex_filtered(n->dev, filter->dev_idx) ||
neigh_master_filtered(n->dev, filter->master_idx)) neigh_master_filtered(n->dev, filter->master_idx))
goto next; goto next;
if (pneigh_fill_info(skb, n, NETLINK_CB(cb->skb).portid, err = pneigh_fill_info(skb, n, NETLINK_CB(cb->skb).portid,
cb->nlh->nlmsg_seq, cb->nlh->nlmsg_seq,
RTM_NEWNEIGH, flags, tbl) < 0) { RTM_NEWNEIGH, flags, tbl);
if (err < 0) {
read_unlock_bh(&tbl->lock); read_unlock_bh(&tbl->lock);
rc = -1;
goto out; goto out;
} }
next: next:
...@@ -2787,12 +2788,10 @@ static int pneigh_dump_table(struct neigh_table *tbl, struct sk_buff *skb, ...@@ -2787,12 +2788,10 @@ static int pneigh_dump_table(struct neigh_table *tbl, struct sk_buff *skb,
} }
read_unlock_bh(&tbl->lock); read_unlock_bh(&tbl->lock);
rc = skb->len;
out: out:
cb->args[3] = h; cb->args[3] = h;
cb->args[4] = idx; cb->args[4] = idx;
return rc; return err;
} }
static int neigh_valid_dump_req(const struct nlmsghdr *nlh, 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,8 +2879,9 @@ static int neigh_dump_info(struct sk_buff *skb, struct netlink_callback *cb)
s_t = cb->args[0]; s_t = cb->args[0];
rcu_read_lock();
for (t = 0; t < NEIGH_NR_TABLES; t++) { for (t = 0; t < NEIGH_NR_TABLES; t++) {
tbl = neigh_tables[t]; tbl = rcu_dereference(neigh_tables[t]);
if (!tbl) if (!tbl)
continue; continue;
...@@ -2897,9 +2897,10 @@ static int neigh_dump_info(struct sk_buff *skb, struct netlink_callback *cb) ...@@ -2897,9 +2897,10 @@ static int neigh_dump_info(struct sk_buff *skb, struct netlink_callback *cb)
if (err < 0) if (err < 0)
break; break;
} }
rcu_read_unlock();
cb->args[0] = t; cb->args[0] = t;
return skb->len; return err;
} }
static int neigh_valid_get_req(const struct nlmsghdr *nlh, static int neigh_valid_get_req(const struct nlmsghdr *nlh,
...@@ -3145,14 +3146,15 @@ int neigh_xmit(int index, struct net_device *dev, ...@@ -3145,14 +3146,15 @@ int neigh_xmit(int index, struct net_device *dev,
const void *addr, struct sk_buff *skb) const void *addr, struct sk_buff *skb)
{ {
int err = -EAFNOSUPPORT; int err = -EAFNOSUPPORT;
if (likely(index < NEIGH_NR_TABLES)) { if (likely(index < NEIGH_NR_TABLES)) {
struct neigh_table *tbl; struct neigh_table *tbl;
struct neighbour *neigh; struct neighbour *neigh;
tbl = neigh_tables[index];
if (!tbl)
goto out;
rcu_read_lock(); rcu_read_lock();
tbl = rcu_dereference(neigh_tables[index]);
if (!tbl)
goto out_unlock;
if (index == NEIGH_ARP_TABLE) { if (index == NEIGH_ARP_TABLE) {
u32 key = *((u32 *)addr); u32 key = *((u32 *)addr);
...@@ -3168,6 +3170,7 @@ int neigh_xmit(int index, struct net_device *dev, ...@@ -3168,6 +3170,7 @@ int neigh_xmit(int index, struct net_device *dev,
goto out_kfree_skb; goto out_kfree_skb;
} }
err = READ_ONCE(neigh->output)(neigh, skb); err = READ_ONCE(neigh->output)(neigh, skb);
out_unlock:
rcu_read_unlock(); rcu_read_unlock();
} }
else if (index == NEIGH_LINK_TABLE) { else if (index == NEIGH_LINK_TABLE) {
...@@ -3891,7 +3894,8 @@ static int __init neigh_init(void) ...@@ -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_NEWNEIGH, neigh_add, NULL, 0);
rtnl_register(PF_UNSPEC, RTM_DELNEIGH, neigh_delete, 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, rtnl_register(PF_UNSPEC, RTM_GETNEIGHTBL, NULL, neightbl_dump_info,
0); 0);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment