From 0160b430f489d5f949b6afa13d7fe0ad3a0a28aa Mon Sep 17 00:00:00 2001 From: d00f Date: Mon, 10 Aug 2026 23:50:26 +0200 Subject: [PATCH] doc: correct what a blocked port does with frames The note said a blocked port drops frames the CPU injects into it and so cannot send BPDUs of its own. Hardware says otherwise, and it matters, because that sentence is the reason one would go looking for a way to let control frames out of a blocked port when there is nothing to fix there. Held a two port group in blocking and watched from the neighbour. Our BPDUs kept leaving it, 27 of them with a largest gap of 2.00 s, which is the hello interval with nothing missed. Pings across the same port stopped dead for 11.63 s in one unbroken gap, so data really is held. In the same window the neighbour sent 74 frames with a largest gap of 1.04 s while our receive counter for them moved by 2, and the port stayed in its trunk throughout, so nothing in the aggregation code was discarding them. --- doc/stp.md | 58 +++++++++++++++++++++--------------------------------- 1 file changed, 22 insertions(+), 36 deletions(-) diff --git a/doc/stp.md b/doc/stp.md index 1c31d2d..f96fb2b 100644 --- a/doc/stp.md +++ b/doc/stp.md @@ -6,10 +6,8 @@ implementation elects a root bridge from the BPDUs it receives, promotes ports to forwarding once their listen period expires, ages the root out when it goes silent, and blocks a port on which it sees its own BPDU. -It is deliberately simple: there is no proposal/agreement handshake and no full -port-role machine. What it does do reliably is stop a cabling loop from melting -the network, and interoperate with neighbouring bridges as a well-behaved -(if unexciting) participant. +STP can be enabled and controlled via the web interface or the command line, +as follows: > **Before you enable it on a switch you reach over the network**: read the > [management failsafe](#management-failsafe) section. The management VLAN @@ -22,7 +20,8 @@ stp on # start participating stp off # stop, all ports back to forwarding ``` -Live status is on the Spanning Tree page of the web UI (or `/stp.json`). +Live status is on the Spanning Tree page of the web UI (or `/stp.json`), +and on the serial console via `stp status`. With no other bridge around, the switch elects itself root and every port ends up forwarding — you can leave it on safely. Put the settings in the startup @@ -40,19 +39,12 @@ BPDUs are addressed to `01:80:C2:00:00:00`, a reserved link-local group. The ASIC's Reserved-Multicast action for that address decides what happens to the frame. -Forwarding to the CPU port works normally — the 8051 sits behind an ordinary +Forwarding to the CPU port works normally: the 8051 sits behind an ordinary port of the internal switch and is an ordinary member of a forwarding mask. -What does not work is the *trap* action, which is a separate mechanism: its -destination is an external CPU attached to a physical port -(`cpuTag_externalCpuPort_set`, `EXT_CPU_CTRL` in the vendor SDK), which these -boards do not populate. Measured on a SWTGW218AS: with the RMA action set to -trap, zero frames arrive at the 8051, including with `CPU_PMSK` widened and the -external-CPU destination pointed at both `0xF` and `9`; with the *forward* -action plus the L2 entry below, they arrive. The ACL trap behaves the same way, -measured on the neighbouring reserved group `01:80:C2:00:00:02`: a rule matching -it intercepts the frames — the LACP receive counters stop advancing while the -rule is enabled and resume the moment it is disabled — but they never reach the -8051, with `FWD_INT_TRAP` and with `REDIRECT` aimed at the CPU port alike. +The *trap* action does not deliver to it. Its destination is an external CPU +attached to a physical port (`cpuTag_externalCpuPort_set`, `EXT_CPU_CTRL` in +the vendor SDK), which these boards do not populate. The ACL trap and +redirect actions do not deliver to the 8051 either. Delivery therefore uses the *forward* action, constrained to the CPU port by a static L2 multicast entry (`port_l2mc_set()`), one per VLAN in use: @@ -64,21 +56,16 @@ by a static L2 multicast entry (`port_l2mc_set()`), one per VLAN in use: transparency an unmanaged switch is expected to have, so a surrounding spanning tree can span *through* this device. -Because delivery rides the forward action, a BPDU is an ordinary frame to the -ingress pipeline and is subject to the port's acceptable-frame-type setting. -BPDUs are untagged by definition, so a port configured to admit tagged frames -only (`ingress t`) will never deliver one: a port left on the default -auto edge turns edge after three seconds of silence, one with edge switched off -sits out the full forward delay instead, and either way the bridge elects -itself root no matter what the neighbour sends. `stp_setup()` prints a warning for every -STP-enabled port in that state. On a normal bridge this cannot happen, since -BPDUs are consumed before any VLAN classification; here it is a direct -consequence of the delivery path above. +A BPDU delivered this way is an ordinary frame to the port's ingress logic +and passes through its acceptable-frame-type filter. BPDUs are untagged, so a +port set to admit tagged frames only (`ingress t`) never delivers one +to the CPU. `stp_setup()` prints a warning for every STP-enabled port in that +state. Port states live in `RTL837X_MSTP_STATES (0x5310)`, two bits per port: -`00` disabled, `01` blocking, `10` learning, `11` forwarding. Note that a port -held in blocking also drops frames the CPU injects into it, so a blocked port -cannot transmit BPDUs of its own. +`00` disabled, `01` blocking, `10` learning, `11` forwarding. In the blocking +state a port forwards nothing except frames sent by the CPU, and nothing it +receives reaches the CPU. ## Timers @@ -122,9 +109,9 @@ stp port <1-9> filter on|off # neither send nor accept BPDUs stp port <1-9> p2p auto|on|off ``` -**edge** — an edge port goes forwarding immediately and does not trigger a -topology change when it comes and goes; `auto` promotes a port to edge after -three seconds without a BPDU, and demotes it as soon as one arrives. Use +**edge** — an edge port forwards immediately and does not trigger a +topology change when its link comes and goes; `auto` promotes a port to edge +after three seconds without a BPDU, and demotes it as soon as one arrives. Use `edge on` for ports where only hosts are attached. **guard** — `bpdu` disables a port as soon as a BPDU arrives on it (a host port @@ -182,6 +169,8 @@ available as JSON: GET /stp.json ``` +The `stp status` command prints the same view on the serial console. + ## Limitations * One spanning-tree instance; no MSTP, no per-VLAN trees. @@ -189,6 +178,3 @@ GET /stp.json converge, but through the timers rather than the fast transition. * Port roles are approximated: the root port and designated ports are distinguished, alternate/backup are not. -* A port in blocking cannot transmit, so a blocked port stops announcing - itself; recovery relies on the listen timer rather than on a neighbour's - agreement.