问:“有以太网的时候就有生成树协议吗?”
答:“不是的,在最初的以太网环境里是不存在生成树协议的,因为那个时候的以太网是基于总线共享的,在这种介质中不存在环路,所以也就不需要生成树协议了。直到网桥将存储转发机制引入以太网后,人们才发现不得不借助一种机制来阻止环路对以太网带来的危害——这种机制就是生成树协议。”
问:“为什么共享以太网中不会出现环路呢?”
答:“在共享介质中,以太网设备工作在半双工状态下,通过CSMA/CD机制抢夺发言权,我们管这种环境叫做冲突域,报文在冲突域中广播。在这个冲突域中,任何设备在‘听’的时候是无法‘说’的,在‘说’的时候也不会‘听’到自己‘说’了什么。在这种环境下,如果用两根同轴电缆将两个冲突域连接起来,那么它们就形成一个大的冲突域。由于共享介质没有任何记忆功能,只是在不同的设备间提供了一个消息传播的渠道,所以只要周围设备保持沉默,这个冲突域内总是安静的。即使如集线器(Hub)这样的设备,如果将两个端口环接起来;或者用两条网线将两个Hub连接起来;又或者将多个Hub连成环状,虽然构造出了一个物理的环形,但是在逻辑上还是一根总线,所以早期的以太网里是不存在环路问题的。”
问:“那网桥又是怎么将环路引入以太网的呢?”
答:“网桥是为了减轻冲突域对通讯效率的影响而产生的,它在网络中起到了隔离冲突域的作用,网桥的每一个接口连接到一个冲突域中,却并不像Hub一样将这些冲突域连成一个更大的冲突域。这样带来了一个问题,如果信号到达网桥的一个接口上时,目的接口所连接的冲突域内并不‘安静’,网桥不能马上转发这个信号,这样就会造成信息丢失。为了解决这个问题,网桥会将这个信号储存起来,等目的接口所连接的冲突域‘安静’下来以后,再将刚才存储起来的信号转发出去。每个经过网桥转发的报文都会先被网桥缓存起来,然后再被转发出去。这就导致网桥在转发报文的时候,‘听’和‘说’是不同步的,这种‘生理缺陷’对于网桥这种没有‘智能’又没有见过什么世面的二层设备而言,简直是致命的——它分不清自己所听到的是不是自己刚才说过的。
这就好像《小孩和回音》那个寓言中的小孩一样,小孩对着大山喊了一声,大山的回音就回答一声,小孩不知道这个是他自己的回声,以为是别人跟他打招呼,就跟自己的回声自问自答起来。如果不是小孩的妈妈来打断他这种无休无止的行为的话,他非要叫到精疲力竭才能歇下来。
网桥在面对自己的回音时,虽然不至于像孩子一般也会高兴生气,却也一丝不苟地忠实于自己的本职工作。像图1中两台网桥,被两根网线连接起来。恰巧这个时候一个广播包从SWA的左侧端口被发送出来,SWB收到了这个广播包,于是将它缓存起来;当SWB缓存了整个广播包后,瞅着右侧端口有空就从右侧端口又发了出去——这是SWB的职责所在,将广播报文在所有端口上转发,而SWB也确实这么尽职尽责地做了。于是这个广播包又被SWA的右侧端口收到——就像回音一样——但是SWA显然不知道这个广播包是它刚才发送给SWB的,于是把这个广播包当作是一个全新的广播包缓存起来,然后在左侧端口空闲时再发送出去。对于SWA而言,被SWB缓存后再发送出来的广播包是一个全新的广播包——就像大山的回音一样,在过了一段时间再回到小孩子的耳朵里后,听起来就好像别人说的一样。
这样广播包在SWA和SWB之间的这两条链路上,被转着圈地反复转发,这样构成了一个环行的转发通道,也就是我们常说的环路。在实际网络中环路不会像图1一样显而易见,它有可能是经过了好几台设备然后绕回来的,大多数时候这种环路是由于没有好的规划,不经意间造成的,比如用一根网线将一堆链形连接的设备首尾连接起来。”
“这种环路对网络有什么危害么?”
“二层环路最大的危害就是会产生广播风暴,以太网是一个支持广播的网络,在没有环路的环境中,广播包在网络中以泛洪的形式被送达到网络的每一个角落,以保证每个设备都能接收到它。在带宽允许的情况下,每个网桥在接收到广播报文以后,都会向除接收端口以外的其他所有端口转发这个广播包,一旦网络中有环路,这种简单的广播机制就会引发灾难性的后果。
让我们回到图1,依旧以逆时针转发方向为例,如果SWA收到了一个广播包,将这个广播包从左侧端口转发出去,SWB收到后再从右侧端口转发回来,于是SWA再从左侧端口转发出去,SWB继续从右侧端口转发回来,直到环路消失之前,这种转发行为会无休止地重复下去;当然在顺时针转发方向也有同样的问题。
由于SWA和SWB都尽职尽责地将这个已经被重复转发了无数次的广播包在收到后的第一时间内再次转发出去,导致两个相邻的广播包之间只相隔了很短的一段时间,这样在SWA和SWB之间的这个环路上,一个广播包被反复转发了千万次,产生了广播风暴并且很快达到或接近端口线速,一下就消耗掉了链路上的带宽。根据转发规则,这些广播包不仅仅只是在环上被无限复制转发,SWA和SWB在每收到一次广播包后,还会向其他端口转发一份,这样整个网络都充斥着大量重复的广播包,如果全网都采用百兆端口互连,那么几乎每条链路上都充斥着100M/s的广播报文,正常的数据报文将很难再获得转发的机会。
在二层网络里,所有通过广播方式转发的报文都会在环路上产生广播风暴,比如未知单播报文、组播报文。而且最糟糕的是,一旦环路上发生广播风暴,这种灾难是不会自己停下来,除非环路消失,这在没有人为干预的情况下几乎是不可能的。”
问:“那么生成树在这种情况下又能起到什么作用呢?”
答:“生成树协议是802.1D中定义的一个应用于网桥的协议,这个协议为网桥定义了一组规则用于探知链路层拓扑,并对网桥的链路层转发行为进行控制。如果生成树协议感知到网络中存在环路,那么它会在环路上选择一个恰当的位置阻塞链路上的端口——阻止端口转发或接收数据报文,通过这种方式消除环路上可能产生的广播风暴。”
问:“如果网络是经过良好的规划并严格按照规划搭建,保证网络中没有环路的话,是不是就不需要生成树了呢?或者说这种环境中生成树没有用武之地了?”
答:“可以这么说,如果能够人为地保证二层网络中没有环路,那么确实可以不用部署生成树协议。但是需要注意的是,网络不是一个静态的东西——也许在某一段时间内,它看起来确实不会发生什么变化,但它不总是一成不变的。有的时候,可能会有人因为误操作在两台已经连通的网桥之间再增加一根网线,或者某处端口突然失效导致一部分局域网无法和局域网的其他部分通信等事情会时常发生,如果二层网络中没有部署生成树协议的话,情况可能会很糟糕。这时候网络会因为广播风暴的影响而处于瘫痪状态,而复杂的网络拓扑又导致定位环路的工作异常复杂,更糟糕的是当网络处于瘫痪状态时,即使想对每一台设备进行排查所耗费的工作量比网络正常时的工作量大得多。从这个角度考虑,即使通过人为规划消除了网络中的环路,部署生成树协议仍然有很大的好处。网络中任何一条新增的链路都会经过生成树的计算和检验,以防止环路的引入和由此而带来的危害。”
问:“那么生成树是如何工作并在网络里产生效果的呢?”
答:“生成树的工作主要由三个部分组成,分别是选举过程、拓扑计算、端口行为确定。”
问:“选举过程是用来做什么的啊?”
答:“选举过程主要是用来在整个二层网络中选举一台网桥作为根桥,用于指挥整网设备协同工作。”
问:“协同工作?”
答:“是的,协同工作。生成树协议为所有的网桥指定了一套统一的行为准则,并依靠网络中每一台设备的独立行为来完成整网拓扑的计算与收敛,它并不依赖于某一台特定设备的工作。换句话说,生成树协议工作的时候,不会有一台或一组指定网桥计算整网的拓扑,然后将部分或全部拓扑信息告诉其他网桥;网络中的每一台网桥都只需要获知有限的拓扑信息就可以各自决定端口行为,最后收敛出完整的拓扑。这种做法被称为分布式计算,采用这种方式的一个很大的好处就是每一台设备用于计算拓扑所需要的工作量相对于计算整网拓扑的工作量小很多,由于网桥的计算能力较弱(相对于路由器这样的设备而言),这种方法非常适合网桥这类设备。”
问:“既然是协同工作,那为什么又要选出一台设备作为根桥呢?”
答:“协同工作和根桥选举并不矛盾,根桥并不负责计算整个拓扑(相反根桥所知道的拓扑信息其实是所有网桥中最少的),它只是负责统一计算规则而已。分布式拓扑计算只是一种工作方式,但是这种工作方式是要建立在一个统一的行为准则的基础之上的,如果没有这个统一的行为准则,每台网桥各自为政,那么最后得到的结果只能是乱七八糟,没有规律,而这个规则就是靠根桥来统一。”
问:“那根桥是怎么统一网络中所有网桥的行为准则呢?”
答:“这就要从头说起了,前面的问答已经提到了部署生成树是为了消除二层网络中的环路所带来的负面影响,它通过在环上的某个恰当位置阻塞端口来阻止环路的发生。那么对于网络中只知道部分拓扑的网桥而言,它怎么知道哪里有环路,哪个端口需要被阻塞呢?从一台网桥的角度来说,它通过这样的法则判断,如果到达网络中的某一网桥只有一条路径,那么必定是不存在环路的了;如果到达某一网桥有两条或者多条路径,那么这两台网桥之间存在环路,只能保持一条通路。从整个网络的角度来说,如果整网中某一台网桥到任何一台网桥都只有唯一的一条路径可达,那么网络中不存在环路——换个说法,如果网络中任何一台网桥到某一台指定网桥都只有唯一的一条路径可达,那么网络中不存在环路。而这里所说的某一台指定网桥,对于网络中所有的网桥而言,必须是同一台网桥。
生成树协议中所通过选举产生的根桥就是前面所说的那台整网指定的唯一一台网桥。如果某一台网桥发现自己能够通过多个端口到达根桥,它只能在这些端口中选择一个作为去往根桥的端口——这个端口就被叫做根端口——其他可以通往根桥的端口都会被阻塞;当网络中所有网桥都只有一条到达根桥的路径时,网络中就没有环路了。这个时候如果把被阻塞的链路除去,整个网络拓扑会退化到一个以根桥为根节点的树型结构,这也是为什么生成树协议会被叫做‘树’的原因。
网络中的每一台网桥都需要记住根桥的桥ID,当然也包括根桥自己。这些网桥的定时器也会和根桥统一,以保证全部网桥的行为准则一致,这些定时器对行为准则有着决定性的影响。”
问:“既然根桥这么重要,那么根桥是如何选举出来的呢?”
答:“根桥是通过网络中所有网桥间互相比较产生的,根据‘所有网桥生来平等’原则任何一台网桥都有做根桥的权利;但是本着‘能者居其位’准则,根桥只能由网络中桥ID最小者担当。任何一台网桥在一开始的时候都把自己作为根桥,根桥ID就是自己的桥ID,然后通过BPDU和自己的邻居交换拓扑信息,如果邻居的根桥ID比自己的桥ID大,则继续做自己的根桥,如果邻居的根桥ID比自己的桥ID小,则把邻居的根桥当作自己的根桥,然后向其他邻居通告这个新的根桥信息。直到网络中所有网桥的根桥ID都一样时,根桥就被选举出来了。”
问:“桥ID是怎么一回事?”
答:“桥ID是生成树协议中规定的一项度量值,它有8个字节,由两部分组成,分别是2字节的桥优先级字段和6个字节的桥MAC字段。其中桥优先级字段可以手工设定,默认值为0x8000;桥MAC字段即网桥的物理MAC,各个网桥均不相同。这样分两段的方式保证了在进行桥ID比较时,既能通过人工设置干预,又能在桥优先级一样的情况下分出高低。通常在部署二层网络时,会指定一台物理位置居中、可靠性较高的网桥作为根桥,将其桥优先级设置为0x00,还可能指定一台网桥作为备份根桥,将其桥优先级设置为0x10,以得到预期的拓扑。”
问:“生成树通过什么机制使网络中的网桥和根桥保持统一呢?”
答:“生成树协议通过一种独特的消息传递机制,使网络中的其他网桥和根桥保持一致,当根桥被选举出来以后,根桥会周期性地向所有邻居发送BPDU报文,这个周期一般被称作Hello Time,默认被设置为2s。BPDU报文中携带了大量信息,包括Message Age、Max Age、Hello Time、Forward Delay等。当邻居收到从根桥发来的BPDU后,它们会用这个BPDU中的信息来配置自己或更新自己的状态和定时器,然后再将这个BPDU转发出去,当然在转发之前还需要根据情况对BPDU进行少量的修改。值得一提的是,在生成树协议(特指STP)中网络内只有根桥有主动发送BPDU的权利,其他网桥只需要在收到BPDU之后,再向下游转发即可;这点与快速生成树协议(RSTP)中有所不同,快速生成树协议中所有网桥都会按照Hello Time的时间间隔主动从指定端口发送BPDU。”
问:“BPDU是一种什么样的报文呢?”
答:“生成树协议中的BPDU报文有两种,一种被称为配置BPDU(Configuration BPDU),一种被称为拓扑变化通知BPDU(Topology Change Notification BPDU或叫TCN BPDU)。这两种BPDU各有各的用处,格式也不一样。
配置BPDU负担着生成树协议运转过程中大部分重要的工作,包括网桥之间的信息交互、拓扑描述、传递根桥信息等。
Octet | |
Protocol Identifier | 1 2 |
Protocol Version Identifier | 3 |
BPDU Type | 4 |
Flags | 5 |
Root Identifier | 6 7 8 9 10 11 12 13 |
Root Path Cost | 14 15 16 17 |
Bridge Identifier | 18 19 20 21 22 23 24 25 |
Port Identifier | 26 27 |
Message Age | 28 29 |
Max Age | 30 31 |
Hello Time | 32 33 |
Forward Delay | 34 35 |
图2 配置BPDU格式
如图2中即为IEEE 802.1D中规定的配置BPDU的格式,其中Protocol Idetifier为协议标识字段,值为0x0000;Protocol Version Identitier为协议版本字段,值为0x00;BPDU Type标明BPDU类型,值为0x00;Flags为标记字段,其最高位和最低位分别代表TCA和TC,置1有效。从第6字节到第13字节是Root Identifier字段,也就是前面根桥选举那个问题中所提到的Root ID,这个字段用于根桥选举。第14字节到第27字节分别为Root Path Cost(根桥路径开销)、Bridge Identifier(桥ID)、Port Identifier(端口ID)三个字段,这三个字段用于端口间优先级的比较,其中端口ID占两个字节,和桥ID类似也分为两个部分,前八比特为优先级,默认值为0x80,可以手工修改;后八比特为端口号,由设备指定,保证每个端口都不一样。后面四个字段是生成树协议中几个重要的定时器,前面提到过。
每个Hello Time周期,根桥发送BPDU到达下游网桥以后,下游网桥会根据情况修改其中的Root Path Cost、Bridge Identifier、Port Identifier和Message Age字段,然后再向下游转发。
TCN BPDU的结构比配置BPDU简单,负责的工作也较少,它是下游桥在发现拓扑变化的时候向根桥发送拓扑变化通知用的,这样根桥就可以知道网络中的拓扑变化并采取应急措施了。
Octet | |
Protocol Identifier | 1 2 |
Protocol Version Identifier | 3 |
BPDU Type | 4 |
TCN BPDU只有三个字段,其中前两个字段的值和配置BPDU中的一样,BPDU Type字段的值在TCN BPDU报文中为0x80,这个报文仅仅在下游桥感知到拓扑变化时才会由下游桥从根端口发送出来,并被一直送交到根桥。”
问:“Root Path Cost(根桥路径开销)的值代表了什么?它是怎么来的?”
答:“根桥路径开销代表了这个网桥到达根桥的距离。在根桥而言,这个值被设置为0,所以从根桥发送出来的BPDU,Root Path Cost字段的值总是0。
网桥的每个端口上还有一个Cost参数(Port Path Cost),这个参数描述了这个端口所连接的介质的路径开销,一般而言,介质速率越低开销也就越大,也就是说如果选择从这个端口发送数据,那么消耗的时间会越长。由于通信的特点,报文数据发送消耗的时间越短,情况越有利,显然在选择报文转发路径时,更倾向与选择那些速率较高的介质,或者是Cost较小的端口。这个参数可以人工设置,设置端口Cost是一种常见的调整生成树拓扑的方法。
当网桥收到了一个BPDU,其中的根桥ID比自己当前的根桥ID小时,这个网桥就会将BPDU中的Root Path Cost加上接收到这个BPDU的端口的Cost值作为自己的Root Path Cost;如果网桥收到了一个BPDU,其根桥ID和自己的根桥ID一样,而Root Path Cost加上接收到这个BPDU的端口的Cost也比自己的Root Path Cost小时,这个网桥也会将这个较小的值更新为自己的Root Path Cost。”
问:“连接到一个LAN的端口是如何进行优先级比较的?”
答:“这是生成树协议发现环路的一个重要机制,每台网桥都各自储存着一套信息,包括当前的根桥ID、Root Path Cost和自己的桥ID,此外每个端口还储存了自己的端口ID。
当几个端口被连接到一起以后,它们都有机会根据所属网桥的情况发送BPDU,由于处于一个广播域内,BPDU报文又是二层组播报文,所以这些连接到一起的网桥都能接收到这个BPDU。当端口接收到BPDU后,它会用这个BPDU中的信息和自己所属网桥所储存的信息进行对比,从根桥ID开始,如果相同说明根桥选举已经完成,需要比较根桥路径开销;如果再相同说明到根桥的距离相等,还可以比较桥ID;如果还是相同的话说明两个端口都在同一台交换机上,只好比较端口ID,由于不同的端口,端口ID必然不同,总能分出大小来。值越小,端口优先级越高。通过这几轮比较,可以得到两种结果:
1、 收到的BPDU信息不如设备和端口上储存的信息,说明发送BPDU的端口优先级比端口自身的优先级低,端口在这轮比较中胜出,不做任何变化;
2、 收到的BPDU信息高于设备和端口上储存的信息,说明发送BPDU的端口优先级比端口自身的优先级高,则端口在这轮比较中失败,停止向LAN中转发BPDU;
这样到了最后,这几个连接到一起的端口中,只有一个会获得最终的胜出,其他的端口都失败了,他们会停止向LAN中转发BPDU。这个时候,这个获得最终胜利的端口就成为这个LAN的指定端口。如果在LAN中有报文需要向根桥转发,那么从指定端口转发所产生的开销最小,所以指定端口负担起了转发LAN中去往根桥的报文的工作。”
问:“那么那些在优先级比较中失败的端口又会怎么样呢?”
答:“在同一台网桥上,这些在比较中失败的端口会再进行一轮比较,它们会依次比较各自从对应指定端口收到BPDU中的下列值:Root Path Cost(要先加上端口自身的Cost)、桥ID和端口ID,如果都一致则比较端口本身的端口ID,选出最小的一个作为根端口。因为BPDU是从根桥发送出来,然后被逐跳转发扩散到整个网络,所以在根桥选举完成、LAN上端口优先级比较结束后,如果端口能够收到从根桥来的BPDU,那么沿着这个BPDU的传递路径逆向回溯必然可以达到根桥。换句话说对于一台网桥而言,有多少这样的端口就会有多少条抵达根桥的路径,这个网桥会从这些端口中选择一个开销最小的端口作为自己的根端口——网桥通往根桥的唯一出口,其他端口成为Alternate端口[1]进入Blocking状态,既不接收或转发数据报文,也不转发BPDU。这样可以保证网桥上所有去往根桥的报文都可以以最小的开销往根桥转发。”
问:“为什么Alternate端口需要被Blocking?”
答:“这个是生成树协议用于阻止环路的一种手段,对于一个LAN而言,连接到这个LAN上的所有端口中,在比较中胜出的端口是到根桥‘最近’的端口,即指定端口是可以转发数据报文的。而连接到这个LAN上的其他端口,如果它们不能成为根端口的话,那么这个端口所接收到的报文——广播报文或者去往根桥的报文,可以从另一条路径到达根桥——它所属网桥的根端口。也就是说如果Alternate端口也能转发报文的话,那么在这个LAN中的报文到达根桥的路径不止一条,很明显这样就构成了环路。为了消除在这些冗余的链路上产生广播风暴的危险,生成树协议阻塞了这些Alternate端口。”
问:“这样繁复地比较有什么好处么?”
答:“生成树协议中不厌其烦地对网桥、端口进行比较主要是为每台网桥或每个网段都选择一个转发开销相对较小的到根桥的路径。虽然最后这个以根桥为中心优化出来的网络也许并不是最好的或是效率最高的,但这可以通过合理部署根桥来改善这种情况。另外,生成树协议中制订这么一系列比较的措施也是为了在正常应用环境中每次比较都不会出现比不出大小的状况,从而保证最终拓扑的一致性。”
问:“那么根端口或指定端口又会怎么样呢?”
答:“这得先讲讲生成树协议中端口的五种状态:Disable、Blocking、Listening、Learning、Forwarding。当端口没有连接上或者被shutdown时,都处于Disable状态;一旦up起来后,就进入Blocking状态,如果没有收到优先级更高的BPDU或者本身被网桥选举为根端口,它会马上进入Listening状态,然后等待一个Forward Delay的时间,进入Learning状态,再经过一个Forward Delay的时间,如果端口没有因为新的选举过程而成为Alternate端口的话,就可以进入Forwarding状态了。
图4 STP中端口状态切换示意图
图4中5种转换条件分别为:
1) 端口UP
2) 端口Down
3) 被选举为指定端口或者根端口
4) 因选举失败而成为Alternate端口
5) Forward Delay计时器超时
(排版建议:将上面这段文字排在图片右侧,和图片做到一起,可采用小字体)
端口处于Disable状态时,说明这个端口根本没有up起来,自然也就不会有任何的转发行为;而Blocking状态下的端口都是Alternate端口,虽然up起来了,但是为了消除环路上的广播风暴,也不会转发任何报文,或者学习MAC地址;端口在Listening状态时即不转发数据报文,也不会根据监听到的数据报文学习MAC地址;在Learning状态时不转发数据报文,但是会根据监听到的数据报文的源MAC学习MAC地址并建立MAC地址表;当端口最终进入Forwarding状态以后,这个端口就和一个普通的网桥端口一样,学习MAC、转发数据报文。”
问:“为什么端口在被选为指定端口或根端口以后,还需要等待两个Forward Delay?”
答:“这是为了防止生成临时环路而采取的一种措施,因为在每台网桥上不管是根桥选举、拓扑计算还是BPDU传递都需要一定的时间,而生成树协议中,拓扑信息又是逐跳传递的,这导致了在拓扑发生变化的时候,不能保证网络内全部网桥的拓扑保持一致,一部分网桥会先感知到变化从而计算出新的拓扑,而另外一些网桥则会由于传递BPDU过程中的延迟,而没有感知到拓扑变化,仍然在沿用老的拓扑。这时一些原来处于Forwarding状态的指定端口或根端口到了新拓扑里可能会变成Altenate端口,但是由于它们所属的网桥的拓扑信息还没有得到及时得更新,端口仍然处于Forwarding状态而没有及时切换;但与此同时,一些原来处于Blocking状态的Alternate端口在新拓扑里可能会变成新的指定端口或根端口,由于它们所属的网桥及时感知到了拓扑变化,并已经计算出了新的拓扑,如果这些端口直接进入Forwarding状态并转发数据报文,那么会在一个短时间内由于拓扑更新没有同步而产生瞬时环路。这种瞬时环路在网络里可能会造成一些不可预期的严重后果,比如在这种瞬时环路上产生的广播风暴消耗了链路上的全部带宽,导致BPDU报文无法正常被送达其他端口,从而使更多的端口因为超时而改变端口状态,以至于全网拓扑完全混乱,生成树失效。
所以处于Blocking的端口在进入Forwarding状态之前,必须经历Listening和Learning两个状态,等待足够长的时间,以保证拓扑变化的信息已经扩散到整个网络,所有的网桥都更新了拓扑,才能放开端口,开始转发。”
问:“端口在Learning状态中会学习MAC地址,这样做有什么好处?为什么在listening状态又不学习MAC地址?”
答:“端口在Learning状态学习MAC地址是为了在拓扑完成收敛以后,当端口开始转发的时候,减少因未知单播在网络内广播而额外消耗带宽。比如图5中的情况:
图5 Learning状态设计思想示意图
两台PC和网桥的一个端口连接到了同一个LAN上,在拓扑已经基本稳定以后,端口进入了Learning状态,在开始转发之前,通过监听两台PC之间通信的报文,端口已经将两台PC的MAC地址学习到端口上了,这样在端口进入Forwarding状态开始转发之后,根据网桥的转发原理,目的地址为0001-0000-0001和0002-0000-0002的报文就不会再从端口被转发出去了。如果没有Learning状态作为过渡,当端口进入Forwarding状态以后便立即开始转发报文,那么此时如果LAN上有目的地址为0001-0000-0001或0002-0000-0002的报文,由于端口还没有学习到这些MAC地址,这些报文会被当作未知单播报文被广播出去,由于其他网桥也没有学习到这些MAC地址(以前学到的都被老化了),这些报文将会在整个网络内广播,白白地消耗带宽。
而端口在Listening状态下的情况和在Learning中的又大不相同,因为在Listening状态时,全网拓扑收敛还没有完成,这个时候在LAN上仍然能够监听到的MAC地址,很可能在新的拓扑中无法再通过这个端口到达。所以处于Listening状态的端口有必要等待其他端口都已经切换到新拓扑中后,才开始学习MAC地址。”
问:“Blocking的端口为什么不能学习MAC地址?”
答:“因为处于Blocking状态的端口不能转发数据报文,所以在这个端口上学习MAC地址是不必要的。如果处于Blocking状态的端口能够学习到MAC地址,甚至可能引发一些数据包无法被正常送达。比如图6中所示:
图中下方的网桥SW有两个端口可以去往根桥,它选择左侧端口转发,阻塞右侧端口。这个时候,根桥向下游广播了一个广播报文,如图中红色箭头所示,报文的目的MAC地址为广播地址,源MAC地址为0001-0000-0001,由于SW上左侧端口去往根桥的路径开销较小,从左侧路径转发的广播报文往往会比从右侧路径转发的广播报文先到达网桥SW上,所以根据网桥转发规则,MAC地址0001-0000-0001被学习到左侧端口上;然后从右侧路径转发的广播报文也到达网桥SW上,如果Blocking的端口也能学习MAC地址的话,根据网桥转发规则,MAC地址0001-0000-0001会被更新到右侧端口上,也就是说左侧端口上,现在已经没有0001-0000-0001的MAC地址了。在这时网桥SW收到一个目的MAC地址为0001-0000-0001的报文,根据转发原则这个报文需要从右侧接口转发,但是这个接口处于Blocking状态,所以这些报文都会被丢弃,也就无法到达目的地。
为了保证转发的正常,处于Blocking状态的端口是不能学习MAC地址的,如果端口在进入Blocking状态之前已经学习到一些MAC地址,这些地址需要立即被老化掉。”
问:“生成树协议中的网络直径是一个什么样的概念?”
答:“网络直径是生成树协议中定义的一系列参数中的一个,它是指网络中任意两个站点之间可能经过的网桥的最大跳数,在协议中建议这个参数取值为7。此外生成树协议还规定了一些重要参数Maximum bridge transit delay、maximum BPDU transmission delay、maximum Message Age increment overestimate,这三个参数都是以秒作为单位的,建议取值都是1s,最大也不能超过4s。这几个值会影响到BPDU传递拓扑信息到整个网络所需要的时间,决定拓扑收敛的速度。”
问:“Message Age和Max Age是指的什么?两者之间有什么联系么?它们有什么用处?”
答:“Message Age是用来衡量当前网桥所收到的BPDU在网络内传播时间的一个参数,由于BPDU从根桥产生后,是经过下游的网桥一跳一跳地传播的,每经过一跳都会产生一定的时延,这样当BPDU从根桥传递到距离根桥较远的设备上时,这个时延就增大到不可忽略了。所以根桥在构造发送BPDU的时候,会将这个字段设置为0,当下游网桥在传递从根桥发来的BPDU时,会在BPDU报文的Message Age字段中把这一跳转发过程中可能引入的时延上限加到里面。这样一来远端的网桥就可以通过BPDU中的Message Age来计算当前拓扑信息存在的时间了。
Max Age则是一个预先设定的值,这个值可以看做是一个门限,用来配合Message Age定时器。
这两个值是生成树协议用于判定拓扑是否变化的重要指标,由于生成树协议所处的环境中,不是所有的拓扑变化都可以直接感知,所以生成树协议中专门设计了一种超时机制来感知拓扑的变化。网桥在根端口上设置了一个定时器,如果通往根桥的路径完好,根端口会定时收到BPDU,而当网桥从根端口上收到一个BPDU报文,它就更新这个定时器;如果一直不能收到BPDU,每过1s定时器就自动加一,当这个定时器超过某一门限(Max Age)之后,网桥会认为原根端口通往根桥的路径已经出现了故障,拓扑发生变化。这是生成树协议中,除了端口down以外,网桥感知拓扑变化的唯一方法,它保证了故障点以下的子树分支上所有的网桥都能在一个大致相同的时间段内检测到链路故障。
图7 通过Message Age超时感知拓扑变化示意图
如图7所示为某网络中的一个生成树分支,在拓扑稳定的情况下,三台下游桥都能不断地收到从根桥发来的BPDU,所以根端口上Message Age定时器总能得到更新。第一台网桥收到BPDU中Message Age为12,它在转发BPDU时将自己的处理时间加到Message Age中发送给第二台网桥后,第二台网桥根端口的Message Age为13;同理,当这个BPDU到达最后一台网桥时Message Age已经增加到14了。
这时去往根桥的路径上发生故障,第一台网桥的根端口收到了最后一个BPDU,并用这个BPDU中的Message Age更新了自己根端口的定时器。一秒以后,它将这个BPDU转发给第二台网桥,并将报文中的Message Age字段置为13,同时它自己根端口上的Message Age定时器也增加到了13。第二台交换机收到第一台设备发来的BPDU报文以后,用报文中的Message Age更新了自己根端口的定时器。两秒以后,第一台交换机根端口上的Message Age定时器增加到14,第二台交换机也处理完了刚才收到的BPDU,在它将这个BPDU向下游转发的时候,Message Age字段被置为14,同时根端口上的Message Age定时器也增加到14。第三台交换机收到第二台设备发来的BPDU以后,用报文中的Message Age更新了自己根端口的定时器,这样第三台交换机根端口上的Message Age定时器也是14。再下一秒,由于没有新的BPDU更新这些网桥端口上的定时器,三台网桥根端口上的定时器都增加1,达到15。这样在故障发生后第八秒时,三台网桥根端口上的定时器都达到了20,如果采用默认的Max Age,这些定时器都达到了超时的标准,三台网桥同时感知到了拓扑的变化。”
问:“Alternate端口也会收到BPDU报文,这类端口也会维护自己的Message Age定时器么?”
答:“是的,每个Alternate端口都会根据自己所收到的BPDU报文中的message Age维护一个独立的定时器,由于生成树协议采用分布式计算,各个端口的定时器都是独立维护的。如果某个根端口或Alternate端口上的Message Age定时器大于Max Age,那么这个端口会认为其所连接的LAN内原来的指定端口已经不可达,这个端口会尝试成为LAN内的指定端口。当然如果LAN内还连接着其他端口的话,这些端口上的Message Age定时器会在差不多同一时间段内超时,它们都会加入指定端口选举的行列,并最终有一个端口胜出。
另外,如果网桥的根端口上的Message Age超时,而其他Alternate端口的message Age仍然能得到更新的话,它会从未超时的Alternate端口中选择一个最优的端口作为新的根端口。
按照前面所说的,如果根端口和Alternate端口到根桥的连接都断开的话,它们也会在差不多同一时间段内超时。”
问:“生成树中各种参数的默认值是怎么来的?有什么道理么?”
答:“生成树中的一部分参数的默认值是人为定义的,而另一部分则是根据这些人为定义的参数计算产生的。
其中人为定义的参数有最大网络直径(dia)、BPDU丢包容忍度(lost_msgs)和前面提到的Maximum bridge transit delay(bt_d)、maximum BPDU transmission delay(pdu_d)、maximum Message Age increment overestimate(msg_aio)。其中‘BPDU丢包容忍度’是指生成树协议容忍网络在转发BPDU时连续丢失的BPDU的最大个数,BPDU在转发的过程中可能会因为突发的拥塞或由链路质量问题产生的错误帧等原因被丢弃,而生成树协议必须容忍这些丢包的发生,以保证协议的健壮性。
上述参数主要是由实际的网络状况和设备性能所决定,协议中给出了这些参数的合理取值范围和建议默认取值。其他参数则是根据实际应用中可能发生的一些状况,利用上面这些人为定义的参数计算产生。
如Hello Time(hello_t)的取值,hello_t = 2×pdu_d,这么做是为了给网桥足够的时间去处理BPDU,以免两个连续到来的BPDU影响网桥的处理过程,默认值为2。
而Max Age则要保证在最差情况下,拓扑仍然能保证稳定,同时还需要在尽可能短的时间里检查出网络中可能发生的故障,所以
max_age = ((lost_msgs + 1)×hello_t) + msg_ao + (pdu_d× (dia– 1))= msg_ao + msg_prop
其中msg_ao= msg_aio×(dia – 1)是指BPDU从根桥发出到网络最远端的网桥在传递过程中所经历的最大时间,考虑可能出现的最差情况,这个BPDU最多会经历7跳(在一个网络直径为7的网络里,根桥不在网络的物理中心而在边缘,所以离根桥最远的设备到根桥的距离共7跳,生成树协议中往往把这种情况视为最差情况,来考虑问题或计算各种参数),如果每经过一跳所引入的时延都是最大时延,那么这个BPDU所经历的最大时延为6。
而msg_prop则是指BDPU在网络上的生存时间,由于每经过一跳BPDU中的message Age都会增加1,所以当BPDU从根桥到达最远端的网桥时的message Age可以认为是BPDU的生存时间,即公式中第二个括号中的部分;但是为了保证生成树协议的健壮性,需要允许网络中可能产生的丢包,那么在丢包数不大于既定数值的前提下,最差的情况,抵达远端网桥的两个BPDU之间的时间差则是公式中第一个括号中的部分。按照协议中推荐的默认值,msg_ao和msg_prop分别应该为6和14,所以推荐max Age采用20作为默认值。
对于Forward Delay(fwd_d)来说,由于端口在进入Forwarding状态前会等待2倍的Forward Delay,以避免新旧拓扑在网络中并存导致的环路,所以这个时间必须大于新的拓扑信息在网络中传播的时间,也就是说:
2×fwd_d >= msg_ao + msg_prop + bt_d + life
其中life在协议中的定义是报文从网络的一端到另一端转发所需要的最大时间,这个时间小于7.5s,所以在默认情况下2×fwd_d >=28.5,Forward Delay为15。”
问:“TCN报文有什么用处呢?”
答:“TCN报文是下游桥在感知到拓扑变化的时候,用于向根桥发送通知的一种报文。由于生成树协议单向传递拓扑的特点,在二层网络中上游网桥无法直接感知到下游发生的拓扑变化,这会引发一些问题:
如图8中,开始的时候下方网桥右侧端口处于Blocking状态,所有报文都从左侧端口转发,其中一条流的源地址为0001-0000-0001,当这条流到达上方网桥时,这条流的源地址被学习到左侧端口上并建立相应的MAC地址表。
由于拓扑变化,下方网桥Blocking的端口切换到左侧如图9中所示,但是上游网桥无法直接感知下方网桥的变化,仍然按照原有的MAC地址表转发,这时如果上方网桥收到一个目的地址为0001-0000-0001的报文,会从左侧端口转发出去,但是这个报文会被下方网桥的左侧端口丢弃。很明显这种情况下原有的MAC表已经不能保证将报文正确的送达目的地,所以在网络拓扑发生变化时,上游网桥也需要更新自己的MAC地址表,以适应这种变化。但是既然上游网桥无法感知下游的拓扑变化,那么上游网桥如何判断更新MAC地址表的时间呢?
这就需要下游网桥在感知到拓扑变化时主动通知上游网桥,生成树协议中采取的方法是下游网桥在感知拓扑变化后,向根桥发送TCN报文,再由根桥将拓扑变化消息向下游广播,从而达到通知全体网桥拓扑变化的情况。
具体做法是,下游桥通过端口状态切换(比如端口进入Blocking、Forwarding状态,或是端口Down掉等)感知拓扑变化,在感知到拓扑变化后,下游网桥将启动一个TCN timer定时器,并从根端口发送TCN;上游桥从指定端口收到TCN后,直接从自己的根端口向上逐跳转发,保证TCN能够被及时得送达根桥;根桥在根桥在收到TCN报文后,会将后面一段时间里(这段时间的计时器叫做Topology Change timer)发送配置BPDU中的TC flag置位,当下游网桥收到TC flag置位的报文,就会知道拓扑发生变化,需要采取相应措施了。
为了保证TCN被根桥收到,协议中还对拓扑变化通知过程设计了一套确认机制,即根桥在收到TCN后,这个收到TCN的端口在下一次发送BPDU时会将TCA falg置位,通知下游网桥TCN已经收到;如果感知到拓扑变化的网桥没有收到TCA flag置位的BPDU,说明TCN报文可能在途中被丢弃,它将会按照Hello Time的间隔向上游发送TCN,直到TCN timer超时为止。”
问:“网桥桥是通过什么机制来感知拓扑变化?”
答:“通常来讲,如果网桥的端口从Learning状态进入Forwarding状态或者从Forwarding状态进入Blocking状态,都表示实际网络拓扑已经发生变化。当某个网桥从非根桥状态成为根桥以后,也说明原有拓扑已经不存在了。此外,如前面所说,当根桥收到下游桥发来的TCN后,也可以感知拓扑变化。”
问:“当网桥感应到拓扑变化以后会采取一些什么措施呢?”
答:“主要是老化表项和再建的过程。根据协议里规定,网桥只需要将现有的MAC地址表老化即可,但是由于一些三层交换机将ARP的出接口也做到了ARP表中,所以对于这些交换机而言,在收到拓扑变化通知以后,还会老化自己的ARP表。”
问:“生成树网络中所有网桥都只有一个根端口这种说法正确么?”
答:“这种说法不正确,在生成树网络中根桥是不会有根端口的,但是其他网桥都有且只有一个根端口。”
问:“根桥上的端口全部都是指定端口么?”
答:“不一定,如果根桥上的两个端口被连接到了同一个LAN上,那么这两个端口中必然有一个不能成为指定端口。”
问:“如果某个端口收到了自己发送出去的BPDU,它应该怎么处理?”
答:“丢弃它,这种情况一般出现在端口所连接的LAN中本身存在环路的情况,或者是遇到攻击的情况,在这些情况中,这种报文是有害的,必须直接丢弃。”
问:“在默认配置下,如果出现故障,生成树最长要经过多长时间才能收敛?”
答:“考虑最差情况,假设某网桥有两个端口可以到达根桥,其中根端口直接通过一个LAN连接到根桥,另一个端口作为备份。那么在LAN中根桥的指定端口刚刚发出了一个BPDU以后就Down掉,那么这台网桥会经历三个过程:
1、 等待根端口超时,由于从根桥发出来的BPDU中message Age为0,所以根端口message Age超时需要等待20s。
2、 选举出根端口,并等待根端口进入Learning状态,这时网桥会直接将那个Alternate端口作为根端口,端口状态从Blocking转到Listening,然后等待15s进入Learning状态。
3、 根端口从Learning进入Forwarding状态,根端口再等待15s的Forward Delay后进入Forwarding状态。
至此拓扑收敛完成,共用时50s。这是在没有拓扑振荡的前提下,最差的网络收敛时间。”
问:“根桥部署有什么策略么?”
答:“一般而言,为了减少收敛后的网络拓扑中的转发开销,建议将根桥设置在网络的物理中心,比如星型组网的汇聚节点。对于双星型组网,则建议将一个汇聚节点设置为根桥,而将另一个设置为备份根桥。在环形组网里,为了尽可能的优化流量分布,建议将环的上行链路所在的设备设置为根桥,若采用两台设备上行则分别设置为根桥和备份根桥。
由于网络半径的限制,环网上部署生成树协议会限制网络规模,而且由于收敛后拓扑呈链型,生成树收敛性能也会收到很大影响。”