ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

一文读懂链路层:帧封装、差错检测与MTU排查实战

一文读懂链路层:帧封装、差错检测与MTU排查实战 1. 链路层到底在干什么干了这么多年网络我发现很多搞应用开发或者运维的朋友对TCP/IP协议栈的理解往往止步于IP层和传输层。一说到链路层大家的第一反应就是不就是网卡驱动嘛交换机和集线器那一层然后就没下文了。但实际上链路层是整个TCP/IP协议栈里最硬核也最容易被忽略的一层。如果你真正去排查过线上网络故障比如莫名其妙的丢包、延迟忽高忽低、甚至整个服务不可用你会发现最后十有八九问题都出在这一层。链路层在TCP/IP协议栈里的位置非常特殊。它处于IP层之下、物理层之上承担着把IP数据报封装成能在物理链路上传输的帧Frame的任务。换句话说IP层负责把数据从A主机送到B主机而链路层负责把数据从A的网卡送到隔壁路由器、再从路由器送到下一跳的网卡。前者是端到端的逻辑寻址后者是逐跳的物理传输这是两个完全不同的概念。这篇文章想帮你彻底搞清楚链路层的三个核心功能封装成帧、差错检测、可靠传输然后带你看懂以太网帧、PPP帧这些最常见的链路层协议长什么样最后结合我实际抓包排查的经验聊聊MTU问题、ARP问题这些大家最容易踩的坑。不管你是刚入门的学生还是写了几年代码的工程师只要你想把网络协议这件事吃透这篇内容都值得你花点时间看完。2. 协议栈里的最后一公里2.1 链路层在TCP/IP模型中的位置很多人一上来就看七层OSI模型觉得TCP/IP只有四层好像不太正规。但实际工程里TCP/IP的分层思路比OSI更贴近真实网络设备的工作方式。TCP/IP模型从上到下是应用层、传输层、网际层、网络接口层其中网络接口层其实就涵盖了OSI里的链路层和物理层。链路层和物理层的边界在哪我习惯这么理解物理层管比特怎么变成电信号、光信号怎么发出去链路层管比特怎么组织成有意义的帧、怎么让对端知道这一帧是完整的、正确的。打个比方物理层是公路本身链路层就是公路上的车道标线和交通规则。没有标线车也能开但大家各走各的绝对乱套。在TCP/IP协议栈里IP层向下发数据时不管底下是以太网、Wi-Fi、PPP还是其他什么链路技术IP层只负责把数据报交给链路层就行。链路层负责把IP数据报装进自己的帧结构里加上帧头、帧尾、校验字段然后交给物理层发送。这就是分层设计的好处IP层不用关心底下到底是有线还是无线链路层也不用关心上面跑的是TCP还是UDP。2.2 为什么说链路层是整个协议栈的地基我见过的很多故障排查到最后都指向链路层的问题但因为大家习惯从上层往下看所以绕了很多弯路。举个真实的例子有一次线上服务出现间歇性超时应用层日志里显示TCP重传率飙升开发同学第一反应是服务端负载过高、或者网络带宽被打满。结果查了半天CPU、内存、带宽都正常最后抓包一看链路上出现大量CRC校验错误的帧网卡统计里rx_crc_errors这个计数器一直在涨。这就是典型的链路层问题物理链路质量差可能是网线接头氧化、光模块接收功率过低导致帧在传输过程中出现了比特翻转接收端网卡做CRC校验发现对不上直接把这些帧丢掉。TCP层发现包丢了就开始重传表现到应用层就是延迟飙升。如果你只盯着TCP层看可能永远定位不到根因。所以我把链路层称为整个协议栈的地基——地基出了问题楼上再怎么装修都白搭。3. 封装成帧、差错检测与可靠传输的底层逻辑3.1 帧结构是怎么设计的链路层把IP数据报封装成帧的过程核心就是做三件事加上帧头、加上帧尾、可能还要做填充。帧头里最关键的字段是目的MAC地址和源MAC地址帧尾里最关键的是FCS帧校验序列字段。以太网帧的标准结构是前导码8字节物理层同步用、目的MAC6字节、源MAC6字节、类型/长度2字节0x0800表示上层是IPv40x0806表示是ARP0x86DD表示IPv6、负载46到1500字节、FCS4字节。这里有个很有意思的细节负载部分最少必须是46字节如果IP数据报太短链路层会做填充Padding保证帧长不小于64字节。为什么是64这跟以太网的冲突检测机制有关简单说就是确保一个站点在发送完整个帧之前能检测到远端的冲突信号——这是CSMA/CD协议在历史设计中留下的约束。3.2 CRC校验的工作原理与工程意义CRC循环冗余校验是链路层差错检测的核心。它不像校验和那样简单地把字节加起来而是把整个帧的数据看作一个巨大的二进制数用一个固定的生成多项式去除得到的余数就是CRC值。接收端收到帧之后重新做一遍同样的除法如果余数不为零说明帧在传输中出了问题直接丢弃。实际工程中以太网用的CRC是CRC-32生成多项式是0x04C11DB7。CRC-32的检错能力有多强它能检测出所有长度不超过32比特的突发错误对更长的突发错误漏检率也仅有2的-32次方级别的概率。这个可靠性在工程上是完全够用的。有个细节值得注意很多人在看Wireshark抓包的时候会发现网卡已经把CRC校验过的帧里的FCS字段去掉了所以你在Wireshark里看不到这个4字节的FCS字段。这很容易让初学者误以为以太网帧不用CRC——不是不用是网卡在接收的时候已经帮你验过并剥掉了。3.3 哪些链路层协议做了可靠传输严格来说以太网链路层本身不提供可靠传输。它是个尽力而为Best Effort的协议只保证发送了不保证对方一定收到了正确的数据。数据丢了、CRC错了以太网不负责重传这个工作交给上层TCP去做。但并不是所有链路层协议都这么佛系。比如PPP协议在特定配置下可以使用LCP链路控制协议里的选项来做差错控制和流量控制。再比如古老的停等协议、滑动窗口协议这些在数据链路层的教科书里讲得很多但实际在以太网里你根本用不到。为什么以太网当初不直接做可靠传输原因很简单复杂度和效率。逐跳重传机制会让每个交换机、每段链路都要维护状态这在高速网络中是不可接受的。既然上层TCP已经能保证端到端的可靠传输链路层再做一次逐跳可靠传输就是纯浪费。这是分层设计里一个非常经典的职责分离案例。4. 不能只会看IP以太网、PPP与WLAN链路层的差异4.1 以太网的帧封装与VLAN标签以太网最经典的帧格式是DIX 2.0也就是Ethernet II格式现在几乎所有以太网设备都在用这个格式。它跟IEEE 802.3原始标准的一个主要区别就是那个类型/长度字段DIX格式里这个字段是类型用来区分上层协议802.3格式里则是长度。后来大家为了兼容就通过约定当这个字段的值大于15000x0600时表示类型小于等于1500时表示长度。因为以太网负载最大就是1500字节所以用这个阈值来区分永远不会冲突。实际工程中还有一个几乎天天见到的扩展802.1Q VLAN标签。加了VLAN标签之后帧结构会变成目的MAC、源MAC、Tag4字节含TPID 0x8100和VLAN ID、优先级、类型、负载、FCS。多出来的4字节标签在交换机内部用于标识帧所属的VLAN实现二层隔离。做网络排查的人一定要知道这个结构因为当你看到PCAP包里的帧带VLAN标签时如果分析工具或者代码没有正确解析这个4字节后面的所有字段都会错位解析出来的IP层信息全是乱的。4.2 PPP协议点对点链路的标准答案PPP点到点协议是我个人觉得链路层协议里被低估的一个。它不像以太网那么普及但在拨号上网、DSL宽带、专线互联、以及很多物联网场景里PPP依然是标准方案。PPP帧的格式是标志字段7E、地址字段FF、控制字段03、协议字段2字节表示上层是IP还是LCP等、信息字段负载、FCS、标志字段7E。PPP最核心的价值在于它的协商机制。两台设备建立PPP链路的时候会先通过LCP协商链路参数比如最大接收单元MRU、认证协议然后通过NCP协商网络层参数比如IPCP分配IP地址、DNS地址。这个过程是动态的、可协商的跟以太网那种插上就能用的方式完全不同。很多人在配置路由器间专线互联的时候遇到过PPP认证失败的问题基本都是PAP或CHAP的用户名密码、认证方式配置不一致导致的。CHAP比PAP安全得多因为CHAP不会明文传输密码而是用挑战-响应机制做三次握手认证我在实际配置里基本都建议用CHAP。4.3 WLAN的链路层有哪些额外机制Wi-Fi802.11在链路层和以太网有三点非常大的不同。第一Wi-Fi的帧类型非常丰富管理帧关联、认证、Beacon、控制帧ACK、RTS/CTS、数据帧而以太网只有数据帧。第二Wi-Fi在链路层就做确认重传每发一个单播数据帧接收方必须回一个ACK帧没收到就不算发送成功发送方会重传。第三Wi-Fi有一个叫做隐藏节点的问题所以引入了RTS/CTS机制来预约信道。做无线网络优化时如果你看到报文里大量RTS/CTS说明环境中存在比较严重的隐藏节点问题这种场景下整体吞吐量会明显下降。这些差异解释了为什么Wi-Fi的链路层开销远大于有线以太网也是为什么同带宽条件下无线实际吞吐永远做不到有线那么高。很多人抱怨千兆Wi-Fi跑不满抛开信号衰减不谈光链路层这些ACK、RTS/CTS的开销就吃掉了一部分理论带宽。5. 实际抓包看链路层一份帧的完整解剖5.1 用Wireshark读懂链路层的每一字节纸上谈兵没意思我建议你实际操作一遍在自己电脑上打开Wireshark抓几个ping包然后仔细看链路层的字段。你第一次会发现一个颠覆认知的事实你在Wireshark里看到的帧跟实际在网线上跑的帧是不完全一样的。具体说Wireshark在解析以太网帧时默认不会显示前导码和FCS字段因为网卡驱动在收发过程中已经处理掉了。Wireshark展示给用户的Frame信息里起始是目的MAC地址。如果你用tcpdump的-e选项去抓包或者直接在交换机上用SPAN端口做镜像抓包能拿到更完整的二层信息。我自己排查二层环路问题时经常直接在交换机上做端口镜像然后把抓到的包放到Wireshark里过滤。有一次发现某个接口上存在大量目的MAC地址全F的广播帧再结合STP的Topology Change Notification和传播延时去分析最终定位到一个老交换机上运行了多余的STP实例导致收敛异常。Wireshark的列表面板里默认有一列叫Info对ARP报文会显示Who has X.X.X.X? Tell Y.Y.Y.Y对IP报文会显示协议类型和TCP/UDP端口信息。但如果你要深入分析链路层建议把Source列切换成Source MAC、Destination列切换成Destination MAC再来看否则你看到的其实主要是IP地址很容易把链路层的信息忽略掉。5.2 过滤器的正确用法分析链路层问题时Wireshark过滤器一定要会用。wlan.fc.type 0可以过滤出Wi-Fi管理帧ether.type 0x0806抓ARP包arp.opcode 1看ARP请求、arp.opcode 2看ARP应答。如果是排查VLAN相关的问题用vlan.id 100来过滤特定VLAN的帧。这些过滤表达式看起来简单但实际排查效率极高。比如你想看链路上有没有设备在发送持续变动的广播风暴直接ether.type 0x0806配合统计工具就能快速确认是ARP风暴还是其他协议风暴。用Wireshark的统计-协议分级功能可以迅速看到当前抓包文件里各种协议所占的比例如果ARP的比例异常高那基本可以断定二层有问题了。5.3 链路层的MTU之争MTU是链路层一个极其重要的参数。以太网的默认MTU是1500字节也就是说一个IP数据报最多能装进1500字节的负载里。如果上层应用发送的数据包超过这个大小IP层就要做分片Fragmentation。分片本身不复杂复杂的是分片之后的组装、以及分片丢失后的重传。实际生产中最常见的问题就是MTU黑洞。所谓黑洞就是网络路径上某个设备的MTU比1500小比如PPPoE拨号场景下MTU是1492但这个设备又不返回ICMP Fragmentation Needed消息。结果是大包在路径上被丢弃发送方不知道要减小包大小TCP连接就会陷入反复重传表现为网页打不开、下载卡住。排查这类问题有一个经典做法用ping -M do -s 1472在Linux下来测试特定的包大小能否通。1472这个数字就是1500减去IP头20字节加ICMP头8字节后的结果。如果ping 1472通、ping 1473不通说明路径上MTU就是1500而不是更大如果更小的包也不通就要考虑路径上是不是有MTU更小的中间设备。我在云上部署服务的时候遇到过几次诡异的问题ECS之间通过负载均衡通信某些特定大小的POST请求总是失败而小请求正常。最后发现是负载均衡和后端服务器之间的链路MTU设置不一致导致大包在中间被丢。改成统一设置MTU并启用PMTUD路径MTU发现之后问题立刻消失。这类问题平时很难发现因为你光看应用日志只能看到请求超时永远看不到根因。6. 链路层问题排查的实战心得6.1 经典的ARP排查思路ARP地址解析协议在TCP/IP里虽然算辅助协议但它本质上是链路层的直接依赖IP层要把包发给下一跳必须先把下一跳的IP地址解析成MAC地址否则帧头里的目的MAC写什么所以ARP表出了问题整个网络就瘫痪了。排查ARP问题我一般分三步走。第一步看ARP表是否完整用arp -aWindows/Linux都支持看本机的ARP缓存。如果目标IP对应的MAC没有解析出来先确认是不是在同一广播域内跨网段的通信必须走网关MAC。第二步抓包看ARP请求是否发出、应答是否回来。很多情况下ARP请求发了但没应答原因可能是目标主机的防火墙过滤了ARP虽然不太常见、交换机端口设置了端口隔离、或者两个设备不在同一个VLAN里。第三步注意ARP表项超时和更新的问题。某些老设备或特殊配置的网络里会出现ARP表更新慢的现象导致设备明明已经换了IP但别的机器还在往旧的MAC地址发数据。6.2 链路层三大经典故障冲突、错包、广播风暴我把这些年遇到最多的链路层故障整理成了一张表供你参考故障类型典型表现底层原因排查手段冲突Collision半双工模式下大量冲突吞吐暴跌共享式集线器仍然存在、双工模式不匹配查看网卡统计信息collisions计数器强制设置为全双工CRC错包丢包率上升TCP重传增多网线质量差、接口氧化、光模块老化查看ethtool -S统计rx_crc_errors尝试更换物理链路广播风暴整个二层网络瘫痪CPU飙升二层环路未启用STP、环路导致广播帧无限转发启用STP/RSTP用生成树协议阻断冗余链路6.3 从网卡统计信息精准定位问题Linux下有个非常好用的命令ethtool -S eth0。它能显示网卡上各种计数器的具体数值比如rx_errors、tx_errors、rx_crc_errors、rx_missed_errors、rx_no_buffer_count等。这些数据是定位链路层问题的一手资料很多人排查网络问题时完全忽略这层信息实在可惜。举个例子如果rx_missed_errors持续增加说明网卡收到了数据但内核没有及时取走导致网卡内部缓冲区溢出丢弃了帧。这可能是内核收包软中断处理不过来也可能是应用层陷入长时间阻塞导致socket缓冲区积压。如果rx_crc_errors在增长优先怀疑物理层问题——换线、换模块、清洁接口。如果tx_timeout出现通常是网卡驱动或者硬件出了问题这时候建议更新驱动或者直接换网卡。6.4 一个完整的排查实例有一次客户报障说内网文件传输服务异常缓慢单文件传输速度从原来的100MB/s掉到了10MB/s以下。我登录服务器后第一步不是看应用日志而是先看网卡统计ethtool -S eth0 | grep -E err|miss|drop。结果发现rx_crc_errors在一分钟内增加了上千次同时rx_errors也在增长。根据这个线索我判断问题出在物理链路上。联系机房维护检查后发现交换机端口对应的光模块接收功率接近临界值-26dBm明显是光模块衰减过大。更换光模块和尾纤后rx_crc_errors停止增长文件传输速度立刻恢复正常。整个过程从排查到解决不到半个小时。如果从应用层开始查可能要查几天都查不出个所以然。7. 链路层内容的后续扩展方向链络层这套东西我写完之后自己回看都觉得信息量不小但实话告诉你这篇文章里能展开的还远不止这些。如果你对这个方向感兴趣后续可以从这几个方向继续深挖。第一个方向是二层交换机的转发原理。网桥和交换机怎么学习MAC地址表、怎么处理广播帧和未知单播帧、STP生成树是怎么算出来的这些是理解整个局域网工作方式的关键。第二个方向是虚拟化网络里的链路层比如Open vSwitch怎么实现的VXLAN封装、Kubernetes里Pod和Service的二层网络方案这些现代基础设施都绕不开链路层技术的变体。第三个方向是无线网络链路层深度分析802.11n/ac/axWi-Fi 6引入的聚合、块确认机制到底怎么提升性能这套东西跟有线以太网是完全不同的思维模式。我个人做网络排查这些年最大的一条心得就是链路层是最接近物理现实的一层也是很多灵异现象的真正根源。把链路层的原理搞清楚遇到问题的时候先别急着追上层先从网卡、帧、CRC这些底层字段入手往往能少走很多弯路。因为上层协议再复杂最后数据终究要变成帧走过网线、通过光模块这一路上遇到的任何颠簸都会在上层暴露成各种看似无关的故障。下次你遇到查不出原因的网络问题可以试试从链路层往下看说不定会有意外收获。
返回列表