第156篇:MPLS 转发过程——标签压入、交换、弹出

关键词

MPLS 转发、标签压入(Push)、标签交换(Swap)、标签弹出(Pop)、标签栈、LFIB、ILM


一、MPLS 数据面与转发模型

前几篇我们了解了 LDP 如何分发标签,本文从数据面的角度,完整追踪一个 IP 包在 MPLS 域中的转发过程。

1.1 关键概念:标签栈(Label Stack)

MPLS 支持多层标签,最多可嵌套数层。每一层标签是一个 4 字节的条目:

IP 数据包(不带标签)
┌─────────────────┐
│     IP 报文      │
└─────────────────┘

单层标签(MPLS 基本转发)
Label IP 报文
双层标签(MPLS VPN 等场景)
Lable2 Label1 IP 报文 ← Label1 是栈底(S=1)
  • S 位标识栈底(1 = 最后一层标签)
  • 标签栈可以嵌套,用于:外层(隧道标签)+ 内层(VPN 标签)

二、三种标签操作全解析

2.1 Push(压入)

操作:在标签栈顶部添加一个新标签。

操作前: ┌─────────────────────┐ │ IP 报文 │ └─────────────────────┘

PUSH Label = 100: | Label 100 | IP 报文 | ← S=1(栈底) | | --- | --- | --- |

执行位置Ingress LSR(数据包进入 MPLS 域时)

R1(普通 IP)→ R2(Ingress LSR):检查路由 → "目标匹配 MPLS 转发"
→ 查找 LFIB → push 标签 300 → 发送到 R3

2.2 Swap(交换)

操作:用新标签替换栈顶标签,栈的深度不变。

操作前: | Label 300 | IP 报文 | ← S=1 | | --- | --- | --- |

SWAP Label 300 → Label 200: | Label 200 | IP 报文 | ← S=1 | | --- | --- | --- |

执行位置Transit LSR(中间节点)

R3(Transit LSR):
  收到标签 300 → 查 LFIB → 出标签 200
  → 交换(300 → 200)→ 发送到 R4

2.3 Pop(弹出)

操作:移除栈顶标签。如果是栈底标签(S=1),弹出后恢复为 IP 包。

操作前: | Label 200 | IP 报文 | ← S=1 | | --- | --- | --- |

POP: ┌─────────────────────┐ │ IP 报文 │ └─────────────────────┘

执行位置Egress LSR(数据包离开 MPLS 域时)

R4(Egress LSR):
  收到标签 200 → 查 LFIB → 操作为 Pop
  → 弹出标签 → 恢复 IP 包 → 普通 IP 转发

三、完整转发过程(逐跳详解)

3.1 场景设定

网络拓扑: R1 ── R2 ── R3 ── R4 │ 10.0.0.0/24

路由及标签信息:

节点 LFIB 条目 R1 路由:10.0.0.0/24 via R2(下一跳) 无 MPLS 标签(普通 IP 转发) R2 入标签:- 出标签:200 下一跳:R3 (Ingress) R3 入标签:200 出标签:100 下一跳:R4 (Transit) R4 入标签:100 出标签:- 弹出标签 (Egress)

3.2 转发过程

步骤 1:R1 发送 IP 包
  R1 ───────────── IP(src=192.168.1.1, dst=10.0.0.1)──────────▶ R2
  R1 不知道 MPLS,只做普通 IP 路由

步骤 2:R2(Ingress)压入标签
  R2 收到 IP 包
    ① IP 路由查找 → 匹配 10.0.0.0/24,下一跳为 R3
    ② 发现该 FEC 有 MPLS 标签绑定
    ③ 查 LFIB:入标签=none,出标签=200,下一跳=R3
    ④ 执行 Push:压入标签 200
    ⑤ 沿链路转发

  R2 ─────── MPLS(Label=200)───────▶ R3

步骤 3:R3(Transit)交换标签
  R3 收到带标签 200 的包
    ① 查 LFIB:入标签=200 → 出标签=100,下一跳=R4
    ② 执行 Swap:把标签 200 换成 100
    ③ 沿链路转发

  R3 ─────── MPLS(Label=100)───────▶ R4

步骤 4:R4(Egress)弹出标签
  R4 收到带标签 100 的包
    ① 查 LFIB:入标签=100 → 操作=Pop
    ② 执行 Pop:移除标签
    ③ 恢复为普通 IP 包
    ④ 查 IP 路由表 → 匹配 10.0.0.0/24 → 从出接口转发

  R4 ───────────── IP(src=192.168.1.1, dst=10.0.0.1)──────────▶ 目标网络

四、ILM(Incoming Label Map)和 NHLFE(Next Hop Label Forwarding Entry)

4.1 ILM 和 NHLFE 的关系

MPLS 转发依赖于两个重要的数据结构:

              ILM                                NHLFE
入标签 → NHLFE 指针 ───────────────────── In-Label NHLFE Index 200 1 300 2 500 3 ───────▶ └─────────────────────────┘ • 出标签 • 出接口 • 下一跳 • 操作(Swap/Pop/Push) • 标签栈操作
组件 作用 查找方式
ILM 入标签到 NHLFE 的映射表 收到标签后查 ILM
NHLFE 定义了对标签的详细操作 ILM 返回 NHLFE 指针后执行

4.2 完整的标签查找流程

收到带标签的分组
       │
       ▼
提取入标签(栈顶)
       │
       ▼
查 ILM
       │
       ▼
获取 NHLFE 条目:操作(Swap/Pop)、出标签、出接口、下一跳
       │
       ▼
执行标签操作
       │
       ▼
封装新的 MAC 头部 → 发送

五、隐式空标签(Implicit NULL)与 PHP

隐式空标签(Implicit NULL,标签值 = 3)是 PHP(Penultimate Hop Popping)机制的核心,详见第157篇。这里只简述在转发中的作用:

没有 PHP 的转发(Egress 承担额外负载):
  R2(push 200)→ R3(swap 100)→ R4(pop 100 + IP 转发)

有 PHP 的转发(Egress 只做 IP 转发):
  R2(push 200)→ R3(pop → 裸 IP)→ R4(仅 IP 转发)

PHP 让 Egress LSR 免于做标签查找,直接做 IP 转发,降低了 Egress 的负担。


六、双层标签转发(VPN 场景预览)

在 MPLS VPN(L3VPN)中,通常使用两层标签

外层标签(隧道标签) 内层标签(VPN 标签) ↓ ↓ | LDP标签 (L2→L3) | VPN标签 (L3→L4) | IP 报文 | | --- | --- | --- | S=0 S=1

转发过程:

PE1(Ingress):
  push VPN 标签(内层)
  push LDP 标签(外层)
  → P 节点

P(Transit):
  只交换外层标签(LDP)
  不看内层 VPN 标签 → 透明传输

PE2(Egress):
  PHP 弹出外层标签 → 看到内层 VPN 标签
  根据 VPN 标签找到对应 VRF → 解封装 IP → IP 转发到 CE

七、MPLS 转发 vs IP 转发对比

对比项 IP 转发 MPLS 转发
查找内容 目的 IP 地址(32 位,前缀匹配) 标签(20 位,精确匹配)
查找表 路由表(RIB)+ FIB ILM + NHLFE
查找方式 最长匹配(LPM) 精确匹配
每跳查表 是(查的是标签表)
路由决策 每跳独立 在 Ingress 一次性确定整条路径
支持多路径 ECMP(基于 IP) ECMP(基于标签)

八、总结

知识点 核心要点
Push Ingress LSR 在标签栈顶部添加新标签
Swap Transit LSR 用新标签替换栈顶标签
Pop Egress LSR 移除栈顶标签,恢复为 IP 包
ILM 入标签到 NHLFE 的映射(入口查表)
NHLFE 定义出标签、出接口、操作类型
标签栈 支持多层标签嵌套,S 位标识栈底
双层转发 外层 LDP 标签 + 内层 VPN 标签,用于 MPLS VPN

九、思考

  1. MPLS 域中有哪三种标签操作?分别由哪类 LSR 执行?
  2. 什么是 ILM?什么是 NHLFE?两者之间的关系是什么?
  3. 在两层标签的转发过程中,Transit LSR 对内层标签做什么操作?
  4. 为什么 Egress LSR 不需要做标签查找(PHP 之后)?
  5. MPLS 标签查找和 IP 路由查找的根本区别是什么?

下篇预告:第157篇《PHP(次末跳弹出)机制》——为什么 MPLS 需要在次末跳就弹出标签?Implicit NULL 和 Explicit NULL 有什么区别?