广播风暴的根源,是一个永远不会“死”的帧
一、问题提出:一条“好心”的冗余链路,放倒了整张网
先看一个真实场景。
某网络原本结构很简单:5 台接入交换机,各自单上联到一台汇聚交换机,汇聚再上联核心。运行多年,相安无事。
后来出于冗余考虑,新增了一台汇聚交换机 B。为了“双保险”,每台接入交换机都改成双上联:一条连原来的汇聚 A,一条连新的汇聚 B。两台汇聚各自单上联到核心。拓扑变成了这样:

割接完成,几分钟后,全网瘫痪:ping 时通时不通,业务全断,交换机管理口卡到登不进去,好不容易登上一台,CPU 100%。
凭直觉判断:环路了。可是问题来了,环在哪? 两台汇聚之间没有连线,汇聚层内部无环;接入交换机彼此也不互联,接入层内部也无环。逐层横着找,哪一层都没环。
症结在于:环路不是某一层、某一台设备的属性,它是一条首尾相接的闭合路径。
任取一台接入交换机出发:
接入 → 汇聚 A → 核心 → 汇聚 B → 回到接入。
一个完美的菱形闭环。5 台接入交换机,就是 5 个这样的菱形,共用“汇聚 A、核心、汇聚 B”这个顶部。
新增汇聚 B 之前,顶部虽然连着,但底部没有会合点,整张网是一棵树;接入一改双上联,底部也接通了,菱形合拢,环路诞生。
那么下一个问题就来了:为什么一条闭合路径,能让整张网在秒级瘫痪? 这才是本文真正要讲的。而所有答案,都藏在一个容易被忽略的事实里:
二层以太网帧没有“寿命”,而交换机对广播帧和查不到表项的帧,默认动作都是泛洪。
前一条决定了循环不会自己停下来,后一条决定了循环会被放大。下面的风暴、MAC 漂移、单播沦陷,以及 STP 为什么只能从几何上破环,都要在这两条之上再叠一层机制才能讲清。
二、先补一个基本功:交换机的 MAC 表是“源学习,目的转发”
要讲清环路,得先讲清交换机平时是怎么干活的。这里有一个非常小、却极其关键的点,很多人记反了。
交换机对每个收到的帧,都会独立地做两个动作:
- 学习。 取帧的源 MAC 加上入端口和所属 VLAN,写入或刷新一条表项:“(VLAN, 这个源 MAC) 在某号端口方向”,并重置该表项的老化计时器(缺省 300 秒)。MAC 表就是这么一条条攒出来的。
- 转发。 取帧的目的 MAC,在同一 VLAN 内决定去向:广播地址(全 F)不查表,直接泛洪;组播地址在没有对应组播转发表项时同样泛洪;单播地址才查 MAC 表,查到就从对应端口精确送出,查不到(未知单播)就从除入端口外、同 VLAN 内的所有端口泛洪出去。
一句口诀记住:源学习,目的转发。
这里有两点要讲清楚。
第一,最常见的误区是以为 MAC 表按“目的 MAC”建立;建表只认源 MAC,目的 MAC 只在转发那一刻用一次。
第二,学习是无条件的:只要帧进来,源 MAC 就被学一次,哪怕这个帧随后因为目的地就在入端口方向而被丢弃,表项照样被刷新。
这两点现在看着不起眼,但它们正是后面“MAC 漂移”的微观真相,先埋个伏笔。
三、环路的本质:两个要素,缺一不可
环路风暴由两个条件叠加产生,缺一不可。

要素一:存在一条物理上闭合的路径
从某台交换机出发,沿着链路走,能不重复地兜一圈回到它自己。这是“环”的几何前提。第一节那个菱形就是典型:本意做冗余的链路,无意间把路径闭合了。
要素二:二层以太网帧头里没有 TTL
这是真正致命的一点。
三层 IP 报文有 TTL(Time To Live,生存时间),每经过一个路由器减 1,减到 0 就被丢弃。所以即使三层路由成了环,报文也会自然消亡,不会无限累积。
但二层以太网帧头里没有任何这样的“寿命”字段。一个帧只要还在链路上,就不会因为“走太久”“绕太多圈”而被丢掉。
两者叠加,灾难就注定了
把这两个要素,和上一节“泛洪”那条规矩合在一起,因果链就闭合了:一个广播帧被泛洪出去 → 它沿着闭合路径绕一圈,从另一个端口又回到了这台交换机 → 交换机一看“这是个广播帧”,忠实地再次泛洪 → 帧再绕一圈回来 → 再泛洪……
因为没有 TTL 让它消亡,这个过程不会自行停止。
这就是环路的本质:一个本该被处理一次就结束的帧,因为“闭合路径 + 无寿命机制”,变成了一台永动机。
四、从“循环”到“风暴”:致命的是放大
如果只是一个帧安静地绕圈,还不至于叫“风暴”。真正让网络崩溃的,是自我复制带来的指数级放大。
放大发生的条件:环路域里存在分叉点
先加一个限定条件,否则结论会被反证。纯粹的单环里(每台交换机在环内只有一个入口和一个出口),广播帧首次泛洪后分成顺、逆两份,之后每台交换机只有一个环内出口,帧数不再翻倍。以太网帧没有 TTL,这两份帧会一直循环下去,每注入一个新广播帧就再多两份。单环里帧数随注入线性累积,最终同样占满链路,但时间尺度慢得多,不是指数增长。
指数放大需要同时满足两个条件:环路域内至少有一台交换机,除入端口外有至少 2 个端口处于转发状态;这些端口复制出的帧中,至少 2 份能沿不同路径回到环内。这样的交换机就是分叉点,帧每经过一次被复制成多份。
回到第一节的菱形拓扑,两个条件都满足:汇聚 A 有 5 个下行口和 1 个上行口,一个从核心方向进来的广播帧在 A 这里被复制成 5 份(泛洪不含入端口),这 5 份分别经 5 台接入交换机上行到汇聚 B,再回到核心、重新进入 A。5 个菱形共用顶部,分叉点密集,实际放大系数远大于 2。
放大有多快:一个量级估算
以千兆链路估算。以太网最小帧 64 字节,加 8 字节前导码和 12 字节帧间隙,线路上占 84 字节即 672 bit,串行化时间 672÷10⁹≈0.67 μs。绕一圈按 4 跳计,每跳存储转发加排队时延按 2~5 μs 估计(企业级交换机的典型量级),一圈耗时 10~25 μs。
按最保守的每圈翻倍算,20 圈后帧数超过百万(2²⁰≈1.05×10⁶),耗时 200~500 μs。但这只是理论上界:千兆链路每秒最多承载约 1.49×10⁶ 个最小帧,一圈时间内单条链路最多通过 15~37 帧,从 1 帧翻倍到这个量级只要 4~6 圈。指数增长在约 40~150 μs 后就因链路饱和、队列丢帧而终止,之后流量维持在线速。
估计:单条链路在百微秒量级被占满,设备表现为全网不可用在秒级。两者口径不同,前者指链路饱和,后者指业务和管理面失效,后者要等上送队列堆积、MAC 表失准、协议报文丢失这些次生效应逐级发作。第一节“割接完成,几分钟后全网瘫痪”里的几分钟,是故障被人察觉并确认的时间,不是风暴形成的时间。
为什么 CPU 会被打爆
带宽被挤满不难理解。但二层转发由转发芯片(ASIC)完成,为什么 CPU 也会到 100%?有四条路径:
- 上送流量激增。 广播帧中相当一部分需要控制面处理,如 ARP 请求、DHCP 报文、各类协议报文,这些帧会进入 CPU 上送队列。
- MAC 表高频改写。 环路使同一源 MAC 在多个端口间反复漂移(MAC flapping),每次表项变动都伴随软件侧同步、老化计时器刷新和告警上报,改写频率足够高时,这部分开销压过正常业务。
- 管理面被挤占。 上送队列占满后,SSH、Telnet、SNMP 报文一同被丢弃,表现为登录不进去。
- 协议报文被挤掉,形成正反馈。 BPDU 和路由协议 Hello 报文同样走上送队列。即便设备通过 CoPP 对 BPDU 做了上送优先级保障,极端风暴下仍可能丢失;一旦 BPDU 丢失或超时,STP 误判拓扑、反复收敛,破环机制被风暴本身破坏。这条最需要警惕:风暴严重到一定程度,STP 会跟着失效。
MAC 漂移:主机没动,表却跳了
主机 H 接在交换机 SW1 的 1 号口上。正常情况下,SW1 的 MAC 表里有一条表项:H 的 MAC 对应 1 号口,发给 H 的帧都从 1 号口送出。
环路出现后,H 发出的广播帧进入环路开始循环。交换机转发不修改源 MAC,因此循环中的每一份拷贝,源 MAC 都是 H 的。
这些拷贝绕环一圈后,会从 SW1 的环路端口(假设是 2 号口)回到 SW1。SW1 无法识别这是绕回来的帧,只按源学习规则处理:源 MAC 为 H 的帧从 2 号口进入,就把表项改写为 H 的 MAC 对应 2 号口。
这条表项与实际不符:H 仍然接在 1 号口上,位置没有变化。但帧在环里持续循环,每从 2 号口进来一次就改写一次,H 的表项在 1 号口和 2 号口之间反复切换。这就是 MAC 漂移,排查时看到的 mac-move / flapping 告警,微观上就是这么来的。源学习不校验帧是否绕环回来,只认入端口,所以在闭合路径下这种改写不可避免。

单播沦陷:连“定向”的特权也没了
正常情况下,泛洪只发生在三类帧上:广播帧、没有组播转发表项的组播帧、目的 MAC 查不到的未知单播帧。已知单播查表命中后定向送出一个端口,不进环路,因此不参与放大。这条豁免完全依赖 MAC 表的准确性。
MAC 表被漂移搅乱后,豁免失效,分两条路径。一是查不到表:STP 拓扑变更(TC,Topology Change)触发 MAC 表快速老化,老化时间从缺省 300 秒临时缩短到 Forward Delay(缺省 15 秒),RSTP/MSTP 则直接清空相关端口上学到的表项;风暴下学习和改写频率超出芯片处理能力,部分表项也建不起来。两种情况查表都落空,帧按未知单播泛洪。二是查得到但表项指向环路端口,交换机严格按表执行,把本该点对点的单播准确地送进了环里。
需要区分的是,第一条路径里的老化是 TC 触发的快速老化,不是常规老化:环里持续有 H 的源 MAC 帧在刷新表项,常规老化根本轮不到。
前者走泛洪路径,后者走定向路径,结果都是单播加入放大。泛洪引擎的输入范围,就此从广播和组播扩大到几乎所有帧。
五、破环:先看全部手段,再看 STP 为什么是默认选项
病因清楚了,再看对策。回看环路的两个要素:
- 要素二(帧没有 TTL)是协议设计层面的硬伤,改不了。 以太网帧格式是定死的,没有任何机制能给存量的二层世界加上寿命字段。
- 所以所有工程手段都作用在要素一:不让路径闭合,或者闭合了也别让它循环起来。
可用手段有五类
工程上常见的手段有以下五类,作用层次不同,不是互斥关系:
| 手段 | 作用机制 | 是否真正破环 |
|---|---|---|
| 生成树协议(STP / RSTP / MSTP) | 逻辑上阻塞冗余端口,把拓扑修剪成树 | 是,主动破环 |
| 环路检测协议(H3C / 华为 loopback-detection,锐捷 RLDP) | 周期性发探测帧,收到自己发出的帧即判定成环,阻塞或关闭该端口 | 是,被动检测后破环 |
| 堆叠 / M-LAG | 把两台汇聚虚拟成一台,双上联收敛为逻辑单上联,拓扑本身无环 | 是,从拓扑上消除环 |
| 三层到边缘 | 缩小二层广播域,把环路影响范围限制在单个接入层 | 部分,缩小爆炸半径 |
| 风暴抑制(storm-control) | 对广播、组播、未知单播设速率或比例阈值,超限丢弃 | 否,只限损不破环 |
要点:风暴抑制不是破环手段。 它能在环路发生时保住一部分带宽和 CPU,让设备还能登录进去排查,但环依然存在,业务依然不通。把 storm-control 当破环方案配上就以为安全,是常见误判。
在本文这个菱形拓扑里,如果两台汇聚支持 M-LAG,它是比 STP 更优的选择:两条上联同时转发,带宽利用率翻倍,且没有生成树收敛过程。选 STP 的场景通常是设备不支持 M-LAG、跨厂商互联、或存量网络不便改造。下面聚焦 STP。
STP 做的事:从几何上掐断跑道
生成树协议(STP,Spanning Tree Protocol;及其演进版 RSTP、MSTP)的思路很纯粹:在每个环里,逻辑上阻塞掉一个端口,让它进入 Discarding(丢弃)状态,接收并处理协议报文 BPDU(Bridge Protocol Data Unit,桥协议数据单元),但不转发业务数据、不学习 MAC。路径不再闭合,帧绕到那个被阻塞的口就过不去了,永动机失去了跑道。
它是从几何上破环的。物理线还在,阻塞口随时可以在主链路故障时顶上来,这就是冗余的意义;但逻辑拓扑被修剪成了一棵无环的树,“生成树”因此得名。
放回第一节的菱形拓扑:STP 跑起来之后,每台接入交换机的两条上联里,会有一条被自动阻塞,另一条正常转发。阻塞口的数量恰好等于第一节算出来的独立环路数 5。主用上联一断,阻塞口秒级接管。
单实例下的一个副作用:汇聚 B 近乎全闲置
这里有一个容易被忽略的后果,它决定了 RSTP 和 MSTP 之间怎么选。
假设核心为根桥,汇聚 A 优先级次低。5 台接入到根桥的两条路径开销相同,选举时按“指定桥 BID 更小者优先”比较,结果是5 台接入全部选择经汇聚 A 上行,5 个阻塞口全部落在朝向汇聚 B 的上联上。
也就是说,在单生成树实例(RSTP)下,汇聚 B 的下行链路全部不转发业务,它退化成一台纯备份设备。这不是配置错误,是单实例生成树的固有结果:全网只有一棵树,所有 VLAN 共用同一套阻塞口。
要摆脱这个限制,需要 MSTP(Multiple Spanning Tree Protocol,多生成树协议):把 VLAN 分组映射到不同实例,每个实例算一棵树,让不同实例的阻塞口落在不同汇聚上,两台汇聚各承担一部分流量。 这也是实网中很少直接用 RSTP 收尾的原因:环破了,但一半的汇聚设备闲着。
一个常见的认知误区:root 与破环
很多人配 STP 时,脑子里把“设核心为根桥(root)”和“破环”划上了等号,以为是核心当了根,才把环破开的。
请记住这句话:
让核心当 root 解决的是生成树长什么形状、阻塞口落在哪的问题,不解决“能不能破环”的问题。不设 root 也能破环,只是树可能长歪;所以设 root 是为了让树长得合理,它不是破环的前提。
因果顺序是反的:STP 一旦在全网正常跑起来,环就破了(前提是每台设备都正常参与、BPDU 收发正常)。谁当 root,只决定这棵树长成什么样、那个被牺牲的阻塞口落在谁身上。
一个反例,把这件事说清
设想这样一个翻车现场:某网工配好了 STP,网络确实不风暴了,但业务时快时慢。一查,root 跑到了一台接入交换机上。生成树以它为中心展开,核心到其中一台汇聚的主干链路被阻塞,去往这台汇聚的流量只能绕经那台接入交换机,由一条接入级上联口承载本该走主干的流量。
环,破了;树,长歪了。
为什么 root 会跑到接入交换机上?因为默认所有设备的桥优先级都是 32768,根桥靠比较 MAC 地址大小产生,结果完全不可控。这就是为什么实战中要显式指定根桥:目的是让那个不可避免的阻塞口,落在我们希望它落的地方。
需要补一句:光设优先级还不够。 后来接入网络的任何一台设备,只要桥优先级更低(比如某人私接了一台默认优先级为 0 的旧交换机),照样能把根抢走。防住这一点需要在核心的下行口配根保护(root-guard):端口一旦收到优先级更高的 BPDU,就被置为 Discarding,直到这类 BPDU 停止出现为止,根因此锁在核心上。
六、结语:一切都回到那个没有 TTL 的帧
从一次真实的瘫痪走到一组破环手段的取舍,全文只讲了一件事:环路风暴的根源,是一个没有寿命的帧,在一条闭合的路径里,被交换机忠实地无限复制。
把因果链再收一遍:
- 二层帧头没有 TTL,帧不会自己消亡,这是前提。
- 交换机对广播、无组播转发表项的组播、未知单播的默认动作是泛洪,这是循环得以持续的机制。
- 环路域里存在分叉点时,泛洪把循环变成指数放大,这是从“循环”升级为“风暴”的条件。
- “源学习”按入端口改写表项,使 MAC 表与主机实际位置不符(MAC 漂移);“目的转发”再依据这张失准的表,把单播也送进环路或降级为泛洪。带宽、CPU、MAC 表、BPDU 四者正反馈,秒级瘫痪。
- TTL 这个硬伤改不了,所以所有对策都作用在闭合路径上:STP 逻辑阻塞、环路检测被动阻断、M-LAG 从拓扑上消环、三层到边缘缩小范围。风暴抑制只限损,不破环。
- root 决定树长成什么样,不决定能不能破环;显式设优先级要配合根保护才守得住。
- STP 破环依赖 BPDU 正常收发,而风暴本身会挤掉 BPDU。storm-control 虽然不破环,但它保住的那部分上送队列,恰恰是 STP 还能继续工作的条件。
理解了那个不会消亡的帧,环路就从一个需要背下来的故障类型,变成一个可以推导出来的结果。