stp: a port without carrier does not become the root port

stp_reselect() took every port with fresh information as a candidate, so a
BPDU credited to a port whose carrier the once-a-second link poll had not
seen yet made that port the root port before the port was set up for it.
A candidate now needs its link bit as well; the poll that sees the carrier
a moment later runs the selection again. Scenario 54.
This commit is contained in:
d00f committed 2026-10-27 22:11:24 +01:00
1 parent b86fd37eaa
commit eb51128ec7
2 files changed
+20 -1

No files matched your search

+1 -1
View File
@@ -660,7 +660,7 @@ static void stp_reselect(void)
continue;
if (!(stp_pflags[stp_j] & STP_PF_ENABLED) || (stp_pflags[stp_j] & STP_PF_ROOTGUARD))
continue;
if (!stp_info_fresh(stp_j))
if (!((stp_link_now >> stp_j) & 1) || !stp_info_fresh(stp_j))
continue;
if (!cmpBytes(stp_dbridge[stp_j].mac, uip_ethaddr.addr, 6))
continue;
+19
View File
@@ -2113,6 +2113,24 @@ static void scen_tc_needs_forwarding(void)
check(stp_tc_count == tc + 1 && flush_count[0] > 0, "now the same TC is passed on");
}
static void scen_root_port_needs_link(void)
{
struct sim_bpdu r;
printf("54. a BPDU credited to a port without carrier does not pick the root port\n");
reset_all();
links_set(1 << 2);
secs(1);
r = root_on(0);
bpdu_in(&r);
tick(2);
check(stp_root_port == 0xff, "the bridge stays its own root");
links_set((1 << 0) | (1 << 2));
secs(1);
check(stp_root_port == 0, "once the carrier is seen the port becomes the root port");
check_state(0, 3, "and forwards");
}
int main(int argc, char **argv)
{
verbose = argc > 1 && argv[1][0] == '-' ? (argv[1][1] == 'd' ? 2 : 1) : 0;
@@ -2169,6 +2187,7 @@ int main(int argc, char **argv)
scen_last_tc();
scen_lag();
scen_tc_needs_forwarding();
scen_root_port_needs_link();
if (failures) {
printf("\n%d check(s) failed\n", failures);
return 1;