bgp优雅重启机制

背景

以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。

bgp优雅重启机制

End-of-RIB

bgp软重启 软重置 bgp优雅重启_路由选择算法

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

bgp软重启 软重置 bgp优雅重启_路由选择算法_02

bgp软重启 软重置 bgp优雅重启_bgp软重启 软重置_03


bgp软重启 软重置 bgp优雅重启_网络协议_04

1、支持Graceful Restart的路由器重启流程

1、BGP路由器重启,BGP连接断开。

2、存储在RIB中的之前的BGP route标为stale状态,仅此而已。在生成实际路由表时,stale状态的BGP route不应该区别对待。

3、BGP路由器启动,重新建立BGP连接,发送OPEN Message,在其中的Graceful Restart Capability中,Restart Flags中第1bit置1,表明刚刚经历了重启。

4、对于每个BGP Address Family,如果在重启过程中,BGP route保留了,那么相应的<AFI, SAFI, Flags for Address Family>中,Flags for Address Family的第1bit置1,表明本地仍然有之前的路由。

5、重新建立BGP连接,接收对端发来的BGP路由。但是当前路由器并不立即进行路由选择算法来更新本地路由表。

6、等到下面两个条件之一满足时再进行路由选择算法:

* 从所有的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)。

7、进行完路由选择算法之后,如果本地标为stale的BGP 路由没有从任何一个BGP peer收到更新,那么说明这条路由真的不存在了,必须被删除。

8、发布计算之后的路由到BGP peer。

9、发布End-of-RIB。

支持Graceful Restart的路由器,最主要的能力就是在BGP重启的过程中,保留之前的BGP route,同时保留自身的转发能力。在BGP 重新建立连接之后,再更新相应的BGP route

2、支持Graceful Restart的路由器发现peer重启的处理流程

1、识别之前已经发送了Graceful Restart Capability的路由器,如果是支持Graceful Restart的路由器断开连接,那么执行下面的操作。

2、保留从peer路由器接收的BGP route,并标记成stale状态。仅此而已。在生成实际路由表时,stale状态的BGP route不应该区别对待。如果在这一步中,BGP route已经是stale,那么BGP route会被删除。也就是对端连续重启可能会造成本地相应的路由删除。

3、对端重新建立BGP连接,在当前BGP 路由器发送的Open Message中,其中Graceful Restart Capability中,Restart Flags中第1bit置0,除非当前BGP路由器也刚刚重启。如果在之前的Graceful Restart Capability中“Restart Time”到达之后,BGP还没有重新建连,那么stale状态的BGP route必须删除。所以,最多为对端保留路由4095秒。

4、对于每个BGP Address Family,如果在peer重启过程中,BGP route保留了,那么相应的<AFI, SAFI, Flags for Address Family>中,Flags for Address Family的第1bit置1,表明本地仍然有之前的路由。

5、但是在从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

6、当前BGP 路由器发送End-of-RIB

7、在收到peer BGP重新发送过来的BGP route时,更新本地的stale状态BGP route。

8、当收到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断开了,也不影响数据面的转发能力。

优雅重启工作流程

bgp软重启 软重置 bgp优雅重启_网络协议_05

bgp软重启 软重置 bgp优雅重启_kubernetes_06


bgp软重启 软重置 bgp优雅重启_网络协议_07

golang如何使用bgp优雅重启机制

示例来源:kube-router

https://github.com/cloudnativelabs/kube-router/blob/master/pkg/controllers/routing/bgp_peers.go

使用gobgp库进行建立bgp连接的时候,可以参考一下示例打开bgp优雅重启机制

if nrc.bgpGracefulRestart {
			n.GracefulRestart = &gobgpapi.GracefulRestart{
				Enabled:         true,
				RestartTime:     uint32(nrc.bgpGracefulRestartTime.Seconds()),
				DeferralTime:    uint32(nrc.bgpGracefulRestartDeferralTime.Seconds()),
				LocalRestarting: true,
			}

			if nrc.isIpv6 {
				n.AfiSafis = []*gobgpapi.AfiSafi{
					{
						Config: &gobgpapi.AfiSafiConfig{
							Family:  &gobgpapi.Family{Afi: gobgpapi.Family_AFI_IP6, Safi: gobgpapi.Family_SAFI_UNICAST},
							Enabled: true,
						},
						MpGracefulRestart: &gobgpapi.MpGracefulRestart{
							Config: &gobgpapi.MpGracefulRestartConfig{
								Enabled: true,
							},
							State: &gobgpapi.MpGracefulRestartState{},
						},
					},
				}
			} else {
				n.AfiSafis = []*gobgpapi.AfiSafi{
					{
						Config: &gobgpapi.AfiSafiConfig{
							Family:  &gobgpapi.Family{Afi: gobgpapi.Family_AFI_IP, Safi: gobgpapi.Family_SAFI_UNICAST},
							Enabled: true,
						},
						MpGracefulRestart: &gobgpapi.MpGracefulRestart{
							Config: &gobgpapi.MpGracefulRestartConfig{
								Enabled: true,
							},
							State: &gobgpapi.MpGracefulRestartState{},
						},
					},
				}
			}
		}

注意

bgp软重启 软重置 bgp优雅重启_bgp软重启 软重置_08