邻接子系统核心

基础知识

Linux 邻接子系统负责发现房钱链路上的节点,并且将 L3(网络层)地址转换为 L2(数据链路层)地址。在 IPv4 中,实现这种转化协议为地址解析协议(Address Resolution Protocol, ARP),而在 IPv6 则为邻居发现协议(Neighbour Discovery Protocol, NDISC 或 ND),邻接子系统为执行 L3 到 L2 映射提供了独立于协议的基础设施。
在 IPv4 中,使用邻接协议为 ARP,相应的请求和应答分别被称为 ARP 请求和 ARP 应答,在 IPv6 中,使用邻接协议为 NDISC,相应的请求和应答分别称为 邻居请求邻居通告
Linux 邻接系统的基本数据结构是邻居,表示于当前链路相连的网络节点,用结构 neighbour 来表示。具体源码如下:

image.png

为了避免每次传输数据包时都发送请求,内核将 L3 地址和 L2 地址之间的映射存储在邻接表的数据结构中。在 IPv4 中,这个表就是 ARP 表,有时也被称为 ARP 缓存。在 IPv6 中,邻接表时 NDISC 表(也叫 NDISC 缓存),ARP 表和 NDISC 表都是结构 neigh_table 实例,具体内核源码表示如下:

image.png

使用领接子系统的每种 L3 协议都要注册一个协议协议处理程序。对于 IPv4 来说,ARP 数据包处理程序方法为 arp_rcv()

image.png

每个邻居对象结构 neigh_ops 中定义一组方法,它包含一个协议簇成员和四个函数指针,具体内核源码如下:

image.png

创建和释放邻居

邻居创建时由 __neigh_create() 处理:

image.png

邻居删除是由 neigh_release() 处理:

image.png

image.png

用户空间和邻接子系统交互

管理 ARP 表,可使用 iproute2 包中的命令 ip neigh,也可以使用 net_tools 包中的命令 arp。

image.png

image.png

ARP 协议(IPv 4)

在以太网中,硬件地址称为 MAC,长度是 48 位,MAC 地址独一无二。发送 IPv4 数据包时,目标是 IPv4 地址是已知的,但是需要创建以太网头,其中包含目标的 MAC 地址,根据给定 IPv4 地址确定 MAC 地址的工作由 ARP 协议完成。ARP 表时一个 neigh_table 结构实例,具体内核源码如下:

image.png

ARP 发送请求

最常见场景是在传输路径中,在离开网络层(L3)进入数据链路层(L2)之前,在方法 ip_finish_output2 中,首先调用方法 __ipv4_neigh_lookup_noref,在 ARP 表中查找下一个 IPv4 地址。

image.png

ARP 接受请求和应答

在 IPv4 中,方法 arp_rcv() 负责处理 ARP 数据包,具体对应函数内核源码如下:

image.png