stp: management failsafe (commit-confirm) + bounded NIC waits

Enabling STP on a bridge whose management rides an in-band VLAN can cut
off that very management - and not only by our own blocking: on this
network the upstream TP-Link Easy Smart switch's "loop prevention"
reacted to our BPDU hellos by blocking ITS port towards us while our
ASIC was all-forwarding, isolating the whole segment until a power
cycle. Recoverable only by going quiet.

Add a commit-confirm watchdog: while STP is enabled, any HTTP request
re-arms a countdown ("stp failsafe <seconds>", default 180, 0 disables);
if management stays silent for the whole window, STP disables itself,
which also stops BPDU TX so a neighbour's loop protection can release
its block. The web UI polls /stp.json every 2 s, so an open browser
naturally keeps the watchdog re-armed. The trip is reported via
/stp.json (fs, fsT) and as a warning on the Spanning Tree page.

Deliberately not conditioned on our own MSTP port states - the incident
above proves the uplink can be dead while every local port forwards.

Also bound the NIC DMA busy-waits (nic_tx_packet, nic_rx_header,
nic_rx_packet): an unbounded spin on SFR_NIC_CTRL freezes the entire
main loop (timers, HTTP, ARP) if the ASIC ever fails to consume a
transfer; give up after ~65k polls and drop the frame instead.

Hardware-verified end to end: with priority 15 against a live RSTP
bridge the uplink died 6 s after "stp on" and the network recovered BY
ITSELF 66 s later (trip at 45 s + neighbour release), fsT=1, LACP and
LAN intact. Telemetry via syslog-to-edge-port host confirmed the full
chain: countdown 44->4, trip, hello TX stopping at the trip.

(cherry picked from commit 1fa9775156fd6d7ebfdda2382f73430b86601230)
This commit is contained in:
d00f
2026-08-04 03:26:10 +02:00
parent fbd19b2b4d
commit 6fcb8ef11f
8 changed files with 80 additions and 7 deletions
+5
View File
@@ -20,6 +20,9 @@
#pragma constseg BANK1
extern volatile __xdata uint8_t sfr_data[4];
extern volatile __xdata uint32_t ticks;
/* 200 Hz free-running tick, owned by rtlplayground.c */
volatile __xdata uint8_t mgmt_alive; /* consumed by the STP management failsafe */
extern __code uint8_t * __code hex;
extern __code struct f_data f_data[];
extern __code char * __code mime_strings[];
@@ -547,6 +550,8 @@ void httpd_appcall(void)
__xdata struct httpd_state * __xdata s = &(uip_conn->appstate);
dbg_char('P');
if (uip_newdata())
mgmt_alive = 1; /* any HTTP activity proves management still works (STP failsafe) */
#ifdef DEBUG
if (uip_newdata())
write_char('N');
+4
View File
@@ -556,6 +556,10 @@ void send_stp(void)
itoa_html(stp_fwddelay_s);
slen += strtox(outbuf + slen, ",\"txhold\":");
itoa_html(stp_txhold);
slen += strtox(outbuf + slen, ",\"fs\":");
itoa_html(stp_failsafe_s);
slen += strtox(outbuf + slen, ",\"fsT\":");
itoa_html(stp_failsafe_tripped);
slen += strtox(outbuf + slen, ",\"rootPrio\":\"");
byte_to_html(root_bridge.prio);
byte_to_html(root_bridge.ext);