Relentless Coding

A Developer’s Blog

STP

In this post, we will have a look at the venerable Spanning Tree Protocol (STP), what it is used for, and how to configure and verify it on Cisco IOS and MikroTik.

STP Theory

STP (802.1D) prevents switching loops. Without it, a LAN with redundant links is susceptible to:

  • Broadcast storms, resulting in
  • MAC table instability; and
  • Multiple frame transmission

A broadcast storm is caused by a broadcast frame that is put on a LAN that has a loop. It never dies, because it is flooded out every interface of a switch, except the interface it came in on.

Because the same broadcast frame comes in on different ports of a switch with the same source address, the switch keeps updating its MAC table: the entry is flapping.

Another consequence of a broadcast storm is that the same frame will be delivered multiple times to the destination, and it might just be that the application cannot handle that correctly.

STP makes sure there is only path from a switch to a so-called root bridge. The root bridge gets elected among all available switches in the broadcast domain.

Root Bridge Election

The election works as follows: using a so-called Hello configuration Bridge Data Protocol Units (BPDUs), each switch advertises itself as the root bridge to its neighbors. It does this by including a root and sender Bridge ID (BID) that consists of a 2-byte priority field and a 6-byte system identifier:

Shows a Bridge ID dissected into a 2-byte priority value and a 6-byte MAC
address

A lower priority value indicates higher priority. The system identifier is equal to the switch’s burned-in MAC address.

The Hello BPDU includes the following fields:

Field Description
Root BID BID of switch the sender of this Hello BPDU believes to be the root bridge
Sender’s BID BID of switch sending this Hello BPDU
Sender’s root cost Root path cost between the sending switch and the current root
Root’s timer values Hello timer, MaxAge timer, forward delay timer

A neighbor receives this BPDU and looks at the advertised root BID. If the root BID is superior (meaning the priority is higher than what it currently thinks of as the root), it will:

  • change the sender BID in the Hello BPDU to its own BID
  • change the sender’s root cost to the cost between this switch and the root; and
  • forward the modified Hello BPDU out its other ports.

If the priority is lower (inferior), however, it will just ignore the BPDU.

By default, the 2-byte priority field in the BID is equal to 32,768 (or 0x8000 in hex). In that case, the system ID (the burned-in MAC address) is used as a tie breaker: the lower the 48-bit MAC address value, the higher its priority (1111.1111.1111 wins from 2222.2222.2222).

After a while, the root will be elected and the network will start to converge (= stabilize on a network topology).

STP Roles and States

After the election, each switch’s interface takes on a role. These roles can be:

  • Root Port (RP): the single port on a switch facing the root switch that has the least cost path to the root switch. Root ports are chosen by:
    1. root path cost
    2. BID of the upstream device
    3. bridge port ID of the upstream device (consisting of a port priority and a unique ID, such as 128.1)
  • Designated Port (DP): a port (facing away from the root switch) on a segment that has the least cost path to the root switch. This port will forward the Hello BPDU onto the segment.

Because the elected root switch has the lowest cost path (0) to the root on all its ports, all of its ports will be designated ports (DPs).

The cost of a path to the root is determined by looking at the current speed (not maximum speed!) of the links that lie between a non-root switch’s port and the root switch’s port. By default, traversing a 100 Mbps link carries a cost of 19, while a 1000 Mbps costs 4:

Ethernet Speed IEEE Cost 1998 (short) IEEE Cost 2004 (long)
10 Mpbs 100 2,000,000
100 Mpbs 19 200,000
1,000 Mpbs/1 Gbps 4 20,000
10,000 Mpbs/10 Gbps 2 2,000
100,000 Mpbs/100 Gbps N/A 200
1,000 Gbps/1 Tbps N/A 20

On IOS, you can switch between the 2 short and long methods by:

Switch# spanning-tree pathcost method <short|long>

Set the interface cost for an interface:

Switch(config-if)# spanning-tree vlan 1 cost 123

Note that on IOS, you set the cost per VLAN on an interface. That is because IOS uses a modified version of STP called the Per-VLAN Spanning Tree Protocol (PVST+)1, which is a topic for a separate blog post.

With STP, every interface can be in state:

  • Blocking (stable)
  • Listening (transient)
  • Learning (transient)
  • Forwarding (stable)
  • Disabled (stable)

(Between parentheses whether the state is a stable state or an intermediate state towards a stable state.)

Root Ports and Designated Ports will be forwarding frames. If a port is not a RP or a DP, it will be blocked. That means that it will not receive nor transmit user frames. It will still receive BPDUs, though.

If an interface is administratively shut down, its state will be “disabled”.

On IOS, you can check on all of this with show spanning-tree:

Switch#sh spanning-tree 
VLAN0001
  Spanning tree enabled protocol rstp
  Root ID    Priority    24577
             Address     000B.BE6A.4623
             Cost        19
             Port        1(FastEthernet0/1)
             Hello Time  2 sec  Max Age 20 sec  Forward Delay 15 sec

  Bridge ID  Priority    28673  (priority 28672 sys-id-ext 1)
             Address     00D0.BA39.4B87
             Hello Time  2 sec  Max Age 20 sec  Forward Delay 15 sec
             Aging Time  20

Interface        Role Sts Cost      Prio.Nbr Type
---------------- ---- --- --------- -------- ---------------------------
Fa0/2            Desg FWD 19        128.2    P2p
Fa0/1            Root FWD 19        128.1    P2p

Timers

A root bridge sends a Hello BPDU every 2 seconds by default. This Hello Time is carried in the BPDU. It also contains a value for MaxAge, which defines how long switches should wait after ceasing to hear Hellos before trying to change the STP topology. By default, it is 10 times the Hello Time. So a switch will wait 20 seconds for Hellos to come in before taking action.

The forward delay timer is used to determine how long a switch will stay in listening and learning states after deciding to transition a port from blocking to listening.

In the listening state, the switch processes BPDUs but does not forward any user frames. It tries to determine whether the interface should indeed be forwarding or should return to the blocking state. It makes this decision based on the received BPDUs. Also, the switch removes unused MAC table entries for which no frames are received during this period.2 In the learning state, the switch begins to learn the MAC addresses of frames received on the interface.

All in all, a switch could take 50 seconds (20 MaxAge, 2 times the forward delay for listening and learning) before an interface transitions from blocking to forwarding.

Edge Devices

Only switches participate in STP. Edge devices (PCs, laptops, IoT, etc.) do not. But the links that connect edge devices to switches will, by default, still go through the motions by first entering listening state and then learning state. You can short-circuit this process by configuring spanning-tree portfast on the interface. The link will now transition to forwarding immediately.

In the event you do connect a switch to a port that was configured with portfast, you can inadvertently create a loop. In that case, you should also enable BPDU Guard on the port by setting spanning-tree bpduguard enable. If the port detects a BPDU coming in, it will automatically disable itself.

MikroTik

On MikroTik’s RouterOS 7, make sure you have STP enabled:

[user@rb] /interface/bridge/set BR1 protocol-mode=rstp

(Even though this post is about the traditional IEEE 802.1D STP, please enable the more modern (faster!) RSTP instead.)

Check the status of a bridge:

[u@rb] /interface/bridge/monitor BR1
                  state: enabled                 
    current-mac-address: 48:A9:8A:11:11:11
            root-bridge: yes                     
         root-bridge-id: 0x8000.48:A9:8A:11:11:11
         root-path-cost: 0                       
              root-port: none                    
             port-count: 23                      
  designated-port-count: 5                       
           fast-forward: no

It indicates this bridge is the root bridge (current-mac-address == root-bridge-id) and has a BID of 0x8000.48:A9:8A:11:11:11: here, 0x8000 is the priority in hex (= 32,768 in decimal; change with set BR1 priority=0xNNNN to a multiple of 4,096) and the system ID is the 48:A9:8A:11:11:11.

Check an individual port:

[u@rb] /interface/bridge/port> monitor [find interface=ether17]
            interface: ether17
               status: in-bridge      
          port-number: 16             
                 role: designated-port
            edge-port: yes            
  edge-port-discovery: yes            
  point-to-point-port: yes            
         external-fdb: no             
         sending-rstp: yes            
             learning: yes            
           forwarding: yes            
     actual-path-cost: 10             
     hw-offload-group: switch1

It automatically discovered that interface ether17 is connected to an edge device. If you want to be specific, you can set PortFast by set [find interface=ether17] edge=yes. Set BPDU Guard with set [find interface=ether1] bpdu-guard=yes.

Change between the long and short automatic costs based on interfaces speeds:

[user@rb] /interface/bridge/set BR1 port-cost-mode=long

And a bit of warning: RouterOS does not currently play well with Cisco’s PVST. It will treat it as regular multicast traffic.


  1. The + at the end indicates that IEEE 802.1Q is used for trunking instead of Cisco’s older, proprietary ISL protocol. ↩︎

  2. This state was subject to dispute, as it is unclear whether it matters if STP is learning MAC addresses or not here. It is telling that RSTP has done away with this state. ↩︎