rtnetlink: use for_each_netdev_dump() in rtnl_stats_dump()
authorEric Dumazet <edumazet@google.com>
Thu, 2 May 2024 11:37:48 +0000 (11:37 +0000)
committerJakub Kicinski <kuba@kernel.org>
Fri, 3 May 2024 22:03:42 +0000 (15:03 -0700)
Switch rtnl_stats_dump() to use for_each_netdev_dump()
instead of net->dev_index_head[] hash table.

This makes the code much easier to read, and fixes
scalability issues.

Signed-off-by: Eric Dumazet <edumazet@google.com>
Reviewed-by: David Ahern <dsahern@kernel.org>
Link: https://lore.kernel.org/r/20240502113748.1622637-3-edumazet@google.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
net/core/rtnetlink.c

index 88980c8bcf334079e2d19cbcfb3f10fc05e3c19b..28050e53ecb025f8d207f4b38805fb108799ca65 100644 (file)
@@ -5961,19 +5961,17 @@ static int rtnl_stats_get(struct sk_buff *skb, struct nlmsghdr *nlh,
 static int rtnl_stats_dump(struct sk_buff *skb, struct netlink_callback *cb)
 {
        struct netlink_ext_ack *extack = cb->extack;
-       int h, s_h, err, s_idx, s_idxattr, s_prividx;
        struct rtnl_stats_dump_filters filters;
        struct net *net = sock_net(skb->sk);
        unsigned int flags = NLM_F_MULTI;
        struct if_stats_msg *ifsm;
-       struct hlist_head *head;
+       struct {
+               unsigned long ifindex;
+               int idxattr;
+               int prividx;
+       } *ctx = (void *)cb->ctx;
        struct net_device *dev;
-       int idx = 0;
-
-       s_h = cb->args[0];
-       s_idx = cb->args[1];
-       s_idxattr = cb->args[2];
-       s_prividx = cb->args[3];
+       int err;
 
        cb->seq = net->dev_base_seq;
 
@@ -5992,37 +5990,24 @@ static int rtnl_stats_dump(struct sk_buff *skb, struct netlink_callback *cb)
        if (err)
                return err;
 
-       for (h = s_h; h < NETDEV_HASHENTRIES; h++, s_idx = 0) {
-               idx = 0;
-               head = &net->dev_index_head[h];
-               hlist_for_each_entry(dev, head, index_hlist) {
-                       if (idx < s_idx)
-                               goto cont;
-                       err = rtnl_fill_statsinfo(skb, dev, RTM_NEWSTATS,
-                                                 NETLINK_CB(cb->skb).portid,
-                                                 cb->nlh->nlmsg_seq, 0,
-                                                 flags, &filters,
-                                                 &s_idxattr, &s_prividx,
-                                                 extack);
-                       /* If we ran out of room on the first message,
-                        * we're in trouble
-                        */
-                       WARN_ON((err == -EMSGSIZE) && (skb->len == 0));
+       for_each_netdev_dump(net, dev, ctx->ifindex) {
+               err = rtnl_fill_statsinfo(skb, dev, RTM_NEWSTATS,
+                                         NETLINK_CB(cb->skb).portid,
+                                         cb->nlh->nlmsg_seq, 0,
+                                         flags, &filters,
+                                         &ctx->idxattr, &ctx->prividx,
+                                         extack);
+               /* If we ran out of room on the first message,
+                * we're in trouble.
+                */
+               WARN_ON((err == -EMSGSIZE) && (skb->len == 0));
 
-                       if (err < 0)
-                               goto out;
-                       s_prividx = 0;
-                       s_idxattr = 0;
-                       nl_dump_check_consistent(cb, nlmsg_hdr(skb));
-cont:
-                       idx++;
-               }
+               if (err < 0)
+                       break;
+               ctx->prividx = 0;
+               ctx->idxattr = 0;
+               nl_dump_check_consistent(cb, nlmsg_hdr(skb));
        }
-out:
-       cb->args[3] = s_prividx;
-       cb->args[2] = s_idxattr;
-       cb->args[1] = idx;
-       cb->args[0] = h;
 
        return err;
 }