1. MAC层基础:以太网帧结构、MAC地址、MAC子层功能
丢包排查,说到底就是跟 MAC 层打交道。你想想看,网络数据从应用层一路封装下来,最后变成比特流在线上跑,MAC 层就是那个“装货上车”的环节。如果这层出了错,上层再好的协议也白搭。我个人习惯先把 MAC 层的基本零件拆开,看清楚帧长什么样、地址怎么用、子层管什么。
1.1 以太网帧结构——数据在线上到底长啥样?
以太网帧不是凭空画出来的。IEEE 802.3 标准规定了它必须包含这些字段。我直接列一个表,后面再逐一说。
| 字段 | 长度(字节) | 说明 |
|---|---|---|
| 前导码(Preamble) | 7 | 1010…交替,用于时钟同步 |
| 帧起始定界符(SFD) | 1 | 10101011,标识帧开始 |
| 目的 MAC 地址 | 6 | 接收方地址 |
| 源 MAC 地址 | 6 | 发送方地址 |
| 类型/长度 | 2 | > 1536 时为 EtherType,否则为长度 |
| 数据 / 填充 | 46–1500 | 最少 46 字节,不够就补 0 |
| 帧校验序列(FCS) | 4 | CRC32,校验除前导码/SFD 外的所有字段 |
这里我特别想告诉你一个坑。我在项目中遇到过好几次,有人把前导码也算进帧长,结果抓包软件显示的帧长总是多 8 字节。实际上,前导码和 SFD 在 MAC 层处理完后就被剥离了,真正发给上层的是从目的 MAC 开始到 FCS 结束的那部分。嗯,记住这一点,后面分析错包时就少绕弯路。
1.2 MAC 地址——它是怎么被分配的?
MAC 地址 48 位,前 24 位是 OUI(组织唯一标识符),后 24 位是设备分配的序列号。你可以在 IEEE 官网查 OUI,但我一般直接 ping 完用 arp -a 看缓存,更快。不过地址的格式里有个字节级的小逻辑:目的 MAC 第一个字节的最低位为 0 表示单播,为 1 表示多播;全 1 是广播。
// 一个典型的单播 MAC:00-1A-2B-3C-4D-5E
// 二进制第一字节:0000 0000 → LSB = 0 → 单播
// 多播 MAC 举例:01-00-5E-00-00-01(用于组播路由的 OSPF)
// 广播 MAC:FF-FF-FF-FF-FF-FF
重要:MAC 地址的比特顺序有大坑。在以太网传输时,每个字节的 LSB 先发送(即所谓的“规范格式”),但有些文档(比如 Ring)用 MSB 先发送。你如果做硬件调试,发现抓到的比特流和预期反了,八成是这个原因。
说白了,MAC 地址只有本地链路意义,出了广播域就不依赖它了。我曾经遇到一个客户,非要用 MAC 跨三层做访问控制,结果路由一跳 MAC 就变了,策略根本执行不了。这就像用门牌号去定位全国的城市,不对路的。
1.3 MAC 子层功能——它到底干了哪些活?
IEEE 802.3 把 MAC 子层拆成两个小部分:MAC 控制子层(可选)和 MAC 数据子层。数据子层就是做帧的封装/解封装,还有介质访问控制——说白了就是 CSMA/CD(半双工时)和现在的全双工流控(PAUSE 帧)。
你可能会问:“现在都是全双工,CSMA/CD 是不是没用了?” 其实不然,很多交换机在端口协商失败后会自动回退到半双工,这时候 MAC 子层仍然要监听碰撞。我排查过一个丢包案例,就是网线只通了两对线导致协商成半双工,单向大量冲突引起 CRC 错误。
MAC 子层还负责两个很关键的“边缘检查”:
- 帧长度检查:小于 64 字节(含 FCS)视为 runt,大于 1518 字节(含 VLAN 标签时 1522)视为 jabber,直接丢弃。
- FCS 校验:计算 CRC32,不匹配就打上错误标记。
这里有一个常见的误解:FCS 错误不一定是物理层问题。我见过一个案例,CPU 驱动的 DMA 环形缓冲区写乱了,导致 MAC 层自己发出的帧 CRC 就是错的。后来改了一下 DMA 描述符对齐才解决。所以排查时别只查线缆,也要看看驱动和硬件 FIFO。
1.4 几个容易让人栽跟头的细节
- 帧最小长度 64 字节(含 FCS)。因为 CSMA/CD 需要确保冲突信号在发送结束前传回。全双工下这个限制仍然存在,只是不用于冲突检测了。我见过一台老交换机扔掉了所有小于 64 字节的正常 TCP ACK,就因为 CPU 发送时没补 0。
- VLAN 标签:802.1Q 在源 MAC 和类型/长度之间插入 4 字节(TPID + TCI),此时最大帧长变为 1522 字节。有些老交换机标称 1518,遇到带 VLAN 的大包直接就丢了。
- 帧间隔(IFG):发送完一帧后必须空闲至少 12 字节时间(96 bit-time)。不算在帧结构里,但 MAC 层必须遵守,否则接收方可能把两帧当成一帧。
好了,这一章我把 MAC 层的几个基本零件拆开讲了一遍。帧结构、地址、子层功能,三者加起来就是以太网通信的基石。记住,很多丢包的根本原因就藏在这些“常识”里——比如 CRC 校验域算错、前导码污染、巨型帧不匹配。下一回你抓个 ping 包,不妨从目的 MAC 第一个字节的第一个比特开始看,说不定能发现点什么。