1 源码
rstplib.1.1.02/topoch.c,topoch.h。
2 拓扑变化规则:
a) 如果一个网桥检测到拓扑变化后,它从所有非边界活动端口传播拓扑变化消息;
b) 如果一个活动端口收到拓扑变化消息后,它从所有其它非边界活动端口传播拓扑变化消
息。另外如果它是指定端口,它还从该指定端口发回一个拓扑变化确认消息;
c) 如果一个指定端口收到一个TCN BPDU,那么它不仅要从所有其它非边界活动端口传播拓扑变化消息,还要从该指定端口传播拓扑变化确认消息;
d) 如果一个端口收到一个拓扑变化确认消息,那么它停止传播拓扑变化消息。
3 代码简析
#ifndef STRONGLY_SPEC_802_1W
/* 很多交换机芯片并不支持在端口粒度上清除学习表项,此情况下,可以将除接收端口外
* 所有非边界端口的学习表信息一次清除
*/
#else
/* 清除单个端口学习信息 */
static Bool flush (STATE_MACH_T *this, char* reason) /* 17.19.9 */
{
register PORT_T* port = this->owner.port;
if (port->operEdge) return True; // 跳过边界端口
/* 清除端口的学习信息,芯片API,具体实现依赖于硬件 */
bret = STP_OUT_flush_lt (port->port_index, port->owner->vlan_id,
LT_FLASH_ONLY_THE_PORT, reason);
}
#endif
Bool STP_topoch_check_conditions (STATE_MACH_T* this)
{
…
switch (this->State) {
case INIT:
return STP_hop_2_state (this, INACTIVE);
case INACTIVE:
/* 活动端口:根端口或指定端口 */
if (port->role == RootPort || port->role == DesignatedPort)
return STP_hop_2_state (this, TCACTIVE);
/* 不活动端口:可选端口、备份端口或弃用端口 */
if ( port->rcvdTc || port->rcvdTcn || port->rcvdTcAck || port->tc || port->tcProp )
return STP_hop_2_state (this, INACTIVE); // 阻止不活动端口传播拓扑变化消息
break;
case TCACTIVE:
if (port->role != RootPort && (port->role != DesignatedPort)) // 活动 -> 不活动
return STP_hop_2_state (this, INIT);
if (port->tc) // 拓扑变化信号,导致拓扑变化消息从所有活动端口传播出去
return STP_hop_2_state (this, DETECTED);
if (port->rcvdTcn) // 拓扑变化通知消息信号(TCN BPDU携带)
return STP_hop_2_state (this, NOTIFIED_TCN);
if (port->rcvdTc) // 拓扑变化消息信号(Config BPDU 或 RST BPDU携带)
return STP_hop_2_state (this, NOTIFIED_TC);
/* 拓扑变化传播信号,从本端口传播拓扑变化消息,只向非边界端口传播 */
if (port->tcProp && !port->operEdge)
return STP_hop_2_state (this, PROPAGATING);
if (port->rcvdTcAck) // 拓扑变化确认消息信号(Config BPDU携带)
return STP_hop_2_state (this, ACKNOWLEDGED);
break;
/* 以下状态皆为无条件转移到TCACTIVE,这样看来,区分这些状态的目的只是为了
* 在TCACTIVE态根据不同的条件执行不同动作,执行完之后马上回到TCACTIVE态
*/
case DETECTED:
return STP_hop_2_state (this, TCACTIVE);
case NOTIFIED_TC:
return STP_hop_2_state (this, TCACTIVE);
…
};
return False;
}
void STP_topoch_enter_state (STATE_MACH_T* this)
{
…
switch (this->State) {
…
case DETECTED: // 检测到拓扑变化
port->tcWhile = newTcWhile (this); // 启动拓扑变化传播定时器
setTcPropBridge (this, "DETECTED"); // 广播拓扑变化消息
port->tc = False; // 清除拓扑变化信号(当前状态的跳入条件,执行完动作后需清除)
break;
case NOTIFIED_TC: // 收到拓扑变化消息
port->rcvdTcn = port->rcvdTc = False;
/* 若为指定端口,则发回一个拓扑变化确认消息 */
if (port->role == DesignatedPort) {
port->tcAck = True;
}
/* 继续向其他所有端口传播拓扑变化消息 */
setTcPropBridge (this, "NOTIFIED_TC");
break;
case PROPAGATING:
port->tcWhile = newTcWhile (this); // 启动拓扑变化传播定时器
flush (this, "topoch PROPAGATING");
port->tcProp = False;
break;
case ACKNOWLEDGED: // 已收到拓扑变化确认消息信号
port->tcWhile = 0;
port->rcvdTcAck = False; // 关闭拓扑变化传播定时器,不再传播变化信息
break;
case NOTIFIED_TCN:
port->tcWhile = newTcWhile (this); // 启动拓扑变化传播定时器
break;
};
}
static void setTcPropBridge (STATE_MACH_T* this, char* reason) /* 17.19.14 */
{
…
/* 向其他所有端口传播拓扑变化消息 */
for (tmp = port->owner->ports; tmp; tmp = tmp->next) {
if (tmp->port_index != port->port_index)
tmp->tcProp = True;
}
/* 清除除了本接收端口之外所有端口的学习信息 */
STP_OUT_flush_lt (port->port_index, port->owner->vlan_id,
LT_FLASH_ALL_PORTS_EXCLUDE_THIS, reason);
}
4 STP vs RSTP
STP是一种集中式算法,一个网桥发现拓扑变化后,首先通知到根网桥,而后再由根网桥负责通知所有其它网桥;
RSTP是一种洪泛式算法,一个网桥发现拓扑变化后,它负责通知与它相连的其它网桥,而其它网桥再负责通知与它们相连的其它网桥,直到传播到所有网桥。