快速生成树之端口信息状态机
来源:互联网 发布:淘宝nba旗舰店是正品吗 编辑:程序博客网 时间:2024/06/03 21:50
1 源码
rstplib.1.1.02/portinfo.c, portinfo.h。
2 功能
端口信息状态机,负责接收BPDUs,维护端口的生成树信息。
3 代码简析
3.1 状态定义
#define STATES { /
CHOOSE(DISABLED), /
CHOOSE(ENABLED), /
CHOOSE(AGED), /
CHOOSE(UPDATE), /
CHOOSE(CURRENT), /
CHOOSE(RECEIVE), /
CHOOSE(SUPERIOR), /
CHOOSE(REPEAT), /
CHOOSE(AGREEMENT), /
}
STATES宏定义了状态机的各个状态(ENABLED态为IEEE 802.1y中定义,此处不讨论),其中CHOOSE也是一个宏,用于运行和调试的切换。
运行时:
#define CHOOSE(a) a
typedef enum STATES THE_STATE_T;
#undef CHOOSE // 取消定义
调试打印时可用来返回状态机名称(前加#转换为字符串,见《宏中"#"和"##"的用法》):
#define CHOOSE(a) #a // 重新定义
static char *state_names[] = STATES;
#undef CHOOSE
3.2 rcvBpdu
static RCVD_MSG_T rcvBpdu (STATE_MACH_T* this)
{
int bridcmp;
register PORT_T* port = this->owner.port; // this状态机所属的端口
...
/* 条件1:消息是从指定端口发出:
* ( 该BPDU是RST BPDU && BPDU的Port Role==Designated) || BPDU是Config BPDU
*/
if (RSTP_PORT_ROLE_DESGN == port->msgPortRole ||
BPDU_CONFIG_TYPE == port->msgBpduType) {
bridcmp = STP_VECT_compare_vector (&port->msgPrio, &port->portPrio); // 条件2:消息优先级向量比端口优先级向量优越
if (bridcmp < 0 ||
(! STP_VECT_compare_bridge_id (&port->msgPrio.design_bridge,
&port->portPrio.design_bridge) &&
port->msgPrio.design_port == port->portPrio.design_port &&
STP_compare_times (&port->msgTimes, &port->portTimes)))
{
return SuperiorDesignateMsg; // 收到更优BPDU,返回更优信息SuperiorDesignateMsg
}
}
/* 条件1:消息是从指定端口发出 */
if (BPDU_CONFIG_TYPE == port->msgBpduType ||
RSTP_PORT_ROLE_DESGN == port->msgPortRole) { // 条件2:msgPriority==portPriority && msgTimes==portTimes
if (! STP_VECT_compare_vector (&port->msgPrio,
&port->portPrio) &&
! STP_compare_times (&port->msgTimes, &port->portTimes)) {
return RepeatedDesignateMsg; // BPDU来自当前指定网桥,返回重复信息RepeatedDesignateMsg
}
}
/* 子网桥根端口统一本端口快速转移到转发态,返回确认信息ConfirmedRootMsg */
if (RSTP_PORT_ROLE_ROOT == port->msgBpduType &&
port->operPointToPointMac &&
! STP_VECT_compare_bridge_id (&port->msgPrio.design_bridge,
&port->portPrio.design_bridge) &&
AGREEMENT_BIT & port->msgFlags) {
return ConfirmedRootMsg;
}
return OtherMsg; // 返回其他信息OtherMsg
}
3.4 updtBPDUVersion
#define BPDU_TOPO_CHANGE_TYPE 0x80
#define BPDU_CONFIG_TYPE 0x00
#define BPDU_RSTP 0x02
static Bool updtBPDUVersion (STATE_MACH_T* this)
{
register PORT_T* port = this->owner.port;
/*STP有2种BPDU:Config BPDU,TCN BPDU(TOPO CHANGE)
* RSTP有1种BPDU:RSTP BPDU
* 此信息由BPDU头部中的BPDU Types字段即msgBpduType标识,参见以上宏定义
*/
if (BPDU_TOPO_CHANGE_TYPE == port->msgBpduType) {
port->rcvdSTP = True; // STP
}
if (BPDU_RSTP == port->msgBpduType) {
port->rcvdRSTP = True; // RSTP
}
return True;
}
关于版本,RSTP能够识别STP BPDU,STP不能够识别RSTP BPDU,即同一拓扑中同时有RSTP设备和STP设备时,协议将退化为STP。
在一个RSTP网桥中,版本类型可以是:
(1) STP兼容模式
在此模式下将禁用可选端口到根端口的快速转移、指定端口快速转移到转发状态并且只发送接收 Config BPDUs 和 TCN BPDUs,丢弃任何收到的RST BPDUs。
(2) RSTP模式
在此模式下将允许可选端口到根端口的快速转移、指定端口快速转移到转发状态可以发送接收Config BPDUs 、TCN BPDUs和RST BPDUs。
3.5 STP_info_rx_bpdu
根据接收BPDU头部的BPDU Types字段信息,维护port的各成员变量的更新,提供状态机切换的触发事件。
void
STP_info_rx_bpdu (PORT_T* port, struct stp_bpdu_t* bpdu, size_t len)
{
/* check bpdu type */
switch (bpdu->hdr.bpdu_type) {
case BPDU_CONFIG_TYPE:
port->rx_cfg_bpdu_cnt++;
if (port->admin_non_stp) return; // 管理员配置为不支持STP兼容模式则直接返回
port->rcvdBpdu = True; // 标记接收到BPDU
break;
case BPDU_TOPO_CHANGE_TYPE:
...
case BPDU_RSTP:
port->rx_rstp_bpdu_cnt++;
if (port->owner->ForceVersion >= NORMAL_RSTP) { // NORMAL_RSTP = 2,大于等于2的版本号才支持RSTP
port->rcvdBpdu = True;
} else {
return;
}
break;
}
/* 更新端口信息 */
port->msgBpduVersion = bpdu->hdr.version;
port->msgBpduType = bpdu->hdr.bpdu_type;
port->msgFlags = bpdu->body.flags;
...
}
3.6 updtRcvdInfoWhile
用来计算rcvdInfoWhile的值
有效年龄=Message Age +╔ max(1,1/16 Max Age)╗(Message Age、Max Age来自portTimes)
(1) 如果有效年龄 > Max Age:rcvdInfoWhile = 0
(2) 如果有效年龄<= Max Age:rcvdInfoWhile = min(Max Age - 有效年龄,HelloTime*3)
3.6 STP_info_enter_state
执行指定状态的特定动作。
void STP_info_enter_state (STATE_MACH_T* this)
{
register PORT_T* port = this->owner.port;
switch (this->State) {
case BEGIN: // 开始态,自定义,用于状态机启动初始化
port->rcvdMsg = OtherMsg;
port->msgBpduType = -1;
port->msgPortRole = RSTP_PORT_ROLE_UNKN;
port->msgFlags = 0; // 此处无break,直接进入DISABLED态
case DISABLED:
...//优先级和时间设为指定值,待重选角色
break;
case ENABLED: /* IEEE 802.1y */
...
break;
case AGED: // 过期态,为一过渡状态
port->infoIs = Aged;
port->reselect = True; port->selected = False; // 待重选角色
break;
case UPDATE:
/* 端口变为指定端口,执行一系列固定配置 */
STP_VECT_copy (&port->portPrio, &port->designPrio);
STP_copy_times (&port->portTimes, &port->designTimes);
port->updtInfo = False;
port->agreed = port->synced = False; /* In UPDATE */
port->proposed = port->proposing = False; /* in UPDATE */
port->infoIs = Mine;
port->newInfo = True;
break;
case CURRENT:
break;
case RECEIVE:
port->rcvdMsg = rcvBpdu (this); // 从rcvBpdu () 获取接收信息,用于决定STP_info_check_conditions()的状态切换
updtBPDUVersion (this); // 更新BPDU版本
setTcFlags (this); // 更新拓扑标志
port->rcvdBpdu = False; // BPDU已得到处理,复位BPDU接收标志
break;
case SUPERIOR: // 转到更优信息态时,说明当前该端口信息与生成树不一致,同步标志置FALSE且待重选角色
STP_VECT_copy (&port->portPrio, &port->msgPrio);
STP_copy_times (&port->portTimes, &port->msgTimes);
updtRcvdInfoWhile (this);
port->proposing = False; /* in SUPERIOR */
port->proposed = recordProposed (this, "SUPERIOR");
port->infoIs = Received;
port->reselect = True;
port->selected = False;
break;
case REPEAT:
/* 记录Proposal标志,返回值赋给proposed
* =TRUE:该BPDU是RST BPDU && 该BPDU的port role==Designated Port && 该BPDU的Proposal标志==TRUE &&
* operPointToPointMAC==TRUE
*/
port->proposed = recordProposed (this, "REPEAT");
updtRcvdInfoWhile (this);
break;
case AGREEMENT:
port->agreed = True;
port->proposing = False; /* In AGREEMENT */
break;
}
}
3.7 STP_info_check_conditions
检查状态机倒换条件并进行相应状态倒换。、
Bool STP_info_check_conditions (STATE_MACH_T* this)
{
register PORT_T* port = this->owner.port;
/* 端口禁止或处于BEGIN态时切换到DISABLED态 */
if ((! port->portEnabled && port->infoIs != Disabled) || BEGIN == this->State) {
return STP_hop_2_state (this, DISABLED);
}
/* 当前态 + 倒换条件 -> 下一状态 */
switch (this->State) {
case DISABLED:
if (port->updtInfo) {
return STP_hop_2_state (this, DISABLED);
}
...
break;
case AGED:
if (port->selected && port->updtInfo) {
return STP_hop_2_state (this, UPDATE);
}
break;
case UPDATE:
return STP_hop_2_state (this, CURRENT);
break;
...
/* RECEIVE态下根据收消息类型决定下一状态port->rcvdMsg在STP_info_enter_state()函数中
* 由port->rcvdMsg = rcvBpdu (this) 获取
*/
case RECEIVE:
switch (port->rcvdMsg) {
case SuperiorDesignateMsg:
return STP_hop_2_state (this, SUPERIOR);
case RepeatedDesignateMsg:
return STP_hop_2_state (this, REPEAT);
case ConfirmedRootMsg:
return STP_hop_2_state (this, AGREEMENT);
default:
return STP_hop_2_state (this, CURRENT);
}
break;
...
}
return False;
}
4 状态机
- 快速生成树之端口信息状态机
- rstplib源码分析---快速生成树之端口信息状态机
- 快速生成树之端口角色选择状态机
- 快速生成树之端口角色转移状态机
- 快速生成树之端口状态转移状态机
- rstplib源码分析---快速生成树之端口角色选择状态机
- rstplib源码分析---快速生成树之端口角色转移状态机
- rstplib源码分析---快速生成树之端口状态转移状态机
- 快速生成树之通用状态机
- 快速生成树之拓扑变化状态机
- rstplib源码分析---快速生成树之拓扑变化状态机
- rstplib源码分析---快速生成树之通用状态机
- 快速生成树之时间信息
- rstplib源码分析---快速生成树之时间信息
- STP生成树协议之根端口 指定端口 阻塞端口
- 快速生成树之优先级向量
- sublime text3快速生成html头部信息
- sublime text3快速生成html头部信息
- 查询记录有技巧
- 什么是网站提速?
- iframe 实现页面无刷新
- 系统环境基本配置 SOE
- 未来五年程序员应当具备的十项技能
- 快速生成树之端口信息状态机
- 软件开发模型
- Windows系统字体与文件对照表
- Linux内核互斥锁
- 数组与指针---都是"退化"惹的祸
- asp.net页面间数据传递(总结篇)
- 文件夹操作
- Android签名证书----Android新手笔记
- ps中 图片透明渐变的制作