3. 数据链路层:以太网帧格式、MAC地址解析、ARP协议工作原理

数据链路层,说白了就是解决「同一物理链路下,数据该怎么传、传给谁」的问题。我刚开始接触网络时,总觉得IP地址才是主角,后来被一个ARP问题折腾了一整晚,才意识到MAC地址和链路层才是真正的「地基」。这一章,咱们就把地基打牢。

3.1 以太网帧格式——数据在网线上到底长什么样?

你想想看,当你的Linux主机发出一段数据,它最终要在网线上变成一串电信号。但光有信号不行,接收方得知道:这包数据从哪来、到哪去、是什么类型、有没有传错。以太网帧就是干这个的。

标准的以太网帧(Ethernet II,也叫DIX帧)格式如下:

字段 长度(字节) 说明
目的MAC地址 6 接收方的物理地址
源MAC地址 6 发送方的物理地址
类型/长度 2 0x0800表示IPv4,0x0806表示ARP
数据载荷 46~1500 上层协议数据(IP包等)
帧校验序列(FCS) 4 CRC校验,检测传输错误

这里有个细节我提醒一下:数据载荷最少46字节。如果上层数据不够,就要填充(Padding)。为什么?因为以太网协议规定帧长度不能小于64字节(从目的MAC到FCS),这是为了冲突检测机制能正常工作。我在调一个嵌入式网卡驱动时,就遇到过因为填充不对导致丢包的情况,查了半天才发现是驱动没做填充。

关键点:以太网帧的最小长度是64字节,最大是1518字节(不含前导码)。这个限制决定了IP包的最大传输单元(MTU)通常是1500字节。

3.2 MAC地址——网络设备的「身份证」

MAC地址是48位的,通常写成六组十六进制数,比如 00:1a:2b:3c:4d:5e。前24位是组织唯一标识符(OUI),由IEEE分配给厂商;后24位是厂商自己分配的序列号。

但这里有个常见的误解:MAC地址并不是全球唯一的。虽然理论上每个网卡出厂时烧录的MAC是唯一的,但操作系统可以修改它。我在做虚拟化平台时,经常需要手动给虚拟机分配MAC地址,只要保证在同一广播域内不冲突就行。

MAC地址有三种类型:

  • 单播地址:目的MAC的第一个字节最低位为0,表示发给单个设备。
  • 多播地址:最低位为1,表示发给一组设备(比如IGMP、STP协议用的)。
  • 广播地址:全1,即 ff:ff:ff:ff:ff:ff,表示发给同一广播域内的所有设备。

实用技巧:在Linux下用 ip link show 或 ifconfig 查看MAC地址。想临时改MAC?ip link set dev eth0 address 00:11:22:33:44:55 就行。但别在生产环境乱改,小心被运维追着打。

3.3 ARP协议——IP地址怎么找到MAC地址?

这是数据链路层的核心问题。你的Linux主机知道目标IP(比如192.168.1.1),但网卡只认MAC地址。谁来做这个翻译?ARP(地址解析协议)。

ARP的工作原理其实很简单,就四个字:问一圈,记下来。

3.3.1 ARP请求与响应

假设主机A(IP: 192.168.1.10,MAC: AA:AA:AA:AA:AA:AA)想和主机B(IP: 192.168.1.20)通信:

  1. A先查自己的ARP缓存表,看有没有B的MAC地址。
  2. 没有?那就发一个ARP请求广播:谁的IP是192.168.1.20?请告诉AA:AA:AA:AA:AA:AA。
  3. 广播帧的目的MAC是 ff:ff:ff:ff:ff:ff,同一网段的所有主机都能收到。
  4. 主机B一看,咦,问的是我的IP,于是回复一个ARP响应(单播):我就是,我的MAC是BB:BB:BB:BB:BB:BB。
  5. A收到后,把B的IP和MAC对应关系写入ARP缓存,然后开始正常通信。

整个过程,我用一张图来展示:

ARP 请求与响应流程 主机A 192.168.1.10 主机B 192.168.1.20 其他主机 忽略请求 ① ARP请求(广播) "谁的IP是192.168.1.20?" ② ARP响应(单播) "我就是,我的MAC是BB:BB:BB:BB:BB:BB" 主机A的ARP缓存表 192.168.1.20 → BB:BB:BB:BB:BB:BB (写入缓存,下次直接使用)

3.3.2 ARP缓存与老化

每次ARP解析完成后,结果会缓存在内核的ARP表中。你可以用 arp -n 或 ip neigh show 查看:

# ip neigh show
192.168.1.1 dev eth0 lladdr 00:11:22:33:44:55 REACHABLE
192.168.1.20 dev eth0 lladdr bb:bb:bb:bb:bb:bb STALE
192.168.1.100 dev eth0 lladdr cc:cc:cc:cc:cc:cc DELAY

状态说明:

  • REACHABLE:刚用过,确认可达。
  • STALE:超过一段时间没用了,但还没删。
  • DELAY:正在确认是否还活着。
  • FAILED:解析失败。

缓存默认超时时间通常是30~60秒(具体看内核参数 gc_stale_time)。为什么要老化?因为网络拓扑会变,设备可能换网卡、关机、换IP。我遇到过一个问题:一台服务器换了网卡,MAC变了,但其他机器的ARP缓存还是旧的,导致通信中断了十几分钟。后来我养成了习惯——换网卡后手动清一下ARP缓存:ip neigh flush all。

3.3.3 免费ARP(Gratuitous ARP)

这是一种特殊的ARP请求:源IP和目标IP都是自己。它有什么用?

  • 检测IP冲突:主机启动时发一个免费ARP,如果收到响应,说明有人用了同样的IP。
  • 更新其他设备的ARP缓存:比如你做VRRP(虚拟路由冗余协议)时,主备切换后新主机会发免费ARP,告诉所有人「网关的MAC变了」。

安全提醒:ARP协议本身没有认证机制,任何人都可以伪造ARP响应。这就是ARP欺骗攻击的原理——攻击者冒充网关,截获你的流量。防范方法:在关键网段配置静态ARP条目,或者使用DAI(动态ARP检测)。

3.4 实战:用tcpdump抓一个ARP包看看

光说不练假把式。咱们在Linux上抓个ARP包看看:

# 终端1:抓取ARP包
tcpdump -i eth0 -e -vv arp

# 终端2:触发ARP请求(比如ping一个不存在的IP)
ping -c 1 192.168.1.200

你会看到类似这样的输出:

14:23:45.123456 aa:aa:aa:aa:aa:aa > ff:ff:ff:ff:ff:ff, ethertype ARP (0x0806), length 42:
  Request who-has 192.168.1.200 tell 192.168.1.10, length 28

14:23:45.123789 (无响应,因为IP不存在)

注意看:ethertype 0x0806 就是ARP协议的类型字段。目的MAC是全f的广播地址。如果目标存在,你会看到一条单播的ARP响应。

我的习惯:排查网络不通时,第一步就是抓ARP包。如果ARP请求发出去没人理,那问题大概率在二层(物理链路、VLAN配置、交换机端口安全等)。如果ARP能解析成功但ping不通,再往三层查。

3.5 本章小结

数据链路层是网络通信的「最后一公里」。以太网帧规定了数据怎么封装,MAC地址解决了设备标识问题,ARP协议则把IP和MAC桥接起来。这三个概念是连在一起的——你理解了帧格式,就知道ARP请求是怎么封装在广播帧里的;你理解了MAC地址,就知道ARP缓存里存的是什么。