Configuring STP/RSTP/MSTP on Linux with Open vSwitch: Prevent Layer 2 Loops

Networking tutorial - IT technology blog
Networking tutorial - IT technology blog

Quick Start: STP on Open vSwitch in 5 Minutes

Theory can wait. Here’s the fastest path to getting STP running on your Linux machine with Open vSwitch (OVS). If you haven’t installed OVS yet:

sudo apt-get install openvswitch-switch -y
sudo systemctl start openvswitch-switch
sudo systemctl enable openvswitch-switch

Create a bridge and flip STP on:

# Create an OVS bridge
sudo ovs-vsctl add-br br0

# Enable STP on the bridge
sudo ovs-vsctl set bridge br0 stp_enable=true

# Verify STP is active
sudo ovs-vsctl get bridge br0 stp_enable

Done. STP is now active on br0. Add ports and OVS handles the rest — it elects a root bridge and blocks redundant paths automatically:

# Add ports to the bridge
sudo ovs-vsctl add-port br0 eth1
sudo ovs-vsctl add-port br0 eth2

# Inspect port STP state
sudo ovs-ofctl show br0

Deep Dive: What STP Actually Does and Why You Need It

Running virtual switches in a lab or cloud environment with OVS almost always means redundant paths somewhere. That’s the right call for availability — but without STP, those redundant paths will eventually trigger a broadcast storm. Every switch floods the frame, it bounces back, gets flooded again. On a 1Gbps link, you can saturate the entire segment in under 3 seconds.

STP (IEEE 802.1D) fixes this by blocking some ports. Only one active path exists between any two bridges at a time. When it fails, STP recalculates and opens an alternate — though classic STP takes 30–50 seconds to converge, long enough to drop active sessions and generate support calls.

STP vs RSTP vs MSTP — Picking the Right One

Open vSwitch supports all three:

  • STP (802.1D) — classic, slow convergence (~50 seconds), avoid in anything production-facing
  • RSTP (802.1w) — rapid convergence (1–2 seconds), backward compatible with STP, the sensible default for most setups
  • MSTP (802.1s) — multiple spanning tree instances, maps VLANs to different trees, best for complex multi-VLAN environments where you need real load balancing across redundant uplinks

RSTP is the right call for most OVS deployments. I’ve run it in production on KVM hypervisor clusters with bonded uplinks — zero broadcast storms, and when an uplink dropped, failover completed in under 2 seconds. It just works.

STP Port States Explained

Each STP-managed port moves through these states:

  • Blocking — receiving BPDUs but not forwarding traffic
  • Listening — participating in root bridge election
  • Learning — building the MAC address table, not yet forwarding
  • Forwarding — fully active, passing traffic normally
  • Disabled — administratively shut down

RSTP can skip straight to forwarding under the right conditions. Edge ports connecting to end devices and point-to-point links between switches go active immediately — no waiting. That’s what cuts convergence from 50 seconds down to under 2.

Root Bridge Election

STP picks a root bridge by comparing Bridge IDs — a combination of priority (default 32768) and MAC address. Lowest wins. Since MAC addresses are outside your control, leaving priority at default means root bridge selection is effectively random. Set it explicitly:

# Lower priority = higher chance of becoming root bridge
# Priority must be a multiple of 4096 (0, 4096, 8192... 61440)
sudo ovs-vsctl set bridge br0 other-config:stp-priority=4096

# Verify
sudo ovs-vsctl get bridge br0 other-config

Advanced Usage: RSTP and MSTP Configuration

Switching to RSTP

OVS treats RSTP as a separate flag from classic STP — you can’t just flip a mode. Enable it explicitly:

# Disable STP first if it was enabled
sudo ovs-vsctl set bridge br0 stp_enable=false

# Enable RSTP
sudo ovs-vsctl set bridge br0 rstp_enable=true

# Confirm
sudo ovs-vsctl get bridge br0 rstp_enable

Tuning Port Path Cost and Priority

Path cost tells STP which route to prefer. Lower cost means the port is preferred for forwarding. Port priority breaks ties when two ports have identical path costs:

# Prefer eth1 over eth2 by giving it a lower path cost
sudo ovs-vsctl set port eth1 other-config:rstp-path-cost=100
sudo ovs-vsctl set port eth2 other-config:rstp-path-cost=200

# Set port priority (lower = preferred, default 128)
sudo ovs-vsctl set port eth1 other-config:rstp-port-priority=64

# Mark a port as edge (connects to servers/VMs — skips learning delay)
sudo ovs-vsctl set port eth1 other-config:rstp-port-admin-edge=true
sudo ovs-vsctl set port eth1 other-config:rstp-port-auto-edge=true

MSTP for Multi-VLAN Environments

MSTP maps VLANs to separate spanning tree instances (MSTIs). VLAN 10 uses one physical path, VLAN 20 uses another — actual load distribution across redundant links, not just failover. In OVS, basic MSTP shares the rstp_enable flag with RSTP:

# Enable RSTP/MSTP
sudo ovs-vsctl set bridge br0 rstp_enable=true

# View current spanning tree topology
sudo ovs-appctl rstp/show br0

Full per-VLAN instance management in OVS typically needs an SDN controller behind it. For standalone OVS, RSTP handles the vast majority of cases without the added complexity.

Inspecting the Spanning Tree Topology

# Detailed RSTP state for all bridges
sudo ovs-appctl rstp/show

# Scoped to one bridge
sudo ovs-appctl rstp/show br0

# Full OVS config overview
sudo ovs-vsctl show

The rstp/show output tells you which bridge is root, port roles (root, designated, alternate), forwarding vs blocking state, and path costs. Start here when something looks wrong.

Practical Tips from the Trenches

1. Always Set Bridge Priority Explicitly

Default priority (32768) means MAC address picks the root — effectively random. Assign priorities deliberately so your most reliable switch always wins:

# Core bridge — root
sudo ovs-vsctl set bridge core-br other-config:rstp-priority=4096

# Distribution bridge — backup root
sudo ovs-vsctl set bridge dist-br other-config:rstp-priority=8192

# Access bridge — never root
sudo ovs-vsctl set bridge access-br other-config:rstp-priority=32768

2. Mark VM/Server Ports as Edge Ports

VM ports and server-facing ports won’t create loops — they connect to endpoints, not other switches. Mark them as edge ports and they skip the STP learning delay entirely, coming up immediately:

# Apply edge port config to all tap interfaces (VM ports)
for port in $(sudo ovs-vsctl list-ports br0 | grep tap); do
  sudo ovs-vsctl set port "$port" other-config:rstp-port-admin-edge=true
  sudo ovs-vsctl set port "$port" other-config:rstp-port-auto-edge=true
done

3. Watch for Topology Change Notifications

Frequent topology changes (TCNs) flush the MAC table and cause temporary flooding. When this keeps happening, something’s wrong — a flapping link, a misconfigured port, or a loop you haven’t caught yet. Watch the logs:

# Watch for STP/RSTP events in real time
sudo tail -f /var/log/openvswitch/ovs-vswitchd.log | grep -i "rstp\|stp\|topology"

# Summarize port roles and states
sudo ovs-appctl rstp/show br0 | grep -E "role|state|cost"

4. Test with a Deliberate Loop

The best sanity check: build a loop manually using veth pairs, then watch OVS block one of the ports on its own:

# Create two bridges
sudo ovs-vsctl add-br br-test1
sudo ovs-vsctl add-br br-test2

# Create two veth pairs (two paths between the bridges = a loop)
sudo ip link add veth1a type veth peer name veth1b
sudo ip link add veth2a type veth peer name veth2b

# Connect both pairs between the two bridges
sudo ovs-vsctl add-port br-test1 veth1a
sudo ovs-vsctl add-port br-test2 veth1b
sudo ovs-vsctl add-port br-test1 veth2a
sudo ovs-vsctl add-port br-test2 veth2b

# Enable RSTP on both
sudo ovs-vsctl set bridge br-test1 rstp_enable=true
sudo ovs-vsctl set bridge br-test2 rstp_enable=true

# Bring up all interfaces
sudo ip link set veth1a up; sudo ip link set veth1b up
sudo ip link set veth2a up; sudo ip link set veth2b up

# Wait a couple of seconds, then check
sudo ovs-appctl rstp/show br-test1

One veth port will show Alternate (blocking), the other Designated (forwarding). The physical loop still exists — STP broke it logically. That’s the confirmation you’re after.

Quick Reference: Common OVS STP Commands

# Enable/disable classic STP
sudo ovs-vsctl set bridge br0 stp_enable=true|false

# Enable/disable RSTP
sudo ovs-vsctl set bridge br0 rstp_enable=true|false

# Set bridge priority (multiple of 4096)
sudo ovs-vsctl set bridge br0 other-config:rstp-priority=4096

# Set port path cost
sudo ovs-vsctl set port eth0 other-config:rstp-path-cost=100

# Show spanning tree state
sudo ovs-appctl rstp/show [bridge-name]

# Check OVS version
sudo ovs-vswitchd --version

STP on OVS isn’t glamorous work. But set priority correctly, mark your VM ports as edge ports, run the loop test once to confirm it’s working, and it’ll quietly keep your network intact while you deal with more interesting problems.

Share: