在FB闯祸的BGP协议简介

Facebook官方披露了这次事故,连接如下

https://engineering.fb.com/2021/10/05/networking-traffic/outage-details/

所以真是无巧不成书, 本来是一个日常的运维任务,使用一条命令去检测全球骨干网的可靠性, 但是非常有效的的确把整个骨干网搞挂了。官方言论肯定要加上一句,我们不是野蛮施工,有命令行Audit工具,但是工具有bug让它无法停止。事实上我们在做很多操作的时候,都会加一个Rollback timer,如果没有人工干预确认,自动在几分钟后就失效。这个是FB保护不好的锅。

紧接着的问题来了,就是DNS服务器终端,导致内部工具完全无法使用,同时另一个问题来了,就是它们DNS的设计也很奇怪, 使用DNS服务器来控制BGP通告,魔改的真有趣了,也就是说后续的BGP withdraw是因为这些Prefix的主机无法到达DNS服务器(DNS被黑洞了)然后DNS服务器在对外的BGP通告中把它们撤销了…. 这个锅..然后就是DNS服务器挂了以后所有内部的工具也挂了,正如我昨天猜测的,然后紧接着好几个小时没有BGP消息的动静,最后这种官方言论嘛一定是我们对用户的资产保护很好的,所以所有的物理安全防护做的非常好,但是物理无法访问它,只能用各种斧头锯子然后慢慢重启接入门禁搞定。。。

这次FB闯祸的BGP协议介绍,协议的确很复杂,所以不要轻易责怪运维的人,毕竟除了写code的人基本上外面没几个人讲的清楚的,而全世界能写BGP Stack的也就那么些人。大概这个文章写于2009年公司内部培训用的. 懒得更新了,直接贴, 这东西反正在我10年后撸一个基于Go的BGP-LS协议栈时还能抄作业… 后面十多年扩展的FlowSpec、EVPN、LS、BMP、SR这些东西懒得整了,因为本来一个协议已经够复杂了不堪重负了,还继续往上加东西…

BGP概述

BGP发展历程

BGP协议源于1989年1月第12次IETF会议, 由Len Bosack, Kirk Lougheed 和Yakov Rekhter提出实现一种所谓的边界网关协议(Board Gateway Protocol”, 其后在三张餐巾纸上完成了BGP设计的草稿. 然后在会议结束后的不到一个月的时间, 他们提出了两个BGP的实现方案, 并在1989年6月发布了RFC1105.

协议设计之初的想法比较简单, 第一个想法在路由信息中包含相关的路径属性, 并且使用它来提供无环路的路由. 第二个想法是采用增量更新来尽量减少路由信息在两个路由器之间的交互. 第三个想法则是通过TCP来保证可靠传输. 最后一个想法则是使用TLV的方式来定义数据结构, 这样使得协议拥有了很好的扩展性. 在BGP发展的这20年中经历了一系列的”浪潮”. 首先是对IPv4的无类域间路由(CIDR)的支持. 然后则是支持BGP联盟(Confederations)/BGP 路由反射器(Route-Reflectors) / BGP团体属性(Community)/ BGP路由惩罚(Route Dampening). 第三次演变浪潮则是支持多协议扩展(Multi-protocols Extensions)和能力通告(Capability Advertisement). 第四次则是加入 BGP/MPLS IP VPN以及基于BGP的VPN自动发现和基于BGP的VPLS支持. 而最近一次演变则是对于4Bytes AS号的支持. 这一系列的演变将BGP的用途进行了很大的扩展, 而不仅限于原有的域间路由功能.

最初的6年(1989~1995), BGP版本号从BGP-1一直升级到BGP-4. 其中包括1990年更新的RFC1163, 1991年10月更新的RFC1267, 直到Tony Li参与制定的BGP-4(RFC1771). 然而从1995年起, BGP的版本号一直沿用到现在. 当然直至今日BGP已经不是一个简单的支持IPv4和IPv6的域间路由协议. 而更多的被设计用来承载自治系统的一些信息来支持一些新的应用(MPLS VPN , VPLS ….).

从BGP的发展历程来看, 我们也可以看到一条实用性的发展方向, 根据遇到的问题, 在基于实用性基础上不停的进行开发. 具体的发展历程可以参考:

http://www.ietf.org/dyn/wg/charter/idr-charter.html

BGP设计理念

为了能够理解BGP为什么这样设计, 首先需要对路由协议进行深入的了解. 从某种意义上来说, 路由协议被分为内部网关协议(IGP)和外部网关协议(EGP). 通常内部和外部通过路由域(Routing domain)来区分.而路由域的实际定义则需要根据上下文的关系来确定. 例如OSPF中的区域. IS-IS中由不同Level隔开的区域.在BGP中定义的路由域则是指的一系列在相同管理控制策略下的路由器的集合. 例如一个工厂内部的所有路由器都由公司内部的技术部门控制, 一个运营商内所有的路由器也都由运营商的网管中心控制. 在BGP中, 我们将这样的路由域称为自治系统(Autonomous System ,AS).

在此, 我们还会有一个疑问: 由于所有的路由协议都是用于提供可达性信息和路径信息, 那么为什么需要IGP和EGP而不是一个单一的整合的路由协议?
事实上在一个自治系统内部, 所有路由器都受到有效地控制, 因此策略传播(policy propagation)并不重要(策略可以通过网管系统或者手工统一配置), 而收敛速度在一个自治系统内部则是十分重要的因素. 相反对于自治系统之间并不是显得那么的重要. 因此在一个自治系统中的路由协议必须关注所提供的汇总信息快速而有效.

那么为什么要刻意去区分路由域内部或者外部的路由? 其主要原因如下:

  • 防止其他路由域中的一些变化对网络运行产生影响.
  • 隐藏网络内部的拓扑信息
  • 易于执行域间的策略, 例如控制域间流量进出的方向.

BGP算法简介

前面我们已经看到过基于距离矢量的RIP和EIGRP的路由协议以及基于链路状态的OSPF和IS-IS. 但当设计实现BGP时将会发现如上两种算法都不适合. 首先对于链路状态路由协议, 由于使用最短路径优先的算法, 因此所支持的路由前缀数目并不是很多. 而距离矢量的路由协议在进行一系列策略时并不灵活,如下拓扑:

在FB闯祸的BGP协议简介

A公司需要连接到C公司, 那么根据链路状态路由协议, 流量将从B公司穿越, 而事实上B公司并不愿意流量穿越的情况, 而与此同时又不想过滤A公司和B公司之间的正常业务流. 因此在域间的路由策略上, 我们需要定义更多的链路属性使其完成不同策略的需求. 与此同时还需要承受大量的路由条目更新(到目前为止, Internet路由条目总数已经超过30万条), 如下图所示:

在FB闯祸的BGP协议简介

看吧,2009年才30万条,现在已经100万条了.

面对如此大量的路由条目, 我们实际上需要一种简单而有效地算法, 一方面完成相关策略的处理, 另外一方面预防路由环路. 因此实现了一种基于路径矢量(Path Vector)的算法,即每个路由条目更新通过一个AS时, 将其穿越的AS号码记录下来, 通过避免路径属性中出现相同的AS号码来避免环路的策略.

BGP对等体关系(BGP Peering)

从拓扑结构上来看, BGP将存在两种邻居关系. 一种是指两个BGP路由器都在同一个自治系统内部构成一个内部的BGP邻接(iBGP)关系, 而处于不同自治系统的BGP路由器则构成外部BGP(EBGP)关系. 在部署时协议对iBGP和EBGP做出了一些严格的要求, 这些内容将在后续的章节叙述.

BGP消息类型

在RFC1771和后续更新的RFC4271中定义了四种BGP消息类型, 它们分别是Open Keepalive UpdateNotification消息.在RFC 2918中定义了第5种消息类型: Route-refresh消息. 同时还规定BGP消息的最大长度为4096字节, 并且每个多字节字段必须使用网络字节序, BGP消息头部(Message header)结构如下图所示:

Marker字段: 长度为16字节. 在RFC1771中被定义用于消息接收者能够预测或者用于BGP Peers之间检测同步丢失的情况以及参与BGP消息的认证工作, 而在2006年更新的RFC4271中则要求该字段所有位都设置为1.

Length字段: 长度为2字节, 其值范围为19字节~4096字节. 该值为整个消息的最小需要的长度, RFC规定BGP消息不能在消息尾端进行任何填充.

Type字段:  消息类型字段, 长度为1字节, 现阶段定义的消息类型如下所示:

Open Message

当传输层(现阶段仅为TCP)处于Established状态, BGP路由器两端发送的第一个消息就是OPEN消息. 它被用于标示自己, 并规定自己的BGP运行参数. 如果OPEN消息被对端接受, 对端将发送一个KEEPALIVE消息作为确认. 通过Wireshark 捕获的OPEN消息如下:

可以注意到在OPEN消息中包含有BGP消息头, 并且Marker字段被全部设置为了1. 而Type字段的值为1, 即表示这是一个OPEN消息. 紧接着BGP消息头的部分为OPEN消息的内容. 其数据结构如下:

Version:是一个1字节的无符号整数, 现在所使用的RFC4271定义的版本号是 4.

My Autonomous System: 是指发送端路由器所使用的自治系统号. 长度为2字节, 该字节可以用于用于确认EBGP或者IBGP会话(注意:对于4字节ASN的特殊处理将会在后续章节中介绍.)

HoldTime:长度为2字节, 路由器收到一个keepalive或者UPDATE消息之前允许经过的最大时间(单位为秒). Holdtime必须是0(在这种情况下, 必须是没有发送(Keepalive)或者至少3s. Cisco默认的holdtime为180s, 如果两个邻居间holdtime不一致, 选较短的做为两者可接受的时间.

BGP Identifier:4字节的无符号整数, 用于区分不同的发送者,  BGP-ID仅在启动BGP进程的时候选定, 并且在每个本地接口或者邻接关系中保持一致. 其选取方式和OSPF相同,使用数值最大的loopback口地址,没有loopback则使用物理接口上数值最大的地址.

Opt Parm Len: 长度为1字节的整数, 用于定义Optional Parameters字段的长度.

Optional Parameters: 长度可变的字段. 用于携带一系列的可选参数. 例如例如鉴别,多协议支持及路由刷新等, 其数据结构如下: 可选参数主要包括Capability Optional Parmeters, 该字段由RFC3392定义.

KEEPALIVE Message

由于BGP没有使用基于TCP的Keepalive机制来检测邻居的可达性. 因此使用了KEEPALIVE消息来实现相应的功能. 同时该消息还可以用于在路由器接受了他在邻居的Open消息中的参数时进行应答. KEEPALIVE消息仅有一个BGP消息头部, 并且Type值等于4. 在Cisco路由器上默认情况Keepalive间隔 60s, 或者是达成一致的Hold Timer的1/3.

事实上, 多个BGP消息可以封装在同一个BGP的报文中, 例如KEEPALIVE消息和OPEN消息可以封装在同一个TCP报文中发送. 如下所示:

UPDATE Message

UPDATE消息主要用于在两个BGP对等体之间传输路由信息.并被用来构造说明自治系统之间关系的图结构.  UPDATE消息被用于通告可用的路由(feasible routes)条目并携带相应的路径属性. 与此同时还可以同时撤销多个不可用的路由. 通过Wireshark捕获的UPDATE报文结构如下所示:

如上可知.  UPDATE消息数据结构如下(但并不是每个UPDATE消息都包括这些字段):

Withdrawn Routes Length: 在一些系统中也被称为unfeasible routes length. 这是一个16位长的整数字段, 用于标记路径属性的起始位置(通过标记撤销路由字段的长度来间接地表示路径属性字段的起始位置).

Withdrawn Routes: 这是一个可变长度的字段包含了需要撤销IP前缀的列表. 并且撤销的地址列表由如下结构构成:

Total Path Attribute Length: 这是一个长度为16位的字段, 包含了所有通告的路径属性的长度, 同时也标明了NLRI的起始位置.

Path Attribute: 这是一个长度可变的字段, 包含了所通告的路由前缀的路径属性, 关于路径属性的内容, 我们将在后续的章节详细叙述.

Network Layer Reachability Info: 这是一个长度可变的字段, 包含了所通告的可行路由(feasilbe Routes). 相应的数据结构如下:

虽然NLRI字段可以包含多个前缀, 但每一个更新消息只描述一条BGP路由(因为路径属性只描述一条路径,但该路径可能会到达多个目的地), 而且当一个消息没有需要撤销的路由(withdrawn route)的时候, Withdrawn Routes字段不存在, 但withdrawn routes length字段必须设置为0.

NOTIFICATION Message

NOTIFICATION消息用于在检测到错误后进行通告, 当NOTIFICATION消息发出后, BGP连接应当立即关闭.  NOTIFICATION消息结构如下:

ERROR Code: 这是一个长度为8位的字段, 包含了错误信息代码.

ERROR SubCode: 这是一个长度为8位的字段, 包含了错误信息子代码.

Data: 这是一个可变长度的字段, 用于对NOTIFICATION的原因进行诊断. 具体内容将在后续章节中叙述.

通过Wireshark捕获的NOTIFICATION消息如下:

ROUTE-REFRESH Message

ROUTE-REFRESH消息在RFC2918中定义. 较早的Soft-reconfiguration做法是把所有的路由拷贝一份, 但这样的做法会消耗大量的CPU和内存的资源. 因此在RFC2918中提出了使用一种新的机制让邻居重新通告来完成这样的工作.

ROUTE-REFRESH消息用于实现路由刷新的能力, 即允许在两个BGP路由器之间动态的交换路由刷新请求并在后续的过程中使相关的Adj-RIB-Out重新通告路由. 最常见的应用是路由器能够简单的进行不间断的策略修改. 其消息结构如下所示:

通过wireshark捕获的报文如下:

BGP Version 协商

在RFC4271 Section 7 定义了BGP版本协商的过程. 当OPEN消息发现版本号不一致时, 路由器将首先发送一个OPEN Message Error的NOTIFICATION消息给对端路由器, 然后降低版本号重发Open消息, 直到版本一致. 但事实上现阶段所有的BGP路由器的版本都是BGP-4, 因此很少存在版本协商的情况.

BGP 能力通告(Capability Advertisement)

BGP Capability Advertisement在RFC2842中, 并根据BGP的发展被RFC3392更新. 后续的一次更新则是在2009年2月发布的RFC5492. 它主要是在OPEN消息中的Optional Parameter字段定义Capabilities Parameters来实现能力交互的过程, 并使得BGP 协议栈能够更容易的进行平滑的能力通告(graceful capability advertisement).

在RFC4271中规定当 BGP收到的 OPEN消息中含有一个或者多个不识别的 Optional Parameters时 , 将会立即终止 BGP对等体关系 . RFC5492定义了一套使用 OPEN消息中的 Optional Parameter字段进行能力交互的规则 , 并允许符合此规范的路由器即便是存在不识别的能力时也能对自己和对等体都支持的能力来产生对等体关系 . Capability Optional Parameter结构 (Parameters Type = 2)如下图所示 :

通过 wireshark捕获的报文如下所示 :

Capabilities Advertisement相关的规则如下 :

  1. 当 BGP路由器检测到邻居不支持 Capabilities Advertisement. 路由器将收到来自邻居错误子代码为为 “Unsupported Optional Parameter” 的 NOTIFICATION消息 . 这时 BGP路由器应当尝试重新建立 BGP连接并不发送 Capabilities Optional Parameter.
  2. 如果 BGP路由器支持 某个 Capabilities但检测到邻居不支持 , 此时可以发送 携带 Unsupported Capability错误子代码的 NOTIFICATION消息告知邻居 .
  3. 如果 BGP路由器 从对端 收到 一个不支持的 Capability时必须忽略它 .

BGP状态机

BGP对等体关系建立的状态机如下图所示:

Idle 状态

BGP通常以Idle State开始(此时拒绝接收所有入连接). 当一个开始事件出现, BGP过程初始化所有BGP资源, 打开重试连接(ConnectRetry)计时器, 初始化到邻居的TCP连接,接听来自邻居的TCP初始化消息并将它的状态转到Connect状态.开始事件是由一个操作者配置一个BGP进程, 或者重置一个已经存在的过程或者路由器软件重置BGP过程引起

一个错误的出现会将BGP过程的状态转为Idle. 路由器可能会试图发起另外一个开始事件. 为了防止在持续错误条件下导致的抖动, 在第一次转回到空闲状态后, 路由器会自动开启重试连接计时器, 当计时器终止后, 路由器就会放弃重新开始BGP.重试计时器第一次的时间为60s, 下一次为前一次的2倍120s, 成指数形式增加

Connect状态

此状态下BGP过程会等到 TCP连接完成以后再决定后续的动作 . 如果 TCP连接建立成功 , BGP连接将ConnectRetry清零 , 完成初始化并给邻居发送一个 Open消息 , 转移到 Open状态 . 如果 TCP连接建立失败 , BGP继续监听由邻居发起的连接 , 重置 ConnectRetry计时器并转移到 Active状态 如果在连接状态下 , ConnectRetry超时 , 计时器将重新开始 , 并再一次试图与邻居建立 TCP连接, BGP保持 Connect状态, 此时如果有任何其他输入事件, 转入 Idle状态

Active状态

在此状态, BGP过程试图与邻居建立一个 TCP连接 . 如果连接成功 , BGP过程将 ConnectRetry计时器清零 , 完成初始化 , 给邻居发送一个 Open消息并转移到发送 Open消息状态 , Hold计时器设置为 4mins. 如果在激活状态 , ConnectRelay计时器超时 , 将回到 ConnectState并且重置 ConnectRelay计时器 .也发起一个到对等的TCP连接并继续监听来自对等体的连接 . 如果邻居试图与一个未知 IP建立 TCP会话 , 同时 ConnectRelay计时器重置 , 连接被拒绝并保持在 Active状态 .

OPEN Sent状态

在此状态下, 已经发送了 Open消息 , BGP等待邻居发来的 Open消息 , 当收到一个 Open消息 , 如果发现差错 , 将给邻居发一个 Notification消息并转入 Idle状态 . 如果收到的 Open消息没有差错 (在此时将进行Version协商和 Capability Advertisement的处理 ), 将给邻居发送一个 Keepalive消息并将 Keepalive计时器清零 ,此时协商一个较短的 holdtime, 如果为 0, 则没有启动 Hold和 keepalive计时器 , 根据 AS号选择 IBGP或者 EBGP, 同时将状态转移到 OpenConfirm状态 . 如果收到一个 TCP断开消息 ,本地断开 BGP连接 ,重置 ConnectRetry计时器 ,并转入 Active状态 .

OPEN Confirm状态

此状态下BGP会等待一个 Keepalive消息或者 Notification消息 . 如果收到一个 Keepalive消息 ,转移到Establish状态 . 如果收到一个 Notification消息 ,转入 Idle状态 ,并断开 TCP连接 . 如果 Hold计时器超时 ,检测到一个差错或出现 stop事件 ,BGP将给邻居发送一个 Notification并断开连接 ,转入 Idle状态 .

Establish状态

此状态下, BGP对等体间的连接已经完全建立 , 可以交换 Update Keepalive和 Notification消息 , 如果收到 Notification自动转入 Idle, 并中断连接.

BGP建立邻居日志

路径属性(Path Attribute)

PATH attribute 字段

由前一节可知, 我们需要在自治系统之间实现灵活的路由控制策略, 通过Wireshark捕获到携带PATH Attribute的消息结构如下所示:

因此我们需要对域间的路径定义一系列路径属性(PATH Attribute), 在UPDATE消息中定义的Path Attribute属性如下所示:

Option bit: 该位被用于定义可选属性的类型: 0. well-known属性 1. 可选属性.

Transitive bit: 该位被用于定义传输属性:0. 不需要传递 1. 需要传递(RFC4271:well-known属性, transit bit必须设置为1)

Partial bit: 该位用于定义可选传递属性是否包含完整的信息, 其它属性(Well-known和Optional-non-transitive属性)该位必须为0.0. 完整的(Complete) 1. 部分的(Partial)

Extended Length bit: 该位用于定义路径属性的长度, 如下所示:0. Regular Length– 8bit,1. Extended Length–16bit

Attribute Type Code: 该位用于定义属性类型, 如下表所示:

路径属性类型

路径属性根据需求被分为四类:Well-known mandatory, 这是一类公认的必须遵守的属性, 因此所有的BGP路由器都必须识别.在相应的更新消息(Update)中必须包含该属性值.

Well-known discretionary, 这是一类公认的斟酌处理的属性, 所有的BGP路由器都能识别它, 但是不是必须需要的, 因此Update消息可以有选择的包含该属性

Optional transitive, 这是一类可选的并可传递的属性, 它不一定被所有的BGP路由器识别, 但所有的BGP路由器都可以传递这个属性.

Optional notransitive, 这是一类可选的非传递属性. 即并不是所有的BGP路由器都能识别. 如果这个属性不被BGP路由器所接受, 那么它可以不再进行传递,而直接丢弃.

BGP的实现必须识别所有的Well-known属性, 并且其中有一些属性是强制(mandatory)的必须在每个包含NLRI的UPDATE消息中携带. 而其它的属于可斟酌处理(discretionary)的well-known属性则可以在UPDATE消息中携带也可以不携带. 一旦对等体更新了任何well-known属性, 它必须把这些新的属性传递给所有的邻居.

除了Well-known属性以外, 每个路径还可以有一个或多个可选(Optional)属性, 这些属性并不要求BGP都能识别和处理, 仅需要在这些属性上标记是否可传递(在Transitive bit位进行标记)即可. BGP路由器必须接受在一条路径上携带有不能识别的可选传递(Optional transitive) 属性, 如果一个携带有不识别的可选传递(Unrecognized transitive optional)属性的路径被接受并传递给其它对等体, 那么这个属性必须随着路径传递给其它BGP对等体并且Partial bit被设置为1-Partial. 如果一条可识别的可选传递属性被接受并沿着路径传递给其它BGP对等体并在前面的一些AS中携带Partial Bit.那么在当前的AS中不能将其设置为0. 对于不识别的可选非传递(Unrecognized no-transitive optional)属性则必须使用静默忽略的方式进行处理, 而且不能传递给其它BGP对等体.

常见的路径属性分类如下:

Origin

ORIGIN属性指出了BGP路由的来源, 用于判断路由的可信度, 当BGP有多条路由来源时, 路由器会将ORIGIN属性作为路由决策进行参考, 具有较低ORIGIN值的条目被优先选择, ORIGIN属性有如下三种:IGP(i,0) 来自于IGP的前缀,EGP( e,1 ) 路由来自于EGP[RFC904],Incomplete( ?, 3)路由被重分布进入BGP

通常通过 network 命令注入BGP的路由前缀ORIGIN值为0, 表明这些路由来自于IGP. 而通常通过重分布redistribute进入的路由前缀的ORIGIN属性为3, 即Incomplete. 在选路过程中最可信的路由条目将优先选取, 因此ORIGIN属性为IGP时可信度较高, 而从BGP重分布进入的则可信度较低. 如下图所示:

AS-Path

AS-Path也是一个公认的必须遵守的属性, 它通过一种Record-Route的方式记录了一个前缀在传递过程中所经过的自治系统. AS-Path实际上是一个TLV型属性, 它由<Path segment type, Path Segment Length,Path Segement Value>三个字段组成. 如下所示:

当Path Segment Type = 1时表示该属性仅记录了路由通过的AS的集合. 而当该值设置为2时, 则表明是顺序记录的路由穿越AS的顺序. BGP路由器修改AS-Path属性遵循以下规则:

  1. 当BGP始发一条路由时将会发送一个携带空AS-Path属性的UPDATE消息给iBGP邻居, 相反对EBGP邻居则会添加一个AS_SEQUENCE字段并将自己的AS号放入其中.
  2. 当BGP发送给一个iBGP邻居时不得修改路由的AS-Path属性
  3. 当BGP发送给一个EBGP邻居时, 则发送UPDATE消息的路由器需要修改AS_path属性 3a. 如果为AS_SEQUENCE属性, 则在Path Segment Value的最左端添加自己的AS号. 如果超过255个AS, 则需要添加一个新的AS_SEQUENCE段. 并且将自己的AS号添加到新的段中.3b. 如果为AS_SET类型, 则本地系统添加一个新的为AS_SEQUENCE类型的AS_Path属性, 并在该属性中包含自己的AS号 3c. 如果AS_Path为空, 那么本地系统将创建一个AS_SEQUENCE类型的属性并将自己的AS号添加进入该字段.

通过wireshark捕获的报文如下:

在RFC3065 中还定义了Type=3 的AS_CONFED_SET 和 Type=4 的AS_CONFED _SEQUENCE 两种新的AS_PATH 属性类型. 而对于4Byte-ASN 支持则采用了新的AS4_Path 属性(Attribute Code: 17) ,这些内容将在稍后的章节中叙述.

AS_Path属性处理的具体流程如下图所示:

当一个本地路由条目加入到BGP表中时, AS-Path属性为空. 并且传递给100ER2 和 100ER3的AS-Path属性也为空. 在通过AS边界时, 发送端在AS-Path中添加自己的AS号, 如上图中的 100ER2 向 200ER1 发送时添加了AS100. 因此在 400ER1 上我们可以看到可以通过两条路径到达10.0.0.0/16. 其中一条经过AS300,AS200到达, 另外一条经过AS500到达. BGP路由器应当优选经过AS最少(即AS-Path长度最短)的路径. 因此上图拓扑中将优先选择400ER3–> 500ER2–>500ER1–>100ER3–>100ER1的路径. 当然如果我们期望优选AS400–>AS300–>AS200–>AS100的路径, 则可以通过配置加长AS400–>AS500–>AS100这条路径上AS-Path的长度(Path Prepending).

除此之外, 当收到一条包含自己AS的路由条目时, 如果接受这条路由的更新将发生路由环路. 因此BGP路由器收到含有自己的AS号更新时将会将其静默的忽略(Silently ignore). 如下所示:

Next-Hop

该属性也是一个公认的必须遵守的属性, 用于表示目的地路由前缀所使用的下一跳路由器的地址.通过wireshark捕获的报文如下:

Next-Hop属性计算方法如下:

  1. 当发送给iBGP邻居时, 如果路由不是本地产生的, 则BGP不能修改NEXT_HOP属性. 除非是BGP路由器被显式配置了需要通告(例如配置 neighbor x.x.x.x next-hop-self)则将自己的地址放入NEXT_HOP属性中. 当通告一条自己产生的路由给iBGP邻居时, 路由器则必须将邻居可达的接口地址通告在Next_HOP属性中. 如下图所示:
  1. 如果是发送给eBGP邻居(和eBGP邻居仅有一跳则默认情况下使用和邻居建立连接的接口地址作为下一跳地址. 如下所示:
  1. 如果多个eBGP路由器连接在同一个共享网段中, 则不改变Next-Hop, 即”third Party” Nexthop:
  1. 对于eBGP多跳互联的情况, 由于两个eBGP 可以通过eBGP会话所使用的地址进行TCP通信, 因此这些地址时可达的, 因此Next-hop通常是建立eBGP连接时所使用的IP地址. 并使用递归路由的方式到达对端.

路由器本地产生的路由条目在该路由器自己的RIB中next-hop显示为0.0.0.0 很多路由器平台中, 管理员都可以手动配置eBGP的next-hop属性, 例如使用route-map或者next-hop-self等方式修改. 这些内容将在后续章节中进行介绍.

Local_Pref

Local_Pref是一个公认的斟酌处理的属性, 其值范围为0~255. UPDATE消息可以携带这个属性并将其发给iBGP邻居并用于AS内部的BGP路由器参考, 具有较高的Local_Pref值的路由条目将被优先考虑, 如下所示:

作为AS 400的边界路由器AS400ER1和AS400ER2同时向AS内部的iBGP邻居通告关于10.0.0.0/16的路由条目, 网络管理员希望通过AS400ER1访问这个网段, 因此在通告时将Local_Pref属性设置为更高的值. 当内部路由器收到两条关于10.0.0.0/16的更新后将会优先选择Local_Pref高的一条路径进行传输. 在Cisco IOS中Local_Pref属性的默认值为100.

BGP 路由器不能将Local_Pref 属性发送给eBGP 邻居(基于联盟的eBGP 邻居除外)如果BGP 收到一个eBGP 邻居(基于联盟的eBGP 邻居除外) 发送来的携带Local_Pref 属性的UPDATE消息, 这个属性应当被忽略掉.

Multi_Exit_Disc(MED)

Multi_Exit_Disc是一个可选的非传递属性并用于存在多条AS间链路时告知对端优选的链路. MED值较小的路径将被优先选择. 通过wireshark捕获的报文如下:

具体原理如下所示:

AS400和AS300之间存在多条链路, AS400的管理员希望AS300优先选择AS400ER2访问本地网络, 因此在通告给AS300的路由器时将AS400ER2路径上的MED属性设置为较小值. 在Cisco IOS上MED属性设置遵循以下规则:

  1. 如果通过network/redistribute命令注入到BGP的路由来自于IGP, 则MED从IGP中导出.
  2. 如果通过network/redistribute命令注入到BGP的路由为直连路由, 则MED设置为0.
  3. 如果通过aggregate-address注入的汇聚路由, 则MED不被设置.

当收到MED属性后, BGP路由器可以将其传递给同一个AS中的内部路由器(iBGP), 但不能将其传递给其它邻接的AS. 也就是说MED的影响范围仅为相邻的AS. 如果需要控制更远的AS的选路策略, 可以通过修改AS_PATH等属性完成.

Atomic_Aggregate

Atomic_Aggregate是一个公认的可斟酌处理的属性, 当BGP路由器进行路由聚合处理时, 由于产生一条新的聚合路由, 因此精细路由所携带的AS_Path属性将会在聚合时被丢失. 路由器可以发送携带Atomic-Aggregate的属性进行通告, 通过wireshark捕获的报文如下所示:

Atomic-Aggregate工作原理如下所示

在聚合成10.0.0.0/16时, 精细路由所携带的AS-Path( AS100/200/300 )均被丢失. 如果这样的聚合路由再次进入上述AS则将产生路由环路. 因此在进行路由聚合时BGP可以将精细路由所携带的AS号全部放入AS_SET中进行传递来避免这个问题. 如下所示:

当然网络管理员也可以自行决定是否通告AS_SET属性. 如果AS_SET没有被通告, 则在进行汇聚路由通告时应当包含ATOMIC_AGGREGATE属性. 如下所示:

当接收到携带ATOMIC_AGGREGATE属性的路由条目后, 如果路由器要将该条目传递给其它邻居则不能移除该属性. Atomic_Aggregate属性可以告知网络管理员当出现环路时应当对AS_Path进行相应的检查.

Aggregator

Aggregator是一个可选的可传递属性, 可以包含在产生聚合路由的UPDATE消息中, 通过携带发送UPDATE消息的路由器BGP-ID来告知进行路由聚合通告的路由器. 通过wireshark捕获的报文如下:

Aggregator工作原理如下所示:

Administrative Weight

除此之外, Cisco还定义了一种私有的属性—管理权重(Administrative-Weight). 它用于对离开AS的报文进行策略控制, 并且它是一个不可传递的属性, 缺省情况下从对等体学到的所有路由的权重值为0, 由所有本地路由器产生的路由的权重值为32768. 在选路时将优先选取权重值最高的路由前缀作为最佳路径.

BGP Community

它是一个可选的可传递的属性, 最先由Cisco定义, 并在RFC 1997和RFC1998中实现了标准化定义.COMMUNITY属性可以用于对路由条目进行分组管理. 通常我们在制定策略的时候需要对一系列路由前缀进行控制, 例如对从某个AS来的路由进行特殊处理等. 基于这样的原因, 我们可以在路径属性中通过携带Community属性来进行相关的路由策略管理. 例如ISP可以对某个特定的用户分配一个Community属性, 此后该ISP就可以基于COMMUNITY值来设置Local_Pref或者MED等属性来完成路由策略的控制.

Community属性是由一个4bytes的值构成, 在RFC1997中规定, 前2个byte是用于表示AS, 后两个Byte用于是出于管理目的定义的标识符. 格式为 AA:NN. 例如来自AS625的某条路由的COMMUNITY标识符为70, 则该路径的Community 属性为625:70. 十六进制表示为625=0x0271 70=0x0046, 因此属性值为0x02710046. 即十进制40960070. 在Cisco IOS中可以利用 ip bgp community new-format 命令将其显示为RFC1997的标准格式. 通过wireshark捕获的报文如下:

如果出现一组携带Community属性的路由条目需要聚合, 如果最后产生的聚合条目没有携带ATOMIC_AGGREGATE属性, 那么聚合路由将包含一个COMMUNITY属性字段, 其中包含了所有精细子路由的Community属性值.

在Community属性中0x00000000~0x0000FFFF以及0xFFFF0000~0xFFFFFFFF为保留字段. 在保留字段中定义了四种well-known的属性

NO_EXPORT(0xFFFFFF01): 如果路由携带该属性则不能通告给EBGP邻居. 如果配置的BGP联盟属性, 也不能将路由宣告到联盟外(联盟属性将在后续的章节中进行详细叙述).

NO_ADVERTISE(0xFFFFF02): 如果接收到的路由携带该属性, 那么路由器不能宣告该路由给任何BGP对等体(包括eBGP或者iBGP邻居).

LOCAL_AS(0xFFFFFF03): 在RFC1997中这个属性被称为NO_EXPORT_SUBCONFED属性, 即携带该属性的路由将不能宣告给任何EBGP对等体, 包括同一联盟内其它自治 系统的对等体.

NOPEER(0xFFFFFF04): 在RFC3765中定义, 该RFC的动机是通过这样的方式来降低internet的路由表条目. 携带有该属性的路由通告给外部AS后, 这些接收到含有 该属性条目的AS将不会向所有的双向的对等体会话(bilateral peer session). 详细解释如下图所示:

当RouterA为发送的精细路由携带NOPEER属性后, RouterC和RouterD均收到这样的路由前缀, 因此RouterC和RouterD可以被认为是一种Bilateral Peer Session的关系, 所以在它们之间并不传递10.0.1.0/24这个路由前缀.

RFC4271中仅定义了前述的一些路径属性. 在运营商进行大规模部署的过程中, 还提出其他一些RFC来完善BGP协议, RFC4456中定义的Route Reflection, RFC3065中定义的Confederation属性等. 这些我们将在随后的章节中详细介绍.

iBGP部署及相关特性

iBGP 导致路由黑洞

由于BGP邻居建立采用TCP连接. 因此在BGP部署时可能产生如下的方式:

如图所示, 由于在AS200中IGP已经部署, Router A和Router C之间可以建立TCP连接并形成iBGP对等体关系. 此后AS100向AS200通告10.0.3.0/24网段. RouterA和RouterC都可以通过BGP学到这条路由. 而Router B仅和RouterA/C建立IGP关系. 因此RouterB上并没有相关的条目. 当RouterC把目的地址为10.0.3.0/23的报文发送给RouterB时, RouterB将会丢弃该报文形成一个路由黑洞.

iBGP 和IGP 同步

对于这样的路由黑洞, 大多数人会想到一种将BGP路由重分布进入IGP的处理方式. 在Internet设计之初由于BGP路由条目相对较少, 这样的做法是可行的. 因此为了避免产生这样的路由黑洞, 我们在基于可以重分布到IGP的这个假设基础上对iBGP和IGP路由表定义了一个同步规则, 如上图所示, 当RouterC把10.0.3.0/24通告给AS400的eBGP邻居前, 必须确保10.0.3.0/24网段通过IGP学习到. 通过这样的方式来避免了向其它网络通告黑洞路由. 即BGP同步规则可以被描述为:

当一个路由器需要将从iBGP学到的路由条目路由加入到路由表中并通告给其它邻居前, 必须确保相应的路由条目通过IGP学到.

事实上在新的IOS中这项功能已经被默认关闭, 主要原因是现阶段internet路由表条目已经接近35万条, 大量的路由被注入到IGP中将产生大量的路由更新消息以及大量的内存来存放这些路由条目. 对于大多数路由平台内存相对较小并且CPU相对较慢. 这样将会对全网运行IGP的路由器产生非常高的负荷甚至导致全网因为路由器过荷而瘫痪. 历史上曾经出现过这样的失误并导致某个运营商的网络宕机19个小时.

切忌不能将BGP路由条目重分布进入IGP中, 大量的BGP条目进入IGP后会导致路由器过载而瘫痪, 并且随着IGP的洪泛更新, 全网的路由器都将受此影响而过载. 除此之外, 当 BGP路由重新分布进入IGP后, AS_PATH等路径属性将会被丢弃. 这样就使得路由器丧失了防止环路的能力.

iBGP Fullmesh

面对如上拓扑, 我们无法通过重分布BGP路由进入IGP的做法来保证信息传递. 因此我们产生另一种想法, 即分别在RouterA和RouterB, RouterB和RouterC之间建立iBGP连接. 如下所示:

为了保证BGP路由更新到达RouterC, BGP协议则必须支持从RouterB发送到RouterC, 即要求BGP路由器从一个iBGP邻居收到路由更新后可以传递给另一个iBGP邻居. 但事实上来看, 这样的做法是完全错误的.在iBGP更新过程中AS_PATH并没有修改. 因此相应的环路保护机制将会失效. 如果在这个情况下RouterA和RouterC建立, RouterC将会把RouterB传递给它的关于10.0.3.0/24的更新再一次传递给RouterA. 由于AS_PATH检查时通过的, RouterA也会接受这样的更新, 于是就产生了环路.基于环路防止的考虑, BGP协议做出了相关的水平分割限制, 如下:

当收到一个iBGP更新后, 路由器不能将其传递给其它iBGP对等体. 为了让所有的BGP路由器获得更新, 则在AS内部所有的BGP路由器必须以全互联的方式进行部署.

BGP Route Reflector

事实上, 对于一个大型的运营商其内部可能有数以百计的BGP路由器并需要全互联形成iBGP对等体.这样的部署方式对于运营商来说是不切实际并不被接受的. 因此Tony Bates和Ravi Chandra在1996年6月提出了RFC1966: Route Reflector 作为一种避免iBGP Fullmesh的备选方案. 并在随后的发展过程中更新为RFC4456.

为了保证整个方案简单同时有很好的兼容性. 并且易于进行平滑的升级. 因此BGP路由反射器仅是在相关协议规范上做出了一些特殊的处理允许上图中的RouterB将从RouterA接收到的iBGP消息再次通告(Readvertisement, 或者也称为reflect)给RouterC, 同时增加一些属性来避免环路的问题. 如下所示:

当RouterB被配置成为路由反射器(Route Reflector, RR)后, 它将iBGP邻居分为两类, 一类为Client Peer,另一类为Non-Client Peer. 并且路由通告遵循以下规则:

  • 当收到一个来自non-client Peer的iBGP更新后, 该路由将会反射到所有的Client-Peer.
  • 当收到一个来自Client Peer的iBGP更新后, 该路由将会反射到所有的Client和Non-Client Peer.
  • 当收到一个来自eBGP更新后, 该路由将会反射到所有的Client和Non-Client Peer.

例如上图中的RouterB作为路由反射器, RouterA和RouterC则是Client Peer. 因此当RouterA发送路由更新给RouterB时, 遵循如上原则, RouterB将该路由传递给RouterC.

我们再来看一个更复杂的例子, 如上图所示, RR还有两个Non-Client Peer. 当RouterA发送路由更新给RR时, RR需要将其转发给RouterC/D/E这三个ClientPeer. 但并不将其转发给RouterB. 这是因为Non-ClientPeer即为标准的iBGP对等体连接. 它遵循iBGP的水平分割原则, 因此上图中的RR和RouterA/RouterB需要构成全互联的对等体关系. 通常我们可以将一个RR和它所有的Client-Peer合在一起成为一个Cluster, 并把这个成为集群的多台路由器看做是一个路由器和其它Non-Client Peer互联.

当然我们需要考虑一个问题, 即RR破坏了原有的iBGP水平分割规则, 因此可能导致路由环路, 为了避免这个问题, 实际上我们可以考虑对每个Cluster进行编号, 即可以通过RR的BGP-ID来定义Cluster-ID. 然后我们可以采用类似于AS_PATH的方式来防止环路产生. 因此RFC4456中定义了CLUSTER_LIST属性, 它是一个Type = 10的可选不传递的路径属性, 具体定义如下:

当一个RR反射一条路由时, 它必须把自己本地的CLUSTER_ID加入到CLUSTER_LIST中. 如果接收到一个路由CLUSTER_LIST中包含RR自己的CLUSTER_ID, 则该路由将被视为环路而丢弃.

RFC4456还定义了一个ORIGINATOR_ID, 它被用于在debug时提供更多的信息同时还可以避免环路. 该属性由路由反射器RR创建. 它是一个Type = 9的可选非传递属性. 该字段将包含本地AS中始发这条路由的BGP路由器的BGP-ID. 当一个路由器接收到一条路由的ORIGINATOR_ID和自己的BGP-ID相同时, 它将忽略该路由. 通过wireshark捕获的报文如下所示:

Cluster_list和ORIGINATOR_ID的工作原理如下图所示:

Router A发送给RouterB时并不携带CLUSTER_LIST和ORIGINATOR_ID属性, 当RouterB作为RR发射路由时,这两个路径属性被加上. 在某些情况下, 我们还可以允许一个RR作为另一个RR的Client-Peer, 进行级联部署, 级联时关于这两个路径属性的处理方式如下图所示:

RR 本地产生的路由条目发送给Client Peer 时, 不会加上CLUSTER_LIST 和ORIGINATOR_ID 这两个属性值. 例如RR1 本地产生的路由条目发送给RR2 时并不携带这两个路径属性

但是我们意识到一个问题, 这样的RR部署容易产生单点故障. 因此我们可以在一个Cluster中放置多个RR. 如下图所示:

当放置两个RR后, RouterA收到来自AS100的eBGP路由更新后, 它将路由更新发送给RR1, RR1则可以将其转发给RR2/RouterB/RouterC, 并添加RR1的Cluster_ID. RR2收到RR1的UPDATE后将检查CLUSTER_LIST属性,当发现它没有包含自己的CLUSTER_ID时, 将会接受这条路由更新, 并且将添加自己的CLUSTER_ID后, 将这些路由转发给RouterA/B/C. 当RouterA收到来自RR2的更新后, 会发现ORIGINATOR_ID是RouterA自己, 因此它将忽略这个UPDATE消息. 我们注意到RR2还会收到一份来自RouterA的UDPATE. 这一份UPDATE并没有携带任何关于CLUSTER_LIST的属性, 因此RR2也将这个更新反射到RR1/RouterB/RouterC. 因此最终状态下,RR1/RR2/RouterB/RouterC都有2份路由. 如果一个Cluster中还存在第三个RR, 那么所有的路由器将会保存3份路由. 这样将大量占用路由器内存. 因此我们并不建议在一个Cluster中部署多于2个的RR.

为了降低路由器的内存消耗, 如上图所示, 我们可以通过在BGP进程模式下配置 bgp cluster-id 的方式, 将RR1/RR2的CLUSTER-ID改为一致. 当RR1把来自RouterA的更新发射给RR2后, RR2将会检测到相同的CLUSTER-ID, 因此会忽略掉这个更新. 但RouterB/RouterC仍然会收到分别来自RR1/RR2的拷贝. 因此更改为相同的CLUSTER-ID仅会减小RR的内存消耗. 在很多关于BGP的资料中都建议这样的RR冗余部署方式, 但是我们来看下面一个问题.

当RR1/RR2配置为相同的CLUSTER-ID后, 如果RR1–RouterB和RR2–RouterA的链路同时中断. RR2并不会接受来自于RR1的路由更新, 因此RouterB将会无法收到任何路由更新. 相反, 如果采用不同的CLUSTER-ID则可以避免这个问题.

建议: 推荐在进行冗余RR部署的时候继续采用系统自定义的CLUSTER-ID分配方式, 对于很多运营商而言, 通常是将网络扩容后淘汰下的路由器来继续用做RR使用. 例如上图中的RR1/RR2在网络升级前有可能是7200, 而RouterA/RouterB为GSR. 在网络升级后, 运营商用CRS-1替代了RouterA/RouterB, 原有的两台GSR通常就被用于替换7200作为RR. 这些路由器在原有部署的时候, 已经可以承载两份路由拷贝. 因此用做RR时, 并不需要通过改CLUSTER-ID的方式来降低内存消耗.另一方面, Cisco在ASR1k等平台采用X86的架构, 并且通过IOS-XR / IOS-XE支持了大内存, 因此如果将这些平台用做RR, 也不需要刻意去降低内存使用.

除此之外我们可以构成如下的拓扑结构, 多个Cluster进行级联. 并且在Cluster中也可以部署全互联拓扑, 关于运营商网络中应该如何部署RR, 主要参照物理拓扑进行设计, 我们将在后续的章节中详细叙述.

BGP Confederation

路由反射器的解决方案是采用一种特殊的iBGP关系, 并在允许iBGP路由更新反射的基础上通过Cluster_list和originator_id两个路径属性来防止环路. 在BGP发展过程中, P. Traina在RFC1965(最近一次将其更新为RFC5065)中提出一种做法, 即将一个AS分成很多成员AS(Member AS). 而原来的AS则被看做有多个Member AS组成的大联盟(Confederation). 原有的AS号则被称为联盟ID(Confederation-ID). 然后原有的iBGP连接可以使用一种特殊的eBGP关系替代. 从而可以避免iBGP水平分割的限制. 而对于环路的处理则继续沿用了原有的AS_Path机制. 具体流程如下:

如上图所示的AS200中, 以前的做法是将Router A/B/C配置路由反射器. 而基于联盟的处理方式如下:

可以非常明显的看到, 它将原来的AS200划分成了AS65510~AS65512三个成员AS. 因此RouterA/B/C之间原有的iBGP对等体关系变成了eBGP对等体关系. 所以将不受iBGP水平分割的限制. 但是细分后我们还需要考虑另外几个问题. AS_PATH在联盟环境下如何处理? 如何隐藏联盟内部的成员AS? Local_Pref/MED这 些路径属性是如何处理的?

首先来看AS_PATH的处理. IANA要求联盟中的成员AS(Member-AS)号采用64512~65534的私有AS号码段,在联盟环境中引入了两个新的AS_PATH类型:AS_CONFED_SEQUENCE(Type-3): 用于顺序记录UPDATE消息在本地联盟中所穿越成员AS号 AS_CONFED_SET(Type-4): 它记录了UPDATE消息在联盟中穿越的成员AS的集合

BGP联盟中的成员在和非联盟中的成员建立BGP连接时, 它必须在OPEN消息和AS_PATH属性中使用Confederation_ID, 例如上图中的RouterD和RouterE建立eBGP连接时, 必须使用AS200和RouterE建立eBGP对等体关系. 而当BGP 联盟中的成员和Member-AS 中的其它路由器建立对等体关系时, 则必须使用Member-AS号. 例如上图中RouterD和RouterA建立BGP对等体关系时必须使用AS65511作为AS号. 而RouterA和Router-C之间则使用AS65511 和 AS65510建立eBGP对等体关系.

在进行环路控制时, 当一个BGP路由器收到的AS_PATH中含有自己Confederation-ID, 将被视为接收到含有自己AS号的更新, 因此这个UPDATE消息将被视作环路而被忽略. 而如果一个BGP路由器收到的AS_CONFED_SEQUENCE或AS_CONFED_SET中包含自己的Member-AS号, 也将被视为接收到含有自己AS号的更新, 并视作环路忽略这个更新. AS_PATH属性修改遵循以下规则如下图所示:

  1. 当BGP路由器通告给相同Member-AS中的另一个对等体时, 不能修改AS_PATH属性.(例如RouterB通告给RouterC时, 不修改AS_PATH属性).

  2. 当BGP路由器通告给联盟中的邻居AS时(例如上图中的RouterC通告给RouterD时), AS_PATH属性修改遵循以下规则:

  • 2a) 如果AS_PATH中的第一段为AS_CONFED_SEQUENCE, 则路由器将自己的Member-AS号添加到AS_CONFED_SEQUENCE的最左端, 如果这个AS_CONFED_SEQUENCE长度为255个AS, 为了避免超出长度, 路由器应当创建一个新的AS_CONFED_SEQUENCE路径属性,并将自己的Member-AS号添加到其中.

  • 2b) 如果AS_PATH的第一段不是AS_CONFED_SEQUENCE, 那么BGP路由器将创建一个包含自己Member-AS号的AS_CONFED_SEQUENCE属性放入到AS_PATH中.

  • 2c) 如果AS_PATH为空,那么BGP路由器将创建一个包含自己Member-AS号的AS_CONFED_SEQUENCE属性放入到AS_PATH中.

  1. 当BGP路由器通告给联盟外部的邻居AS时(例如上图中的RouterE通告给RouterF), AS_PATH属性可以按照如下规则进行修改:
  • 3a) 如果AS_PATH 中含有AS_CONFED_SEQUENCE 或AS_CONFED_SET, 这些字段必须从AS_PATH中去除.然后AS_PATH属性按照如下的b,c,d步骤进行处理.

  • 3b) 如果AS_PATH 中含有AS_SEQUENCE, 那么BGP 路由器将自己的联盟ID 加入到AS_SEQUENCE的最左端, 如果这个AS_ SEQUENCE长度为255个AS, 为了避免超出长度, 路由器应当创建一个新的AS_ SEQUENCE路径属性, 并将自己的联盟ID添加到其中.

  • 3c) 如果AS_PATH中的第一个属性为AS_SET, 那么BGP路由器将创建一个新的AS_SEQUENCE属性, 并将联盟ID添加到其中.

  • 3d) 如果AS_PATH为空, 那么BGP路由器将创建一个包含自己联盟ID的AS_SEQUENCE属性放入到AS_PATH中.

  1. 当BGP路由器始发一条路由, AS_PATH根据以下规则处理:
  • 4a) 如果始发的这条前缀的路由器在联盟边界, 并且要通告给联盟外部的邻居, 那么BGP路由器将创建一个新的AS_SEQUENCE属性, 并将联盟ID添加到其中.

  • 4b) 如果始发的这条前缀的路由器需要将其通告给联盟内部的其它成员AS, 那么BGP路由器将创建一个包含自己Member-AS号的AS_CONFED_SEQUENCE属性放入到AS_PATH中.

  • 4c) 如果始发的这条前缀的路由器需要将其通告给相同Member-AS中的成员, 那么BGP路由器将保持AS_PATH属性为空.

  1. 当在联盟中使用 address-aggregate 聚合路由时, 如果聚合命令携带 as-set 关键字, 那么聚合路由将产生一个AS_CONFED_SET属性, 并原有的精细路由中所携带的AS_CONFED_SEQUENCE属性中的成员AS号放入到AS_CONFED_SET中.

在使用联盟部署的网络中, NEXT_HOP 和MED 属性可以不加修改的进行传递, 并且Local_Pref 属性也可以进行传递. 联盟属性还影响了路由决策, 这些内容我们将在下面一节进行叙述.

BGP路由决策

BGP路由表构成

BGP具体构成如下所示:

在RFC4271 Section 3.2中定义的BGP的路由信息库由三个部分组成:

  1. Adj-RIBs-In: 它用于存储从对等体接收到的UPDATE消息所携带的路由信息. 或者根据UPDATE消息中的WITHDAWN Route 在Adj-RIBs-In中删除相关条目. 并在此后交 由路径决策进程进行处理.
  2. Loc-RIB: 它用于存储路径抉择进程的处理结果. 同时某些本地路径也可以注入到这个RIB中. 并且这些结果将用于生成本地的路由表
  3. Adj-RIB-Out: Loc-RIB的结果在进行一些输出策略处理后将会把相关允许输出的路由放入到Adj-RIB-Out中. 然后BGP路由器根据Adj-RIB-Out向其它对等体发送更新消息.

BGP 路径决策过程

为了满足互联网上灵活的流量控制需求, BGP需要经过一个复杂的算法来决定最佳路由并更新BGPRIB和IP RIB. 即路径决策过程从Adj-RIB-In中查找并选出被本地使用的路由, 并选择出需要通告的路由, 同时对路由聚合进行处理.

当存在多条到达特定目的地的有效BGP路径时, IOS将会根据收到它们的相反顺序列出这些路径, 即最后收到的路径列在最前面, 而最老的路径列在最后. 然后在进行路径比较时采用冒泡排序的方法逐条进行对比, 即将列表中的第一条路径和第二条路径进行对比, 选取最优的一条和第三条进行对比, 以此类推.

当然如果一条路径不满足下列任一条件, 那么它将被排除在路径选择列表之外.

  1. 路径的下一跳不可达
  2. 路径未同步, 但同步功能被启用(该功能将在后续的章节中详细叙述)
  3. 路径被inbound BGP Policy 拒绝
  4. BGP soft-reconfiguration inbound 配置时
  5. BGP Route flap dampening[RFC2439]

在Cisco IOS中执行的 BGP选路规则如下 :

  1. Weight: Cisco私有属性 Weight被最先考虑 . Weight值最高的路径优先 . 这个参数值是本地有效的 , 并且不进行传递 . 本地始发的路由条目 Weight值被默认设置为 32768, 而其它所有接收到的路径 Weight默认值被设置为 0 .

  2. Local_Pref: 在 Cisco IOS中 Local_Pref的默认值为 100, 可以通过 bgp default local preference 命令修改默认值 . 而对于特定的路由修改 Local_pref属性可以通过在 route map中匹配相应的路由前缀 , 然后配置 set local preference 实现 .

  3. 基于始发地的路由评估 , 路由器本地始发的路径将被优先考虑 . 相关添加顺序如下 :

  • 3a. 选择基于每个邻居配置的默认路由 ( neighbor x.x.x.x default originate)
  • 3b. 选择基于 SAFI配置的默认路由 ( default infomation originate )
  • 3c. 选择基于 network 命令通告的路由
  • 3d. 选择基于 redistribute 命令重分布进入的路由
  • 3e. 选择基于 aggregate address 配置的汇总路由
  1. AS Path: 选择 AS_Path列表最短的路径作为最优路径 . 可以通过 “bgp bestpath as path ignore”(该命令为隐藏命令 )来跳过这一步 . 对于 As path长度评估遵循如下原则 :
  • 4a. 一个 AS SET长度被记为 1, 即不管 AS set中有多少个 AS, 其长度永远为 1.
  • 4b. AS_CONFED_SEQUENCE和 AS_CONFED_SET不包含在 AS_Path长度中 .
  1. Origin: 这一步选择最小的 ORIGIN值的路径作为最优路径 . IGP < EGP < INCOMPLETE

  2. MED: 选择 MED值最小的路由作为最优路径 .

  • 6a. 缺省条件下 , 仅在两条路径的第一个 AS(邻接的 AS)相同的情况下进行 MED比较 , 同时任何联盟的 sub AS号都将被忽略 . 换句话说 , MED仅在 AS_SEQUENCE中第一个 AS相同的情况下才能进行比较 , 任何 AS_CONFED_SEQUENCE属性都将被忽略
  • 6b. 如果开启 bgp always compare med 功能 , MED将在所有的 Path上进行比较 . 如果启用这个选项 , 为了防止路由环路 , 应当在整个 AS中启用这个功能 .
  • 6c. 如果开启 bgp bestpath med confed 功能 , MED对仅包含 AS_CONFED_SEQUENCE属性的路由进行比较 . 即仅对联盟内部始发的路径进行比较 .如果一条路径包含了任何外部的自治系统 , 那么这条路径也将不会被比较 .
  • 6d. 如果从邻居收到一个 MED为 4,294,967,295的 MED值 , 它将在被加入到 BGP表之前更改为 4,294,967,294.
  • 6e. 如果收到一个没有包含 MED属性的路径 , 那么路由器将其 MED值设置为 0. 如果配置了 bgp bestpath med missing as worst, 那么 MED值将被设置为 4,294,967,294f. bgp deterministic med 命令启用后 , 路由器会把所有的路径基于 AS_PATH编组 , 在每一个 AS_PATH组内 , 根据 MED的大小对路径进行排序 . 具体内容参看后续小节.
  1. eBGP路径优于 iBGP路径 . 包含 AS_CONFED_* 的路径 (无论是否还包含有 AS_SEQUENCE或AS_SET属性 )对于联盟来说是本地的 , 所以 被看做是内部路径 . 因此 在路径选择过程中 , 联盟外部 (Confederation External)和联盟内部 (Confederation Internal)路径时没有差别的 , 都被看做是Internal的路由 (即视为 iBGP路径对待 ). 如果仅剩下 EBGP学到的路径条目 , 转到第 9步

  2. 选择到 BGP NextHop地址的 IGP metric最小的路径 , 即通过 IGP选择到 BGP nexthop的最短路径 .

  3. 如果配置了 bgp multipath, 即配置了 maximum paths N , 则最多可以将 N条最近接收到的路径加入到 IP路由选择表中 . 这可以使得 eBGP在多条路径上进行负载分担 . 目前 N所代表的最大数目是 32. 如果没有配置则继续下一步 .

  4. 当两条路径都是外部路径时 , 优先选择最早被接收的路由前缀 .

  • 10a. 这样的处理方法可以将路由摆动的影响降到最小 , 因此新接收的路径并不会取代老的路径 . 即便是在后续的选择步骤中新收到的路径更优 , 路由器依旧选择最老的路径
  • 10b. 如果配置了 bgp bestpath compare_routerid , 那么这一步将会被跳过 .
  • 10c. 如果所有路由的 Router ID是相同的 , 即它们都来自同一个路由器 , 在这种情况下 , 这一步选择将会被跳过 .
  • 10d. 如果当前没有最佳路径 (例如提供这条路径 的对等体路由器失效 ), 这一步将会被跳过
  1. BGP优先选择来自于具有最低的 Router ID的路由 . 如果路径包含路由反射器特征 , 则ORIGINATOR_ID最小的路径将会被优先选择 .

  2. 如果多条路径的 ORIGINATOR_ID或者 Router_ID相同 , 那么将优先选择 Cluster_LIST长度最短的路由条目 . 这条选路规则仅在 RR部署的情况下使用 .

  3. 优先选择 Peer_ID最小的邻居 , 即在 neighbor remote as 中配置的 IP地址最小的邻居 .

在路径选择过程中, 我们还需要注意对 bgp deterministic med 和 bgp always compare med 功能的特殊处理 . 默认情况下它们是被关闭的 , 但是打开它们将会影响到 BGP选路 , 例如某路由器存在如下三条路由 :

  • entry1: ASPATH 1, MED 100, internal, IGP metric to NEXT_HOP 10
  • entry2: ASPATH 2, MED 150, internal, IGP metric to NEXT_HOP 5
  • entry3: ASPATH 1, MED 200, external

BGP路由接收的顺序是 entry3 , entry2, entry1 , 即 entry3 是 BGP表中的最老的路由条目 . 缺省情况下 (即 bgp deterministic med关闭的情况下 ). 首先将对 entry1和 entry2进行比较 . 由于 AS_PATH中最后一个 AS并不相同 , 因此不会比较 MED, 根据选路规则第 8步 , 系统将优选 IGP到达 Next hop最近的 entry2. 然后 entry2和 entry3再进行比较 , 根据选路规则第 7步 , 系统将优先选择通过 eBGP始发的 entry3. 在这种情况下 , 即便是 entry 1和 entry 3来自于同一个 AS并在 MED比较中将优选 entry 1. 但根据接收顺序的影响 . entry 3成为了最优路由 .

如果打开bgp deterministic med 功能 , 路由器将根据 ASPATH属性对路由条目进行分组 , 并忽略接收到的先后顺序 , 如下所示 :

Group 1:

  • entry1: ASPATH 1, MED 100, internal, IGP metric to NEXT_HOP 10

  • entry3: ASPATH 1, MED 200, external

Group 2:

  • entry2: ASPATH 2, MED 150, internal, IGP metric to NEXT_HOP 5

此后在Group1中由于 entry 1有最小的 MED值将被优选 , 最后和 Group2的最优路由 entry 2进行比较 . 根据选路规则第 8步 , 系统将优选 IGP到达 Next hop最近的 entry2作为最优路由 . 如果启用 bgp always compare med 功能 , Group1和 Group2的最优路由比较时将忽略 ASPATH属性选择 MED最小的 entry 1作为最优路由 .

在FB闯祸的BGP协议简介》来自互联网,仅为收藏学习,如侵权请联系删除。本文URL:https://www.hashtobe.com/235.html