1 源码
rstplib.1.1.02/roletrns.c,roletrns.h。
2 代码简析
/* 使本网桥所有端口的同步请求信号sync = TRUE */
static void setSyncBridge (STATE_MACH_T *this)
{
register PORT_T* port;
/* this->owner.port:此状态机所属的端口
* this->owner.port->owner:端口所属的网桥
* this->owner.port->owner->ports:网桥的端口链表的头端口
*/
for (port = this->owner.port->owner->ports; port; port = port->next) {
port->sync = True; /* in ROOT_ PROPOSED (setSyncBridge) */
}
}
reRoot:重选根端口信号,该信号由根端口控制。
/* 向所有端口发重选根端口信号reRoot */
static void setReRootBridge (STATE_MACH_T *this)
{
register PORT_T* port;
for (port = this->owner.port->owner->ports; port; port = port->next) {
port->reRoot = True; /* In setReRootBridge */
}
}
/* 该端口所属的网桥的其他所有端口都已同步 */
static Bool compute_all_synced (PORT_T* this)
{
register PORT_T* port;
for (port = this->owner->ports; port; port = port->next) {
if (port->port_index == this->port_index) continue; // 跳过自身
if (! port->synced) {
return False;
}
}
return True;
}
/* 判断是否还有端口为根端口,没有则返回TRUE,否则返回FALSE */
static Bool compute_re_rooted (PORT_T* this)
{
register PORT_T* port;
for (port = this->owner->ports; port; port = port->next) {
if (port->port_index == this->port_index) continue;
/* rrWhile:最近根端口定时器 (“recent root while”Timer)
*初值=FwdDelay
*当一个端口变成根端口后,它将一直使它=FwdDelay。
*当端口变成丢弃状态时,它=0。
*用途:它表示该端口还有多久就完全不是根端口了
*rrWhile!=0:表示该端口目前是或最近是根端口
*rrWhile==0:表示该端口已经完全不是根端口了
*/
if (port->rrWhile) {
return False;
}
}
return True;
}
/* 执行状态动作 */
void STP_roletrns_enter_state (STATE_MACH_T* this)
{
register PORT_T* port = this->owner.port;
register STPM_T* stpm;
stpm = port->owner;
switch (this->State) {
case BEGIN: // 开始状态,无动作
case INIT_PORT: // 初始化
/* 本端口当前角色和新选角色都置为“弃用端口” */
port->role = port->selectedRole = DisabledPort;
port->reselect = True; // 重选端口角色信号置True
port->synced = False; // 同步标志置False,待同步
port->sync = True; // 同步请求信号置True
port->reRoot = True; // 重选根端口信号置True
port->rrWhile = stpm->rootTimes.ForwardDelay; // 最近根端口定时器设初值
port->fdWhile = stpm->rootTimes.ForwardDelay;
/* 最近备份端口定时器,表示该端口还有多久就完全不是备份端口了 */
port->rbWhile = 0;
break;
case BLOCK_PORT:
port->role = port->selectedRole; // 设置新角色-弃用端口
port->learn = // 此处空白,即同下面forward赋同样值,省略写法
port->forward = False; // 禁止学习、转发
break;
case BLOCKED_PORT:
/* 转发延迟定时器重置,使处于弃用、备份、可选的端口保持丢弃状态 */
port->fdWhile = stpm->rootTimes.ForwardDelay;
port->synced = True; /* In BLOCKED_PORT */
port->rrWhile = 0;
port->sync = port->reRoot = False; /* BLOCKED_PORT */
break;
case BACKUP_PORT:
/* rbWhile是最近备份端口定时器,
* 当一个端口变成备份端口后,将一直使rbWhile =2*HelloTime
*/
port->rbWhile = 2 * stpm->rootTimes.HelloTime;
break;
case ROOT_PROPOSED:
setSyncBridge (this); //使本网桥所有端口的sync = TRUE
port->proposed = False; // 清除转发提议接收信号
break;
case ROOT_AGREED:
/* 清除进入本状态的相关触发信号 */
port->proposed = port->sync = False;
port->synced = True;
port->newInfo = True;
break;
case REROOT:
setReRootBridge (this); // 向所有端口发重选根端口信号
break;
case ROOT_PORT:
port->role = RootPort; // 角色设为根端口
port->rrWhile = stpm->rootTimes.ForwardDelay; // 启动最近根端口定时器
break;
case REROOTED:
port->reRoot = False;
break;
/* 转发延迟定时器fdWhile到期后,端口就可以进行状态转移:
* 丢弃→学习 或 学习→转发
*/
case ROOT_LEARN:
port->fdWhile = stpm->rootTimes.ForwardDelay;
port->learn = True;
break;
case ROOT_FORWARD:
port->fdWhile = 0;
port->forward = True;
break;
case DESIGNATED_PROPOSE:
port->proposing = True; // 转发提议信号,本端口希望快速转移到转发状态
port->newInfo = True; // 发送新消息信号,导致端口发送状态机发送一个BPDU
break;
case DESIGNATED_SYNCED:
port->rrWhile = 0; // 使端口变成丢弃状态
port->synced = True; // 本端口已同步
port->sync = False; // 清除同步请求信号
break;
case DESIGNATED_RETIRED:
port->reRoot = False; // 经过重选后,刚从根端口角色退休,清除重选根端口信号
break;
case DESIGNATED_PORT:
port->role = DesignatedPort;
break;
case DESIGNATED_LISTEN:
port->learn = port->forward = False;
port->fdWhile = stpm->rootTimes.ForwardDelay; // 为转移到学习状态设置定时器
break;
case DESIGNATED_LEARN:
port->learn = True;
port->fdWhile = stpm->rootTimes.ForwardDelay; // 为转移到转发状态设置定时器
break;
case DESIGNATED_FORWARD:
port->forward = True;
port->fdWhile = 0;
break;
};
}
Bool STP_roletrns_check_conditions (STATE_MACH_T* this)
{
/* 初始化进入INIT_PORT状态 */
if (BEGIN == this->State) {
return STP_hop_2_state (this, INIT_PORT);
}
/* 若端口角色有变,则根据新选择的角色跳到对应状态,分为三个子状态机:
* (1) 弃用、备份、可选端口的端口角色转移状态机:BLOCK_PORT;
* (2) 根端口的端口角色转移状态机:ROOT_PORT;
* (3) 指定端口的端口角色转移状态机:DESIGNATED_PORT;
*/
if (port->role != port->selectedRole &&
port->selected &&
! port->updtInfo) {
switch (port->selectedRole) {
case DisabledPort:
case AlternatePort:
case BackupPort:
return STP_hop_2_state (this, BLOCK_PORT);
case RootPort:
return STP_hop_2_state (this, ROOT_PORT);
case DesignatedPort:
return STP_hop_2_state (this, DESIGNATED_PORT);
default:
return False;
}
}
switch (this->State) {
/* 弃用、备份、可选端口的端口角色转移状态机:
* 使处于弃用、备份、可选的端口保持丢弃状态
*/
case BLOCK_PORT:
/* 端口角色选择尚未完成或有信息待更新时直接返回 */
if (!port->selected || port->updtInfo) break;
/* 既非学习又非转发,则进入阻塞态 */
if (!port->learning && !port->forwarding) {
return STP_hop_2_state (this, BLOCKED_PORT);
}
break;
case BLOCKED_PORT:
…
/* 同步请求信号、重选根端口信号等非同步事件则维持阻塞 */
if (port->fdWhile != stpm->rootTimes.ForwardDelay ||
port->sync ||
port->reRoot ||
!port->synced) {
return STP_hop_2_state (this, BLOCKED_PORT);
}
/* 角色为备份端口,则进入BACKUP_PORT,并一直使rbWhile =2*HelloTime */
if (port->rbWhile != 2 * stpm->rootTimes.HelloTime &&
port->role == BackupPort) {
return STP_hop_2_state (this, BACKUP_PORT);
}
break;
case BACKUP_PORT:
return STP_hop_2_state (this, BLOCKED_PORT);
/*根端口的端口角色转移状态机:
* (1) 使处于根端口的端口保持转发状态;
* (2) 负责与父网桥指定端口完成握手协议
*/
/*指定端口的端口角色转移状态机:
* 使处于指定端口的端口保持转发状态
*/
}