跳到主要内容

6. 根发起的路由状态 (Root-Initiated Routing State)

6.1. RPL 网络建立 (RPL Network Setup)

为了避免 6LoWPAN 端点需要执行路径 MTU 发现 (Path MTU Discovery), 6LoWPAN 链路通常定义为 MTU 1280, 见 [6LoWPAN] 第 4 节. 将数据包注入 Track 通常涉及 IP-in-IP 封装和额外的 IPv6 扩展头部. 如果生成的数据包超过为 RPL 域定义的 MTU, 这可能导致分片.

虽然 6LoWPAN LLN 中可以进行分片, 例如使用 [6LoWPAN], [RFC8930] 或 [RFC8931], 但推荐在构成主 DODAG 的 RPL 路由器之间定义大于 1280 的 MTU, 以便容纳必要的头部增加, 同时仍向 6LoWPAN 端点协议栈呈现 1280.

6.2. 请求 Track (Requesting a Track)

本规范引入 P-DAO-REQ 消息, LLN 节点使用该消息请求形成新的 Track, 且该 LLN 节点是该 Track 的入口 (ingress). 注意, TrackID 的命名空间由入口节点拥有. 在没有 P-DAO-REQ 的情况下, 必须存在某种流程, 使 Root 能够在该命名空间中分配 TrackID, 同时避免冲突, 更多内容见第 6.3 节.

P-DAO-REQ 指示期望的 TrackID, 以及应建立 Track 的持续时间. 收到 P-DAO-REQ 后, Root 可以按请求安装 Track. 在这种情况下, Root 以 PDR-ACK 应答, 并指示授予的 Track Lifetime. 所有 segment 必须采用相同模式, 即 Storing 或 Non-Storing. 所有 segment 必须使用相同的 TrackID 和 P-DAO 中指示的相同 DODAGID 创建.

Root 按其认为合适的方式设计 Track, 并随着时间推移更新或更改 segment, 以按需服务该 Track. 注意, 没有协议元素用于在 Track 深处发生变化时通知发起请求的 Track 入口, 因此这些变化对 Track 入口是透明的. 如果主 Root 无法维持预期的服务水平, 则需要完全拆除该 Track. P-DAO 消息中的 Segment Lifetime 不需要与 P-DAO-REQ 中的 Requested Lifetime 对齐, 不同 segment 的 P-DAO 消息之间也不需要对齐. 例如, Root 可以为 segment 使用较短的生存期, 并在 Track 的生存期内续订或更改它们. Track 的所有组成部分, 即保护路径和 segment, 必须在 TrackID 可重用之前被销毁, 或者其生存期已经届满.

当 Track Lifetime 相对接近届满时, 即大致处于节点到 Root 的往返时间量级, 发起请求的节点应当使用 PDR-ACK 中的 TrackID 重新发送 P-DAO-REQ, 以延长 Track 的生存期. 否则, Track 将超时, Root 将拆除整个结构.

如果 Track 失败且无法恢复, Root 会异步向发起请求的节点发送 Track Lifetime 为 0 的 PDR-ACK, 表示该 Track 已失败, 并通过 PDR-ACK Status 指示故障原因.

6.3. 标识 Track (Identifying a Track)

RPL 定义 Instance 的概念, 用于指示单独的路由拓扑, 且同一网络中可以共存多个拓扑. 每个数据包的 RPI 中都会标记 RPLInstanceID, 以指示该数据包实际遵循哪个拓扑.

本规范按如下方式利用 RPL Instance 模型:

  • 主 Root 可以使用 P-DAO 消息在主 Instance 中添加更好的路由, 但必须符合该 Instance 中的路由目标.

    为此, 主 Root 可以沿主 DODAG 向下的一条路径安装一个 segment, 该主 DODAG 以 Non-Storing Mode 运行. 这支持松散源路由 (loose source routing), 并减少 Routing Header 的大小. 见第 3.3.1 节. 主 Root 也可以跨主 DODAG 安装保护路径, 以补充路由拓扑.

    向 RPL 主 DODAG 添加 P-Route 时, 主 Root 必须将 P-DAO Base Object 的 RPLInstanceID 字段设置为主 DODAG 的 RPLInstanceID, 见 [RPL] 第 6.4.1 节, 并且禁止使用 DODAGID 字段. 与经由主 Root 的默认路由相比, P-Route 对 Target Address 提供更长匹配, 因此会被优先选择.

  • 主 Root 也可以使用 P-DAO 消息安装 Track, 将其作为独立路由拓扑, 例如流量工程拓扑 (Traffic Engineered), 以实现从入口到出口端点的特定路由特征. 为此, 主 Root 必须建立 Local RPL Instance, 见 [RPL] 第 5 节, 且 Local RPLInstanceID 充当 TrackID. 对于作为该 Track 的 DODAGID 的 Track 入口 IPv6 ULA 或 GUA, TrackID 必须唯一.

    这样, Track 由元组 (DODAGID, TrackID) 唯一标识. 其中 TrackID 始终以 'D' 标志设置为 0 的形式表示, 另见 [RPL] 第 5.1 节, 表示当它用于 RPI 时, IPv6 数据包的源地址指示 DODAGID.

    P-DAO Base Object 必须指示标识 Track 的元组 (DODAGID, TrackID), 如图 8 所示. 标识 P-Route 的 P-RouteID 必须在 VIO 中指示, 如图 16 所示.

    Track 入口是由 Local RPL Instance 形成的 DODAGID 的 Root. 它拥有自身 TrackID 的命名空间, 因此可以选择任意未使用的值, 通过 P-DAO-REQ 请求新的 Track. 在不使用 P-DAO-REQ 的特定部署中, 命名空间的一部分可以通过管理方式委派给主 Root, 这意味着主 Root 对其创建的 Track 的 TrackID 分配具有权威性.

    采用本规范时, 主 Root 知道所有活动 Track, 因此它也可以选择任意未使用的值, 在没有 P-DAO-REQ 的情况下形成 Track. 为了避免主 Root 与 Track 入口同时选择相同值而发生冲突, 推荐 Track 入口从值 0 开始递增分配用作 TrackID 的 Local RPLInstanceID 的 ID 值, 见 [RPL] 第 5.1 节, 而 Root 从 63 开始递减分配.

6.4. 安装 Track (Installing a Track)

一条路径可以由单个 P-Route 安装. 该 P-Route 指示连续节点序列, 可以在 Storing Mode 中作为单 segment Track, 或在 Non-Storing Mode 中作为单保护路径 Track. 单保护路径 Track 可以作为松散的 Non-Storing Mode P-Route 安装. 在这种情况下, 下一个松散条目必须通过一条路径递归到达.

Complex Track 可以作为具有相同 DODAGID 和 TrackID 的一组 P-Route 安装. Non-Storing Mode P-Route 的入口是该 DODAGID 的所有者和 Root. Storing Mode P-Route 的入口必须是 DODAGID 的所有者, 或者同一 Track 的保护路径上的一跳. 在后一种情况下, 如果保护路径存在下一跳, 则 P-Route 的 Target 必须包含该保护路径的下一跳, 以确保转发连续性. 对于 Complex Track, 每个 segment 都由 Root 独立且异步维护, 并拥有自己的生存期, 该生存期可以短于, 等于或长于 Track 的生存期.

如果某个 Track 的 TrackID 不是主 DODAG 的 RPLInstanceID, 则沿该 Track 的路由必须以高于沿主 DODAG 的路由的优先级安装, 这意味着:

  • 最长匹配必须是路由比较的首要依据.

  • 对于等长匹配, 必须优先选择沿 Track 的路由, 而不是沿主 DODAG 的路由.

  • 除非存在用于选择哪些数据包使用哪个 Track 的策略, 否则不应存在从同一入口节点通向同一 Target 的两个不同 Track. 此类策略不在本文档范围内.

  • 已沿 Track 路由的数据包禁止再次沿主 DODAG 路由. 如果在数据包退出 Track 的节点处, 目标无法作为邻居到达, 则必须丢弃该数据包.

6.4.1. 指示投射路由 (Signaling a Projected Route)

本规范增加一种能力, 使主 DODAG 的 Root 能够将 Track 作为一组 P-Route 安装, 并为每条单独的保护路径或 segment 使用一个 P-DAO 消息. P-DAO 在一个或多个 RTO 中指示一组 Target. 这些 Target 可以通过 VIO 中指示的一系列路由器到达.

与传统 DAO 消息一样, 只有当 P-DAO 按 RPL 规范 [RPL] 第 9.2.2 节 "Generation of DAO Messages" 的定义是"新的"时, 它才会导致状态变化. 该判断使用来自 VIO 的 Segment Sequence 信息, 而不是来自 TIO 的 Path Sequence. 此外, VIO 中 Segment Lifetime 为 0 表示与该 segment 关联的 P-Route 将被删除. P-Route 有两种操作模式: Storing 和 Non-Storing.

P-DAO 消息必须从作为主 DODAG 的 DODAGID 的 Root 地址发送. 它必须包含以下两者之一: 恰好一个由一个或多个 RTO 后跟一个 VIO 构成的序列, 或任意数量的由一个或多个 RTO 后跟一个或多个 TIO 构成的序列. 前者是本规范的常规表达, 后者对应第 7.2 节中描述的较少受限环境变体.

创建或更新保护路径的 P-DAO 必须发送到保护路径入口的 GUA 或 ULA. 除非正在删除保护路径, 否则该 P-DAO 必须包含保护路径中的完整跳列表. 创建新 Track segment 的 P-DAO 必须发送到 segment 出口的 GUA 或 ULA, 并且必须指示 segment 中的完整跳列表. 更新, 包括删除, 某个 segment 区段的 P-DAO 必须发送到被修改 segment 之后的第一个节点, 并且必须指示从紧邻被修改区段之前的节点开始的该区段完整跳列表.

在 Non-Storing Mode 中, 如第 6.4.3 节所述, Root 将 P-DAO 发送到 Track 入口, 源路由状态在那里应用. 而在 Storing Mode 中, P-DAO 发送到安装路径上的最后一个节点, 并沿反向转发, 在每一跳安装 Storing Mode 状态, 如第 6.4.2 节所述. 在这两种情况下, Track 入口都是 Track 的所有者, 并在安装成功时生成 P-DAO-ACK.

如果 P-DAO 中存在 'K' 标志, 则必须使用 P-DAO-ACK 确认该 P-DAO, 并将 P-DAO-ACK 发回接收该 P-DAO 时所来自的 Root 地址. 在大多数情况下, 保护路径, segment 或 segment 更新区段的第一个节点是发送确认的节点. 规则的例外情况是, segment 中的某个中间节点未能将 Storing Mode P-DAO 转发给 SM-VIO 中的前一个节点.

在 No-Path Non-Storing Mode P-DAO 中, SRH-6LoRH 禁止出现在 NSM-VIO 中. 无论如何, 入口中的状态都会被清除. 在所有其他情况下, VIO 必须包含至少一个 Via Address, 且同一 Via Address 禁止出现多次, 否则会形成环路.

处理 VIO 的节点可以验证这些条件是否发生. 一旦发生其中任何条件, 该节点必须忽略 P-DAO, 并在 DAO-ACK 中以 RPL 拒绝状态 "Error in VIO" 拒绝它. 见第 11.16 节.

除显式讨论的错误外, 阻止路由安装的其他错误会在 P-DAO-ACK 中以 RPL 拒绝状态 "Unqualified Rejection" 确认.

6.4.2. 使用 Storing Mode P-Route 安装 Track Segment (Installing a Track Segment with a Storing Mode P-Route)

如图 18 所示, Storing Mode P-DAO 沿 SM-VIO 指示的 segment 安装到达 Target Options 中所示 Target 的路由. 该 segment 将被包含在 P-DAO Base Object 指示的 DODAG 中, 该 DODAG 可以是主 DODAG 形成的 DODAG, 也可以是与 Local RPL Instance 关联的 Track.

           ------+---------
| Internet
|
+-----+
| | Border Router
| | (RPL Root)
+-----+ | P- ^ |
| | DAO | P-DAO-ACK |
o o o o | | |
o o o o Ingress o o o | ^ | Projected .
o o o o o \\ o o o | | P-DAO | Route .
o o o o \\ o o o o | ^ | .
o o o o o Egress o o v | P-DAO v .
o o LLN o o o |
o o o o o Loose Source Route Path |
o o o o v

图 18: 投射路由 (Projecting a Route)

为了沿 segment 安装相关路由状态, Root 向正在安装的路由 segment 的 Track 出口路由器发送单播 P-DAO 消息. P-DAO 消息包含一个 SM-VIO, 其中带有严格的 Via Address 序列. SM-VIO 跟在一个或多个 RTO 之后, 这些 RTO 指示该 Track 所通向的 Target. SM-VIO 包含一个 Segment Lifetime, 指明状态应维护的时间.

Root 将 P-DAO 直接发送到 segment 的出口节点. 在该 P-DAO 中, 目标 IP 地址与 SM-VIO 中的最后一个 Via Address 匹配. 出口由此识别自身角色. 类似地, segment 入口节点也因为与 SM-VIO 中的第一个 Via Address 匹配而识别自身角色.

segment 的出口节点是路径中唯一不会因 P-DAO 而安装路由的节点. 预期它已经能够基于现有表项路由到 Target. 如果其中一个 Target 未知, 该节点必须用 P-DAO-ACK 应答 Root, 在 RTO 中列出不可达 Target, 并给出拒绝状态 "Unreachable Target".

如果出口节点可以到达所有 Target, 它会按照 VIO 列表中的指示, 将内容不变的 P-DAO 转发给 segment 中的前驱节点. 随后, 该消息沿 P-DAO 中指示的路由器序列递归地不变传播, 但方向相反, 即从出口到入口.

作为传播 DAO 消息目标的前驱地址, 可在 Via Address 列表中位于传播节点地址之前的位置找到. 传播节点的地址用作该消息的源地址.

收到传播的 DAO 后, 除出口路由器外的所有节点都必须经由它们在 SM-VIO 中的后继节点安装到 DAO Target 的路由. 如果某路由器无法存储指向 P-DAO 中所有 Target 的路由, 它必须向 Root 发送 P-DAO-ACK 并使用拒绝状态 "Out of Resources" 来拒绝该 P-DAO, 而不是将 DAO 转发给列表中的前驱. 路由器可以安装指向 SM-VIO 中出现在自身地址之后的 Via Address 的额外路由, 如果存在这些地址. 但在发生冲突或资源不足时, 必须优先安装指向 Target 的路由.

如果某路由器无法到达其在 SM-VIO 中的前驱, 该路由器必须向 Root 发送 P-DAO-ACK, 并给出拒绝状态 "Predecessor Unreachable".

该过程持续到 P-DAO 被传播至 segment 的入口路由器. 入口路由器随后以 P-DAO-ACK 应答 Root. Root 始终预期收到 P-DAO-ACK, 该确认要么来自 Track 入口并带有肯定状态, 要么来自 segment 上任意节点并带有否定状态. 如果未收到 P-DAO-ACK, Root 可以使用相同 TrackID 重试 DAO, 或拆除该路由.

6.4.3. 使用 Non-Storing Mode P-Route 安装保护路径 (Installing a Protection Path with a Non-Storing Mode P-Route)

如图 19 所示, Non-Storing Mode P-DAO 在 P-DAO Base Object 指示的 Track 内安装到达 Target Options 中所示 Target 的源路由路径. 源路由路径需要 Source Routing Header, 这意味着需要 IP-in-IP 封装, 以便向现有数据包添加 SRH. 该 P-DAO 发送到 Track 入口, 入口创建一个与 Track 关联的隧道, 并通过该隧道建立到 RTO 中 Target 的连接路由. 隧道封装必须通过 VIO 中按相同顺序列出的地址纳入 Routing Header. Track 入口在封装数据包以沿 Track 转发时, 必须逐字使用 NSM-VIO 中从第一个 SRH-6LoRH 头部开始的内容.

              ------+---------
| Internet
|
+-----+
| | Border Router
| | (RPL Root)
+-----+ | P- ^ P-DAO-ACK
| Track | DAO |
o o o Ingress V |
o o o o o o X o X Source-
o o o o o o o X o o X Routed
o o o o o o X o X Segment
o o o o o o o o X X
Egress
o o o o o |
Target
o o LLN o
o o o o

图 19: 投射 Non-Storing 路由 (Projecting a Non-Storing Route)

源路由路径中的下一个条目必须是前一个条目的邻居, 或者可作为 Target 通过另一个 P-Route 到达, 该 P-Route 可以是 Storing 或 Non-Storing. 这意味着嵌套 P-Route 必须在松散序列之前安装, 且 P-Route 必须沿数据路径从最后一个到第一个安装. 例如, Track 的某个 segment 必须先于使用它的同一 Track 的保护路径安装. 拼接的 segment 必须按从最后一个到第一个的顺序安装, 以到达 Target.

如果松散序列中的下一个条目可通过 Storing Mode P-Route 到达, 则它必须是某个 segment 的 Target, 同时也是下一个 segment 的入口, 且两者都已建立. 这些 segment 与同一 Track 关联, 因而不需要额外封装. 例如, 在第 3.5.1.3 节中, 必须先用 Storing Mode P-DAO 消息 1 和 2 安装 segment A==>B-to-C 和 C==>D==>E-to-F, 然后才能用 Non-Storing Mode P-DAO 3 安装将它们连接起来的 Track A-->C-->E-to-F.

相反, 如果它可通过 Non-Storing Mode P-Route 到达, 则内部 Track 的下一个松散源路由跳是先前安装的 Track 的 Target, 同时也是下一个 Track 的入口. 这要求在切换连接松散跳的外层 Track 时执行解封装和重新封装. 第 3.5.2.3 节给出了示例, 其中 Non-Storing Mode P-DAO 1 和 2 安装严格 Track, 而 Non-Storing Mode P-DAO 3 将它们连接为 super Track. 在这种情况下, 数据包会受到双重 IP-in-IP 封装.

6.5. 拆除 P-Route (Tearing Down a P-Route)

生存期为 0 的 P-DAO 被解释为 No-Path DAO. 其功能是清理现有状态, 而不是刷新现有状态或安装新状态. 要拆除 Track, Root 必须逐一拆除组成该 Track 的所有 Track segment 和保护路径.

由于 Track 的保护路径状态只位于入口节点上, Root 通过向入口发送 NSM-VIO 来清理保护路径. 该 NSM-VIO 指示被删除保护路径的 TrackID 和 P-RouteID, Segment Lifetime 为 0, 并包含更新的 Segment Sequence. NSM-VIO 中带有 Via Address 的 SRH-6LoRH 不需要存在. 它不应放入消息中, 且接收方必须忽略它. 收到该 NSM-VIO 后, 入口节点删除该 Track 的所有状态, 如果存在这些状态, 并且无论如何都给出肯定回复.

Root 通过向 segment 的最后一个节点发送 SM-VIO 来清理 segment 的某个区段. 该 SM-VIO 带有更新后的 TrackID 和 P-RouteID, Segment Lifetime 为 0, 并包含更新的 Segment Sequence. SM-VIO 中的 Via Address 指示正在修改的 segment 区段, 从第一个受影响节点到最后一个受影响节点. 如果整个 segment 被完全删除, 这可以是整个 segment. 如果某个或多个节点已被 segment 更新绕过, 这也可以是一组节点序列.

No-Path P-DAO 沿反向列表正常转发, 即使中间节点找不到要清理的 segment 状态也是如此. 这会清理现有 segment 状态, 如果存在, 而不是刷新现有状态或安装新状态.

6.6. 维护 Track (Maintaining a Track)

为 Track segment 或保护路径重新选路可能导致抖动和数据包乱序. 对于要求及时和/或按序交付的关键流, 可能需要在高度冗余的 Track 上部署 PREOF [RAW-ARCH]. 本规范允许为一个 Track 使用多条保护路径以及 1+N 数据包冗余.

本节给出确保不会因操作本身而丢包的步骤. 这一点通过从新路径区段的最后一个节点到第一个节点安装该区段来保证. 因此, 当中间节点沿新区段安装路由时, 该区段中的所有下游节点已经安装了各自的路由. 当飞行中的数据包沿新区段转发后, 被禁用的区段也会被删除.

6.6.1. 维护 Track Segment (Maintaining a Track Segment)

为了在保留 segment 中第一个节点和第二个下游节点的同时修改它们之间的某个区段, 这两个节点可以分别是入口和出口, Root 向第二个节点发送 SM-VIO, 指示该 segment 新区段中的节点序列. SM-VIO 指示正在更新的 segment 的 TrackID 和 P-RouteID, 并包含更新的 Segment Sequence. P-DAO 从第二个节点传播到第一个节点. 在此过程中, 它会更新旧区段和新区段共有节点上的状态, 并在新节点中创建状态.

当中间节点中的状态被更新时, 该节点可能仍会收到从入口沿旧 segment 区段飞行到自身的数据包. 由于 segment 的剩余部分已经更新, 这些数据包从该节点开始沿新版 segment 转发.

经过一段合理时间后, Root 按第 6.5 节所述拆除旧 segment 的剩余区段, 以便被弃用的区段排空其流量.

6.6.2. 维护保护路径 (Maintaining a Protection Path)

本规范允许 Root 通过向入口发送 Non-Storing Mode P-DAO 来向 Track 添加保护路径, 该 P-DAO 与相同 TrackID 和新的 SegmentID 关联. 如果保护路径是松散的, 则必须先创建连接这些跳的 segment. 在删除一条变得过度丢包的保护路径之前添加新的保护路径, 并在删除旧保护路径之前切换到新保护路径, 是合理的做法. 在新 Track 安装前丢弃旧 Track 会使流量经由 Root 重新路由. 这可能使延迟增加到超过可接受阈值, 并使 Root 附近的网络过载. 对于拼接 Track, 这还可能导致环路: 无法注入第二个 Track 的数据包可能被路由回第一个 Track 的入口并重新注入.

也可以通过向入口发送 Non-Storing Mode P-DAO 来更新保护路径, 该 P-DAO 使用相同 SegmentID, 递增的 Segment Sequence, 以及 NSM-VIO 中新的完整跳列表. 更新活动保护路径意味着更改一个或多个中间松散跳, 并且需要在为新保护路径发出 NSM-VIO 之前, 布置通向和来自这些新松散跳的新 segment.

仍在旧版保护路径上飞行的数据包继续沿旧 segment 上的旧源路由路径转发. 经过一段合理时间后, Root 按第 6.5 节所述拆除这些 segment, 以便被弃用的 segment 排空其流量.

6.7. 沿 Track 封装和转发 (Encapsulating and Forwarding Along a Track)

将数据包注入 Track 时, 入口路由器必须使用 IP-in-IP 封装该数据包, 以添加 Source Routing Header, 并将最终目标设置为 Track 出口.

Track 操作的所有属性都继承自用于安装该 Track 的主 Instance. 例如, 是否按 [RFC8138] 使用压缩取决于 RPL 主 DODAG 中是否使用压缩, 例如通过在 RPL Configuration option 中设置 'T' 标志 [RFC9035].

当 Track 入口将数据包放入 Track 时, 它会用一个额外的 IPv6 头部, 一个 Routing Header, 以及一个包含 RPI 的 IPv6 Hop-by-Hop Option Header 进行封装, 如下所示:

  • 在未压缩形式中, 数据包的源是该路由器用作 Track 的 DODAGID 的地址, 目标是 NSM-VIO 中的第一个 Via Address, RH 是包含剩余 Via Address 列表的 SRH [RFC6554], 并以 Track 出口结尾.

  • 在使用 6LoWPAN 头部压缩 [RFC6282] 的网络中, 优先实现 "IPv6 over Low-Power Wireless Personal Area Network (6LoWPAN) Paging Dispatch" [RFC8025], 并按 [RFC8138] 所示压缩 RPL 构件.

    在这种情况下, RPL Source Route Header 是 NSM-VIO 中发现的 SRH-6LoRH 链的精确副本, 同样以 Track 出口结尾. 随后追加 RPI-6LoRH, 再后面是一个 IP-in-IP 6LoRH 头部, 该头部在 Encapsulator Address 字段中指示入口路由器. 见 [RFC8138] 图 20 中的类似情形.

为了在数据包中指示 Track, 本规范按如下方式利用 RPL 转发模型:

  • 在数据包中, Track DODAGID 和 TrackID 必须分别通过 IPv6 源地址以及 RPI 的 RPLInstanceID 字段指示, 且该字段必须放置在外层 IPv6 头部链中.

    RPI 携带名为 TrackID 的 Local RPLInstanceID. 它与 DODAGID 结合, 指示数据包沿哪个 Track 转发.

    RPLInstanceID 中的 'D' 标志必须设置为 0, 以指示 IPv6 头部中的源地址被设置为 DODAGID, 更多内容见第 6.3 节.

  • 关于沿 Track 的数据包转发和封装, 本规范符合 [RFC9008] 的原则, 如下所示:

    • 采用本规范时, Track 是一个 RPL DODAG. 从该 DODAG 的角度看, Track 入口是 Root, Track 出口是 RPL-Aware 6LR, 而能够通过 Track 到达但位于 Track 外部的 Track 出口邻居是外部目标, 并被视为 RPL-Unaware Leaves (RULs). [RFC9008] 中的封装规则适用.

    • 如果 Track 入口是数据包的发起者, 且 Track 出口是该数据包的目标, 则不需要封装.

    • 因此, Track 入口必须封装并非由自身发起的流量, 并且必须在封装中包含 RPI, 以指示 TrackID.

    正在关联到第一个 Non-Storing Mode Track 的 RPL Instance 上路由的数据包, 可以递归地放入第二个 Track, 以覆盖第一个 Track 的一个松散跳, 详见第 3.5.2.3 节. 另一方面, Storing Mode segment 必须是严格的, 放入 Storing Mode segment 的数据包必须沿该 segment 一直转发到 segment 出口.

通过封装中的源地址和 RPI 可以知道数据包沿 Track 转发. TrackID 用于标识与该 Track 关联的 RIB 条目. 在中间节点中, 这些条目对应于该转发路由器所知道的 Track segment 的 P-Route. 数据包处理使用如下优先级: 1) 如果存在 Routing Header, 先进行本地交付或 Routing Header 处理, 2) 交付给直接邻居, 3) 交付给间接邻居, 4) 沿 Track 的 segment 路由, 5) 作为最后手段将数据包注入另一个 Track.

为实现这一点, 数据包处理逻辑必须按以下顺序执行:

  • 如果数据包的目标是本节点:

    1. 如果头部链包含尚未完全消耗的 RPL Source Route Header, 则按 [RFC6554] 的规定沿 Track 转发该数据包, 这意味着 Routing Header 中的下一个条目成为目标.

    2. 否则, 如果该数据包已封装, 则对该数据包解封装, 并递归执行转发过程. 否则, 将该数据包交付给协议栈.

  • 否则, 数据包按如下方式转发:

    1. 如果数据包的目标是直接邻居, 例如通过 IPv6 Neighbor Discovery 安装, 则必须将该数据包转发给该邻居.

    2. 否则, 如果数据包的目标是间接邻居, 例如通过来自共同邻居的 multicast DAO 消息安装, 见第 4.1.4 节, 则必须将该数据包转发给该共同邻居.

    3. 否则, 如果存在同一 Track 的 RIB 条目, 例如通过 DAO 消息中的 SM-VIO 安装且目标作为 target, 并且 RIB 条目中的下一跳是直接邻居, 则将该数据包传递给该邻居.

    4. 否则, 如果存在不同 Track 的 RIB 条目, 例如通过 DAO 消息中的 NSM-VIO 安装且目标作为 target, 则对该数据包进行封装以沿该 Track 转发, 并递归执行转发过程. 否则, 丢弃该数据包.

    5. 为避免环路, 与未封装的数据包相反, 从 Track 解封装的数据包禁止沿主 DODAG 的默认路由转发. 这样做意味着端到端路径不受控制. 发现故障的节点必须丢弃该数据包.

在上述任一步骤中丢弃数据包的节点, 必须向 Root 发送 ICMPv6 错误消息 [RFC4443], 并使用新代码 "Error in P-Route", 见第 11.15 节. Root 随后可以通过更新损坏的 segment 和/或 Track 来修复. 对于损坏的 segment, Root 使用生存期为 0 的 SM-VIO 删除该 segment 遗留的区段, 指示正在删除一个或多个节点的区段, 见第 6.6 节.

如果源路由路径上发生永久性转发错误, 未能转发的节点应当按 [RPL] 第 11.2.2.3 节所述, 向数据包源发送带有代码 "Error in Source Routing Header" 的 ICMP 错误. 收到此消息后, 封装节点应当在一段合理时间内停止使用该源路由路径, 该时间取决于部署, 并且应当向 Root 发送带有代码 "Error in P-Route" 的 ICMP 消息. 不遵循这些步骤可能导致数据包丢失, 并在损坏的源路由路径上浪费资源.

无论哪种方式, 连续发生时 ICMP 消息都必须限速. 该消息的源必须是此 Track 中用于源节点的 ULA 或 GUA, 以便 Root 能够确定错误发生的位置.

在 ICMP 消息中返回的触发数据包部分应当至少记录到 RH, 如果存在 RH. 该 RH 的跳应当由此节点消耗, 使 IPv6 头部中的目标成为此节点无法到达的下一跳. 如果使用 6LoRH [RFC8138] 在外层头部中携带 IPv6 路由信息, 则完整的 6LoRH 信息应当出现在 ICMP 消息中.

6.8. RPL 构件压缩 (Compression of RPL Artifacts)

当 6LoWPAN LLN 中的主 DODAG 以 Non-Storing Mode 运行, 且数据包使用 [RFC8138] 压缩时, 在主 DODAG 中流通的典型数据包格式如图 20 所示, 表示需要 IP-in-IP 封装的情况, 见 [RFC9008] 表 19:

   +-+ ... -+- ... -+- ... -+-+- ... +-+-+-+ ... +-+-+ ... -+ ... +-...
|11110001| SRH- | RPI- | IP-in-IP | NH=1 |11110CPP| UDP | UDP
| Page 1 | 6LoRH | 6LoRH | 6LoRH |LOWPAN_IPHC| UDP | hdr |Payld
+-+ ... -+- ... -+- ... -+-+- ... +-+-+-+ ... +-+-+ ... -+ ... +-...
<= RFC 6282 =>
<================ Inner packet ==================== = =

图 20: 沿主 DODAG 转发的数据包 (A Packet as Forwarded Along the Main DODAG)

由于封装数据包与封装之间没有 page switch, 压缩数据包中充当页面选择器的第一个八位字节实际上会在封装时被移除. 因此, 以下描述中使用的内部数据包从 SRH-6LoRH 开始, 且正是图 20 中从第二个八位字节起表示的数据包.

在封装内部数据包以将其放入 Track 时, 入口首先在内部数据包头部追加一个 IP-in-IP 6LoRH 头部. 在该头部中, 封装器地址映射到未压缩形式中的 IPv6 源地址, 包含入口节点的 GUA 或 ULA IPv6 地址. 该入口节点充当 Track 的 DODAGID, 且该地址以主 DODAG 的 DODAGID 作为压缩参考, 用压缩形式表示. 如果该地址被压缩为 2 bytes, 则 Length 字段的结果值, 如图 21 所示, 为 3, 意味着整个 SRH-6LoRH 长度为 5 octets.

    0                   1                   2
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+- ... -+
|1|0|1| Length | 6LoRH Type 6 | Hop Limit | Track DODAGID |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+- ... -+

图 21: IP-in-IP 6LoRH 头部 (The IP-in-IP 6LoRH Header)

然后, Track 入口在生成的字节序列头部添加 P-RPI-6LoRH 头部, 以传输压缩形式的 RPI, 如图 12 所示. RPI 以 RPLInstanceID 形式携带 TrackID. 结合 IP-in-IP 6LoRH 头部, 这允许无歧义地标识 Track.

随后将 SRH-6LoRH 添加到生成的字节序列头部, 它是指示所选保护路径的 SM-VIO 内容的逐字副本.

    0                   1
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 .. .. ..
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+- -+- -+ ... +- -+
|1|0|0| Size |6LoRH Type 0..4| Hop1 | Hop2 | | HopN |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+- -+- -+ ... +- -+
Where N = Size + 1

图 22: SRH-6LoRH 头部 (The SRH-6LoRH Header)

生成的封装数据包按 [RFC8138] 采用压缩形式, 其格式如图 23 所示:

   +-+ ... -+-+-+- ... -+-+-+- ... -+-+-+-+-+- ... +-+-+-+-+-+-+- ...
| Page 1 | SRH-6LoRH | P-RPI-6LoRH | IP-in-IP 6LoRH | Inner Packet
+-+ ... -+-+-+- ... -+-+-+- ... -+-+-+-+-+- ... +-+-+-+-+-+-+- ...

Signals : Loose Hops : TrackID : Track DODAGID :

图 23: 沿 Track 转发的数据包 (A Packet as Forwarded Along a Track)