文/叶翀
在开始之前,假设让我们来给通信协议画一个简单的素描。
抛开对上层协议和复杂应用的支持不谈,通信协议最基本的功能是运行在两台或多台设备之间,通过收集、发布、交换一些信息,来为设备间的通信建立通道,即实现支撑上层数据互通。为了实现通信协议这个基本功能,需要解决三个问题:
l 单台设备需要收集和存储哪些信息?
l 设备之间如何交互和通信,来汇总出完整的信息?
l 信息汇总之后,进行怎样的决策,来得出通信通道?
对如上三个问题进一步分解,可以得出:
一、协议发布哪些信息?
l 协议需要哪些信息?
l 如何描述和存储这些信息?
二、与谁交换信息?
l 选择哪一个底层协议作为承载进行通信交互?
l 动态发现交换对象——邻居,还是静态配置邻居?
l 邻居建立过程是怎样的?
三、如何交换信息?
l 交换信息报文格式如何?
l 报文格式怎么做可以具备比较好的扩展性?
四、如何从信息中决策出最佳通信通道?
五、其他必要的考虑
通过这些问题,我们将在下文描述BGP的简单框架。当然这些仅仅是框架,它们只是BGP协议最基础的部分。BGP最强大的功能在于灵活的策略和多协议扩展支持,这些在本文中都没有涉及,在本刊的其他文章中都会有详尽的介绍。
在BGP的前身EGP中,引入一个概念,叫做自治系统AS,Autonomous System。AS指的是在统一技术管理下的一系列路由器。比如运行OSPF的一张网络,或者运行ISIS的一张网络,都可以作为一个AS。实际网络中,自治系统是人工规划的,AS号由专门的机构分配。通常在AS内部运行某种IGP协议,用于AS内部的路由学习和管理;而在AS的边界运行BGP,用于AS之间交换路由信息。借助BGP,各AS可以独立选择自己适合的IGP协议,并通过BGP来获得其它AS的路由信息。
从这个用途来看,对BGP来说,需要做到以下几点:
l 能够支持从各类IGP(包括直连路由)引入路由信息
l 能够从这些数据中决策出最优路由
l 不论从哪类IGP引入,将最优路由对外发布时,采用统一的格式
路由信息的引入过程不在本文的讨论范围内,决策过程见本文第5节。我们来看看上面三点中信息的收集和存储问题。BGP需要收集哪些信息,来支撑下一步的决策?
最基本的是IP前缀和掩码、下一跳,这是一条路由的最简描述,任何一种路由协议都需要收集这些信息。为了支持路由优选,需要考虑路由的优先级(至少一种度量),并记录路由的来源(哪个AS发布,什么方式引入),这是我们需要收集的可供下一步决策的最小信息集合。后面我们会看到,这些其实就是BGP UPDATE报文中的主要字段。IP前缀和掩码对应UPDATE中的NLRI,下一跳对应NEXT_HOP,优先级对应LOCAL_PREF和MED,路由来源对应AS_PATH和ORIGIN。
BGP存储路由信息的数据库叫做RIB,Routing Information Base。这个数据库分为三个部分:
l Adj-RIBs-In,保存BGP Speaker从邻居学到的路由信息,即初始路由
l Loc-RIB,保存经过决策从Adj-RIBs-In选取的路由信息,即最优路由
l Adj-RIBs-Out,保存BGP Speaker发给邻居的路由信息,即发布路由
上面三个数据库,仅仅是协议关于BGP路由管理的概念性设想,实际实现中,不要求必须保留路由的三套拷贝。
初步设想了单台设备需要收集和存储哪些信息之后,我们来看看设备之间如何通信。考虑到BGP用在AS之间,是作为大型网络之间接口的角色存在,对报文传输的稳定性有很高的要求,BGP选择了TCP作为承载协议,使用端口号179。由于TCP提供了稳定可靠的传输,BGP不需要专门的机制来处理复杂的报文分片、重传、确认等细节。
在TCP之上,BGP报文头如图1所示,共19个字节:
图1 BGP报文头
承载不同BGP协议报文类型通过Type字段标识,Length字段标识BGP消息的字节长度,含BGP报文头,虽然是16Bit数,合法范围只从19到4096。Marker字段用来探测对端与本端是否同步。
承载协议确立为TCP之后,下一个问题是,采用普通路由协议的动态发现邻居方式呢,还是采用手工静态配置方式?BGP采用了后者,只要双方指定地址路由可达,就可以建立邻居。这么做至少有两个好处:
1、可以与对端设备用任何IP地址建立邻居,而不限于某个固定的接口IP。这样,当两台设备采用环回地址而非直连地址建立BGP邻居时,即使主链路中断了,也可以切换到备份链路上,保持邻居不断。这种稳定性正是BGP作为大型网络路由承载的必要特质。
2、可以跨越多台设备建立邻居。当一个AS有多个设备运行BGP 建立域内全连接时,不必每台设备物理直连,只要用IGP保证建立邻居的地址可达,即可建立全网连接,减少不必要的链路建设。
同一个AS内,设备之间的邻居叫做IBGP(Interior BGP)邻居,不同AS间,设备之间的邻居叫做EBGP(Exterior BGP)邻居。运行BGP的设备叫做BGP发言者(BGP Speaker),相互之间称作BGP对等体(BGP peer)。
BGP用来建立邻居的OPEN消息格式如图2所示:
图2 OPEN消息
Version:标识运行的BGP版本。如果一个对等体的版本比对方旧,它会拒绝新版本的连接,于是对方降低版本号重新进行协商,直到双方对版本达成一致为止。
My AS:邻居建立发起者的AS号。用来决定双方是IBGP邻居,还是EBGP邻居。
Hold Time:对等体通过定期发送KEEPALIVE消息通知对端本端还在,以保持邻居。由于KEEPALIVE纯粹是一个通信知会,不需要携带什么信息,因此KEEPALIVE报文实际上是不带数据的BGP报文头。Hold Time是设备收到一个KEEPALIVE之前允许经过的最大秒数。这个时间或者是0秒(不发送KEEPALIVE),或者是至少3秒。一般默认KEEPALIVE每60秒发送一次,Hold Time为180秒。协商时,采用OPEN消息中较小的那个Hold Time作为双方的Hold Time。
BGP Identifier:用来标识邻居的IP地址。
Optional Parameters:公布对一些可选功能的支持,如认证、多协议支持等等。
建立邻居时,BGP先尝试与对等体建立一个TCP连接。如果TCP连接建立成功,BGP发送一个OPEN消息给对端,并等待从对端发来的OPEN消息。收到一个OPEN消息以后,BGP检查该消息的所有字段,如果没有发现错误,则向对端发送一个KEEPALIVE消息并启动KEEPALIVE定时器。收到KEEPALIVE消息,则邻居建立。
当邻居检测到错误需要中断连接时,BGP发送NOTIFICATION消息通知对端,消息格式如图3所示:
图3 NOTIFICATION消息
相关错误码和含义的列表请参考协议,这里不展开讨论。
综上我们可以得出BGP四种消息报文的用途:OPEN用来建立邻居,KEEPALIVE维持邻居,UPDATE发布路由信息,NOTIFICATION通知对端检测到错误。
BGP建立邻居采用有限状态机,共有6种状态。BGP的运行流程就是在这6种状态之间根据资源和事件的要求作转换。它们分别是:
1、Idle
BGP协议初始时是处于Idle状态。在这个状态时,系统不分配任何资源,也拒绝所有进入的BGP连接。只有收到Start Event时,才分配BGP资源,启动ConnectRetry计时器,启动对其它BGP对等体的传输层连接,同时也侦听是否有来自其它对等体的连接请求。
2、Connect
这个状态下,BGP等待TCP完成连接。若连接成功,本地清空ConnectRetry计时器,并向对等体发送OPEN报文,然后状态改变为OpenSent状态;否则,本地重置ConnectRetry计时器,侦听是否有对等体启动连接,并移至Active状态。
3、Active
这个状态下,BGP初始化TCP连接来获得一个对等体。如果连接成功,本地清空ConnectRetry计时器,并向对等体发送OPEN报文,并转至OpenSent状态。
4、OpenSent
这个状态下,BGP等待对等体的OPEN报文。收到报文后对报文进行检查,如果发现错误,本地发送NOTIFICATION报文给对等体,并改变状态为IDLE。如果报文正确,BGP发送KEEPALIVE报文,并转至OpenConfirm状态。
5、OpenConfirm
这个状态下,BGP等待KEEPALIVE或NOTIFICATION报文。如果收到KEEPALIVE报文,则进入Established状态,如果收到NOTIFICATION报文,则变为Idle状态。
6、Established
这个状态下, BGP可以和其他对等体交换UPDATE,NOTIFICATION,KEEPALIVE报文。如果收到了正确的UPDATE或KEEPALIVE报文,就认为对端处于正常运行状态,本地重置Hold Timer。如果收到NOTIFICATION报文,本地转到Idle状态。如果收到错误的UPDATE报文,本地发送NOTIFICATION报文通知对端,并改变本地状态为Idle。如果收到了TCP拆链通知,本地关闭BGP连接,并回到Idle状态。
综上,我们可以画出BGP的有限状态机如图4所示:
图4 BGP有限状态机
邻居建立后,BGP采用UPDATE消息来发布路由或撤销路由。UPDATE消息由三部分组成:
Unfeasible Routes:之前发布过,不再有效的路由。
Path Attributes:路由信息的附加描述,是BGP用以进行路由控制和决策的重要信息。
NLRI:由一个或多个IP地址/前缀长度组成。
其格式如图5所示,一个UPDATE消息中可以携带多条路由信息:
图5 UPDATE消息
由于BGP在报文格式中普遍采用了TLV(Type,Length,Value)的形式,而不是固定长度固定字段的形式,使得BGP具有非常好的扩展性,在后期追加新类型支持新业务时,只需要定义新的类型编码和值,报文不需要做任何更改。
关于BGP属性的具体类型和含义,请参考《BGP属性简介》一文。
上面我们描述了BGP发言者之间交换哪些信息。决策过程选择路由用于下一步的发布,应用本地策略信息库PIB(Policy Informaiton Base)来处理Adj-RIB-In中的路由。决策过程的输出是发布到所有邻居(包括IBGP和EBGP)的路由信息集合,被选的路由存储在Adj-RIB-Out中。
决策过程分三步来进行:
1、当本地BGP发言者接收到EBGP邻居发布过来的更新、替代或撤销路由时,为每一条路由计算优先级,并将最高优先级的路由通告到所有IBGP邻居。
2、在步骤一完成后激活。负责从到达目的地的所有路由中选择最好的路由,同时安装每条选中的路由到相应的Loc-RIB。如果路由信息携带的下一跳路由不可达,则将该路由排除在这个决策过程之外。
3、在步骤二完成后激活。负责根据在PIB中的规则,发布Loc_RIB中的路由到EBGP邻居的每个对端。
最优路由有三种情况:
1、 对同一个目的地集合有路由的最高优先级
2、 是到目的地的唯一路由
3、 两条或两条以上具有相同优先级,必须用更细的法则算出一条最优来。此过程称之为Tie-Break
一般来说,BGP计算路由优先级采用如下规则:
1、 选择具有最高LOCAL_PREF值的路由
2、 如果LOCAL_PREF相同,选择从本地IGP(含直连路由)引入的路由
3、 如果LOCAL_PREF相同,且没有本地引入路由,则选择AS_PATH最短的路由
4、 如果AS_PATH路径长度相同,判断ORIGIN值,IGP优于EGP,EGP优于Incomplete
5、 如果ORIGIN相同,优选MULTI_EXIT_DISC值较小的
6、 如果MED也相同,依次选择从EBGP、Confederation、IBGP发布的路由
7、 如果发布源也相同,优选下一跳IP在本地路由表中Cost值最小的路由
8、 如果下一跳Cost也相同,优选CLUSTER_LIST长度最短的路由
9、 如果CLUSTER_LIST长度也相同,优选ORIGINATOR_ID最小的路由
10、 如果ORIGINATOR_ID长度也相同,优选ROUTER_ID最小的路由
Tie-break采用如下过程:
1、 优选MULTI_EXIT_DISC值较小的.
2、 优选下一跳IP在本地路由表中Cost值最小的路由
3、 优选EBGP邻居发布的路由
4、 选择BGP标识符最小的邻居发布的路由
为优化协议,BGP还在如下方面做了考虑:
1、减少路由振荡
大型网络之间,路有频繁振荡会带来严重的后果。因此BGP为尽可能减少路由振荡做了一些考虑。
l BGP邻居超时时间很长,通常是180秒。当应用环回地址建立邻居时,即便链路中断,只要备份链路能够及时发布切换环回地址路由,邻居可以保持建立,不引起振荡。
l BGP规定,如果需要撤销到一个目的地址的路由,同时更新一个掩码不同的路由,则应该把他们组合在一个UPDATE消息中。这样BGP可以一次处理,不出现路由振荡。
l BGP提供路由抑制机制(Route flap damping),它为每条路由分配一个动态的度量数字,用来反馈路由稳定程度。当一条路由出现振荡,就给他分配一个惩罚值。振荡越多,惩罚值越高。如果惩罚值超出预设的门限,该路由就不再对外发布。直到一段时间后惩罚值降低到可重新使用的门限值。
2、节省设备资源
l 在BGP向其他邻居发布路由时,引入一个介于0.75~1的随机因子,将该因子分别与每对邻居间发布路由的最小时间间隔相乘,从而得出不同的路由发布最小时间间隔,以避免路由都挤在一个时间发布占用太多的带宽和CPU。
l BGP支持路由聚合,可根据某些属性进行灵活的聚合,减少路由发布条目。
l 引入路由反射器。IBGP要求全链接,引入反射器后,每台BGP发言者只需要与BGP反射器建立邻居,BGP反射器会把从IBGP邻居学到的路由发布给其他IBGP邻居,以节省开销。
小测试:
1、 你能画出BGP的邻居状态机吗?
2、 BGP采用手工静态配置邻居,有哪些好处?