netdev
[Top] [All Lists]

[1/6]: Abstract neigh table walking

To: laforge@xxxxxxxxxxxx
Subject: [1/6]: Abstract neigh table walking
From: "David S. Miller" <davem@xxxxxxxxxxxxx>
Date: Thu, 23 Sep 2004 22:48:41 -0700
Cc: netdev@xxxxxxxxxxx
Sender: netdev-bounce@xxxxxxxxxxx
This way we can hide hash table accesses inside
of net/core/neigh.c

# This is a BitKeeper generated diff -Nru style patch.
#
# ChangeSet
#   2004/09/23 15:15:26-07:00 davem@xxxxxxxxxxxxxxxxxx 
#   [NET]: Abstract neigh table walking.
#   
#   This way no code actually needs to traverse the
#   neigh hash tables outside of net/core/neighbour.c
#   
#   Signed-off-by: David S. Miller <davem@xxxxxxxxxxxxx>
# 
# net/ipv4/arp.c
#   2004/09/23 15:14:50-07:00 davem@xxxxxxxxxxxxxxxxxx +20 -163
#   [NET]: Abstract neigh table walking.
#   
#   This way no code actually needs to traverse the
#   neigh hash tables outside of net/core/neighbour.c
#   
#   Signed-off-by: David S. Miller <davem@xxxxxxxxxxxxx>
# 
# net/decnet/dn_neigh.c
#   2004/09/23 15:14:50-07:00 davem@xxxxxxxxxxxxxxxxxx +52 -120
#   [NET]: Abstract neigh table walking.
#   
#   This way no code actually needs to traverse the
#   neigh hash tables outside of net/core/neighbour.c
#   
#   Signed-off-by: David S. Miller <davem@xxxxxxxxxxxxx>
# 
# net/core/neighbour.c
#   2004/09/23 15:14:50-07:00 davem@xxxxxxxxxxxxxxxxxx +260 -0
#   [NET]: Abstract neigh table walking.
#   
#   This way no code actually needs to traverse the
#   neigh hash tables outside of net/core/neighbour.c
#   
#   Signed-off-by: David S. Miller <davem@xxxxxxxxxxxxx>
# 
# net/atm/clip.c
#   2004/09/23 15:14:50-07:00 davem@xxxxxxxxxxxxxxxxxx +117 -129
#   [NET]: Abstract neigh table walking.
#   
#   This way no code actually needs to traverse the
#   neigh hash tables outside of net/core/neighbour.c
#   
#   Signed-off-by: David S. Miller <davem@xxxxxxxxxxxxx>
# 
# include/net/neighbour.h
#   2004/09/23 15:14:49-07:00 davem@xxxxxxxxxxxxxxxxxx +19 -0
#   [NET]: Abstract neigh table walking.
#   
#   This way no code actually needs to traverse the
#   neigh hash tables outside of net/core/neighbour.c
#   
#   Signed-off-by: David S. Miller <davem@xxxxxxxxxxxxx>
# 
diff -Nru a/include/net/neighbour.h b/include/net/neighbour.h
--- a/include/net/neighbour.h   2004-09-23 22:25:53 -07:00
+++ b/include/net/neighbour.h   2004-09-23 22:25:53 -07:00
@@ -47,6 +47,7 @@
 #include <linux/skbuff.h>
 #include <linux/netdevice.h>
 #include <linux/rcupdate.h>
+#include <linux/seq_file.h>
 
 #include <linux/err.h>
 #include <linux/sysctl.h>
@@ -223,6 +224,24 @@
 extern int neigh_add(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg);
 extern int neigh_delete(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg);
 extern void neigh_app_ns(struct neighbour *n);
+
+extern void neigh_for_each(struct neigh_table *tbl, void (*cb)(struct 
neighbour *, void *), void *cookie);
+extern void __neigh_for_each_release(struct neigh_table *tbl, int (*cb)(struct 
neighbour *));
+extern void pneigh_for_each(struct neigh_table *tbl, void (*cb)(struct 
pneigh_entry *));
+
+struct neigh_seq_state {
+       struct neigh_table *tbl;
+       void *(*neigh_sub_iter)(struct neigh_seq_state *state,
+                               struct neighbour *n, loff_t *pos);
+       unsigned int bucket;
+       unsigned int flags;
+#define NEIGH_SEQ_NEIGH_ONLY   0x00000001
+#define NEIGH_SEQ_IS_PNEIGH    0x00000002
+#define NEIGH_SEQ_SKIP_NOARP   0x00000004
+};
+extern void *neigh_seq_start(struct seq_file *, loff_t *, struct neigh_table 
*, unsigned int);
+extern void *neigh_seq_next(struct seq_file *, void *, loff_t *);
+extern void neigh_seq_stop(struct seq_file *, void *);
 
 extern int                     neigh_sysctl_register(struct net_device *dev, 
                                                      struct neigh_parms *p,
diff -Nru a/net/atm/clip.c b/net/atm/clip.c
--- a/net/atm/clip.c    2004-09-23 22:25:53 -07:00
+++ b/net/atm/clip.c    2004-09-23 22:25:53 -07:00
@@ -123,64 +123,49 @@
        spin_unlock_bh(&entry->neigh->dev->xmit_lock);
 }
 
-
-static void idle_timer_check(unsigned long dummy)
+/* The neighbour entry n->lock is held. */
+static int neigh_check_cb(struct neighbour *n)
 {
-       int i;
+       struct atmarp_entry *entry = NEIGH2ENTRY(n);
+       struct clip_vcc *cv;
 
-       /*DPRINTK("idle_timer_check\n");*/
-       write_lock(&clip_tbl.lock);
-       for (i = 0; i <= NEIGH_HASHMASK; i++) {
-               struct neighbour **np;
+       for (cv = entry->vccs; cv; cv = cv->next) {
+               unsigned long exp = cv->last_use + cv->idle_timeout;
 
-               for (np = &clip_tbl.hash_buckets[i]; *np;) {
-                       struct neighbour *n = *np;
-                       struct atmarp_entry *entry = NEIGH2ENTRY(n);
-                       struct clip_vcc *clip_vcc;
-
-                       write_lock(&n->lock);
-
-                       for (clip_vcc = entry->vccs; clip_vcc;
-                           clip_vcc = clip_vcc->next)
-                               if (clip_vcc->idle_timeout &&
-                                   time_after(jiffies, clip_vcc->last_use+
-                                   clip_vcc->idle_timeout)) {
-                                       DPRINTK("releasing vcc %p->%p of "
-                                           "entry %p\n",clip_vcc,clip_vcc->vcc,
-                                           entry);
-                                       vcc_release_async(clip_vcc->vcc,
-                                                         -ETIMEDOUT);
-                               }
-                       if (entry->vccs ||
-                           time_before(jiffies, entry->expires)) {
-                               np = &n->next;
-                               write_unlock(&n->lock);
-                               continue;
-                       }
-                       if (atomic_read(&n->refcnt) > 1) {
-                               struct sk_buff *skb;
-
-                               DPRINTK("destruction postponed with ref %d\n",
-                                   atomic_read(&n->refcnt));
-                               while ((skb = skb_dequeue(&n->arp_queue)) !=
-                                    NULL) 
-                                       dev_kfree_skb(skb);
-                               np = &n->next;
-                               write_unlock(&n->lock);
-                               continue;
-                       }
-                       *np = n->next;
-                       DPRINTK("expired neigh %p\n",n);
-                       n->dead = 1;
-                       write_unlock(&n->lock);
-                       neigh_release(n);
+               if (cv->idle_timeout && time_after(jiffies, exp)) {
+                       DPRINTK("releasing vcc %p->%p of entry %p\n",
+                               cv, cv->vcc, entry);
+                       vcc_release_async(cv->vcc, -ETIMEDOUT);
                }
        }
+
+       if (entry->vccs || time_before(jiffies, entry->expires))
+               return 0;
+
+       if (atomic_read(&n->refcnt) > 1) {
+               struct sk_buff *skb;
+
+               DPRINTK("destruction postponed with ref %d\n",
+                       atomic_read(&n->refcnt));
+
+               while ((skb = skb_dequeue(&n->arp_queue)) != NULL) 
+                       dev_kfree_skb(skb);
+
+               return 0;
+       }
+
+       DPRINTK("expired neigh %p\n",n);
+       return 1;
+}
+
+static void idle_timer_check(unsigned long dummy)
+{
+       write_lock(&clip_tbl.lock);
+       __neigh_for_each_release(&clip_tbl, neigh_check_cb);
        mod_timer(&idle_timer, jiffies+CLIP_CHECK_INTERVAL*HZ);
        write_unlock(&clip_tbl.lock);
 }
 
-
 static int clip_arp_rcv(struct sk_buff *skb)
 {
        struct atm_vcc *vcc;
@@ -833,120 +818,126 @@
        }
 }
 
+/* This means the neighbour entry has no attached VCC objects. */
+#define SEQ_NO_VCC_TOKEN       ((void *) 2)
+
 static void atmarp_info(struct seq_file *seq, struct net_device *dev,
                        struct atmarp_entry *entry, struct clip_vcc *clip_vcc)
 {
+       unsigned long exp;
        char buf[17];
-       int svc, off;
+       int svc, llc, off;
+
+       svc = ((clip_vcc == SEQ_NO_VCC_TOKEN) ||
+              (clip_vcc->vcc->sk->sk_family == AF_ATMSVC));
+
+       llc = ((clip_vcc == SEQ_NO_VCC_TOKEN) ||
+              clip_vcc->encap);
+
+       if (clip_vcc == SEQ_NO_VCC_TOKEN)
+               exp = entry->neigh->used;
+       else
+               exp = clip_vcc->last_use;
 
-       svc = !clip_vcc || clip_vcc->vcc->sk->sk_family == AF_ATMSVC;
-       seq_printf(seq, "%-6s%-4s%-4s%5ld ", dev->name, svc ? "SVC" : "PVC",
-           !clip_vcc || clip_vcc->encap ? "LLC" : "NULL",
-           (jiffies-(clip_vcc ? clip_vcc->last_use : entry->neigh->used))/HZ);
+       exp = (jiffies - exp) / HZ;
 
-       off = scnprintf(buf, sizeof(buf) - 1, "%d.%d.%d.%d", 
NIPQUAD(entry->ip));
+       seq_printf(seq, "%-6s%-4s%-4s%5ld ",
+                  dev->name,
+                  svc ? "SVC" : "PVC",
+                  llc ? "LLC" : "NULL",
+                  exp);
+
+       off = scnprintf(buf, sizeof(buf) - 1, "%d.%d.%d.%d",
+                       NIPQUAD(entry->ip));
        while (off < 16)
                buf[off++] = ' ';
        buf[off] = '\0';
        seq_printf(seq, "%s", buf);
 
-       if (!clip_vcc) {
+       if (clip_vcc == SEQ_NO_VCC_TOKEN) {
                if (time_before(jiffies, entry->expires))
                        seq_printf(seq, "(resolving)\n");
                else
                        seq_printf(seq, "(expired, ref %d)\n",
                                   atomic_read(&entry->neigh->refcnt));
        } else if (!svc) {
-               seq_printf(seq, "%d.%d.%d\n", clip_vcc->vcc->dev->number,
-                          clip_vcc->vcc->vpi, clip_vcc->vcc->vci);
+               seq_printf(seq, "%d.%d.%d\n",
+                          clip_vcc->vcc->dev->number,
+                          clip_vcc->vcc->vpi,
+                          clip_vcc->vcc->vci);
        } else {
                svc_addr(seq, &clip_vcc->vcc->remote);
                seq_putc(seq, '\n');
        }
 }
 
-struct arp_state {
-       int bucket;
-       struct neighbour *n;
+struct clip_seq_state {
+       /* This member must be first. */
+       struct neigh_seq_state ns;
+
+       /* Local to clip specific iteration. */
        struct clip_vcc *vcc;
 };
-  
-static void *arp_vcc_walk(struct arp_state *state,
-                         struct atmarp_entry *e, loff_t *l)
-{
-       struct clip_vcc *vcc = state->vcc;
 
-       if (!vcc)
-               vcc = e->vccs;
-       if (vcc == (void *)1) {
-               vcc = e->vccs;
-               --*l;
-       }
-       for (; vcc; vcc = vcc->next) {
-               if (--*l < 0)
-                       break;
-       }
-       state->vcc = vcc;
-       return (*l < 0) ? state : NULL;
-}
-  
-static void *arp_get_idx(struct arp_state *state, loff_t l)
+static struct clip_vcc *clip_seq_next_vcc(struct atmarp_entry *e,
+                                         struct clip_vcc *curr)
 {
-       void *v = NULL;
-
-       for (; state->bucket <= NEIGH_HASHMASK; state->bucket++) {
-               for (; state->n; state->n = state->n->next) {
-                       v = arp_vcc_walk(state, NEIGH2ENTRY(state->n), &l);
-                       if (v)
-                               goto done;
-               }
-               state->n = clip_tbl.hash_buckets[state->bucket + 1];
+       if (!curr) {
+               curr = e->vccs;
+               if (!curr)
+                       return SEQ_NO_VCC_TOKEN;
+               return curr;
        }
-done:
-       return v;
+       if (curr == SEQ_NO_VCC_TOKEN)
+               return NULL;
+
+       curr = curr->next;
+
+       return curr;
 }
 
-static void *arp_seq_start(struct seq_file *seq, loff_t *pos)
+static void *clip_seq_vcc_walk(struct clip_seq_state *state,
+                              struct atmarp_entry *e, loff_t *pos)
 {
-       struct arp_state *state = seq->private;
-       void *ret = (void *)1;
+       struct clip_vcc *vcc = state->vcc;
 
-       read_lock_bh(&clip_tbl.lock);
-       state->bucket = 0;
-       state->n = clip_tbl.hash_buckets[0];
-       state->vcc = (void *)1;
-       if (*pos)
-               ret = arp_get_idx(state, *pos);
-       return ret;
-}
+       vcc = clip_seq_next_vcc(e, vcc);
+       if (vcc && pos != NULL) {
+               while (*pos) {
+                       vcc = clip_seq_next_vcc(e, vcc);
+                       if (!vcc)
+                               break;
+                       --(*pos);
+               }
+       }
+       state->vcc = vcc;
 
-static void arp_seq_stop(struct seq_file *seq, void *v)
+       return vcc;
+}
+  
+static void *clip_seq_sub_iter(struct neigh_seq_state *_state,
+                              struct neighbour *n, loff_t *pos)
 {
-       struct arp_state *state = seq->private;
+       struct clip_seq_state *state = (struct clip_seq_state *) _state;
 
-       if (state->bucket != -1)
-               read_unlock_bh(&clip_tbl.lock);
+       return clip_seq_vcc_walk(state, NEIGH2ENTRY(n), pos);
 }
 
-static void *arp_seq_next(struct seq_file *seq, void *v, loff_t *pos)
+static void *clip_seq_start(struct seq_file *seq, loff_t *pos)
 {
-       struct arp_state *state = seq->private;
-
-       v = arp_get_idx(state, 1);
-       *pos += !!PTR_ERR(v);
-       return v;
+       return neigh_seq_start(seq, pos, &clip_tbl, NEIGH_SEQ_NEIGH_ONLY);
 }
 
-static int arp_seq_show(struct seq_file *seq, void *v)
+static int clip_seq_show(struct seq_file *seq, void *v)
 {
        static char atm_arp_banner[] = 
                "IPitf TypeEncp Idle IP address      ATM address\n";
 
-       if (v == (void *)1)
+       if (v == SEQ_START_TOKEN) {
                seq_puts(seq, atm_arp_banner);
-       else {
-               struct arp_state *state = seq->private;
-               struct neighbour *n = state->n; 
+       } else {
+               struct clip_seq_state *state = seq->private;
+               struct neighbour *n = v;
                struct clip_vcc *vcc = state->vcc;
 
                atmarp_info(seq, n->dev, NEIGH2ENTRY(n), vcc);
@@ -955,15 +946,15 @@
 }
 
 static struct seq_operations arp_seq_ops = {
-       .start  = arp_seq_start,
-       .next   = arp_seq_next,
-       .stop   = arp_seq_stop,
-       .show   = arp_seq_show,
+       .start  = clip_seq_start,
+       .next   = neigh_seq_next,
+       .stop   = neigh_seq_stop,
+       .show   = clip_seq_show,
 };
 
 static int arp_seq_open(struct inode *inode, struct file *file)
 {
-       struct arp_state *state;
+       struct clip_seq_state *state;
        struct seq_file *seq;
        int rc = -EAGAIN;
 
@@ -972,6 +963,8 @@
                rc = -ENOMEM;
                goto out_kfree;
        }
+       memset(state, 0, sizeof(*state));
+       state->ns.neigh_sub_iter = clip_seq_sub_iter;
 
        rc = seq_open(file, &arp_seq_ops);
        if (rc)
@@ -987,16 +980,11 @@
        goto out;
 }
 
-static int arp_seq_release(struct inode *inode, struct file *file)
-{
-       return seq_release_private(inode, file);
-}
-
 static struct file_operations arp_seq_fops = {
        .open           = arp_seq_open,
        .read           = seq_read,
        .llseek         = seq_lseek,
-       .release        = arp_seq_release,
+       .release        = seq_release_private,
        .owner          = THIS_MODULE
 };
 #endif
diff -Nru a/net/core/neighbour.c b/net/core/neighbour.c
--- a/net/core/neighbour.c      2004-09-23 22:25:53 -07:00
+++ b/net/core/neighbour.c      2004-09-23 22:25:53 -07:00
@@ -1489,6 +1489,266 @@
        return skb->len;
 }
 
+void neigh_for_each(struct neigh_table *tbl, void (*cb)(struct neighbour *, 
void *), void *cookie)
+{
+       int chain;
+
+       read_lock_bh(&tbl->lock);
+       for (chain = 0; chain <= NEIGH_HASHMASK; chain++) {
+               struct neighbour *n;
+
+               for (n = tbl->hash_buckets[chain]; n; n = n->next)
+                       cb(n, cookie);
+       }
+       read_unlock_bh(&tbl->lock);
+}
+EXPORT_SYMBOL(neigh_for_each);
+
+/* The tbl->lock must be held as a writer and BH disabled. */
+void __neigh_for_each_release(struct neigh_table *tbl,
+                             int (*cb)(struct neighbour *))
+{
+       int chain;
+
+       for (chain = 0; chain <= NEIGH_HASHMASK; chain++) {
+               struct neighbour *n, **np;
+
+               np = &tbl->hash_buckets[chain];
+               while ((n = *np) != NULL) {
+                       int release;
+
+                       write_lock(&n->lock);
+                       release = cb(n);
+                       if (release) {
+                               *np = n->next;
+                               n->dead = 1;
+                       } else
+                               np = &n->next;
+                       write_unlock(&n->lock);
+                       if (release)
+                               neigh_release(n);
+               }
+       }
+}
+EXPORT_SYMBOL(__neigh_for_each_release);
+
+#ifdef CONFIG_PROC_FS
+
+static struct neighbour *neigh_get_first(struct seq_file *seq)
+{
+       struct neigh_seq_state *state = seq->private;
+       struct neigh_table *tbl = state->tbl;
+       struct neighbour *n = NULL;
+       int bucket = state->bucket;
+
+       state->flags &= ~NEIGH_SEQ_IS_PNEIGH;
+       for (bucket = 0; bucket <= NEIGH_HASHMASK; bucket++) {
+               n = tbl->hash_buckets[bucket];
+
+               while (n) {
+                       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 (n->nud_state & ~NUD_NOARP)
+                               break;
+               next:
+                       n = n->next;
+               }
+
+               if (n)
+                       break;
+       }
+       state->bucket = bucket;
+
+       return n;
+}
+
+static struct neighbour *neigh_get_next(struct seq_file *seq,
+                                       struct neighbour *n,
+                                       loff_t *pos)
+{
+       struct neigh_seq_state *state = seq->private;
+       struct neigh_table *tbl = state->tbl;
+
+       if (state->neigh_sub_iter) {
+               void *v = state->neigh_sub_iter(state, n, pos);
+               if (v)
+                       return n;
+       }
+       n = n->next;
+
+       while (1) {
+               while (n) {
+                       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 (n->nud_state & ~NUD_NOARP)
+                               break;
+               next:
+                       n = n->next;
+               }
+
+               if (n)
+                       break;
+
+               if (++state->bucket > NEIGH_HASHMASK)
+                       break;
+
+               n = tbl->hash_buckets[state->bucket];
+       }
+
+       if (n && pos)
+               --(*pos);
+       return n;
+}
+
+static struct neighbour *neigh_get_idx(struct seq_file *seq, loff_t *pos)
+{
+       struct neighbour *n = neigh_get_first(seq);
+
+       if (n) {
+               while (*pos) {
+                       n = neigh_get_next(seq, n, pos);
+                       if (!n)
+                               break;
+               }
+       }
+       return *pos ? NULL : n;
+}
+
+static struct pneigh_entry *pneigh_get_first(struct seq_file *seq)
+{
+       struct neigh_seq_state *state = seq->private;
+       struct neigh_table *tbl = state->tbl;
+       struct pneigh_entry *pn = NULL;
+       int bucket = state->bucket;
+
+       state->flags |= NEIGH_SEQ_IS_PNEIGH;
+       for (bucket = 0; bucket <= PNEIGH_HASHMASK; bucket++) {
+               pn = tbl->phash_buckets[bucket];
+               if (pn)
+                       break;
+       }
+       state->bucket = bucket;
+
+       return pn;
+}
+
+static struct pneigh_entry *pneigh_get_next(struct seq_file *seq,
+                                           struct pneigh_entry *pn,
+                                           loff_t *pos)
+{
+       struct neigh_seq_state *state = seq->private;
+       struct neigh_table *tbl = state->tbl;
+
+       pn = pn->next;
+       while (!pn) {
+               if (++state->bucket > PNEIGH_HASHMASK)
+                       break;
+               pn = tbl->phash_buckets[state->bucket];
+               if (pn)
+                       break;
+       }
+
+       if (pn && pos)
+               --(*pos);
+
+       return pn;
+}
+
+static struct pneigh_entry *pneigh_get_idx(struct seq_file *seq, loff_t *pos)
+{
+       struct pneigh_entry *pn = pneigh_get_first(seq);
+
+       if (pn) {
+               while (*pos) {
+                       pn = pneigh_get_next(seq, pn, pos);
+                       if (!pn)
+                               break;
+               }
+       }
+       return *pos ? NULL : pn;
+}
+
+static void *neigh_get_idx_any(struct seq_file *seq, loff_t *pos)
+{
+       struct neigh_seq_state *state = seq->private;
+       void *rc;
+
+       rc = neigh_get_idx(seq, pos);
+       if (!rc && !(state->flags & NEIGH_SEQ_NEIGH_ONLY))
+               rc = pneigh_get_idx(seq, pos);
+
+       return rc;
+}
+
+void *neigh_seq_start(struct seq_file *seq, loff_t *pos, struct neigh_table 
*tbl, unsigned int neigh_seq_flags)
+{
+       struct neigh_seq_state *state = seq->private;
+       loff_t pos_minus_one;
+
+       state->tbl = tbl;
+       state->bucket = 0;
+       state->flags = (neigh_seq_flags & ~NEIGH_SEQ_IS_PNEIGH);
+
+       read_lock_bh(&tbl->lock);
+
+       pos_minus_one = *pos - 1;
+       return *pos ? neigh_get_idx_any(seq, &pos_minus_one) : SEQ_START_TOKEN;
+}
+EXPORT_SYMBOL(neigh_seq_start);
+
+void *neigh_seq_next(struct seq_file *seq, void *v, loff_t *pos)
+{
+       struct neigh_seq_state *state;
+       void *rc;
+
+       if (v == SEQ_START_TOKEN) {
+               rc = neigh_get_idx(seq, pos);
+               goto out;
+       }
+
+       state = seq->private;
+       if (!(state->flags & NEIGH_SEQ_IS_PNEIGH)) {
+               rc = neigh_get_next(seq, v, NULL);
+               if (rc)
+                       goto out;
+               if (!(state->flags & NEIGH_SEQ_NEIGH_ONLY))
+                       rc = pneigh_get_first(seq);
+       } else {
+               BUG_ON(state->flags & NEIGH_SEQ_NEIGH_ONLY);
+               rc = pneigh_get_next(seq, v, NULL);
+       }
+out:
+       ++(*pos);
+       return rc;
+}
+EXPORT_SYMBOL(neigh_seq_next);
+
+void neigh_seq_stop(struct seq_file *seq, void *v)
+{
+       struct neigh_seq_state *state = seq->private;
+       struct neigh_table *tbl = state->tbl;
+
+       read_unlock_bh(&tbl->lock);
+}
+EXPORT_SYMBOL(neigh_seq_stop);
+
+#endif /* CONFIG_PROC_FS */
+
 #ifdef CONFIG_ARPD
 void neigh_app_ns(struct neighbour *n)
 {
diff -Nru a/net/decnet/dn_neigh.c b/net/decnet/dn_neigh.c
--- a/net/decnet/dn_neigh.c     2004-09-23 22:25:53 -07:00
+++ b/net/decnet/dn_neigh.c     2004-09-23 22:25:53 -07:00
@@ -514,141 +514,66 @@
        return (*min < priority) ? (min - 6) : NULL;
 }
 
-int dn_neigh_elist(struct net_device *dev, unsigned char *ptr, int n)
-{
-       int t = 0;
-       int i;
-       struct neighbour *neigh;
-       struct dn_neigh *dn;
-       struct neigh_table *tbl = &dn_neigh_table;
-       unsigned char *rs = ptr;
-       struct dn_dev *dn_db = (struct dn_dev *)dev->dn_ptr;
-
-       read_lock_bh(&tbl->lock);
-
-       for(i = 0; i < NEIGH_HASHMASK; i++) {
-               for(neigh = tbl->hash_buckets[i]; neigh != NULL; neigh = 
neigh->next) {
-                       if (neigh->dev != dev)
-                               continue;
-                       dn = (struct dn_neigh *)neigh;
-                       if (!(dn->flags & (DN_NDFLAG_R1|DN_NDFLAG_R2)))
-                               continue;
-                       if (dn_db->parms.forwarding == 1 && (dn->flags & 
DN_NDFLAG_R2))
-                               continue;
-                       if (t == n)
-                               rs = dn_find_slot(ptr, n, dn->priority);
-                       else
-                               t++;
-                       if (rs == NULL)
-                               continue;
-                       dn_dn2eth(rs, dn->addr);
-                       rs += 6;
-                       *rs = neigh->nud_state & NUD_CONNECTED ? 0x80 : 0x0;
-                       *rs |= dn->priority;
-                       rs++;
-               }
-       }
-
-       read_unlock_bh(&tbl->lock);
-
-       return t;
-}
-
-
-#ifdef CONFIG_PROC_FS
-
-struct dn_neigh_iter_state {
-       int bucket;
+struct elist_cb_state {
+       struct net_device *dev;
+       unsigned char *ptr;
+       unsigned char *rs;
+       int t, n;
 };
 
-static struct neighbour *neigh_get_first(struct seq_file *seq)
+static void neigh_elist_cb(struct neighbour *neigh, void *_info)
 {
-       struct dn_neigh_iter_state *state = seq->private;
-       struct neighbour *n = NULL;
-
-       for(state->bucket = 0;
-           state->bucket <= NEIGH_HASHMASK;
-           ++state->bucket) {
-               n = dn_neigh_table.hash_buckets[state->bucket];
-               if (n)
-                       break;
-       }
-
-       return n;
-}
+       struct elist_cb_state *s = _info;
+       struct dn_dev *dn_db;
+       struct dn_neigh *dn;
 
-static struct neighbour *neigh_get_next(struct seq_file *seq,
-                                       struct neighbour *n)
-{
-       struct dn_neigh_iter_state *state = seq->private;
+       if (neigh->dev != s->dev)
+               return;
 
-       n = n->next;
-try_again:
-       if (n)
-               goto out;
-       if (++state->bucket > NEIGH_HASHMASK)
-               goto out;
-       n = dn_neigh_table.hash_buckets[state->bucket];
-       goto try_again;
-out:
-       return n;
+       dn = (struct dn_neigh *) neigh;
+       if (!(dn->flags & (DN_NDFLAG_R1|DN_NDFLAG_R2)))
+               return;
+
+       dn_db = (struct dn_dev *) s->dev->dn_ptr;
+       if (dn_db->parms.forwarding == 1 && (dn->flags & DN_NDFLAG_R2))
+               return;
+
+       if (s->t == s->n)
+               s->rs = dn_find_slot(s->ptr, s->n, dn->priority);
+       else
+               s->t++;
+       if (s->rs == NULL)
+               return;
+
+       dn_dn2eth(s->rs, dn->addr);
+       s->rs += 6;
+       *(s->rs) = neigh->nud_state & NUD_CONNECTED ? 0x80 : 0x0;
+       *(s->rs) |= dn->priority;
+       s->rs++;
 }
 
-static struct neighbour *neigh_get_idx(struct seq_file *seq, loff_t *pos)
+int dn_neigh_elist(struct net_device *dev, unsigned char *ptr, int n)
 {
-       struct neighbour *n = neigh_get_first(seq);
+       struct elist_cb_state state;
 
-       if (n)
-               while(*pos && (n = neigh_get_next(seq, n)))
-                       --*pos;
-       return *pos ? NULL : n;
-}
+       state.dev = dev;
+       state.t = 0;
+       state.n = n;
+       state.ptr = ptr;
+       state.rs = ptr;
 
-static void *dn_neigh_get_idx(struct seq_file *seq, loff_t pos)
-{
-       void *rc;
-       read_lock_bh(&dn_neigh_table.lock);
-       rc = neigh_get_idx(seq, &pos);
-       if (!rc) {
-               read_unlock_bh(&dn_neigh_table.lock);
-       }
-       return rc;
-}
+       neigh_for_each(&dn_neigh_table, neigh_elist_cb, &state);
 
-static void *dn_neigh_seq_start(struct seq_file *seq, loff_t *pos)
-{
-       return *pos ? dn_neigh_get_idx(seq, *pos - 1) : SEQ_START_TOKEN;
+       return state.t;
 }
 
-static void *dn_neigh_seq_next(struct seq_file *seq, void *v, loff_t *pos)
-{
-       void *rc;
-
-
-       if (v == SEQ_START_TOKEN) {
-               rc = dn_neigh_get_idx(seq, 0);
-               goto out;
-       }
 
-       rc = neigh_get_next(seq, v);
-       if (rc)
-               goto out;
-       read_unlock_bh(&dn_neigh_table.lock);
-out:
-       ++*pos;
-       return rc;
-}
-
-static void dn_neigh_seq_stop(struct seq_file *seq, void *v)
-{
-       if (v && v != SEQ_START_TOKEN)
-               read_unlock_bh(&dn_neigh_table.lock);
-}
+#ifdef CONFIG_PROC_FS
 
 static inline void dn_neigh_format_entry(struct seq_file *seq,
                                         struct neighbour *n)
 {
-       struct dn_neigh *dn = (struct dn_neigh *)n;
+       struct dn_neigh *dn = (struct dn_neigh *) n;
        char buf[DN_ASCBUF_LEN];
 
        read_lock(&n->lock);
@@ -675,10 +600,16 @@
        return 0;
 }
 
+static void *dn_neigh_seq_start(struct seq_file *seq, loff_t *pos)
+{
+       return neigh_seq_start(seq, pos, &dn_neigh_table,
+                              NEIGH_SEQ_NEIGH_ONLY);
+}
+
 static struct seq_operations dn_neigh_seq_ops = {
        .start = dn_neigh_seq_start,
-       .next  = dn_neigh_seq_next,
-       .stop  = dn_neigh_seq_stop,
+       .next  = neigh_seq_next,
+       .stop  = neigh_seq_stop,
        .show  = dn_neigh_seq_show,
 };
 
@@ -686,11 +617,12 @@
 {
        struct seq_file *seq;
        int rc = -ENOMEM;
-       struct dn_neigh_iter_state *s = kmalloc(sizeof(*s), GFP_KERNEL);
+       struct neigh_seq_state *s = kmalloc(sizeof(*s), GFP_KERNEL);
 
        if (!s)
                goto out;
 
+       memset(s, 0, sizeof(*s));
        rc = seq_open(file, &dn_neigh_seq_ops);
        if (rc)
                goto out_kfree;
diff -Nru a/net/ipv4/arp.c b/net/ipv4/arp.c
--- a/net/ipv4/arp.c    2004-09-23 22:25:53 -07:00
+++ b/net/ipv4/arp.c    2004-09-23 22:25:53 -07:00
@@ -1269,162 +1269,10 @@
 }
 #endif /* CONFIG_AX25 */
 
-struct arp_iter_state {
-       int is_pneigh, bucket;
-};
-
-static struct neighbour *neigh_get_first(struct seq_file *seq)
-{
-       struct arp_iter_state* state = seq->private;
-       struct neighbour *n = NULL;
-
-       state->is_pneigh = 0;
-
-       for (state->bucket = 0;
-            state->bucket <= NEIGH_HASHMASK;
-            ++state->bucket) {
-               n = arp_tbl.hash_buckets[state->bucket];
-               while (n && !(n->nud_state & ~NUD_NOARP))
-                       n = n->next;
-               if (n)
-                       break;
-       }
-
-       return n;
-}
-
-static struct neighbour *neigh_get_next(struct seq_file *seq,
-                                       struct neighbour *n)
-{
-       struct arp_iter_state* state = seq->private;
-
-       do {
-               n = n->next;
-               /* Don't confuse "arp -a" w/ magic entries */
-try_again:
-               ;
-       } while (n && !(n->nud_state & ~NUD_NOARP));
-
-       if (n)
-               goto out;
-       if (++state->bucket > NEIGH_HASHMASK)
-               goto out;
-       n = arp_tbl.hash_buckets[state->bucket];
-       goto try_again;
-out:
-       return n;
-}
-
-static struct neighbour *neigh_get_idx(struct seq_file *seq, loff_t *pos)
-{
-       struct neighbour *n = neigh_get_first(seq);
-
-       if (n)
-               while (*pos && (n = neigh_get_next(seq, n)))
-                       --*pos;
-       return *pos ? NULL : n;
-}
-
-static struct pneigh_entry *pneigh_get_first(struct seq_file *seq)
-{
-       struct arp_iter_state* state = seq->private;
-       struct pneigh_entry *pn;
-
-       state->is_pneigh = 1;
-
-       for (state->bucket = 0;
-            state->bucket <= PNEIGH_HASHMASK;
-            ++state->bucket) {
-               pn = arp_tbl.phash_buckets[state->bucket];
-               if (pn)
-                       break;
-       }
-       return pn;
-}
-
-static struct pneigh_entry *pneigh_get_next(struct seq_file *seq,
-                                           struct pneigh_entry *pn)
-{
-       struct arp_iter_state* state = seq->private;
-
-       pn = pn->next;
-       while (!pn) {
-               if (++state->bucket > PNEIGH_HASHMASK)
-                       break;
-               pn = arp_tbl.phash_buckets[state->bucket];
-       }
-       return pn;
-}
-
-static struct pneigh_entry *pneigh_get_idx(struct seq_file *seq, loff_t pos)
-{
-       struct pneigh_entry *pn = pneigh_get_first(seq);
-
-       if (pn)
-               while (pos && (pn = pneigh_get_next(seq, pn)))
-                       --pos;
-       return pos ? NULL : pn;
-}
-
-static void *arp_get_idx(struct seq_file *seq, loff_t pos)
-{
-       void *rc;
-
-       read_lock_bh(&arp_tbl.lock);
-       rc = neigh_get_idx(seq, &pos);
-
-       if (!rc) {
-               read_unlock_bh(&arp_tbl.lock);
-               rc = pneigh_get_idx(seq, pos);
-       }
-       return rc;
-}
-
-static void *arp_seq_start(struct seq_file *seq, loff_t *pos)
-{
-       struct arp_iter_state* state = seq->private;
-
-       state->is_pneigh = 0;
-       state->bucket = 0;
-       return *pos ? arp_get_idx(seq, *pos - 1) : SEQ_START_TOKEN;
-}
-
-static void *arp_seq_next(struct seq_file *seq, void *v, loff_t *pos)
-{
-       void *rc;
-       struct arp_iter_state* state;
-
-       if (v == SEQ_START_TOKEN) {
-               rc = arp_get_idx(seq, 0);
-               goto out;
-       }
-
-       state = seq->private;
-       if (!state->is_pneigh) {
-               rc = neigh_get_next(seq, v);
-               if (rc)
-                       goto out;
-               read_unlock_bh(&arp_tbl.lock);
-               rc = pneigh_get_first(seq);
-       } else
-               rc = pneigh_get_next(seq, v);
-out:
-       ++*pos;
-       return rc;
-}
-
-static void arp_seq_stop(struct seq_file *seq, void *v)
-{
-       struct arp_iter_state* state = seq->private;
-
-       if (!state->is_pneigh && v != SEQ_START_TOKEN)
-               read_unlock_bh(&arp_tbl.lock);
-}
-
 #define HBUFFERLEN 30
 
-static __inline__ void arp_format_neigh_entry(struct seq_file *seq,
-                                             struct neighbour *n)
+static void arp_format_neigh_entry(struct seq_file *seq,
+                                  struct neighbour *n)
 {
        char hbuffer[HBUFFERLEN];
        const char hexbuf[] = "0123456789ABCDEF";
@@ -1455,8 +1303,8 @@
        read_unlock(&n->lock);
 }
 
-static __inline__ void arp_format_pneigh_entry(struct seq_file *seq,
-                                              struct pneigh_entry *n)
+static void arp_format_pneigh_entry(struct seq_file *seq,
+                                   struct pneigh_entry *n)
 {
        struct net_device *dev = n->dev;
        int hatype = dev ? dev->type : 0;
@@ -1470,13 +1318,13 @@
 
 static int arp_seq_show(struct seq_file *seq, void *v)
 {
-       if (v == SEQ_START_TOKEN)
+       if (v == SEQ_START_TOKEN) {
                seq_puts(seq, "IP address       HW type     Flags       "
                              "HW address            Mask     Device\n");
-       else {
-               struct arp_iter_state* state = seq->private;
+       } else {
+               struct neigh_seq_state *state = seq->private;
 
-               if (state->is_pneigh)
+               if (state->flags & NEIGH_SEQ_IS_PNEIGH)
                        arp_format_pneigh_entry(seq, v);
                else
                        arp_format_neigh_entry(seq, v);
@@ -1485,12 +1333,20 @@
        return 0;
 }
 
+static void *arp_seq_start(struct seq_file *seq, loff_t *pos)
+{
+       /* Don't want to confuse "arp -a" w/ magic entries,
+        * so we tell the generic iterator to skip NUD_NOARP.
+        */
+       return neigh_seq_start(seq, pos, &arp_tbl, NEIGH_SEQ_SKIP_NOARP);
+}
+
 /* ------------------------------------------------------------------------ */
 
 static struct seq_operations arp_seq_ops = {
        .start  = arp_seq_start,
-       .next   = arp_seq_next,
-       .stop   = arp_seq_stop,
+       .next   = neigh_seq_next,
+       .stop   = neigh_seq_stop,
        .show   = arp_seq_show,
 };
 
@@ -1498,11 +1354,12 @@
 {
        struct seq_file *seq;
        int rc = -ENOMEM;
-       struct arp_iter_state *s = kmalloc(sizeof(*s), GFP_KERNEL);
+       struct neigh_seq_state *s = kmalloc(sizeof(*s), GFP_KERNEL);
        
        if (!s)
                goto out;
 
+       memset(s, 0, sizeof(*s));
        rc = seq_open(file, &arp_seq_ops);
        if (rc)
                goto out_kfree;

<Prev in Thread] Current Thread [Next in Thread>
  • [1/6]: Abstract neigh table walking, David S. Miller <=