以BGP为代表的路由协议,从设计之初,就关注路由表的正确性,因为这是确保整个网络系统正常工作的最基本要求。因此每个BGP路由器,总是会以最快的速度收敛到整个网络最新的状态上。当一个BGP peer的BGP连接断开时,当前BGP路由器会认为BGP peer已经不能工作,进而会以最快的速度删除之前从这个BGP peer收到的路由。
但这里其实有一些问题。首先,BGP连接断开了不一定代表路由器不能工作了。可能只是BGP所基于的TCP连接有问题,也可能是BGP keepalive消息丢了,但是路由器还是具备正常转发的能力。如果仅以BGP断连来判断路由器不能工作有时候会误伤。其次,路由器上的BGP进程可能正在重启,所以BGP连接只是短暂的断开,马上又能重连回来。如果一断开就删路由,重新建连又添加路由,会造成BGP路由器上路由反转,进而产生短时间的路由环路或者黑洞路由。这样一个路由反转可能会传递到整个数据中心,不仅消耗了路由器控制平面的计算能力,甚至会引起整个网络的抖动。
这在之前的硬件BGP设备中不是严重的问题,因为硬件设备设计就是一直运行,不需要重启。但是对于软件BGP来说,软件维护需要经常的重启BGP进程。为了解决这个问题,RFC4724为BGP(包括传统的BGP-4和MP-BGP)增加了一种新的能力,也就是Graceful Restart,它能在BGP短时间断连的时候,不删除相应的路由信息,从而确保网络的稳定性。从协议上来看,Graceful Restart在BGP协议的基础上增加了两个部分:End-of-RIB和Graceful Restart Capability。
End-of-RIB
BGP协议是由4类消息组成的。End-of-RIB从格式上看就是一种特殊的Update消息,它没有可达的Network Layer Reachability Information(NLRI),同时带的撤回NLRI也是空的。End-of-RIB就是一个空的Update消息,按照正常的处理逻辑是没有意义,并且不会产生任何影响。BGP路由器在启动的时候,会计算本地路由并发布到与之相连的BGP peer。这个过程结束之后,BGP路由器就是断断续续的接收一些更新事件,再将路由redistribute到BGP peer。所以,BGP路由器启动之后,过程可以分为两个部分,一个是初始化路由发布,另一个是正常工作时的路由发布。对于一个支持Graceful Restart的路由器来说,End-of-RIB的作用就是区分这两个部分,它会在初始化路由发布完之后,正常工作之前发布。
Graceful Restart Capability
Graceful Restart新增了一个BGP capability(RFC5492),就叫做Graceful Restart Capability。它在BGP建立连接的时候,随着OPEN message进行发布。BGP Capability的格式如下:
对应于Graceful Restart Capability,code是64;length一个字节,最大为255;value的组成如下:
其中:
- Restart Flags
第1bit表明当前BGP是不是刚刚经历了重启。
- Restart Time
重启超时时间,12bit长,所以最多是4095秒。Restart Time建议是不超过在Open Message中的HOLDTIME。
- <AFI, SAFI, Flags for Address Family>
说明哪些BGP Address Family,支持Graceful Restart。AFI和SAFI由MP-BGP(RFC4760)定义用来标识BGP地址族。Flags for Address Family的第1bit表明,在刚才的BGP重启过程中,当前的BGP Address Family对应的路由,是否被保留了。受限于BGP Capability的长度,<AFI, SAFI, Flags for Address Family>可以是0到63个。如果是0个,说明当前路由器不能在BGP重启过程中保留任何BGP路由,但是可以配合支持Graceful Restart的对端路由器。
如果一个BGP路由器发布了Graceful Restart Capability,那就意味着它有两个能力:
- 它在重启的时候,能保留BGP路由(取决于<AFI, SAFI, Flags for Address Family>)。
- 它在初始的路由计算发布完成之后,会发布一个End-of-RIB。
支持Graceful Restart的路由器重启流程
- BGP路由器重启,BGP连接断开。
- 存储在RIB中的之前的BGP route标为stale状态,仅此而已。在生成实际路由表时,stale状态的BGP route不应该区别对待。
- BGP路由器启动,重新建立BGP连接,发送OPEN Message,在其中的Graceful Restart Capability中,Restart Flags中第1bit置1,表明刚刚经历了重启。
- 对于每个BGP Address Family,如果在重启过程中,BGP route保留了,那么相应的<AFI, SAFI, Flags for Address Family>中,Flags for Address Family的第1bit置1,表明本地仍然有之前的路由。
- 重新建立BGP连接,接收对端发来的BGP路由。但是当前路由器并不立即进行路由选择算法来更新本地路由表。
- 等到下面两个条件之一满足时再进行路由选择算法:
- 从所有的BGP peer都收到了End-of-RIB。但是这里要排除在Open Message中,将Restart Flag设置为1的peer,因为它们也在等当前路由器的End-of-RIB,而当前路由器只有在收完BGP peer的End-of-RIB并且进行完本地的路由选择算法之后才会发送自己的End-of-RIB,所以如果这里互相等待的话就会死锁。
- 路由选择算法等待时间超时了。为了避免当前路由器无尽的等待而不进行路由选择算法,支持Graceful Restart的BGP路由器,必须支持配置这个超时时间(Selection_Deferral_Timer)。
- 进行完路由选择算法之后,如果本地标为stale的BGP 路由没有从任何一个BGP peer收到更新,那么说明这条路由真的不存在了,必须被删除。
- 发布计算之后的路由到BGP peer。
- 发布End-of-RIB。
支持Graceful Restart的路由器,最主要的能力就是在BGP重启的过程中,保留之前的BGP route,同时保留自身的转发能力。在BGP 重新建立连接之后,再更新相应的BGP route。
支持Graceful Restart的路由器发现peer重启的处理流程
- 识别之前已经发送了Graceful Restart Capability的路由器,如果是支持Graceful Restart的路由器断开连接,那么执行下面的操作。
- 保留从peer路由器接收的BGP route,并标记成stale状态。仅此而已。在生成实际路由表时,stale状态的BGP route不应该区别对待。如果在这一步中,BGP route已经是stale,那么BGP route会被删除。也就是对端连续重启可能会造成本地相应的路由删除。
- 对端重新建立BGP连接,在当前BGP 路由器发送的Open Message中,其中Graceful Restart Capability中,Restart Flags中第1bit置0,除非当前BGP路由器也刚刚重启。如果在之前的Graceful Restart Capability中“Restart Time”到达之后,BGP还没有重新建连,那么stale状态的BGP route必须删除。所以,最多为对端保留路由4095秒。
- 对于每个BGP Address Family,如果在peer重启过程中,BGP route保留了,那么相应的<AFI, SAFI, Flags for Address Family>中,Flags for Address Family的第1bit置1,表明本地仍然有之前的路由。
- 但是在从peer BGP路由器收到的Graceful Restart Capability中,如果满足下面三个条件之一,表明peer BGP在重启过程中没有保留BGP route,那么需要立即删除相应的stale 状态的BGP route。
- 对应的Address Family中的Flags for Address Family第1bit为0;
- 没有相应的Address Family;
- 根本就没有Graceful Restart Capability
- 当前BGP 路由器发送End-of-RIB
- 在收到peer BGP重新发送过来的BGP route时,更新本地的stale状态BGP route。
- 当收到peer BGP发送的End-of-RIB时,删除相应Address Family中仍然为stale的BGP route。
支持Graceful Restart的路由器,在同样支持Graceful Restart的peer BGP路由器重启过程中,会保留之前的BGP route,仍然相信peer BGP具备转发能力。在BGP 重新建立连接之后,再更新相应的BGP route。
BGP优雅重启,实际上就是将作为控制平面的BGP和转发平面解耦开。这样,就算控制面BGP断开了,也不影响数据面的转发能力。