Linux内核分析 - 网络[九]:邻居表
neigh_periodic_work NUD_STALE状态的定时函数 当neigh处于NUD_STALE状态时,此时它等待一段 时间,主机引用到它,从而转入NUD_DELAY状态;没有引用,则转入NUD_FAIL,被释放。不同于NUD_INCOMPLETE、NUD_DELAY、 NUD_PROBE、NUD_REACHABLE状态时的定时器,这里使用的异步机制,通过定期触发neigh_periodic_work()来检查NUD_STALE状态 。 tbl->parms.base_reachable_time = 30 HZ 当初始化邻居表时,添加了neigh_periodic_work工作 neigh_table_init() -> neigh_table_init_no_netlink(): INIT_DELAYED_WORK_DEFERRABLE(&tbl- >gc_work, neigh_periodic_work); 当neigh_periodic_work执行时,首先计算到达时间(reachable_time),其中要 注意的是 p->reachable_time = neigh_rand_reach_time(p->base_reachable_time); unsigned long neigh_rand_reach_time(unsigned long base) { return (base ? (net_random() % base) + (base >> 1) : 0); } 因此,reachable_time实际取值是1/2 base ~ 2/3 base,而base = base_reachable_time,当表项处于 NUD_REACHABLE状态时,会启动一个定时器,时长为reachable_time,即一个表项在不被使用时存活时间是1/2 base_reachable_time ~ 2/3 base_reachable_time。 然后它会遍历整个邻居表,每个hash_buckets的每个表项,如果在 gc_staletime内仍未被引用过,则会从邻居表中清除。
for (i = 0 ; i <= tbl->hash_mask; i++) { np = &tbl->hash_buckets[i]; while ((n = *np) != NULL) { ….. if (atomic_read(&n->refcnt) == 1 && (state == NUD_FAILED || time_after(jiffies, n->used + n->parms->gc_staletime))) { *np = n->next; n->dead = 1; write_unlock(&n->lock); neigh_cleanup_and_release(n); continue; } …… } 在工作最后,再次添加该工作到队列中,并延时1/2 base_reachable_time开始执行,这样,完成了 neigh_periodic_work工作每隔1/2 base_reachable_time执行一次。 schedule_delayed_work(&tbl->gc_work, tbl- >parms.base_reachable_time >> 1); neigh_periodic_work定期执行,但要保证表项不会刚添加就被 neigh_periodic_work清理掉,这里的策略是:gc_staletime大于1/2 base_reachable_time。默认的,gc_staletime = 30, base_reachable_time = 30。也就是说,neigh_periodic_work会每15HZ执行一次,但表项在NUD_STALE的存活时间是30HZ,这样 ,保证了每项在最差情况下也有(30 - 15)HZ的生命周期。 neigh_update 邻居表项状态更新 如果新状态是非有效(! NUD_VALID),那么要做的就是删除该表项:停止定时器neigh_del_timer,设置neigh状态nud_state为新状态new。除此之外,当 是NUD_INCOMPLETE或NUD_PROBE状态时,可能有暂时因为地址没有解析而暂存在neigh->arp_queue中的报文,而现在表项更新 到NUD_FAILED,即解析无法成功,那么这么暂存的报文也只能被丢弃neigh_invalidate。 if (!(new & NUD_VALID)) { neigh_del_timer(neigh); if (old & NUD_CONNECTED) neigh_suspect(neigh); neigh->nud_state = new; err = 0; notify = old & NUD_VALID; if ((old & (NUD_INCOMPLETE | NUD_PROBE)) && (new & NUD_FAILED)) { neigh_invalidate(neigh); notify = 1; } goto out; } 中间这段代码是对比表项的地址是否发生了变化,略过。#个人认为NUD_REACHABLE状态时,新状态为NUD_STALE是在 下面这段代码里面除去了,因为NUD_REACHABLE状态更好,不应该回退到NUD_STALE状态。但是当是NUD_DELAY, NUD_PROBE, NUD_INCOMPLETE时仍会被更新到NUD_STALE状态,对此很不解??? else { if (lladdr == neigh->ha && new == NUD_STALE && ((flags & NEIGH_UPDATE_F_WEAK_OVERRIDE) || (old & NUD_CONNECTED))) new = old; } (编辑:应用网_丽江站长网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |