summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid S. Miller <davem@nuts.davemloft.net>2004-09-24 02:05:14 -0700
committerDavid S. Miller <davem@kernel.bkbits.net>2004-09-24 02:05:14 -0700
commit0aced2d6835647edaf121d09f7bc811c7373ac6f (patch)
treea017a1e5ec34188d3763ab163652deef60be7564
parentaf6e4ad0b7a9d84e5a6d0cb79608ebcc9b2762fc (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.h1
-rw-r--r--net/core/neighbour.c66
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);