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

BGP 传的不是距离,是「完整路径」——一串 AS 号。 路径里出现自己的 AS 号就丢掉,一轮就防住环。

📝 本节和前面几节的关系

7.6.1 讲了 BGP 的形态,这一节讲它为什么这么设计。 这是全章最后一种算法,和 7.3.1、7.3.2 合起来是「三种答法」。

一、第三种答法:记路径

距离向量记「多远」,链路状态记「地图」,BGP 记「怎么走」。 三者其实是「信息量」的三个档位:只够选路、够自己算、够判断「这条路绕不绕我」。 为什么 BGP 不能只记距离:AS 之间没有统一的度量。 一个 AS 内部的「1 跳」和另一个 AS 内部的「1 跳」,背后可能是完全不同的带宽和延迟。 所以「距离相加」在跨 AS 的尺度上没有意义——你没法把「电信的 1 跳」和「联通的 1 跳」加起来。 所以 BGP 只能退一步:「我不比快慢,我只记「经过谁」,然后按「经过几个 AS」来粗排」。 这就是「路径向量」这个名字的来由——它传递的是一个向量(一串 AS 号),不是标量(一个距离)。

二、防环:一句话就够

规则:收到的 AS_PATH 里如果出现自己的 AS 号,直接丢弃。 不需要等距离涨到无穷,一轮就发现。 为什么这条规则成立:因为 AS_PATH 记录的是「这个通告从哪儿来的完整历史」。 如果我收到一条「经过我」的通告,说明「这个通告是从我这儿出发, 绕了一圈又回到我这儿」——那它对我没有新信息。 这条规则和 7.4.4 的水平分割是同一个思路:「别把我告诉你的东西再告诉我」。 区别在于:水平分割靠「记住是从哪条线学的」,BGP 靠「路径里带着完整的历史」。 后者更强,因为它能防「绕过好几台再传回来」。 注意这条规则只在 eBGP 上严格生效: iBGP 不改 AS_PATH,所以 iBGP 之间的防环靠另外两个属性(Cluster ID 和 Originator ID)。 这是「同一种思想在不同尺度的两次实现」。

三、选路不是一个指标

BGP 选路是一串比较,不是一个公式。 以常见实现为例,顺序大致是:

序 比较项 性质
1 Weight 本机私有偏好
2 Local Preference 本 AS 统一偏好
3 本地始发 自己宣告的优先
4 AS_PATH 最短 第一项「客观」指标
5 Origin 路由来源的可信度
6 MED 建议邻居从哪进

注意 AS_PATH 只排第四——前面三条都是「人定的偏好」,不是「算出来的优劣」。 所以「BGP 选的路不是最快的」这句话是对的,而且这是设计使然,不是 bug。 运维可以靠 Local Preference 强行让流量走某条线,哪怕它更长。 第五行的 Origin 是个容易被忽略的字段: 它记录「这条路由是怎么进 BGP 的」—— i 表示「从 IGP 里重分发进来的」(最可信),e 表示「从 EGP 学的」, ? 表示「来源不明」(通常是重分发时没配好)。 看到一堆 ? 就要查重分发配置,因为「来源不明」的路由在选路时会排最后。

四、路径还能被人为拉长

AS_PATH 有一个很实用的用法:往里面重复塞自己的 AS 号。 这叫 AS path prepending。 效果是「让对方觉得这条路很长」——因为对方比的是长度,看到 5 个 AS 就换一条 3 个 AS 的走。 这是 BGP 里最常见的「软性引导」手法, 用来做「主备链路」或者「让我的一部分流量走 A 运营商」。 为什么叫「软性」: 因为它只是「建议」,对端可以不理——如果对端只有这一条路可选,再长也得走。 真正的「硬性」控制要靠 Local Preference(自己的出方向)和 MED(请求对方从哪边进), 但两者都只在「自己这一侧」有效。 这也说明了 BGP 的本质:它是一个「协商协议」,不是一个「计算协议」。 你能表达「我希望你这样走」,但不能命令。 所以跨 AS 的流量优化,永远是「影响」而不是「控制」—— 这也是为什么「跨运营商访问慢」这件事,单方面几乎解决不了。

五、动手 Demo:路径向量为什么不会计数到无穷

AS 100 收到四条去往同一个前缀的路由,看哪条被丢、为什么。 规则只有一句:路径里有自己就丢。

me = 100
paths = [
    ('200 300 400', [200, 300, 400]),
    ('500 100 600', [500, 100, 600]),
    ('700',         [700]),
    ('800 100',     [800, 100]),
]
for txt, p in paths:
    if me in p:
        print('%-14s 丢掉(路径里有 %d)' % (txt, me))
    else:
        print('%-14s 收下,长度 %d' % (txt, len(p)))

实跑输出:

--------------------------------------------------------------------
路径向量为什么不会计数到无穷
--------------------------------------------------------------------
**距离向量只记「多远」,路径向量记「怎么走」。**
**多记这一样东西,环路问题就没了。**

**假设 AS 100 收到四条去往同一个前缀的路由**:

  收到的 AS_PATH     长度     处理               原因
  ------------------------------------------------------------------------
  `200 300 400`      3        **收下**           **没绕回自己**
  `500 100 600`      3        **丢掉**           **路径里有 100,会绕圈**
  `700`              1        **收下,最优**     **最短**
  `800 100`          2        **丢掉**           **路径里有 100**

**规则就一句话:路径里出现自己的 AS 号,直接丢。**
**不需要等「距离涨到无穷」,一轮就发现。**
**这是路径向量比距离向量强的地方。**

**再看一个「距离对不上」的例子**:

  走法       AS_PATH                       长度     特点
  -----------------------------------------------------------------------
  路径 A     `65010 15169`                 2        **物理上绕但 AS 少**
  路径 B     `65020 65030 65040 15169`     4        **物理上近但 AS 多**

**BGP 会选路径 A**,**因为长度只有 2。**
**可路径 A 可能实际延迟更高**——**「经过的 AS 少」和「经过的线路短」是两件事。**
**所以「BGP 选的路不是最快的」这句话是对的,而且这是设计使然,不是 bug。**

**再补一点**:**AS_PATH 的长度还可以被人为拉长。**
**想让流量别走某条线,就重复写几遍自己的 AS 号(叫 AS path prepending)**,
**对方一看「这条路好长」,自然就换一条了。**
**这是 BGP 里最常见的「软性引导」手法。**

规则就一句话:路径里出现自己的 AS 号,直接丢。 不需要等「距离涨到无穷」,一轮就发现。 这是路径向量比距离向量强的地方。 再看一个「距离对不上」的例子: 路径 A 是「65010 15169」长度 2,路径 B 是「65020 65030 65040 15169」长度 4。 BGP 会选 A,因为长度只有 2。 可 A 可能实际延迟更高——「经过的 AS 少」和「经过的线路短」是两件事。 所以「BGP 选的路不是最快的」这句话是对的,而且这是设计使然。 再补一点:AS_PATH 的长度还可以被人为拉长。 想让流量别走某条线,就重复写几遍自己的 AS 号,对方一看「这条路好长」,自然就换一条了。 这是 BGP 里最常见的「软性引导」手法。

30 秒实验

  1. 想一下:为什么跨 AS 的「距离」不能直接相加?
  2. 想一下:BGP 防环和水平分割,哪个更彻底?为什么?
  3. 想一下:AS path prepending 为什么只是「建议」?

常见误区

  1. 以为「BGP 选最短 AS 路径就是选最快」。 长度不等于延迟, 而且前面还有三条人工偏好在它之前。
  2. 以为「BGP 能命令别的 AS 怎么走」。 它只能影响,对端可以不理。
  3. 以为「iBGP 也靠 AS_PATH 防环」。 iBGP 不改 AS_PATH,靠 Cluster ID 和 Originator ID。
自测三问(点开对答案) 1. BGP 靠什么防环? —— **AS_PATH 里出现自己的 AS 号就丢弃**,一轮就发现。 2. 为什么 BGP 不按「距离」选路? —— **AS 之间的度量不可比**,「电信的 1 跳」和「联通的 1 跳」加不起来。 3. AS path prepending 是什么? —— **往路径里重复塞自己的 AS 号,让对端觉得这条路长**,从而换一条。

下一节看 MPLS:一种「不看 IP 地址」的转发方式。

相关笔记