第157篇:PHP(次末跳弹出)机制
关键词:PHP、次末跳弹出、隐式空标签、显式空标签、Explicit Null、Implicit Null、标签弹出优化
一、引言
在标准的 MPLS 转发模型中,标签弹出(Pop)操作由 Egress LER(出口边缘路由器)执行。然而,这种设计意味着 Egress LER 需要对每到达的标签报文执行一次标签弹出操作,增加了出口节点的转发负担。PHP(Penultimate Hop Popping,次末跳弹出)机制通过让倒数第二跳提前弹出标签,将 Pop 操作从前向传播到中间节点,从而优化了整个 LSP 的转发效率。
二、核心概念
2.1 PHP 原理
PHP(Penultimate Hop Popping,次末跳弹出)的核心思想是:Egress LER 在 Label Mapping 报文中不为 FEC 分配具体的标签值,而是通告一个特殊的"空标签"(Null Label),通知上游邻居自己是该 FEC 的出口。上游收到空标签后,在倒数第二跳将标签弹出,将原始 IP 报文直接发送给 Egress LER。

2.2 MPLS 保留标签值
MPLS 定义了 0-15 的保留标签范围:
| 标签值 | 名称 | 用途 |
|---|---|---|
| 0 | Router Alert | 路由器告警标签,用于 OAM(如 LSP Ping) |
| 1 | IPv4 Explicit Null | IPv4 显式空标签,保留 EXP/TTL 信息 |
| 2 | IPv6 Explicit Null | IPv6 显式空标签 |
| 3 | Experimental | 实验保留,用于 EXP/QoS 优先级扩展 |
| 4-13 | 保留 | IANA 保留 |
| 14 | 保留 | IANA 保留 |
| 15 | Implicit Null | 隐式空标签(PHP 使用) |
2.3 三种空标签对比
| 标签类型 | 标签值 | 是否保留标签头 | 适用场景 |
|---|---|---|---|
| Implicit Null | 15 | 否(完全弹出标签) | PHP 默认使用,Egress 收到纯 IP 报文 |
| Explicit Null | 1(IPv4)/ 2(IPv6) | 是(保留标签头但不Swap) | 需要保留 EXP 位(QoS)、TTL 或 ECMP |

三、技术细节
3.1 PHP 工作过程

3.2 为什么需要 Explicit Null?
虽然 PHP 减少了 Egress LER 的标签操作,但在某些场景下,Egress LER 需要标签头中的信息:
| 场景 | 需要 Explicit Null 的原因 |
|---|---|
| QoS 标记保持 | 标签头中的 EXP 位携带 QoS 优先级,Pop 后丢失 |
| ECMP 负载均衡 | 末跳对多个下一跳执行 ECMP,需要标签头中的信息作为哈希输入 |
| TTL 传递 | 某些场景需要精确传递 IP TTL 值 |
| MPLS TE 隧道 | TE 隧道需要保留 EXP 位进行隧道优先级标记 |
3.3 PHP 与多层标签
在多层标签(Label Stack)场景中,PHP 行为更加复杂:
| 场景 | 外层标签行为 | 内层标签行为 |
|---|---|---|
| LDP 单层 | PHP 点 Pop 外层 | 无内层标签 |
| TE + LDP | TE 终点 Pop TE 标签 | 内层 LDP 标签暴露 |
| L3VPN | PE PHP 点 Pop VPN 标签 | 无(内层就是客户报文) |
| L2VPN over TE | TE 终点 Pop TE | PW 标签继续 Swap |
四、实战配置/案例分析
4.1 华为设备上 PHP 配置
# 华为设备默认启用 PHP,无需额外配置
# 验证 PHP 行为
# Step 1: 查看 LSP 状态,确认出标签类型
<NE40E> display mpls lsp verbose
NLRR: 10.1.1.5/32
INLBL: 1028, OURLBL: ImpNull
# ImpNull 表示出标签为隐式空标签(PHP生效)
# Step 2: 强制使用 Explicit Null(禁用PHP)
[NE40E] interface 10GE 1/0/1
[NE40E-10GE1/0/1] mpls static-label 1 ipv4-explicit-null 10.1.1.5 32
# Step 3: 验证 Explicit Null 效果
<NE40E> display mpls lsp verbose
NLRR: 10.1.1.5/32
INLBL: 1028, OURLBL: 1 (Explicit Null)
# 出标签为1 (Explicit Null), 标签头保留
4.2 查看 PHP 行为
# 在 Egress LER 查看本地标签
<Egress> display mpls ldp local-fec
FEC: 10.1.1.4/32
Local Label: 3 (Implicit Null for PHP)
# Egress 为直连 FEC 分配的标签为 Implicit Null
# 在上游查看 LSP 详细信息
<Upstream> display mpls lsp 10.1.1.4 32 verbose
NLRR: 10.1.1.4/32
INLBL: 1027, OURLBL: ImpNull
OUTIF: 10GE1/0/1
# 出标签为 ImpNull,确认 PHP 生效
# 抓包验证
<Upstream> packet-capture interface 10GE 1/0/1
# 在 PHP 点的出接口抓包,应看到纯 IP 报文(无 MPLS 标签头)
4.3 故障排查:PHP 导致 EXP 丢失
故障场景:某 L3VPN 网络的 CE 侧接口收到的报文 DSCP 标记全部为 0,导致 QoS 策略失效。
# Step 1: 在 PE 入接口检查入站报文 EXP/DSCP
<PE1> packet-capture interface GE 1/0/0
# 入站报文 DSCP=46 (EF), 正常
# Step 2: 在 P 设备检查 MPLS EXP
<P> packet-capture interface 10GE 1/0/1
# MPLS EXP=6, 映射正常
# Step 3: 在对端 PE 出接口检查
<PE2> display mpls lsp verbose
# 出标签为 ImpNull, PHP点在P设备已弹出标签
# Step 4: 分析根因
# PHP点在P设备弹出标签时, EXP位随标签头一起丢弃
# PE2收到的是纯IP报文, DSCP需要重新从IP头部读取
# 但IP头部的DSCP在入站时未被正确复制
# Step 5: 解决方案
# 方案A: 使用Explicit Null保留EXP位
[PE2] interface 10GE 1/0/1
[PE2-10GE1/0/1] mpls static-label 1 ipv4-explicit-null 10.x.x.x 32
# 方案B: 配置EXP到DSCP的映射
[PE2] qos
[PE2-qos] exp-table 1 dscp 0 1 2 3 4 5 6 7
[PE2] interface GE 1/0/1
[PE2-GigabitEthernet1/0/1] qoss exp-dscp 1
四(续)、高级主题
4.4 PHP 与 QoS 标记保持方案对比
| 方案 | 实现方式 | 开销 | 适用场景 |
|---|---|---|---|
| 方案 A:禁用 PHP | 使用 Explicit Null(标签值=1) | 增加 Egress Pop 操作 | QoS 标记必须保留的场景 |
| 方案 B:EXP→DSCP 映射 | PHP 点后在 Egress 重新映射 | 需配置映射表 | 大多数 QoS 场景 |
| 方案 C:IP DSCP 透传 | Ingress PE 复制 EXP 到 IP DSCP | 无需额外配置 | 端到端 DSCP 标记场景 |
# 方案A: 禁用PHP(使用Explicit Null)
[Egress-PE] interface 10GE 1/0/1
[Egress-PE-10GE1/0/1] mpls static-label 1 ipv4-explicit-null 10.1.1.1 32
# 1 = IPv4 Explicit Null
# 次末跳不弹出标签,Egress执行Pop
# 方案C: 配置IP DSCP透传(入口PE)
[Ingress-PE] qos
[Ingress-PE-qos] dscp-table 1
[Ingress-PE-qos-table-1] mpls-exp 0 dscp 0
[Ingress-PE-qos-table-1] mpls-exp 1 dscp 1
[Ingress-PE-qos-table-1] mpls-exp 2 dscp 2
[Ingress-PE-qos-table-1] mpls-exp 3 dscp 3
[Ingress-PE-qos-table-1] mpls-exp 4 dscp 4
[Ingress-PE-qos-table-1] mpls-exp 5 dscp 5
[Ingress-PE-qos-table-1] mpls-exp 6 dscp 6
[Ingress-PE-qos-table-1] mpls-exp 7 dscp 7
4.5 多层标签场景下的 PHP 行为
| 场景 | 标签结构 | PHP 发生位置 | 说明 |
|---|---|---|---|
| LDP 单层 | [Label] | 次末跳 | 标准 PHP |
| L3VPN 双层 | [Outer-LDP][Inner-VPN] | PE(对Inner标签) | PE对CE弹出VPN标签 |
| TE+LDP 双层 | [TE-Label][LDP-Label] | TE终点 | TE终点弹出TE标签 |
| L2VPN over TE | [TE-Label][PW-Label] | TE终点 | TE终点弹出TE,PW继续 |
| SR-MPLS | [End SID][PHP SID] | 倒数第二跳 | 类似LDP PHP |
# L3VPN双层标签PHP验证
<PE2> display mpls lsp vpn verbose
NLRR: 10.1.2.1:100:10.1.2.0/24
Inner Label: 16015 (from PE1, VPN标签)
Outer Label: 1025 (LDP到PE1)
# PE2对PE1发送的是双层标签
# P设备对Outer标签执行Swap
# PE1(入口PE)对Inner标签执行Pop(PHP)
# TE+LDP双层标签PHP验证
<P-TE> display mpls te tunnel-interface interface Tunnel 1 verbose
TE Label: 16020 (TE终点弹出)
Inner LDP Label: 16015 (继续Swap)
# TE终点(P-TE)弹出TE标签后, 暴露LDP标签继续转发
4.6 PHP 行为验证 Checklist
| 检查项 | 命令 | 预期结果 |
|---|---|---|
| PHP 生效确认 | display mpls lsp verbose \| include ImpNull |
出标签为 ImpNull |
| Explicit Null 确认 | display mpls lsp verbose \| include "OURLBL: 1" |
出标签为 1 |
| 抓包验证 | packet-capture interface <PHP点的出接口> |
PHP 点后无 MPLS 头 |
| Egress 收包 | packet-capture interface <Egress入接口> |
Egress 收到纯 IP 报文 |
| EXP 值检查 | 抓包分析 MPLS EXP 字段 | 按 QoS 策略正确标记 |
五、总结
| 项目 | 要点 |
|---|---|
| PHP 目的 | 减少 Egress LER 的标签 Pop 操作,优化转发效率 |
| Implicit Null (15) | 次末跳完全弹出标签,Egress 收到纯 IP 报文(默认) |
| Explicit Null (1/4) | 次末跳替换为空标签头,保留 EXP/TTL 信息 |
| PHP 配置 | 华为默认启用,特殊场景可强制使用 Explicit Null |
| 注意事项 | PHP 可能导致 EXP/DSCP 丢失,需配合 QoS 映射策略 |
思考
- PHP 机制下,如果次末跳路由器出现异常(如 LFIB 条目丢失),标签如何处理?流量是否会中断?
- 在 ECMP 场景中,为什么 Explicit Null 比 Implicit Null 更适合?标签头中的哪些字段参与了 ECMP 哈希计算?
- 多层标签场景下(如 TE+L3VPN),PHP 发生在哪一层标签上?内层标签的 PHP 如何处理?
下篇预告:第158篇:MPLS 流量工程基础:RSVP-TE