《Linux 网络编程》深入理解数据链路层:从MAC帧到ARP协议的底层原理详解

🔥小叶-duck个人主页

❄️个人专栏《Data-Structure-Learning》《C++入门到进阶&自我学习过程记录》

《Linux系统从入门到实践》《Linux网络从入门到实践》

《Qt 方寸极境》 《MySQL》

未择之路,不须回头
已择之路,纵是荆棘遍野,亦作花海遨游


目录

前言

一、数据链路层基础与以太网

[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_rcvarp_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 循环冗余校验,检测链路传输过程中是否出现数据损坏

关键细节

  1. MAC 地址:一共 48 位(6 字节),是网卡出厂固化的全球唯一物理地址,格式示例:08:00:27:03:fb:19。虚拟机 MAC 可能出现冲突,部分网卡支持手动修改 MAC 地址。
  2. 数据载荷长度限制
    • 最大 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. 载波监听:发送数据前先监听信道是否空闲。
  2. 碰撞检测:主机发送数据时同步监听信道电平,硬件 + 软件配合实时检测是否发生碰撞;一旦检测碰撞,发送方立刻丢弃当前发送的错误帧。
  3. 碰撞避让:执行随机等待算法,等待随机时长后重新尝试发送;随机延时可以大幅降低二次碰撞概率。
  4. 超时重传:链路层内置重传机制,避让等待结束后重新发送报文。

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 协商

  1. 通信双方在发送 SYN 报文 时,在TCP 选项字段填入自己支持的 MSS。
  2. 双方获取到彼此的 MSS 之后,选取两者中较小的值 ,作为本次连接通信使用的最终 MSS
  3. 后续发送 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 字节以太网首部(数据链路层硬件解析)

这部分由网卡等链路层硬件直接解析,固定拆分为三个字段:

  1. 目的 MAC 地址(6 字节)

    ARP 请求报文 :填写全 F 广播地址 FF:FF:FF:FF:FF:FF,表示该帧需要被局域网内所有主机接收。

    ARP 应答报文:填写请求主机的真实单播 MAC 地址,表示只发给特定目标。

  2. 源 MAC 地址(6 字节):固定填充当前发送主机自身网卡的 MAC 地址。

  3. 帧类型(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 地址重复的设计原因

以太网环境下以太网首部 MACARP 载荷内部 MAC数据重复看似冗余,本质是协议为兼容令牌环等非以太网异构网络。异构链路中两处 MAC 字段作用不一致,无法省略;同时遵循计算机网络分层思想做拆分:

  • 以太网首部的 MAC 地址是给网卡和交换机看的,决定帧在物理上要发给谁
  • ARP 数据部分的 MAC 地址是给操作系统的 ARP 协议看的,用于更新 ARP 缓存表

2.3 ARP 请求、应答交互流程

以路由器 R 访问同网段主机 E 为例,R 已知 E 的 IP、无 E 的 MAC 缓存条目,完整触发一次标准 ARP 交互。

2.3.1 ARP 请求报文封装与全网广播

  1. 组装 ARP 载荷 :硬件类型 1、协议 0x0800、地址长度 6/4、op=1,发送端写入 MACR、IPR,目的 IP 填 IPE、目的 MAC 全 0 填充;

  2. 封装以太网帧 :首部目的 MAC 为全 F 广播,源 MAC=MACR,帧类型 0x0806,尾部附加硬件 CRC 校验;

  3. 整帧在局域网广播:网段内所有主机网卡接收该数据帧。

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 应答报文封装与单播发送

  1. 组装 ARP 载荷:op 修改为 2 应答码,发送端填充 MACE、IPE,目的字段填写请求方 MACR、IPR(这些信息直接从刚才收到的请求报文中提取,无需再次广播);

  2. 外层以太网首部修改 :目的 MAC 改为 MACR(单播地址),源 MAC=MACE,帧类型保持 0x0806,追加 CRC 校验;

  3. 封装完成后以单播形式向局域网发送

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;
}

核心逻辑

  1. 校验报文长度,判断报文是否满足 ARP 头部最小长度,非法报文直接释放 skb。
  2. 校验硬件类型、协议类型、硬件地址长度、协议地址长度,仅保留以太网 + IPv4 类型的 ARP 报文,其余报文丢弃。
  3. 读取操作码,区分 ARP 请求报文与 ARP 应答报文,统一交给arp_process()函数处理。
  4. 处理完毕返回,非法报文会释放 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);
    }
}

核心逻辑

  1. 从 ARP 报文中解析提取发送方 IP、发送方 MAC、目标 IP 地址。
  2. 查找 neighbour(ARP 缓存)表项,只要收到 ARP 报文,无条件更新发送端 IP 与 MAC 的映射关系,这也是 ARP 欺骗能够实现的底层根源。
  3. 判断报文类型:如果是 ARP 请求报文,并且目标 IP 为本机地址,则调用arp_send(),回复 ARP 应答报文,把本机 MAC 地址返回给请求方。

总结

本章完整梳理数据链路层 ARP 全维度知识点,覆盖概念、帧结构、交互流程、缓存等核心板块,汇总复习重难点:

  1. **协议分层考点:**ARP 宏观归属数据链路层,微观封装在 MAC 帧上层,处于二层与三层中间位置。所有 ARP 报文都必须依托 MAC 帧,才能在局域网内完成传输。
  2. 帧结构核心参数: 以太网首部固定 14 字节,ARP 对应的帧类型标识为0x0806,ARP 载荷 28 字节。以太网硬件类型值为 1,IPv4 协议字段0x0800;op=1 代表 ARP 请求,op=2 代表 ARP 应答。请求报文外层目的 MAC 为全 F 广播,内层目的 MAC 填全 0 占位;应答报文内外目的 MAC 统一填写请求方 MAC。双层 MAC 重复设计是为兼容令牌环等异构网络,分层架构区分硬件解析、系统解析两个使用主体。
  3. 收发流程易混点: ARP 请求采用全网广播,无关主机在内层 ARP 层面丢弃报文;ARP 应答使用单播传输,无关主机在外层 MAC 链路层直接丢弃帧。丢包所在层级是高频考点
  4. **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 地址,二者配合,才能完成端到端的数据传输。

相关推荐
开开心心就好1 小时前
安卓手写文字生成工具,多种纸张一直免费
网络·网络协议·tcp/ip·leetcode·智能手机·电脑·模拟退火算法
j7~2 小时前
【Linux 网络】四十.《网络基础(传输层协议:UDP、TCP)》--中篇
linux·tcp·tcp协议·确认应答机制·连接管理机制·tcp流量控制
牢姐与蒯2 小时前
Linux进程间通信(三).基于匿名管道的进程池的实现
linux·运维·服务器·ubuntu
凤年徐2 小时前
C++ 仿 muduo 高并发服务器:用户态缓冲区 Buffer 模块实现
linux·c++
Java红桃峰峰日拱一卒4 小时前
在jdk8的centos上安装jdk17
linux·jdk17·jdk8
M78佐菲10 小时前
ARM学习笔记(1)
linux·arm开发·笔记·嵌入式硬件·学习
益达丫11 小时前
Socket编程揭秘:端口、IP与进程通信的底层逻辑
linux·笔记
比兔代理11 小时前
正向代理与反向代理技术辨析,为什么代理 IP 属于正向代理
服务器·网络·http·ip
Ivanqhz13 小时前
SVD++算法
java·服务器·网络·深度学习·神经网络