概述

在分配邻居子系统之后,会设置定时器来处理那些需要定时器处理的状态,定时器回调函数为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的更多相关文章

  1. 邻居子系统 之 更新neigh_update

    概述 neigh_update函数用来更新指定的邻居项,更新内容是硬件地址和状态,更新之后,会根据新状态设置其输出函数,CONNECTED状态则使用快速输出,否则使用慢速输出:如果是由原来的无效状态变 ...

  2. 邻居子系统 之 邻居项创建__neigh_create

    概述 IP层输出数据包会根据路由的下一跳查询邻居项,如果不存在则会调用__neigh_create创建邻居项,然后调用邻居项的output函数进行输出: __neigh_create完成邻居项的创建, ...

  3. 邻居子系统输出 之 neigh_output、neigh_hh_output

    概述 ip层在构造好ip头,检查完分片之后,会调用邻居子系统的输出函数neigh_output进行输出,输出分为有二层头缓存和没有两种情况,有缓存时调用neigh_hh_output进行快速输出,没有 ...

  4. jQuery使用():Deferred有状态的回调列表(含源码)

    deferred的功能及其使用 deferred的实现原理及模拟源码 一.deferred的功能及其使用 deferred的底层是基于callbacks实现的,建议再熟悉callbacks的内部机制前 ...

  5. 邻居子系统 之 邻居表的初始化neigh_table_init

    概述 邻居子系统支持多种实现,例如ARP,ND等,这些实现需要在其初始化的时候,调用neigh_table_init将邻居表项添加到全局邻居子系统数组中,并对实例中的字段(如hash,定时器等)进行相 ...

  6. Linux时间子系统之四:定时器的引擎:clock_event_device

    早期的内核版本中,进程的调度基于一个称之为tick的时钟滴答,通常使用时钟中断来定时地产生tick信号,每次tick定时中断都会进行进程的统计和调度,并对tick进行计数,记录在一个jiffies变量 ...

  7. Linux时间子系统之七:定时器的应用--msleep(),hrtimer_nanosleep()

    我们已经在前面几章介绍了低分辨率定时器和高精度定时器的实现原理,内核为了方便其它子系统,在时间子系统中提供了一些用于延时或调度的API,例如msleep,hrtimer_nanosleep等等,这些A ...

  8. Linux时间子系统之七:定时器的应用--msleep(),hrtimer_nanosleep()【转】

    转自:http://blog.csdn.net/droidphone/article/details/8104433 我们已经在前面几章介绍了低分辨率定时器和高精度定时器的实现原理,内核为了方便其它子 ...

  9. Linux时间子系统之四:定时器的引擎:clock_event_device【转】

    本文转载自:http://blog.csdn.net/droidphone/article/details/8017604 版权声明:本文为博主原创文章,未经博主允许不得转载.   目录(?)[+] ...

随机推荐

  1. gdb-example-ncurses

    gdb-example-ncurses http://www.brendangregg.com/blog/2016-08-09/gdb-example-ncurses.html 1. The Prob ...

  2. C语言——指针总结

    在创建指针时,我们首先要做的是先初始化它,没有初始化的指针是很危险的,因为指针可以指向一个地址后直接改变它的值,所以为了避免我们的指针在创建后指向一个危险区域(即可能指向系统文件等),我们会先给它一个 ...

  3. 使用display:table实现两列自适应布局

    在张鑫旭大神那边看到的方法,我自己写了一遍,稍微添加了一些自己的风格特色. IE6/7不支持这个属性,从IE8开始支持这个属性,对于IE6/7可以用display:inline-block解决. ta ...

  4. R 读取xls/xlsx文件

    包readxl install.packages('readxl',repois='https://mirrors.utsc.edu.cn/CRAN/) library(readxl) # read_ ...

  5. 7.SpringMVC 配置式开发-ModelAndView和视图解析器

    ModelAndView 1.Model(模型) 1.model的本质就是HashMap,向模型中添加数据,就是往HashMap中去添加数据 2.HashMap 是一个单向查找数组,单向链表数组 3. ...

  6. Spring Cloud(二)服务提供者 Eureka + 服务消费者(rest + Ribbon)

    Ribbon是什么? Ribbon是Netflix发布的开源项目,主要功能是提供客户端的软件负载均衡算法,将Netflix的中间层服务连接在一起.Ribbon客户端组件提供一系列完善的配置项如连接超时 ...

  7. C# 一个数组集合,任意组合,不遗漏,不重复

    using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using S ...

  8. 二:MVC之LINQ查询语法

    LINQ(Language Integrated Query)语言集成查询是一组用于c#和Visual Basic语言的扩展.它允许编写C#或者Visual Basic代码以操作内存数据的方式,查询数 ...

  9. spring boot2X代码混淆

    为了防止代码很容易被反编译而造成泄露,所以打包时进行代码混淆 使用 proguard-maven-plugin插件 <build> <finalName>${artifactI ...

  10. appium+python 【Mac】UI自动化测试封装框架介绍 <二>---脚本编写(单设备)

    1.单设备的执行很简单,平时可多见的是直接在config中进行配置并进行运行即可.如下: # coding=UTF- ''' Created on // @author: SYW ''' from T ...