mirror of
https://github.com/logicog/RTLPlayground.git
synced 2026-09-02 15:02:51 +08:00
stp: pass a received topology change through the switch
The tree structure already crossed the switch by regeneration, but the topology-change information did not: a received TC flag was ignored and a TCN only acknowledged, so bridges behind this one kept stale entries until normal aging. A TC flag in a received BPDU now flushes the other non-edge ports once and arms the transmit window our BPDUs already copy the flag from, refreshed to hello+1 seconds by every further flagged frame so it ends one hello after the neighbour stops, without shortening the longer window a local change arms. A TCN is acknowledged as before and then treated like a local change on that port.
This commit is contained in:
+13
@@ -80,6 +80,16 @@ A port entering the tree spends `fwd` seconds in blocking before it forwards
|
|||||||
(an edge port skips the wait). Root information is discarded after `maxage`
|
(an edge port skips the wait). Root information is discarded after `maxage`
|
||||||
seconds without a BPDU, and the switch then reclaims the root role.
|
seconds without a BPDU, and the switch then reclaims the root role.
|
||||||
|
|
||||||
|
## Topology changes
|
||||||
|
|
||||||
|
A change on a local non-edge port (the link coming or going, a port promoted
|
||||||
|
to forwarding) flushes the addresses learned on it and sets the TC flag in
|
||||||
|
our BPDUs for `maxage + fwd` seconds. A TC flag received in a BPDU is passed
|
||||||
|
on: the switch flushes the other non-edge ports once and keeps the flag in
|
||||||
|
its own BPDUs until one hello after the last flagged frame, so the
|
||||||
|
notification crosses the switch instead of dying at it. A legacy TCN is
|
||||||
|
acknowledged with TCA and then treated like a local change.
|
||||||
|
|
||||||
## Bridge settings
|
## Bridge settings
|
||||||
|
|
||||||
```
|
```
|
||||||
@@ -139,3 +149,6 @@ The `stp status` command prints the same view on the serial console.
|
|||||||
converge, but through the timers rather than the fast transition.
|
converge, but through the timers rather than the fast transition.
|
||||||
* Port roles are approximated: the root port and designated ports are
|
* Port roles are approximated: the root port and designated ports are
|
||||||
distinguished, alternate/backup are not.
|
distinguished, alternate/backup are not.
|
||||||
|
* Topology changes propagate away from the root only: nothing is announced
|
||||||
|
on the root port (no TCN and no BPDUs at all), so bridges upstream rely on
|
||||||
|
their own detection.
|
||||||
|
|||||||
+25
-3
@@ -501,12 +501,14 @@ void stp_in(void) __banked
|
|||||||
|
|
||||||
if (STP_I->bpdu_type == 0x80) {
|
if (STP_I->bpdu_type == 0x80) {
|
||||||
/* TCN: a downstream bridge reports a topology change. Acknowledge it
|
/* TCN: a downstream bridge reports a topology change. Acknowledge it
|
||||||
* on this port so the sender stops repeating; the change itself is
|
* on this port so the sender stops repeating, then treat it like a
|
||||||
* counted (and, once implemented, propagated rootward). */
|
* change of our own: flush the port and carry the TC flag on the
|
||||||
|
* designated ports for the full window. No TCN goes towards the
|
||||||
|
* root, so a legacy root further up keeps its normal aging. */
|
||||||
stp_tx_flags_extra = 0x80; /* Topology Change Acknowledgment */
|
stp_tx_flags_extra = 0x80; /* Topology Change Acknowledgment */
|
||||||
stp_cnf_send(port); /* transmits internally */
|
stp_cnf_send(port); /* transmits internally */
|
||||||
uip_len = 0; /* ...so handle_rx must not TX again */
|
uip_len = 0; /* ...so handle_rx must not TX again */
|
||||||
stp_tc_count++;
|
stp_topology_change(port);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -563,6 +565,26 @@ void stp_in(void) __banked
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Topology Change in transit. The flag arms a short window that our
|
||||||
|
* own BPDUs copy downstream (the TX side already sends TC while
|
||||||
|
* stp_tc_while runs) and that each further flagged BPDU refreshes, so
|
||||||
|
* it expires one hello after the neighbour stops - without shortening
|
||||||
|
* the long window a local change may have armed. The flush runs once,
|
||||||
|
* on the arming edge: everything learned on the other non-edge ports
|
||||||
|
* may sit behind the moved link and must be relearned. */
|
||||||
|
if (STP_I->flags & 0x01) {
|
||||||
|
if (!stp_tc_while) {
|
||||||
|
uint8_t i;
|
||||||
|
stp_tc_count++;
|
||||||
|
for (i = machine.min_port; i <= machine.max_port; i++)
|
||||||
|
if (i != port && (stp_pflags[i] & STP_PF_ENABLED)
|
||||||
|
&& !(stp_pflags[i] & STP_PF_OPEREDGE))
|
||||||
|
port_l2_forget_port(i);
|
||||||
|
}
|
||||||
|
if (stp_tc_while < ((uint16_t)stp_hello_s + 1) * STP_HZ)
|
||||||
|
stp_tc_while = ((uint16_t)stp_hello_s + 1) * STP_HZ;
|
||||||
|
}
|
||||||
|
|
||||||
stp_record_designated(port);
|
stp_record_designated(port);
|
||||||
|
|
||||||
/* Better root than the one we know? The identifier is priority, system
|
/* Better root than the one we know? The identifier is priority, system
|
||||||
|
|||||||
Reference in New Issue
Block a user