Linux 邻居子系统介绍
一 Linux网络邻居子系统简介
1.1邻居子系统
- MAC地址唯一标识一台主机,当系统要发送数据到其他主机时,必须事先知道它的MAC地址, 并且上层应用协议并不关心MAC地址,然而在数据链接层,必须要获取发送方和接收方的MAC地址,这样数据才能正确到达接收方。邻居子系统的作用就是把IP地址转换成对应的MAC地址. 如果目的主机不是和发送发位于同一局域网时,解析的MAC地址就是下一跳网关地址
二 邻居子系统协议和指令
Linux 系统中,通过一定的封装和抽象,实现了邻居协议基础框架层,具体的邻居协议定义各自的参数,然后注册到基础框架层,并使用基础层提供的API.Linux目前支持的邻居协议有ARP(ipv4), NDISC(ipv6),decnet,但是邻居协议只有简单的两条指令ARP_REQUEST和ARP_REPLY
2.1邻居通用基础结构功能
为每个协议缓存L3到L2的地址
提供缓存的添加,删除,改变和查找
为每个协议缓存的数据项提供老化机制
为每个邻居提供一个请求队列
2.2 源码和数据结构
net/core/neighbour.c :实现所有基础框架功能
struct neigh_table : 表示一个具体的邻居协议,通过neigh_table_init函数注册到neighbour
struct neigh_parms: 邻居协议参数,包含探测次数,探测间隔,垃圾回收时间,可到达性存活时间等
struct neighbour :表示一个具体的邻居,包含邻居的MAC地址,邻居状态,确认时间,output函数,数据缓冲队列
三 邻居子系统状态机
neighbour共有六种状态
#define NUD_INCOMPLETE 0x01 //正在进行邻居项MAC地址探测,但还没有收到应答
#define NUD_REACHABLE 0x02 //邻居项是可到达的
#define NUD_STALE 0x04 //长时间没有使用邻居项,
#define NUD_DELAY 0x08 //延时探测
#define NUD_PROBE 0x10 //探测状态
#define NUD_FAILED 0x20 //探测失败
从这六种状态,可以衍生出NUD_IN_TIMER,NUD_VALID,NUD_CONNECTE新状态
NUD_IN_TIMER (NUD_INCOMPLETE|NUD_REACHABLE|NUD_DELAY|NUD_PROBE)
NUD_VALID(NUD_PERMANENT|NUD_NOARP|NUD_REACHABLE|NUD_PROBE|NUD_STALE|NUD_DELAY)
NUD_CONNECTED (NUD_PERMANENT|NUD_NOARP|NUD_REACHABLE)
状态的实现函数为neigh_update,不仅会更新neighbour状态,还有处理和neighbour相关的数据缓存
四 邻居子系统定时器
邻居子系统使用了几个定时器,有些定时器是全局的,也有些是为每个邻居协议单独创建.
4.1 状态转移定时器
处理函数为neigh_timer_handler,负责neighbour的状态转换,以及根据当前状态进行MAC地址探测
static void neigh_timer_handler(unsigned long arg)
{
struct neighbour *neigh = (struct neighbour *)arg;
write_lock(&neigh->lock);
state = neigh->nud_state;
now = jiffies;
next = now + HZ;
/*如果不是处理in timer状态,则直接返回*/
if (!(state & NUD_IN_TIMER))
goto out;
/*依次对三种状态下的neighbour进行处理*/
if (state & NUD_REACHABLE) {
/*如果上次确认时间加上neigh存活时间比now靠后,这就说明此neigh没有过期 */
if (time_before_eq(now,
neigh->confirmed + neigh->parms->reachable_time)) {
neigh_dbg(2, "neigh %p is still alive\n", neigh);
next = neigh->confirmed + neigh->parms->reachable_time;
} else if (time_before_eq(now,/*now没有超过上一次使用的时间加上probe delay时间,则进入delay状态 */
neigh->used +
NEIGH_VAR(neigh->parms, DELAY_PROBE_TIME))) {
neigh_dbg(2, "neigh %p is delayed\n", neigh);
neigh->nud_state = NUD_DELAY;/*为什么会从reachable到delay了?这是为了延时发送ARP REQUST数据包 */
neigh->updated = jiffies;
neigh_suspect(neigh);
next = now + NEIGH_VAR(neigh->parms, DELAY_PROBE_TIME);
} else {
neigh_dbg(2, "neigh %p is suspected\n", neigh);
neigh->nud_state = NUD_STALE;//进入STALE状态,表示一段时间没有使用了
neigh->updated = jiffies;
neigh_suspect(neigh);
notify = 1;
}
} else if (state & NUD_DELAY) {
if (time_before_eq(now,
neigh->confirmed +
NEIGH_VAR(neigh->parms, DELAY_PROBE_TIME))) {
neigh_dbg(2, "neigh %p is now reachable\n", neigh);
neigh->nud_state = NUD_REACHABLE;/*在delay状态,收到了可到达性确认 */
neigh->updated = jiffies;
neigh_connect(neigh);
notify = 1;
next = neigh->confirmed + neigh->parms->reachable_time;
} else {
neigh_dbg(2, "neigh %p is probed\n", neigh);
neigh->nud_state = NUD_PROBE;/*在delay的时间段内,没有收到confirm,则需 要发送ARP REQUST数据包 */
neigh->updated = jiffies;
atomic_set(&neigh->probes, 0);
notify = 1;
next = now + NEIGH_VAR(neigh->parms, RETRANS_TIME);
}
} else {
/* NUD_PROBE|NUD_INCOMPLETE */
next = now + NEIGH_VAR(neigh->parms, RETRANS_TIME);
}
if (neigh->nud_state & (NUD_INCOMPLETE | NUD_PROBE)) {
neigh_probe(neigh);/*发送ARP REQUST数据包 */
} else {
out:
write_unlock(&neigh->lock);
}
if (notify)
neigh_update_notify(neigh);
neigh_release(neigh);
}
4.2 垃圾回收定时器
这是一个周期性的定时器,确保内存不会由于邻居项过多而导致占用过多内存的问题
处理函数为: neigh_periodic_work,垃圾回收有异步回收和同步回收两种.
五 ARP协议
5.1 ARP协议数据格式
硬件类型:以太网/令牌环等等
协议类型:ipv4,ipv6等等
硬件地址长度:MAC地址长度
协议地址长度:IP地址长度
操作码: REQUST和REPLY两种指令, 后面四个字段表示发送方和接收方的MAC和IP地址
5.2 ARP选项
通过arp选择,可以选择处理IP地址和过滤某些ARP包
arp_announce: 发送arp request时,控制怎么去选择源IP地址
0 : 任何本地IP都可以
1 : 如果可以,尽量选择与目的IP为同一子网的地址
2 : 优先使用主地址
arp_ignore
这个选项控制判断是否处理arp request的条件
0 :对任何本地地址ARP请求都应答
1 :如果目的IP地址配置在接收ARP请求的接口上,才应答
2 :在满足1的前提下,源IP和目的IP属于同一子网
3 :如果目的IP的scope不是本地主机,才应答
4-7 :保留.
8 不应答
> 未知值,接收请求
5.3 ARP处理函数
arp_rcv函数负责处理接收到的ARP_REQUST和ARP_REPLY指令,并作出相应的应答
if (arp->ar_op == htons(ARPOP_REQUEST) && //收到ARP_REQUEST指令
ip_route_input_noref(skb, tip, sip, 0, dev) == 0) {//必须知道如何到达请求方
rt = skb_rtable(skb);
addr_type = rt->rt_type;
if (addr_type == RTN_LOCAL) {
int dont_send;
/*判断ARP_IGNORE参数设置 */
dont_send = arp_ignore(in_dev, sip, tip);
if (!dont_send && IN_DEV_ARPFILTER(in_dev))
dont_send = arp_filter(sip, tip, dev);
if (!dont_send) {
/*这里是被动更新neighbour缓存 */
n = neigh_event_ns(&arp_tbl, sha, &sip, dev);
if (n) {/*发送ARP_REPLY应答 */
arp_send(ARPOP_REPLY, ETH_P_ARP, sip,
dev, tip, sha, dev->dev_addr,
sha);
neigh_release(n);
}
}
}
/* 更新ARP tables */
n = __neigh_lookup(&arp_tbl, &sip, dev, 0);
if (n) {
int state = NUD_REACHABLE;
int override;
/* If several different ARP replies follows back-to-back,
use the FIRST one. It is possible, if several proxy
agents are active. Taking the first reply prevents
arp trashing and chooses the fastest router.
*/
override = time_after(jiffies,
n->updated +
NEIGH_VAR(n->parms, LOCKTIME)) ||
is_garp;
/* Broadcast replies and request packets
do not assert neighbour reachability.
*/
if (arp->ar_op != htons(ARPOP_REPLY) ||
skb->pkt_type != PACKET_HOST)
state = NUD_STALE;
/*更新neighbour状态 */
neigh_update(n, sha, state,
override ? NEIGH_UPDATE_F_OVERRIDE : 0);
neigh_release(n);
}
Linux 邻居子系统介绍相关推荐
- Linux邻居子系统的细节之confirm-Open××× server模式的MAC地址学习
在<Linux实现的ARP缓存老化时间原理解析>一文中,我剖析了Linux协议栈IPv4的邻居子系统的转化,再次贴出那个状态机转化图,可是这个图更详细了些,因为它有一个外部输入,那就是co ...
- Linux音频子系统(2) - ALSA ASoC
1. linux音频子系统介绍 Linux音频系统比较复杂,各层间有很多交叉,可能是最无序的子系统. 1.1 ALSA ALSA 是 Advanced Linux Sound Architecture ...
- linux内核的邻居表,Linux内核报文收发-L3 - Section 3. IP协议、邻居子系统主要是接收、转发和发送三部分...
版本说明 Linux版本: 3.10.103 网卡驱动: ixgbe 网络协议注册 inet_init主要是注册各种协议 注册TCP协议proto_register(&tcp_prot, 1) ...
- linux内核 邻居子系统
基于linux2.4.0分析. 数据结构: struct neigh_table {//邻居表结构struct neigh_table *next;//指向队列中的下一个邻居表int family;/ ...
- tcp/ip 协议栈Linux内核源码分析11 邻居子系统分析二 arp协议的实现处理
内核版本:3.4.39 内核邻居子系统定义了一个基本的框架,使得不同的邻居协议可以共用一套代码.比起其它的内核模块,邻居子系统框架代码还是比较简单易懂的.邻居子系统位于网络层和流量控制子系统中间,它提 ...
- tcp/ip 协议栈Linux内核源码分析十 邻居子系统分析一 概述通用邻居框架
内核版本:3.4.39 为什么需要邻居子系统呢?因为在网络上发送报文的时候除了需要知道目的IP地址还需要知道邻居的L2 mac地址,为什么是邻居的L2地址而不是目的地的L2地址呢,这是因为目的地网络可 ...
- Linux Graphic DRI 显示子系统 介绍1
1. 前言 图形子系统是linux系统中比较复杂的子系统之一:对下,它要管理形态各异的.性能各异的显示相关的器件:对上,它要向应用程序提供易用的.友好的.功能强大的图形用户界面(GUI).因此,它是l ...
- Linux设备模型、平台设备驱动、设备树(device tree)、GPIO子系统以及pinctrl子系统介绍
文章目录 一.Linux设备模型介绍 (1)设备驱动模型总体介绍 (2)设备驱动模型文件表现 (3)设备驱动模型工作原理 [1]总线 [2]设备 [3]驱动 [4]注册流程 二.平台设备驱动介绍 (1 ...
- linux网络协议栈源码分析 - 邻居子系统邻居状态转移
1.邻居项状态转移图 邻居项主要的状态转移如下(省略邻居项垃圾回收及转移原因,更权威详细的状态转移图参看<深入理解LINUX网络技术内幕>P648 "图26-13: NUD状态间 ...
最新文章
- PCL-1.8.1从源码搭建开发环境二(FLANN库的编译)
- 北大率先官宣朱松纯加盟,现身燕园,任职AI研究院院长,“AI发展离不开哲学思考”...
- OI常用的常数优化小技巧
- python模块用法教程_Python学习之asyncore模块用法实例教程
- 携程集团副总裁王韦:探索携程度假农庄发展新路径 打造“一村一旅游目的地”...
- fiddler 自动响应数据保存_想测试HTTP响应不知道如何开展怎么办?
- (转)jquery图片左右滚动
- pyqtSignal信号和槽
- 面试回忆之四:所投职位和背景极端不匹配的简历
- 3t硬盘 xp_解决方案:如何在Windows XP SP3 32位系统下识别3T容​​量GPT格式的硬盘...
- 用户故事与敏捷方法—Scrum与用户故事
- oc渲染器实时预览用的是编辑器细分,不是渲染器细分。
- 【什么是IaaS,PaaS,SaaS? DaaS又是什么?】
- Maple: 矩阵转置
- 甲骨文确认关闭中国研发中心
- Type-c快充加音频芯片深度解析(LDR6023C)
- 2019智能手表推荐_2020年买什么智能手表合适?
- 3D Touch介绍:电子秤App与快捷操作
- IOS之plist文件
- 美国IT业第一季度裁员4.9万人 失业率超过5%