STP二层防环:根桥选举、RSTP/MSTP选型与保护配置

发布时间:2026/10/26 4:54:37
STP二层防环:根桥选举、RSTP/MSTP选型与保护配置

1. 二层环路为什么必须由 STP 来管

1.1 一条网线接成环之后到底发生了什么

生成树协议(Spanning Tree Protocol,STP)是二层网络里最古老、也最容易被忽视的一套机制。很多人一开始接触它,是在 ENCOR 官方认证指南的第二章,翻两页觉得"不就是防环吗",然后跳过;等到某天机房里的交换机指示灯疯狂闪烁、业务全线卡死,才会回头发现这一章有多值钱。我在实际项目里见过太多次,一个看似人畜无害的"备用链路",因为没管住二层环路,三分钟内把整栋楼的网络拖进泥潭。

想理解 STP,先把二层转发的规则吃透。二层交换机做转发时不看 IP,它只做一件事:收到一个帧,把源 MAC 记到"从哪个口进来的"这个表项里,再查目标 MAC 在不在表里,在就从对应口出去,不在就泛洪到除了入口之外的所有端口。注意最后那半句话,它是环路的根源。三次转发规则叠在一起:泛洪、源 MAC 学习、老化时间默认 300 秒,就构成了一个自激放大的系统。

想象一个最经典的最小环路:两台交换机之间接了两根线。主机 A 发出一个广播帧,交换机 1 从 g0/1 收到,泛洪到 g0/2 和所有接入口;交换机 2 从自己的 g0/1 收到这个帧,再泛洪回它的 g0/2,于是又一个副本回到交换机 1,交换机 1 再泛洪……帧在两个口之间来回弹,每弹一次就复制一份。这不需要任何攻击者,也不需要配置错什么高级特性,只要物理上有个闭环,它自己就会滚起来。这就是为什么 STP 的定位不是"优化功能",而是二层的安全带,没有它,网络规模一大就必然出事。

1.2 广播风暴、MAC 表震荡、重复帧的三重打击

环路带来的破坏不是单一症状,而是三个问题同时爆发。第一个也是最直观的是广播风暴:广播帧、未知单播帧、组播帧在环里无限复制,链路带宽在几秒内被吃满,交换机的 CPU 因为要不断处理中断和复制帧直接飙到 100%,最后连管理面都进不去。这时候你去 ping 网关,超时;去 SSH 交换机,超时;唯一能做的就是跑到机房拔线,这就是所谓的"物理救火"。

第二个问题是MAC 地址表震荡。同一个源 MAC 会在环的不同端口上反复出现,交换机不停地"这个 MAC 在 g0/1……不对,在 g0/2……不对,又在 g0/1",表项内容被每秒刷写成百上千次。这带来的直接后果是转发面彻底混乱:本来应该从 A 口出去的帧从 B 口出去了,单播开始被当成未知单播泛洪,等于把单播的带宽优势也废掉了。而且 MAC 表本身是有容量上限的,震荡加上泛洪学习,很容易把表打满,之后的行为就是大面积泛洪,进一步加剧风暴。

第三个问题最隐蔽,叫重复帧。同一个帧被复制成多份送到目的主机,TCP 层会认为是重传、乱序,触发大量的重传和拥塞窗口收缩,表现出来就是"网络能通,但是慢得离谱""打开一个网页转圈半天"。有些应用层协议还会因为收到重复请求产生业务副作用,比如重复下单、重复扣款。这三种症状往往叠加出现,所以排查时你会看到"时通时断""丢包 30%""延迟忽高忽低"这种没有明显规律的现象,很容易被误判成线路质量或者运营商问题。

提示:看到交换机所有端口指示灯同步、高频闪烁,且业务全断,优先怀疑二层环路,不要先去查路由和防火墙。

1.3 为什么不靠三层或者加带宽来解决

有人会问,既然环路是二层的事,那我全用三层路由不就行了?理论上可以,但现实里做不到。接入层的 VLAN 划分、无线 AP 的 PoE 供电、虚拟机迁移要求的大二层、监控摄像头的组网,这些都强依赖二层域。而且三层路由本身也有环路防护(TTL 逐跳递减),二层帧没有 TTL 字段,一个帧只要不被丢弃就能永远活下去,这就是二层必须有一套独立的、基于逻辑阻塞的防环机制的根本原因。

加带宽、换更好的交换机同样解决不了。环路是逻辑拓扑问题,不是性能问题,你给的带宽越大,风暴滚起来吃满的速度越快。真正有效的做法只有一条:在逻辑上把环形拓扑剪成一棵无环的树,让每条链路上"该通的通,该堵的堵",同时保留物理冗余——一旦主链路断开,被堵的那条自动放开。这正是 STP 干的事:它把物理上的网图,算出一棵逻辑上的树,被剪掉的端口进入阻塞状态,只保留备用身份。

这套思路的好处和维护成本值得说清楚。优势是零配置也能跑(所有交换机出厂都默认开启 STP,虽然不同平台默认的版本不一定一样),而且它是分布式的,不需要控制器,每台设备靠交换 BPDU 报文自己算。代价是收敛慢、拓扑变化时会有短暂中断、而且所有流量都被强行压到一棵树上,没法做链路负载均衡——这三点,恰恰是后面 RSTP 和 MSTP 要解决的问题。

2. STP 的版本谱系与选型思路

2.1 从 802.1D 到 RSTP 再到 MSTP 的演进逻辑

最早的 STP 是 IEEE 802.1D 标准,也叫 CST(Common Spanning Tree),整个网络只有一棵树,所有 VLAN 共用。它的问题很直接:收敛慢。一个链路故障,要靠 Max Age(默认 20 秒)超时才能发现,然后经历 Listening(15 秒)、Learning(15 秒)才进入 Forwarding,最坏情况要 50 秒业务才恢复。50 秒对文件传输无所谓,对语音、视频、数据库连接就是灾难,TCP 早就断了。

后来出现了几个厂商私有的加速特性,比如 UplinkFast(优化接入层上行切换)、BackboneFast(优化骨干链路间接故障检测),还有每个 VLAN 一棵树的 Per-VLAN 实现。私有的东西跨厂商就不好使,于是 IEEE 出了 802.1w,也就是 RSTP(Rapid Spanning Tree Protocol)。RSTP 的核心改动是把"等超时"换成"主动协商":端口之间通过 Proposal/Agreement 握手,直接把端口推到转发状态,收敛从几十秒压到秒级甚至亚秒级。同时它把端口状态从五个精简成三个(Discarding、Learning、Forwarding),并引入了边缘端口的概念,接终端的口不再参与计算。RSTP 向下兼容 802.1D,同一网络里两种设备可以共存,只是快速收敛的优势会被老设备拖累。

再往后是 802.1s,也就是 MSTP(Multiple Spanning Tree Protocol)。它解决的是"一个 VLAN 一棵树"带来的资源浪费问题:PVST+ 在 100 个 VLAN 的环境里要维护 100 棵独立的树,每棵都要跑 BPDU、都要算,CPU 和带宽开销都上去了,而且阻塞端口互相独立,链路的利用率依然很低。MSTP 的做法是把多个 VLAN 映射到少数几个实例(Instance)上,每个实例一棵树,不同实例可以让不同的链路处于转发状态,从而实现按 VLAN 组做负载分担。实际项目里常见的配置是两个实例,VLAN 10-20 走左侧上行,VLAN 30-40 走右侧上行,两边互为备份。

2.2 PVST+ 与 MSTP 的取舍

选型没有一个放之四海皆准的答案,要看网络规模和运维习惯。PVST+ 的优势是"简单直观":每个 VLAN 独立,配置一条spanning-tree vlan 10 priority 4096就能精确控制某一组业务的走向,排错时show spanning-tree vlan 10一敲结果一目了然,而且跨厂商兼容性相对好(PVST+ 的 BPDU 走的是 802.1Q 的组播地址,跟标准 MSTP 能互通)。它的问题在于规模。接入层几十台交换机、几百个 VLAN 的时候,每台设备要为每个 VLAN 维护一套状态机,BPDU 数量线性增长,CPU 占用和收敛时间都会恶化。

MSTP 的优势是"省",劣势是"区域一致性要求苛刻"。MSTP 的交换机必须属于某个区域(Region),区域由三个要素唯一确定:区域名、修订号(Revision)、VLAN 到实例的映射关系。这三项必须完全一致,差一个字符,两台设备就分属不同区域,边界上的行为会退化成 CST,你精心设计的实例负载分担直接失效,严重的还会绕出次优路径。我在一个园区网改造项目里就吃过这个亏:一边写的是region-01,另一边写的是region01,少了个中划线,花了大半天才定位到。

对比维度802.1D (CST)PVST+ / Rapid-PVST+MSTP (802.1s)
每 VLAN 一棵树否,全局一棵是否,按实例
典型收敛时间30-50 秒1-3 秒(Rapid 模式)1-3 秒
负载分担能力无强,逐 VLAN 精确控制中,按实例分组
大规模适用性差中等(VLAN 多时开销大)好
跨厂商互通好一般好(标准)
配置复杂度低中高(区域一致性)

我的经验是:接入层设备数量在 30 台以内、VLAN 数量不超过 50 个的办公网,Rapid-PVST 完全够用,好维护、好排错;超过这个量级,尤其是多栋楼、多个厂区的园区网,直接上 MSTP,用两到四个实例把业务分级,前期多花两小时规划,后期省无数麻烦。

2.3 版本共存的坑

混合部署是绕不开的现实。老设备只支持 802.1D,新设备跑 RSTP,两者对接时 RSTP 会自动降级,用 802.1D 的规则跟它协商,快速收敛的好处就没了。更麻烦的是 PVST+ 与 MSTP 对接:MSTP 设备在收到 PVST+ 的 BPDU 时,会把对应 VLAN 当成独立的实例来处理,这可能让原本设计的树结构发生变化。

实操建议是:统一版本,并在边界处做好隔离。如果确实要混跑,先把老设备的位置摸清楚,把它们放在网络边缘,核心和汇聚全部统一成同一个版本和同一种模式。切换之前先在实验环境验证一遍,尤其是根桥位置、阻塞端口的分布,跟预期对不对得上。不要在没有维护窗口的情况下直接改模式,因为改模式会触发整个二层重新收敛,中间有几秒的断网。

3. 根桥选举与端口角色:STP 的大脑

3.1 BPDU 报文字段与优先级向量比较

STP 的所有决策都靠一种叫 BPDU(Bridge Protocol Data Unit)的报文完成。默认每 2 秒(Hello Time)从指定端口发一次,目的组播地址是固定的,交换机收到后不做转发,只做解析。理解 BPDU 的字段,是理解 STP 全部行为的钥匙。关键字段有这么几个:根桥 ID(Root Bridge ID)、根路径开销(Root Path Cost)、发送者桥 ID(Sender Bridge ID)、发送者端口 ID(Port ID)、消息年龄(Message Age)、最大年龄(Max Age)、Hello 时间、转发延迟(Forward Delay)。

比较顺序是死的,从上到下逐级比,谁小谁赢:先比根桥 ID,再比根路径开销,再比发送者桥 ID,最后比发送者端口 ID。这个顺序必须记牢,因为排错时 90% 的"为什么根端口选错了"都是因为某一级的比较结果跟你预期不一样。桥 ID 是 8 字节,前 2 字节是优先级(默认 32768,只能是 4096 的整数倍),后 6 字节是设备的 MAC 地址。所以即使所有人都不配优先级,也有一个 MAC 地址最小的设备自动当选根桥——这就是为什么在没规划的网络里,根桥经常是那台最老、最边缘、性能最差的交换机,因为它出厂早,MAC 地址小。

路径开销是按带宽折算的,值越小越好。用长整型(Long)计算时:10Mbps=100,100Mbps=19,1Gbps=4,10Gbps=2。用短整型(Short)计算时:10Mbps=100,100Mbps=19,1Gbps=4,10Gbps=1。这个区别在混合千兆和万兆链路的网络里会直接影响选路结果,规划时最好全网络统一一种算法。另外要注意,开销是有方向的,累加的是"从本端到根桥"沿途所有接收端口的开销之和,跟发送方向无关。

3.2 根桥、根端口、指定端口、阻塞端口怎么定

整个选举过程可以拆成三步,按顺序执行,不能跳。

第一步,选根桥。全网所有交换机互相发 BPDU,谁发的 BPDU 里根桥 ID 最小,谁就是根桥。根桥上的所有端口都是指定端口,全部转发。这一步决定了整棵树的"圆心"。

第二步,选根端口(Root Port)。每台非根桥设备都要选出一个"离根桥最近"的端口,作为自己的上行口。判定的依据就是上面那个比较顺序:收到的 BPDU 里根路径开销最小的那个端口就是根端口;开销相同就比发送者桥 ID,再相同就比端口 ID。每台非根交换机有且只有一个根端口,它一定是转发状态。

第三步,选指定端口(Designated Port)。每条网段上都要选出一个端口负责往这个网段转发,判定依据是这条链路上谁发的 BPDU 更优。剩下的既不是根端口、也不是指定端口的,就是阻塞端口(在 RSTP 里叫 Alternate 或 Backup),它只收 BPDU 不发数据。

还有第四种角色容易被忽略:禁用端口。这是管理员手工 shutdown 或者被保护机制 err-disable 掉的端口,不参与计算。排错时如果发现某个端口既不是 Root 也不是 Designated 也不是 Alternate,先看看它是不是被关掉了。

理解这套角色分配的价值在于:你能预测出网络里每根线、每个口的状态,从而做出符合业务需求的设计。比如你希望核心的双上行里,左边走业务 A、右边走业务 B,那就必须在 VLAN 层面把根桥优先级调成不同的值,让不同 VLAN 算出不同的树。凭空猜是猜不出来的,必须动优先级。

3.3 根桥摆放与路径开销的实操设计

根桥放在哪,直接决定了全网流量的走向。默认不配的话,根桥由 MAC 地址决定,你完全无法控制,后果通常是:大部分流量要绕到某台边缘交换机再回来,核心之间的万兆链路反而闲置,形成"骨干空跑、边缘拥堵"的怪现象。

正确的做法是手工指定根桥,并且成对做备份。核心的两台设备,一台配成主根,一台配成备根。命令上有个小技巧:用root primary和root secondary比手工写优先级更省心,前者会把优先级设成 24576(如果当前根桥优先级比 24576 还低,则设成比它低 4096),后者固定设成 28672。这样做的逻辑是:主根优先级必须明显低于其他所有设备,"明显"的意义在于留出余量,避免以后新加设备时不小心被抢走根桥;同时主备之间差 4096,保证主设备故障后备设备能顺利接位。

! 核心交换机 A —— 主根 spanning-tree vlan 10,20,30 root primary spanning-tree vlan 40,50 root secondary ! 核心交换机 B —— 备根,VLAN 分组互换实现负载分担 spanning-tree vlan 10,20,30 root secondary spanning-tree vlan 40,50 root primary

如果不用root primary,手工写也可以,但一定要记住优先级必须是 4096 的倍数,写个 100 上去设备会直接报错或者自动取整,行为就不受控了:

spanning-tree vlan 10 priority 4096

配置完之后一定要验证,不能只看配置回显。用show spanning-tree root看每台设备认为的根桥是谁,用show spanning-tree vlan 10看根端口和阻塞端口是不是落在了你期望的接口上。我见过配置写对了但没生效的情况,原因是环路上的某台设备还在跑 802.1D,或者某条链路的 BPDU 在传输设备上被过滤掉了,这时候配置看起来完美,实际拓扑跟设计完全不搭。

注意:接入层设备永远不要配成根桥。一旦接入交换机成了根,所有跨 VLAN 的流量都要往接入层绕一圈,延迟和带宽都会出问题。用root guard在下行口做防护,能挡住这类误配置和恶意抢根。

4. 端口状态机与收敛过程

4.1 802.1D 的五个状态与三十到五十秒是怎么来的

老 STP 的收敛慢,不是因为它算法笨,而是因为它不敢快。二层转发一旦出错就是环路,所以它采取的策略是"宁可慢,不能错"。这体现在端口状态机的设计上,五个状态各有明确的作用:

状态收 BPDU学 MAC转发数据持续时间
Disabled否否否手工关闭
Blocking是否否Max Age (20s)
Listening是否否Forward Delay (15s)
Learning是是否Forward Delay (15s)
Forwarding是是是稳定状态

关键就在 Listening 和 Learning 各 15 秒的等待。Listening 阶段设备在听 BPDU,确认自己在拓扑里的角色,但绝对不学 MAC,因为一旦学了 MAC 又发生拓扑变化,就会留下错误的表项;Learning 阶段开始学 MAC 但不转发,目的是在真正转发之前把地址表先"预热"一遍,减少首次泛洪。两个 15 秒加上故障检测的 20 秒 Max Age,总共 50 秒,这就是那个经典数字的由来。

这套设计的价值在于稳,代价是慢。有人会想到调小 Forward Delay 和 Max Age 来加速,我必须提醒:这个念头非常危险。按照规范,Forward Delay 应该是"Hello Time + 1"再乘以网络直径的关系,Max Age 应该是 Hello Time 的若干倍,随便调小会导致在大型网络里 BPDU 还没传完一圈,设备就以为超时了,反而制造出临时环路。真要加速,换 RSTP,不要动 802.1D 的定时器。

4.2 RSTP 的三种状态与 Proposal/Agreement 握手

RSTP 把五个状态砍成三个:Discarding(丢弃,合并了 Disabled、Blocking、Listening)、Learning、Forwarding。这不是换汤不换药,真正的改变是引入了主动握手。新链路上,两端的端口一开始都处于 Discarding/Designated 状态,上游设备发送一个带 Proposal 标志的 BPDU,表示"我建议你立刻成为根端口";下游设备收到后,先把自己所有其他端口同步到 Discarding(这一步很关键,本质上是把非边缘端口先"关掉",防止握手期间形成临时环路),确认没有环路风险后回一个带 Agreement 标志的 BPDU。上游收到 Agreement,立刻把端口推到 Forwarding。

整个过程只依赖于一次 RTT 级别的报文交互,不需要等任何超时,所以收敛是毫秒到秒级。这个"先同步其他端口再放开"的设计,跟 802.1D 靠时间熬是完全不同的思路:前者靠信息,后者靠猜。类比一下,老 STP 像是两个人约见面,不知道对方什么时候到,只能掐着表等半小时;RSTP 像是打个电话确认"你现在就出发",立刻就能会合。

另外 RSTP 还有一种叫Proposal 传播的机制,在链式拓扑下,握手可以像多米诺骨牌一样从根桥一路传到最末端的接入交换机,一次收敛覆盖整条链。这个特性让 RSTP 在树形结构下的收敛表现非常优秀。但要注意,只有点到点全双工链路才能做握手,半双工链路或者通过 Hub 连接的多点链路,RSTP 会退回类似 802.1D 的行为。所以现在还在用半双工的地方,先在接口上确认一下双工状态。

4.3 边缘端口与链路类型

RSTP 里最实用也最容易被滥用的就是边缘端口(Edge Port)。它的语义是:这个口接的是终端设备,不可能产生环路,所以它跳过所有协商,一插上就进入 Forwarding。这一下子解决了接入层最大的痛点——电脑开机、网络唤醒、桌面打印机上线,不用再也等 30 秒。

interface GigabitEthernet1/0/10 spanning-tree portfast

但这个优化的前提必须成立,否则就是给自己挖坑。如果边缘端口接的不是电脑而是一台交换机、一个无线 AP 的桥接口、一台虚拟化主机的软交换机、一个监控摄像头的自带交换模块,那么它一旦收到 BPDU,就可能把整个二层搅乱。所以边缘端口的正确姿势是永远和 BPDU Guard 配对使用,而不是单独存在。

链路类型(Link Type)这个概念在 RSTP 里也很重要,分 Shared 和 Point-to-Point 两种。全双工接口默认是 Point-to-Point,可以跑快速握手;接 Hub 或者半双工的接口要手工配成 Shared,否则设备会误判为点对点,握手行为就会异常。现在 Hub 基本绝迹了,但在一些工业现场、老旧产线上还能见到,碰到奇怪的收敛问题,先查一下接口的双工模式。

interface GigabitEthernet1/0/24 spanning-tree link-type shared

我在一个工控网络里碰到过这种情况:几台 PLC 通过一个工业交换模块串起来,RSTP 一直不稳定,日志里反复出现拓扑变更。查了三天,最后发现是那个模块的端口协商成了半双工,但 STP 还认为是点对点,握手报文丢失导致反复重算。改成 Shared 之后彻底安静了。这种问题没有任何文档会告诉你,只能靠现场观察和日志比对。

5. 拓扑变更与保护机制

5.1 TCN 与 TC 机制:Mac 表为什么要被缩短

拓扑变化处理是 STP 里最容易被忽略、却最容易引发"间歇性变慢"的部分。先说 802.1D 的机制。当一台非根桥发现有端口状态变化(比如根端口挂了、新端口进入 Forwarding),它会从自己的根端口向上游发送 TCN BPDU(Topology Change Notification)。上游设备收到后,会继续向自己的根端口传,一直传到根桥。根桥收到后,回一个带 TCA(Topology Change Acknowledgment)标志的配置 BPDU,然后在一段时间内(默认是 Forward Delay + Max Age,也就是约 35 秒)把自己所有 BPDU 里的 TC 标志置位,全网设备看到 TC 标志,就把 MAC 地址表老化时间从默认的 300 秒临时缩短到 Forward Delay 的 15 秒。

为什么要缩短?因为拓扑变了,原来学到的一些 MAC 地址对应的端口可能已经不对了,如果还按 300 秒慢慢老化,这段时间里流量会走错路、被丢弃。缩短老化时间等于"强制大家快点忘记旧信息,重新学"。代价是这 15 到 35 秒内,全网会有大量未知单播被泛洪,带宽和 CPU 都会抖一下。

RSTP 的机制更激进也更合理:它不再需要 TCN 逐跳上报,而是直接泛洪 TC 报文,收到 TC 的交换机立刻把除边缘端口外的所有端口 MAC 表中的动态表项清除(不是缩短老化,是直接清)。这样收敛更快,但代价是拓扑变化瞬间会有一次大范围泛洪。所以 RSTP 里"避免不必要的拓扑变化"变得更加重要——边缘端口要配好,下行端口要开 BPDU Guard,否则一台设备反复上下线就会让整个网络反复清表。

提示:show spanning-tree detail里的 "Number of topology changes" 和 "Last change occurred" 是排查抖动的重要指标。正常网络的拓扑变化次数应该是个位数,如果几千上万,说明下面有东西在反复撩拨 STP。

5.2 PortFast、BPDU Guard、BPDU Filter 三兄弟怎么配

这三个特性经常被混为一谈,但作用完全不同,配错了就是灾难。

PortFast的作用是让端口跳过 Listening 和 Learning 直接转发,只该用在接终端的接入端口上。它的风险是:如果这个口下面接了一台交换机,那台交换机启动期间 STP 完全收不到对方的 BPDU,会认为自己是唯一设备,直接转发,等对方起来时环路早就形成了。

BPDU Guard是 PortFast 的保险。它在配了 PortFast 的端口上监听 BPDU,一旦收到就立刻把端口 err-disable 掉。逻辑是:这条链路本来就是给终端的,终端不可能发 BPDU,所以你发了 BPDU 就说明有问题,我宁可断掉也不能冒环路的险。默认情况下端口被 err-disable 后不会自动恢复,必须手工shutdown再no shutdown,或者配置errdisable recovery cause bpduguard加上恢复时间。

BPDU Filter的行为最微妙。在全局配spanning-tree portfast bpdufilter default时,它的作用是"边缘端口既不发也不收 BPDU",相当于让这个端口彻底脱离 STP 的视野。局部在接口上配spanning-tree bpdufilter enable则是无条件丢弃 BPDU。这个特性用错地方会造成非常隐蔽的故障:如果配置在一个本来应该参与 STP 的端口上,它会把上游的 BPDU 全吃掉,本端设备以为自己就是根桥,直接进入转发,环路就这么形成了。

我的建议很明确:接入层端口统一开启 PortFast + BPDU Guard,BPDU Filter 原则上不用。BPDU Filter 唯一的合理场景是连接某些会发送 BPDU 的第三方设备(某些 IP 电话、无线控制器),而你又必须让它接入,这时要非常清楚自己在做什么,并且做好记录。

! 全局启用:对所有边缘端口生效 spanning-tree portfast default spanning-tree portfast bpduguard default ! 单个接口精细化控制 interface range GigabitEthernet1/0/1 - 24 spanning-tree portfast spanning-tree bpduguard enable ! 端口被 err-disable 后的恢复 errdisable recovery cause bpduguard errdisable recovery interval 300

5.3 Root Guard、Loop Guard 与单向链路

这一组是"防单向故障"的。Root Guard配在指定端口上(通常是从核心指向下级的端口),作用是禁止这个端口收到更优的 BPDU。如果下游设备不听话配了个优先级 0 想抢根桥,Root Guard 会把这个端口置为 root-inconsistent 状态,不转发数据,从而保住核心的根桥地位。它的价值在于把"配置错误"隔离在局部,而不是让全网跟着绕路。

Loop Guard解决的是更阴险的问题:单向链路。光纤一头断了、光模块只发送不接收、中间传输设备把 BPDU 丢了,都会造成这种情况。本端设备收不到 BPDU,按照 Blocking 端口的超时规则(Max Age 20 秒),它会认为"对方消失了,这条链路可以用",于是把阻塞端口放开进入转发。但对方的发送方向还是好的,数据发过去、对方转回来,环路瞬间形成。Loop Guard 的做法是:如果阻塞端口在应该收到 BPDU 的时候没收到,就把它置为 loop-inconsistent,不允许它进入转发。这个特性在光纤环境里几乎是必配的。

UDLD(单向链路检测)是配合 Loop Guard 的另一个机制,工作在更底层,能直接检测出物理层的单向故障。它和 Loop Guard 的区别是:Loop Guard 防的是"逻辑上收不到 BPDU",UDLD 防的是"物理上只通一个方向"。两者建议都开,UDLD 用 aggressive 模式,能在几十秒内发现并 err-disable 端口。

特性配置位置防御目标触发后状态
BPDU Guard接终端的边缘端口误接交换机、发 BPDU 的设备err-disable
Root Guard指向下游的指定端口下游设备抢根桥root-inconsistent
Loop Guard根端口/备根端口单向链路导致的 BPDU 丢失loop-inconsistent
UDLD光纤、跨传输链路物理层单向故障err-disable

6. 实操配置与验证清单

6.1 一套可以直接抄的接入层模板

我现在的习惯是给接入交换机做一份标准模板,新设备上线直接套,省得每次现编。核心思路:模式统一、根桥规划好、接入端口全开 PortFast 加 BPDU Guard、上行端口加 Root Guard 和 Loop Guard、关闭不需要的边缘特性减少攻击面。

! 1. 统一 STP 模式(先确认当前模式,避免意外重启收敛) spanning-tree mode rapid-pvst ! 2. 全局默认开启边缘端口与 BPDU 防护 spanning-tree portfast default spanning-tree portfast bpduguard default ! 3. 全局路径开销算法与端口优先级保持默认,不做无谓修改 ! 默认长整型开销,端口优先级 128 ! 4. 上行端口模板 interface range GigabitEthernet1/0/49 - 50 spanning-tree portfast disable spanning-tree guard root spanning-tree guard loop spanning-tree link-type point-to-point ! 5. 确认端口优先级和开销 show spanning-tree interface GigabitEthernet1/0/49 detail

这里有个细节我想特别强调:spanning-tree portfast default只对接入模式(Access)的端口生效,Trunk 端口不受影响。这一点救过很多人,但也害过很多人——如果你把接 IP 电话的端口配成了 Trunk(带语音 VLAN 的常见做法),PortFast 全局配置是不会生效的,你还需要手工加一句。很多人以为配了全局就万事大吉,结果电话重启要等 30 秒,找不到原因。

6.2 MSTP 实例规划与配置

MSTP 的配置顺序有讲究:先配区域,再配实例优先级,最后验证。区域配置必须在全局配置模式下进spanning-tree mst configuration子模式,name和revision全网必须一模一样,instance映射的 VLAN 范围不能重叠。

! 所有交换机上执行相同的区域配置 spanning-tree mode mst spanning-tree mst configuration name CAMPUS-CORE revision 10 instance 1 vlan 10-29 instance 2 vlan 30-49 exit ! 主根:实例 1 主、实例 2 备 spanning-tree mst 1 priority 4096 spanning-tree mst 2 priority 8192 ! 备根:实例 1 备、实例 2 主 spanning-tree mst 1 priority 8192 spanning-tree mst 2 priority 4096

关于实例划分,我的经验是不要划太多。见过有人给每个 VLAN 单独开一个实例,觉得这样负载分担最灵活,结果是配置量爆炸、维护成本剧增,而且实例数量和硬件资源是挂钩的,超过芯片支持的数量会直接报错。两到四个实例足够覆盖绝大多数场景,按业务类型分:办公一个、生产一个、监控一个、管理一个,每个实例在不同链路上有独立的主备路径,已经能把链路的利用率拉起来了。

验证 MSTP 有个专门命令show spanning-tree mst configuration看本地区域信息,show spanning-tree mst 0看 IST 的情况,show spanning-tree mst 1看具体实例。怀疑区域不一致时,用show spanning-tree mst 0 detail里的 "Boundary" 标记来判断,如果一台设备所有端口都被标记为 Boundary,那基本就是区域没对上。

注意:修改 MSTP 区域配置会导致该区域所有交换机重新收敛,必须在维护窗口做,而且要一次改完,中间状态可能出现临时环路。

6.3 验证命令与日志阅读

排错时最有用的几个命令,我按使用频率排个序:

show spanning-tree summary ! 总览:模式、端口数量、根桥是谁 show spanning-tree vlan 10 ! 单个 VLAN 的详细拓扑 show spanning-tree root ! 每台设备认定的根桥,交叉核对首选 show spanning-tree interface g1/0/1 ! 单端口角色、状态、开销、BPDU 计数 show spanning-tree detail ! 拓扑变化次数、时间戳 show spanning-tree inconsistentports ! 被保护机制挂掉的端口一网打尽 show logging | include SPANTREE ! 过滤 STP 相关日志

show spanning-tree summary那一行 "Root bridge for: VLAN0010, VLAN0020" 是最快的判断依据。如果一台接入交换机上显示它是某个 VLAN 的根,而这本来不该发生,你就找到问题了。show spanning-tree inconsistentports更是宝藏命令,BPDU Guard 导致的 err-disable、Root Guard 导致的 root-inconsistent 都在这里列出来,比一个个端口查快得多。

日志里需要重点关注的字符串有几类:%SPANTREE-2-BLOCK_BPDUGUARD(有设备在边缘端口发 BPDU)、%SPANTREE-2-ROOTGUARD_BLOCK(有人在抢根)、%SPANTREE-2-LOOPGUARD_BLOCK(单向链路或 BPDU 丢失)、%SPANTREE-2-PVSTSIM_FAIL(PVST 仿真失败,MSTP 与 PVST 边界有问题)。这四条覆盖了绝大部分现场故障,看到就知道该往哪个方向查。

7. 常见问题排查与避坑实录

7.1 故障速查表

下面这张表是我这些年反复用到的,基本上现场能碰到的 STP 问题都在里面了。

现象可能的根因排查命令处理方式
全网上网卡死、指示灯全闪二层环路show spanning-tree看阻塞口分布断开疑似链路,逐段隔离
某端口不转发,也看不到错误Root Guard / Loop Guard 触发show spanning-tree inconsistentports确认正常后排查对端配置
端口 err-disable,日志有 BPDUGUARD边缘端口收到了 BPDUshow logging关掉 PortFast 或隔离对端设备
根桥与设计不符优先级没生效或新设备 MAC 更小show spanning-tree root手工配 root primary,加 Root Guard
收敛特别慢(30秒+)模式是 802.1D 或半双工链路show spanning-tree summary改 RSTP,检查双工和链路类型
拓扑变化次数暴涨某个端口反复 flappingshow spanning-tree detail查该端口物理层和对接设备
跨厂商对接后实例失效MSTP 区域三要素不一致show spanning-tree mst config统一 name、revision 和映射
单向光纤引起间断环路BPDU 单向丢失show interfaces counters errors开启 Loop Guard 和 UDLD

7.2 那些文档里不会写的坑

第一个坑:别在业务高峰期改 STP 参数。我见过有人在上午十点把全网从 PVST 改成 Rapid-PVST,理由是"改一下模式而已,很快"。结果改到一半,新旧模式的设备在边界上互相不认,BPDU 格式对不上,部分 VLAN 直接成了无环保护状态,整个办公区断了二十分钟。改模式、改区域、改根桥,全都是会引发全网重算的操作,必须进变更窗口。

第二个坑:虚拟化主机的软交换机会发 BPDU。服务器上跑的虚拟交换机如果桥接了物理网卡,它可能会把物理网卡收到的 BPDU 透传上去,也可能自己生成 BPDU。表现就是接入交换机上那个口莫名其妙被 BPDU Guard 干掉,虚拟机网络中断。处理方式是找虚拟化管理员确认网卡的桥接策略,在物理交换机上把这个口排除在 PortFast 之外,或者调整虚拟侧的 STP 设置。这个问题在云环境里很常见,排查时如果发现被干掉的全是服务器机柜的口,基本就是这个原因。

第三个坑:端口优先级相同导致选路跟直觉不符。STP 的最后一级比较是端口 ID,由端口优先级(默认 128)和端口号组成。当两台交换机的上联口端口号恰好一样,或者端口号小的那个口其实是备用链路口时,选出来的根端口就跟你预期的相反。解决办法是改端口优先级,把它设成 16 的倍数(比如 112、96),让某个口优先:

interface GigabitEthernet1/0/49 spanning-tree port-priority 112

第四个坑:老化时间被缩短引发的性能抖动。拓扑变化时 MAC 表老化时间从 300 秒缩到 15 秒,意味着这段时间内表项会大量失效,未知单播被疯狂泛洪。如果网络里本来就有大流量,这个泛洪会雪上加霜。所以减少不必要的拓扑变化比什么都重要:接入口配好 PortFast 和 BPDU Guard,下行口用spanning-tree guard loop,能砍掉 80% 的误触发。

第五个坑:以为关了 STP 就没事了。有些做高性能计算或者存储网络的同行,为了追求"零收敛延迟",直接把 STP 关掉,靠人工保证无环。这在封闭环境里确实可行,但一旦有人插错一根线,就是零防护。我的态度是:可以不用 STP 承载业务,但绝不能让它彻底关闭,保留 STP 作为最后一道保险的成本几乎为零,收益是避免了灾难性故障。

7.3 关于这一章的学习建议

回到 ENCOR 这一章本身。STP 的知识点密度很高,但它有个特点:所有结论都可以推导。你只要记住那个比较顺序(根桥 ID → 根路径开销 → 发送者桥 ID → 端口 ID)和那几种端口角色,剩下的都是逻辑推演。做题时不要背答案,拿张纸画拓扑,按优先级向量一步步比,比三遍就形成肌肉记忆了。

还有一个方法我觉得特别有效:在模拟器里故意搞破坏。故意给两台交换机配成一样的优先级看选谁、故意把根桥放在接入层看流量怎么绕、故意断一根光纤看 Loop Guard 会不会触发、故意让两台交换机的 MSTP 区域名差一个字符看边界退化。这些"错误实验"留下印象,比看十遍配置示例都深。我在实际项目里能快速定位问题,很大程度上靠的就是这些年在实验环境里主动踩过的坑。

最后提醒一句:真实环境里,STP 的问题往往不是 STP 本身的问题,而是链路问题、双工问题、中间传输设备透传问题的表象。看到 STP 报错,先别急着改 STP 配置,先用show interfaces看物理层有没有 CRC 错包、有没有 up/down 抖动、双工是不是匹配。把底层坐实了,再谈上层的树结构,这个顺序能让你少走很多弯路。