Implements the standard 802.1D-2004/802.1w configuration surface:
Bridge: priority (0-15 x4096), hello time, max age, forward delay,
force-version (RSTP v2 / STP-compatible v0 Config BPDUs), tx hold
count (per-port per-second BPDU budget).
Per port: enable, admin edge (forwarding immediately - no listen gap),
auto edge (forwarding after 3 s of BPDU silence; DEFAULT, so
host-facing ports no longer take the full forward delay),
path cost (0=auto/20000), port priority, BPDU guard (port disabled
on BPDU receipt), root guard (never accept a better root on the
port), BPDU filter (no BPDUs in or out).
Engine additions: root max-age expiry (reclaim the tree when the root goes
silent), root path cost accounting (rx cost + root-port cost, advertised in
our BPDUs), loop detection (our own BPDU coming back blocks the port for a
listen period), topology-change counter, approximated per-port roles
(Root/Designated/Alternate) for diagnostics.
CLI: "stp prio|hello|maxage|fwd|txhold|version ..." and
"stp port <n> on|off|edge|cost|prio|guard|filter ..." (stp_parse, delegated
from cmd_parser); all forms accepted by the startup-config validator so the
whole configuration persists. /stp.json now reports config + status; the
Spanning Tree page exposes everything with immediate-apply controls and live
state/role columns (edit-in-flight guard against the 2 s refresh).
8051 memory: the module moves to code BANK2; internal-RAM pressure from
cross-bank calls resolved by xdata loop iterators/scratch, __reentrant on
the small helpers, and moving httpd's header-pointer globals to xdata.
Verified on hardware (SWTGW218AS): defaults land per standard; priority and
hello change live; admin-edge ports (the LACP bond uplinks) keep the LAN at
0% loss THROUGH "stp on"; auto-edge ports forward after 3 s; a port that
heard real BPDUs (a VM bridge behind physical port 6) correctly declined
auto-edge, sat out the full listen period and became Designated; tc counts
promotions; we win the root election at priority 16384 vs 32768.
(cherry picked from commit 09a34dc6acdc81ab9cab0727d2f4a59c68131a3e)
"stp on" put every port into blocking (stp_setup, port_timers = "10 s") but
nothing ever counted those timers down: stp_timers() only sent hello BPDUs.
On a network with no other (R)STP bridge - i.e. nobody sends us BPDUs - every
port therefore stayed blocking FOREVER and enabling STP took the whole
network down until "stp off".
- stp_timers(): count port_timers down; when a port's listen period expires
with no better root heard, promote it to forwarding in MSTP_STATES (we are
the designated bridge on that port).
- Calibrate the tick constants to the real stp_timers() rate (~64 Hz: main
loop ~256 Hz / (STP_TICK_DIVIDER+1)): TIME_HELLO 0x200->0x80 is an actual
2 s hello, port_timers 0xa00->0x280 an actual 10 s listen period. Measured
before the fix, ports converged only after ~40 s.
- Move struct bridge into rtl837x_stp.h and export root_bridge/-_cost for
the web UI status endpoint.
Verified on hardware: "stp on" -> ports report Blocking, after the 10 s
listen period all ports promote to Forwarding and LAN connectivity returns;
"stp off" restores forwarding immediately. We elect ourselves root (weRoot)
with no other bridge present.
(cherry picked from commit 8537a15ca254b2122272b20bec7a66426e86df4b)
This reads RSTP configuration packages and updates the
state information about the believed Root-bridge. New
RSTP packages are sent with the updated information.