arp: fix seq_file support

parent aaf75c12
...@@ -1142,65 +1142,115 @@ struct arp_iter_state { ...@@ -1142,65 +1142,115 @@ struct arp_iter_state {
int is_pneigh, bucket; int is_pneigh, bucket;
}; };
static __inline__ struct neighbour *neigh_get_bucket(struct seq_file *seq, static struct neighbour *neigh_get_first(struct seq_file *seq)
loff_t *pos)
{ {
struct neighbour *n = NULL;
struct arp_iter_state* state = seq->private; struct arp_iter_state* state = seq->private;
loff_t l = *pos; struct neighbour *n;
int i;
state->is_pneigh = 0;
for (; state->bucket <= NEIGH_HASHMASK; ++state->bucket)
for (i = 0, n = arp_tbl.hash_buckets[state->bucket]; n; for (state->bucket = 0;
++i, n = n->next) state->bucket <= NEIGH_HASHMASK;
/* Do not confuse users "arp -a" with magic entries */ ++state->bucket) {
if ((n->nud_state & ~NUD_NOARP) && !l--) { n = arp_tbl.hash_buckets[state->bucket];
*pos = i; while (n && !(n->nud_state & ~NUD_NOARP))
goto out; n = n->next;
} if (n)
out: break;
}
return n; return n;
} }
static __inline__ struct pneigh_entry *pneigh_get_bucket(struct seq_file *seq, static struct neighbour *neigh_get_next(struct seq_file *seq,
loff_t *pos) struct neighbour *n)
{ {
struct pneigh_entry *n = NULL;
struct arp_iter_state* state = seq->private; struct arp_iter_state* state = seq->private;
loff_t l = *pos;
int i; do {
n = n->next;
for (; state->bucket <= PNEIGH_HASHMASK; ++state->bucket) /* Don't confuse "arp -a" w/ magic entries */
for (i = 0, n = arp_tbl.phash_buckets[state->bucket]; n; try_again:
++i, n = n->next) } while (n && !(n->nud_state & ~NUD_NOARP));
if (!l--) {
*pos = i; if (n)
goto out; goto out;
} if (++state->bucket > NEIGH_HASHMASK)
goto out;
n = arp_tbl.hash_buckets[state->bucket];
goto try_again;
out: out:
return n; return n;
} }
static __inline__ void *arp_get_bucket(struct seq_file *seq, loff_t *pos) static struct neighbour *neigh_get_idx(struct seq_file *seq, loff_t *pos)
{ {
void *rc = neigh_get_bucket(seq, pos); struct neighbour *n = neigh_get_first(seq);
if (!rc) { if (n)
struct arp_iter_state* state = seq->private; 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); read_unlock_bh(&arp_tbl.lock);
state->is_pneigh = 1; rc = pneigh_get_idx(seq, pos);
state->bucket = 0;
*pos = 0;
rc = pneigh_get_bucket(seq, pos);
} }
return rc; return rc;
} }
static void *arp_seq_start(struct seq_file *seq, loff_t *pos) static void *arp_seq_start(struct seq_file *seq, loff_t *pos)
{ {
read_lock_bh(&arp_tbl.lock); return *pos ? arp_get_idx(seq, *pos - 1) : (void *)1;
return *pos ? arp_get_bucket(seq, pos) : (void *)1;
} }
static void *arp_seq_next(struct seq_file *seq, void *v, loff_t *pos) static void *arp_seq_next(struct seq_file *seq, void *v, loff_t *pos)
...@@ -1209,38 +1259,19 @@ static void *arp_seq_next(struct seq_file *seq, void *v, loff_t *pos) ...@@ -1209,38 +1259,19 @@ static void *arp_seq_next(struct seq_file *seq, void *v, loff_t *pos)
struct arp_iter_state* state; struct arp_iter_state* state;
if (v == (void *)1) { if (v == (void *)1) {
rc = arp_get_bucket(seq, pos); rc = arp_get_idx(seq, 0);
goto out; goto out;
} }
state = seq->private; state = seq->private;
if (!state->is_pneigh) { if (!state->is_pneigh) {
struct neighbour *n = v; rc = neigh_get_next(seq, v);
rc = n = n->next;
if (n)
goto out;
*pos = 0;
++state->bucket;
rc = neigh_get_bucket(seq, pos);
if (rc) if (rc)
goto out; goto out;
read_unlock_bh(&arp_tbl.lock); read_unlock_bh(&arp_tbl.lock);
state->is_pneigh = 1; rc = pneigh_get_first(seq);
state->bucket = 0; } else
*pos = 0; rc = pneigh_get_next(seq, v);
rc = pneigh_get_bucket(seq, pos);
} else {
struct pneigh_entry *pn = v;
pn = pn->next;
if (!pn) {
++state->bucket;
*pos = 0;
pn = pneigh_get_bucket(seq, pos);
}
rc = pn;
}
out: out:
++*pos; ++*pos;
return rc; return rc;
...@@ -1291,7 +1322,6 @@ static __inline__ void arp_format_neigh_entry(struct seq_file *seq, ...@@ -1291,7 +1322,6 @@ static __inline__ void arp_format_neigh_entry(struct seq_file *seq,
static __inline__ void arp_format_pneigh_entry(struct seq_file *seq, static __inline__ void arp_format_pneigh_entry(struct seq_file *seq,
struct pneigh_entry *n) struct pneigh_entry *n)
{ {
struct net_device *dev = n->dev; struct net_device *dev = n->dev;
int hatype = dev ? dev->type : 0; int hatype = dev ? dev->type : 0;
char tbuf[16]; char tbuf[16];
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment