How Switches Quietly Agree Not to Set the Network on Fire

Spanning-Tree: one safe path through the loops

I left the last post on a bit of a cliffhanger: all that neat envelope-wrapping quietly assumes your local network isn’t secretly a tangle of cables looping back on themselves, endlessly forwarding the same frame until everything grinds to a halt. That assumption doesn’t hold by luck — a protocol enforces it, and it has a wonderfully literal name. Meet spanning-tree, the quiet hero that stops your switches eating themselves.

A frame with no off-switch

Here’s the detail that makes this whole topic matter. Remember how an IP packet carries a hop count — a little fuse that ticks down at every router and eventually kills a packet that’s wandered too far? An Ethernet frame has no such fuse. None. A frame caught in a loop will circle forever, because nothing inside it ever says “you’ve been going round too long, give up.”

Now add a habit every sensible network has: running two cables between important switches, so that if one fails you don’t lose the link. That redundancy is exactly what you want for resilience — and, thanks to that missing fuse, it’s also a loaded gun pointed straight at your own network.

Why one extra cable can melt everything

Picture three switches cabled into a triangle — a perfectly reasonable, redundant little arrangement. Now something sends a broadcast: a frame addressed to “everyone on this network”, which switches dutifully flood out of every port. Watch what happens.

flowchart LR
  A(["Switch A"]) -->|frame| B(["Switch B"])
  B -->|copy| C(["Switch C"])
  C -->|copy| A

Switch A floods the broadcast to B. B floods it to C. C floods it straight back to A. A has no memory that it has seen this frame before, so it floods it to B again — and we’re off. Within milliseconds that single broadcast has become thousands of copies tearing around the loop: a broadcast storm. Worse, each switch keeps seeing the same sender arrive on different ports, so its address table thrashes back and forth and legitimate traffic can’t get a look in.

Back in the encapsulation post I said a mangled frame just gets binned — no fuss, no resend. That was fine when frames have somewhere to go. But nothing bins a frame that never stops, and a switching loop is the one situation where the network doesn’t gently degrade — it falls over completely, in seconds.

But we can’t just ban the second cable

The obvious fix is simply “don’t create loops” — but that throws away the very thing we wanted. Those redundant links are the whole reason the network survives a cut cable or a dead switch, so banning them isn’t a solution, it’s just a different kind of failure. What we need instead is a way to keep every spare cable plugged in and ready, yet switched off until the moment it’s called for. Keep the redundancy; lose the loop.

Enter spanning-tree: keep the cables, kill the loops

That’s precisely what the Spanning Tree Protocol does. Left running, the switches quietly gossip among themselves — swapping little status messages called BPDUs — and between them build a picture of every link on the network. Then they agree to block just enough of those links to leave exactly one path between any two points. A loop-free shape. A tree.

Tidbit: what’s a BPDU?

BPDU stands for Bridge Protocol Data Unit — a tiny frame switches send to a special multicast address roughly every two seconds, whether or not there’s a loop to worry about. Each one carries the essentials: who the sender thinks the root is, how far away it reckons it is, and the sender’s own ID. That steady heartbeat is how switches elect a root, notice when the topology changes, and agree on which ports to block — and if the BPDUs suddenly stop arriving on a link, a switch takes that as “something moved” and recalculates. It isn’t just spanning-tree’s backbone, either: protections like BPDU Guard, Root Guard and storm control all key off this same chatter, which is why BPDUs quietly underpin a huge amount of how switches keep one another honest.

flowchart TD
  A(["Switch A (root)"]) --- B(["Switch B"])
  A --- C(["Switch C"])
  B -. blocked .- C

The blocked link isn’t unplugged — it’s sitting there, powered up, holding its breath. It carries no normal traffic, so there’s no loop and no storm, but it’s watching, ready to spring into action the instant it’s needed. Same three switches, same three cables, but now there’s precisely one way for a frame to get from any switch to any other. The loop is gone; the spare is still in your back pocket.

How it decides, without the exam cram

You don’t need the cost tables to hold the shape of the logic in your head. It goes like this:

  1. Elect a root. One switch is chosen as the reference point for the whole network — the root bridge. Think of it as the town hall everyone measures their distance from.
  2. Everyone finds their best route to the root. Each other switch works out its shortest path back to the town hall; the port pointing that way becomes its root port.
  3. Each link picks a winner. For every cable, the two ends sort out which of them is closer to the root; that end stays forwarding (the designated port).
  4. Everything left over is blocked. Any port that’s neither a root port nor a designated port quietly stops forwarding — still plugged in, just not passing traffic.

Do that across the whole network and — almost like magic — every loop is broken and a single clean tree remains, all measured outward from that one root bridge. Which raises a question the protocol will happily answer for you if you don’t: who gets to be the root?

Set your root bridge on purpose — or the network votes for you

If you never tell spanning-tree which switch should be root, it decides for itself, and its tie-breaker is delightfully arbitrary: the switch with the lowest bridge ID wins, and with the configurable part left at its default that comes down to the lowest MAC address — which in practice usually means the oldest switch in the building. Very often that’s some ancient access switch shoved in a cupboard on the edge of the network, not your shiny core.

Why does that matter? Because the entire tree is measured from the root. Put the root out on the edge and you get a lopsided mess:

flowchart TB
  subgraph chance["Left to chance: old edge switch wins"]
    E1(["Edge switch (root)"]) --- C1(["Core 1"])
    E1 --- C2(["Core 2"])
    C1 -. blocked .- C2
  end
  subgraph purpose["Set on purpose: core is root"]
    K1(["Core 1 (root)"]) --- K2(["Core 2"])
    K1 --- E2(["Edge switch"])
    K2 -. blocked .- E2
  end

On the left, an old edge switch has accidentally won the election. Now the direct link between your two core switches gets blocked — because as far as the tree is concerned, the “proper” path runs out to the edge and back. Traffic between two core switches sitting side by side in the same rack is suddenly hauled out to a tired old box on the edge, squeezed through its uplink, and dragged back. Congestion, a baffling bottleneck, and a single flaky device now sitting at the centre of your world.

On the right, someone spent thirty seconds telling the core switch to be root. The tree now radiates sensibly from the middle, the fast core link stays live, and it’s the edge switch’s spare link that’s held in reserve — exactly where you’d want it.

Note: decide your root, don’t discover it

Setting the root is one deliberate step: lower the priority on the switch you want at the centre (typically a core switch), and set a second switch as backup root so there’s a sensible successor if the primary dies. It’s the difference between a network whose shape you designed and one whose shape you’ll be reverse-engineering at 2am. If you take a single habit from this whole post, take this one.

The payoff: self-healing

Here’s the reward for all that ceremony. Yank a live cable — or lose a switch entirely — and the network notices within seconds. The switches re-gossip, recalculate the tree, and one of those blocked-but-waiting links is quietly promoted to forwarding. Traffic reroutes onto the spare with nobody lifting a finger. You designed in the redundancy; spanning-tree is what lets you actually use it without burning the place down.

The catch (and the modern version)

Classic spanning-tree is a cautious beast. When a port first comes up it doesn’t just start forwarding — it sits and thinks, listening and learning for a good 30 to 50 seconds, making very sure it won’t create a loop before it commits. Safe, but agonising when it’s the port your laptop is plugged into and you’re standing there waiting to even get an IP address.

That caution is why the modern default is RSTP (Rapid Spanning Tree) — the same core idea, dramatically quicker to settle — and why “edge” ports, the ones you plug PCs and phones into, get special handling so they can skip the wait. Two names worth knowing: PortFast, which lets a known edge port start forwarding immediately, and BPDU Guard, which instantly shuts a port down if it ever hears spanning-tree gossip — because a device speaking BPDUs on a desk port means someone’s plugged in a rogue switch (or looped two wall sockets), and you’d very much like to catch that before it upends your carefully-elected tree.

Warning

When a port is slow to come up, the tempting “fix” is to switch spanning-tree off on it. Don’t. You’re not removing a delay, you’re removing the one thing standing between you and a broadcast storm. The right tools are PortFast (skip the wait safely) and BPDU Guard (catch anyone who abuses it) — never turning the protection off.

A quick family tree of STP flavours

Read a few switch configs and you’ll trip over a small zoo of acronyms. They’re less intimidating than they look — nearly all of them are answering just two questions: one tree for everything, or a separate tree per VLAN? and the slow original, or the rapid rewrite?

  • STP (802.1D) — the original. One tree for the whole switched network. Reliable, and slow.
  • RSTP (802.1w) — the same idea with rapid convergence. The sensible modern baseline.
  • PVST+ / Rapid PVST+ — Cisco’s per-VLAN flavour: every VLAN gets its own spanning-tree. That’s genuinely handy — you can make one switch root for VLAN 10 and another root for VLAN 20, so your redundant links share the load instead of one sitting idle. The cost is overhead: lots of VLANs means lots of trees to compute. (Rapid PVST+ is the fast version, and a common Cisco default.)
  • MST / MSTP (802.1s) — the answer to “I have 300 VLANs and per-VLAN trees are melting my switch CPUs”. It maps many VLANs onto a small handful of shared trees, and it’s vendor-neutral. More to set up, but it scales properly.

For a first mental model that’s plenty: one tree versus many, slow versus rapid. Everything else is detail you can pick up the day a network actually forces you to.

The one-sentence version

Spanning-tree lets you cable in all the redundancy you like, then quietly agrees on a single loop-free path through it and holds the rest in reserve — and if you remember nothing else, remember to choose your root bridge rather than letting a switch from 2009 volunteer for the job.

You’ll have noticed VLANs kept elbowing their way into this post — first the coloured wristband from the encapsulation tidbit, then per-VLAN spanning-trees just now. That’s no accident: VLANs are where switching gets properly clever, carving one physical network into many isolated ones. That’s the next post.