linux网络协议栈(四)链路层 (3)邻居子系统ARP

2024-05-09 22:32

本文主要是介绍linux网络协议栈(四)链路层 (3)邻居子系统ARP,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

4.3、邻居子系统+ARP:

4.3.1、什么是邻居:

所谓邻居就是二层直连的两个主机,如A与B直连或者A与B通过二层交换机连接,都是邻居。邻居子系统的作用是就是实现L3地址和L2地址的映射关系。

邻居子系统本身只实现一个通用架构,具体实现按照具体的L3协议和L2协议确定,如对于IPV4/ethernet,ARP协议就是邻居子系统的实现内容,对于IPV6/ethernet则是ND协议,对于其他的L3协议和L2协议还会有其他的协议。事实上理解了邻居子系统,也就理解了ARP或其他L2.5协议。

在详细描述邻居子系统之前,首先仔细感受下它到底的用途是什么,在输入报文需要转发,以及输出报文的处理,在其路由缓存条目的路由结果dst_entry中的output方法都会设置为ip_output函数,output方法是离开L3层的处理方法,也就是说无论输入报文需要转发还是输出报文,都要调用ip_output函数离开L3层进入L2层,该函数逻辑如下图:


注意记录出接口的操作,这是非常重要的一个容易被忽略的地方,接下来是函数ip_finish_output,它的主要任务是处理分帧,关于分帧详见第五章,接下来它会调用函数ip_finish_output2,在这里将根据路由缓存条目绑定的邻居(未绑定邻居无法发送)的情况,选择发送方式,首次发送将选择慢速方式发送,之后则按快速方式发送,如下图:


路由结果dst_entry的hh,回看5.3.2.2节中,在实际把路由缓存条目加入路由缓存表时对调用函数arp_bind_neighbour创建邻居条目,即dst->neighbour,所以第一次发送时调用dst->neighbour->output方法发送,这是慢速发送。

上面的内容重点不在细节,而是感受到邻居系统的作用:由路由缓存条目绑定的邻居条目,确定发送报文的目的MAC,并调用相应的发送方法发送报文。事实上理解了这一点已经差不多够了,邻居子系统的细节是为了更好的理解链路层处理。

由前面已经知道,邻居子系统的作用是绑定L3地址和L2地址的对应关系,最终发送报文必须知道给哪个主机的链路层发送,典型如以太网,在二层是按MAC地址转发,所以必须确定目的地的MAC地址,否则报文无法发到目的地,而所谓邻居,就是那么目的地,作为终端的主机可能没有多少邻居,但可以看下作为路由器网关的设备,如下图是192.168.99.1的一个路由器网关设备的arp缓存情况:


实际条目是上图的10倍以上,可以感受到邻居数目的众多。

那么ARP和邻居是什么关系?不同的链路层协议使用不同的L2.5层协议,而邻居子系统是一个通用的子系统,为所有类似ARP的L2.5层协议封装了一个通用架构。邻居子系统不仅仅提供最基本的二三层地址绑定关系,还实现通用的处理机制,如邻居条目状态机、用户接口、超时机制等,其他L2.5层协议如ARP都是在邻居子系统架构下实现。

4.3.2、邻居子系统详述:

邻居子系统最核心的内容是邻居状态机,在讨论邻居状态机之前首先描述一些必要的内容:

1、邻居表

每个L2.5层协议都会调用函数neigh_table_init在邻居子系统中注册自己的邻居表,以管理自己的邻居条目,对于ARP协议是全局变量arp_tbl;

2、邻居条目:


目前无需理解全部字段的含义,只需知道如下信息:

每个路由缓存条目都会绑定的邻居条目就是这样的一个数据结构,其中的邻居的目的MAC地址是struct hh_cache结构体成员hh,

对应的接口是成员dev,

发送报文的方法还是就是其中的output成员,

每个存在着的邻居条目都会处在邻居子系统状态机的某一个状态,由nud_state指示,

如果发送了请求后,无法正常收到邻居的应答,会触发邻居子系统的重传机制,成员probes记录已重传次数,

若当前无法发送报文则会把报文先缓存在队列arp_queue中,

primary_key存储的是路由缓存条目的IP地址。

4.3.2.1、邻居子系统状态机:
了解上述内容后,下图是邻居子系统状态机:


1、在创建新的邻居条目,这是在创建新的路由缓存条目时调用arp_bind_neighbour函数创建的邻居条目,创建邻居条目最终会调用函数neigh_create,无需过于纠缠其实现细节,重点要知道在此处把路由缓存条目中的下一跳网关成员rt_gateway作为IP地址赋给邻居条目的primary_key成员,把输出接口成员dev赋给邻居条目的dev成员,初始状态为NUD_NONE;

2、收到了ARP请求报文,并且是发给自己的(通过路由信息的路由类型字段),那么状态变为NUD_STALE,解析出对方的IP地址和MAC地址,创建这个发送者的邻居条目;

3、收到了ARP请求报文,但不是发给自己的(通过路由信息的路由类型字段),这就是ARP代理(事实上这是邻居子系统通用功能,所有L2.5层协议都支持L2.5层代理),路由器网关必须行使的功能,状态变为NUD_STALE,它将把报文放入邻居代理队列(proxy_queue),启动代理队列定时器,该定时器处理将给发送者发送回应,即行使ARP代理功能;

4、收到了ARP回复报文,并且是发给自己的(通过报文的类型字段skb->pkt_type),那么状态升为NUD_REACHABLE;

5、在NUD_NONE情况下,发送报文,由于路由结果dst_entry中还没有邻居(ARP)缓存,即hh_cache成员还未赋值,属于第一次发送,由函数neigh_resolve_output处理,将按慢速发送处理,所谓慢速发送就是要首先确保所要发送的邻居条目有效(由函数neigh_event_send确定是否有效)然后才发送,如果有效,那么将在路由缓存条目中缓存二层包头并填充skb的二层包头并发送,从此路由缓存结果dst_entry中就记录了邻居缓存即目的MAC地址,从此以后就可以走快速发送方式,即直接由邻居缓存中记录的目的MAC地址填充报文并立即发送,注意发送函数是dev_queue_xmit,它将走到相应的网卡驱动;状态升为NUD_INCOMPLETE,与此同时,将启动定时器,检查是否收到了回复;

6、在NUD_INCOMPLETE情况下,只有在NUD_NONE状态下发送报文才会进入此状态,并且同时启动了定时器,邻居定时器处理(neigh_timer_handler)将会检查状态依然是NUD_INCOMPLETE (因为收到回复是异步的,比如arp_process收到给本机的回复则走第4步,状态就会升为NUD_REACHABLE)的邻居条目,检查其重传次数是否到限,限制值是由邻居条目创建时的邻居参数决定的(不是重点),若到限则状态降为NUD_FAILED,否则继续重传;

7、在NUD_INCOMPLETE情况下,如果在重传次数到限之前收到了邻居的回复,则状态升为NUD_REACHABLE,并且把MAC地址记录在路由缓存条目的hh_cache中,标记本邻居条目今后可走快速发送路径,则报文发送时直接由路由缓存条目的hh_cache填充包头发送;

8、在第2、3步中由于接受到ARP请求所以创建邻居条目并且状态为NUD_STALE,在定时器处理中,检查其是否超时(闲置时间过长),若超时则状态降为NUD_FAILED;

9、在NUD_STALE下,如果要发送ARP请求,则状态报文NUD_DELAY,如果超时时间内未收到回复则状态报文NUD_PROBE即重传状态,否则状态升为NUD_REACHABLE;

10、在NUD_REACHABLE状态下,如果闲置时间过长(老化),该邻居条目状态降为NUD_STALE;

11、在NUD_REACHABLE状态下,发送ARP请求,状态变为NUD_DELAY,如果超时时间内未收到回复则状态报文NUD_PROBE即重传状态,否则状态依然为NUD_REACHABLE;

12、在重传状态NUD_PROBE下,如果超时并且重传次数到限,则状态降为NUD_FAILED,如果收到了邻居的回复,则状态升为NUD_REACHABLE,如果超时但重传次数还未到限,并且也未收到邻居的回复,则继续重传,状态不变;

13、在NUD_FAILED状态下,这里的邻居条目都将被删除;

4.3.3、ARP:

ARP是用于L3为IPV4和L2为以太网的L2.5层协议,它绑定的是IPV4地址和MAC地址,注意ARP条目不是永远存在,超时会老化掉,否则需要保存的ARP缓存条目太多了。

所有ARP报文按照以太网类型0x0806注册在内核的链路层处理中(proc/net/ptype),其hook处理函数为arp_rcv,该函数在进行ARP处理前netfilter之后调用arp_process,这是ARP报文的实际处理的地方,事实上该函数就是在根据收到的ARP报文的类型调用相关的邻居子系统方法,创建/删除/更新邻居条目及其状态,行使包括ARP代理在内的ARP协议功能;ARP报文发送接口函数为arp_send,在构造arp报文之后调用arp_xmit,它将进行ARP处理后netfilter之后调用dev_queue_xmit实际发送报文。

在proc文件系统中可通过查看proc/net/arp查看本机当前的arp缓存条目,对于IPV4和以太网的设备来说事实上就是邻居条目。

下图是结合ARP的邻居子系统的流程图:


关于ARP子系统的一些细节,后续再补充,个人认为其细节不是重点,对于ARP或者说对于邻居子系统重在理解原理和解决一些可能出现的问题,后续对ARP防控多做总结

这篇关于linux网络协议栈(四)链路层 (3)邻居子系统ARP的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/974683

相关文章

Linux脚本(shell)的使用方式

《Linux脚本(shell)的使用方式》:本文主要介绍Linux脚本(shell)的使用方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录概述语法详解数学运算表达式Shell变量变量分类环境变量Shell内部变量自定义变量:定义、赋值自定义变量:引用、修改、删

Linux链表操作方式

《Linux链表操作方式》:本文主要介绍Linux链表操作方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、链表基础概念与内核链表优势二、内核链表结构与宏解析三、内核链表的优点四、用户态链表示例五、双向循环链表在内核中的实现优势六、典型应用场景七、调试技巧与

详解Linux中常见环境变量的特点与设置

《详解Linux中常见环境变量的特点与设置》环境变量是操作系统和用户设置的一些动态键值对,为运行的程序提供配置信息,理解环境变量对于系统管理、软件开发都很重要,下面小编就为大家详细介绍一下吧... 目录前言一、环境变量的概念二、常见的环境变量三、环境变量特点及其相关指令3.1 环境变量的全局性3.2、环境变

Linux系统中的firewall-offline-cmd详解(收藏版)

《Linux系统中的firewall-offline-cmd详解(收藏版)》firewall-offline-cmd是firewalld的一个命令行工具,专门设计用于在没有运行firewalld服务的... 目录主要用途基本语法选项1. 状态管理2. 区域管理3. 服务管理4. 端口管理5. ICMP 阻断

Linux实现线程同步的多种方式汇总

《Linux实现线程同步的多种方式汇总》本文详细介绍了Linux下线程同步的多种方法,包括互斥锁、自旋锁、信号量以及它们的使用示例,通过这些同步机制,可以解决线程安全问题,防止资源竞争导致的错误,示例... 目录什么是线程同步?一、互斥锁(单人洗手间规则)适用场景:特点:二、条件变量(咖啡厅取餐系统)工作流

Linux中修改Apache HTTP Server(httpd)默认端口的完整指南

《Linux中修改ApacheHTTPServer(httpd)默认端口的完整指南》ApacheHTTPServer(简称httpd)是Linux系统中最常用的Web服务器之一,本文将详细介绍如何... 目录一、修改 httpd 默认端口的步骤1. 查找 httpd 配置文件路径2. 编辑配置文件3. 保存

Linux使用scp进行远程目录文件复制的详细步骤和示例

《Linux使用scp进行远程目录文件复制的详细步骤和示例》在Linux系统中,scp(安全复制协议)是一个使用SSH(安全外壳协议)进行文件和目录安全传输的命令,它允许在远程主机之间复制文件和目录,... 目录1. 什么是scp?2. 语法3. 示例示例 1: 复制本地目录到远程主机示例 2: 复制远程主

Linux基础命令@grep、wc、管道符的使用详解

《Linux基础命令@grep、wc、管道符的使用详解》:本文主要介绍Linux基础命令@grep、wc、管道符的使用,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐... 目录grep概念语法作用演示一演示二演示三,带选项 -nwc概念语法作用wc,不带选项-c,统计字节数-

Linux CPU飙升排查五步法解读

《LinuxCPU飙升排查五步法解读》:本文主要介绍LinuxCPU飙升排查五步法,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录排查思路-五步法1. top命令定位应用进程pid2.php top-Hp[pid]定位应用进程对应的线程tid3. printf"%

Linux下安装Anaconda3全过程

《Linux下安装Anaconda3全过程》:本文主要介绍Linux下安装Anaconda3全过程,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录简介环境下载安装一、找到下载好的文件名为Anaconda3-2018.12-linux-x86_64的安装包二、或者通