stp: vendor-style per-port config + status (path cost, p2p, designated info)

Bring the Spanning Tree page in line with a typical managed switch's
per-port panel. Configuration gains the full-range path cost (raw
0..200000000, 0 = auto, replacing the old 1000x-scaled byte), a
point-to-point admin control (auto/on/off), and the priority is now a
0..240 step-16 dropdown. A new status table shows, per port, the Port
State, Role, Designated Bridge / Port ID / Cost (learned from received
BPDUs, kept per port and aged via the BPDU age), Operational Edge and
Operational Point-to-Point.

The designated fields fall back to presenting this switch as the
segment's designated bridge when no fresh BPDU has been heard (so a
quiet port shows our own bridge-id, as the vendor UIs do). /stp.json
carries the packed hex fields plus our own MAC for that fallback.

Space: reclaim BANK2 for the above by moving rtl837x_pins to HOME and
compacting leds_dump into a register-address table (~800B); bandwidth
returns to BANK1. No BANK3 - hardware-verified that PSBANK > 2 crashes
this SoC at boot (a bricked unit and an SPI-programmer recovery earlier
today); a warning to that effect is now in rtl837x_lldp.c.

Hardware-verified: cost 200000000 and p2p off round-trip through the CLI
and JSON, the status table populates correctly with STP enabled (all
ports Forwarding/Designated, oper-edge and oper-p2p True), LACP 3f/3f
and the LAN unaffected.

(cherry picked from commit 2ec62072f061dc9e78bc821ba1c297cb6819e206)
This commit is contained in:
d00f
2026-08-04 03:28:07 +02:00
parent 6fcb8ef11f
commit 7ec0286d69
7 changed files with 144 additions and 41 deletions
+52 -5
View File
@@ -535,7 +535,31 @@ void send_lag(void)
* 0 Dis 1 Blk 2 Lrn 3 Fwd), an approximated role, and the per-port config
* (enabled, edge admin/auto/oper, cost/1000, prio, guard, filter, tripped). */
__xdata uint8_t stp_we_root;
__xdata uint8_t pi_i, pi_j; /* shared loop iterators (DSEG relief) */
__xdata uint8_t pi_i, pi_j, pi_j2; /* shared loop iterators (DSEG relief) */
/* Parameter relays in xdata: keeps these helpers off the IRAM overlay */
static __xdata uint32_t pi_u32;
static __xdata uint8_t pi_prio, pi_ext;
static __xdata uint8_t * __xdata pi_mac;
static void u32hex_html(void)
{
/* byte access instead of uint32 shifts: sdcc/mcs51 expands each
* 32-bit shift into a large helper sequence. Little-endian layout. */
__xdata uint8_t *b = (__xdata uint8_t *)&pi_u32;
byte_to_html(b[3]);
byte_to_html(b[2]);
byte_to_html(b[1]);
byte_to_html(b[0]);
}
static void bridge_to_html(void)
{
byte_to_html(pi_prio);
byte_to_html(pi_ext);
for (pi_j2 = 0; pi_j2 < 6; pi_j2++)
byte_to_html(pi_mac[pi_j2]);
}
void send_stp(void)
{
@@ -566,6 +590,9 @@ void send_stp(void)
slen += strtox(outbuf + slen, "\",\"rootMac\":\"");
for (pi_j = 0; pi_j < 6; pi_j++)
byte_to_html(root_bridge.mac[pi_j]);
slen += strtox(outbuf + slen, "\",\"myMac\":\"");
for (pi_j = 0; pi_j < 6; pi_j++)
byte_to_html(uip_ethaddr.addr[pi_j]);
slen += strtox(outbuf + slen, "\",\"cost\":\"");
byte_to_html(root_bridge_cost >> 24);
byte_to_html(root_bridge_cost >> 16);
@@ -599,11 +626,31 @@ void send_stp(void)
itoa_html(3);
slen += strtox(outbuf + slen, ",\"f\":");
itoa_html(stp_pflags[pi_i]);
slen += strtox(outbuf + slen, ",\"cost\":");
itoa_html(stp_pcost[pi_i] / 1000);
slen += strtox(outbuf + slen, ",\"prio\":");
/* path cost (raw hex, full 0..200M range), priority, p2p */
slen += strtox(outbuf + slen, ",\"pc\":\"");
pi_u32 = stp_pcost[pi_i]; u32hex_html();
slen += strtox(outbuf + slen, "\",\"prio\":");
itoa_html(stp_pprio[pi_i]);
slen += strtox(outbuf + slen, "},");
slen += strtox(outbuf + slen, ",\"p2\":");
itoa_html(stp_pp2p[pi_i]);
/* designated info: a freshly heard BPDU wins, else we are the
* segment's designated bridge and report our own values */
stp_we_root = stp_dbridge[pi_i].mac[5] && stp_bpdu_age[pi_i] < (uint16_t)stp_maxage_s * 64;
slen += strtox(outbuf + slen, ",\"db\":\"");
if (stp_we_root) {
pi_prio = stp_dbridge[pi_i].prio; pi_ext = stp_dbridge[pi_i].ext;
pi_mac = stp_dbridge[pi_i].mac;
} else {
pi_prio = stp_prio; pi_ext = 0;
pi_mac = uip_ethaddr.addr;
}
bridge_to_html();
slen += strtox(outbuf + slen, "\",\"dp\":\"");
byte_to_html(stp_we_root ? (stp_dpid[pi_i] >> 8) : stp_pprio[pi_i]);
byte_to_html(stp_we_root ? stp_dpid[pi_i] : (pi_i + 1));
slen += strtox(outbuf + slen, "\",\"dc\":\"");
pi_u32 = stp_we_root ? stp_dcost[pi_i] : root_bridge_cost; u32hex_html();
slen += strtox(outbuf + slen, "\"},");
}
slen -= 1; // remove comma
slen += strtox(outbuf + slen, "]}");