5.5 CBT操作
DVMRP和MOSPF都有两个限制条件。首先,它们都是密集模式协议,在稀疏拓扑结构下的扩展性不好,也就是说,当互联网络中的组成员仅占全部主机的一小部分且分布于整个互联网络之内时,为了达到这些组成员,DVMRP和MOSPF都要消耗大量难以承受的网络资源,大部分资源消耗都是计算和维持每个多播树(以每个多播源为根)所必需的开销。其次,这两种协议在确定多播树时被局限于单一单播路由协议——DVMRP被局限于基于RIP的协议,而MOSPF被局限于OSPF协议。与此相反,CBT(Core-Based Trees,核心树)是一种与协议无关的、稀疏模式的共享树协议。
与协议无关(Protocol-independent)意味着CBT可以使用任何底层的单播路由协议来发现多播源,发现其他CBT路由器,构建其多播树。由于CBT可以使用现有路由协议(而不是为支持多播而增加其他路由协议),因而除了提高了灵活性之外,还可以达到降低所需的开销。此外,CBT树以核心(core)CBT路由器为根,而不是以多播源网络为根。核心CBT路由器可以位于互联网络中的任何位置,而且很多多播源都可以以同一个核心CBT路由器为根,使得CBT更适用于稀疏多播拓扑结构。
目前有3种版本的CBT, CBTv2(在RFC 2189中描述)替代了CBTvl,还有一个处于提议状态的CBTv3。这3种版本都属于试验性版本,都没有得到大规模的部署应用,出于试验性状态,CBTv2和CBTv3都不具备与先前版本的后向兼容性。本章重点关注CBTv2,在提及术语“CBT”时,指的都是CBTv2。
5.5.1 CBT 基础
CBT使用以下9种类型的消息。
• JOIN_REQUEST(加入请求);
• JOIN_ACK(加入应答);
• ECHO_REQUEST(回应请求);
• ECHO_REPLY(回应应答);
• QUIT_NOTIFICATION(退出通告);
• FLUSH_TREE(清除多播树);
• Candidate Core Advertisement(候选核心路由器宣告);
• Bootstrap(引导);
• HELLO。
除了将在5.5.3小节中讨论的一个例外情况之外,所有的CBT消息都被发送给保留的多播地址224.0.0.15(见表5-1),且TTL为1,这意味着所有的CBT信息都要在多播域中进行逐跳传递。有关这些消息的格式将在5.5.5小节中进行详细描述。
与其他IP多播路由协议类似,在主机希望加入多播组时,是通过IGMP成员关系报告消息来通知CBT的。CBT使用显式加入机制,因而当CBT路由器必须向特定多播组转发数据包时,必须首先将自己嫁接到该多播组的多播树。CBT首先要检查其单播路由表,找到该特定多播组的核心路由器的位置,之后沿路径向上游方向的核心路由器转发JOIN_REQUEST消息,该消息包含以下3部分重要信息。
• 多播组的地址;
• 核心路由器的地址;
• 消息发起者的地址。
注意: 路由器如何发现核心路由器是5.5.2小节的主题。
当下一跳路由器接收到JOIN_REQUEST消息之后,会检查组地址和核心路由器地址。根据这些信息,该路由器会知道自己属于下面的某一种情形。
• 核心路由器;
• 连接在该多播组的多播树上(属于on-tree[树上]路由器);
如果该路由器是核心路由器或on-tree路由器,那么就会向JOIN_REQUEST消息的发起者发送一条JOIN_ACK消息,表示发起者已经已经成功加入多播树。该路由器还会将收到JOIN_REQUEST消息的接口加入到该多播组的转发表项中,并开始在该接口上转发多播包。
如果该路由器既不是核心路由器,也不在多播树上,那么就必须加入该多播树,这样就要检查其单播路由表,以找出核心路由器的位置,并将JOIN_REQUEST消息的拷贝转发给上游邻居。该路由器还会开始进入瞬时加入状态(transient join state),包括该多播组、接收到JOIN_REQUEST消息的接口以及传送JOIN_REQUEST消息的接口在内的信息都被记录下来,并启动一个定时器。如果在7.5秒(瞬时超时(transient timeout)周期)之内仍未收到JOIN_ACK消息,那么就会删除瞬时加入状态,表示加入不成功。
在CBT的术语中,面向核心路由器的上游接口是父接口(parent interface),而面向组成员的下游接口是子接口(child interface)。与此类似,上游邻居是父路由器,而下游邻居则是子路由器。通过接收JOIN_ACK消息而建立了多播树之后,子路由器会每隔60秒向其父路由器发送一条ECHO_REQUEST消息,ECHO_REQUEST消息中仅包含发起该消息的子路由器的地址,父路由器会响应以ECHO_REPLY消息,该消息会列出父路由器在该链路上转发多播包的所有多播组。
如果在70秒之内仍未收到ECHO_REPLY消息,那么该父路由器就会被宣告为不可达。与此类似,如果在90秒之内,某特定多播组都没有被列在ECHO_REPLY消息之中,那么该多播组就会被宣告为无效。之后,子路由器会向其上游父路由器发送一条QUIT_NOTIFICATION消息,并向其下游每个子路由器各发送一条FLUSH_TREE消息。其中,FLUSH_TREE消息中列出了所有无效的多播组地址,接收到该消息的所有子路由器都会将FLUSH_TREE消息中列出的无效多播组信息从其转发表中清除掉,然后这些子路由器又继续向其子路由器发送FLUSH_TREE消息,一直持续下去,直至该失效路由器以下的多播树树枝都被删除。
QUIT_NOTIFICATION消息还被用于剪枝,如果某台路由器通过IGMP离开组消息学习到其不再连接某特定多播组的成员,那么就会向其父路由器发送一条QUIT_NOTIFICATION消息,在该消息中列出将要被剪除的多播组地址。以此类推,如果该父路由器也没有连接该多播组的成员,而且也没有该多播组的子接口,那么也要向其上游路由器发送QUIT_NOTIFICATION消息。以此往复,该树枝一直会被剪除,直到到达一台活动的on-tree路由器或核心路由器。
5.5.2 发现核心路由器
CBT路由器构建到核心路由器的多播树的先决条件是要知道哪台路由器是核心路由器。一种解决方法是在所有路由器上预先配置每个多播组的核心路由器地址,该方法对小型多播网络来说可能很好,能够提供很好的网络控制能力,但相应的管理需求导致难以适应较大规模的互联网络。
另一种解决方法就是Bootstrap(引导)机制。使用该方法时,要将CBT域中的一组路由器配置为候选核心路由器(candidate core)。这些路由器之间交换Candidate Core(候选核心路由器)消息,根据优先级,将其中的某台路由器选举为BSR(Bootstrap Router,引导路由器),如果所有路由器的优先级均相等,那么就选举IP地址最大的路由器为BSR,其余的候选核心路由器将每隔60秒向BSR发送一条单播Candidate Core消息,作为保持激活消息。根据这些Candidate Core消息,BSR会组建一个CC-set(Candidate Core set,候选核心路由器集合),并通过Bootstrap消息将CC-set宣告为域中的所有CBT路由器。当某路由器被要求加入某多播组时(通过IGMP),会对CC-set进行哈希运算,以正确确定该多播组的核心路由器。
CBT和PIM-SM使用相同的Bootstrap协议,由于本章的重点内容是PIM-SM协议,因而本小节仅简要叙述引导机制,有关细节内容将在5.8节进行详细描述。
5.5.3 CBT 指派路由器
CBT使用HELLO消息来选举多路接入网络中的指派路由器,CBT DR的使用方式与 DVMRP指派转发路由器及MOSPF DR相同。由于CBT在转发多播包时不进行RPF检查,因而当存在多条上行路径去往核心路由器时,DR在预防环路方面就显得非常重要(如图5-39所示)。
图5-39 CBT需要在多路接入网络中选举一台指派路由器,以管理去往核心路由器的多条路径
每个CBT路由器接口均被配置一个0〜255的优先值,该优先值被携带在HELLO消息中。其中,1〜254表示该路由器可以成为DR,值越小表示优先级越高,也就是说,优先值为10的路由器比优先值为20的路由器“更合格”,优先值0则表示该路由器为DR。
当CBT路由器首次在多路接入链路上激活时,会连续发送两条HELLO消息,以宣告其的存在以及优先值。之后,该路由器会侦听HELLO消息,结果为以下情形之一。
• 侦听到来自本网络其他路由器的HELLO消息中的优先值小于其优先值;
• 侦听到来自本网络其他路由器的HELLO消息中的优先值均大于其优先值;
• 没有侦听到来自本网络的其他HELLO消息。
对第一种情形来说,该新加入路由器知道优先值较小的路由器将被选举为DR。对其他两种情形来说,该新加入路由器将承担DR的角色,并在其HELLO消息中将优先值设置为0以宣告该事实。如果所有HELLO消息中的优先值均相同,那么IP地址最小的路由器将被选举为DR。
在稳定状态时,DR会每隔60秒发送一条HELLO消息,一方面宣告其状态,另一方面作为保持激活消息。此外,DR还会用HELLO消息作为来自其他新加入路由器的HELLO消息的响应消息,而其他路由器则不发送HELLO消息,也不响应来自新加入路由器的HELLO消息。
在某些情况下,选出的DR可能不在去往核心路由器的路径上。假设图5-39中的RTA被选举为DR,但RTB是去往核心路由器的最佳下一跳路由器,此时,当RTC向RTA转发JOIN_REQUEST消息时,RTA会以单播方式通过多路访问链路将JOIN_REQUEST消息转发给RTB。这种重定向操作仅仅针对于JOIN_REQUEST消息,当RTB发送JOIN_ACK消息时,该消息会被直接发送给RTC。
5.5.4 成员源和非成员源
读者可能已经注意到,到现在为止仍然只字未提多播源如何将自己的多播流量传送给核心路由器。在很多多播应用中,发送方本身也是组成员,CBT就是如此,即CBT的发送方也是组成员——即成员源(member source)。由于成员源直连的路由器是on-tree路由器,因而可以到达核心路由器。图5-40解释了这个概念,图中标记为SG1的主机是多播组1的成员源,由于该主机是一个组成员,因而其本地路由器已加入多播组1的CBT树,这样一来,当SG1发起多播组1的多播包时,本地路由器能够沿多播树向上将多播流量转发到核心路由器。
图5-40 SG1是多播组1的成员源,其本地路由器已加入多播组1的多播树,能够将多播包沿多播树向上进行转发
该操作行为描述了CBT的一个基本特性,即CBT使用双向树(bidirectional trees)。换句话说,多播流量不仅能够沿着自核心路由器至组成员的多播树下行方向进行传送,还可以沿着自成员源至核心路由器的多播树上行方向进行传送。这一点与另一种共享树协议PIM-SM不同,PIM-SM使用的是单向树。
当然,并不是所有的多播源都是组成员,因而,CBT必须有相应的机制来适应这些非成员源(nonmenber source),该机制就是IP-in-IP隧道,如图5-41所示。图中的主机正在生成多播组1的多播流量,但该主机本身并不是多播组1的组成员,当其本地路由器接收到该多播流量时,会创建一条去往核心路由器的隧道(假定该路由器正运行CBT,因而知道核心路由器的地址),之后就通过单播方式将多播流量传送给核心路由器,再由核心路由器将多播流量传送到多播树上。
图5-41 如果源主机不是组成员,那么其本地CBT路由器会将该多播源的多播流量封装在IP-in-IP隧道中,并以单播方式将多播流量传送给核心路由器
5.5.5 CBT 消息格式
CBT消息被封装在IP头部之中,协议号为7。除了本节前面所说的单播例外,数据包都被传送到目的地址224.0.0.15,且TTL为1。图5-42显示了CBT消息所共享的通用头部格式。
图5-42 CBT消息头格式
CBT消息头的字段定义如下。
• 版本(Version):指定CBT版本号,虽然有被废弃的版本1和处于提议状态的版本3,但本字段专门指定版本2。
• 类型(Type):消息类型,表5-10显示了不同CBT消息所使用的类型号。
• 地址长度(Address Length):指定相关消息中携带的单播或多播地址的长度(以字节为单位)。
• 校验和(Checksum):采用的是标准算法,是整个CBT消息的反码和的反码。
表5-10 CBT消息类型
1.CBT HELLO消息格式
HELLO消息的格式如图5-43所示,该消息被用于在多路接入网络中选举指派路由器,DR路由器会每隔60秒发送一次HELLO消息,以用于保持激活消息。
图5-43 CBT HELLO消息格式
CBT HELLO消息的字段定义如下。
• 优先值(Preference):取值范围为0〜255。其中,1〜254表示发信路由器成为DR的“合格程度”,优先值越低,表示越合格;0表示该HELLO消息由DR发起。当路由器首次在网络中被激活时,会连续发送两条包含其优先值的HELLO消息,以触发DR选举进程。优先值大于该新加入路由器优先值的路由器(较不合格)都不予以回应,而优先值小于该新加入路由器优先值的路由器将会响应一条携带其优先值的HELLO消息。这台新加入的路由器要么成为DR(如果其没有收到任何响应 HELLO消息),要么被明确告知其他具有较小优先值的路由器已经被选举为DR(通过停止发送HELLO消息)。
• 选项类型(Option Type):指定选项值(Option Value)字段中的选项类型。CBTv2仅定义了一种选项BR(Border Router,边界路由器),本节一直没有描述该选项,BR是一种将CBT域连接到其他多播路由域的路由器,由BR发起的HELLO消息中的选项类型为0。
• 选项长度(Option Length):指定选项值(Option Value)字段的长度(以字节为单位),由BR发起的HELLO消息中的选项长度为0。
• 选项值(Option Value):是一个携带选项值的可变长字段,由BR发起的HELLO消息中的选项值为0。
2.CBT JOIN_REQUEST消息格式
由于IGMP成员关系报告消息的缘故,那些希望被嫁接到某特定多播组CBT树上的路由器会发起一条JOIN_REQUEST消息,该消息的格式如图5-44所示。
图5-44 CBT JOIN_REQUEST消息格式
CBT JOIN_REQUEST消息的字段定义如下。
• 组地址(Group Address):所要加入的多播组的多播地址。
• 目标路由器(Target Router):该多播组的核心路由器的地址。
• 发信路由器(Originating Router):发起该消息的路由器的地址。
• 选项类型(Option Type)、选项长度(Option Length)和选项值(Option Value):与 HELLO消息中的对应字段一样。
3.CBT JOIN_ACK消息格式
核心路由器或on-tree路由器在响应JOIN_REQUEST消息时发送的就是JOIN_ACK消息,其格式如图5-45所示。该消息被发送给发起JOIN_REQUEST消息的发信路由器,表示已成功加入该多播组。
图5-45 CBT JOIN_ACK消息格式
CBT JOIN_ACK消息的字段定义如下。
• 组地址(Group Address):正在加入的多播组的多播地址。
• 目标路由器(Target Router):JOIN_ACK消息所要发送到的路由器地址,也就是 JOIN_REQUEST消息(即JOIN_ACK所要响应的消息)中发信路由器字段中的地址。
• 选项类型(Option Type)、选项长度(Option Length)和选项值(Option Value):与 HELLO消息中的对应字段一样。
4.CBT QUIT_NOTIFICATION消息格式
QUIT_NOTIFICATION消息的格式如图5-46所示,该消息被发送给父路由器(直连的上游路由器),以请求从某多播组树中剪除出去。当某路由器没有针对某特定多播组的下行接口时(收到了IGMP离开组消息,查询超时或者从其子路由器(直连的下游路由器)收到 QUIT_NOTIFICATION消息),就会发起QUIT_NOTIFICATION消息。
图5-46 CBT QUIT_NOTIFICATION消息格式
CBT QUIT_NOTIFICATION消息的字段定义如下。
• 组地址(Group Address):正要推出的多播组的多播地址。
• 发信子路由器(Originating Child Router):发起该消息的路由器地址。
5.CBT ECHO_REQUEST消息格式
子路由器负责维护去往父路由器的链路,为此,子路由器每隔60秒就发送一条ECHO_REQUEST消息。如图5-47所示,ECHO_REQUEST消息仅包含消息头和发信子路由器的地址。
图5-47 CBT ECHO_REQUEST消息格式
6.CBT ECHO_REPLY消息格式
父路由器发送ECHO_REPLY消息(其格式如图5-48所示)作为来自子路由器的 ECHO_REQUEST消息的响应消息,这两条消息合在一起就构成了父路由器与子路由器间链路的保持激活机制。
图5-48 CBT ECHO_REPLY消息格式
CBT ECHO_REPLY消息的字段定义如下。
• 发信父路由器(Originating Parent Router):指定消息发起者的地址。
• 组地址(Group Address):一个或多个列出了多播组地址(父路由器将这些多播组的多播包转发给链路上的子路由器)的字段。
7.CBT FLUSH_TREE消息格式
当CBT路由器失去与父路由器的连接时,会向其下游子路由器发送FLUSH_TREE消息(其格式如图5-49所示),子路由器收到FLUSH_TREE消息后,会清除该消息中列出的所有多播组的转发信息。
图5-49 CBT FLUSH_TREE消息格式
CBT FLUSH_TREE消息的字段定义如下。
组地址(Group Address):一个或多个列出了多播组地址(发信父路由器与这些多播组失去联系,收到该消息的子路由器应清除这些多播组的转发状态)的字段。