Decoding an 802.1D Configuration BPDU field by field, what does each field mean, and which fields does a relaying bridge rewrite?
answer
- the root's facts versus the sender's
- a cost that grows per hop
- an age that grows per hop
- timers copied, not chosen
- times in 1/256 of a second
basics
~20 sA Configuration BPDU carries the root ID, the sender's root path cost, bridge ID and port ID, message age, the root's three timers and the TC/TCA flags. Relaying bridges copy the root ID and timers but rewrite cost, sender IDs and age.
solid answer
~50 sA Configuration BPDU is 35 octets: protocol identifier `0x0000`, version `0`, type `0x00`, a **Flags** octet (TC in the lowest bit, TCA in the highest), then the **Root Identifier** (8 octets: 2 of priority, 6 of MAC), the **Root Path Cost** (4 octets), the sender's **Bridge Identifier** (8), its **Port Identifier** (2), and four 2-octet times in units of 1/256 s: **Message Age**, **Max Age**, **Hello Time**, **Forward Delay**. When an 802.1D bridge relays the root's information from its root port onto a designated port, it copies the root ID and the three timers, adds its root port's path cost to the cost, puts in its own bridge ID and the sending port's ID, and increases Message Age. The TC flag is passed on from the root; TCA is set only to acknowledge a TCN on that port.
code
pseudocode · 16 lines// Configuration BPDU sent on a designated port (802.1D-1998)
best = info_stored_on(root_port) // what the root port last received
out.protocol_id = 0x0000
out.version = 0
out.type = 0x00 // Configuration
out.root_id = best.root_id // copied
out.root_cost = best.root_cost + path_cost(root_port) // 4 + 4 = 8
out.bridge_id = my_bridge_id // replaced
out.port_id = port_id(designated_port) // 0x8005
out.message_age = best.message_age + increment // 1 s -> about 2 s
out.max_age = best.max_age // the root's timers, copied
out.hello_time = best.hello_time
out.forward_delay = best.forward_delay
out.flags.tc = best.flags.tc // the root's TC, passed on
out.flags.tca = owes_tcn_ack(designated_port)
send(designated_port, out)go deeper
Recall the main fields: root ID, root path cost, sender bridge ID, port ID, and the timers that ride along.
Walk a received BPDU through a relaying bridge: which fields it copies, which it rewrites, and how cost and age grow per hop.
Use a packet capture to diagnose: an unexpected root ID, a cost that does not add up, or a timer that differs from the one configured all point to a specific misconfiguration.
Discuss why carrying the root's timers and an age in every BPDU makes one bridge's configuration govern the whole layer-2 domain, and what that means for change control.
## The layout A **Configuration BPDU** is the message through which every bridge in an **IEEE 802.1D** spanning tree learns who the root is, how far away it is, and which timers to run. Its format is the IEEE standard's (the IETF's Bridge MIB, RFC 4188, restates the values it carries but not the frame). Here is one, decoded, as a bridge might receive it from a neighbour one hop from the root. MAC addresses are from the documentation range `00-00-5E-00-53-00` to `00-00-5E-00-53-FF` (RFC 9542). | Offset | Octets | Field | Example (hex) | Meaning | |---|---|---|---|---| | 0 | 2 | Protocol Identifier | `00 00` | spanning tree | | 2 | 1 | Protocol Version | `00` | 802.1D; RSTP uses `2` | | 3 | 1 | BPDU Type | `00` | Configuration; a TCN is `0x80` | | 4 | 1 | Flags | `01` | TC set, TCA clear | | 5 | 8 | Root Identifier | `80 00 00 00 5E 00 53 01` | root: priority 32,768, MAC ...53-01 | | 13 | 4 | Root Path Cost | `00 00 00 04` | sender's cost to the root: 4 | | 17 | 8 | Bridge Identifier | `80 00 00 00 5E 00 53 02` | the sender: priority 32,768, MAC ...53-02 | | 25 | 2 | Port Identifier | `80 02` | port priority 128, port number 2 | | 27 | 2 | Message Age | `01 00` | 256/256 = 1 s | | 29 | 2 | Max Age | `14 00` | 5,120/256 = 20 s | | 31 | 2 | Hello Time | `02 00` | 512/256 = 2 s | | 33 | 2 | Forward Delay | `0F 00` | 3,840/256 = 15 s | The offsets add up to 35 octets. Two details trip people up: - **Times are in units of 1/256 of a second** on the wire. The Bridge MIB reports the same timers in hundredths of a second, so `0x1400` read as centiseconds would wrongly give 51.2 s. - **Identifiers are compared as numbers**, priority first. RFC 4188 describes the bridge ID as 8 octets whose first two are the settable priority; with IEEE 802.1t that priority moves in steps of 4,096. How the comparison elects a root is a separate subject. ## Which fields describe the root, and which describe the sender The fields split cleanly into two groups: - **The root's facts, copied unchanged downstream:** Root Identifier, Max Age, Hello Time, Forward Delay, and the TC flag. - **The sender's facts, rewritten at every hop:** Root Path Cost, Bridge Identifier, Port Identifier, Message Age, and TCA. Together, root ID, root path cost, sender bridge ID and sender port ID form the **priority vector** a receiving bridge compares, field by field and lowest first, to decide which BPDU is better. How that comparison picks root and designated ports belongs to port-role selection. ## What a relaying bridge rewrites Under 802.1D-1998, a non-root bridge sends Configuration BPDUs on its designated ports when fresh information arrives on its root port. Suppose the bridge above receives this BPDU on its root port, whose path cost is 4 (the 802.1D-1998 short value for 1 Gb/s, the IEEE's), and relays it on its port 5: 1. **Root Identifier** — copied: `80 00 00 00 5E 00 53 01`. 2. **Root Path Cost** — received cost plus its own root port's cost: 4 + 4 = **8**. 3. **Bridge Identifier** — replaced with its own ID. 4. **Port Identifier** — replaced with the sending port's ID, here `80 05`. 5. **Message Age** — increased, here to about 2 s; each relay adds a small increment. 6. **Max Age, Hello Time, Forward Delay** — copied from the root's values. 7. **Flags** — TC copied from what the root sent; TCA set only on a port that owes a TCN an acknowledgement. So **Message Age** measures roughly how long ago, and across how many relays, the root issued this information. A bridge discards stored information when its age reaches **Max Age**. ## Why the design looks like this - Copying the root's timers means one bridge, the root, sets the pace for the whole tree. - Rewriting cost and sender identity lets each receiver compare *paths*, not just roots. - Carrying age lets old information die everywhere at roughly the same moment, not hop by hop. ## What changed with RSTP An RSTP bridge (IEEE 802.1w, now in 802.1D-2004) sends a 36-octet BPDU with version `2` and type `0x02`; it adds a Version 1 Length octet and uses the six flag bits between TC and TCA for its handshake and port role. The priority vector and timer fields keep the same places.
- Why does Message Age grow at each hop instead of being reset by every relaying bridge?Message Age measures how old the root's information is, not how old this copy is. If each bridge reset it, information could circulate indefinitely after the root died. Because it grows, information stored anywhere reaches Max Age at roughly the same moment, and a bridge too many hops away from the root receives information that is already almost expired, which is why Max Age also limits the tree's diameter.
- A captured BPDU shows Protocol Version 2 and BPDU type 0x02. What are you looking at?An RSTP BPDU (IEEE 802.1w, folded into 802.1D-2004), not an 802.1D Configuration BPDU. It is 36 octets, adds a Version 1 Length octet, and uses the six flag bits between TC and TCA for RSTP's proposal, agreement and port-role signalling. RFC 4318 lists the version values stpCompatible(0) and rstp(2).
saying these in an interview costs you the question
- Each bridge forwards the root's BPDU unchanged to the next switch.
- Root Path Cost is just the cost of the link the BPDU arrived on.
- The Bridge Identifier field always holds the root's bridge ID.
- Every bridge advertises its own configured Hello, Max Age and Forward Delay.
- BPDU times are carried in milliseconds.