rtnetlink: use xarray iterator to implement rtnl_dump_ifinfo()
authorEric Dumazet <edumazet@google.com>
Sun, 11 Feb 2024 21:44:04 +0000 (21:44 +0000)
committerJakub Kicinski <kuba@kernel.org>
Wed, 14 Feb 2024 02:34:50 +0000 (18:34 -0800)
Adopt net->dev_by_index as I did in commit 0e0939c0adf9
("net-procfs: use xarray iterator to implement /proc/net/dev")

This makes sure an existing device is always visible in the dump,
regardless of concurrent insertions/deletions.

v2: added suggestions from Jakub Kicinski and Ido Schimmel,
    thanks for the help !

Link: https://lore.kernel.org/all/20240209142441.6c56435b@kernel.org/
Link: https://lore.kernel.org/all/ZckR-XOsULLI9EHc@shredder/
Signed-off-by: Eric Dumazet <edumazet@google.com>
Reviewed-by: Ido Schimmel <idosch@nvidia.com>
Link: https://lore.kernel.org/r/20240211214404.1882191-3-edumazet@google.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
net/core/rtnetlink.c

index 31f433950c8dc953bcb65cc0469f7df962314b87..6f1c5537e8421bdb677e926e7fc9be1beb5ff969 100644 (file)
@@ -2188,25 +2188,22 @@ static int rtnl_valid_dump_ifinfo_req(const struct nlmsghdr *nlh,
 
 static int rtnl_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb)
 {
+       const struct rtnl_link_ops *kind_ops = NULL;
        struct netlink_ext_ack *extack = cb->extack;
        const struct nlmsghdr *nlh = cb->nlh;
        struct net *net = sock_net(skb->sk);
-       struct net *tgt_net = net;
-       int h, s_h;
-       int idx = 0, s_idx;
-       struct net_device *dev;
-       struct hlist_head *head;
+       unsigned int flags = NLM_F_MULTI;
        struct nlattr *tb[IFLA_MAX+1];
+       struct {
+               unsigned long ifindex;
+       } *ctx = (void *)cb->ctx;
+       struct net *tgt_net = net;
        u32 ext_filter_mask = 0;
-       const struct rtnl_link_ops *kind_ops = NULL;
-       unsigned int flags = NLM_F_MULTI;
+       struct net_device *dev;
        int master_idx = 0;
        int netnsid = -1;
        int err, i;
 
-       s_h = cb->args[0];
-       s_idx = cb->args[1];
-
        err = rtnl_valid_dump_ifinfo_req(nlh, cb->strict_check, tb, extack);
        if (err < 0) {
                if (cb->strict_check)
@@ -2250,36 +2247,21 @@ static int rtnl_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb)
                flags |= NLM_F_DUMP_FILTERED;
 
 walk_entries:
-       for (h = s_h; h < NETDEV_HASHENTRIES; h++, s_idx = 0) {
-               idx = 0;
-               head = &tgt_net->dev_index_head[h];
-               hlist_for_each_entry(dev, head, index_hlist) {
-                       if (link_dump_filtered(dev, master_idx, kind_ops))
-                               goto cont;
-                       if (idx < s_idx)
-                               goto cont;
-                       err = rtnl_fill_ifinfo(skb, dev, net,
-                                              RTM_NEWLINK,
-                                              NETLINK_CB(cb->skb).portid,
-                                              nlh->nlmsg_seq, 0, flags,
-                                              ext_filter_mask, 0, NULL, 0,
-                                              netnsid, GFP_KERNEL);
-
-                       if (err < 0) {
-                               if (likely(skb->len))
-                                       goto out;
-
-                               goto out_err;
-                       }
-cont:
-                       idx++;
+       err = 0;
+       for_each_netdev_dump(tgt_net, dev, ctx->ifindex) {
+               if (link_dump_filtered(dev, master_idx, kind_ops))
+                       continue;
+               err = rtnl_fill_ifinfo(skb, dev, net, RTM_NEWLINK,
+                                      NETLINK_CB(cb->skb).portid,
+                                      nlh->nlmsg_seq, 0, flags,
+                                      ext_filter_mask, 0, NULL, 0,
+                                      netnsid, GFP_KERNEL);
+               if (err < 0) {
+                       if (likely(skb->len))
+                               err = skb->len;
+                       break;
                }
        }
-out:
-       err = skb->len;
-out_err:
-       cb->args[1] = idx;
-       cb->args[0] = h;
        cb->seq = tgt_net->dev_base_seq;
        nl_dump_check_consistent(cb, nlmsg_hdr(skb));
        if (netnsid >= 0)