neighbour: Convert seq_file functions to use hlist
authorGilad Naaman <gnaaman@drivenets.com>
Thu, 7 Nov 2024 16:04:40 +0000 (16:04 +0000)
committerJakub Kicinski <kuba@kernel.org>
Sat, 9 Nov 2024 21:22:57 +0000 (13:22 -0800)
Convert seq_file-related neighbour functionality to use neighbour::hash
and the related for_each macro.

Signed-off-by: Gilad Naaman <gnaaman@drivenets.com>
Reviewed-by: Kuniyuki Iwashima <kuniyu@amazon.com>
Reviewed-by: Eric Dumazet <edumazet@google.com>
Link: https://patch.msgid.link/20241107160444.2913124-4-gnaaman@drivenets.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
net/core/neighbour.c

index 5552e6b05c82ee749d152e0631a2697bc2e4fc72..3485d6b3ba99a71777f70b407626fa18079b7571 100644 (file)
@@ -3193,43 +3193,53 @@ EXPORT_SYMBOL(neigh_xmit);
 
 #ifdef CONFIG_PROC_FS
 
-static struct neighbour *neigh_get_first(struct seq_file *seq)
+static struct neighbour *neigh_get_valid(struct seq_file *seq,
+                                        struct neighbour *n,
+                                        loff_t *pos)
 {
        struct neigh_seq_state *state = seq->private;
        struct net *net = seq_file_net(seq);
+
+       if (!net_eq(dev_net(n->dev), net))
+               return NULL;
+
+       if (state->neigh_sub_iter) {
+               loff_t fakep = 0;
+               void *v;
+
+               v = state->neigh_sub_iter(state, n, pos ? pos : &fakep);
+               if (!v)
+                       return NULL;
+               if (pos)
+                       return v;
+       }
+
+       if (!(state->flags & NEIGH_SEQ_SKIP_NOARP))
+               return n;
+
+       if (READ_ONCE(n->nud_state) & ~NUD_NOARP)
+               return n;
+
+       return NULL;
+}
+
+static struct neighbour *neigh_get_first(struct seq_file *seq)
+{
+       struct neigh_seq_state *state = seq->private;
        struct neigh_hash_table *nht = state->nht;
-       struct neighbour *n = NULL;
-       int bucket;
+       struct neighbour *n, *tmp;
 
        state->flags &= ~NEIGH_SEQ_IS_PNEIGH;
-       for (bucket = 0; bucket < (1 << nht->hash_shift); bucket++) {
-               n = rcu_dereference(nht->hash_buckets[bucket]);
-
-               while (n) {
-                       if (!net_eq(dev_net(n->dev), net))
-                               goto next;
-                       if (state->neigh_sub_iter) {
-                               loff_t fakep = 0;
-                               void *v;
 
-                               v = state->neigh_sub_iter(state, n, &fakep);
-                               if (!v)
-                                       goto next;
-                       }
-                       if (!(state->flags & NEIGH_SEQ_SKIP_NOARP))
-                               break;
-                       if (READ_ONCE(n->nud_state) & ~NUD_NOARP)
-                               break;
-next:
-                       n = rcu_dereference(n->next);
+       while (++state->bucket < (1 << nht->hash_shift)) {
+               neigh_for_each_in_bucket(n, &nht->hash_heads[state->bucket]) {
+                       tmp = neigh_get_valid(seq, n, NULL);
+                       if (tmp)
+                               return tmp;
                }
-
-               if (n)
-                       break;
        }
-       state->bucket = bucket;
 
-       return n;
+       return NULL;
 }
 
 static struct neighbour *neigh_get_next(struct seq_file *seq,
@@ -3237,46 +3247,28 @@ static struct neighbour *neigh_get_next(struct seq_file *seq,
                                        loff_t *pos)
 {
        struct neigh_seq_state *state = seq->private;
-       struct net *net = seq_file_net(seq);
-       struct neigh_hash_table *nht = state->nht;
+       struct neighbour *tmp;
 
        if (state->neigh_sub_iter) {
                void *v = state->neigh_sub_iter(state, n, pos);
+
                if (v)
                        return n;
        }
-       n = rcu_dereference(n->next);
-
-       while (1) {
-               while (n) {
-                       if (!net_eq(dev_net(n->dev), net))
-                               goto next;
-                       if (state->neigh_sub_iter) {
-                               void *v = state->neigh_sub_iter(state, n, pos);
-                               if (v)
-                                       return n;
-                               goto next;
-                       }
-                       if (!(state->flags & NEIGH_SEQ_SKIP_NOARP))
-                               break;
 
-                       if (READ_ONCE(n->nud_state) & ~NUD_NOARP)
-                               break;
-next:
-                       n = rcu_dereference(n->next);
+       hlist_for_each_entry_continue(n, hash) {
+               tmp = neigh_get_valid(seq, n, pos);
+               if (tmp) {
+                       n = tmp;
+                       goto out;
                }
-
-               if (n)
-                       break;
-
-               if (++state->bucket >= (1 << nht->hash_shift))
-                       break;
-
-               n = rcu_dereference(nht->hash_buckets[state->bucket]);
        }
 
+       n = neigh_get_first(seq);
+out:
        if (n && pos)
                --(*pos);
+
        return n;
 }
 
@@ -3379,7 +3371,7 @@ void *neigh_seq_start(struct seq_file *seq, loff_t *pos, struct neigh_table *tbl
        struct neigh_seq_state *state = seq->private;
 
        state->tbl = tbl;
-       state->bucket = 0;
+       state->bucket = -1;
        state->flags = (neigh_seq_flags & ~NEIGH_SEQ_IS_PNEIGH);
 
        rcu_read_lock();