鄰居項的垃圾回收
為了避免浪費不必要的存儲空間,鄰居子系統維護著一套垃圾回收機制,它將失效的或者是長時間末使用的鄰居項刪除。
回憶一下,在鄰居表(neigh_table)中有一個定時器struct timer_list gc_timer結構,我們看它是怎麼初始化的。
在neigh_table_init()中
{
…
….
init_timer(&tbl->gc_timer);
tbl->gc_timer.data = (unsigned long)tbl;
tbl->gc_timer.function = neigh_periodic_timer;
tbl->gc_timer.expires = now + 1;
add_timer(&tbl->gc_timer;
…
}
在一滴答之後,計時器超時,運行計時器處理函數neigh_periodic_timer()
static void neigh_periodic_timer(unsigned long arg)
{
struct neigh_table *tbl = (struct neigh_table *)arg;
struct neighbour *n, **np;
unsigned long expire, now = jiffies;
NEIGH_CACHE_STAT_INC(tbl, periodic_gc_runs);
write_lock(&tbl->lock);
/*
* periodically recompute ReachableTime from random function
*/
//每300HZ隨機初始化REACHABLE狀態超時時間
if (time_after(now, tbl->last_rand + 300 * HZ)) {
struct neigh_parms *p;
tbl->last_rand = now;
for (p = &tbl->parms; p; p = p->next)
p->reachable_time =
neigh_rand_reach_time(p->base_reachable_time);
}
//hash_chain_gc在初始化函數中並末處理
//所以,此處為零
np = &tbl->hash_buckets[tbl->hash_chain_gc];
//使hash_chain_gc指向下一項,如過超過最大值hash_mash
//則又返回到初始值
tbl->hash_chain_gc = ((tbl->hash_chain_gc + 1) & tbl->hash_mask);
while ((n = *np) != NULL) {
unsigned int state;
write_lock(&n->lock);
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;
//如果引用計數為1,且狀態為FAILED,則狀其刪除,並
//釋放其所占的空間
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;
}
/* 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);
}