RFC 3031 - 标签分发规程(Label Distribution Procedures)
5. 标签分发规程(Hop-by-Hop)
在本节中, 我们只考虑这样一些标签绑定 (label binding): 它们被用于「沿其逐跳路由路径 (hop-by-hop routed path) 进行标签交换的流量」. 在这些情形下, 所讨论的标签将对应于路由表中的某个地址前缀.
5.1 通告与使用标签的规程(The Procedures for Advertising and Using labels)
有多种不同的规程可用于分发标签绑定. 其中一些由下游 LSR (downstream LSR) 执行, 另一些由上游 LSR (upstream LSR) 执行.
下游 LSR 必须执行:
-
分发规程 (Distribution Procedure), 以及
-
撤回规程 (Withdrawal Procedure).
上游 LSR 必须执行:
-
请求规程 (Request Procedure), 以及
-
不可用规程 (NotAvailable Procedure), 以及
-
释放规程 (Release Procedure), 以及
-
标签使用规程 (labelUse Procedure).
MPLS 体系结构为上述每一种规程都支持若干种变体.
然而, MPLS 体系结构并不支持所有变体的所有可能组合. 受支持的组合集合将在 5.2 节中描述, 该节还将讨论不同组合之间的互操作性.
5.1.1 下游 LSR: 分发规程(Downstream LSR: Distribution Procedure)
分发规程由下游 LSR 用来确定: 何时应当把「某个特定地址前缀的标签绑定」分发给它的标签分发对等体 (label distribution peers). 体系结构支持四种不同的分发规程.
无论采用哪一种具体规程, 若某个特定地址前缀的标签绑定已由下游 LSR Rd 分发给上游 LSR Ru, 且该绑定的属性 (如上文所定义) 在任何时候发生变化, 则 Rd 必须把新属性告知 Ru.
若某个 LSR 维护着到达某特定地址前缀的多条路由, 那么, 该 LSR 是否为该地址前缀绑定多个标签 (每条路由一个), 从而分发多个绑定, 属于本地事务 (local matter).
5.1.1.1 PushUnconditional
设 Rd 是一个 LSR. 假设:
-
X 是 Rd 路由表中的一个地址前缀;
-
就 X 而言, Ru 是 Rd 的标签分发对等体.
只要这些条件成立, Rd 就必须为 X 绑定一个标签, 并把该绑定分发给 Ru. Rd 有责任记录它已分发给 Ru 的那些绑定, 并确保 Ru 始终持有这些绑定.
执行「下游自主标签分配」(unsolicited downstream label assignment)、且采用「独立 LSP 控制模式」(Independent LSP Control Mode) 的 LSR 会使用这一规程.
5.1.1.2 PushConditional
设 Rd 是一个 LSR. 假设:
-
X 是 Rd 路由表中的一个地址前缀;
-
就 X 而言, Ru 是 Rd 的标签分发对等体;
-
Rd 是 X 的 LSP 出口 (LSP Egress) 或 LSP 代理出口 (LSP Proxy Egress), 或者 Rd 到 X 的第 3 层下一跳 (L3 next hop) 是 Rn, 其中 Rn 不同于 Ru, 且 Rn 已为 X 绑定标签并把该绑定分发给了 Rd.
那么, 一旦这些条件全部成立, Rd 就应当为 X 绑定一个标签, 并把该绑定分发给 Ru.
PushUnconditional 会为路由表中的所有地址前缀分发标签绑定, 而 PushConditional 只会为这样的地址前缀分发标签绑定: 或者已经从自己的 LSP 下一跳那里收到了标签绑定, 或者自己没有具备 MPLS 能力的 L3 下一跳.
执行下游自主标签分配、且采用「有序 LSP 控制模式」(Ordered LSP Control Mode) 的 LSR 会使用这一规程.
5.1.1.3 PulledUnconditional
设 Rd 是一个 LSR. 假设:
-
X 是 Rd 路由表中的一个地址前缀;
-
就 X 而言, Ru 是 Rd 的标签分发对等体;
-
Ru 已显式请求 Rd 为 X 绑定一个标签, 并把该绑定分发给 Ru.
那么, Rd 应当为 X 绑定一个标签, 并把该绑定分发给 Ru. 注意: 若 X 不在 Rd 的路由表中, 或者就 X 而言 Rd 并不是 Ru 的标签分发对等体, 则 Rd 必须告知 Ru 它目前无法提供绑定.
若 Rd 已经把地址前缀 X 的一个绑定分发给了 Ru, 而又收到 Ru 对地址前缀 X 绑定的新请求, 则它会再绑定第二个标签, 并把新的绑定分发给 Ru. 第一个标签绑定仍然保持有效.
执行「下游按需标签分发」(downstream-on-demand label distribution)、且采用独立 LSP 控制模式的 LSR 会使用这一规程.
5.1.1.4 PulledConditional
设 Rd 是一个 LSR. 假设:
-
X 是 Rd 路由表中的一个地址前缀;
-
就 X 而言, Ru 是 Rd 的标签分发对等体;
-
Ru 已显式请求 Rd 为 X 绑定一个标签, 并把该绑定分发给 Ru;
-
Rd 是 X 的 LSP 出口或 LSP 代理出口, 或者 Rd 到 X 的 L3 下一跳是 Rn, 其中 Rn 不同于 Ru, 且 Rn 已为 X 绑定标签并把该绑定分发给了 Rd.
那么, 一旦这些条件全部成立, Rd 就应当为 X 绑定一个标签, 并把该绑定分发给 Ru. 注意: 若 X 不在 Rd 的路由表中, 且无法经由 Rd 到 X 的下一跳获得 X 的绑定, 或者就 X 而言 Rd 并不是 Ru 的标签分发对等体, 则 Rd 必须告知 Ru 它目前无法提供绑定.
然而, 若唯一未成立的条件是 Rn 尚未向 Rd 提供标签, 则 Rd 必须推迟对 Ru 的任何响应, 直到它从 Rn 收到绑定为止.
若 Rd 已经把地址前缀 X 的标签绑定分发给了 Ru, 而在此后的某个时刻该标签绑定的任何属性发生了变化, 则 Rd 必须把带有新属性的标签绑定重新分发给 Ru. 即使 Ru 没有发出新的请求, 它也必须这样做.
执行下游按需标签分配、且采用有序 LSP 控制模式的 LSR 会使用这一规程.
在 5.2 节中, 我们将讨论如何在任一给定时刻选择所要使用的具体规程, 以及如何确保选择了不同规程的 LSR 之间的互操作性.
5.1.2 上游 LSR: 请求规程(Upstream LSR: Request Procedure)
请求规程由某地址前缀的上游 LSR 用来确定: 何时显式请求下游 LSR 为该前缀绑定标签并分发该绑定. 有三种可以采用的规程.
5.1.2.1 RequestNever
从不发出请求. 若下游 LSR 使用的是 PushConditional 规程或 PushUnconditional 规程, 这一做法是有用的; 但若下游 LSR 使用的是 PulledUnconditional 规程或 PulledConditional 规程, 这一做法便没有用处.
当同时采用下游自主标签分发与「自由标签保留模式」(Liberal Label Retention Mode) 时, LSR 会使用这一规程.
5.1.2.2 RequestWhenNeeded
只要到某地址前缀的 L3 下一跳发生了变化, 或者学到了新的地址前缀, 而自己又尚未从该下一跳那里获得针对该地址前缀的标签绑定, 就发出请求.
只要使用了「保守标签保留模式」(Conservative Label Retention Mode), LSR 就会使用这一规程.
5.1.2.3 RequestOnRequest
除了按需发出请求 (如 5.1.2.2 节所述) 之外, 每当收到一个请求, 就再发出一个请求. 若 Ru 不具备充当 LSP 入口 (LSP ingress) 的能力, 它可以只在收到来自上游的请求时才发出请求.
若 Rd 收到 Ru 发来的这种请求, 且所针对的是 Rd 已经分发给 Ru 一个标签的地址前缀, 则 Rd 必须分配一个新的 (互不相同的) 标签, 把它绑定到 X, 并分发该绑定. (Rd 能否立即把该绑定分发给 Ru, 取决于所使用的分发规程.)
执行下游按需标签分发、但不做标签合并 (label merging) 的 LSR 会使用这一规程, 例如不支持 VC 合并 (VC merge) 的 ATM-LSR.
5.1.3 上游 LSR: 不可用规程(Upstream LSR: NotAvailable Procedure)
若 Ru 与 Rd 分别是地址前缀 X 的上游与下游标签分发对等体, Rd 是 Ru 到 X 的 L3 下一跳, 且 Ru 向 Rd 请求 X 的绑定, 但 Rd 答复说它目前无法提供绑定, 原因是它没有到 X 的下一跳, 那么, NotAvailable 规程决定了 Ru 如何应对. 有两种可能约束 Ru 行为的规程:
5.1.3.1 RequestRetry
Ru 应当在稍后的时间再次发出请求. 也就是说, 请求方有责任在稍后重试, 以获得所需的绑定. 当使用下游按需标签分发时, 会采用这一规程.
5.1.3.2 RequestNoRetry
Ru 绝不应当再次发出该请求, 而是假定 Rd 会在绑定可用时自动提供绑定. 若 Rd 使用的是 PushUnconditional 规程或 PushConditional 规程, 即若使用了下游自主标签分发, 这一做法是有用的.
注意: 若 Rd 答复 Ru 说它无法提供绑定的原因是出现了某种错误状态, 而不是因为它没有下一跳, 那么, Ru 的行为将由标签分发协议的错误恢复条件来约束, 而不是由 NotAvailable 规程来约束.
5.1.4 上游 LSR: 释放规程(Upstream LSR: Release Procedure)
假设 Rd 是一个 LSR, 它已把某个标签绑定到地址前缀 X, 并已把该绑定分发给 LSR Ru. 若 Rd 恰好不是 Ru 到地址前缀 X 的 L3 下一跳, 或者已不再是 Ru 到地址前缀 X 的 L3 下一跳, 那么 Ru 将不会使用该标签. 释放规程决定了 Ru 在这种情形下如何行动. 有两种可能约束 Ru 行为的规程:
5.1.4.1 ReleaseOnChange
Ru 应当释放该绑定, 并把自己已经这样做的情况告知 Rd. 这一规程用于实现保守标签保留模式.
5.1.4.2 NoReleaseOnChange
Ru 应当维护该绑定, 以便在 Rd 日后重新成为 Ru 到 X 的 L3 下一跳时, 它能够立即再次使用该绑定. 这一规程用于实现自由标签保留模式.
5.1.5 上游 LSR: 标签使用规程(Upstream LSR: labelUse Procedure)
假设 Ru 是一个 LSR, 它从 LSR Rd 那里收到了「标签 L 绑定到地址前缀 X」的绑定, 且就 X 而言 Ru 位于 Rd 的上游, 而且事实上 Rd 就是 Ru 到 X 的 L3 下一跳.
若 Rd 是 Ru 到 X 的 L3 下一跳, Ru 就会使用该绑定. 若在 Ru 收到该绑定的那一刻, Rd 不是 Ru 到 X 的 L3 下一跳, 则 Ru 此时不会对该绑定作任何使用. 不过, 若 Rd 日后成为 Ru 到 X 的 L3 下一跳, Ru 可以在稍后的某个时刻开始使用该绑定.
标签使用规程 (labelUse Procedure) 决定的正是 Ru 如何使用 Rd 的绑定.
Ru 可以使用两种规程:
5.1.5.1 UseImmediate
Ru 可以立即把该绑定投入使用. 只要在任一时刻 Ru 持有来自 Rd 的 X 的绑定, 且 Rd 是 Ru 到 X 的 L3 下一跳, 那么 Rd 同时也会是 Ru 到 X 的 LSP 下一跳. 不使用「环路检测」(loop detection) 时采用这一规程.
5.1.5.2 UseIfLoopNotDetected
这一规程与 UseImmediate 相同, 除非 Ru 已经在 LSP 中检测到环路 (loop). 若已检测到环路, Ru 将停止使用标签 L 向 Rd 转发分组.
使用环路检测时采用这一规程.
这种状态会一直持续下去, 直到 X 的下一跳发生变化, 或者环路不再被检测到为止.
5.1.6 下游 LSR: 撤回规程(Downstream LSR: Withdraw Procedure)
在这种情形下, 只存在单一的规程.
当 LSR Rd 决定解除标签 L 与地址前缀 X 之间的绑定时, 必须把这次解除绑定 (unbinding) 的情况分发给该绑定曾被分发给的所有 LSR.
必须做到: 在 Rd 把「标签 L 绑定到任何其他地址前缀 Y (其中 X != Y)」的任何新绑定分发给某个 LSR Ru 之前, 先把「L 与 X 解除绑定」这件事分发给 Ru. 若 Ru 在得知 L 与 X 解除绑定之前就得知了 L 与 Y 之间的新绑定, 并且匹配 X 的分组和匹配 Y 的分组都会由 Ru 转发给 Rd, 那么, 在一段时期内, Ru 会既给匹配 X 的分组、又给匹配 Y 的分组打上标签 L.
标签绑定的分发与撤回 (withdrawal) 是通过标签分发协议 (label distribution protocol) 完成的. 所有标签分发协议都要求: 在两个标签分发对等体之间建立一个标签分发邻接 (label distribution adjacency) (「隐式对等体」(implicit peers) 除外). 若 LSR R1 与 LSR R2 之间存在标签分发邻接, 并且 R1 已经由该邻接从 LSR R2 收到了标签绑定, 那么, 若该邻接被任何一方拆除 (无论是由于故障, 还是作为正常操作的一部分), 经由该邻接收到的所有绑定都必须被视为已被撤回.
只要相关的标签分发邻接仍然存在, 被撤回的标签绑定就必须始终被显式地撤回. 若有第二个标签被绑定到某个地址前缀, 其结果并不是隐式地撤回第一个标签, 而是同时绑定这两个标签; 这是支持多路径路由 (multi-path routing) 所必需的. 若有第二个地址前缀被绑定到某个标签上, 其结果并不是隐式地撤回该标签与第一个地址前缀之间的绑定, 而是把该标签同时用于这两个地址前缀.
5.2 MPLS 方案: 受支持的规程组合(MPLS Schemes: Supported Combinations of Procedures)
考虑两个 LSR, Ru 与 Rd, 就某个地址前缀集合而言它们是标签分发对等体, 其中 Ru 是上游对等体, Rd 是下游对等体.
约束 Ru 与 Rd 之间交互的 MPLS 方案 (MPLS scheme) 可以描述为一个五元组: <分发规程 (Distribution Procedure), 请求规程 (Request Procedure), 不可用规程 (NotAvailable Procedure), 释放规程 (Release Procedure), 标签使用规程 (labelUse Procedure)>. (由于只存在一种撤回规程, 无需提及.) 出现在某个位置上的 "*" 是通配符 (wild-card), 表示该类别中的任何规程都可以出现; 出现在特定位置上的 "N/A" 表示该类别中不需要任何规程.
只有下文规定的那些 MPLS 方案才得到 MPLS 体系结构的支持. 将来若证明了对其他方案的需要, 也可以增补.
5.2.1 支持标签合并的 LSR 的方案(Schemes for LSRs that Support Label Merging)
若 Ru 与 Rd 是标签分发对等体, 且两者都支持标签合并, 则必须使用下列方案之一:
-
<PushUnconditional, RequestNever, N/A, NoReleaseOnChange, UseImmediate>
这是下游自主标签分发, 采用独立控制、自由标签保留模式, 且无环路检测.
-
<PushUnconditional, RequestNever, N/A, NoReleaseOnChange, UseIfLoopNotDetected>
这是下游自主标签分发, 采用独立控制、自由标签保留模式, 且带环路检测.
-
<PushConditional, RequestWhenNeeded, RequestNoRetry, ReleaseOnChange, *>
这是下游自主标签分发, 采用有序控制 (自出口发起) 与保守标签保留模式. 环路检测是可选的.
-
<PushConditional, RequestNever, N/A, NoReleaseOnChange, *>
这是下游自主标签分发, 采用有序控制 (自出口发起) 与自由标签保留模式. 环路检测是可选的.
-
<PulledConditional, RequestWhenNeeded, RequestRetry, ReleaseOnChange, *>
这是下游按需标签分发, 采用有序控制 (自入口发起)、保守标签保留模式, 环路检测可选.
-
<PulledUnconditional, RequestWhenNeeded, N/A, ReleaseOnChange, UseImmediate>
这是下游按需标签分发, 采用独立控制与保守标签保留模式, 不带环路检测.
-
<PulledUnconditional, RequestWhenNeeded, N/A, ReleaseOnChange, UseIfLoopNotDetected>
这是下游按需标签分发, 采用独立控制与保守标签保留模式, 带环路检测.
5.2.2 不支持标签合并的 LSR 的方案(Schemes for LSRs that do not Support Label Merging)
假设 R1, R2, R3 和 R4 是一些不支持标签合并、但被用作 LSR 的 ATM 交换机. 再假设地址前缀 X 的 L3 逐跳路径是 <R1, R2, R3, R4>, 且目的地址为 X 的分组可以从其中任何一个 LSR 进入网络. 由于不存在多点到点 (multipoint-to-point) 能力, 这些 LSP 必须被实现为点到点 VC, 这意味着地址前缀 X 需要三条这样的 VC: <R1, R2, R3, R4>, <R2, R3, R4> 和 <R3, R4>.
因此, 若 R1 与 R2 是 MPLS 对等体, 且其中一方是使用传统 ATM 交换硬件 (即不具备信元交错抑制 (cell interleave suppression) 能力) 实现的 LSR, 或者在其他方面不具备执行标签合并的能力, 那么, R1 与 R2 之间使用的 MPLS 方案必须是下列之一:
-
<PulledConditional, RequestOnRequest, RequestRetry, ReleaseOnChange, *>
这是下游按需标签分发, 采用有序控制 (自入口发起)、保守标签保留模式, 环路检测可选.
RequestOnRequest 规程的使用会导致 R4 为 X 向 R3 分发三个标签; R3 会为 X 向 R2 分发两个标签, 而 R2 会为 X 向 R1 分发一个标签.
-
<PulledUnconditional, RequestOnRequest, N/A, ReleaseOnChange, UseImmediate>
这是下游按需标签分发, 采用独立控制与保守标签保留模式, 不带环路检测.
-
<PulledUnconditional, RequestOnRequest, N/A, ReleaseOnChange, UseIfLoopNotDetected>
这是下游按需标签分发, 采用独立控制与保守标签保留模式, 带环路检测.
5.2.3 互操作性考虑(Interoperability Considerations)
很容易看出, 某些五元组并不能产生可行的 MPLS 方案. 例如:
-
<PulledUnconditional, RequestNever, *, *, *> <PulledConditional, RequestNever, *, *, *>
在这些 MPLS 方案中, 下游 LSR Rd 只有在收到上游 LSR Ru 的请求时才会分发标签绑定, 但 Ru 从不发出任何这样的请求. 显然, 这些方案是不可行的, 因为它们不会使标签绑定得到正确的分发.
-
<*, RequestNever, *, *, ReleaseOnChange>
在这些 MPLS 方案中, Rd 在自己不使用绑定时就释放它们, 但它从不再次请求这些绑定, 即使它日后需要它们. 因此, 这些方案无法确保标签绑定得到正确的分发.
在本节中, 我们规定一些规则, 以防止一对标签分发对等体采用那些会导致不可行的 MPLS 方案的规程. 这些规则要求: 或者在标签分发邻接初始化期间, 在标签分发对等体之间交换信息; 或者以先验 (a priori) 的方式获知该信息 (即通过本文档范围之外的某种手段获得).
-
双方都必须声明自己是否支持标签合并.
-
若 Rd 不支持标签合并, Rd 必须在 PulledUnconditional 规程与 PulledConditional 规程之间作出选择. 若 Rd 选择了 PulledConditional, 则 Ru 被迫使用 RequestRetry 规程.
也就是说, 若下游 LSR 不支持标签合并, 那么, 在选择 MPLS 方案时以它的偏好为准.
-
若 Ru 不支持标签合并而 Rd 支持, 则 Ru 必须在 RequestRetry 与 RequestNoRetry 两种规程之间作出选择. 这会分别迫使 Rd 使用 PulledConditional 规程或 PulledUnconditional 规程.
也就是说, 若只有一方 LSR 不支持标签合并, 那么, 在选择 MPLS 方案时以它的偏好为准.
-
若 Ru 与 Rd 都支持标签合并, 那么, 自由与保守标签保留模式之间的选择权属于 Ru. 也就是说, Ru 既可以选择使用 RequestWhenNeeded/ReleaseOnChange (保守), 也可以选择使用 RequestNever/NoReleaseOnChange (自由). 然而, "push" 与 "pull" 之间、以及 "conditional" 与 "unconditional" 之间的选择权属于 Rd. 若 Ru 选择了自由标签保留模式, Rd 可以选择 PushUnconditional 或 PushConditional. 若 Ru 选择了保守标签保留模式, Rd 可以选择 PushConditional, PulledConditional 或 PulledUnconditional.
这些选择共同决定了所使用的 MPLS 方案.