Commit 0aced2d6 authored by David S. Miller's avatar David S. Miller Committed by David S. Miller

[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: default avatarDavid S. Miller <davem@davemloft.net>
parent af6e4ad0
...@@ -176,6 +176,7 @@ struct neigh_table ...@@ -176,6 +176,7 @@ struct neigh_table
struct neighbour **hash_buckets; struct neighbour **hash_buckets;
unsigned int hash_mask; unsigned int hash_mask;
__u32 hash_rnd; __u32 hash_rnd;
unsigned int hash_chain_gc;
struct pneigh_entry **phash_buckets; struct pneigh_entry **phash_buckets;
}; };
......
...@@ -631,9 +631,8 @@ static void neigh_connect(struct neighbour *neigh) ...@@ -631,9 +631,8 @@ static void neigh_connect(struct neighbour *neigh)
static void neigh_periodic_timer(unsigned long arg) static void neigh_periodic_timer(unsigned long arg)
{ {
struct neigh_table *tbl = (struct neigh_table *)arg; struct neigh_table *tbl = (struct neigh_table *)arg;
unsigned long now = jiffies; struct neighbour *n, **np;
int i; unsigned long expire, now = jiffies;
write_lock(&tbl->lock); write_lock(&tbl->lock);
...@@ -649,41 +648,49 @@ static void neigh_periodic_timer(unsigned long arg) ...@@ -649,41 +648,49 @@ static void neigh_periodic_timer(unsigned long arg)
neigh_rand_reach_time(p->base_reachable_time); neigh_rand_reach_time(p->base_reachable_time);
} }
for (i = 0; i <= tbl->hash_mask; i++) { np = &tbl->hash_buckets[tbl->hash_chain_gc];
struct neighbour *n, **np; tbl->hash_chain_gc = ((tbl->hash_chain_gc + 1) & tbl->hash_mask);
np = &tbl->hash_buckets[i]; while ((n = *np) != NULL) {
while ((n = *np) != NULL) { unsigned int state;
unsigned state;
write_lock(&n->lock); write_lock(&n->lock);
state = n->nud_state; state = n->nud_state;
if (state & (NUD_PERMANENT | NUD_IN_TIMER)) { if (state & (NUD_PERMANENT | NUD_IN_TIMER)) {
write_unlock(&n->lock); write_unlock(&n->lock);
goto next_elt; goto next_elt;
} }
if (time_before(n->used, n->confirmed)) if (time_before(n->used, n->confirmed))
n->used = n->confirmed; n->used = n->confirmed;
if (atomic_read(&n->refcnt) == 1 && if (atomic_read(&n->refcnt) == 1 &&
(state == NUD_FAILED || (state == NUD_FAILED ||
time_after(now, n->used + n->parms->gc_staletime))) { time_after(now, n->used + n->parms->gc_staletime))) {
*np = n->next; *np = n->next;
n->dead = 1; n->dead = 1;
write_unlock(&n->lock);
neigh_release(n);
continue;
}
write_unlock(&n->lock); write_unlock(&n->lock);
neigh_release(n);
continue;
}
write_unlock(&n->lock);
next_elt: 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); write_unlock(&tbl->lock);
} }
...@@ -1324,8 +1331,7 @@ void neigh_table_init(struct neigh_table *tbl) ...@@ -1324,8 +1331,7 @@ void neigh_table_init(struct neigh_table *tbl)
init_timer(&tbl->gc_timer); init_timer(&tbl->gc_timer);
tbl->gc_timer.data = (unsigned long)tbl; tbl->gc_timer.data = (unsigned long)tbl;
tbl->gc_timer.function = neigh_periodic_timer; tbl->gc_timer.function = neigh_periodic_timer;
tbl->gc_timer.expires = now + tbl->gc_interval + tbl->gc_timer.expires = now + 1;
tbl->parms.reachable_time;
add_timer(&tbl->gc_timer); add_timer(&tbl->gc_timer);
init_timer(&tbl->proxy_timer); init_timer(&tbl->proxy_timer);
......
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