加入收藏 | 设为首页 | 会员中心 | 我要投稿 应用网_丽江站长网 (http://www.0888zz.com/)- 科技、建站、数据工具、云上网络、机器学习!
当前位置: 首页 > 服务器 > 搭建环境 > Linux > 正文

Linux内核分析 - 网络[九]:邻居表

发布时间:2016-05-28 22:17:43 所属栏目:Linux 来源:网络整理
导读:内核版本:2.6.34 这部分的重点是三个核心的数据结构-邻居表、邻居缓存、代理邻居表,以及NUD状态转移图。 总的来说,要成功添加一条邻居表项,需要满足两个条

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;     
}

(编辑:应用网_丽江站长网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

热点阅读