1 源码
rstplib.1.1.02/rolesel.c, rolesel.h
2 功能
每个网桥拥有一个端口角色选择状态机,负责为每个端口分配角色。
3 端口角色
RSTP中端口角色有如下几种:根端口、指定端口、可选端口、备份端口、弃用端口。
端口角色的分配由以下因素决定:
a) 每个网桥的唯一网桥ID(BridgeIdentifier);
b) 每个网桥端口的路径代价(PortPathCost);
c) 每个网桥端口的端口ID(portId)。
3.1 基础概念:
根网桥:所有网桥中网桥ID最小的那个网桥是该桥接LAN的根网桥。
路径代价:帧经过该端口要花费的代价是该端口的路径代价(可配置)。
根路径代价(网桥):从根网桥到该网桥的最小代价路径中,所有接收帧的端口(即根端口)的路径代价之和是该网桥的根路径代价,根网桥的根路径代价为0。
指定网桥(LAN):接在LAN上的所有网桥中根路径代价最小的那个网桥是该LAN的指定网桥。
根路径代价(LAN): LAN的根路径代价等于该LAN的指定网桥的根路径代价
3.2 端口角色概念:
根端口(网桥):从到根网桥的最小代价路径接收帧的那个端口就是该网桥的根端口,根端口提供了到达根网桥的一条最优路径。
指定端口(LAN):将LAN连到指定网桥的端口是该LAN的指定端口。
备份端口:如果一个网桥是一个LAN的指定网桥,那么除了指定端口外,该网桥的所有接在该LAN上的可工作端口都是备份端口,备份端口是指定端口的一个备份。
可选端口:如果一个端口是可工作的,并且它不是根端口、指定端口或备份端口,那么它就是可选端口,可选端口提供了到达根网桥的另一条可选路径。
弃用端口(可配置):如果该端口是不可工作的(MAC_Operational==FALSE),那么该端口是弃用端口。
当桥接LAN的拓扑结构稳定后:每个LAN仅有一个指定端口,除了根网桥外每个网桥只有一个根端口。
4 代码简析
4.1 状态定义
#define STATES { /
/* 初始化进入INIT_BRIDGE状态 */
CHOOSE(INIT_BRIDGE), /
/* 计算端口角色并为每个端口分配角色,如果在计算过程中任一端口的reselect又被置位,那么计算过程立刻将重新开始 */
CHOOSE(ROLE_SELECTION), /
}
4.2 STP_rolesel_enter_state
负责执行切换到某角色后的固定动作。
void STP_rolesel_enter_state (STATE_MACH_T* this)
{
STPM_T* stpm;
stpm = this->owner.stpm; // 指向所属网桥
switch (this->State) {
case BEGIN:
case INIT_BRIDGE:
updtRoleDisableBridge (stpm); // 使本网桥所有端口的selectedRole = DisabledPort
break;
case ROLE_SELECTION:
clearReselectBridge (stpm); // 使本网桥所有端口的reselect = FALSE
updtRolesBridge (this); // 为本网桥所有端口分配角色
setSelectedBridge (stpm); // 当本网桥所有端口的reselect == FALSE时,使本网桥所有端口的selected = TRUE
break;
}
}
selectedRole:选择的角色,端口角色选择状态机为本端口新选择的角色。
reselect:重选端口角色信号,=TRUE:当rcvBpdu()返回SuperiorDesignatedMsg时或infoIs == Disabled或infoIs == Aged。
selected:角色选择完成标志。
4.3 STP_rolesel_check_conditions
检查倒换条件并进行状态倒换。
Bool STP_rolesel_check_conditions (STATE_MACH_T* s)
{
STPM_T* stpm;
register PORT_T* port;
switch (s->State) {
/* BEGIN -> INIT_BRIDGE -> ROLE_SELECTION 皆为无条件倒换 */
case BEGIN:
return STP_hop_2_state (s, INIT_BRIDGE);
case INIT_BRIDGE:
return STP_hop_2_state (s, ROLE_SELECTION);
case ROLE_SELECTION:
stpm = s->owner.stpm;
/* 遍历此网桥的所有端口,如果在计算角色过程中任一端口的reselect又被置位,那么计算过程立刻将重新开始,
* 即重新切换到ROLE_SELECTION
*/
for(port = stpm->ports; port; port = port->next) {
if (port->reselect) {
return STP_hop_2_state (s, ROLE_SELECTION);
}
}
break;
}
return False;
}
5 状态机