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) 負責與父網橋指定端口完成握手協議
*/
/*指定端口的端口角色轉移狀態機:
* 使處於指定端口的端口保持轉發狀態
*/
}