stp: send BPDUs with a per port source address

802.1D puts the port's own address in the source field and the bridge
address only in the Bridge Identifier. We used the bridge address for
both, and on this hardware that costs the management path.

Measured on a SWTGW218AS: the ASIC learns the source address of a frame
addressed to 01:80:c2:00:00:00, and the bridge's own address is not
exempt. A BPDU that leaves a blocked port and comes back on a forwarding
one therefore moves the management address off the CPU port, and frames
for it are then sent down that port instead of to the CPU. Traffic
between other stations is unaffected, which is what makes it look like
the CPU port has been blocked.

The derived address keeps the bridge address and sets the locally
administered bit, so it differs from the bridge address in the first
octet for any globally assigned OUI, with the port number in the low
nibble of the last octet. Nothing here reads the source address of a
received BPDU; the loop check compares the Bridge Identifier.
This commit is contained in:
d00f
2026-08-18 23:31:05 +02:00
parent 810db48a00
commit 85d1d7520a
+2
View File
@@ -381,6 +381,8 @@ void stp_cnf_send(uint8_t port) __reentrant
stp_tx_flags_extra = 0; stp_tx_flags_extra = 0;
memcpy(STP_O->src_addr, uip_ethaddr.addr, 6); memcpy(STP_O->src_addr, uip_ethaddr.addr, 6);
STP_O->src_addr[0] |= 0x02;
STP_O->src_addr[5] = (uip_ethaddr.addr[5] & 0xf0) | port;
memcpy(STP_O->root.mac, root_bridge.mac, 6); memcpy(STP_O->root.mac, root_bridge.mac, 6);
memcpy(STP_O->bridge.mac, uip_ethaddr.addr, 6); memcpy(STP_O->bridge.mac, uip_ethaddr.addr, 6);