net-procfs: use xarray iterator to implement /proc/net/dev
authorEric Dumazet <edumazet@google.com>
Wed, 7 Feb 2024 16:53:18 +0000 (16:53 +0000)
committerJakub Kicinski <kuba@kernel.org>
Fri, 9 Feb 2024 03:06:09 +0000 (19:06 -0800)
In commit 759ab1edb56c ("net: store netdevs in an xarray")
Jakub added net->dev_by_index to map ifindex to netdevices.

We can get rid of the old hash table (net->dev_index_head),
one patch at a time, if performance is acceptable.

This patch removes unpleasant code to something more readable.

As a bonus, /proc/net/dev gets netdevices sorted by their ifindex.

Signed-off-by: Eric Dumazet <edumazet@google.com>
Link: https://lore.kernel.org/r/20240207165318.3814525-1-edumazet@google.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
net/core/net-procfs.c

index 09f7ed1a04e8ab881e461971e919728641927252..2e4e96d30ee1a7a51e49587378aab47aed1290da 100644 (file)
@@ -6,49 +6,18 @@
 
 #include "dev.h"
 
-#define BUCKET_SPACE (32 - NETDEV_HASHBITS - 1)
-
-#define get_bucket(x) ((x) >> BUCKET_SPACE)
-#define get_offset(x) ((x) & ((1 << BUCKET_SPACE) - 1))
-#define set_bucket_offset(b, o) ((b) << BUCKET_SPACE | (o))
-
-static inline struct net_device *dev_from_same_bucket(struct seq_file *seq, loff_t *pos)
+static void *dev_seq_from_index(struct seq_file *seq, loff_t *pos)
 {
-       struct net *net = seq_file_net(seq);
+       unsigned long ifindex = *pos;
        struct net_device *dev;
-       struct hlist_head *h;
-       unsigned int count = 0, offset = get_offset(*pos);
 
-       h = &net->dev_index_head[get_bucket(*pos)];
-       hlist_for_each_entry_rcu(dev, h, index_hlist) {
-               if (++count == offset)
-                       return dev;
+       for_each_netdev_dump(seq_file_net(seq), dev, ifindex) {
+               *pos = dev->ifindex;
+               return dev;
        }
-
-       return NULL;
-}
-
-static inline struct net_device *dev_from_bucket(struct seq_file *seq, loff_t *pos)
-{
-       struct net_device *dev;
-       unsigned int bucket;
-
-       do {
-               dev = dev_from_same_bucket(seq, pos);
-               if (dev)
-                       return dev;
-
-               bucket = get_bucket(*pos) + 1;
-               *pos = set_bucket_offset(bucket, 1);
-       } while (bucket < NETDEV_HASHENTRIES);
-
        return NULL;
 }
 
-/*
- *     This is invoked by the /proc filesystem handler to display a device
- *     in detail.
- */
 static void *dev_seq_start(struct seq_file *seq, loff_t *pos)
        __acquires(RCU)
 {
@@ -56,16 +25,13 @@ static void *dev_seq_start(struct seq_file *seq, loff_t *pos)
        if (!*pos)
                return SEQ_START_TOKEN;
 
-       if (get_bucket(*pos) >= NETDEV_HASHENTRIES)
-               return NULL;
-
-       return dev_from_bucket(seq, pos);
+       return dev_seq_from_index(seq, pos);
 }
 
 static void *dev_seq_next(struct seq_file *seq, void *v, loff_t *pos)
 {
        ++*pos;
-       return dev_from_bucket(seq, pos);
+       return dev_seq_from_index(seq, pos);
 }
 
 static void dev_seq_stop(struct seq_file *seq, void *v)