mirror of
https://github.com/logicog/RTLPlayground.git
synced 2026-10-29 17:54:14 +08:00
stp: pass a topology change on only from a forwarding port
stp_in() propagated the TC flag of any BPDU that did not arrive on an alternate port, and acknowledged and propagated a TCN from any port, so a port still in its listen period or held discarding in a dispute could flush the addresses of every other port and move the topology change counter. 802.1D-2004 17.31 keeps the Topology Change machine in LEARNING until the port forwards and drops rcvdTc and rcvdTcn there. Both paths now ask for the forwarding state first; an alternate port is discarding, so the old check is covered by the new one. Scenario 53 plays a TC flag and a TCN into a port that is still discarding, and then into the same port once it forwards. Scenario 51 used a TCN on a port one tick short of its edge transition as the trigger for the clock it tests; it now waits for the transition.
This commit is contained in:
1 parent
b92a773cad
commit
b86fd37eaa
3 files changed
+60
-5
No files matched your search
+4
-3
@@ -154,9 +154,10 @@ BPDUs toward the root, so the change reaches the rest of the network. With
|
|||||||
`stp version stp` the root port sends TCN instead, until a Config BPDU with
|
`stp version stp` the root port sends TCN instead, until a Config BPDU with
|
||||||
TCA comes back.
|
TCA comes back.
|
||||||
|
|
||||||
A TC flag received on a root or designated port is passed on the same way to
|
A TC flag received on a forwarding root or designated port is passed on the
|
||||||
the other ports, not back to the port it came in on. A legacy TCN is
|
same way to the other ports, not back to the port it came in on; a port that
|
||||||
acknowledged with TCA and then treated like a received TC. A port that turns
|
is still discarding or learning drops it. A legacy TCN is acknowledged with
|
||||||
|
TCA and then treated like a received TC. A port that turns
|
||||||
alternate, loses its link, or is blocked for a loop flushes its own addresses
|
alternate, loses its link, or is blocked for a loop flushes its own addresses
|
||||||
without raising a topology change, and an edge port never raises one.
|
without raising a topology change, and an edge port never raises one.
|
||||||
|
|
||||||
|
|||||||
+3
-1
@@ -1018,6 +1018,8 @@ void stp_in(void) __banked
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
if (STP_I->bpdu_type == BPDU_TYPE_TCN) {
|
if (STP_I->bpdu_type == BPDU_TYPE_TCN) {
|
||||||
|
if (stp_state_get(port) != 0b11)
|
||||||
|
return;
|
||||||
stp_tx_flags_extra = BPDU_FLAG_TCACK;
|
stp_tx_flags_extra = BPDU_FLAG_TCACK;
|
||||||
stp_cnf_send(port);
|
stp_cnf_send(port);
|
||||||
uip_len = 0;
|
uip_len = 0;
|
||||||
@@ -1063,7 +1065,7 @@ void stp_in(void) __banked
|
|||||||
|
|
||||||
if ((STP_I->flags & BPDU_FLAG_TCACK) && port == stp_root_port)
|
if ((STP_I->flags & BPDU_FLAG_TCACK) && port == stp_root_port)
|
||||||
stp_tcwhile[port] = 0;
|
stp_tcwhile[port] = 0;
|
||||||
if ((STP_I->flags & BPDU_FLAG_TC) && !((stp_alt >> port) & 1) && stp_tc_prop(port))
|
if ((STP_I->flags & BPDU_FLAG_TC) && stp_state_get(port) == 0b11 && stp_tc_prop(port))
|
||||||
stp_tc_count++;
|
stp_tc_count++;
|
||||||
|
|
||||||
if ((stp_pflags[port] & STP_PF_ROOTGUARD)
|
if ((stp_pflags[port] & STP_PF_ROOTGUARD)
|
||||||
|
|||||||
+53
-1
@@ -1988,7 +1988,7 @@ static void scen_last_tc(void)
|
|||||||
links_set(1 << 8);
|
links_set(1 << 8);
|
||||||
tcn = root_on(8);
|
tcn = root_on(8);
|
||||||
tcn.legacy = 2;
|
tcn.legacy = 2;
|
||||||
secs(3);
|
secs(4);
|
||||||
before = stp_tc_count;
|
before = stp_tc_count;
|
||||||
bpdu_in(&tcn);
|
bpdu_in(&tcn);
|
||||||
check(stp_tc_count != before, "a TCN moves the topology change counter");
|
check(stp_tc_count != before, "a TCN moves the topology change counter");
|
||||||
@@ -2062,6 +2062,57 @@ static void scen_lag(void)
|
|||||||
check(port_state(1) == 1 && port_state(2) == 1, "the ports start over discarding");
|
check(port_state(1) == 1 && port_state(2) == 1, "the ports start over discarding");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void scen_tc_needs_forwarding(void)
|
||||||
|
{
|
||||||
|
struct sim_bpdu r;
|
||||||
|
struct sim_bpdu worse = {
|
||||||
|
.port = 2, .root_prio = 0x40, .root_cost = 200000, .br_prio = 0x80, .port_id = 4, .flags = 0x3d
|
||||||
|
};
|
||||||
|
struct sim_bpdu tcn;
|
||||||
|
int tc;
|
||||||
|
|
||||||
|
printf("53. a topology change heard on a port that does not forward yet is not passed on\n");
|
||||||
|
reset_all();
|
||||||
|
stp_pflags[2] &= ~STP_PF_AUTOEDGE;
|
||||||
|
links_set((1 << 0) | (1 << 2));
|
||||||
|
secs(1);
|
||||||
|
r = root_on(0);
|
||||||
|
for (int i = 0; i < 3; i++) {
|
||||||
|
bpdu_in(&r);
|
||||||
|
secs(2);
|
||||||
|
}
|
||||||
|
check_state(0, 3, "root port 1 forwards");
|
||||||
|
check_state(2, 1, "port 3 is still discarding");
|
||||||
|
memcpy(worse.root_mac, ROOT_MAC, 6);
|
||||||
|
memcpy(worse.br_mac, PEER_MAC, 6);
|
||||||
|
memset(flush_count, 0, sizeof(flush_count));
|
||||||
|
tc = stp_tc_count;
|
||||||
|
bpdu_in(&worse);
|
||||||
|
tick(2);
|
||||||
|
check(stp_tc_count == tc, "a TC flag on the discarding port raises no topology change");
|
||||||
|
check(flush_count[0] == 0, "and the root port keeps its addresses");
|
||||||
|
tcn = worse;
|
||||||
|
tcn.legacy = 2;
|
||||||
|
memset(last_tx, 0, sizeof(last_tx));
|
||||||
|
bpdu_in(&tcn);
|
||||||
|
tick(2);
|
||||||
|
check(stp_tc_count == tc, "a TCN on the discarding port raises none either");
|
||||||
|
check((last_tx[2].flags & 0x80) == 0, "and is not acknowledged");
|
||||||
|
for (int i = 0; i < 16; i++) {
|
||||||
|
bpdu_in(&r);
|
||||||
|
secs(2);
|
||||||
|
}
|
||||||
|
check_state(2, 3, "port 3 forwards after both forward delays");
|
||||||
|
for (int i = 0; i < 2; i++) {
|
||||||
|
bpdu_in(&r);
|
||||||
|
secs(2);
|
||||||
|
}
|
||||||
|
tc = stp_tc_count;
|
||||||
|
bpdu_in(&worse);
|
||||||
|
tick(2);
|
||||||
|
check(stp_tc_count == tc + 1 && flush_count[0] > 0, "now the same TC is passed on");
|
||||||
|
}
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
verbose = argc > 1 && argv[1][0] == '-' ? (argv[1][1] == 'd' ? 2 : 1) : 0;
|
verbose = argc > 1 && argv[1][0] == '-' ? (argv[1][1] == 'd' ? 2 : 1) : 0;
|
||||||
@@ -2117,6 +2168,7 @@ int main(int argc, char **argv)
|
|||||||
scen_bpdu_handling();
|
scen_bpdu_handling();
|
||||||
scen_last_tc();
|
scen_last_tc();
|
||||||
scen_lag();
|
scen_lag();
|
||||||
|
scen_tc_needs_forwarding();
|
||||||
if (failures) {
|
if (failures) {
|
||||||
printf("\n%d check(s) failed\n", failures);
|
printf("\n%d check(s) failed\n", failures);
|
||||||
return 1;
|
return 1;
|
||||||
|
|||||||
Reference in new issue
Block a user