邻居子系统 之 状态定时器回调neigh_timer_handler
概述
在分配邻居子系统之后,会设置定时器来处理那些需要定时器处理的状态,定时器回调函数为neigh_timer_handler;函数会根据状态机变换规则对状态进行切换,切换状态后,如果需要更新输出函数则更新,并更新定时器下一次超时时间;其中NUD_INCOMPLETE | NUD_PROBE状态需要发送邻居请求,如果超过最大次数,则释放缓存中的数据包;
源码分析
/* 邻居项各个状态的定时器处理回调 */
static void neigh_timer_handler(unsigned long arg)
{
unsigned long now, next;
struct neighbour *neigh = (struct neighbour *)arg;
unsigned int state;
int notify = ; write_lock(&neigh->lock); state = neigh->nud_state;
now = jiffies;
next = now + HZ; /* 无定时器状态 */
if (!(state & NUD_IN_TIMER))
goto out; /* REACHABLE状态 */
if (state & NUD_REACHABLE) {
/* 确认时间未超时,设置下次超时时间 */
if (time_before_eq(now,
neigh->confirmed + neigh->parms->reachable_time)) {
neigh_dbg(, "neigh %p is still alive\n", neigh);
next = neigh->confirmed + neigh->parms->reachable_time;
}
/* 确认时间已经超时了,但是闲置时间未达到 */
else if (time_before_eq(now,
neigh->used +
NEIGH_VAR(neigh->parms, DELAY_PROBE_TIME))) {
neigh_dbg(, "neigh %p is delayed\n", neigh);
/* 进入DELAY状态 */
neigh->nud_state = NUD_DELAY;
neigh->updated = jiffies; /* 更新output函数 */
neigh_suspect(neigh);
next = now + NEIGH_VAR(neigh->parms, DELAY_PROBE_TIME);
}
/* 确认时间和闲置时间都超时了 */
else {
neigh_dbg(, "neigh %p is suspected\n", neigh);
/* 进入STALE状态 */
neigh->nud_state = NUD_STALE;
neigh->updated = jiffies;
/* 更新输出函数 */
neigh_suspect(neigh);
notify = ;
}
}
/* DELAY状态 */
else if (state & NUD_DELAY) {
/* 最后一次确认时间没达到超时时间 */
if (time_before_eq(now,
neigh->confirmed +
NEIGH_VAR(neigh->parms, DELAY_PROBE_TIME))) {
neigh_dbg(, "neigh %p is now reachable\n", neigh); /* 进入REACHABLE状态,更新输出函数 */
neigh->nud_state = NUD_REACHABLE;
neigh->updated = jiffies;
neigh_connect(neigh);
notify = ;
next = neigh->confirmed + neigh->parms->reachable_time;
}
/* 最后确认时间已经达到了超时时间,进入PROBE状态 */
else {
neigh_dbg(, "neigh %p is probed\n", neigh);
neigh->nud_state = NUD_PROBE;
neigh->updated = jiffies;
atomic_set(&neigh->probes, );
notify = ;
next = now + NEIGH_VAR(neigh->parms, RETRANS_TIME);
}
}
/* NUD_PROBE|NUD_INCOMPLETE */
else {
/* NUD_PROBE|NUD_INCOMPLETE */
next = now + NEIGH_VAR(neigh->parms, RETRANS_TIME);
} /* NUD_PROBE|NUD_INCOMPLETE状态,达到了最大尝试次数 */
if ((neigh->nud_state & (NUD_INCOMPLETE | NUD_PROBE)) &&
atomic_read(&neigh->probes) >= neigh_max_probes(neigh)) {
/* 进入FAILED状态,清空缓存包队列 */
neigh->nud_state = NUD_FAILED;
notify = ;
neigh_invalidate(neigh);
goto out;
} /* 定时器处理状态,则更新定时器 */
if (neigh->nud_state & NUD_IN_TIMER) {
if (time_before(next, jiffies + HZ/))
next = jiffies + HZ/;
if (!mod_timer(&neigh->timer, next))
neigh_hold(neigh);
} /* NUD_PROBE|NUD_INCOMPLETE状态,发送请求包 */
if (neigh->nud_state & (NUD_INCOMPLETE | NUD_PROBE)) {
neigh_probe(neigh);
} else {
out:
write_unlock(&neigh->lock);
} /* 通知关心的模块 */
if (notify)
neigh_update_notify(neigh, ); neigh_release(neigh);
}
邻居子系统 之 状态定时器回调neigh_timer_handler的更多相关文章
- 邻居子系统 之 更新neigh_update
概述 neigh_update函数用来更新指定的邻居项,更新内容是硬件地址和状态,更新之后,会根据新状态设置其输出函数,CONNECTED状态则使用快速输出,否则使用慢速输出:如果是由原来的无效状态变 ...
- 邻居子系统 之 邻居项创建__neigh_create
概述 IP层输出数据包会根据路由的下一跳查询邻居项,如果不存在则会调用__neigh_create创建邻居项,然后调用邻居项的output函数进行输出: __neigh_create完成邻居项的创建, ...
- 邻居子系统输出 之 neigh_output、neigh_hh_output
概述 ip层在构造好ip头,检查完分片之后,会调用邻居子系统的输出函数neigh_output进行输出,输出分为有二层头缓存和没有两种情况,有缓存时调用neigh_hh_output进行快速输出,没有 ...
- jQuery使用():Deferred有状态的回调列表(含源码)
deferred的功能及其使用 deferred的实现原理及模拟源码 一.deferred的功能及其使用 deferred的底层是基于callbacks实现的,建议再熟悉callbacks的内部机制前 ...
- 邻居子系统 之 邻居表的初始化neigh_table_init
概述 邻居子系统支持多种实现,例如ARP,ND等,这些实现需要在其初始化的时候,调用neigh_table_init将邻居表项添加到全局邻居子系统数组中,并对实例中的字段(如hash,定时器等)进行相 ...
- Linux时间子系统之四:定时器的引擎:clock_event_device
早期的内核版本中,进程的调度基于一个称之为tick的时钟滴答,通常使用时钟中断来定时地产生tick信号,每次tick定时中断都会进行进程的统计和调度,并对tick进行计数,记录在一个jiffies变量 ...
- Linux时间子系统之七:定时器的应用--msleep(),hrtimer_nanosleep()
我们已经在前面几章介绍了低分辨率定时器和高精度定时器的实现原理,内核为了方便其它子系统,在时间子系统中提供了一些用于延时或调度的API,例如msleep,hrtimer_nanosleep等等,这些A ...
- Linux时间子系统之七:定时器的应用--msleep(),hrtimer_nanosleep()【转】
转自:http://blog.csdn.net/droidphone/article/details/8104433 我们已经在前面几章介绍了低分辨率定时器和高精度定时器的实现原理,内核为了方便其它子 ...
- Linux时间子系统之四:定时器的引擎:clock_event_device【转】
本文转载自:http://blog.csdn.net/droidphone/article/details/8017604 版权声明:本文为博主原创文章,未经博主允许不得转载. 目录(?)[+] ...
随机推荐
- Swagger学习(三、配置扫描接口)
生产环境中使用,发布的时候不能使用
- HTTP请求方式及其区别
一.请求方式 所有的请求都可以给服务器传递内容,也可以从服务器获取内容. GET:从服务器获取数据(给的少拿的多) POST:向服务器推送数据(给的多拿的少) DELETE:删除服务器的一些内容 PU ...
- react——css样式
1.行内样式: 两个大括号包着.第一个大括号表示里面写js,第二个大括号里面是样式对象 2.传对象 将对象和结构分离,直接写一个大括号,里面写对象 3.将所有的样式对象合并成一个大对象,直接点 以上样 ...
- Spring源码解析 - springMVC核心代码
一.首先来讲解下springMVC的底层工作流程 1.首先我们重点放在前端控制器(DispatcherServlet) 其类图: 因为从流程图看,用户的请求最先到达就是DispatcherServle ...
- C#遍历文件夹下的所有文件
DirectoryInfo theFolder = new DirectoryInfo(path); DirectoryInfo[] dirInfo = theFolder.GetDirectorie ...
- git回退到历史版本
问题描述 在开发的过程中,想要修改一个参数的命名.然后修改各种地方,并且push上码云的远程仓库.然后突然发现还要改很多地方,突然后悔不想改动了.那该怎么办呢? 处理步骤 回退本地的git版本 将本地 ...
- Linux系统上对其他用户隐藏进程的简单方法
mount -o remount,rw,hidepid=2 /proc 我使用的是多用户系统,大部分的用户通过ssh客户端访问他们的资源.我如何(怎么样)避免泄露进程信息给他们?如何(怎么样)在Deb ...
- Js操作DOM元素及获取浏览器高宽
在JavaScript中,经常会来获取Document文档元素,是 HTML 文档对象模型的英文缩写,Document Object Model for HTML,是基于浏览器编程,HTML DOM ...
- java线程基础巩固---线程生命周期以及start方法源码剖析
上篇中介绍了如何启动一个线程,通过调用start()方法才能创建并使用新线程,并且这个start()是非阻塞的,调用之后立马就返回的,实际上它是线程生命周期环节中的一种,所以这里阐述一下线程的一个完整 ...
- faucet搭建(linux/win)
sudo apt-get install libssl-dev pip3 install flaskpip3 install flask_scriptpip3 install flask_sqlalc ...