Commit e0f89d28 authored by Eric Dumazet's avatar Eric Dumazet Committed by Jakub Kicinski

mpls: no longer hold RTNL in mpls_netconf_dump_devconf()

- Use for_each_netdev_dump() to no longer rely
  on net->dev_index_head hash table.

- No longer care of net->dev_base_seq

- Fix return value at the end of a dump,
  so that NLMSG_DONE can be appended to current skb,
  saving one recvmsg() system call.

- No longer grab RTNL, RCU protection is enough,
  afer adding one READ_ONCE(mdev->input_enabled)
  in mpls_netconf_fill_devconf()
Signed-off-by: default avatarEric Dumazet <edumazet@google.com>
Link: https://lore.kernel.org/r/20240410111951.2673193-1-edumazet@google.comSigned-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parent e1eb10f8
...@@ -1154,7 +1154,7 @@ static int mpls_netconf_fill_devconf(struct sk_buff *skb, struct mpls_dev *mdev, ...@@ -1154,7 +1154,7 @@ static int mpls_netconf_fill_devconf(struct sk_buff *skb, struct mpls_dev *mdev,
if ((all || type == NETCONFA_INPUT) && if ((all || type == NETCONFA_INPUT) &&
nla_put_s32(skb, NETCONFA_INPUT, nla_put_s32(skb, NETCONFA_INPUT,
mdev->input_enabled) < 0) READ_ONCE(mdev->input_enabled)) < 0)
goto nla_put_failure; goto nla_put_failure;
nlmsg_end(skb, nlh); nlmsg_end(skb, nlh);
...@@ -1303,11 +1303,12 @@ static int mpls_netconf_dump_devconf(struct sk_buff *skb, ...@@ -1303,11 +1303,12 @@ static int mpls_netconf_dump_devconf(struct sk_buff *skb,
{ {
const struct nlmsghdr *nlh = cb->nlh; const struct nlmsghdr *nlh = cb->nlh;
struct net *net = sock_net(skb->sk); struct net *net = sock_net(skb->sk);
struct hlist_head *head; struct {
unsigned long ifindex;
} *ctx = (void *)cb->ctx;
struct net_device *dev; struct net_device *dev;
struct mpls_dev *mdev; struct mpls_dev *mdev;
int idx, s_idx; int err = 0;
int h, s_h;
if (cb->strict_check) { if (cb->strict_check) {
struct netlink_ext_ack *extack = cb->extack; struct netlink_ext_ack *extack = cb->extack;
...@@ -1324,40 +1325,23 @@ static int mpls_netconf_dump_devconf(struct sk_buff *skb, ...@@ -1324,40 +1325,23 @@ static int mpls_netconf_dump_devconf(struct sk_buff *skb,
} }
} }
s_h = cb->args[0]; rcu_read_lock();
s_idx = idx = cb->args[1]; for_each_netdev_dump(net, dev, ctx->ifindex) {
mdev = mpls_dev_get(dev);
for (h = s_h; h < NETDEV_HASHENTRIES; h++, s_idx = 0) { if (!mdev)
idx = 0; continue;
head = &net->dev_index_head[h]; err = mpls_netconf_fill_devconf(skb, mdev,
rcu_read_lock(); NETLINK_CB(cb->skb).portid,
cb->seq = net->dev_base_seq; nlh->nlmsg_seq,
hlist_for_each_entry_rcu(dev, head, index_hlist) { RTM_NEWNETCONF,
if (idx < s_idx) NLM_F_MULTI,
goto cont; NETCONFA_ALL);
mdev = mpls_dev_get(dev); if (err < 0)
if (!mdev) break;
goto cont;
if (mpls_netconf_fill_devconf(skb, mdev,
NETLINK_CB(cb->skb).portid,
nlh->nlmsg_seq,
RTM_NEWNETCONF,
NLM_F_MULTI,
NETCONFA_ALL) < 0) {
rcu_read_unlock();
goto done;
}
nl_dump_check_consistent(cb, nlmsg_hdr(skb));
cont:
idx++;
}
rcu_read_unlock();
} }
done: rcu_read_unlock();
cb->args[0] = h;
cb->args[1] = idx;
return skb->len; return err;
} }
#define MPLS_PERDEV_SYSCTL_OFFSET(field) \ #define MPLS_PERDEV_SYSCTL_OFFSET(field) \
...@@ -2773,7 +2757,8 @@ static int __init mpls_init(void) ...@@ -2773,7 +2757,8 @@ static int __init mpls_init(void)
mpls_getroute, mpls_dump_routes, 0); mpls_getroute, mpls_dump_routes, 0);
rtnl_register_module(THIS_MODULE, PF_MPLS, RTM_GETNETCONF, rtnl_register_module(THIS_MODULE, PF_MPLS, RTM_GETNETCONF,
mpls_netconf_get_devconf, mpls_netconf_get_devconf,
mpls_netconf_dump_devconf, 0); mpls_netconf_dump_devconf,
RTNL_FLAG_DUMP_UNLOCKED);
err = ipgre_tunnel_encap_add_mpls_ops(); err = ipgre_tunnel_encap_add_mpls_ops();
if (err) if (err)
pr_err("Can't add mpls over gre tunnel ops\n"); pr_err("Can't add mpls over gre tunnel ops\n");
......
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