diff options
| author | David S. Miller <davem@nuts.davemloft.net> | 2004-09-24 02:05:14 -0700 |
|---|---|---|
| committer | David S. Miller <davem@kernel.bkbits.net> | 2004-09-24 02:05:14 -0700 |
| commit | 0aced2d6835647edaf121d09f7bc811c7373ac6f (patch) | |
| tree | a017a1e5ec34188d3763ab163652deef60be7564 | |
| parent | af6e4ad0b7a9d84e5a6d0cb79608ebcc9b2762fc (diff) | |
[NET]: Smooth out periodic neighbour GC.
Based almost entirely upon work by Tim Gardner
(timg@tpi.com) and Harald Welte (laforge@gnumonks.org)
Signed-off-by: David S. Miller <davem@davemloft.net>
| -rw-r--r-- | include/net/neighbour.h | 1 | ||||
| -rw-r--r-- | net/core/neighbour.c | 66 |
2 files changed, 37 insertions, 30 deletions
diff --git a/include/net/neighbour.h b/include/net/neighbour.h index 7b08b1220533..e66c71da2357 100644 --- a/include/net/neighbour.h +++ b/include/net/neighbour.h @@ -176,6 +176,7 @@ struct neigh_table struct neighbour **hash_buckets; unsigned int hash_mask; __u32 hash_rnd; + unsigned int hash_chain_gc; struct pneigh_entry **phash_buckets; }; diff --git a/net/core/neighbour.c b/net/core/neighbour.c index 69515e0083fd..7dd08adcd2c5 100644 --- a/net/core/neighbour.c +++ b/net/core/neighbour.c @@ -631,9 +631,8 @@ static void neigh_connect(struct neighbour *neigh) static void neigh_periodic_timer(unsigned long arg) { struct neigh_table *tbl = (struct neigh_table *)arg; - unsigned long now = jiffies; - int i; - + struct neighbour *n, **np; + unsigned long expire, now = jiffies; write_lock(&tbl->lock); @@ -649,41 +648,49 @@ static void neigh_periodic_timer(unsigned long arg) neigh_rand_reach_time(p->base_reachable_time); } - for (i = 0; i <= tbl->hash_mask; i++) { - struct neighbour *n, **np; + np = &tbl->hash_buckets[tbl->hash_chain_gc]; + tbl->hash_chain_gc = ((tbl->hash_chain_gc + 1) & tbl->hash_mask); - np = &tbl->hash_buckets[i]; - while ((n = *np) != NULL) { - unsigned state; + while ((n = *np) != NULL) { + unsigned int state; - write_lock(&n->lock); + write_lock(&n->lock); - state = n->nud_state; - if (state & (NUD_PERMANENT | NUD_IN_TIMER)) { - write_unlock(&n->lock); - goto next_elt; - } + state = n->nud_state; + if (state & (NUD_PERMANENT | NUD_IN_TIMER)) { + write_unlock(&n->lock); + goto next_elt; + } - if (time_before(n->used, n->confirmed)) - n->used = n->confirmed; + if (time_before(n->used, n->confirmed)) + n->used = n->confirmed; - if (atomic_read(&n->refcnt) == 1 && - (state == NUD_FAILED || - time_after(now, n->used + n->parms->gc_staletime))) { - *np = n->next; - n->dead = 1; - write_unlock(&n->lock); - neigh_release(n); - continue; - } + if (atomic_read(&n->refcnt) == 1 && + (state == NUD_FAILED || + time_after(now, n->used + n->parms->gc_staletime))) { + *np = n->next; + n->dead = 1; write_unlock(&n->lock); + neigh_release(n); + continue; + } + write_unlock(&n->lock); next_elt: - np = &n->next; - } + np = &n->next; } - mod_timer(&tbl->gc_timer, now + tbl->gc_interval); + /* Cycle through all hash buckets every base_reachable_time/2 ticks. + * ARP entry timeouts range from 1/2 base_reachable_time to 3/2 + * base_reachable_time. + */ + expire = tbl->parms.base_reachable_time >> 1; + expire /= (tbl->hash_mask + 1); + if (!expire) + expire = 1; + + mod_timer(&tbl->gc_timer, now + expire); + write_unlock(&tbl->lock); } @@ -1324,8 +1331,7 @@ void neigh_table_init(struct neigh_table *tbl) init_timer(&tbl->gc_timer); tbl->gc_timer.data = (unsigned long)tbl; tbl->gc_timer.function = neigh_periodic_timer; - tbl->gc_timer.expires = now + tbl->gc_interval + - tbl->parms.reachable_time; + tbl->gc_timer.expires = now + 1; add_timer(&tbl->gc_timer); init_timer(&tbl->proxy_timer); |
