☰
EVE-NG实战:STP根桥选举与端口状态机抓包全解析
2026/9/29 15:24:21 网站建设 项目流程

EVE-NG流量洞察系列做到第7期,终于轮到STP了。前面几篇拆ARP、ICMP、DHCP,都有很明显的业务流量特征,测试时抓包结果一目了然。STP不一样,它平时安安静静在后台跑,二层用户流量看不到它,但一旦物理环路出现,广播风暴能把整个交换网打瘫。更麻烦的是,很多人只背得出“STP能防环”,真问根桥是谁、哪个端口在阻塞、收敛要多久,就开始含糊。这期我用EVE-NG搭一个三台交换机的环形拓扑,从BPDU抓包入手,把根桥选举、端口角色、状态机迁移和拓扑变更通知完整过一遍。适合正在学交换、准备认证,或者想真正搞懂环路故障的网工。

1. STP在EVE-NG里为什么值得单独抓一次包

1.1 二层环路被禁止后,BPDU成了唯一“语言”

日常说STP防环,其实说得太抽象。二层交换机本身不具备“知道全网拓扑”的能力,它只需要回答一个问题:每个端口到底能不能转发用户数据。STP就是靠BPDU不停交换、不停竞争得出的结果。每台交换机把自己当前认为的根桥、自己到根桥的cost、自己的Bridge ID全部塞进BPDU里,默认2秒发一次;收到更优的BPDU就放弃发言,收到次优的BPDU就保持原状或者改端口状态。整个过程就像一群交换机在开会,BPDU是唯一的表决单。

过去我们验证STP,最常见的方式是配置完之后执行show spanning-tree看几行状态。但那只看到本机视角,看不到报文交互过程。在EVE-NG里观察STP,等于直接去旁听这场会。物理环境里你很难同时监听多段链路的BPDU,因为BPDU是二层组播帧,普通笔记本接上去未必能抓到;而在EVE-NG里,任何两台设备之间的连线都能直接出pcap,想在哪段链路上看就在哪段链路上看。这就是“流量洞察”这个系列的核心价值:把协议行为变成可以反复回放的报文。

1.2 虚拟环境和物理环境观察STP的差异

有人会担心EVE-NG是虚拟环境,跑STP不准。其实不用太担心。EVE-NG里的IOL镜像跑的是真实IOS代码,BPDU是从虚拟网卡真实发出来的,协议状态机、Hello计时器、Forward Delay这些都由IOS自己在维护,不是模拟器“画”出来的效果。所以你在物理交换机上看到的行为,在这里基本都能复现。

差异主要体现在二层链路本身。EVE-NG的虚拟线缆没有传输时延,BPDU里的Message Age不会像真实网络那样随着物理跳数明显增加;另外,如果宿主机CPU忙,Hello时间可能出现微小抖动。这些都不影响你学习STP的核心逻辑。还有一点要注意:EVE-NG里如果加的是普通Linux主机镜像,它默认不跑STP;要看STP必须用支持交换功能的设备镜像。最方便的是Cisco IOL L2镜像,其次是带交换能力的QEMU镜像,别选成纯路由镜像。

2. 一个三角环拓扑,把根桥选举和端口角色一次讲清

2.1 拓扑设计:三条链路制造一个物理环路

我搭的拓扑很简单:三台交换机S1、S2、S3,链路如下表。

链路两端接口预期端口角色
S1 — S2S1 E0/0 : S2 E0/0S1指定端口,S2根端口
S1 — S3S1 E0/1 : S3 E0/0S1指定端口,S3根端口
S2 — S3S2 E0/1 : S3 E0/1S2指定端口,S3阻塞端口

S1-S2-S3-S1形成一个物理上的三角环。如果不跑STP,广播帧会在这个环里无限循环,交换机的MAC表也会疯狂抖动。选三角而不是两交换机互联,是因为两点一线的拓扑只能看到“一个根端口和一个指定端口”的简单状态,看不到真正的阻塞端口,更看不到后续“阻塞端口被激活”的过程。三角环既有根端口、指定端口,又有阻塞端口,三种角色齐全,适合一次学明白。

为了让收敛过程可观察,我还会在S1下挂PC1、S3下挂PC2,断链时用连续ping来量化中断时间。不过前期学BPDU时,这两个主机不是必需的,它们只会增加抓包里的广播噪音。

2.2 优先级规划决定谁是根桥、谁阻塞

为了让结果可控,我先把VLAN控制在VLAN1。PVST+里每个VLAN各自是一棵生成树,如果你同时放行VLAN10、VLAN20,抓包里BPDU数量会成倍增加,新手容易看花眼。先用一个VLAN把STP本身吃透,后面要学多实例,再往上加VLAN。

三台交换机都配置为trunk互联,然后显式设置根优先级。

! S1 hostname S1 spanning-tree vlan 1 priority 4096 interface Ethernet0/0 switchport mode trunk no shutdown interface Ethernet0/1 switchport mode trunk no shutdown
! S2 hostname S2 spanning-tree vlan 1 priority 8192 interface Ethernet0/0 switchport mode trunk no shutdown interface Ethernet0/1 switchport mode trunk no shutdown
! S3 hostname S3 spanning-tree vlan 1 priority 12288 interface Ethernet0/0 switchport mode trunk no shutdown interface Ethernet0/1 switchport mode trunk no shutdown

优先级从低到高排列,S1必然是根桥。S2和S3都有一条直连根桥的链路,端口cost按100M以太网算都是19,所以在S2-S3这段链路上,S2的Bridge ID优先级更低,成为指定端口,S3对应端口进入阻塞。如果让三台设备都用默认优先级32768,最终根桥会由MAC地址大小决定,结果不够直观。我现在把角色“预定”好了,后面抓包验证时不会出现歧义。

2.3 上线验证:先让STP收敛,再开始抓包

配置完成后不要立刻抓包。三台交换机从启动到选举稳定需要一段时间,建议等30到40秒,先看一遍各设备的状态。

S3# show spanning-tree vlan 1 VLAN0001 Spanning tree enabled protocol ieee Root ID Priority 4097 Address aabb.cc00.0100 Cost 19 Port 5 (Ethernet0/0) Hello Time 2 sec Max Age 20 sec Forward Delay 15 sec Bridge ID Priority 12289 (priority 12288 sys-id-ext 1) Address aabb.cc00.0300 Hello Time 2 sec Max Age 20 sec Forward Delay 15 sec Interface Role Sts Cost Prio.Nbr Type E0/0 Root FWD 19 128.5 Shr E0/1 Altn BLK 19 128.6 Shr

注意Root ID的Priority显示为4097,不是4096。很多第一次做实验的人在这里会愣一下:4096怎么变成了4097?因为PVST+在BPDU里把VLAN号作为sys-id-ext加进了优先级字段,4096 + VLAN1 = 4097。这完全正常。

此时S3的E0/0是根端口,Forwarding;E0/1是Alternate端口,Blocking。如果你看到E0/1显示为Forwarding,说明STP没收敛或者模式不对,先检查优先级配置,再检查端口是否都在trunk模式下。确认无误后,才开始下一节的抓包。

3. 从抓包里读出STP的“潜台词”:Root ID、Cost、Port ID

3.1 在EVE-NG起抓包的正确姿势

在EVE-NG拓扑界面里,右键点击S3和S2之间的连线,选择Capture,会弹出选择节点或接口的窗口,选S3的Ethernet0/1,Wireshark就会开始收包。如果你的EVE-NG没有弹出Wireshark,通常是本机缺少desktop integration组件,装好关联工具再试。

打开Wireshark后,第一步不是看包,先把显示过滤器设为stp。BPDU是组播的二层帧,不走TCP/UDP,用tcp过滤肯定什么都看不到。我也建议不要在抓包前的Capture Filter里直接写stp,因为BPDU走的是802.3/LLC封装,BPF语法容易误伤,直接抓全量再显示过滤最省事。

抓包要持续多久?至少10秒。STP收敛完成后,S3的E0/1是阻塞端口,它只管收、不主动发BPDU,所以这端抓到的其实是S2周期性发来的Hello BPDU,每2秒一条。看到这种规律性的BPDU流,说明端口确实处于被动的阻塞状态。

3.2 BPDU关键字段逐个过

Wireshark里展开一条STP报文,会看到很多字段。新手没必要全部背下来,但下面这张表里的字段必须会看。

字段典型值含义
Destination MAC01:80:c2:00:00:00或PVST+组播地址二层BPDU专用组播地址
LLC DSAP/SSAP0x42SNAP封装标识
Protocol Identifier0x0000802.1D STP
BPDU Type0x00配置BPDU,0x80 TCNBPDU的种类
Root Identifier优先级+VLAN+根桥MAC全网唯一的根桥身份
Root Path Cost0或19等发送者到根桥的路径开销
Bridge Identifier优先级+本机MAC这条BPDU是谁发出的
Port Identifier端口优先级+端口号从哪个端口发出
Message Age0~20秒从根桥生成后经过的时间
Max Age20秒BPDU多久没收到视为过期
Hello Time2秒配置BPDU发送周期
Forward Delay15秒Listening/Learning持续时间

看包的核心方法是三连问。一问Root Identifier是不是同一个:全网必须只有一个根桥,如果S2发给S3的BPDU里Root ID和S1发给S3的Root ID不一样,说明选举还没稳定。二问Root Path Cost是多少:S2发给S3的BPDU里,Root Path Cost是19,表示S2到根桥要经过一条100M链路;如果S3收到的成本变成38,则说明根桥又远了一个网段。三问Bridge Identifier是自己还是别人:一条BPDU里Bridge ID等于Root ID,说明这条BPDU来自根桥本身;否则就是中间交换机在转述根桥的信息。

3.3 用显示过滤器快速定位异常信息

单纯看几十条BPDU不累,但真实网络里BPDU数量很大,需要会过滤。Wireshark里双击展开某个STP字段,左下角会提示对应的过滤语法。比如你想只看某类BPDU,可以按stp.bpdutype或类似字段过滤;想对比不同发送者,就按stp.bridge_*系列字段分组。不同Wireshark版本字段名称略有差异,鼠标点字段看提示是最稳的,不要硬背语法。

再提供一个偏工程师口味的做法:用Python直接读pcap,把BPDU的Root MAC、Path Cost、Bridge MAC提出来打印。Scapy里STP层字段名在不同版本略有不同,跑之前先ls(STP())确认一下。

from scapy.all import rdpcap from scapy.layers.l2 import STP pkts = rdpcap("s3-e0-1.pcap") for pkt in pkts: if STP in pkt: stp = pkt[STP] print(stp.rootmac, stp.rootpathcost, stp.bridgemac, stp.portid)

输出里Root MAC和Bridge MAC对比一下,谁在说自己是根桥,谁在复述别人,一目了然。这个思路在处理几百MB的pcap时比Wireshark图形界面高效得多。

4. 断一条链路,把状态机和TCN的完整过程看一遍

4.1 断链前的静态验证:show spanning-tree和抓包的数据要能对上

在动手断链之前,先建立“本机视角”和“邻居视角”的双重基线。

本机视角是S3上的show spanning-tree vlan 1,看到E0/0是Root端口、Forwarding,E0/1是Altn、Blocking。邻居视角是Wireshark里S3-E0/1端口的抓包:这条链路上只能看到S2发来的BPDU,源MAC是S2,Root ID是S1,Root Path Cost是19,而且每2秒一条。S3自己在这条链路上一言不发,因为它不是指定端口。

这时候从PC2去ping PC1,ICMP能通,但流量不会经过S2-S3链路,因为S3的E0/1还在阻塞。链路是通的,业务流量跟STP路径完全一致,这就是一个健康的二层环路场景。

4.2 断链后,S3端口从Blocking走到Forwarding的30秒

现在在S3上把直连根桥的E0/0关掉。

S3(config)# interface Ethernet0/0 S3(config-if)# shutdown

连通性变化很直观:PC2到PC1的ping开始大量丢包,等大约30秒后恢复。这30秒就是经典STP的收敛时间,由两个15秒的Forward Delay组成。

具体过程在抓包里是这样体现的。S3失去E0/0这根根端口后,它只剩E0/1这一条候选路径。而E0/1之前虽然是阻塞状态,但一直在接收S2发来的BPDU,里面包含的信息是“根桥S1可达,路径开销19”。这条信息比S3自己宣称的“我是根桥”要优,所以S3立刻判断E0/1可以成为新根端口。端口从Blocking进入Listening,此时Wireshark上最明显的变化是:S3开始主动从E0/1发出BPDU了。之前只收不发,现在两边都有包,说明S3在这个网段获得了发言权。

按802.1D的计时器,Listening持续15秒,之后进入Learning再15秒,然后才Forwarding。我用连续ping测试,丢包窗口大约是30秒,和理论值一致。如果你实验里看到端口秒开、ping只断了一两秒,十有八九把STP模式开成了Rapid PVST或RSTP,那就要回到模式设置上检查。

4.3 TCN/TCA和配置BPDU的TC标志:拓扑变化的连锁反应

单纯看端口状态迁移还不够,STP里更有意思的是拓扑变化通知。当S3检测到端口角色变化,它会通过根端口向外发一条TCN BPDU,告诉根桥“网络拓扑变了”。这个根端口恰好也是刚变成Forwarding的E0/1,所以抓包里会看到:

大致时间帧方向BPDU类型解读
0秒左右S3 → S2TCNS3通知上游有拓扑变化
0秒左右S2 → S3TCAS2确认收到TCN
0秒左右S2 → S1TCNS2向根桥转告
0秒左右S1 → S2TCA根桥确认
随后35秒S1 → 全网带TC标志的配置BPDU根桥要求大家缩短MAC表老化时间

TC标志的作用很多人理解不到位。正常情况下交换机MAC表条目老化时间是300秒,拓扑变了以后如果还用300秒老化,交换机很可能继续把帧发往已经失效的端口,造成长时间丢包。根桥收到TCN后,会在配置BPDU里置位TC标志并持续Max Age加Forward Delay的时间,即大约35秒。这段时间内所有交换机临时把MAC老化时间缩短为15秒,快速清掉老旧条目。Wireshark里你不需要猜测,直接看根桥发出的配置BPDU里的Topology Change字段,是1就是正在通知全网刷新。

这一连串动作下来,你会清楚看到STP不只是“把某个端口堵住”,而是一套完整的状态同步机制。抓包把TCN、TCA、TC标志全部摆出来,比背十遍理论知识都管用。

5. EVE-NG里观察STP容易踩的三个坑

5.1 默认模式可能不是你想看的经典STP

这个坑我在好几台IOL镜像上都遇到过。你以为自己在看经典802.1D的30秒收敛,结果端口从阻塞到转发只用了两秒,因为你没确认当前STP模式,而镜像默认跑的是Rapid PVST。

配置完成后,先在所有交换机上执行show spanning-tree vlan 1,看输出里的“Spanning tree enabled protocol”这一行。显示ieee是PVST/802.1D,显示rstp就是Rapid PVST。想复现经典STP全过程,在三台设备上都执行spanning-tree mode pvst,然后再测。

混用模式也是个麻烦。如果S2是Rapid PVST、S3是PVST,两台设备在BPDU版本和协商flag上不一致,抓包里的字段会变得很奇怪,比如配置BPDU里出现不明的Proposal/Agreement位。排障逻辑也会被带偏。统一模式再做实验,省得怀疑自己拓扑搭错了。

5.2 复制粘贴节点带来的MAC重复问题

EVE-NG里搭建实验时,很多人习惯从已有点上右键复制节点,再粘贴出一个新交换机。复制出来的节点如果继承了原节点的虚拟MAC,问题就来了:Wireshark里你会看到两台不同交换机发出的BPDU,Bridge Identifier完全相同。STP选举遇到完全相同的Bridge ID,优先级和MAC都无法比较,运气成分就上来了,你没法预料谁会成为根桥。

遇到这种诡异情况,先别怀疑Wireshark,去检查两个节点的网卡MAC是否重复。最简单的办法是删掉出问题的节点重新拖一个出来,也能直接看节点配置里MAC地址段能否修改。保持全网Bridge ID唯一,是STP实验能够复现的前提。

5.3 别用删连线代替接口shutdown,抓包会断

断链时的一个低级错误,是在EVE-NG画布里直接右键删除S3-S1之间的连线。这样确实模拟了“链路断开”,但你会立刻失去这段链路的抓包入口,后续想复盘BPDU流就没了。更稳的做法是在设备console里执行shutdown/no shutdown,让IOS自己经历link down和link up事件,抓包继续保留,还能顺便观察恢复后的BPDU交互。

同理,如果你需要反复测试收敛,建议不要频繁重启节点。重启节点会让整个交换机的STP状态清零,重新经历根桥选举和端口角色竞争,干扰你对单一链路故障的判断。

还有个小提醒:抓BPDU时如果一直开着Wireshark但没看到任何STP帧,先检查是不是交换机节点根本没起来,或者端口被shutdown了。EVE-NG里节点启动是个异步过程,刚开机时IOS还没跑到STP,等二三十秒再抓包是正常的。

6. 把流量洞察变成真实排障能力

6.1 拿到一份陌生网络的BPDU,怎么反推根桥和阻塞点

从抓包文件反推网络结构和根桥,方法其实固定。先按Root Identifier排序,所有BPDU里Root ID一致,说明生成树已经收敛。然后找“Root ID等于Bridge ID”的那些BPDU,发件人就是根桥。根桥通常会在所有活跃端口上都发配置BPDU,而且Root Path Cost是0。

再看每一段链路上谁在发配置BPDU。同一段网段里,持续发BPDU的是指定端口;只接收但不发的是根端口或阻塞端口。区分根端口和阻塞端口,需要结合交换机本机的状态:如果这个端口是到达根桥路径里最优的那个,就是根端口;否则就是被阻塞的Alternate端口。你不需要认识网络里的每一台交换机,只要把BPDU里的Port ID和Bridge ID记下来,再对照show mac address-table找出这些MAC对应哪台设备,整个STP拓扑就拼出来了。

6.2 实际网络里抓STP包的“黄金时机”

在物理网络里抓BPDU,比EVE-NG麻烦不少,但思路完全一样。以下几个时间点最值得抓。

第一,加新交换机之前。此时抓一段已有链路的BPDU,看Root ID是否稳定;把新交换机接进去后再次抓,依然稳定,说明选举没有被打乱;如果换成了新交换机的MAC,说明新设备优先级更高,它正在抢根桥。

第二,广播风暴刚发生时。多数人的第一反应是看哪个端口流量最大,但STP视角能看得更准:如果各端口的BPDU还在正常流动且Root ID一致,说明根桥还在,风暴大概率来自某个不支持STP的设备被接进了网络;如果BPDU里出现多个不同的Root ID,说明网络被切成多个互不知情的“岛屿”,每个岛都以为自己是根桥。

第三,业务中断恢复之后。这时别急着下班,把抓包打开复盘TCN的流向。如果中断30秒以上,通常能看到经典STP的Listening/Learning过程;如果不到一秒就恢复,则要确认是不是RSTP或者有PortFast参与。下次再故障,你就有基线数据可以对比。

物理网络中抓BPDU的常用手段是交换机SPAN口,把镜像流量引到笔记本上。和EVE-NG抓包一样,过滤条件依然只用stp,不要加多余的tcp或port条件。

6.3 一点个人体会:Wireshark和Console需要配合看

最后说一个我从这套实验里得到的实际体会:抓包和console一定要同时开着看。Wireshark告诉你设备在“说什么”,console告诉你设备在“做什么”。比如S3的E0/1开始主动发BPDU,Wireshark已经能看到包了,但如果不同步看S3的show spanning-tree vlan 1,你没法确定这个端口当前正处于Listening还是Learning。两边一对照,端口状态和报文方向立刻对应上。

后来我在真实网络排障里也用这个习惯。先抓一段pcap,再从交换机上确认本机认为根桥是谁、端口角色是什么。报文会说谎的情况很少,但人对协议的误读很常见,抓包加命令行交叉验证,能过滤掉大部分错误判断。这套EVE-NG里的STP实验做完,你以后再碰到环路故障,至少能指着抓包软件说:根桥在这里,阻塞端口在这里,收敛时间就是这么长。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询