1. 从一个抓包现场说起:为什么需要单独理解数据链路层
很多人学网络是从TCP/IP四层模型或者OSI七层模型开始的,背得滚瓜烂熟,但一到实际抓包就懵了。我见过不少刚入行的朋友,用抓包工具抓到一堆帧,看到里面既有MAC地址又有IP地址,还有各种类型字段,完全分不清哪些是数据链路层干的活,哪些是网络层干的活。更典型的一个场景是:两台机器明明IP配在同一网段,ping就是不通,查了路由表没问题,最后发现是交换机端口VLAN配错了——这就是典型的二层问题,但很多人第一反应会往三层去查。
数据链路层这个位置很特殊。它夹在物理层和网络层之间,往下要管比特流怎么变成帧,往上要给网络层提供一个“看起来没有差错”的链路。你可以把它理解成一个“快递打包+同城配送”的角色:网络层是发货方,告诉它“把这个包送到隔壁城市那个地址”,数据链路层负责把包裹装进合适的箱子、贴上本地的配送标签、确保从仓库到转运中心这一段路上不出岔子。至于跨城市怎么走,那是网络层的事。
交换机就是在这个层面上工作的核心设备。它不看IP,只看MAC地址,根据MAC地址表决定把帧从哪个端口转发出去。这个“只看MAC”的特性既是它快的原因,也是很多问题的根源——因为它不关心IP层面的逻辑,所以IP层的广播风暴、ARP欺骗这些问题,它照单全收地转发。
这篇文章我会从实际排错和抓包的角度出发,把数据链路层的核心功能拆开讲清楚,然后把交换机的工作原理从MAC地址学习到转发决策到环路避免,一层层剥开。适合已经了解网络基础但想深入理解二层机制的朋友,也适合正在准备网络方向面试或认证的读者。我会尽量用实际场景和抓包结果来说明,而不是堆砌定义。
2. 数据链路层的三大核心功能:不止是“加个MAC头”那么简单
2.1 帧定界与透明传输:物理层给的比特流怎么切
物理层交给数据链路层的就是一串连续的比特流,没有边界。数据链路层第一件事就是把这串比特流切成一个个帧。怎么切?常见的方法有几种:字符计数法、字符填充法、零比特填充法、违规编码法。实际以太网用的是前导码加帧起始定界符的方式,前面7个字节的0xAA做前导码用于时钟同步,然后是1个字节的0xAB作为帧起始定界符,接收方看到这个模式就知道帧开始了。
这里有个容易被忽略的点:透明传输。如果帧的数据部分恰好出现了和帧定界符一样的比特模式怎么办?比如数据里出现了连续的5个1,接收方可能会误认为是帧结束标志。以太网的做法是零比特填充:发送方在数据中每遇到5个连续的1就自动插入一个0,接收方收到后每遇到5个连续的1就把后面的0删掉。这个操作是在物理层编码阶段完成的,但逻辑上属于数据链路层的功能范畴。
我在实际抓包时经常看到有人问“为什么我抓到的帧长度和实际数据长度对不上”,很多时候就是因为没有把帧头帧尾的开销算进去。一个标准以太网帧,最小64字节,最大1518字节(不含VLAN标签),其中帧头14字节,帧尾FCS 4字节,实际数据部分最少46字节,最多1500字节。这个1500就是MTU的由来。
2.2 差错检测:FCS能查什么,不能查什么
以太网帧尾部有一个4字节的帧检验序列(FCS),用的是CRC-32算法。发送方计算帧头加数据部分的CRC值填入FCS,接收方收到后重新计算并比对。如果对不上,帧就被丢弃。
但这里有个关键认知:FCS只能检测比特错误,不能检测帧丢失、帧重复、帧乱序。也就是说,如果某个帧在传输过程中整个丢了,接收方根本不知道——因为FCS只对收到的帧做校验,没收到的东西它无从校验。这就是为什么数据链路层被称为“不可靠传输”,可靠性要靠上层(比如TCP)来保证。
另一个常见误解是认为交换机在转发时会重新计算FCS。实际上,交换机在存储转发模式下会检查FCS,如果错误就直接丢弃,不会转发;如果正确,它会重新计算FCS再发出去,因为源MAC和目的MAC可能变了,帧头变了FCS自然要重算。但在直通转发模式下,交换机只看到目的MAC就开始转发,根本不检查FCS,所以错误帧也会被转发出去。这就是直通转发延迟低但可能传播错误帧的原因。
2.3 介质访问控制:谁先说话的问题
以太网用的是CSMA/CD(载波监听多路访问/冲突检测),这是半双工时代的产物。简单说就是:想发数据先听,线路空闲就发,发的时候继续听,如果发现冲突就停止发送,等一个随机时间再重试。这个机制在共享式以太网(用集线器的时代)是必须的,因为所有设备在同一个冲突域里。
但现在全双工交换式以太网普及了,每个端口都是一个独立的冲突域,CSMA/CD实际上已经不再启用。你在全双工端口上抓包是看不到冲突的。不过理解这个机制仍然重要,因为它解释了为什么集线器和交换机的性能差距那么大:集线器所有端口在同一个冲突域,同一时刻只能有一个设备发送;交换机每个端口独立冲突域,可以同时收发。
无线网络里的CSMA/CA是类似的思路,但用避免碰撞代替检测碰撞,因为无线环境很难检测冲突。这个区别在理解Wi-Fi性能问题时很关键。
3. 交换机内部到底在做什么:MAC地址表的学习、转发与老化
3.1 MAC地址表是怎么建起来的
交换机刚上电时,MAC地址表是空的。当它从某个端口收到一个帧时,会做两件事:第一,把帧的源MAC地址和接收端口号记录到MAC地址表里,如果表中已有这个MAC就更新端口和老化计时器;第二,根据目的MAC地址查表决定从哪个端口转发。
这个过程叫“源地址学习”。我见过有人问“交换机是不是一开机就知道所有设备的MAC”,不是的,它必须通过实际流量来学习。所以如果你把一台设备插到交换机上但从不发数据,交换机的MAC地址表里就没有它。这时候如果有其他设备要发数据给它,交换机会因为查不到目的MAC而泛洪到所有端口(除了接收端口)。
MAC地址表的老化时间默认是300秒(5分钟)。如果5分钟内没有收到某个MAC的帧,表项就被删除。这个设计是为了适应设备迁移:如果一台设备从端口1拔下来插到端口2,交换机需要重新学习。如果老化时间太长,中间这段时间发往该MAC的帧会被错误地转发到端口1。
3.2 泛洪、转发和过滤:三种转发决策
交换机收到帧后,根据目的MAC查表,有三种可能:
- 转发:表中找到了目的MAC,且对应的端口不是接收端口,就从该端口转发出去。
- 过滤:表中找到了目的MAC,但对应的端口就是接收端口,说明目的设备和源设备在同一端口上(比如中间还接了一个集线器),直接丢弃,不转发。
- 泛洪:表中没找到目的MAC,或者目的是广播地址(FF:FF:FF:FF:FF:FF)或多播地址,就从除了接收端口以外的所有端口转发出去。
泛洪是很多网络问题的根源。比如ARP请求就是广播帧,会被泛洪到所有端口。如果网络里有环路,广播帧会在环路里无限循环,形成广播风暴,瞬间打满带宽。这就是为什么二层网络必须用生成树协议(STP)来破环。
3.3 交换机的三种转发模式对比
| 转发模式 | 工作原理 | 延迟 | 错误帧处理 | 适用场景 |
|---|---|---|---|---|
| 存储转发 | 收完整个帧,检查FCS,再查表转发 | 高(与帧长成正比) | 丢弃错误帧 | 对可靠性要求高的核心层 |
| 直通转发 | 只读到目的MAC(前6字节)就开始转发 | 低(固定延迟) | 转发错误帧 | 对延迟敏感的高性能计算 |
| 无碎片转发 | 读到前64字节(最小帧长)再转发 | 中等 | 丢弃小于64字节的碎片帧 | 折中方案,常见于接入层 |
实际设备上,很多交换机支持自适应模式:默认存储转发,如果错误率低于某个阈值就自动切到直通。这个阈值通常是可配的,我一般建议在接入层保持存储转发,因为接入层流量不大,延迟差异用户感知不到,但错误帧被转发出去可能导致上层协议异常。
4. 二层环路与STP:为什么你的网络会突然“卡死”
4.1 广播风暴是怎么形成的
假设你有三台交换机连成一个三角形,没有启用STP。现在某台设备发了一个ARP广播帧。交换机A从端口1收到,泛洪到端口2和端口3。交换机B从端口1收到,泛洪到端口2和端口3。交换机C从端口1收到,泛洪到端口2和端口3。然后交换机B从端口2又收到了交换机C泛洪过来的同一个帧,它不认识这是同一个帧,又泛洪一遍……如此循环,广播帧的数量呈指数增长,几秒钟内就能占满所有链路带宽,CPU也被中断处理打满。
这个现象在实际中表现为:网络突然变得极慢,ping丢包严重,交换机指示灯疯狂闪烁,管理界面可能都登不上去。如果你拔掉一条环路中的线,网络立刻恢复,那基本可以确定是环路问题。
4.2 STP的工作过程:选根、定角色、置状态
STP(生成树协议)的核心思想是:在逻辑上把有环的物理拓扑剪成一棵树,让任意两台设备之间只有一条活动路径。过程分三步:
选根桥:所有交换机交换BPDU(桥协议数据单元),比较桥ID(优先级+MAC地址),最小的成为根桥。优先级默认32768,可以手动调低让某台设备成为根桥。我一般建议把核心交换机优先级设为4096或8192,确保它被选为根。
选根端口:每台非根交换机选一个到根桥路径开销最小的端口作为根端口。路径开销和带宽有关:10M是100,100M是19,1G是4,10G是2。所以万兆链路比千兆链路更优先。
选指定端口:每条链路上选一个指定端口,负责向该链路转发BPDU和用户数据。根桥上的所有端口都是指定端口。
剩下的端口进入阻塞状态,不转发用户数据,只接收BPDU。如果活动链路故障,阻塞端口经过监听(15秒)、学习(15秒)后进入转发状态,整个过程默认30-50秒。这个收敛时间在现在来看太长了,所以有了RSTP(快速生成树),收敛时间可以降到1秒以内。
4.3 实际排错中怎么快速定位环路
我常用的方法是:登录交换机,看MAC地址表里同一个MAC是否出现在多个端口上。如果出现,说明有环路。或者看接口的广播包速率,如果某个端口广播包速率异常高(比如每秒几千个),基本可以确定环路在那个方向。
还有一个更直接的方法:在交换机上开启风暴控制,设置一个广播包速率阈值,超过就自动关闭端口。这样至少能保护网络不被一个环路打垮。但这是治标不治本,根本还是要找到环路点并启用STP。
注意:有些低端交换机默认不开STP,或者STP实现有问题。如果你在接入层用这种设备,一定要在接入口配置BPDU Guard,防止下面接的设备发BPDU干扰生成树计算。
5. VLAN与Trunk:交换机如何在一个物理网络上切出多个逻辑网络
5.1 VLAN解决的是什么问题
没有VLAN的时候,一个交换机就是一个广播域。所有设备的广播帧都会泛洪到所有端口。如果网络规模大了,广播流量会占用大量带宽,而且安全性也差——任何人都能收到别人的广播。VLAN把一个物理交换机划分成多个逻辑交换机,每个VLAN是一个独立的广播域,VLAN之间的广播是隔离的。
划分VLAN的方式有几种:基于端口(最常用)、基于MAC地址、基于协议、基于子网。实际部署中99%的场景用的是基于端口,因为最简单最可控。比如把端口1-8划到VLAN 10,端口9-16划到VLAN 20,这样VLAN 10里的广播不会传到VLAN 20。
5.2 Trunk链路和802.1Q标签
如果两台交换机上都有VLAN 10和VLAN 20,它们之间的链路需要同时传输两个VLAN的流量,这就是Trunk链路。Trunk链路上传输的帧会打上802.1Q标签,在源MAC和类型字段之间插入4个字节,其中包含12位的VLAN ID(支持4096个VLAN,实际可用1-4094)。
标签里还有一个3位的优先级字段(802.1p),用于QoS。这个在实际中很有用:比如你可以把语音流量标记为高优先级,交换机在拥塞时优先转发。
Access端口收到不带标签的帧时,会打上该端口PVID(默认是端口所属VLAN)的标签;发送时如果标签等于PVID就剥离标签再发。Trunk端口收到带标签的帧时,如果VLAN ID在允许列表里就转发,否则丢弃;发送时保留标签(除了Native VLAN)。
Native VLAN是个容易出问题的地方。默认是VLAN 1,Trunk两端必须一致,否则会出现VLAN跳变。我一般建议把Native VLAN改成一个不用的VLAN,并且不要在这个VLAN上放任何设备,避免安全问题。
5.3 VLAN间通信为什么需要三层
VLAN隔离了广播域,但也隔离了单播——不同VLAN的设备即使IP在同一网段也ping不通,因为交换机不会把一个VLAN的帧转发到另一个VLAN。要实现VLAN间通信,必须经过三层设备:要么用路由器(单臂路由),要么用三层交换机(SVI接口)。
三层交换机的SVI(交换机虚拟接口)是给每个VLAN配一个IP地址,作为该VLAN的网关。当VLAN 10的设备要访问VLAN 20的设备时,它把帧发给网关MAC(SVI的MAC),三层交换机收到后查路由表,发现目的网段在VLAN 20,就把帧重新封装(源MAC变成VLAN 20 SVI的MAC,目的MAC变成目标设备的MAC)后转发出去。这个过程叫“一次路由,多次交换”——第一个包走慢路径(CPU参与),后续包走快路径(硬件ASIC转发)。
6. 从抓包看二层:几个真实场景的帧分析
6.1 ARP请求与应答的帧结构
ARP请求是一个广播帧,目的MAC是FF:FF:FF:FF:FF:FF,类型字段0x0806。帧的数据部分包含发送方MAC、发送方IP、目的MAC(全0)、目的IP。交换机收到后泛洪到所有端口。目标设备收到后,发现目的IP是自己,就发一个单播ARP应答,目的MAC是请求方的MAC。
这里有个细节:ARP请求帧的源MAC是请求方的MAC,但交换机在转发时不会修改MAC地址。所以你在目标设备上抓包,看到的源MAC就是请求方的MAC,不是交换机的MAC。这也是为什么二层网络里MAC地址可以用于追踪设备物理位置——因为MAC不会被三层设备修改(除非经过路由)。
6.2 ping同网段和跨网段的帧差异
ping同网段设备时,源和目的MAC都是最终设备的MAC,IP也是最终设备的IP。帧在交换机上根据目的MAC转发,不经过路由器。
ping跨网段设备时,源MAC是发送方的MAC,目的MAC是网关的MAC,但源IP和目的IP是最终设备的IP。网关收到后,重新封装帧:源MAC变成网关出接口的MAC,目的MAC变成下一跳的MAC(或者最终目的MAC,如果是最后一跳)。所以你在抓包时会看到MAC地址逐跳变化,但IP地址不变。
这个差异是理解二层和三层分工的关键。交换机只看MAC,路由器只看IP。交换机不关心IP是什么,路由器不关心MAC是什么(除了在封装帧的时候)。
6.3 生成树BPDU帧的识别
BPDU帧的目的MAC是01:80:C2:00:00:00,这是一个多播地址(不是广播),所以交换机不会泛洪到所有端口,而是只发给参与STP计算的端口。类型字段是0x0026(STP)或0x0027(RSTP)。数据部分包含根桥ID、根路径开销、发送桥ID、端口ID、消息年龄、最大年龄、Hello时间、转发延迟等字段。
如果你在抓包时看到大量BPDU帧,说明STP在正常工作。如果STP配置有问题,可能会看到BPDU帧异常增多或者拓扑变更通知(TCN)频繁出现。TCN帧的目的是通知其他交换机MAC地址表需要缩短老化时间(从300秒降到15秒),因为拓扑变了,原来的MAC地址表可能已经不准了。
7. 几个容易踩的坑和实操建议
7.1 MAC地址表溢出攻击与端口安全
交换机的MAC地址表容量是有限的,低端交换机可能只有几千条。如果有人恶意发送大量源MAC不同的帧,MAC地址表会被填满,之后交换机收到正常帧时查不到目的MAC,就会泛洪到所有端口。攻击者就能收到本该发给别人的流量。
防御方法是配置端口安全:限制每个端口能学习的MAC数量,超过就触发保护动作(关闭端口、丢弃帧或发送告警)。我一般建议接入层端口限制为2-3个MAC(一个PC加一个IP电话),超过就关闭端口并记录日志。
7.2 双工不匹配:一个隐蔽的性能杀手
双工不匹配是指链路一端是全双工,另一端是半双工。这种情况下,全双工端会同时收发,半双工端会检测到冲突并重传,导致性能急剧下降(可能只有正常值的十分之一)。更麻烦的是,这种问题不会导致链路完全不通,只是慢,所以很难发现。
我遇到过好几次这种情况:用户抱怨网络慢,但ping延迟正常,只是大流量传输时速度上不去。最后发现是某台老设备强制了半双工,而对端是自协商全双工。解决办法是两端都设为自协商,或者都强制为全双工。千万不要一端自协商一端强制,自协商端会通过并行检测机制 fallback 到半双工。
7.3 交换机堆叠与链路聚合的取舍
堆叠是把多台物理交换机当成一台逻辑交换机来管理,好处是管理简单、跨设备链路聚合方便。链路聚合是把多条物理链路绑成一条逻辑链路,增加带宽和冗余。两者经常一起用:堆叠后做跨设备聚合,既有多台设备的端口密度,又有聚合的带宽和冗余。
但堆叠也有风险:堆叠线缆故障可能导致堆叠分裂,分裂后两台交换机都认为自己是主,IP地址冲突,网络混乱。所以堆叠一般建议用环形拓扑,并且配置双主检测。链路聚合则要注意:聚合的两端必须配置一致(速率、双工、VLAN模式),否则可能聚合失败或者部分链路不转发。
7.4 抓包时如何过滤二层问题
用抓包工具时,我常用的过滤条件是:
ether broadcast:只看广播帧,快速判断广播风暴。ether multicast:看多播帧,判断STP、OSPF等协议是否正常。arp:看ARP请求和应答,判断ARP欺骗或ARP表问题。stp:看BPDU帧,判断生成树拓扑。vlan:看VLAN标签,判断Trunk配置是否正确。
如果你怀疑是二层环路,可以抓包看是否有大量重复的广播帧,源MAC相同但经过不同路径到达。如果怀疑是MAC地址表问题,可以看是否有大量未知单播帧被泛洪。
8. 个人体会:二层是网络的地基,值得花时间吃透
我刚开始做网络运维的时候,总觉得二层太简单——不就是MAC地址转发吗?后来踩的坑多了才发现,大部分“网络时通时不通”“突然变慢”“部分设备上不了网”的问题,根子都在二层。三层路由问题反而好查,因为路由表、ARP表、ping和traceroute都能给出明确线索。二层问题往往没有直接的工具,需要你理解交换机内部在做什么,才能从现象反推原因。
我的建议是:如果你手头有可管理的交换机,花一个下午把STP、VLAN、端口安全、链路聚合这几个功能都配一遍,然后用抓包工具看每种配置下帧的变化。这比看十遍理论都管用。另外,MAC地址表、ARP表、STP拓扑这三个东西要养成定期查看的习惯,很多问题在爆发之前都有征兆——比如MAC地址表里某个端口突然多了几百个MAC,或者STP拓扑频繁变更,这些都是需要立刻关注的信号。
二层网络的设计原则其实很简单:保持拓扑简单,避免环路,控制广播域大小,接入层做好端口安全。但简单不等于容易,因为二层是透明的,出了问题往往要一层层排除才能定位到根因。这份耐心和细致,可能比技术本身更重要。