rstplib源码分析---快速生成树之端口角色转移状态机

时间:2021-08-26 19:57:39

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) 负责与父网桥指定端口完成握手协议

     */

 

     /*指定端口的端口角色转移状态机:

      * 使处于指定端口的端口保持转发状态

      */

}