跳到主要内容

RFC 4379 - 4. Theory of Operation

4. 操作理论 (Theory of Operation)​

MPLS echo request 用于测试特定的 LSP. 被测 LSP 由 "FEC 栈" 标识; 例如, 若 LSP 经 LDP 建立且到出口 IP 地址 10.1.1.1, 则 FEC 栈包含单个元素, 即值为 10.1.1.1/32 的 LDP IPv4 前缀子 TLV. 若被测 LSP 为 RSVP LSP, FEC 栈由唯一标识该 LSP 的 RSVP 会话与发送方模板的单个元素组成.

FEC 栈可以更复杂. 例如, 可能要测试经出口 10.10.1.1 的 LDP LSP 隧道的 VPN IPv4 前缀 10.1/8. 则 FEC 栈含两个子 TLV, 底部为 VPN IPv4 前缀, 顶部为 LDP IPv4 前缀. 若底层 (LDP) 隧道未知或认为无关, FEC 栈可仅为含 VPN IPv4 子 TLV 的单个元素.

当收到 MPLS echo request 时, 期望接收方验证控制平面与数据平面均健康 (对正在 ping 的 FEC 栈), 且两平面同步. 程序见第 4.4 节.

4.1. 处理等价多路径 (ECMP) (Dealing with Equal-Cost Multi-Path)​

LSP 不必是简单的点对点隧道. 单个 LSP 常始于多个入端终于多个出端 (LDP LSP 中很常见). 给定 FEC 的 LSP 在 transit LSR 处也可能有多个 "下一跳". 在入端, 也可能有多个不同 LSP 可选以到达期望端点. 最后, LSP 可能有备份路径, 绕行路径及其他替代路径.

后两者先处理: 假定发起 MPLS echo request 的 LSR 能将 echo request 强制进入任意期望 LSP, 因此在入端选择多个 LSP 不成问题. 探测各种备份路径 (通常主 LSP 宕机前不用于转发数据) 的问题此处不讨论.

由于给定分组实际采用的 LSP 与路径可能事先未知, 若 MPLS echo request 能遍历所有可能路径则有益. 但这虽理想, 或因各 LSR 用于在不同路径上分配分组的算法可能是专有的而不切实际.

为在一定程度上覆盖替代路径, 选择 MPLS echo request 的目的地 IP 地址与源 UDP 端口有一定自由度. 这显然不够; 在 traceroute 情况下, 下游映射 TLV 的多路径信息提供了更多自由度. 用法如下: 入端 LSR 周期性发送 MPLS traceroute 消息以确定给定 LSP 是否存在多路径. 若有, 每一跳将提供如何驱动其各下游路径的信息. 入端随后可发送遍历这些路径的 MPLS echo request. 若多个 transit LSR 有 ECMP, 入端 MAY 尝试组合它们以遍历所有可能路径. 但完整覆盖可能不可行.

4.2. 测试用于承载 MPLS 载荷的 LSP (Testing LSPs That Are Used to Carry MPLS Payloads)​

为检测某些 LSP 中断, 测试用于承载 MPLS 载荷 (如承载 L2VPN 与 L3VPN 流量的 LSP) 的 LSP 时, MAY 需要以至少一个额外标签封装 MPLS echo request. 例如, 测试 LDP 或 RSVP-TE LSP 时, 仅发送 MPLS echo request 可能无法检测到: LSP ping 目的地紧邻上游的路由器因使用倒数第二跳弹出 (penultimate hop popping) 而经未配置承载 MPLS 载荷的接口成功转发了 MPLS echo request. 由于接收路由器无法区分 IP 分组是无标签发送还是隐式标签发送, 在 MPLS echo request 之上用 Nil FEC 垫片标签 (shim) 可防止路由器经未标签接口转发此类分组.

4.3. 发送 MPLS Echo Request (Sending an MPLS Echo Request)​

MPLS echo request 是 UDP 分组. IP 首部设置如下: 源 IP 地址为发送方可路由地址; 目的 IP 地址为取自 127/8 范围 (IPv4) 或 0:0:0:0:0:FFFF:127/104 范围 (IPv6) 的 (随机选取的) 地址. IP TTL 设为 1. 源 UDP 端口由发送方选择; 目的 UDP 端口设为 3503 (IANA 为 MPLS echo request 分配). IP 首部 MUST 设置 Router Alert 选项.

MPLS echo request 以对应于被测 FEC 栈的标签栈发送. 注意若 (例如) 到栈顶 FEC 的正常路由经流量工程隧道 [RSVP-TE], 可应用进一步标签. 若栈中所有 FEC 均对应 Implicit Null 标签, 即使发送时会应用进一步标签, MPLS echo request 仍视为无标签.

若 echo request 有标签, 可 (取决于所 ping 对象) 将最内层标签的 TTL 设为 1, 以防止 ping 请求走得过远. 应这样做的例子包括 ping VPN IPv4 或 IPv6 前缀, L2 VPN 端点或伪线. 防止 ping 请求走得过远也可通过在标签上插入 Router Alert 标签实现; 但这可能导致 MPLS echo request 走与实际数据不同的数据路径的不良副作用. 关于这些机制如何用于伪线连通性验证, 见 [VCCV].

在 "ping" 模式 (端到端连通性检查) 下, 最外层标签的 TTL 设为 255. 在 "traceroute" 模式 (故障隔离模式) 下, TTL 依次设为 1, 2, 依此类推.

发送方选择 Sender's Handle 与 Sequence Number. 发送后续 MPLS echo request 时, SHOULD 将 Sequence Number 加 1. 但发送方 MAY 选择发送一组具有相同 Sequence Number 的 echo request, 以提高至少含该 Sequence Number 的一个分组到达的机会.

TimeStamp Sent 设为 echo request 发送的时间 (秒与微秒). TimeStamp Received 设为零.

MPLS echo request MUST 有 FEC 栈 TLV. 此外, 回复模式 MUST 设为期望的回复模式; 返回码与子码设为零. 在 "traceroute" 模式下, echo request SHOULD 包含下游映射 TLV.

4.4. 接收 MPLS Echo Request (Receiving an MPLS Echo Request)​

将 MPLS echo request 送往控制平面由一个以下分组处理异常触发: Router Alert 选项, IP TTL 过期, MPLS TTL 过期, MPLS Router Alert 标签, 或 127/8 地址范围内的目的地址. 控制平面进一步通过 UDP 目的端口 3503 识别它.

为报告目的, 栈底视为栈深 1. 这是为实际栈可能含比 Target FEC 栈中 FEC 更多标签的情况建立绝对参考.

此外, 本文档所列所有错误码中, 栈深 0 表示 "未指定值", 以便与不使用返回子码字段的现有实现兼容.

收到 MPLS echo request 的 LSR X 按下处理:

  1. 验证分组总体合法性. 若分组格式不良, LSR X SHOULD 发送返回码为 "Malformed echo request received", 子码为 0 的 MPLS Echo Reply. 若有任何未标记为 "Ignore" 且 LSR X 不理解的 TLV, LSR X SHOULD 发送适当的 MPLS "TLV not understood", 子码为 0; 后者情况下, 仅在应答的 Errored TLVs TLV 中将这些未被理解的 TLV 作为子 TLV 包含. 头字段 Sender's Handle, Sequence Number 与 Timestamp Sent 不被检查, 但包含在 MPLS echo reply 消息中.

算法使用以下变量与标识符:

  • Interface-I: 收到 MPLS echo request 的接口.
  • Stack-R: 分组收到时的标签栈.
  • Stack-D: 下游映射 TLV 中携带的标签栈 (不一定存在).
  • Label-L: 当前正在检查的来自实际栈的标签. 无需初始化.
  • Label-stack-depth: 正在验证的标签深度. 初始化为收到标签栈 S 中的标签数.
  • FEC-stack-depth: 应用于验证当前实际标签的 Target FEC 栈中 FEC 的深度. 无需初始化.
  • Best-return-code: 含当前已知最佳的 echo reply 返回码. 随算法推进, 此码可能因进一步检查而改变.
  • Best-rtn-subcode: 类似 Best-return-code, 但用于 Echo Reply 子码.
  • FEC-status: 第 4.4.1 节 FEC 检查算法返回的结果值.
  1. 若 echo request 良好, LSR X 将收到 echo 的接口存入 Interface-I, 收到时的标签栈存入 Stack-R.

  2. 标签验证 (Label Validation):

    若 Label-stack-depth 为 0: 设置 FEC-stack-depth 为 1, Label-L 为 3 (Implicit Null); 设置 Best-return-code 为 3 ("Replying router is an egress for the FEC at stack depth"), Best-rtn-subcode 为 FEC-stack-depth 值 (1), 转步骤 5 (Egress Processing).

    否则, 从 Stack-R 的 Label-stack-depth 深度提取 Label-L, 在入标签映射 (ILM) 中查找以确定标签是否已分配且关联某操作. 若无 L 的条目: 设置 Best-return-code 为 11 ("No label entry at stack-depth"), Best-rtn-subcode 为 Label-stack-depth, 转步骤 7 (Send Reply Packet). 否则, 从对应 NLFE 取回关联标签操作, 转步骤 4.

  3. 标签操作检查 (Label Operation Check):

    若标签操作为 "Pop and Continue Processing" (含 Explicit Null 与 Router Alert 标签): 递减 Label-stack-depth 迭代到下一标签, 回到步骤 3.

    若标签操作为 "Swap or Pop and Switch based on Popped Label": 设置 Best-return-code 为 8 ("Label switched at stack-depth"), Best-rtn-subcode 为 Label-stack-depth 以报告 transit 交换. 若收到的 echo request 含下游映射 TLV: 若 TLV 中 IP 地址为 127.0.0.1 或 0::1, 设置 Best-return-code 为 6 ("Upstream Interface Index Unknown"), 应答中 SHOULD 包含 Interface and Label Stack TLV, 填入 Interface-I 与 Stack-R. 否则, 验证下游映射 TLV 中 IP 地址, 接口地址与标签栈匹配 Interface-I 与 Stack-R; 若不匹配, 设置 Best-return-code 为 5 ("Downstream Mapping Mismatch"), 应答中 SHOULD 包含 Interface and Label Stack TLV, 基于 Interface-I 与 Stack-R 填入, 转步骤 7. 对每个可用下游 ECMP 路径: 从 NHLFE 条目取回输出接口; 若输出接口未启用 MPLS, 设置 Best-return-code 为 9 ("Label switched but no MPLS forwarding at stack-depth"), Best-rtn-subcode 为 Label-stack-depth, 转 Send_Reply_Packet. 若含下游映射 TLV, 应答中 SHOULD 包含填入当前 ECMP 路径信息的下游映射 TLV. 若无下游映射 TLV, 或下游 IP 地址设为 ALLROUTERS 组播地址, 转步骤 7. 若 "Validate FEC Stack" 标志未置且 LSR 未配置默认执行 FEC 检查, 转步骤 7.

    确定 FEC-stack-depth: 从下游映射 TLV 的 Stack-D 自底向上遍历, 每遇非 Implicit Null 标签递减标签数, 同时每遇标签递增 FEC-stack-depth; 若含一个或多个 Implicit Null 标签, FEC-stack-depth 可能大于 Label-stack-depth. 设 FEC-stack-depth 为 0, i 为 Label-stack-depth; 当 i>0: ++FEC-stack-depth; 若 Stack-D[FEC-stack-depth]!=3 (Implicit Null) 则 --i. 若 FEC 栈中标签数 >= FEC-stack-depth, 执行 4.4.1 节 FEC 检查过程; 若 FEC-status 为 2, 设置 Best-return-code 为 10; 若返回码为 1, 设置 Best-return-code 为 FEC-return-code, Best-rtn-subcode 为 FEC-stack-depth. 转步骤 7.

  4. 出口处理 (Egress Processing): 若收到的 echo request 不含下游映射 TLV, 或下游 IP 地址为 127.0.0.1 或 0::1, 转步骤 6 (Egress FEC Validation). 验证下游映射 TLV 中 IP 地址, 接口地址与标签栈匹配 Interface-I 与 Stack-R; 若不匹配, 设置 Best-return-code 为 5, 应答中 SHOULD 创建 Received Interface and Label Stack TLV, 转步骤 7.

  5. 出口 FEC 验证 (Egress FEC Validation): 对从 FEC-stack-depth 开始的 Target FEC 栈所有条目循环. 按 4.4.1 节算法对 Label-L 与 FEC-stack-depth 处的 FEC 执行 FEC 检查; 设置 Best-return-code 为 FEC-code, Best-rtn-subcode 为 FEC-stack-depth 值. 若 FEC-status 为 1, 转步骤 7. ++FEC-stack-depth; 若 FEC-stack-depth > FEC 栈中 FEC 数, 转步骤 7. 若 FEC-status 为 0: ++Label-stack-depth; 若 Label-stack-depth > Stack-R 中标签数, 转步骤 7; Label-L = 从 Stack-R 的 Label-stack-depth 深度提取的标签; 回到步骤 6.

  6. 发送应答分组 (Send Reply Packet): 发送返回码为 Best-return-code, 返回子码为 Best-rtn-subcode 的 MPLS echo reply, 包含上述过程创建的所有 TLV. 发送 echo reply 的程序见 4.4.1 节.

4.4.1. FEC 验证 (FEC Validation)​

本节描述 Target FEC 栈中 FEC 条目的验证, 接受 FEC, Label-L 与 Interface-I. 算法步骤如下:

  1. 两个返回值 FEC-status 与 FEC-return-code 初始化为 0.
  2. 若 FEC 是 Nil FEC: 若 Label-L 为 Explicit_Null 或 Router_Alert, 返回. 否则, 设置 FEC-return-code 为 10, FEC-status 为 1, 返回.
  3. 检查描述 LSP 上收到流量如何进一步交换或关联哪个应用的 FEC 标签映射. 若无映射, 设置 FEC-return-code 为 4 ("Replying router has no mapping for the FEC at stack-depth"), FEC-status 为 1, 返回.
  4. 若 FEC 的标签映射为 Implicit Null, 设置 FEC-status 为 2 转步骤 5. 否则, 若 FEC 的标签映射为 Label-L, 转步骤 5. 否则, 设置 FEC-return-code 为 10, FEC-status 为 1, 返回.
  5. 协议检查: 检查将用于通告 FEC 的协议. 若可确定与 Interface-I 关联的协议不会通告该 FEC 类型的 FEC, 设置 FEC-return-code 为 12 ("Protocol not associated with interface at FEC stack-depth"), FEC-status 为 1.
  6. 返回.

4.5. 发送 MPLS Echo Reply (Sending an MPLS Echo Reply)​

MPLS echo reply 是 UDP 分组. 它 MUST 仅响应 MPLS echo request 发送. 源 IP 地址为应答方可路由地址; 源端口为 LSP ping 的知名 UDP 端口. 目的 IP 地址与 UDP 端口从 echo request 的源 IP 地址与源 UDP 端口复制. IP TTL 设为 255. 若 echo request 中回复模式为 "Reply via an IPv4 UDP packet with Router Alert", 则 IP 首部 MUST 含 Router Alert IP 选项; 若经 LSP 发送应答, 最顶层标签 MUST 为 Router Alert 标签 (1) [LABEL-STACK].

echo reply 格式同 echo request. Sender's Handle, Sequence Number 与 TimeStamp Sent 从 echo request 复制; TimeStamp Received 设为收到 echo request 的时间 (若请求方与应答方时钟同步, 此信息最有用). echo request 的 FEC 栈 TLV MAY 复制到应答.

应答方 MUST 填入上一小节确定的返回码与子码.

若 echo request 含 Pad TLV, 应答方 MUST 解释首字节关于如何回复的指示.

若应答路由器是 FEC 的目的地, echo reply 中 SHOULD NOT 包含下游映射 TLV.

若 echo request 含下游映射 TLV 且应答路由器不是 FEC 目的地, 应答方 SHOULD 计算其下游路由器及对应入标签的标签, 并向回发送的 echo reply 中为每个下游路由器添加下游映射 TLV.

若下游映射 TLV 含的多路径信息所需处理超出接收路由器愿意执行的, 应答路由器 MAY 选择仅以 echo request 下游映射中包含的多路径子集应答. (注意: echo request 发起方 MAY 发送含应答中未包含多路径信息的另一 echo request.)

除回复模式 4 ("Reply via application level control channel") 外, echo reply 总在 IP/MPLS 网络上下文中发送.

4.6. 接收 MPLS Echo Reply (Receiving an MPLS Echo Reply)​

LSR X 应仅收到其发送的 MPLS echo request 的应答. 因此收到 MPLS echo reply 时, X 应解析分组确保其格式良好, 然后尝试用目的 UDP 端口与 Sender's Handle 将其与先前发送的 echo request 匹配. 若未找到匹配, X 丢弃该 echo reply; 否则检查 Sequence Number 是否匹配.

若 echo reply 含下游映射且 X 希望进一步 traceroute, SHOULD 将下游映射复制到其下一个 echo request (TTL 加 1).

4.7. VPN IPv4 与 IPv6 前缀的问题 (Issue with VPN IPv4 and IPv6 Prefixes)​

通常, 对 VPN IPv4 前缀或 VPN IPv6 前缀的 LSP ping 以深度大于 1 的标签栈发送, 最内层标签 TTL 为 1, 以在 ping 到达客户设备前终止于出口 PE. 但某些情况下, 标签栈可在 ping 命中出口 PE 前收缩为单个标签; 这将导致 ping 过早终止. 多 AS 运营商的运营商 VPN (Carrier's Carrier VPN) 即为一例.

为绕过此问题, 一种方法是收到此类 ping 的 LSR 意识到 ping 过早终止, 回送错误码 13. 此时发起 LSR 可在 VPN 标签上递增 TTL 后重试 ping. 如此, 入端 LSR 将依次尝试 TTL 值直至找到允许 VPN ping 到达出口 PE 的值.

4.8. 不合规路由器 (Non-compliant Routers)​

若被 ping 的 FEC 栈的出口不支持 MPLS ping, 则不发送应答, 导致可能的 "假阴性". 若在 "traceroute" 模式下, transit LSR 不支持 LSP ping, 则该 LSR 对某些 TTL (如 n) 无应答. 发起 echo request 的 LSR SHOULD 尝试以 TTL=n+1, n+2, ..., n+k 发送 echo request 以探测路径更下游的 LSR. 此情况下, 对 TTL>n 的 echo request, 在收到含下游映射 TLV 的应答前, SHOULD 将下游映射 TLV 的 "Downstream IP Address" 字段设为 ALLROUTERS 组播地址发送. 标签栈 MAY 从下游映射 TLV 省略. 此外, 在收到含下游映射 TLV 的 echo reply 前, SHOULD NOT 设置 "Validate FEC Stack" 标志.