STP and RSTP on Cisco IOS-XE: Spanning Tree Configuration, Tuning, and Troubleshooting

STP and RSTP on Cisco IOS-XE: Spanning Tree Configuration, Tuning, and Troubleshooting

Spanning Tree Protocol. It’s been around since the 1980s, it’s been blamed for more outages than almost any other Layer 2 technology, and yet it’s still running in the majority of campus and enterprise networks today. If you’re working with Cisco switches — whether it’s a stack of Catalyst 9300s in a wiring closet or a pair of Nexus 7Ks in the data center — you need to understand STP, RSTP, and MST deeply enough to configure them correctly, tune them for fast convergence, and troubleshoot them when they go sideways.

This guide digs into Spanning Tree on Cisco IOS-XE: how STP and RSTP work at a protocol level, how to configure and tune them, and how to identify and fix the most common failure scenarios you’ll encounter in production. Real CLI, real output, no hand-waving.

Why STP Still Matters (and Why It’s Still Dangerous)

Ethernet frames have no TTL. In a switched network with redundant paths and no loop-prevention mechanism, a single broadcast frame loops indefinitely — saturating CPU on every switch in the loop, crashing the network. STP exists to prevent that by logically blocking redundant paths, leaving only a loop-free active topology.

The problem is that 802.1D STP was designed in an era when 10 Mbps was fast and convergence times of 30-50 seconds were acceptable. It uses timers and state machines that make it slow to adapt to topology changes, and its defaults are easy to misconfigure in ways that cause silent, intermittent, or catastrophic failures.

RSTP (802.1w, merged into 802.1D-2004) addressed the convergence problem with a proposal/agreement handshake mechanism that can converge in under a second on point-to-point links. Cisco IOS-XE defaults to Rapid PVST+ (a Cisco extension of RSTP that runs a separate instance per VLAN), which gives you per-VLAN topology control and fast convergence.

If you’re interested in how to lock down the control plane around STP and other protocols, check out the Cisco CoPP guide on IOS-XE — protecting the CPU from STP BPDUs during a TCN storm is something CoPP handles well.

STP Fundamentals: Root Bridge, Port Roles, Port States

Before touching any configuration, let’s nail the fundamentals.

Root Bridge Election

Every STP domain elects a root bridge — the switch with the lowest Bridge ID. Bridge ID = Priority (2 bytes) + MAC address (6 bytes). Default priority on Cisco is 32768, so without manual configuration, the switch with the lowest MAC wins the election. That’s almost never what you want.

In Rapid PVST+, there’s a separate root election per VLAN. So in a network running VLANs 10, 20, and 30, you could (and should) have different root bridges for different VLANs to distribute load.

Port Roles

  • Root Port (RP) — The port on a non-root switch with the best path cost to the root bridge. One per switch (per VLAN in PVST+).
  • Designated Port (DP) — On each network segment, the port that forwards traffic toward the root. The root bridge’s ports are always designated.
  • Alternate Port — RSTP concept. A backup to the root port, in a discarding state.
  • Backup Port — RSTP concept. A backup to a designated port on the same segment, in a discarding state.
  • Disabled — Administratively shut down.

Port States in RSTP

RSTP reduces the 802.1D states to three operational states:

  • Discarding — Neither forwarding frames nor learning MACs. Combines the old Blocking, Listening states.
  • Learning — Learning MACs but not forwarding.
  • Forwarding — Fully operational.

RSTP Link Types

RSTP’s fast convergence depends on link type. Point-to-point links (full duplex) get the proposal/agreement handshake — no timer wait. Shared links (half duplex) fall back to 802.1D timer-based convergence. Edge ports (PortFast-enabled) skip the handshake entirely and go straight to forwarding.

Viewing the Current STP Topology

Before changing anything, understand what’s running. These are the commands you’ll use constantly:

! View STP summary for all VLANs
Switch# show spanning-tree summary

! View STP detail for a specific VLAN
Switch# show spanning-tree vlan 10

! View per-port STP state
Switch# show spanning-tree vlan 10 detail

! Quick port-role overview
Switch# show spanning-tree vlan 10 brief

Sample output for a non-root switch:

Switch# show spanning-tree vlan 10

VLAN0010
  Spanning tree enabled protocol rstp
  Root ID    Priority    24586
             Address     f8b7.e246.1a00
             Cost        4
             Port        1 (GigabitEthernet1/0/1)
             Hello Time   2 sec  Max Age 20 sec  Forward Delay 15 sec

  Bridge ID  Priority    32778  (priority 32768 sys-id-ext 10)
             Address     f8b7.e246.3c00
             Hello Time   2 sec  Max Age 20 sec  Forward Delay 15 sec
             Aging Time  300 sec

Interface           Role Sts Cost      Prio.Nbr Type
------------------- ---- --- --------- -------- --------------------------------
Gi1/0/1             Root FWD 4         128.1    P2p
Gi1/0/2             Desg FWD 4         128.2    P2p
Gi1/0/3             Altn BLK 4         128.3    P2p

This tells you: RSTP is running, the root is at priority 24586 + MAC (that’s 24576 + VLAN 10 sys-id-ext), Gi1/0/1 is the root port, Gi1/0/2 is a designated port, and Gi1/0/3 is an alternate port (blocking).

Configuring Root Bridge Priority

Never leave root bridge election to chance. Explicitly configure which switch should be root — and a secondary in case the primary fails.

! Method 1: Use the macro (sets priority to 24576 for specified VLANs)
Switch(config)# spanning-tree vlan 10,20,30 root primary
Switch(config)# spanning-tree vlan 40,50 root secondary

! Method 2: Set priority manually
! Priority must be a multiple of 4096
Switch(config)# spanning-tree vlan 10 priority 4096

! Verify
Switch# show spanning-tree vlan 10 | include Priority|Address
  Root ID    Priority    4106
             Address     f8b7.e246.1a00

The root primary macro sets priority to 24576 if the current root is higher than 24576, or to 4096 if the current root priority is already 24576 or lower. The root secondary macro sets it to 28672. For deterministic environments, set priority values explicitly.

PortFast and BPDUGuard: Edge Port Protection

PortFast tells a switch port to skip the listening/learning states and go straight to forwarding — critical for hosts, servers, and access ports where you don’t want 30-second delays on link-up. BPDUGuard shuts the port immediately if it receives a BPDU — protecting against someone plugging a switch into an access port and accidentally becoming part of the STP domain.

! Enable PortFast globally for all access ports (recommended)
Switch(config)# spanning-tree portfast default

! Enable BPDUGuard globally for all PortFast ports (strongly recommended)
Switch(config)# spanning-tree portfast bpduguard default

! Per-interface override (explicit configuration)
Switch(config)# interface GigabitEthernet1/0/10
Switch(config-if)# spanning-tree portfast
Switch(config-if)# spanning-tree bpduguard enable

! Check which ports have PortFast enabled
Switch# show spanning-tree summary totals
Switch# show spanning-tree interface Gi1/0/10 portfast

When BPDUGuard triggers, the port goes into err-disabled state:

Switch# show interfaces GigabitEthernet1/0/10 status
Port      Name               Status       Vlan       Duplex  Speed Type
Gi1/0/10                     err-disabled 10         full    1000  10/100/1000BaseTX

Switch# show errdisable detect | include bpduguard
bpduguard          ErrDisable Enabled

! Manual recovery (or configure auto-recovery)
Switch# interface GigabitEthernet1/0/10
Switch# shutdown
Switch# no shutdown

! Auto-recovery after 300 seconds
Switch(config)# errdisable recovery cause bpduguard
Switch(config)# errdisable recovery interval 300

BPDUFilter: Use With Caution

BPDUFilter stops a port from sending or receiving BPDUs. When applied globally (via spanning-tree portfast bpdufilter default), it silences BPDU generation on PortFast ports but reverts to normal STP behavior if a BPDU is received — this is generally safe. When applied per-interface, it permanently filters BPDUs in both directions, effectively removing the port from STP. That can create loops if someone plugs a switch into the port.

! SAFER: Global BPDUFilter on PortFast ports only (still receives BPDUs, disables PortFast if one arrives)
Switch(config)# spanning-tree portfast bpdufilter default

! DANGEROUS: Per-interface BPDUFilter (use only when you absolutely know what you're doing)
Switch(config-if)# spanning-tree bpdufilter enable

The rule of thumb: use BPDUGuard, not BPDUFilter, for access port protection. BPDUFilter per-interface is for specific scenarios like connecting to service provider bridges where you don’t want to participate in STP but also don’t want the port shut down on BPDU receipt.

Path Cost Tuning

STP uses path cost to determine the best path to the root. Lower cost = preferred path. Default costs by speed (long method, recommended for modern networks):

! Use long path costs (supports 10G+ links properly)
Switch(config)# spanning-tree pathcost method long

Speed       Long Cost
10 Mbps     2,000,000
100 Mbps    200,000
1 Gbps      20,000
10 Gbps     2,000
100 Gbps    200
! Override path cost on a specific interface
Switch(config)# interface GigabitEthernet1/0/2
Switch(config-if)# spanning-tree vlan 10 cost 10000

! Override port priority to influence which port becomes root port on the downstream switch
Switch(config-if)# spanning-tree vlan 10 port-priority 64

! Verify
Switch# show spanning-tree vlan 10 interface Gi1/0/2 detail

MST: Multiple Spanning Tree

Rapid PVST+ runs a separate STP instance per VLAN. In environments with hundreds of VLANs, that’s hundreds of STP instances — significant CPU overhead on switches and uplinks. MST (802.1s) maps multiple VLANs to a smaller number of STP instances, reducing overhead while still allowing load balancing.

! Configure MST globally
Switch(config)# spanning-tree mode mst

Switch(config)# spanning-tree mst configuration
Switch(config-mst)# name IGNA-CAMPUS
Switch(config-mst)# revision 1
Switch(config-mst)# instance 1 vlan 10-19,30-39
Switch(config-mst)# instance 2 vlan 20-29,40-49
Switch(config-mst)# show   ! Preview before committing
Switch(config-mst)# exit

! Set root bridge per MST instance
Switch(config)# spanning-tree mst 1 root primary
Switch(config)# spanning-tree mst 2 root secondary

! Verify MST configuration
Switch# show spanning-tree mst configuration
Switch# show spanning-tree mst 1

MST instances 0 (IST, Internal Spanning Tree) is always present and carries all VLANs not explicitly mapped. All MST bridges that should be in the same region must have identical name, revision, and VLAN-to-instance mapping.

Common STP Failure Scenarios and Troubleshooting

Topology Change Notification (TCN) Storms

TCNs flush MAC tables across the network to prevent stale entries after a topology change. Too many TCNs — caused by flapping links, misconfigured servers, or VMs migrating — can cause severe performance degradation as switches relearn MAC addresses for every frame.

! Identify TCN sources
Switch# show spanning-tree vlan 10 detail | include from|changes

  Number of topology changes 1523 last change occurred 00:00:03 ago
          from GigabitEthernet1/0/15

! Check interface TCN statistics
Switch# show spanning-tree vlan 10 interface Gi1/0/15 detail
Gi1/0/15 is a designated port
   ...
   Number of transitions to forwarding state: 47
   BPDU: sent 15230, received 0

A port sending no BPDUs but generating lots of transitions typically points to a host with a flapping NIC, a misconfigured VM, or a loop caused by someone plugging in an unmanaged switch. PortFast on access ports helps because PortFast ports don’t generate TCNs on link state changes — only when they transition to forwarding from a non-forwarding state initially.

Unidirectional Link (Loop Guard and UDLD)

A unidirectional link — where a fiber strand receives but doesn’t transmit, or vice versa — can cause STP loops because a switch thinks the link is up and stops blocking ports based on BPDUs it should have received but didn’t.

! Loop Guard: blocks ports that stop receiving BPDUs (instead of transitioning to designated)
! Apply to non-edge, non-root ports — ideally uplinks between switches
Switch(config)# spanning-tree loopguard default

! Per-interface Loop Guard
Switch(config-if)# spanning-tree guard loop

! UDLD: Layer 1 detection of unidirectional links (aggressive mode shuts port)
Switch(config)# udld aggressive

! Per-interface UDLD (fiber interfaces often need explicit enable)
Switch(config-if)# udld port aggressive

! Check UDLD status
Switch# show udld interface Gi1/0/1
Switch# show spanning-tree vlan 10 | include loop
Gi1/0/1             Root FWD 4         128.1    P2p
Gi1/0/3             Altn BLK 4         128.3    P2p *LOOP_Inc*

The *LOOP_Inc* flag means Loop Guard has put the port into an inconsistent state because it stopped receiving BPDUs. This is the protection working correctly — investigate the link rather than clearing the inconsistency without understanding why it happened.

Root Guard: Protecting the Root Bridge

Root Guard prevents a port from becoming the root port. If a superior BPDU arrives on a Root Guard-enabled port, the port is placed into a root-inconsistent (blocked) state rather than allowing a rogue switch to become root.

! Apply Root Guard to all ports where the root bridge should NEVER appear
! Typically, all switch ports facing downstream (edge switches, distribution toward access)
Switch(config)# interface range GigabitEthernet1/0/5-24
Switch(config-if-range)# spanning-tree guard root

! Check Root Guard status
Switch# show spanning-tree vlan 10 | include Root_Inc

! If triggered:
Switch# show spanning-tree inconsistentports
Name                   Interface              Inconsistency
---------------------- ---------------------- ------------------
VLAN0010               GigabitEthernet1/0/20  Root Inconsistent

The port self-recovers once the superior BPDUs stop — unlike err-disable from BPDUGuard, no manual intervention needed.

STP and EtherChannel Interactions

EtherChannel bundles multiple physical links into a single logical link. STP sees the bundle as one interface, which is correct behavior — but misconfigured EtherChannel is one of the most common causes of STP loops and traffic black-holing.

! STP runs on the Port-Channel interface, not on individual member links
Switch# show spanning-tree vlan 10 interface Port-channel1 detail

! Verify EtherChannel is correctly formed before trusting STP state
Switch# show etherchannel summary
Flags:  D - down        P - bundled in port-channel
        I - stand-alone s - suspended
        H - Hot-standby (LACP only)
        R - Layer3      S - Layer2
        U - in use      f - failed to allocate aggregator

Group  Port-channel  Protocol    Ports
------+-------------+-----------+-----------------------------------------------
1      Po1(SU)         LACP      Gi1/0/1(P) Gi1/0/2(P)

If member links show I (stand-alone) instead of P (bundled), EtherChannel is misconfigured and STP will see individual links — potentially blocking one while LACP tries to negotiate. A common culprit: one side is LACP, the other is static (mode on), or timers/modes don’t match.

STP Tuning for Fast Convergence: Best Practices Summary

Here’s a consolidated set of commands for a well-tuned Rapid PVST+ deployment:

! Global STP tuning best practices

! Use Rapid PVST+ (default on modern IOS-XE, but verify)
spanning-tree mode rapid-pvst

! Use long path costs for correct cost calculation on high-speed links
spanning-tree pathcost method long

! Enable PortFast on all access ports (hosts, servers, printers)
spanning-tree portfast default

! Enable BPDUGuard on all PortFast ports
spanning-tree portfast bpduguard default

! Enable Loop Guard globally to protect uplinks from unidirectional link failures
spanning-tree loopguard default

! Enable UDLD aggressive on all fiber uplinks
udld aggressive

! Explicit root bridge assignment (replace VLANs as appropriate)
spanning-tree vlan 1-100 root primary
spanning-tree vlan 101-200 root secondary

! Apply Root Guard to all downstream-facing ports
interface range GigabitEthernet1/0/5-48
 spanning-tree guard root

! EtherChannel to core switches
interface range GigabitEthernet1/0/1-2
 channel-group 1 mode active
interface Port-channel1
 spanning-tree portfast trunk  ! Only if this is a trunk to a single host/blade; don't use on switch uplinks

Verifying RSTP Convergence Speed

RSTP convergence on point-to-point links should be near-instant. You can verify with a controlled test:

! Watch STP topology changes in real time
Switch# debug spanning-tree events
Switch# debug spanning-tree bpdu

! Monitor convergence after a link failure
Switch# show spanning-tree vlan 10 detail | include transitions|last change

! Check STP timers (lower these only on very stable, controlled networks)
Switch# show spanning-tree vlan 10 | include Hello|Max|Forward
  Hello Time   2 sec  Max Age 20 sec  Forward Delay 15 sec

! Diameter-based timer adjustment (for networks with >7 switch hops — uncommon)
Switch(config)# spanning-tree vlan 10 max-age 14
Switch(config)# spanning-tree vlan 10 forward-time 10

Don’t tune STP timers below defaults without understanding the network diameter. Aggressive timers in large networks can cause instability — RSTP’s proposal/agreement mechanism handles convergence without timer changes in most environments. If you’re seeing slow convergence on access ports specifically, PortFast is almost always the answer.

STP and Modern Network Designs

Many modern campus designs use routed access (Layer 3 to the access layer) to eliminate STP at the access layer entirely, relying on ECMP routing for redundancy instead. But STP remains necessary wherever Layer 2 redundancy exists — stacked switches, dual-homed servers, MLAG configurations, and any scenario with multiple physical paths in the same broadcast domain.

Understanding STP deeply also makes you better at troubleshooting VLANs — because a blocked port is transparent at Layer 3 but visible at Layer 2. If you haven’t read the VLAN segmentation guide, it pairs well with this material. And if you’re dealing with OSPF adjacency issues that trace back to Layer 2 problems caused by STP topology changes, the OSPF troubleshooting guide has you covered.

Final Thoughts

STP is one of those protocols where a shallow understanding is genuinely dangerous — you can configure it incorrectly and have a network that works fine under normal conditions but fails catastrophically during a link flap or maintenance window. The goal isn’t just to make the lights go green; it’s to have a topology you can reason about, where you know exactly which paths are active and which are blocked, and where failures converge predictably and quickly.

Rapid PVST+ with PortFast, BPDUGuard, Root Guard, Loop Guard, and UDLD gives you a solid defensive posture. Explicit root bridge priority assignment gives you control. And regular verification — show spanning-tree should be as routine as show interface — keeps you ahead of problems before they become outages.

Enjoying this post?

Get more guides like this delivered straight to your inbox. No spam, just tech and trails.