
🔥小叶-duck:个人主页
❄️个人专栏:《Data-Structure-Learning》《C++入门到进阶&自我学习过程记录》
《Linux系统从入门到实践》《Linux网络从入门到实践》
✨未择之路,不须回头
已择之路,纵是荆棘遍野,亦作花海遨游
目录
[1.1 数据链路层的核心作用](#1.1 数据链路层的核心作用)
[1.1.1 IP 寻址与 MAC 寻址:唐僧取经类比](#1.1.1 IP 寻址与 MAC 寻址:唐僧取经类比)
[1.1.2 路由器解包与重封装原理](#1.1.2 路由器解包与重封装原理)
[1.2 认识以太网](#1.2 认识以太网)
[1.3 以太网(Ethernet II)标准帧格式详解(RFC 894)](#1.3 以太网(Ethernet II)标准帧格式详解(RFC 894))
[1.4 数据碰撞、碰撞域与 CSMA/CD](#1.4 数据碰撞、碰撞域与 CSMA/CD)
[问题 1:主机 A 为什么要把数据交给主机 E?](#问题 1:主机 A 为什么要把数据交给主机 E?)
[问题 2:使用以太网时,数据帧越长越好,还是越短越好?数据帧越多越好,还是越少越好?](#问题 2:使用以太网时,数据帧越长越好,还是越短越好?数据帧越多越好,还是越少越好?)
[1.4.1 CSMA/CD 碰撞处理机制](#1.4.1 CSMA/CD 碰撞处理机制)
[1.5 MTU 对上层 IP、UDP、TCP 三层协议的差异化影响](#1.5 MTU 对上层 IP、UDP、TCP 三层协议的差异化影响)
[1.5.1 MTU 对 IP 协议:IP 分片机制](#1.5.1 MTU 对 IP 协议:IP 分片机制)
[1.5.1.1 MTU 与 IP 分片的特点](#1.5.1.1 MTU 与 IP 分片的特点)
[1.5.2 MTU 对 UDP 协议](#1.5.2 MTU 对 UDP 协议)
[1.5.3 MTU 对 TCP 协议:MSS 最大报文段尺寸](#1.5.3 MTU 对 TCP 协议:MSS 最大报文段尺寸)
[1.5.3.1 MSS:TCP 最大段尺寸](#1.5.3.1 MSS:TCP 最大段尺寸)
[1.5.3.2 MSS 协商机制(三次握手协商)](#1.5.3.2 MSS 协商机制(三次握手协商))
[1.5.3.3 MSS 与 MTU 的关系](#1.5.3.3 MSS 与 MTU 的关系)
[二、已知 IP,未知对应 MAC:引出 ARP 协议](#二、已知 IP,未知对应 MAC:引出 ARP 协议)
[2.1 ARP 协议的基础定位与核心作用](#2.1 ARP 协议的基础定位与核心作用)
[2.1.1 为什么需要 ARP?(网络分层与寻址困境)](#2.1.1 为什么需要 ARP?(网络分层与寻址困境))
[2.1.2 ARP 的协议分层定位](#2.1.2 ARP 的协议分层定位)
[2.2 ARP + 以太网整体帧结构详细拆解](#2.2 ARP + 以太网整体帧结构详细拆解)
[2.2.1 外层信封:14 字节以太网首部(数据链路层硬件解析)](#2.2.1 外层信封:14 字节以太网首部(数据链路层硬件解析))
[2.2.2 内层信纸:28 字节 ARP 载荷(操作系统 ARP 程序解析)](#2.2.2 内层信纸:28 字节 ARP 载荷(操作系统 ARP 程序解析))
[2.2.2.1 ARP 报文的前四个固定字段](#2.2.2.1 ARP 报文的前四个固定字段)
[2.2.2.2 操作码(Op)字段](#2.2.2.2 操作码(Op)字段)
[2.2.2.3 后四个字段(地址信息)](#2.2.2.3 后四个字段(地址信息))
[2.2.2.4 IP层目的IP 与 ARP层目的IP 的区别](#2.2.2.4 IP层目的IP 与 ARP层目的IP 的区别)
[2.2.3 双层 MAC 地址重复的设计原因](#2.2.3 双层 MAC 地址重复的设计原因)
[2.3 ARP 请求、应答交互流程](#2.3 ARP 请求、应答交互流程)
[2.3.1 ARP 请求报文封装与全网广播](#2.3.1 ARP 请求报文封装与全网广播)
[2.3.2 局域网主机处理请求报文](#2.3.2 局域网主机处理请求报文)
[非目标主机的处理逻辑(以主机 A 为例)](#非目标主机的处理逻辑(以主机 A 为例))
[目标主机的处理逻辑(主机 E)](#目标主机的处理逻辑(主机 E))
[2.3.3 ARP 应答报文封装与单播发送](#2.3.3 ARP 应答报文封装与单播发送)
[2.3.4 应答报文局域网转发与源主机收尾](#2.3.4 应答报文局域网转发与源主机收尾)
[非目标主机的处理逻辑(以主机 A 为例)](#非目标主机的处理逻辑(以主机 A 为例))
[目标路由器 R 的处理逻辑](#目标路由器 R 的处理逻辑)
[2.4 ARP 本地缓存机制](#2.4 ARP 本地缓存机制)
[2.4.1 ARP 缓存表的存在意义:为什么要记录到 ARP 缓存表中?](#2.4.1 ARP 缓存表的存在意义:为什么要记录到 ARP 缓存表中?)
[2.4.2 ARP 缓存表的生命周期管理:为什么缓存时间必须是有限的?](#2.4.2 ARP 缓存表的生命周期管理:为什么缓存时间必须是有限的?)
[三、Linux 内核 ARP 源码解读](#三、Linux 内核 ARP 源码解读)
[3.1 ARP 报文接收函数:arp_rcv ()](#3.1 ARP 报文接收函数:arp_rcv ())
[3.2 ARP 报文处理函数:arp_process ()](#3.2 ARP 报文处理函数:arp_process ())
前言
前面章节我们学习了 IP 协议相关知识,了解了网络层依靠 IP 地址完成跨网段寻址,依靠路由表确定报文转发的下一跳。但 IP 地址只能确定报文要去往哪个网段,想要在同一个局域网内把数据交付到相邻设备,还需要底层的数据链路层来完成相邻节点的传输,这就需要 MAC 地址来完成二层寻址。
本章我们就进入数据链路层的学习,从以太网基础、帧格式、碰撞机制入手,讲解 MTU 对上层 TCP、UDP、IP 协议带来的影响,理解 IP 分片与 MSS 协商的底层逻辑。之后重点学习 ARP 协议,搞懂 ARP 如何完成 IP 地址到 MAC 地址的解析,梳理 ARP 报文交互流程、缓存管理机制,并且结合 Linux 内核源码,从
arp_rcv、arp_process函数看内核处理 ARP 报文的完整逻辑。学习完本章,你能够打通网络层与数据链路层之间的衔接关系,理解 IP 寻址和 MAC 寻址分工协作的完整逻辑,为后续网络编程和内核网络源码学习打下扎实基础。
一、数据链路层基础与以太网
1.1 数据链路层的核心作用
我们可以对比网络层与数据链路层的职责来理解:
- 网络层(IP): 确定数据传输完整的起点和终点,解决去哪里的问题,负责端到端的寻址。
- 数据链路层(MAC): 定义单次链路传输的起点与终点,解决怎么去下一跳的问题,负责相邻节点之间的数据交付。


1.1.1 IP 寻址与 MAC 寻址:唐僧取经类比
用唐僧取经的例子可以很形象理解二者的分工:IP 地址就像全程路线地图,代表从长安到西天的完整路径,用来规划整条传输路径,判断下一站要去往哪个网段;MAC 地址就相当于白龙马这类交通工具,负责完成当前这一段链路的传输。
只知道 IP 地址,相当于拿到地图,知道最终目的地以及下一跳是哪个设备。但在当前局域网内发送以太网帧,必须填写目的 MAC。只有地图,没有对应的 MAC 地址,就好比唐僧知道目的地西天,但是没有白龙马,无法走完当前这一段路程,数据帧也就无法在局域网中投递。 IP 负责跨网段的端到端寻址,决定报文整体走向;MAC 只负责相邻一跳的二层交付。知道 IP,只能确定方向;拿到 MAC,才能把帧在当前局域网送到下一个网卡。ARP 协议,就是用来根据 IP 查询对应 MAC 地址的机制。
1.1.2 路由器解包与重封装原理
这也就解释了报文每经过一台路由器,都需要解包、再次封装的原因。 路由器收到以太网帧后,首先剥离二层帧头,取出里面的 IP 报文。读取 IP 头部里的目标 IP,查询自身路由表,判断报文的下一跳地址。解包的核心目的,就是拿到目标 IP,查表确定下一站该去往哪里。
确定下一跳之后,需要重新封装二层帧:通过 ARP 拿到这个下一跳对应的 MAC 地址,生成新的以太网头部,更新源 MAC 和目的 MAC,再重新封装成新的数据帧,从对应网卡转发出去。 简单概括:解包是为了看 IP、找下一跳;重新封装是为了填入新链路所需的 MAC 地址,适配当前这一段局域网的二层传输。
注意: 普通路由转发场景下,IP 报文的源 IP、目的 IP 不会改变,只会修改 TTL;变化的只有二层以太网帧头。NAT 场景才会修改源 IP 地址。
1.2 认识以太网
以太网并不是某一种实体物理网络,而是一套综合性技术标准,同时定义了数据链路层和物理层的规范。
- **物理层:**规定传输介质默认使用双绞线,支持 10M/100M/1000M 等传输速率。
- **数据链路层:**定义以太网帧格式、介质访问控制方式(CSMA/CD)等规则。
以太网是当前应用最广泛的局域网技术。同期还有令牌环网、无线 LAN 等局域网方案,令牌环网依靠令牌作为信道访问凭证,令牌类似操作系统的互斥锁,依靠令牌流转实现信道独占,规避以太网的碰撞缺陷。但以太网凭借简单、高效的特点,占据了局域网的绝对主导地位。
1.3 以太网(Ethernet II)标准帧格式详解(RFC 894)
以太网帧是数据链路层的基本传输单元,完整 MAC 帧结构: 6字节目的MAC + 6字节源MAC + 2字节类型 + 46~1500字节数据载荷 + 4字节CRC校验
| 字段 | 长度(字节) | 作用 |
|---|---|---|
| 目的 MAC 地址 | 6 | 接收方网卡的硬件物理地址 |
| 源 MAC 地址 | 6 | 发送方网卡的硬件物理地址 |
| 类型 | 2 | 标识上层承载的协议类型:0x0800=IPv4,0x0806=ARP,0x8035=RARP |
| 数据载荷 | 46~1500 | 上层协议数据,如 IP 报文、ARP 报文 |
| CRC 校验 | 4 | 循环冗余校验,检测链路传输过程中是否出现数据损坏 |
关键细节
- MAC 地址:一共 48 位(6 字节),是网卡出厂固化的全球唯一物理地址,格式示例:
08:00:27:03:fb:19。虚拟机 MAC 可能出现冲突,部分网卡支持手动修改 MAC 地址。 - 数据载荷长度限制
- 最大 1500 字节:也就是 MTU(最大传输单元),当载荷超过 1500 字节,就需要在网络层进行 IP 分片。
- 最小 46 字节:如果上层数据不足 46 字节,底层会自动填充 PAD 无用数据补齐最小长度。接收方依靠 IP 首部总长度字段区分有效数据和填充的 PAD。
1.4 数据碰撞、碰撞域与 CSMA/CD
以太网属于共享介质网络,同一个局域网就是一个碰撞域。在同一个碰撞域内,同一时刻只允许一台主机发送数据帧,信道属于临界共享资源。
问题 1:主机 A 为什么要把数据交给主机 E?
主机 A 决定把数据交付给主机 E,是 IP 层查找路由表得出的结果。 主机 A 拿到目标 IP 后,查询本机路由,判断目标主机 E 和自己处于同一局域网。IP 协议负责端到端寻址,确定通信的两端;IP 层确定目标主机是 E 之后,会委托链路层完成局域网内的数据交付。
链路层需要填写二层头部:源 MAC 为 MacA,目的 MAC 为 MacE,封装成以太网帧发送到局域网。这个帧会广播到局域网内所有主机,主机 B、C、D 收到后,比对目的 MAC 地址,发现不是自身 MAC,直接丢弃报文;只有主机 E 匹配到目的 MAC,接收这份数据,并以同样的二层广播方式返回应答。
简单区分:IP 路由用来找到目标主机,MAC 地址用来在同一个局域网内把帧送到目标网卡。
问题 2:使用以太网时,数据帧越长越好,还是越短越好?数据帧越多越好,还是越少越好?
答案:帧越短越好,帧越少越好。
以太网信道是共享临界资源,同一时刻只能传输一个数据帧。
- **如果单个数据帧很长:**会长时间占用信道,其他主机都不能发送报文,极易引发数据碰撞;
- **如果单个数据帧很短:**会产生大量零碎的小帧,主机需要频繁抢占信道,同样会增大碰撞发生的概率。
综合来看: 以太网帧不能太长,也不能太短 ,因此以太网规定 了帧长度的上下限 ,也就是 MTU。
MTU 上限 1500 字节,限制单帧最大载荷,避免长时间占用链路;同时存在最小帧长 46 字节,保证可以正常检测碰撞。

1.4.1 CSMA/CD 碰撞处理机制
由于局域网是共享介质的,多台主机同时发送数据会产生数据碰撞,导致数据损坏。以太网采用 CSMA/CD(载波监听多路访问 / 碰撞检测)机制解决这个问题:
- 载波监听:发送数据前先监听信道是否空闲。
- 碰撞检测:主机发送数据时同步监听信道电平,硬件 + 软件配合实时检测是否发生碰撞;一旦检测碰撞,发送方立刻丢弃当前发送的错误帧。
- 碰撞避让:执行随机等待算法,等待随机时长后重新尝试发送;随机延时可以大幅降低二次碰撞概率。
- 超时重传:链路层内置重传机制,避让等待结束后重新发送报文。
1.5 MTU 对上层 IP、UDP、TCP 三层协议的差异化影响
MTU(最大传输单元)是数据链路层对上层数据的最大长度限制,以太网标准 MTU=1500 字节。底层链路 MTU 的限制,会对网络层 IP、传输层 UDP 与 TCP 产生不同的影响。
1.5.1 MTU 对 IP 协议:IP 分片机制
当 IP 报文整体长度大于出口链路 MTU 时,网络层会自动将原始 IP 报文拆分为多个 IP 分片包。
- **分片标识:**由同一个原始 IP 拆分出来的所有分片,IP 首部 16 位标识 ID 完全一致,用来标识属于同一个原始报文。
- **标志位:**IP 首部 3 位标志段,第 2 位代表是否允许分片,第 3 位为结束标记,1 代表最后一个分片,0 代表中间分片。
- **片偏移:**标识分片数据在原始完整 IP 报文中的偏移位置,接收端依靠该字段把分片按顺序重组。
- 重组规则:目标主机网络层依靠标识、标志位、片偏移完成分片重组;任意一个分片丢失,整份 IP 报文重组失败。IP 协议本身不提供重传能力,需要由上层协议负责数据补发。报文跨异构网络传输时,途经路由器还可能对已经分片的报文执行二次分片。
1.5.1.1 MTU 与 IP 分片的特点
MTU 是数据链路层规定的单次帧最大承载数据长度。网络路径上每一台路由器的数据链路层 MTU 配置可以互不相同。
如果发送主机所在链路 MTU 为 1500 字节,主机发出的 IP 报文最大就是 1500 字节。但报文在转发途中,若经过某一段链路的 MTU 小于 1500,途经的路由器收到报文后,会自主对这个 IP 报文执行分片。
由此可见:IP 分片不一定由发送主机完成,也可能在网络传输中途由路由器进行分片。
可以类比快递打包:IP 层相当于寄件人,把携带目标地址的包裹交给链路层投递。包裹过大超过货车运载上限,就拆分成多个小包裹分别运输;收件人收到所有小包裹之后,再依据包裹上的编号,重新组装成完整包裹。只要任意一个小包裹丢失,整份快递就无法复原。
1.5.2 MTU 对 UDP 协议
以太网 MTU=1500,扣除 20 字节默认 IP 首部 + 8 字节 UDP 首部,UDP 应用数据安全上限为 1472 字节。 当应用发送 UDP 数据大于 1472 字节时,网络层会强制进行 IP 分片。
UDP 本身没有可靠重传机制,分片之后只要任意一个分片丢失,就会直接导致整段数据报废。 因此在 UDP 业务开发中,尽量控制单包数据小于 1472 字节,规避分片带来的丢包风险。
1.5.3 MTU 对 TCP 协议:MSS 最大报文段尺寸
1.5.3.1 MSS:TCP 最大段尺寸
MSS 全称最大段尺寸,代表 TCP 单个报文段能够承载的最大应用数据长度。
- MSS 是 TCP 传输层的概念,TCP 报文段里承载的数据部分不能超过 MSS。
- 不同主机配置的 MSS 可以不一样。
- MSS 信息放在 TCP 头部的变长选项中(kind=2),在 SYN 报文中携带。
理想情况下,MSS 取值要保证封装 IP 首部之后,整个 IP 报文不会触发 IP 分片,而这个上限最终受底层链路 MTU 约束。
1.5.3.2 MSS 协商机制(三次握手协商)
协商存在的必要性
举个例子:发送方 MSS=1460,封装后 IP 报文总长 1500 字节,在发送端不会分片。但接收方 MSS 只有 1000。如果发送方直接按 1460 发送,接收方无法处理。
根源问题:通信双方一开始不知道对方支持的 MSS 上限。
协商流程
TCP 在三次握手建立连接阶段 完成MSS 协商:
- 通信双方在发送 SYN 报文 时,在TCP 选项字段填入自己支持的 MSS。
- 双方获取到彼此的 MSS 之后,选取两者中较小的值 ,作为本次连接通信使用的最终 MSS。
- 后续发送 TCP 数据时,单次应用数据不超过这个协商后的 MSS。
沿用上面例子,协商后 MSS 取 1000,封装 IP 头部后 IP 报文总长不超过 1040 字节。报文整体体积变小,大幅降低报文在传输途中被路由器分片的可能性。
1.5.3.3 MSS 与 MTU 的关系
MTU 属于数据链路层,代表一帧能承载的 IP 报文最大总长度;MSS 属于传输层,代表 TCP 报文段中纯应用数据的最大长度。 简单换算关系:MTU = IP首部(默认20字节) + TCP首部(默认20字节) + MSS。 常见以太网 MTU=1500,默认场景下 MSS=1460。
MSS 的设计目标,就是尽量让组装后的 IP 报文长度小于链路 MTU,从源头避免 IP 分片。
补充 :IP 分片有明显缺陷,分片报文只要任意一个分片丢失,整个报文就必须全部重传。TCP 通过 MSS 协商,就是为了尽量规避 IP 分片,提升传输可靠性。
二、已知 IP,未知对应 MAC:引出 ARP 协议
主机依托路由表只能查询到下一跳设备的 IP 地址(如默认网关 IP),无法直接获取网关硬件 MAC 地址 ;链路层封装 MAC 帧必须填写目的 MAC 地址,缺少 MAC 则无法组装帧、无法在局域网发送数据,由此诞生 ARP 协议。

2.1 ARP 协议的基础定位与核心作用
2.1.1 为什么需要 ARP?(网络分层与寻址困境)
-
逻辑地址与物理地址的割裂 :在网络通信中,上层应用程序(如浏览器)只认识目标的 IP 地址 (逻辑地址,如
192.168.1.2),这用于在全球网络中定位目标主机所在的位置。但是,数据要在实际的物理线路上传输,数据链路层(以太网)只认识 MAC 地址 (物理地址,如08:00:27:03:fb:19)。 -
数据帧的接收过滤 :网卡在接收数据帧时,会优先校验帧头部的目标 MAC 地址(这里说法存在一定问题,后续讲解 ARP 请求与应答的时候再修正)。如果目标 MAC 不是自己的(或者不是广播地址),网卡会直接丢弃该数据帧。因此,在发送数据之前,必须知道目标主机对应网卡上的 MAC 地址。
-
ARP 的核心作用 :在正式数据传输前,建立 IP 逻辑地址与 MAC 物理地址的映射对照表,补齐二层寻址必需的硬件地址信息。
2.1.2 ARP 的协议分层定位
-
层级归属 :ARP 无法被单一划分至网络层或数据链路层。它位于数据链路层和网络层之间。
-
封装结构 :它处在 MAC 帧的上层,和 MAC 帧构成同模块上下级关系。ARP 报文不能"裸包"在局域网传输,必须整体封装进 MAC 帧的数据载荷字段,依托数据链路层完成物理传输。
-
运行特性:协议运行全程不与用户应用进程直接交互,IP 与 MAC 的地址映射管理工作由操作系统内核自主完成。
-
适用范围 :ARP 是基于局域网广播机制设计的二层协议,原生依托以太网物理广播特性完成报文交互。跨广域网的数据传输过程中,每一台中转路由设备获取下一跳 IP 后,依旧会在对应接口所在局域网触发 ARP 解析。

2.2 ARP + 以太网整体帧结构详细拆解
在以太网环境中,ARP 报文不能"裸包"传输,必须封装进以太网帧中。一个完整的 ARP 以太网帧由三段组成:14 字节以太网首部 + 28 字节 ARP 载荷 + 4 字节 CRC 帧校验序列。

2.2.1 外层信封:14 字节以太网首部(数据链路层硬件解析)
这部分由网卡等链路层硬件直接解析,固定拆分为三个字段:
-
目的 MAC 地址(6 字节) :
ARP 请求报文 :填写全 F 广播地址
FF:FF:FF:FF:FF:FF,表示该帧需要被局域网内所有主机接收。ARP 应答报文:填写请求主机的真实单播 MAC 地址,表示只发给特定目标。
-
源 MAC 地址(6 字节):固定填充当前发送主机自身网卡的 MAC 地址。
-
帧类型(2 字节) :标识上层载荷协议。ARP 固定为
0x0806,普通 IP 报文固定为0x0800。

2.2.2 内层信纸:28 字节 ARP 载荷(操作系统 ARP 程序解析)
2.2.2.1 ARP 报文的前四个固定字段
对于以太网 + IPv4 环境,ARP 请求/应答的头部前四个字段是固定的:
-
硬件类型(2字节) :值为
1,代表以太网。 -
协议类型(2字节) :值为
0x0800,代表 IPv4 协议。 -
硬件地址长度(1字节) :值为
6,代表 MAC 地址长度。 -
协议地址长度(1字节) :值为
4,代表 IPv4 地址长度。这四个字段共同定义了:在以太网中,使用 IPv4 协议进行地址解析。

2.2.2.2 操作码(Op)字段
操作码字段(2字节)用于区分 ARP 报文的类型:
-
值为
1:表示 ARP 请求(Request)。 -
值为
2:表示 ARP 应答(Reply)。ARP 请求和应答使用完全相同的报文结构,仅通过此字段区分。

2.2.2.3 后四个字段(地址信息)
ARP 报文的后四个字段包含了发送方和目的方的以太网地址(MAC)和 IP 地址:
-
发送端以太网地址:发送方的 MAC 地址(已知,直接填入)。
-
发送端 IP 地址:发送方的 IP 地址(已知,直接填入)。
-
目的以太网地址 :如果是请求报文,因为不知道对方的 MAC,填全
0或全F;如果是应答报文,填入请求方的 MAC。 -
目的 IP 地址:这是解析的目标 IP。

2.2.2.4 IP层目的IP 与 ARP层目的IP 的区别
-
IP 层中的目的 IP:始终是最终目标主机的 IP 地址,在数据包整个路由转发过程中保持不变。
-
ARP 层中的目的 IP :是下一跳的 IP 地址。它取决于当前主机所处的子网和转发路径:
-
如果目标主机在同一子网内,ARP 的目的 IP 就是目标主机的 IP。
-
如果目标主机在子网外,ARP 的目的 IP 则是当前主机的默认网关(路由器接口)的 IP。
-
当数据包到达下一个路由器时,路由器会重新发起一个新的 ARP 请求,此时新 ARP 的目的 IP 就变成了下一个路由器的 IP。
即:每一跳的 ARP 目的 IP 会根据当前链路重新确定,但 IP 层的目的 IP 始终指向终点。
-

2.2.3 双层 MAC 地址重复的设计原因
以太网环境下以太网首部 MAC 和ARP 载荷内部 MAC数据重复看似冗余,本质是协议为兼容令牌环等非以太网异构网络。异构链路中两处 MAC 字段作用不一致,无法省略;同时遵循计算机网络分层思想做拆分:
- 以太网首部的 MAC 地址是给网卡和交换机看的,决定帧在物理上要发给谁
- ARP 数据部分的 MAC 地址是给操作系统的 ARP 协议看的,用于更新 ARP 缓存表
2.3 ARP 请求、应答交互流程
以路由器 R 访问同网段主机 E 为例,R 已知 E 的 IP、无 E 的 MAC 缓存条目,完整触发一次标准 ARP 交互。
2.3.1 ARP 请求报文封装与全网广播
-
组装 ARP 载荷 :硬件类型 1、协议
0x0800、地址长度 6/4、op=1,发送端写入 MACR、IPR,目的 IP 填 IPE、目的 MAC 全 0 填充; -
封装以太网帧 :首部目的 MAC 为全 F 广播,源 MAC=MACR,帧类型
0x0806,尾部附加硬件 CRC 校验; -
整帧在局域网广播:网段内所有主机网卡接收该数据帧。

2.3.2 局域网主机处理请求报文
非目标主机的处理逻辑(以主机 A 为例)
当这个广播 ARP 请求发送到局域网后,局域网内的所有主机都会在物理层面收到这个电信号。
-
MAC 层视角(第一道门卫):
-
主机 A 网卡收到帧,提取帧头的目标 MAC,发现是
FF:FF:FF:FF:FF:FF(广播地址)。 -
动作 :MAC 层判定"这是需要我处理的广播",于是受理。剥去以太网帧头,将有效载荷(ARP 报文)向上交付给 ARP 层。
-
-
ARP 层视角(第二道门卫):
-
主机 A 的 ARP 层收到报文,提取 ARP 报头里的"目的 IP 地址"字段(IPE)。
-
发现目标 IP 不是自己(自己是
192.168.1.3,目标是192.168.1.2)。 -
动作 :ARP 层判定"这不是找我的",直接丢弃该报文,不产生任何回复。
-
-
结论:主机 B、C、D 也是同样的处理逻辑,在 ARP 层被过滤掉。
目标主机的处理逻辑(主机 E)
主机 E 同样会收到这个广播报文。
-
MAC 层视角 :与主机 A 一样,看到全 F 广播地址,受理并向上交付给 ARP 层。
-
ARP 层视角(关键步骤):
-
不能只看目的 IP:如果 ARP 层直接看目的 IP(IPE)发现是自己,就立刻认为这是请求报文,那是错误的。因为如果不检查操作码,可能误把别人发来的 ARP 应答当成请求处理。
-
必须先看操作码(op) :主机 E 拿到报文后,首先检查 ARP 报头中的
op字段。 -
判定为请求 :发现
op == 1,确认这是一个"ARP 请求报文"。 -
确认目标是自己:再检查目的 IP,发现正是自己的 IP(IPE)。
-
准备回应:判定需要向路由器 R 发送一个 ARP 应答报文。
-

2.3.3 ARP 应答报文封装与单播发送
-
组装 ARP 载荷:op 修改为 2 应答码,发送端填充 MACE、IPE,目的字段填写请求方 MACR、IPR(这些信息直接从刚才收到的请求报文中提取,无需再次广播);
-
外层以太网首部修改 :目的 MAC 改为 MACR(单播地址),源 MAC=MACE,帧类型保持
0x0806,追加 CRC 校验; -
封装完成后以单播形式向局域网发送。

2.3.4 应答报文局域网转发与源主机收尾
非目标主机的处理逻辑(以主机 A 为例)
当 ARP 应答报文发送到局域网时(通过交换机单播转发)。
-
MAC 层视角:主机 A 网卡收到帧,提取帧头的目标 MAC,发现是 macR,而自己的 MAC 是 macA。
-
动作 :MAC 层直接判定"这不是发给我的",在MAC 层就直接丢弃了,根本不会拆包,也不会向上交付给 ARP 层。
-
核心论点:广播与受理是两码事
-
物理层面(广播域):在以太网中,广播帧会被交换机泛洪到所有物理接口,所有主机网卡在物理上都会收到电信号。
-
逻辑层面(受理):收到信号后,处理逻辑是分层的。是否"受理"并"向上交付",取决于每一层的过滤规则。
-
-
分层过滤的智慧(为什么要这样设计?):
-
为了节省 CPU 资源。MAC 层(硬件)负责过滤掉所有目标 MAC 不是本机的单播帧。只有广播帧、组播帧,或目标 MAC 正好是本机的单播帧,才能通过第一道门卫。
-
ARP 层(软件/驱动)作为第二道门卫,负责过滤掉"虽然 MAC 是广播,但目标 IP 不是我"的 ARP 请求。
-
目标路由器 R 的处理逻辑
路由器 R 最终收到了主机 E 发来的 ARP 应答报文。
-
MAC 层视角 :网卡发现目标 MAC 正是自己的 macR,受理并剥去帧头,将 ARP 报文向上交付给 ARP 层。
-
ARP 层视角(二次确认):
-
不能只看发送端 MAC:路由器 R 不能因为看到发送端 MAC 是 macE,就盲目认为这是主机 E 发来的应答。可能有其他主机伪造,或者有其他主机发来的请求。
-
必须看操作码(op) :路由器 R 的 ARP 层拿到报文后,首先检查
op字段。 -
判定为应答 :发现
op == 2,确认这是一个"ARP 应答报文"。 -
提取信息:确认无误后,路由器 R 提取发送端的 IP(IPE)和 MAC(macE),将其记录到自己的 ARP 缓存表中。
-

2.4 ARP 本地缓存机制
在路由器 R(或任何主机)成功获取到目标 MAC 地址后,它并不会用完即弃,也不会永远保存,而是会将其存入本地的 ARP 缓存表 中。
2.4.1 ARP 缓存表的存在意义:为什么要记录到 ARP 缓存表中?
-
避免重复解析:如果路由器 R 需要连续向主机 E 发送 100 个数据包。如果没有 ARP 缓存,路由器每发一个包,都要重新发起一次 ARP 广播请求("谁是 IPE?"),主机 E 就要回复 100 次。这将极大地浪费局域网带宽和 CPU 资源。
-
直接封装发送:有了 ARP 缓存,路由器 R 在发送第一个包解析到 macE 后,后续的包直接从缓存中读取 macE,立刻封装成单播以太网帧发送。这就是缓存带来的效率飞跃。
2.4.2 ARP 缓存表的生命周期管理:为什么缓存时间必须是有限的?
ARP 缓存不能永久保存,必须设置一个老化时间(通常在几分钟到几十分钟不等,例如 Linux 默认约 60 秒,Windows 约 15-45 秒)。原因如下:
-
IP 与 MAC 的映射关系是动态的:
-
硬件更换:主机 E 的网卡坏了,换了一块新网卡,它的 MAC 地址就变了(比如变成了 macE2),但它的 IP 地址可能没有变(依然是 IPE)。
-
IP 地址重新分配:局域网内 DHCP 服务器重新分配了 IP,导致原来的 IPE 现在分给了另一台主机 F(MAC 为 macF)。
-
设备移动:笔记本电脑从办公室 A 拔掉网线,插到了办公室 B 的网口上,IP 可能变了,或者 IP 没变但物理接口的 MAC 变了。
-
-
如果缓存永不过期:路由器 R 的缓存里依然记录着"IPE 对应 macE"。当下次再给 IPE 发送数据时,它会把数据包发给错误的旧 MAC(macE),导致数据包丢失(因为 macE 可能已经不在网络里了,或者收到了包但因为 IP 不对而不处理)。
-
老化机制的作用 :设置过期时间,意味着过了一段时间后,路由器 R 会清空这条记录。如果还需要通信,它会重新发起 ARP 请求,从而获取到最新、最准确的 IP-MAC 映射关系。
总结 :ARP 缓存表是**"空间换时间"** (用内存存储映射关系,换取免去重复广播的时间)和**"动态适应性"**(用老化机制,换取适应网络拓扑变化的能力)的完美结合。它保证了局域网通信既高效又可靠。

三、Linux 内核 ARP 源码解读
Linux 内核中 ARP 协议的实现代码位于net/ipv4/arp.c文件,核心包含两个关键函数:arp_rcv()负责接收并处理 ARP 报文,arp_send()用于发送 ARP 请求或者 ARP 应答报文。
3.1 ARP 报文接收函数:arp_rcv ()
cpp
int arp_rcv(struct sk_buff *skb, struct net_device *dev,
struct packet_type *pt, struct net_device *orig_dev)
{
struct arphdr *arp;
struct net *net = dev_net(dev);
// 检查报文长度是否合法
if (skb->len < sizeof(struct arphdr))
goto out_free;
arp = arp_hdr(skb);
// 只处理以太网硬件类型、IPv4地址的ARP请求/应答
if (arp->ar_hrd != htons(ARPHRD_ETHER) ||
arp->ar_pro != htons(ETH_P_IP) ||
arp->ar_hln != ETH_ALEN ||
arp->ar_pln != 4)
goto out_free;
// 根据操作码区分处理ARP请求或者应答报文
switch (ntohs(arp->ar_op)) {
case ARPOP_REQUEST:
arp_process(net, skb, arp); // 处理ARP请求
break;
case ARPOP_REPLY:
arp_process(net, skb, arp); // 处理ARP应答
break;
default:
goto out_free;
}
return 0;
out_free:
kfree_skb(skb);
return 0;
}
核心逻辑
- 校验报文长度,判断报文是否满足 ARP 头部最小长度,非法报文直接释放 skb。
- 校验硬件类型、协议类型、硬件地址长度、协议地址长度,仅保留以太网 + IPv4 类型的 ARP 报文,其余报文丢弃。
- 读取操作码,区分 ARP 请求报文与 ARP 应答报文,统一交给
arp_process()函数处理。 - 处理完毕返回,非法报文会释放 skb 缓冲区,回收内存。
3.2 ARP 报文处理函数:arp_process ()
cpp
static void arp_process(struct net *net, struct sk_buff *skb, struct arphdr *arp)
{
__be32 sip, tip;
unsigned char *sha, *tha;
struct neighbour *n;
// 提取发送端IP、MAC地址,以及目的IP地址
sip = *(__be32 *)arp->ar_sip;
tip = *(__be32 *)arp->ar_tip;
sha = arp->ar_sha;
tha = arp->ar_tha;
// 更新ARP缓存表:无论请求还是应答,都会更新发送端IP-MAC映射(ARP欺骗的根源)
n = neigh_lookup(&arp_tbl, &sip, dev);
if (n) {
neigh_update(n, sha, NUD_REACHABLE, 0, 0);
neigh_release(n);
}
// 如果收到ARP请求,并且目的IP是本机IP,则构造并发送ARP应答报文
if (arp->ar_op == htons(ARPOP_REQUEST) &&
inet_addr_type(net, tip) == RTN_LOCAL) {
arp_send(ARPOP_REPLY, ETH_P_ARP, tip, dev, sip, sha, tha);
}
}
核心逻辑
- 从 ARP 报文中解析提取发送方 IP、发送方 MAC、目标 IP 地址。
- 查找 neighbour(ARP 缓存)表项,只要收到 ARP 报文,无条件更新发送端 IP 与 MAC 的映射关系,这也是 ARP 欺骗能够实现的底层根源。
- 判断报文类型:如果是 ARP 请求报文,并且目标 IP 为本机地址,则调用
arp_send(),回复 ARP 应答报文,把本机 MAC 地址返回给请求方。
总结
本章完整梳理数据链路层 ARP 全维度知识点,覆盖概念、帧结构、交互流程、缓存等核心板块,汇总复习重难点:
- **协议分层考点:**ARP 宏观归属数据链路层,微观封装在 MAC 帧上层,处于二层与三层中间位置。所有 ARP 报文都必须依托 MAC 帧,才能在局域网内完成传输。
- 帧结构核心参数: 以太网首部固定 14 字节,ARP 对应的帧类型标识为
0x0806,ARP 载荷 28 字节。以太网硬件类型值为 1,IPv4 协议字段0x0800;op=1 代表 ARP 请求,op=2 代表 ARP 应答。请求报文外层目的 MAC 为全 F 广播,内层目的 MAC 填全 0 占位;应答报文内外目的 MAC 统一填写请求方 MAC。双层 MAC 重复设计是为兼容令牌环等异构网络,分层架构区分硬件解析、系统解析两个使用主体。 - 收发流程易混点: ARP 请求采用全网广播,无关主机在内层 ARP 层面丢弃报文;ARP 应答使用单播传输,无关主机在外层 MAC 链路层直接丢弃帧。丢包所在层级是高频考点。
- **ARP 缓存考点:**不同平台的 ARP 缓存老化时间存在差异,缓存无法永久保存,主要有三点原因:DHCP 分配动态 IP、网卡硬件更换、设备下线。ARP 解析可以跨网段触发,查询路由下一跳 IP 同样需要 ARP 解析。
结束语
到这里,数据链路层的内容就全部讲解完毕。我们从以太网基础、帧格式、CSMA/CD 碰撞机制开始,分析了 MTU 对 IP、UDP、TCP 带来的影响,理清了 IP 分片与 MSS 协商的内在关联。随后完整学习 ARP 协议,理解了 ARP 如何完成 IP 到 MAC 的地址解析,梳理报文交互流程、ARP 缓存生命周期,并且结合 Linux 内核源码,看到内核接收、处理 ARP 报文的底层实现。
网络层 IP 负责跨网段的寻址,而数据链路层与 ARP 负责相邻节点的二层交付。IP 寻址确定报文要去往哪个网段,ARP 解析获取下一跳的 MAC 地址,二者配合,才能完成端到端的数据传输。