第3章 以太网帧结构:从前导码到FCS,每一字节都不白给
抓包这么多年,我发现很多人一上来就盯着IP和TCP看。底层的以太网帧长什么样?反而没人关心。但你想想看,交换机转发数据靠的是什么?就是以太网帧头里的MAC地址。搞不懂帧结构,丢包定位就少了一半的线索。
这一章咱们把以太网帧从头到尾拆一遍。每个字段干什么用、占多少字节、抓包时怎么看。都是我实际排查中用得上的东西。
3.1 帧结构总览
标准的以太网帧长这样。你记一下,总共7个字段,从前往后依次是:前导码、帧起始定界符、目标MAC、源MAC、类型/长度、数据、FCS。前导码和SFD在物理层加上去,抓到包时Wireshark通常不显示这两段。
上面这张图就是以太网帧的全貌。我建议你把它存下来,以后抓包分析时对照着看。每个字段的位置、长度、顺序,都是固定的。交换机就是靠着这个结构,一级一级把数据送到目的地。
3.2 前导码与帧起始定界符
前导码占7个字节,内容是1010...交替。它的作用就是让接收端的时钟同步。说白了,就是告诉对方“我要发数据了,你准备好”。
SFD是帧起始定界符,1个字节,内容是10101011。最后两位是11,表示下一字节就是MAC头了。我在项目里曾经遇到过,某个老交换机在长时间高负载下偶尔会误判SFD,导致整包被丢弃。这种情况非常隐蔽,只有长时间抓包才能发现。
3.3 目标MAC与源MAC
这两个字段各6个字节,一共12字节。MAC地址是全球唯一的,由OUI(厂商代码)+ 序列号组成。目标MAC决定这个帧要去哪,源MAC告诉别人这个帧从哪来。
交换机转发数据,就是靠学习源MAC建立转发表,再根据目标MAC做转发决策。我建议你熟记几个特殊的MAC:
- 广播MAC: FF-FF-FF-FF-FF-FF,所有设备都会接收
- 组播MAC: 以01-00-5E开头,对应IP组播地址
- 全0 MAC: 一般用于STP等控制协议,正常数据帧不能用
我记得有一次,一个网段里突然所有设备都收不到包。抓包一看,源MAC全是FF-FF-FF-FF-FF-FF。明显是某台设备的MAC芯片出了问题,产生了大量的非法广播帧。这种问题,你不看MAC字段,根本找不到根因。
3.4 类型/长度字段
这个字段很有意思。2个字节,有两种用法:
- 当值 ≥ 0x0600(1536)时, 表示上层协议类型。比如0x0800是IPv4,0x0806是ARP,0x86DD是IPv6。
- 当值 ≤ 0x05DC(1500)时, 表示后面数据字段的实际长度。这是802.3标准定义的用法。
现在的网络设备基本都按类型来用。你抓包时看一眼这个字段,就知道上层跑的是什么协议。我个人的习惯是,先过滤掉非IP的帧,只保留0x0800的,分析起来更清爽。
3.5 数据字段
数据字段承载上层协议报文。最小46字节,最大1500字节。你想想看,为什么要有最小限制?因为以太网要求帧长度不能小于64字节(从目标MAC到FCS)。减去18字节的头部(目标MAC6 + 源MAC6 + 类型2 + FCS4),数据最少要46字节。不够的话,自动补0。
这个最小64字节的规则,是为了冲突检测。CSMA/CD机制要求帧在发送完毕前,必须能被所有站点感知到。如果帧太短,发完了冲突还没传回来,就检测不到了。现在的全双工链路虽然不用CSMA/CD,但这个最小长度限制一直保留着。
我遇到过一个问题:某个业务报文只有30字节,发送端补了16个0填充到46字节。抓包时业务系统说收到了多余的数据,其实那些0是填充,不是业务数据。应用层应该自己记录真实长度,而不是看帧长度。
3.6 FCS 帧校验序列
FCS是4个字节的CRC32校验值。覆盖从目标MAC开始到数据结束的所有字段。发送端计算好填进去,接收端重新算一遍,不一致就丢帧。
这个校验能检测出传输过程中出现的比特错误。但不能纠正。我在项目中见过一个案例:某条光纤链路老化,偶尔会出现单比特翻转。应用层偶发性报错,但重传后就恢复了。最后是在交换机端口上看到了大量的CRC错误计数,才锁定是物理层问题。
Frame check sequence 字段。如果显示 [Incorrect],那就是校验失败了。另外,交换机的端口统计里一般都有 CRC errors 和 FCS errors,这两个计数增长就说明链路层有问题。
下面是各字段的汇总表,我经常打印出来贴在工位上。你收好。
| 字段名 | 长度(字节) | 作用 | 抓包中是否可见 |
|---|---|---|---|
| 前导码(Preamble) | 7 | 接收端时钟同步 | 否(物理层添加) |
| 帧起始定界符(SFD) | 1 | 标识帧开始 | 否(物理层添加) |
| 目标MAC(Destination MAC) | 6 | 接收方地址 | 是 |
| 源MAC(Source MAC) | 6 | 发送方地址 | 是 |
| 类型/长度(Type/Length) | 2 | 上层协议类型 或 数据长度 | 是 |
| 数据(Payload) | 46 ~ 1500 | 承载上层报文 | 是 |
| 帧校验序列(FCS) | 4 | CRC32 检错 | 是(Wireshark显示校验结果) |
3.7 抓包实战:从十六进制看帧结构
讲完了理论,咱们来点实际的。下面是一个完整的以太网帧的十六进制表示。我拿它带你亲手拆一遍每个字段的位置。
前导码(7B) SFD(1B) 目标MAC(6B) 源MAC(6B) 类型/长度(2B) 数据(46-1500B) FCS(4B)
AA AA AA AA AA AA AA AB 00 1E 4F 3A 2B 1C 00 1E 4F 3A 2B 1D 08 00 45 00 00 3C ... 00 00 12 34 56 78
↑——物理层添加,抓包通常不显示——↑ ↑——Wireshark 中 Ethernet II 头部显示——↑ ↑——IP头+数据——↑ ↑——校验和——↑
在Wireshark里展开 Ethernet II 这一层,你就能看到目标MAC、源MAC和类型/长度这三个字段。前导码和SFD不显示,FCS会显示校验是否通过。我建议你下次抓包时,对着这个布局看一遍,每个字节落在哪个字段上,心里就有数了。
-e 参数,或者在Wireshark里开启 “捕获时包含帧校验序列” 选项。否则你看到的帧最后4个字节其实是填充数据,不是真的FCS。
以太网帧结构,说白了就是数据在链路上跑的“外壳”。搞懂了每个字段的含义和位置,你抓包时就能一眼看出问题出在哪一层。MAC地址错了、类型不对、FCS报错——这些都是丢包的常见原因,而且都能在帧结构里找到直接证据。