11. 分组转发和环路避免/检测 (Packet Forwarding and Loop Avoidance/Detection)
11.1. 分组转发建议 (Suggestions for Packet Forwarding)
本文档规定一种路由协议. 以下非规范性建议用于帮助设计转发实现, 通过说明此类实现可以如何与 RPL 协同工作来提供指导.
向目的地转发分组时, 按如下顺序优先选择下一跳后继:
-
本规范只覆盖如何从与被转发分组的 IPv6 头部中标记的 RPLInstanceID 匹配的 DODAG Version 中选择后继. 只要部署额外规则 (例如对实例和路由协议进行严格排序以防范环路), 就可以在实例之外进行路由. 此类规则可以在单独文档中定义.
-
如果本地管理偏好倾向于使用从 RPL 以外的其他路由协议学到的路由, 则使用该后继.
-
如果分组头部通过包含 [RFC6554] 中规定的 RH4 头部来指定源路由, 则使用该路由. 如果节点无法使用指定源路由转发该分组, 则应丢弃该分组. 节点 MAY 记录错误. 节点可以向该分组源发送 Source Routing Header 中的 ICMPv6 错误 (见第 20.18 节).
-
如果路由表中存在与目的地匹配且从组播目的地通告学到的条目 (例如目的地是一跳邻居), 则使用该后继.
-
如果路由表中存在与目的地匹配且从单播目的地通告学到的条目 (例如目的地位于 sub-DODAG 的 Down 方向), 则使用该后继. 如果有与多个后继关联的 DAO Path Control 位, 则在选择时查阅 Path Control 位以按偏好排列后继. 对于给定 DAO Path Control 位, 如果记录了多个后继都声明过该位, 则应优先选择最近声明该位的后继.
-
如果存在某个 DODAG Version 提供到匹配目的地的前缀的路由, 则根据 OF 和路由度量选择其中一个 DODAG 父节点作为后继.
-
当不存在更好匹配时, 可以选择任何其他尚未尝试的 DODAG 父节点作为下一次转发单播分组的尝试.
-
最后, 丢弃该分组. MAY 调用 ICMP Destination Unreachable (检测到不一致).
按 [RFC2460], 转发时 MUST 递减 Hop Limit.
注意, 所选后继 MUST NOT 是该分组的前驱邻居 (split horizon), 除非预期该分组从 Upward 方向改变为 Downward 方向. 这种改变由执行该改变的节点的路由表确定, 例如为了在接近目的地时继续朝目的地前进, 从 DIO 路由切换到 DAO 路由.
11.2. 环路避免和检测 (Loop Avoidance and Detection)
RPL 环路避免机制保持简单, 并被设计为尽量减少 churn 和状态. 环路可能因多种原因形成, 例如控制分组丢失. RPL 包含一种反应式环路检测技术, 用于防止崩溃并触发故障路径修复.
RPL 环路检测使用在数据分组中传输的 RPL Packet Information, 并依赖外部机制 (例如 [RFC6553]) 将 RPL Packet Information 放入 IPv6 Hop-by-Hop 选项头部.
RPL Packet Information 的内容定义如下:
-
Down 'O': 1 位标志, 指示预期分组向 Up 还是向 Down 前进. 当预期分组向 Down 前进 (使用 DAO 路由) 时, 路由器设置 'O' 标志; 当向 DODAG 根转发 (转发到 Rank 较低的节点) 时, 路由器清除该标志. 主机或 RPL 叶节点 MUST 将 'O' 标志设置为 0.
-
Rank-Error 'R': 1 位标志, 指示是否检测到 Rank 错误. 当相对 Rank 与 'O' 位指示的方向不匹配时, 检测到 Rank 错误. 主机或 RPL 叶节点 MUST 将 'R' 位设置为 0.
-
Forwarding-Error 'F': 1 位标志, 指示该节点无法继续向目的地转发该分组. 对于设置了 Down 'O' 位的分组, 如果子节点没有到目的地的路由, 则该子节点可能设置 'F' 位. 主机或 RPL 叶节点 MUST 将 'F' 位设置为 0.
-
RPLInstanceID: 8 位字段, 指示分组沿其发送的 DODAG 实例.
-
SenderRank: 16 位字段, 由源设置为零, 并由在 RPL 网络内部转发的路由器设置为 DAGRank(rank).
11.2.1. 源节点操作 (Source Node Operation)
如果源知道该分组首选的 RPLInstanceID, 则它 MUST 相应设置与该分组关联的 RPLInstanceID 字段; 否则, 它 MUST 将其设置为 RPL_DEFAULT_INSTANCE.
11.2.2. 路由器操作 (Router Operation)
11.2.2.1. 实例转发 (Instance Forwarding)
RPLInstanceID 由源与分组关联. 无论主机还是路由器, 任何节点放置该分组的 RPL Instance 都 MUST 与此 RPLInstanceID 匹配. RPLInstanceID 是 RPL Packet Information 的一部分.
在 RPL 网络中转发分组的 RPL 路由器 MUST 检查该分组是否包含 RPL Packet Information. 如果不包含, 则该 RPL 路由器 MUST 插入 RPL Packet Information. 如果该路由器是将分组注入 RPL 网络的入口路由器, 则该路由器 MUST 设置 RPL Packet Information 中的 RPLInstanceID 字段. 该路由器如何确定到 RPLInstanceID 的映射, 其细节超出本规范范围, 留待未来规范定义.
在 RPL 网络外转发分组的路由器 MUST 移除 RPL Packet Information.
当路由器收到指定了给定 RPLInstanceID 的分组, 且该节点可以沿与该实例关联的 DODAG 转发该分组时, 该路由器 MUST 这样做, 并保持 RPLInstanceID 值不变.
如果任何节点无法沿与 RPLInstanceID 关联的 DODAG 转发分组, 则该节点 SHOULD 丢弃该分组并发送 ICMP 错误消息.
11.2.2.2. DAG 不一致环路检测 (DAG Inconsistency Loop Detection)
如果分组方向与 Rank 关系不匹配, 则 DODAG 不一致. 接收方在收到以下任一分组时检测到不一致:
-
从 Rank 较高的节点收到设置了 'O' 位 (Down) 的分组.
-
从 Rank 较低的节点收到清除了 'O' 位 (Up) 的分组.
当 DODAG 根递增 DODAGVersionNumber 时, 下一个 DODAG Version 和先前 DODAG Version 之间可能形成临时 Rank 不连续, 特别是在节点正在调整其在下一个 DODAG Version 中的 Rank 并推迟迁移到下一个 DODAG Version 时. 仍是先前 DODAG Version 成员的路由器可以选择将分组转发给处于下一个 DODAG Version 中的 (未来) 父节点. 在某些情况下, 这可能导致该父节点检测到不一致, 因为先前 DODAG Version 中的 Rank 排序不一定与下一个 DODAG Version 中相同, 并且该分组可能被判断为没有取得前进进展. 如果发送路由器知道所选后继已经加入下一个 DODAG Version, 则发送路由器在跨越不连续进入下一个 DODAG Version 转发分组时, MUST 将 SenderRank 更新为 INFINITE_RANK, 以避免误检测 Rank 不一致.
路径上的一次不一致不视为严重错误, 分组可以继续. 但是, 同一分组沿路径第二次被检测到不一致不应发生, 且该分组 MUST 被丢弃.
此过程由与分组关联的 Rank-Error 位控制. 当在分组上检测到不一致时, 如果 Rank-Error 位未设置, 则设置 Rank-Error 位. 如果该位已设置, 则该分组 MUST 被丢弃, 并且 Trickle 计时器 MUST 被重置.
11.2.2.3. DAO 不一致检测和恢复 (DAO Inconsistency Detection and Recovery)
DAO 不一致环路恢复是一种仅适用于 Storing 运行模式的机制.
在 Non-Storing 模式下, 分组通过源路由被路由到目的地, DAO 不一致不会在本地纠正. 相反, 带有新 code "Error in Source Routing Header" 的 ICMP 错误会被发送回根. "Error in Source Routing Header" 消息具有与 [RFC4443] 中规定的 "Destination Unreachable Message" 相同的格式. 在 ICMP 消息中返回的触发分组部分至少应记录到路由头部, 并且该路由头部应被该节点消耗, 使 IPv6 头部中的目的地成为该节点无法到达的下一跳.
当路由器具有一条先前通过子节点从 DAO 消息学到的 Downward 路由, 但该 Downward 路由在子节点中不再有效时, 就会发生 DAO 不一致, 例如因为子节点中相关状态已被清理. 通过 DAO 不一致环路恢复, 分组可以用于递归探索并清理 sub-DODAG 沿途的过期 DAO 状态.
一般而言, 向 Down 的分组不应再次向 Up. 如果应用 DAO 不一致环路恢复, 则路由器 SHOULD 将该分组发回传递该分组的父节点, 并设置 Forwarding-Error 'F' 位且保持 'O' 位不变. 否则, 路由器 MUST 静默丢弃该分组.
收到设置了 Forwarding-Error 位的分组后, 节点 MUST 移除导致向该邻居转发的路由状态, 清除 Forwarding-Error 位, 并尝试再次发送该分组. 在用户可配置的实现特定计时器到期后, 该分组可以发送给备用邻居. 如果该备用邻居仍通过此节点具有不一致 DAO 状态, 则该过程会递归, 此节点会设置 Forwarding-Error 'F' 位, 备用邻居中的路由状态也会被清理.