stp: warn when an enabled port cannot receive BPDUs

A port set to admit tagged frames only will never see a BPDU, because
delivery rides the forward action and the ingress pipeline drops untagged
frames before the L2 lookup. The failure is silent and looks like a dead
receive path: the port turns edge after three seconds, the bridge elects
itself root, and nothing hints at the ingress setting. Diagnosing exactly
that cost most of a day on a live switch, with the neighbour provably
transmitting the whole time.

stp_setup() now prints one line per affected port, so the hint lands at
"stp on" and at every config replay on boot. The check runs in its own
loop after the MSTP write: port_ingress_filter_get() reads a register
into sfr_data, which the state-building loop above is still using. The
port number in the message is physical, matching what the ingress
command takes.

doc/stp.md explains why this can happen here and not on a normal bridge,
where BPDUs are consumed before any VLAN classification.

stp.rel stays at DSEG 5 with no OSEG and the image at 10498 bytes of
XDATA.
This commit is contained in:
d00f
2026-08-18 23:28:39 +02:00
committed by d00f
parent 2cf60e177b
commit 7ebb420e7d
3 changed files with 22 additions and 0 deletions
+11
View File
@@ -64,6 +64,17 @@ 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 transparency an unmanaged switch is expected to have, so a surrounding
spanning tree can span *through* this device. 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 <port>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.
Port states live in `RTL837X_MSTP_STATES (0x5310)`, two bits per port: Port states live in `RTL837X_MSTP_STATES (0x5310)`, two bits per port:
`00` disabled, `01` blocking, `10` learning, `11` forwarding. Note that a 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 held in blocking also drops frames the CPU injects into it, so a blocked port
+1
View File
@@ -75,6 +75,7 @@ void port_eee_status(uint8_t port) __banked;
void print_port_ingress_filter_mode(vlan_ingress_mode_t mode) __banked; void print_port_ingress_filter_mode(vlan_ingress_mode_t mode) __banked;
bool port_ingress_vlan_filter_set(__xdata uint8_t port, __xdata bool enabled) __banked; bool port_ingress_vlan_filter_set(__xdata uint8_t port, __xdata bool enabled) __banked;
bool port_ingress_vlan_filter_get(__xdata uint8_t port) __banked; bool port_ingress_vlan_filter_get(__xdata uint8_t port) __banked;
vlan_ingress_mode_t port_ingress_filter_get(__xdata uint8_t port) __banked;
void port_isolate(register uint8_t port, __xdata uint16_t pmask) __banked; void port_isolate(register uint8_t port, __xdata uint16_t pmask) __banked;
uint16_t port_isolation_get(register uint8_t port) __banked; uint16_t port_isolation_get(register uint8_t port) __banked;
+10
View File
@@ -720,6 +720,16 @@ void stp_setup(void) __banked
print_reg(RTL837X_MSTP_STATES); write_char('\n'); print_reg(RTL837X_MSTP_STATES); write_char('\n');
for (stp_i = machine.min_port; stp_i <= machine.max_port; stp_i++) {
if (!(stp_pflags[stp_i] & STP_PF_ENABLED))
continue;
if (port_ingress_filter_get(stp_i) != VLAN_TAGGED)
continue;
print_string("STP: port ");
write_char('0' + machine.log_to_phys_port[stp_i]);
print_string(" admits tagged frames only - BPDUs are untagged and will not arrive\n");
}
/* Seed the carrier bitmap, so turning STP on does not report every /* Seed the carrier bitmap, so turning STP on does not report every
* port that was already down as a fresh topology change. */ * port that was already down as a fresh topology change. */
reg_read_m(RTL837X_REG_LINKS_STS); reg_read_m(RTL837X_REG_LINKS_STS);