一 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 邻居子系统介绍相关推荐

  1. Linux邻居子系统的细节之confirm-Open××× server模式的MAC地址学习

    在<Linux实现的ARP缓存老化时间原理解析>一文中,我剖析了Linux协议栈IPv4的邻居子系统的转化,再次贴出那个状态机转化图,可是这个图更详细了些,因为它有一个外部输入,那就是co ...

  2. Linux音频子系统(2) - ALSA ASoC

    1. linux音频子系统介绍 Linux音频系统比较复杂,各层间有很多交叉,可能是最无序的子系统. 1.1 ALSA ALSA 是 Advanced Linux Sound Architecture ...

  3. linux内核的邻居表,Linux内核报文收发-L3 - Section 3. IP协议、邻居子系统主要是接收、转发和发送三部分...

    版本说明 Linux版本: 3.10.103 网卡驱动: ixgbe 网络协议注册 inet_init主要是注册各种协议 注册TCP协议proto_register(&tcp_prot, 1) ...

  4. linux内核 邻居子系统

    基于linux2.4.0分析. 数据结构: struct neigh_table {//邻居表结构struct neigh_table *next;//指向队列中的下一个邻居表int family;/ ...

  5. tcp/ip 协议栈Linux内核源码分析11 邻居子系统分析二 arp协议的实现处理

    内核版本:3.4.39 内核邻居子系统定义了一个基本的框架,使得不同的邻居协议可以共用一套代码.比起其它的内核模块,邻居子系统框架代码还是比较简单易懂的.邻居子系统位于网络层和流量控制子系统中间,它提 ...

  6. tcp/ip 协议栈Linux内核源码分析十 邻居子系统分析一 概述通用邻居框架

    内核版本:3.4.39 为什么需要邻居子系统呢?因为在网络上发送报文的时候除了需要知道目的IP地址还需要知道邻居的L2 mac地址,为什么是邻居的L2地址而不是目的地的L2地址呢,这是因为目的地网络可 ...

  7. Linux Graphic DRI 显示子系统 介绍1

    1. 前言 图形子系统是linux系统中比较复杂的子系统之一:对下,它要管理形态各异的.性能各异的显示相关的器件:对上,它要向应用程序提供易用的.友好的.功能强大的图形用户界面(GUI).因此,它是l ...

  8. Linux设备模型、平台设备驱动、设备树(device tree)、GPIO子系统以及pinctrl子系统介绍

    文章目录 一.Linux设备模型介绍 (1)设备驱动模型总体介绍 (2)设备驱动模型文件表现 (3)设备驱动模型工作原理 [1]总线 [2]设备 [3]驱动 [4]注册流程 二.平台设备驱动介绍 (1 ...

  9. linux网络协议栈源码分析 - 邻居子系统邻居状态转移

    1.邻居项状态转移图 邻居项主要的状态转移如下(省略邻居项垃圾回收及转移原因,更权威详细的状态转移图参看<深入理解LINUX网络技术内幕>P648 "图26-13: NUD状态间 ...

最新文章

  1. PCL-1.8.1从源码搭建开发环境二(FLANN库的编译)
  2. 北大率先官宣朱松纯加盟,现身燕园,任职AI研究院院长,“AI发展离不开哲学思考”...
  3. OI常用的常数优化小技巧
  4. python模块用法教程_Python学习之asyncore模块用法实例教程
  5. 携程集团副总裁王韦:探索携程度假农庄发展新路径 打造“一村一旅游目的地”...
  6. fiddler 自动响应数据保存_想测试HTTP响应不知道如何开展怎么办?
  7. (转)jquery图片左右滚动
  8. pyqtSignal信号和槽
  9. 面试回忆之四:所投职位和背景极端不匹配的简历
  10. 3t硬盘 xp_解决方案:如何在Windows XP SP3 32位系统下识别3T容​​量GPT格式的硬盘...
  11. 用户故事与敏捷方法—Scrum与用户故事
  12. oc渲染器实时预览用的是编辑器细分,不是渲染器细分。
  13. 【什么是IaaS,PaaS,SaaS? DaaS又是什么?】
  14. Maple: 矩阵转置
  15. 甲骨文确认关闭中国研发中心
  16. Type-c快充加音频芯片深度解析(LDR6023C)
  17. 2019智能手表推荐_2020年买什么智能手表合适?
  18. 3D Touch介绍:电子秤App与快捷操作
  19. IOS之plist文件
  20. 美国IT业第一季度裁员4.9万人 失业率超过5%

热门文章

  1. #03 ASP.NET主题
  2. ESP32开发--使用NVS存储数据
  3. TTL、Ping包最大字节数、网络时延、抖动、丢包率,看完瞬间变大神!
  4. CentOS安装scp命令及其scp的使用
  5. android连接和断开蓝牙音箱的问题
  6. 携手绿凯智能,趣开门人脸识别门禁落地武汉光谷生物城
  7. 富而喜悦2023直播盛典 唐苓馨主题演说“特别的礼物”!
  8. 内网 centos7 离线安装rpm包的三种方法
  9. GIS开发之二维地下管线综合管理系统(Arcgis)第四节 查询(2)
  10. 微型计算机基础理论——计算机中的数制及其应用