mirror of
https://github.com/logicog/RTLPlayground.git
synced 2026-08-30 14:52:51 +08:00
stp: keep the root port quiet and relay the message age
Two protocol-correctness fixes on the information we advertise: Only designated ports announce periodically. The root port is where our root information arrives; sending it back there feeds the upstream bridge its own data and makes us look like a competing designated bridge on that segment. Relay the message age instead of always claiming zero. A bridge increments the received age by one second per hop, so downstream neighbours can age the information out; advertising 0 forever made our BPDUs look eternally fresh no matter how stale the root information was. Age stays 0 while we are the root ourselves.
This commit is contained in:
+16
-2
@@ -96,6 +96,7 @@ __xdata uint16_t stp_sec_tick; /* 1 s window for the tx budget */
|
|||||||
__xdata uint8_t stp_scratch;
|
__xdata uint8_t stp_scratch;
|
||||||
__xdata uint8_t stp_tx_flags_extra; /* one-shot flags OR-ed into the next BPDU (TCA) */
|
__xdata uint8_t stp_tx_flags_extra; /* one-shot flags OR-ed into the next BPDU (TCA) */
|
||||||
__xdata uint16_t stp_rxlen; /* received frame length, saved before uip_len is consumed */
|
__xdata uint16_t stp_rxlen; /* received frame length, saved before uip_len is consumed */
|
||||||
|
__xdata uint8_t stp_msg_age; /* message age of the root info we hold, seconds */
|
||||||
__xdata uint8_t stp_i; /* shared loop iterator (DSEG relief) */
|
__xdata uint8_t stp_i; /* shared loop iterator (DSEG relief) */
|
||||||
__xdata uint32_t stp_cost_scratch;
|
__xdata uint32_t stp_cost_scratch;
|
||||||
|
|
||||||
@@ -191,6 +192,7 @@ static void stp_claim_root(void)
|
|||||||
memcpy(root_bridge.mac, uip_ethaddr.addr, 6);
|
memcpy(root_bridge.mac, uip_ethaddr.addr, 6);
|
||||||
root_bridge_cost = 0;
|
root_bridge_cost = 0;
|
||||||
stp_root_port = 0xff;
|
stp_root_port = 0xff;
|
||||||
|
stp_msg_age = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -255,7 +257,11 @@ void stp_cnf_send(uint8_t port) __reentrant
|
|||||||
|
|
||||||
STP_O->port_prio = stp_pprio[port];
|
STP_O->port_prio = stp_pprio[port];
|
||||||
STP_O->port_id = port + 1;
|
STP_O->port_id = port + 1;
|
||||||
STP_O->age = 0x00; // FIXME: This only works because we do not use HTONS and the values are in 1/256 seconds
|
/* Message age, incremented by one second per bridge we relay through.
|
||||||
|
* The timer fields are in 1/256 s on the wire, and sdcc stores uint16
|
||||||
|
* little-endian, so assigning the plain second count lands the value in
|
||||||
|
* the high (seconds) octet - see age_max/hello/fwd_delay below. */
|
||||||
|
STP_O->age = (stp_root_port == 0xff) ? 0 : (uint16_t)(stp_msg_age + 1);
|
||||||
STP_O->age_max = stp_maxage_s;
|
STP_O->age_max = stp_maxage_s;
|
||||||
STP_O->hello = stp_hello_s;
|
STP_O->hello = stp_hello_s;
|
||||||
STP_O->fwd_delay = stp_fwddelay_s;
|
STP_O->fwd_delay = stp_fwddelay_s;
|
||||||
@@ -380,6 +386,9 @@ void stp_in(void) __banked
|
|||||||
|
|
||||||
/* Refresh our cost to the root when the update comes in on the root port */
|
/* Refresh our cost to the root when the update comes in on the root port */
|
||||||
if (port == stp_root_port) {
|
if (port == stp_root_port) {
|
||||||
|
/* Age of the information we now hold (see the TX note on the wire
|
||||||
|
* format); saturate rather than wrap on absurd input. */
|
||||||
|
stp_msg_age = (STP_I->age > 254) ? 254 : (uint8_t)STP_I->age;
|
||||||
stp_cost_scratch = STP_I->root_path_cost;
|
stp_cost_scratch = STP_I->root_path_cost;
|
||||||
/* big-endian on the wire */
|
/* big-endian on the wire */
|
||||||
root_bridge_cost = ((stp_cost_scratch & 0xff) << 24)
|
root_bridge_cost = ((stp_cost_scratch & 0xff) << 24)
|
||||||
@@ -433,7 +442,12 @@ void stp_timers(void) __banked
|
|||||||
port_hello[stp_i]--;
|
port_hello[stp_i]--;
|
||||||
if (!port_hello[stp_i]) {
|
if (!port_hello[stp_i]) {
|
||||||
port_hello[stp_i] = (uint16_t)stp_hello_s * STP_HZ;
|
port_hello[stp_i] = (uint16_t)stp_hello_s * STP_HZ;
|
||||||
stp_cnf_send(stp_i);
|
/* Only designated ports announce periodically: the root port is
|
||||||
|
* where our own root information comes FROM, and echoing it back
|
||||||
|
* there just feeds the upstream bridge its own data (and looks
|
||||||
|
* like a competing designated bridge on that segment). */
|
||||||
|
if (stp_i != stp_root_port)
|
||||||
|
stp_cnf_send(stp_i);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Promote a port out of blocking once its listen period expires
|
/* Promote a port out of blocking once its listen period expires
|
||||||
|
|||||||
Reference in New Issue
Block a user