这篇文章将讨论 BGP 的基本操作,包括 BGP 的消息类型、消息使用方式以及消息格式 。此外,本章还要讨论与路由相关联的各种基本的 BGP 属性以及利用这些属性选择最佳路由的方式,最后将解释 BGP 对等会话的配置以及故障检测与排除方式。
谁需要 BGP
如果以下 4 个问题的答案都是 是,那么就需要 BGP:
- 是否连接了其他路由域
- 是否连接了处于不同管理机构管辖范围内的域
- 域是否配置了多归属
- 是否需要路由策略
虽然 BGP 是一种域间路由协议,但是 BGP 并不是不同域之间的唯一一种路由协议。
连接非信任域
IGP 的潜在假设就是邻居均处于同一个管理机构的管辖范围,因而这些邻居都是可信任的:信任其没有恶意,信任其配置正确,信任其不会发送错误的路由信息。IGP 的设计目的是自由地交换路由信息,关注点是性能以及易配置性,而不是对路由信息进行严格控制。BGP 的设计目的是连接不受自己管理控制的域中的邻居。通常无法信任这些邻居,必须利用路由策略仔细控制与这些邻居(如果 BGP 的配置正确无误)交换的信息。
如果连接外部域是唯一的需求(特别是只有在一条连接的情况下),那么就不一定需要 BGP。此时静态路由可能是更加选择,这样就不用担心所交换的信息是错误信息,因为此时根本就不会交换任何信息。静态路由是控制数据包进出网络的最终手段。
如下所示,用户网络通过单一链路接入 ISP,如果该单一链路出现故障,由于不存在其他可选路由,因而无需做出任何决策,此时路由协议起不到任何作用。因此该拓扑结构的用户在边界路由器上配置了一条静态路由,并将该静态路由重分配到本 AS 中,同时 ISP 也会增加一条指向用户空间的静态路由并宣告到自己的 AS 中。
![](/fuchencong.github.io/2019/05/27/routing-tcp-ip-16/images/01.jpg)
处理 AS 间的流量时需要记住的一条重要规则是:每条物理链路实际上代表的是两条逻辑链路,一条用于入站流量,另一条用于出站流量。在不同方向上宣告的路由仅影响响应方向上的流量,路由宣告可以认为是承载数据包达到路由中所表示地址空间的承诺。用户路由器将默认路由宣告到本地 AS 中,也就是将数据包分发到所有目的地的承诺。同样,宣告了路由器 205.110.32.0/20 的 ISP 路由器也承诺将路由转发给该用户的 AS。因此,来自用户 AS 的出站流量取决于默认路由,而去往用户 AS 的入站流量则取决于 ISP 路由器宣告的路由。
该拓扑结构存在一个非常明显的脆弱点,那就是整个连接都存在大量单点故障,这种拓扑结构所欠缺的就是冗余性。
连接多个外部邻居
如下给出了一个改良后的拓扑结构,用户到同一个服务商拥有了冗余链路。只有入站流量和出站流量如何通过冗余链路则取决于这两条链路的使用方式。例如,多归属到单个服务提供商的典型配置方式是将其中一条链路设置为主要链路(专用 Internet 接入链路),另一条链路设置为备用链路。
![](/fuchencong.github.io/2019/05/27/routing-tcp-ip-16/images/02.jpg)
如果冗余链路仅用作备份,那么也不需要使用 BGP,此时的路由宣告方式与单归属应用场景相同,只是需要将备用链路相关的路由度量设置的高一些。
如下给出了主用及备用路由器的配置:
1 | Primary Router: |
1 | Backup Router: |
备用路由器有一条管理距离被设置为 150 的默认路由,这样仅当主用路由器的默认路由不可用时,该默认路由器的默认路由才会进入路由表。而且备用默认路由器以较高的度量值(大于主用默认路由的度量值)进行宣告,以确保 OSPF 域中的其他路由器优选主用默认路由。
虽然主用/备用设计方式满足了冗余性需求,但无法有效地利用可用带宽。一种更好的设计方式是同时使用这两条路径,在链路或路由器出现故障时,这两条路径可以互为备份。如下所示,负载共享到同一个 AS 时,两台路由器的配置可以完全相同:
1 | router ospf 100 |
此时两台路由器的静态路由拥有相同的管理距离,而且这两条默认路由均以相同的度量值进行宣告,而且是以 OSPF 度量类型 E1 进行宣告。对于该度量类型来说,OSPF 域中的每台路由器除了要考虑默认路由的开销之外,还要考虑到达边界路由器的内部的开销,因而每台路由器在选取默认路由时都会选择最近的出口点。
在大多数情况下,从多个出口点将默认路由宣告到 AS 中并在相同的出口点对离开 AS 的地址空间进行汇总,此时需要考虑的就是非对称流量模式是否存在问题。如果两个或多个出口点的地理间隔足够大,以至于时延变化变得非常重要时,就可能需要更好地控制路由,这时就可以考虑使用 BGP 了。入站路由宣告将影响出站流量,而出站路由宣告将影响入站流量。
在考虑是否使用 BGP 时,需要仔细权衡所得到的好处与增加路由复杂度所带来的代价,只有对流量控制有益时,才应该优选 BGP(相对于静态路由而言)。而且还应该分别考虑出站和入站流量,如果仅需要控制入站流量,那么可以通过 BGP 将路由宣告给提供商,而提供商仍然仅将默认路由宣告给用户 AS。如果仅需要控制出站流量,那么就可以利用 BGP 仅接收来自提供商的路由,但一定要仔细考虑该接收来自提供商的哪些路由。接收全部 BGP 路由意味着提供商会将整个 Internet 路由表都宣告给用户。
运行 BGP 的另一个考虑因素就是需要通过一个 AS 号来标识用户的路由域,与 IPv4 地址相似,AS 号的数量也是有限的,并且只能由区域性地址注册管理机构根据需要进行分配。与 IPv4 地址类似,AS 号也有一部分被保留用作私有用途:AS 号 64512-65535,这些 AS 号不是全局唯一的号码,不能包含在宣告给公共 Internet 的所有路由的 AS_PATH 中。几乎毫无例外,连接到单个服务提供商(无论是单归属还是多归属的用户)都使用该保留范围内的 AS 号,服务提供商则会将这些私有 AS 号从宣告的 BGP 路径中过滤掉。
设置路由策略
如下所示,用户归属到多个服务提供商网络,除了前面描述的多归属好处,该用户还能防范单个 ISP 故障导致的 Internet 连接丢失问题,对于该拓扑结构来说,与静态路由相比,BGP 通常是一种更佳选择。
![](/fuchencong.github.io/2019/05/27/routing-tcp-ip-16/images/03.jpg)
用户也可以不使用 BGP,一种可选方式就是将其中的一个 ISP 用作主用 Internet 连接,将另一个 ISP 作为备用。另一种可选方式就是设置指向这两个服务提供提供商的默认路由,让路由进程自行选择相应的路由。但是如果用户在多归属上支付了额外的费用,并与多个服务提供商签订了服务合同,那么就不应该采用这两种解决方案,此时应该优选 BGP。
此时也需要分开考虑入站流量和出站流量,对于入站流量和出站流量。对于入站流量,如果将所有的内部路由都宣告给了两个提供商,那么就能达到最可靠的结果,可以确保通过任何一个 ISP 到达用户 AS 中的所有目的端,即使两个提供商都在宣告相同的路由,入站流量也会优选其中的一条路径,BGP 提供了相应的路径优选工具。对于出站流量来说,应仔细考虑从提供商接收的路由,如果接受了两个提供商的全部路由,那么就能为所有的 Internet 目的端选择最佳路由。
如下所示,假设 ISP1 是所有 Internet 连接的优选提供商,而另一个提供商 ISP2 则只是少数目的端的优选提供商,那么就可以接受优选提供商的全部路由,而仅接受另一个提供商的部分路由。因此可以让次选提供商发送其客户路由,并配置一条指向该次选 ISP 的默认路由,在主用 ISP 的连接出现故障时再使用 ISP 的连接。
![](/fuchencong.github.io/2019/05/27/routing-tcp-ip-16/images/04.jpg)
ISP1 发送的全部路由中可能包含 ISP2 的客户路由(可能学自 Internet,也可能学自直接的对等连接),但由于用户会从 ISP2 收到相同的客户路由,而用户路由器通常都会优选经由 ISP2 的较短路径,因此如果到 ISP2 的链路出现故障,那么用户将使用 ISP1 及其他 Internet 网络的较长路径去往 ISP2 的客户。与此类似,用户通常都会选择经 ISP1 去往除 ISP2 的客户之外的所有目的端,但是如果经 ISP1 的部分或全部精确路由都丢失了,那么用户将选择经 ISP2 的默认路由。
如果路由器因 CPU 和内存的限制而无法接收全部路由,那么也可以接收两个提供商的部分路由。每个提供商都会发送自己的客户路由,而用户则将默认路由指向这两个提供商。此时用户将以牺牲路由的精确性来换取路由器硬件的节省。
不断增加的复杂度使得用户越来越需要部署 BGP 以及路由策略,随着多归属以及相关路由策略的复杂度增加,对 BGP 的需求也就愈加迫切。
BGP 的危害
创建 BGP 对等关系涉及一个有趣的信任和非信任问题。一方面,由于 BGP 对等体是另外一个 AS,因而必须信任对端的网络管理员,以了解他们正在做些什么?另一方面,如果足够聪明,还应该检查每个操作,以防止对网络管理员的错误操作对本网造成损害。此外,还必须采取有效措施,以免自己的错误给 BGP 对等体造成影响。
路由宣告实质上是一个将数据包分发到所宣告目的端的承诺,对外宣告的路由会直接影响接收到的数据包,而收到的路由会直接影响所发送的数据包。对一个好的 BGP 对等方案来说,双方都应该完全了解每个方向上宣告的路由,而且必须考虑入站和出站流量,每个对等体都要确保仅传送正确路由,同时还要使用路由过滤器或其他路由策略工具以确保仅接收正确的路由。
ISP 一般都不会容忍用户的 BGP 配置差错,最糟糕的情况是双方的 BGP 对等方案都出现了故障。BGP 被设计用来在自主控制的系统之间进行通信。一个成功的、可靠的 BGP 对等方案不仅需要深入了解每个方向上宣告的路由,而且还要深入了解每个参与方的路由策略。
BGP 操作
之前已经介绍过 BGP 的一些基础知识,主要包括下面这些:
- BGP 是所有 IP 路由协议中非常独特的一种协议,BGP 仅发送单播消息,并且要与每个对等体建立一个独立的点到点连接
- BGP 是一种为其点到点连接使用 TCP(端口 179)的应用层协议,依靠 TCP 的内在特性实现会话的维护功能
- BGP 是一种矢量协议,由于 BGP 将去往目的端的路由视为经由一系列自治系统(而不是一系列路由跳)的路径,因而通常将 BGP 称为路径矢量协议,而不是距离矢量协议
- BGP 路由利用 AS_PATH 路由属性来描述路径矢量,AS_PATH 按序列出了到达目的端的路径所包含的 AS 号
- AS_PATH 属性是一种最短路径行列式,如果有多条路径去往同一个目的端,那么 AS_PATH 中 AS 号最少的路径就是最短路径
- AS_PATH 列表中的 AS 号可以实现环路检测机制,路由器收到 BGP 路由后,如果发现自己的 AS 号位于该路由的 AS_PATH 列表中,那么就认为出现了环路,从而丢弃该路由
- 如果路由器与拥有不同 AS 号的邻居建立了 BGP 会话,那么就将该 BGP 会话称为 EBGP 会话,如果邻居与该路由器的 AS 号相同,那么就称为 IBGP 会话,此时分别将这两类邻居称为外部邻居和内部邻居
接下来将以此为基础讨论 BGP 的操作方式。
BGP 消息类型
在建立 BGP 对等连接之前,两个邻居必须执行标准的 TCP 握手过程,并打开到端口 179 的 TCP 连接。TCP 为一条可靠连接提供了分段、重传、确认以及排序等功能,从而将 BGP 从这些功能中解放出来。所有的 BGP 消息都采用单播方式经 TCP 连接传递给邻居,BGP 使用以下 4 种基本消息类型:
- Open(打开)消息
- Keepalive(保持激活)消息
- Update(更新)消息
- Notification(通告)消息
还有第五种 BGP 消息:Route Refresh(路由刷新),但是第五种消息并不属于基本的 BGP 功能。
Open 消息
TCP 会话建立之后,两个邻居之间需要发送 Open 消息,每个邻居都用该消息标识自己并指定 BGP 操作参数。Open 消息包含以下信息:
- BGP 版本号(BGP version number):指定发起端正在运行的 BGP 版本号(2、3、4),IOS 默认使用 BGP-4。
- 自治系统号(Autonomous system number):该字段表示的是会话发起路由器的 AS 号,该信息可以确定 BGP 会话是 EBGP 会话(如果与邻居的 AS 号不同)或 IBGP 会话(如果邻居的 AS 号相同)
- 保持时间(Hold time):该字段表示路由器在收到 keepalive 消息或 update 消息之前可以等待的最长时间(以秒为单位)。如果邻居双方的保持时间不一致,那么将以较短的时间作为双方可接受的保持时间。
- BGP 标识符(BGP identifier):该字段标识邻居的 IPv4 地址。IOS 确定 BGP 标识符的过程与确定 OSPF 路由器 ID 的过程完全一致:使用数值最大的环回地址;如果环回接口没有配置 IP 地址,那么就选择数值最大的物理接口的 IP 地址
- 可选参数(Optional Parameters):该字段用来宣告验证、多协议支持以及路由刷新等可选支持能力
keepalive 消息
如果路由器接受邻居发送的 Open 消息中指定的参数,那么就响应一条 Keepalive 消息。此后 IOS 将默认每 60s 发送一条 keepalive 消息,或者是按照已协商的保持时间的 1/3 为周期发送 Keepalive 消息。需要注意,虽然 BGP 将部分可靠性功能挪到了底层的 TCP 会话上,但使用的仍然是自己的 Keepalive 消息,而不是 TCP 的 Keepalive 消息。
Update 消息
Update 消息用于宣告可行路由、撤销路由或两者。Update 消息包括以下信息:
- NLRI(Network Layer Reachability Information,网络层可达性信息):该字段是一个或多个宣告目的端前缀及其长度(长度、前缀)二元组。
- 路径属性(Path Attributes):是所宣告 NLRI 的特性,该属性提供了允许 BGP 选择最短路径、检测路由环路并确定路由策略的相关信息
- 撤销路由(Withdrawn Routes):描述已成为不可达且退出服务的目的端的(长度、前缀)二元组
虽然 NLRI 字段可以包含多个前缀,但每条 Update 消息仅描述单条 BGP 路径(这是因为路径属性仅描述单条路径,只是该路径可能会通往多个目的端)。需要再次强调的是,BGP 是一种比 IGP 更高层级的互联网络视图(IGP 路由总是指向单个目的 IP 地址)。
Notification 消息
路由器检测到差错之后,会发送 Notification 消息,并且总要关闭 BGP 连接。
BGP 有限状态机
可以利用有限状态机来描述 BGP 连接的建立和维护阶段。如下给出了完整的 BGP 有限状态机以及触发状态迁移的各种输入事件。
![](/fuchencong.github.io/2019/05/27/routing-tcp-ip-16/images/05.jpg)
Idle 状态
BGP 总是以 Idel 状态为起始点,该状态拒绝所有入站连接。启动事件(IE1)发生后,BGP 进程会初始化所有 BGP 资源、启动 ConnectRetry(连接重试)定时器、初始化去往邻居的 TCP 连接,侦听来自邻居的 TCP 初始化并将状态更改为 Connect(连接)状态。启动事件由配置 BGP 进程或重置现有进程的操作员发起,或者由重置 BGP 进程的路由器软件发起。
如果发生差错,BGP 进程将迁移到 Idle 状态,此时路由器可能会自动尝试发起另一个启动事件,为了限制经常性地重启导致波动,在第一次迁移到 Idle 状态后,路由器会设置 ConnectRetry 定时器,在定时器到期之后才会重新再起 BGP,以后每次 ConnectRetry 时间都是之前的两倍。
Connect 状态
该状态下,BGP 进程一直等待 TCP 连接的完成,如果 TCP 连接建立成功,BGP 将会向邻居发送 Open 消息并进入 OpenSent(打开发送)状态。如果 TCP 连接建立不成功,BGP 进程将继续侦听由邻居初始化的连接,重置 ConnectRetry 定时器,并迁移到 Active(激活)状态。
如果 ConnectRetry 定时器到期仍处于 Connect 状态,则重置定时器,并再次尝试与邻居建立 TCP 连接,进程也将继续维持在 Connect 状态,其他输入事件将会让 BGP 进程迁移到 Idle 状态。
Active(激活)状态
该状态下,BGP 进程会尝试与邻居初始化 TCP 连接,如果 TCP 连接建立成功,BGP 进程会清除 ConnectRetry 定时器、完成初始化过程、向其邻居发送 Open 消息,并迁移到 OpenSent 状态。
如果 ConnectRetry 定时器到期时,BGP 进程仍处于 Active 状态,那么进程将返回 Connect 状态并重置 ConnectRetry 定时器,而且还要与对等体进行 TCP 连接的初始化并继续侦听来自对等体的连接。
如果邻居试图以非期望的 IP 地址建立 TCP 会话,则重置 ConnectRetry 定时器、拒接该连接,并继续维持在 Active 状态。
其他输入事件(启动事件除外,Active 状态会忽略启动事件)将会让 BGP 进程迁移到 Idle 状态。
OpenSent 状态
该状态下,已经发送了 Open 消息,BGP 会一直等待直至侦听到来自邻居的 Open 消息。接收到 Open 消息后,会检查该消息的每个字段,如果存在差错,则发送 Notification 消息并迁移到 Idle 状态。
如果接收到的 Open 消息没有差错,则发送 Keepalive 消息并设置 Keepalive 定时器,此外还要协商保持时间,以确定一个较小的保持时间值。如果协商后的保持时间为 0,则不启动保持定时器和 Keepalive 定时器。根据对等体 AS 号,可以确定对等连接是内部连接还是外部连接,并迁移到 OpenConfirm (打开确认)状态。
如果收到断开 TCP 连接的请求,则本地进程将关闭 BGP 连接、重置 ConnectRetry 定时器、开始侦听由邻居发起的新连接,并迁移到 Active 状态。其他输入事件(启动事件除外,因为该状态会忽略启动事件)则会让 BGP 迁移到 Idle 状态。
OpenConfirm(打开确认)状态
该状态下,BGP 进程将等待 Keepalive 消息或 Notification 消息,如果收到的是 Keepalive 消息,则迁移到 Established(建立状态),如果收到是 Notification 消息或断开 TCP 连接请求,则迁移到 Idle 状态。如果保持定时器到期,或检测到差错,或发生了终止事件,则向邻居发送一条 Notification 消息,关闭 BGP 连接,并将状态更改为 Idle 状态。
Established(建立)状态
该状态下,BGP 对等连接已完全建立,对等体之间可以相互交换 Update、Keepalive 和 Notification 消息。如果收到的是 Update 或 Keepalive 消息,则重新启动保持定时器(如果协商好的保持时间不是 0)。如果收到的是 Notification 消息,则迁移到 Idle 状态。其他事件(启动事件除外,因为该状态会忽略启动事件)将会让 BGP 发送一条 Notification 消息并迁移到 Idle 状态。
路径属性
路径属性是所宣告 BGP 路由的特性,虽然该术语专用于 BGP,但是这个概念并不陌生:每条路由宣告(无论发起的路由协议是何种路由协议)都有属性。例如每条路由宣告都有表达目的端的某种信息(地址前缀)、能够与去往相同目的端的其他路由进行对比的某种量值(度量)以及关于目的端的方向性信息(如下一条地址)。BGP 不但拥有大家已经熟知的与其他路由协议相同的各种属性,而且还拥有许多用于创建并沟通路由策略的特有属性。所有的路径属性都可以归入以下 4 类:
- 周知强制属性
- 周知自选属性
- 可选传递性属性
- 可选非传递性属性
首先每种属性要么是周知属性(即要求所有 BGP 实现都能识别这些属性),要么就是可选属性(即不要求所有 BGP 实现都支持这些属性)。周知属性包括强制属性(即必须包含在所有的 BGP Update 消息中)或自选属性(即可以包含在特定 Update 消息中,也可以不包含在特定 Update 消息中)。
如果可选属性是传递性的,那么 BGP 进程就应该接受包含该属性的 Update 消息(即使该进程并不支持该属性),而且应该将该属性传递给对等体。如果可选属性是非传递性的,那么无法识别该属性的 BGP 进程可以忽略包含该属性的 Update 消息,而且不该将路径宣告给其他对等体。简单而言,就是属性可以通过或者不可以通过路由器进行传递。
ORIGIN 属性
ORIGIN 是一种周知强制属性,指定了路由更新的来源。如果 BGP 存在多条去往同一个目的端的路由时,那么就将 ORIGIN 属性作为确定优选路由的要素之一。ORIGIN 属性指定的路由来源有:
- IGP:NLRI(Network Layer Reachability Information,网络层可达性信息)学自源 AS 的内部协议。如果路由来源是 IGP,那么 ORIGIN 值将为最高优先级。
- EGP:NLRI 学自外部网关协议。EGP 的优先级仅次于 IGP。由于 EGP 已被废除,因此以后不可能在遇到这种源类型,这是当初从 EGP 转换到 BGP 时的遗留产物。
- 不完全(Incomplete):NLRI 学自其他渠道。路由来源不完全的路由拥有最低优先级的 ORIGIN 值。不完全的路由并不是说该路由有缺陷,只是确定该路由来源的信息不完全而已。BGP 通过重分发机制学习到的路由向携带不完全路由来源属性,这是因为没有办法确定该路由的来源。
AS_PATH 属性
AS_PATH 属性是一种周知强制属性,该属性利用一串 AS 号来描述去往由 NRLI 指定的目的地的 AS 间路径或 AS 级路由。AS 发起路由(在其 AS 内向外部邻居宣告目的地的 NLRI)时,会将自己的 AS 号添加到 AS_PATH 中。后续的 BGP 路由器在将路由宣告给外部对等体时,也会将自己的 AS 号添加到 AS_PATH 中,因而 AS_PATH 描述了路由所经过的全部自治系统(从刚刚到达的 AS 开始,到发起该路由的源 AS 结束)。
仅当 Update 消息发送给其他 AS 时,BGP 路由器才会在 AS_PATH 中添加自己的 AS 号。也就是说仅在 EBGP 对等体之间宣告路由时,才会在 AS_PATH 中追加自己的 AS 号,如果是在 IBGP 对等体之间宣告路由,那么就不会追加 AS 号。
一般来说,AS_PATH 列表中存在同一 AS 号的多个实例是毫无意义的,而且还会破会 AS_PATH 属性的作用。但是对于某些特定场合来说,在 AS_PATH 属性中添加特定 AS 号的多个实例也是非常有用的。通常将这种在 AS_PATH 中增加额外 AS 号的操作称为 AS 路径预附加。
AS_PATH 属性包含了一系列有序的 AS 号,用来描述去往特定目的端的路径,实际上,AS_PATH 属性可以分为以下两种类型,这两种属性是通过 AS_PATH 属性中的类型代码进行区分的:
- AS_SEQUENCE:是一种有序的 AS 号列表
- AS_SET:是去往目的端的路径的无序 AS 号列表
AS_PATH 属性的另一个功能就是预防环路,如果 BGP 路由器发现从外部对等体收到的路由的 AS_PATH 中包含自己的 AS 号,那么就认为该路由出现了环路,从而丢弃该路由。但是如果执行了前缀聚合操作,那么就有可能丢失某些 AS_PATH 细节信息,从而增大潜在的环路风险。
AS_PATH 的环路预防功能并不需要列表中的 AS 号必须以特定顺序出现,唯一需要的就是接收端路由器能够确定自己的 AS 号是否位于 AS_PATH 中,因而出现了 AS_SET。BGP 路由器根据从其他 AS 学到 NLRI 创建聚合路由时,可以像 AS_SET 那样,在 AS_PATH 中包含所有的 AS 号。
如下所示,聚合路由仍然以 AS_SEQUENCE 为起始,接收端路由器能够根据该路径回溯到聚合点,但聚合路由中包含了 AS_SET,因而能够避免路由环路。
![](/fuchencong.github.io/2019/05/27/routing-tcp-ip-16/images/06.jpg)
AS_SET 是一种折中解决方法,路由汇总的主要好处之一就是路由稳定性,如果属于聚合路由的某个网络出现故障,那么不会将该故障宣告到聚合点之外。但是如果在聚合路径的 AS_PATH 中包含了 AS_SET,那么该聚合路由的稳定性将大大降低,因为 AS_SET 的变化情况也会宣告到聚合点之外。但是,与聚合路由相关联的的成员 AS 号可见性相比,更应该关注的是聚合路由背后的大量前缀的可见性。
NEXT_HOP 属性
该周知属性描述了去往所宣告目的端的路径上的下一跳路由器的 IP 地址。但是与通常的 IGP 不同,BGP 的 NEXT_HOP 属性所描述的 IP 地址并不总是邻居路由器的 IP 地址,其规则如下:
- 如果宣告路由器与接收路由器位于不同的自治系统中(外部对等体),那么 NEXT_HOP 是宣告路由器的接口 IP 地址
- 如果宣告路由器与接收路由器位于同一自治系统中(内部对等体),且 Update 消息的 NLRI 指向的是同一 AS 内的目的地,那么 NEXT_HOP 是宣告该路由的邻居的 IP 地址
- 如果宣告路由器和接收路由器是内部对等体,且 update 消息的 NLRI 指向的是不同 AS 内的目的地,那么 NEXT_HOP 是外部对等体(通过该对等体学习到该路由)的 IP 地址
如下分别展示了这三种情况下的 NEXT_HOP 属性:
![](/fuchencong.github.io/2019/05/27/routing-tcp-ip-16/images/07.jpg)
![](/fuchencong.github.io/2019/05/27/routing-tcp-ip-16/images/08.jpg)
![](/fuchencong.github.io/2019/05/27/routing-tcp-ip-16/images/09.jpg)
对于第三种情况,需要保证内部路由器知道连接在这两个自治系统上的外部子网,虽然可以使用静态路由,但更好的方式是在外部接口上运行被动模式下的 IGP。或者也可以考虑第二种替代解决方案(该解决方案也被视为最佳实践):即利用被称为 next-hop-self 的配置选项让 AS 边界路由器在 NEXT_HOP 属性中设置自己的 IP 地址,而不是外部对等体的 IP 地址,此后内部对等体的下一跳路由器地址即为 AS 内边界路由器的地址(IGP 知道该地址)。
权重
权重是 Cisco 的专有 BGP 路径属性,仅对单台路由器内的路由有效,无法与其他路由器进行通信。分配给每条路由的 WEIGHT 取值范围为 0-65535,权重越大,表明该路由越优。在所有路由特性中,权重是 BGP 决策进程选择最佳路径时最重要的判断要素。在默认情况下,所有从对等体学习到的路由的权重为 0,而所有本地路由器生成的路由的权重为 32768。
优先级仅在本地对单台路由有效,权重信息既不包含在 BGP update 消息中,也不会以任何方式宣告给 BGP 路由器的对等体。因此权重仅影响单台路由器的路由决策,而不会影响其他路由器的路由决策。
BGP 决策进程
BGP 的 RIB(Routing Information Base,路由信息库)包括以下三个部分:
- Adj-RIBs-In:存储了从对等体学到的路由更新中未经处理的路由信息,Adj-RIBs-In 中的路由被认为是可行路由
- Loc-RIB:包含了 BGP 发话路由器对 Adj-RIBs-In 中的路由应用本地路由策略之后选定的路由,这些路由以及通过其他路由协议发现的路由均被安装在路由表(RIB)中
- Adj-RIBs-Out:包含了 BGP 发话路由器在 BGP Update 消息中宣告给对等体的路由。出站路由策略决定将哪些路由放到 Adj-RIBs-Out 中
RIB 的这 3 个组成部分既可以是三个完全不同的数据库,也可以是利用指针来区分不同部分的单个数据库。BGP 决策进程通过对 Adj-RIBs-In 中的路由应用入站路由策略,并向 Loc-RIB 输入选定的或修改的路由来进行路由选择。BGP 决策进程包括以下三个阶段:
- 第一阶段计算 Adj-RIBs-In 中的每条可行路由的优先级。无论什么时候,只要路由器从邻接 AS 的对等体收到 BGP Update 消息(包含新路由、发生变化的路由或撤销路由),就会激活本决策阶段,该阶段会单独计算每条路由,并为每条路由生成一个用于指示该路由优先级的非负整数
- 第二阶段从所有可用路由中为特定目的端选择最佳路由,并将其安装到 Loc-RIB 中。只有完成了第一阶段之后才会激活本决策阶段。第二阶段还通过检查 AS_PATH 来检测环路,本地 AS 位于 AS_PATH 中的路由均被丢弃
- 第三阶段将适当的路由添加到 Adj-RIBs-Out 中,以便向对等体进行宣告。只有当 Loc-RIB 发生变化且第二阶段已经完成之后才会激活本决策阶段。路由聚合(如果执行了路由聚合操作)就发生在本阶段
除非指定了其他特殊的路由策略,否则第 2 阶段总是在所有可行路由中为特定目的端选择最精确路由。请注意,如果,如果路由的 NEXT_HOP 属性指定的地址不可达,那么就不会选择该路由。对于 IGBP 来说还存在一种特殊情况:未与 IGP 同步的路由将无法选择。
到目前为止,已经了解了可以为增加单台路由器、内部对等体、邻接自治系统以及自治系统之外的路由策略而赋予 BGP 路由多种属性。路由器在多条去往相同目的端的等价路由之间做出决策时,需要遵循一系列决策过程,这些决策过程就是 BGP 决策进程。IOS 规定的决策进程如下:
- 优选权重最大的路由,这是 IOS 专有功能
- 如果权重相同,则优选 LOCAL_PERF 值最大的路由
- 如果 LOCAL_PERF 值相同,那么就优选该路由器本地发起并通过 network 或 aggregate 命令或重分发操作注入到 BGP 的路由,也就是说优选学自同一台路由器上的 IGP 或直连路由。
- 如果 LOCAL_PERF 值相等且没有本地发起的路由,那么就优选 AS_PATH 最短的路由
- 如果 AS_PATH 长度相等,那么就优选 ORIGIN 代码最小的路径,IGP 小于 EGP,EGP 小于 Incomplete
- 如果 ORIGIN 代码相同,那么就优选 MED(MULTI_EXIT_DISC)值最小的路由,仅当所有备选路由的 AS 号均相同才比较 MED 值
- 如果 MED 相同,那么就优选 EBGP 路由,次选联盟 EBGP 路由,最后选择 IBGP 路由
- 如果此时的路由仍相同,那么就优选到达 BGP_NEXT_HOP 路径最短的路由,该路由是到达下一跳地址的路由中 IGP 度量最小的路由
- 如果此时的路由仍相同,且这些路由均来自同一个邻接 AS,并通过命令 maximum-paths 启用了 BGP 多路径功能,那么就在 Loc-RIB 中安装所有等价路由
- 如果此时的路由仍相同且是外部路由,那么就优选最开始接受到的路径,由于可以避免新路由抢占老路由,因而可以降低路由翻动的概率。如果启用了语句 bgp best path compare-routerid,就会忽略本步骤
- 如果没有启用多路径功能,那么就优选 BGP 路由器 ID 最小的路由。如果使用了路由反射机制,那么就优选 ORIGINATOR_ID 最小的路由
- 如果此时的路由仍相同且使用了路由反射机制,那么就优选 CLUSTER_LIST 最短的路由
- 如果此时的路由仍相同,那么就优选 IP 地址最小的邻居宣告来的路由
BGP 消息格式
BGP 消息是在 TCP 报文段中使用 TCP 端口 179 进行承载的,最大消息长度为 4096 个字节,最小长度为 19 字节,所有 BGP 消息都有一个相同的头部,对不同类型的 BGP 消息来说,数据部分可能位于该头部之后,也可能不位于该头部之后。
BGP 消息头部如下:
![](/fuchencong.github.io/2019/05/27/routing-tcp-ip-16/images/10.jpg)
- 标志:16 字节,用于检测 BGP 对等体之间的同步丢失情况,并且在支持验证功能的情况下可以进行消息验证
- 长度:2 字节,指示消息的全部长度(包括头部),以字节为单位
- 类型:1 字节,指示消息的类型
Open 消息
Open 消息的格式如下,该消息是 TCP 连接建立后发出的第一条消息,如果收到的 Open 消息是可接受的,俺么就发送一条 Keepalive 消息,以确认该 Open 消息。确认了 Open 消息之后,BGP 连接就处于 Established 状态,可以发送 Update、Keepalive 以及 Notification 消息。
![](/fuchencong.github.io/2019/05/27/routing-tcp-ip-16/images/11.jpg)
BGP Open 消息包含以下字段:
- 版本:1 个字节,用于指定发起方运行的 BGP 版本
- 我的自治系统:2 个字节,用于指定发起方的 AS 号
- 保持时间:2 个字节,用于表示发送端建议的保持时间。接收端将该字段的值与其配置的保持时间进行对比,要么接受较小的保持时间值,要么拒绝该连接
- BGP 标识符:4 个字节,是发起方的 BGP 路由器 ID,除非在 BGP 配置中指定路由器 ID,否则 IOS 将路由器 ID 设置为最大的环回接口 IP 地址,如果没有配置环回接口,那么就设置为最大的物理接口 IP 地址
- 可选参数长度:1 个字节,表示后面可选参数的长度
- 可选参数:该可变长度字段包含一个可选参数列表,每个参数都由一个长为 1 个字节的类型字段、一个长为 1 个字节的长度字段以及一个包含参数值的可变长度字段组成
Update 消息
Update 消息的格式如下,该消息的作用是向对等体宣告一条可行路由或撤销多条不可行路由,或者两者。
![](/fuchencong.github.io/2019/05/27/routing-tcp-ip-16/images/12.jpg)
BGP Update 消息包含以下字段:
- 撤销路由的长度:2 个字节,用于指示后面被撤销路由字段的的长度,该字段为 0 时表示没有被撤销的路由
- 被撤销路由:该可改变长度字段包含了一个要退出服务的路由列表,列表中的每条路由都以(长度,前缀)二元组形式加以表示
- 整个路径属性长度:长 2 个字节,用于指示后面的路径属性字段的长度
- 路径属性:该可变长度字段列出了与后面 NLRI 字段相关联的属性信息,每个路径属性都以可变长度的三元组(属性类型、属性长度、属性值)进行表示,属性类型部分是要给长为 2 个字节的字段,由 4 个标记比特,4 个未用比特以及一个字节的属性类型代码组成
- 网络层可达性信息:该可变长度字段包含一个(长度,前缀)二元组,其中长度部分以比特为单位表示后面的前缀长度,前缀部分则是 NRLI 的 IP 地址前缀。如果长度部分取值为 0,那么就表示前缀将匹配所有 IP 地址
Keepalive 消息
Keepalive 消息以保持时间的 1/3(但不得小于 1 秒钟)为周期进行交换,如果协商后保持时间为 0,那么就不发送 Keepalive 消息。Keepalive 消息仅包含长度为 19 个字节的 BGP 消息头部,不包含其他数据。
Notification 消息
Notification 消息的格式如下所示,路由器检测到差错条件之后就会发送该消息。该消息发出之后,将立即关闭 BGP 连接。
![](/fuchencong.github.io/2019/05/27/routing-tcp-ip-16/images/13.jpg)
BGP 的 Notification 消息包括以下字段:
- 差错代码(Error Code):1 个字节,用于指示差错类型
- 差错子代码(Error Subcode):一个字节,提供了更精确的差错信息
- 数据(Data):该可变长度字段用于诊断差错原因,该字段的内容与差错代码及差错子代码相关
BGP 对等关系的配置及故障检测与排除
BGP 的配置非常复杂,但 BGP 配置的复杂性主要在于策略,BGP 对等关系的配置实际上并不十分复杂,即使其复杂度仍然高于大多数 IGP 配置。
案例研究:EBGP 对等会话
配置路由器之间的 BGP 会话的步骤如下:
- 第一步:利用命令 router bgp 建立 BGP 进程并指定本地 AS 号
- 第二步:利用命令 neighbour remote-as 指定邻居及邻居的 AS 号
使用命令 debug ip bgp 命令可以查看路由器的 BGP 的变化情况。利用 neighbor remote-as 命令创建了邻居之后,就会在 BGP 邻居数据库中为指定邻居创建一个表项,show ip bgp neighbors 命令既可以显示整个 BGP 邻居数据库,也可以显示指定邻居表项。
案例研究:基于 IPv6 的 EBGP 对等会话
BGP 路由器之间的 TCP 连接既可以是 IPv4,也可以是 IPv6。需要记住的是,TCP 会话的端点地址与运行在该 TCP 连接上的 BGP 会话所支持的地址族没有关系,也与 BGP 交换的前缀类型无关,无论 TCP 会话基于 IPv4 地址还是 IPv6 地址,BGP 都能同时交换 IPv4 和 IPv6 前缀。
如果没有配置路由器的 BGP 会话承载其他地址族,那么 EBGP 会话(虽然该会话运行在两个 IPv6 端点之间)只能承载 IPv4 前缀(也就是默认地址族)。
案例研究:IBGP 对等会话
如下显示了一个 AS(AS200)连接到 AS100 上(为简化起见,连接 Vail 和 Taos 的接口仍然是 IPv4),AS100 中增加了两台路由器:Aspen 和 Telluride,并且 Telluride 通过 EBGP 连接了 Alta(位于 AS400)中:
![](/fuchencong.github.io/2019/05/27/routing-tcp-ip-16/images/14.jpg)
AS100 中的三台路由器与该 AS 中的其他两台路由器具有一个 IBGP 对等会话,之前说过,基于以下两条理由必须建立全网状的 IBGP 连接(同一 AS 中的每台 BGP 路由器之间都必须建立一条直接相连的 IBGP 连接):
- 由于 AS_PATH 属性对于单个 AS 来说没有任何意义,因而 IBGP 没有环路避免机制,全网状 IBGP 连接意味着每台 BGP 路由器都直接将自己的前缀信息宣告给同一 AS 中的其他每一台 BGP 路由器,因而所有路由器都不需要将学自内部对等体的前缀宣告给其他内部对等体,否则将导致路由环路。默认的 BGP 规则进一步强化了全网状连接需求:BGP 不能将学自内部邻居的路由宣告给其他内部邻居
- 转发路径上的每台 BGP 路由器都必须知道路由器与外部对等体使用的 BGP 路由,从而转发到纯内部 BGP 路由器的数据包在去往外部下一跳的途中不会被内部路由器丢弃。
从总体上来说,IBGP 对等会话的配置方式与 EBGP 对等会话完全相同,之所以是 IBGP 而不是 EBGP,原因就在于 neighbor remote-as 命令引用的 AS 号与 router bgp 命令引入的本地 AS 号完全相同。
另一条日常维护和检测与排除 BGP 网络故障的常见命令:show ip bgp summary,该命令可以显示路由器上配置的 BGP 对等会话的摘要信息以及每个对等会话的状态信息。
部署 IBGP 时可能遇到的一个非常普遍的问题,与 IGP 不同,IBGP 会话通常会跨越多个路由器跳,因而除非路由器知道如何到达对等体,否则无法与对等体建立 IBGP 会话。因此,在检测与排除处于 Active 状态(侦听已配置邻居)的 IBGP 会话故障时,首先就要查看这两个邻居的路由表,以确定它们是否知道如何达到对方。
为了增加 AS100 的可靠性,AS100 需要一个更具弹性的拓扑结构,从而可靠地转发数据包并交换 BGP 信息。如下所示,在 Telluride 与 Vali 之间增加了一条链路之后,就可以增强 AS100 的冗余性,从而解决了单条内部链路的故障隐患问题。
![](/fuchencong.github.io/2019/05/27/routing-tcp-ip-16/images/15.jpg)
如果链路出现故障,那么希望原先使用该链路的 IBGP 会话能够通过替代路径进行重路由,但是由于 IBGP 会话运行在物理接口之间,因而无法确定一定可以实现。一种可能的解决方法就是配置冗余的 IBGP 会话,但是随着 AS 拓扑结构复杂度的增加,这种方法(所有路由器都要配置到所有物理接口的冗余 IBGP 连接)会导致 BGP 的配置长度以及 IBGP 会话数量的急剧增加。
更好的解决方法是在环回接口(而不是物理接口)之间配置对等会话。如果在环回地址之间建立对等会话,那么可以从 IBGP 的拓扑结构中删除物理接口的依赖性,AS 内的每台路由器之间都只需要单个 IBGP 会话,而且该会话是通过最佳可用路径进行路由的。如果路径上的某条链路出现了故障,那么 IBGP 会话就可以通过次优路径进行重路由。
在环回接口之间配置 IBGP 对等会话,不仅要为 IBGP 会话的远端指定邻居的环回地址(而不是物理地址),而且还必须将本地路由器的环回接口指定为 IBGP 会话的发起端(默认情况下,出站 TCP 会话源自出站物理接口地址),neighbor update-source 语句指示路由器在发起 TCP 会话时必须从指定的本地环回接口去往指定邻居。
案例研究:直连检查与 EBGP 多跳
上一个案例中 IBGP 会话运行在环回地址之间,EBGP 会话仍然运行在直连物理接口之间,这也是绝大多数 EBGP 会话的标准实践方式。IOS 默认设置通过以下两种措施来确保外部 BGP 对等体之间是直接相连的:
- 将发送给外部对等体且包含 BGP 消息的数据包的 TTL 值设为 1,如果数据包经过了一个路由器跳,那么就会递减为 0,从而丢弃该数据包
- 检查已配置邻居的 IP 地址,以确定该地址属于直连子网
有时在环回接口之间运行 EBGP 也非常有用,此时可以将邻居的环回地址指定为邻居地址,利用 neighbor update-source 语句从本地环回接口发起 EBGP 会话,并配置相应的机制让会话两端的路由器都能发现远端对端地址。根据定义,IGP 无法运行在不同自治系统之间的路由器上,因此可以使用静态路由,为每条物理链路都配置一条指向远端环回地址的静态路由,并将链路的远端地址指定为下一跳。
另外需要注意,如果外部 BGP 邻居是直连邻居,但邻居地址不属于本地子网(这是在环回接口之间建立 EBGP 对等会话时的最常见情形),那么就可以利用 neighbor disable-connected-check 语句禁用 IOS 的直连检查特性。
neighbor ebgp-multihop
语句可以更改发送给指定邻居的 EBGP 消息的默认 TTL 值,当 BGP 路由器被配置为穿越多个路由器建立 EBGP 会话时,需要配置该命令。而且配置该命令时,会自动禁用直连检查机制。
案例研究:管理和保护 BGP 连接
有一些更丰富的配置特性可以让 BGP 会话更加可管,也更加安全,虽然这些特性对于 BGP 会话的建立以及运行来说并非必不可少。如下是一些常见的管理和安全特性:
- bgp router-id:之前讲过,IOS 在获得 BGP 路由器 ID 时的处理进程与 OSPF 路由器 ID 相同,如果存在环回接口地址,那么就使用环回接口地址,否则就使用数值最大的物理接口地址。而该配置可以忽略该自动进程,允许手工分配 BGP 路由器 ID
- bpg log-neighbor-changes:最新 IOS 版都默认启用该特性。如果邻居状态发生了变化,那么该功能特性就能将变化情况以及变化原因记录到路由器的日志缓存
- neighbor password:可以为邻居启用 MD5 认证并指定密码。与 IGP 一样,必须认证所有的 IBGP 会话,但是认证 EBGP 会话不仅非常重要,而且也是保护网络的必备需求,绝大多数面向路由协议的攻击尝试都是针对 EBGP 的,由于 EBGP 是暴露在外部网络的协议,因而也是最容易访问的协议,因此永远不要在无认证的情况下运行 EBGP
- neighbor ttl-security:会改变接收到的 EBGP 消息包的可接受 TTL 值以及发送的 BGP 消息包的 TTL 值。接收到的 BGP 消息包的 TTL 值必须是 254 甚至更大,发送出去的 BGP 消息包的 TTL 值为 255。将发起数据包的数据包的 TTL 值设置为 1的默认行为可以确保数据包不会传播到直连路由器之外,但接收 TTL 为 0 或值更大的数据包的默认行为却意味着可以向 EBGP 发起多种远程攻击。而 ttl-security 的行为这样可以确保无法从非直连路由器向本地 BGP 进程发送数据包。但是 neighbor ttl-security 与 neighbor ebgp-multihop 不兼容,可以调整 neighbor ttl-security 的跳数规范来达到相同效果
- neighbor description:对于 BGP 没有功能上的效应,只是为邻居地址提供了一个最多 80 个字符的文字描述,能够在配置中更容易地标识邻居
- neighbor shutdown:如果希望禁用指定邻居的连接,但是又不希望删除该邻居的配置,就可以使用该配置语句
展望
这里全面讨论了 BGP 对等会话以及底层 TCP 会话的配置方式以及故障检测与排除技术,下一章将详细讨论通过 BGP 会话发送和接收路由信息的相关技术,以及利用路由策略改变路由信息的使用方式。