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

MPLS 在 IP 头前面插一个 32 位的标签,路由器只看标签转发。 入口打上、中间换、出口剥掉,这条路径叫 LSP。

📝 本节和前面几节的关系

7.6 讲完了「怎么算出路由」,这一节换一个维度:转发时看什么。 MPLS 不改路由协议,它改的是「拿到路由之后,怎么把包发出去」。

一、标签只有 32 位,四个字段

MPLS 的「标签」是一块 4 字节的头部,插在二层头和 IP 头之间。它的四个字段分工很明确:

字段 位数 作用
标签值 20 决定下一跳怎么转发
EXP 3 优先级,后来改名叫 TC
S 1 栈底标记,1 表示最后一层
TTL 8 和 IP 的 TTL 一个用途,防环

标签值占 20 位,所以标签空间是 2 的 20 次方,约 104 万个。 这个数字是「每台设备本地有效」的,不是全球唯一—— 同一台设备的同一个标签,只能对应一条转发规则。 S 位只有 1 位,但它是「栈」这个设计的枢纽。 它告诉设备「下面还有没有标签」,所以设备可以「只看最外层」而不必关心里面有几层。 这就是 MPLS 能把「运营商」和「客户」分开的技术基础。

二、三种动作:push、swap、pop

一个包穿过 MPLS 网络,标签会被改好几次,但动作只有三种:

动作 在哪儿做 干什么
push 入口 LER 打上一个标签
swap 中间 LSR 换成本机的出标签
pop 出口 LER 剥掉标签,恢复纯 IP 包

入口和出口叫 LER(标签边缘路由器),中间叫 LSR(标签交换路由器)。 整条路径叫 LSP(标签交换路径)。 这三个缩写要记住,因为排错时说的就是它们。 为什么中间要「换」而不是「一直用同一个号」: 因为标签是「本地有效」的—— 每台设备自己分配自己的号,只保证「进来的包用这个号,从那个口出去」。 所以同一条路径上,每一跳的号都可以不一样。 这个设计让标签分配变成了「各管各的」,不需要全局协调。

三、为什么要有标签栈

一层标签就够转发了,为什么还要「栈」: 因为一层标签只能表达「去哪儿」,表达不了「这是谁的流量」。 两层标签正好把这两件事分开:外层决定「送到哪个站点」,内层决定「送到站点里的哪个网段」。 这个分工带来了 MPLS VPN 的核心能力:中间的运营商路由器只换外层,内层原封不动地传过去。 所以运营商不需要知道客户的内部结构——它只知道「这个包属于客户 A,要送到站点 B」。 客户的地址空间可以重叠(两家客户都用 10.0.0.0/8),因为外层标签把它们区分开了。 注意「只换外层」这件事的实现方式:外层 swap、内层不动,所以栈的深度不变。 只有到了出口,两个标签才一起 pop。 这也解释了 S 位的作用——没有 S 位,设备就不知道「剥掉这一层之后,下面那层是不是还要用」。

四、标签是怎么发下来的

标签不是人配的,是协议分的。 有两种常见的分发方式:一种是跟着路由协议走(LDP),一种是用 BGP 扩展(BGP 加标签)。 LDP 的思路很直白:「我有一条路由,我就给它分一个标签,然后告诉邻居」。 所以 LSP 是跟着路由表自动长出来的——路由变了,标签也跟着变。 这也意味着「MPLS 域内的转发路径和 IP 路由是同一棵树」, 所以单靠 LDP 做不到「让某条流量走另一条路」。 要「指定路径」就得用 RSVP-TE 或 SR:它们能显式指定一条 LSP 经过哪些节点, 这才是 MPLS 做流量工程的入口。 所以「MPLS 能管流量」这句话,严格说应该是「MPLS 加流量工程信令才能管流量」。

五、动手 Demo:MPLS 的标签是怎么换的

看一个包从 R1 到 R4 的过程中,标签栈怎么变。 重点在「每台的号都不一样」这一点。

hops = [
    ('R1 入口 LER', None, 100, 'push'),
    ('R2 核心 LSR', 100, 200, 'swap'),
    ('R3 核心 LSR', 200, 300, 'swap'),
    ('R4 出口 LER', 300, None, 'pop'),
]
for name, inl, outl, act in hops:
    print('%-14s %-6s -> %-6s  %s'
          % (name, inl or '—', outl or '—', act))

print('标签空间 2**20 =', 2 ** 20)

实跑输出:

--------------------------------------------------------------------
MPLS 的标签是怎么换的
--------------------------------------------------------------------
**MPLS 在 IP 头前面插一个 32 位的「标签」**,**路由器只看标签转发,不看 IP 地址。**
**一个包穿过网络时,标签会被换好几次。**

**标签本身占 20 位,所以标签空间是 2 的 20 次方,等于 1,048,576 个。**

  字段         位数          作用
  ------------------------------------------------------------
  标签值       20 位         决定下一跳怎么转发
  EXP          3 位          优先级(后来改叫 TC,给 QoS 用)
  S            1 位          栈底标记,1 表示这是最后一个标签
  TTL          8 位          和 IP 的 TTL 一个用途,防环
  **合计**     **32 位**     **正好 4 字节**

**下面跟着一个包走一遍**:**路径是 R1 → R2 → R3 → R4,R4 后面是目标网段。**

  节点               标签栈变化      动作
  -----------------------------------------------------------------
  R1(入口 LER)     `— → 100`       **push**:打上标签 100
  R2(核心 LSR)     `100 → 200`     **swap**:换成 200
  R3(核心 LSR)     `200 → 300`     **swap**:换成 300
  R4(出口 LER)     `300 → —`       **pop**:剥掉,恢复成纯 IP 包

**入口和出口叫 LER**(标签边缘路由器),**中间叫 LSR**(标签交换路由器)。
**入口负责「打上」,中间负责「换」,出口负责「剥掉」。**
**整条路径叫 LSP**(标签交换路径)。

**标签栈可以有多层**,这就是「栈」这个名字的来源:

  层           示例值     谁看它
  -----------------------------------------------------
  外层标签     `5000`     **决定「这个包去哪个用户」**
  内层标签     `120`      **决定「在用户网里怎么走」**

**两层标签正是 MPLS VPN 的实现方式**:**外层管「送到哪个站点」,内层管「送到站点里的哪个网段」。**
**中间的运营商路由器只换外层,内层原封不动地传过去**——**所以运营商不需要知道客户的内部结构。**
**这个「外层可见、内层不可见」的分工,是 MPLS 最值钱的地方。**

入口和出口叫 LER(标签边缘路由器),中间叫 LSR(标签交换路由器)。 入口负责「打上」,中间负责「换」,出口负责「剥掉」。 整条路径叫 LSP(标签交换路径)。 注意「100 到 200 到 300」不是约定,是各自分配的结果—— R2 用的是「本机分给这条 LSP 的号」,R3 也用自己的一套。 所以抓包看到的标签值,只有「同一台设备的入和出」这一对是有意义的。 拿两台设备的标签号去比大小,是没有意义的。 pop 有两种做法: 一种是「倒数第二跳弹出」(PHP)——出口的前一跳就把标签剥掉,出口只做纯 IP 转发。 另一种是出口自己剥。 PHP 更常用,因为它让出口设备「不需要维护标签表」,代价是「出口看不到标签,只能看 IP 头」。

30 秒实验

  1. 算一下:20 位标签空间有多大?
  2. 想一下:为什么每台设备的标签号可以不一样?
  3. 想一下:两层标签分别解决什么问题?

常见误区

  1. 以为「标签是全局唯一的」。 只在本机有效,每一跳都可以换号。
  2. 以为「MPLS 改了路由协议」。 它不改路由,改的是「拿到路由之后怎么转发」。
  3. 以为「配了 LDP 就能做流量工程」。 LDP 跟着路由走,要指定路径得用 RSVP-TE 或 SR。
自测三问(点开对答案) 1. 标签的四个字段是什么? —— **20 位标签值、3 位 EXP、1 位 S、8 位 TTL。** 2. 三种动作分别在哪做? —— **push 在入口 LER、swap 在中间 LSR、pop 在出口 LER。** 3. 为什么需要标签栈? —— **一层只能表达「去哪儿」**,两层才能同时表达「哪个客户」和「哪个网段」。

下一节看 MPLS 到底解决了什么问题。

相关笔记