跳到主要内容

7. 地址解析和邻居不可达检测

本节描述地址解析和 Neighbor Unreachability Detection. 地址解析是节点在仅知道邻居 IP 地址的情况下确定该邻居链路层地址的过程. Neighbor Unreachability Detection (NUD) 是跟踪到邻居路径的可达性状态的过程.

7.1. 地址解析

地址解析只对已确定为链路上的地址执行. 它绝不会对多播地址执行.

当节点有 IPv6 分组要发送时, 它首先检查 Destination Cache, 以确定该目的地的下一跳地址. 如果 Destination Cache 不包含该目的地的条目, 节点使用下一跳确定算法 (见 Section 5.2) 来确定下一跳地址.

一旦知道下一跳 IP 地址, 发送方就检查 Neighbor Cache, 获取关于下一跳的链路层信息. 如果不存在条目, 发送方会创建一个条目, 将其状态设置为 INCOMPLETE, 发起 Address Resolution, 并将数据分组排队等待地址解析完成.

对多播分组而言, 下一跳始终是 (多播) 目的地址, 并被认为位于链路上. 确定与多播 IP 地址对应的链路层地址的过程, 在描述如何在特定链路类型上运行 IP 的单独文档中规定 (例如 [IPv6-ETHER]).

对单播分组而言, 地址解析按如下方式执行. 发送方为下一跳地址创建 Neighbor Cache 条目 (如果尚不存在), 将其状态设置为 INCOMPLETE, 并通过向与目标地址对应的 solicited-node multicast address 发送 Neighbor Solicitation 消息来发起地址解析. 该 solicitation 从分配给发送该 solicitation 的接口的地址发送.

Neighbor Solicitation 的 Target Address 被设置为下一跳地址. 如果发送方拥有分配给发送 Neighbor Solicitation 的接口的地址,应该包含 Source Link-Layer Address 选项. 如果发送方没有分配给发送该 solicitation 的接口的地址 (例如在初始化期间), 发送方不得包含 Source Link-Layer Address 选项.

在等待地址解析完成期间, 发送方必须为每个邻居保留一个小型队列, 存放等待地址解析完成的分组. 队列必须至少保存一个分组,可以包含更多分组. 但是, 每个邻居排队分组的数量应该限制为某个较小值. 一旦地址解析完成, 节点会发送所有排队分组.

在等待地址解析完成期间, 发送方继续发送 Neighbor Solicitation. 用于地址解析的 Neighbor Solicitation 每 RetransTimer 毫秒发送一次, 直到收到 Neighbor Advertisement, 或已发送最大数量的 Neighbor Solicitation (MAX_MULTICAST_SOLICIT) 为止. 如果在 MAX_MULTICAST_SOLICIT 次 solicitation 后仍未收到 Neighbor Advertisement, 地址解析失败. 发送方必须释放该分组的任何缓存副本, 并且应该对每个因等待地址解析而排队的分组返回 code 3 (Address Unreachable) 的 ICMP destination unreachable indication.

7.2. Neighbor Unreachability Detection

7.2.1. 可达性确认

如果节点最近收到确认, 表明最近发送给邻居的分组已被该邻居的 IP 层接收, 则认为该邻居可达. 正向确认可以通过两种方式收集: 来自上层协议的提示, 指示连接正在取得 "forward progress", 或收到作为 Neighbor Solicitation 响应的 Neighbor Advertisement 消息.

如果从远端对等体收到的分组只能在最近发送给该对等体的分组实际到达它时才会到达, 则连接取得了 "forward progress". 例如在 TCP 中, 收到一个 (新的) acknowledgement 表示先前发送的数据已到达对等体. 同样, 新的 (非重复) 数据到达表示先前的 acknowledgement 正在到达远端对等体. 如果分组正在到达对等体, 它们也必然正在到达对等体的 IP 层, 这正是 Neighbor Unreachability Detection 的要求.

对链路外目的地而言, forward progress 意味着第一跳路由器可达. 当存在这种确认时, 实现可以更新第一跳路由器的 Neighbor Cache 条目, 并将其可达性状态设置为 REACHABLE. 如果实现不跟踪 forward progress, 当持续从远端对等体接收分组时, 它应该假定正在取得 forward progress.

Neighbor Unreachability Detection 与正在发送分组的应用并行运行. 向邻居发送分组并不确认其可达性; 收到相应 acknowledgement 才确认. 实现不得仅因某个邻居正在被主动使用就断定该邻居可达.

当节点需要对邻居地址执行地址解析, 但已经存在该地址的 STALE 状态 Neighbor Cache 条目时, 节点将状态更新为 DELAY 而不是 INCOMPLETE, 并发送 Neighbor Solicitation 以确认可达性. 然后节点等待 DELAY_FIRST_PROBE_TIME 秒. 如果在此期间未收到可达性确认, 该条目的状态改为 PROBE, 并开始 Neighbor Unreachability Detection.

7.2.2. Neighbor Cache 条目状态

对于正在发送流量的邻居, 其 Neighbor Cache 条目可以处于五种可能状态之一:

INCOMPLETE - 正在对此条目执行地址解析. 具体来说, 已向目标的 solicited-node multicast address 发送 Neighbor Solicitation, 但尚未收到对应的 Neighbor Advertisement.

REACHABLE - 最近 ReachableTime 毫秒内收到正向确认, 表明到该邻居的前向路径工作正常. 在 REACHABLE 状态下, 发送分组时不执行特殊动作.

STALE - 自上次收到表明前向路径工作正常的正向确认以来, 已经过超过 ReachableTime 毫秒. 在 stale 状态下, 直到发送分组才执行动作.

收到更新缓存链路层地址的 unsolicited Neighbor Discovery 消息时进入 STALE 状态. 收到此类消息并不确认可达性, 进入 STALE 状态可确保路径故障被快速检测. 但是, 直到使用该条目时才真正验证可达性.

DELAY - 自上次收到表明前向路径工作正常的正向确认以来, 已经过超过 ReachableTime 毫秒, 且最近 DELAY_FIRST_PROBE_TIME 秒内发送过分组. 如果进入 DELAY 状态后的 DELAY_FIRST_PROBE_TIME 秒内未收到可达性确认, 则发送单播 Neighbor Solicitation 并将状态改为 PROBE.

DELAY 状态是一种优化, 用于在由于近期无流量导致自上次确认以来已超过 ReachableTime 毫秒的情况下, 给上层协议更多时间来提供可达性确认. 没有此优化时, 在流量空闲后打开 TCP 连接会发起探测, 即使随后的 three-way handshake 几乎会立即提供可达性确认.

PROBE - 通过每 RetransTimer 毫秒重传单播 Neighbor Solicitation 主动寻求可达性确认, 直到收到可达性确认或已发送最大数量的探测 (MAX_UNICAST_SOLICIT) 为止. 如果发送 MAX_UNICAST_SOLICIT 次 solicitation 后仍未收到响应, 重传停止, 该条目应该被删除. 后续到该邻居的流量将重新创建条目并再次执行地址解析.

注意, 所有 Neighbor Solicitation 都按每个邻居进行速率限制. 节点不得以高于每 RetransTimer 毫秒一次的频率向同一目标发送 Neighbor Solicitation.

7.2.3. 节点行为

Neighbor Unreachability Detection 算法的运行方式取决于该条目是否正在用于转发分组.

收到可达性确认时 (通过上层建议或 solicited Neighbor Advertisement), 条目的状态变为 REACHABLE. 唯一例外是, 上层建议对 INCOMPLETE 状态的条目无效 (例如尚未缓存链路层地址的条目).

当节点向处于 STALE 状态的邻居发送分组时, 节点将该条目的状态更新为 DELAY, 并设置一个在 DELAY_FIRST_PROBE_TIME 秒后到期的定时器. 如果定时器到期时该条目仍处于 DELAY 状态, 条目的状态变为 PROBE, 并发送一个单播 Neighbor Solicitation. Neighbor Solicitation 使用缓存的链路层地址发送. 后续 solicitation (如果有) 使用同一缓存链路层地址发送. Neighbor Solicitation 每 RetransTimer 毫秒重传一次, 直到收到可达性确认或已发送 MAX_UNICAST_SOLICIT 次 solicitation 为止.

如果收到响应单播 Neighbor Solicitation 的 Neighbor Advertisement, 且该 Neighbor Advertisement 的 Solicited flag 已置位, 条目的状态变为 REACHABLE. 如果 Solicited flag 未置位, 条目保持 PROBE 状态.

如果在 PROBE 状态收到可达性确认, 条目的状态变为 REACHABLE. 如果已发送最大数量的探测但未收到可达性确认, 该条目应该被删除, 未来到该邻居的流量将需要再次执行地址解析. 实现可以随时垃圾回收陈旧条目. 但是, INCOMPLETE 状态的条目不应该在地址解析失败前删除 (即已发送 MAX_MULTICAST_SOLICIT 次 Neighbor Solicitation 且未收到响应).

7.3. Neighbor Unreachability Detection 协议

本节概述 Neighbor Unreachability Detection 算法如何运行.

7.3.1. 可达性确认事件

以下事件会使缓存的链路层地址被重新确认为 REACHABLE:

  1. 收到某个条目的 solicited Neighbor Advertisement, 且该条目不是 INCOMPLETE 状态.

  2. 收到某个条目的上层可达性确认 (例如正向 TCP acknowledgement), 且该条目不是 INCOMPLETE 状态.

  3. 对处于 STALE, DELAY 或 PROBE 状态的条目, 发送 Neighbor Solicitation 并收到 solicited Neighbor Advertisement.

7.3.2. 状态转换

状态转换如下:

INCOMPLETE -> REACHABLE: 收到包含 Target Link-Layer Address 选项的有效 Neighbor Advertisement 时.

INCOMPLETE -> (deleted): 地址解析失败时 (即已发送 MAX_MULTICAST_SOLICIT 次 Neighbor Solicitation 且无响应).

REACHABLE -> STALE: ReachableTime 毫秒过去且未收到可达性确认时.

STALE -> DELAY: 向处于 STALE 状态的邻居发送分组时.

STALE -> REACHABLE: 收到可达性确认时.

DELAY -> PROBE: DELAY_FIRST_PROBE_TIME 秒过去且未收到可达性确认时.

DELAY -> REACHABLE: 收到可达性确认时.

PROBE -> REACHABLE: 收到可达性确认时.

PROBE -> (deleted): 已发送 MAX_UNICAST_SOLICIT 次探测且未收到可达性确认时.

7.3.3. 发送 Neighbor Solicitation

为 Neighbor Unreachability Detection 目的发送 Neighbor Solicitation 消息时, 适用以下规则:

  • Neighbor Solicitation 的 Target Address 必须设置为正在确认其可达性的邻居的 IP 地址.

  • Neighbor Solicitation 必须作为单播分组使用缓存的链路层地址发送.

  • Neighbor Solicitation 的 Source Address 必须是分配给发送 Neighbor Solicitation 的接口的地址.

  • Neighbor Solicitation 应该包含 Source Link-Layer Address 选项.

7.3.4. 接收 Neighbor Solicitation

收到 Neighbor Solicitation 时, 接收方检查自己是否为该 solicitation 的目标. 如果是, 接收方应该为发送方创建或更新 Neighbor Cache 条目. 如果发送方的 Neighbor Cache 条目已存在, 接收方会更新该条目的链路层地址 (如果不同), 并按如下方式设置该条目的状态:

  • 如果条目处于任何状态且收到的 Neighbor Advertisement 中 Override flag 已置位, 则更新该条目的链路层地址.

  • 如果条目处于 INCOMPLETE 状态, 则将其链路层地址设置为 Source Link-Layer Address 选项中的值 (如果存在), 并将状态设置为 STALE.

  • 如果条目处于 INCOMPLETE 以外的任何状态, 且收到的 Source Link-Layer Address 不同于缓存的链路层地址, 并且 Override flag 已置位, 则用收到的地址替换缓存的链路层地址, 条目的状态保持不变.

7.4. 发送 Neighbor Advertisement

节点响应 Neighbor Solicitation 时发送 Neighbor Advertisement, 也会在其链路层地址变化时发送 unsolicited Neighbor Advertisement.

7.4.1. 响应 Neighbor Solicitation

收到 Neighbor Solicitation 时, 目标节点应该以 Neighbor Advertisement 响应. 如果 Neighbor Solicitation 的源地址不是 unspecified address, Neighbor Advertisement 会发送到该源地址; 否则, Neighbor Advertisement 会发送到 all-nodes multicast address.

Neighbor Advertisement 的 Target Address 从 Neighbor Solicitation 的 Target Address 复制. 如果 Neighbor Advertisement 是响应 Neighbor Solicitation 而发送, Solicited flag 设置为一; 否则设置为零.

如果 Neighbor Solicitation 中包含 Target Link-Layer Address 选项, 且链路层地址不同于接收节点的链路层地址, Override flag 设置为一; 否则按具体情况设置.

7.4.2. Unsolicited Neighbor Advertisement

节点可以发送 unsolicited Neighbor Advertisement 来宣布其链路层地址变化. 当节点检测到其链路层地址已改变时 (例如热插拔 Ethernet 接口之后), 它应该向 all-nodes multicast address 组播少量 Neighbor Advertisement, 以快速更新邻居的 Neighbor Cache 条目.

对 unsolicited Neighbor Advertisement 而言, Override flag 应该设置为一, 以确保邻居更新其缓存的链路层地址. Solicited flag 必须在 unsolicited Neighbor Advertisement 中设置为零.