📚 第七章 路由协议
📄 一句话概括

BGP 是 AS 之间唯一的协议,靠 TCP 179 端口传。 它分 eBGP 和 iBGP:一个跨 AS,一个在 AS 内部传外部路由。

📝 本节和前面几节的关系

7.5 讲完了 AS 内部,这一节跨出边界。 7.6.2 讲 BGP 怎么防环,这一节先讲它长什么样。

一、为什么用 TCP

BGP 的邻居之间先建一条 TCP 连接(端口 179),再在它上面交换路由。 这是它和 OSPF 最直观的差别——OSPF 直接挂在 IP 上,BGP 套了一层 TCP。 理由和 7.5.1 那条正好相反:OSPF 要在「还没有路由」时工作,所以不能依赖 TCP; BGP 只在「已经能通」的边界路由器之间跑,所以可以依赖 TCP。 而且 BGP 的通告必须可靠——丢一条就可能让一大片网络不可达,自己实现重传太费事。 用 TCP 还有个副作用:BGP 会话「建立慢、保持久」。 TCP 三次握手加上 BGP 的 OPEN、KEEPALIVE,要几秒才建起来;但建好之后可以保持几个月不动。 所以「BGP 邻居断了」通常意味着「底层链路真的出事了」,不像 OSPF 那样可能只是丢了一个 Hello。

二、eBGP 和 iBGP

这两个名字容易混,但区别很简单:看两端是不是同一个 AS。

类型 两端 作用 默认行为
eBGP 不同 AS 真正交换外部路由 改 AS_PATH
iBGP 同一个 AS 把外部路由传给内部 不改 AS_PATH

为什么需要 iBGP:边界路由器从外面学到的路由,要告诉 AS 内部的所有路由器。 这件事不能靠 OSPF——因为 OSPF 不认识 AS 路径, 如果把外部路由重分发进 OSPF,AS_PATH 信息就丢了,防环能力也没了。 所以「外部路由在 AS 内部也用 BGP 传」,这就是 iBGP。 iBGP 有一条反直觉的规矩:「iBGP 学到的路由,不再传给其他 iBGP 邻居」(叫水平分割)。 所以一个 AS 里有 n 台边界路由器,就要建 n 乘 (n 减 1) 除 2 条 iBGP 全互联。 n 大了就撑不住——这就是要用「路由反射器」或「联盟」的原因。

三、全互联撑不住怎么办

算一下就知道为什么要优化:

边界路由器数 iBGP 会话数 能不能维护
5 10 可以
20 190 勉强
100 4,950 不行
500 124,750 完全不行

n 的平方涨得太快,所以有两种优化: 一是路由反射器(RR):指定几台做「中转」,其他只跟它建会话。 二是联盟(confederation):把一个大 AS 切成几个子 AS,内部再用 eBGP。 路由反射器更常用,因为它「不改变 AS 号」——对外还是一个 AS,只是内部多了一层中转。 代价是「环路风险」: RR 要保证「反射出去的路由不会再绕回来」,它靠 Cluster ID 和 Originator ID 两个属性来防。 这两个属性是 BGP 里少数「专为反射而加」的字段。

四、AS 号的两个写法

AS 号原本 16 位,现在 32 位。 32 位的号有两种写法:asplain 是直接写十进制(4200000000), asdot 是「高 16 位点低 16 位」(64086.59904)。 为什么要有 asdot:因为老设备只认 2 字节,它的配置界面里只能填 0 到 65535。 asdot 是一种「用两个 16 位数表示一个 32 位数」的写法,让老设备的命令行也能表达大号。 新设备一般直接用 asplain,因为十进制更直观。 注意「AS 号和 IP 地址没有换算关系」这件事在 BGP 里尤其容易混: 经常看到「AS 4134 宣告了 1.2.3.0/24」,看起来像「AS 号加前缀」,其实那是「一条通告」的写法, 意思是「这个前缀由这个 AS 起源」。 查一个 IP 属于哪个 AS,要查 BGP 表或 whois,不能靠地址反推。

五、动手 Demo:BGP 的路径长什么样

看一条 AS_PATH 由哪些 AS 组成,再看 4 字节 AS 号的两种写法。 重点在 asdot 那个换算。

path = ['65001', '65010', '4134', '15169']
print('AS_PATH =', ' '.join(path), ' 长度 =', len(path))

for asn in (65536, 4200000000, 4294967294):
    hi, lo = asn >> 16, asn & 0xFFFF
    print('%11d  ->  asdot %d.%d' % (asn, hi, lo))

实跑输出:

--------------------------------------------------------------------
BGP 的路径长什么样
--------------------------------------------------------------------
**BGP 传的不是「距离」,是一串 AS 号。**
**这串东西叫 AS_PATH,它同时干了三件事**:**算长度、防环路、写策略。**

  AS 号     是谁             在路径里的角色
  ------------------------------------------
  65001     你自己的 AS      起点
  65010     本地运营商       第一跳
  4134      中国电信骨干     国内转接
  15169     Google           目的地所在 AS

**一条完整的 AS_PATH 就是「65001 65010 4134 15169」。**
**BGP 选路时先比长度**——**路径越短越优先,这跟 RIP 数跳数是一个思路。**

**但长度只是第一道筛子**,后面还有一堆。

  顺序     比较项                   含义
  ---------------------------------------------------------------------
  1        **Weight**               **本机自己设的偏好(Cisco 私有)**
  2        **Local Preference**     **本 AS 内部统一说的「优先走哪」**
  3        **本地始发**             **自己宣告的比学来的优先**
  4        **AS_PATH 最短**         **跳过的 AS 最少**
  5        **Origin**               **IGP 优于 EGP,EGP 优于不完整**
  6        **MED**                  **建议邻居「从哪个口进我」**
  7        **eBGP 优于 iBGP**       **外部学的优先**
  8        **IGP 到下一跳最短**     **自己内部哪条路近**
  9        **Router ID 最小**       **最后的兜底**

**注意 AS_PATH 只排第四**——**前面三条都是「人定的偏好」,不是「算出来的优劣」。**
**这正是 7.2.3 说的「AS 之间不选最快,选最合适」。**
**运维可以靠 Local Preference 强行让流量走某条线,哪怕它更长。**

**4 字节 AS 号的写法**:

  asplain 写法     asdot 写法
  -----------------------------
  65536            1.0
  4200000000       64086.59904
  4294967294       65535.65534

**asdot 就是「高 16 位点低 16 位」**——**65536 等于 1 乘 65536 加 0,所以写成 1.0。**
**这种写法是为了让老设备(只认 2 字节)能看懂**,**新设备一般直接用 asplain 的十进制。**

一条完整的 AS_PATH 就是「65001 65010 4134 15169」。 BGP 选路时先比长度——路径越短越优先,这跟 RIP 数跳数是一个思路。 asdot 就是「高 16 位点低 16 位」——65536 等于 1 乘 65536 加 0,所以写成 1.0。 4294967294 的高位是 65535、低位是 65534,所以写成 65535.65534。 这两个数正好是 2 字节 AS 号的上限,所以看起来像「越界」, 其实是「4 字节号刚好用满了两个 16 位的格子」。 但长度只是第一道筛子,BGP 后面还有一堆比较项(Local Preference、Origin、MED 等), 而且排在前面的几项都是「人定的偏好」而不是「算出来的优劣」。 这正是 7.2.3 说的「AS 之间不选最快,选最合适」。

30 秒实验

  1. 算一下:把 65536 拆成高 16 位和低 16 位,写出来是什么?
  2. 想一下:为什么 iBGP 学到的路由不再传给其他 iBGP 邻居?
  3. 想一下:20 台边界路由器,iBGP 全互联要建多少条会话?

常见误区

  1. 以为「BGP 和 OSPF 一样直接跑在 IP 上」。 它用 TCP 179,因为它的通告必须可靠。
  2. 以为「一个 AS 只有一条 iBGP 会话」。 要全互联,n 台就是 n 乘 (n 减 1) 除 2 条。
  3. 以为「AS 号是地址前缀」。 两者没有算术关系,查归属要查 BGP 表。
自测三问(点开对答案) 1. BGP 为什么用 TCP? —— **通告必须可靠**,而且 BGP 只在「已经能通」的邻居之间跑,不担心启动顺序。 2. eBGP 和 iBGP 的区别是什么? —— **两端是不是同一个 AS。** eBGP 跨 AS,iBGP 在 AS 内部。 3. asdot 的 64086.59904 对应哪个十进制 AS 号? —— **4200000000**,就是 64086 乘 65536 加 59904。

下一节看 BGP 怎么用「路径」防环。

相关笔记