第3章 以太网帧结构:从前导码到FCS,每一字节都不白给

抓包这么多年,我发现很多人一上来就盯着IP和TCP看。底层的以太网帧长什么样?反而没人关心。但你想想看,交换机转发数据靠的是什么?就是以太网帧头里的MAC地址。搞不懂帧结构,丢包定位就少了一半的线索。

这一章咱们把以太网帧从头到尾拆一遍。每个字段干什么用、占多少字节、抓包时怎么看。都是我实际排查中用得上的东西。

说个我个人的习惯: 每次抓包分析,我第一件事就是先看帧头。确认MAC地址对不对、FCS有没有报错。这些底层的线索,往往比上层协议更早暴露问题。

3.1 帧结构总览

标准的以太网帧长这样。你记一下,总共7个字段,从前往后依次是:前导码、帧起始定界符、目标MAC、源MAC、类型/长度、数据、FCS。前导码和SFD在物理层加上去,抓到包时Wireshark通常不显示这两段。

以太网帧结构(802.3 标准) 前导码 7 字节 SFD 1 字节 目标MAC 6 字节 源MAC 6 字节 Type/Len 2 字节 数 据 46 ~ 1500 字节 FCS 4 字节 注意:前导码 + SFD 共 8 字节由物理层添加,Wireshark 不显示这两段 抓包时你看到的最小帧长度是 64 字节(从目标MAC到FCS) ← 帧起始 帧结束 →

上面这张图就是以太网帧的全貌。我建议你把它存下来,以后抓包分析时对照着看。每个字段的位置、长度、顺序,都是固定的。交换机就是靠着这个结构,一级一级把数据送到目的地。

3.2 前导码与帧起始定界符

前导码占7个字节,内容是1010...交替。它的作用就是让接收端的时钟同步。说白了,就是告诉对方“我要发数据了,你准备好”。

SFD是帧起始定界符,1个字节,内容是10101011。最后两位是11,表示下一字节就是MAC头了。我在项目里曾经遇到过,某个老交换机在长时间高负载下偶尔会误判SFD,导致整包被丢弃。这种情况非常隐蔽,只有长时间抓包才能发现。

我曾经踩过这个坑: 有次排查一个间歇性丢包的问题,抓包看了半天没发现异常。后来把物理层抓下来一看,前导码和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的,分析起来更清爽。

实战要点: 抓包排查丢包时,如果发现大量非IP类型的帧(比如0x0806 ARP或0x8100 VLAN Tag),说明网络中存在异常的控制平面流量。这时候要先确认不是攻击或环路,再往下查。

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错误计数,才锁定是物理层问题。

查FCS的方法: 在Wireshark里直接看 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会显示校验是否通过。我建议你下次抓包时,对着这个布局看一遍,每个字节落在哪个字段上,心里就有数了。

注意: 有些抓包工具(比如tcpdump)默认会把FCS去掉。如果需要看FCS,记得在捕获时加 -e 参数,或者在Wireshark里开启 “捕获时包含帧校验序列” 选项。否则你看到的帧最后4个字节其实是填充数据,不是真的FCS。

以太网帧结构,说白了就是数据在链路上跑的“外壳”。搞懂了每个字段的含义和位置,你抓包时就能一眼看出问题出在哪一层。MAC地址错了、类型不对、FCS报错——这些都是丢包的常见原因,而且都能在帧结构里找到直接证据。

一句话总结: 帧头看MAC,帧尾看FCS,中间看类型和数据。三层以上再复杂,底下这层稳不住,上层全白搭。我自己每次排查丢包,都从这一层开始看,能省不少弯路。