摘要

  • IPv6 邻居不可达检测把“可达”限定为一个需要近期正向证据的判断。证据超过有效时间后,邻居缓存只会转为 STALE;如果没有数据要发,协议既不删除条目,也不制造探测流量。
  • STALE 条目第一次被使用时进入 DELAY,先等待上层通信自然证明路径仍在前进;只有等不到确认才进入 PROBE。RFC 7048 后来又用 UNREACHABLE 与指数退避,把“应当尝试其他下一跳”和“彻底放弃这个邻居”拆成两项决定。

STALE 描述的是证据年龄

一台主机刚才还通过默认路由器通信,随后安静了一段时间。邻居缓存仍保存路由器的 IPv6 地址和链路层地址,没有新报文否定这组映射,也没有链路事件宣布故障。发生变化的只有一件事:上一次证明转发路径有效的证据已经不够新。

IPv6 将这种状态命名为 STALE。这个词在运维界面里很容易被读成“坏掉了”,但协议含义更窄。RFC 1970 在 1996 年首次标准化 IPv6 Neighbor Discovery 时,就把 Neighbor Unreachability Detection(NUD)列为基础机制;RFC 2461 和后来的 RFC 4861 保留了同一条证据链。

当距离上一次正向确认超过 ReachableTime,REACHABLE 变为 STALE。但只要没有报文使用这个邻居,协议就不采取动作。从正确性看,一个不用的旧条目甚至可以长期留在缓存里。内存不足时可以另行回收,可“因为资源被回收”与“因为路径被证明失败”不是同一个事实。

能收到邻居的报文,不等于能把报文送到邻居

NUD 关心的是发送方眼中的正向路径。一份 Router Advertisement 抵达主机,只能证明路由器到主机这一方向刚刚通过;一份未被请求的 Neighbor Advertisement 也是如此。它们不能证明主机刚发出的报文到达了邻居的 IP 层。

因此,规范只接受两类正向确认。第一类是对本机 Neighbor Solicitation 作出的 solicited Neighbor Advertisement:请求必须先到邻居,回答再返回,两个方向都留下了证据。第二类来自能够证明“通信在前进”的上层协议。

TCP 给出了最直观的例子。新的确认号意味着早先的数据已经到达对端;新的、非重复数据也可能说明此前的 ACK 送到了对端。若目的地不在本链路,这种进展也间接证明第一跳路由器最近确实转发了流量。UDP 或只负责转发的路由器未必能获得同样的上层提示,所以仍需要主动探测。

这种确认没有越权。它不认证邻居身份,不保证应用健康,也不承诺未来可用。它只回答一个足以支持本地转发的问题:这条通向下一跳的正向路径,最近是否实际工作过?

第一个真实报文先获得发言权

条目变为 STALE 后,下一次发送仍使用缓存中的链路层地址,同时把状态改为 DELAY。RFC 4861 的默认等待时间是五秒。

这五秒不是盲等,而是给普通通信一个低成本作证的机会。比如,沉寂之后新建 TCP 连接,握手很可能立即产生足够的上层进展。若确认在 DELAY 期间出现,条目直接回到 REACHABLE,不必额外发送邻居探测。

若等待期结束仍无证据,节点才发送单播 Neighbor Solicitation 并进入 PROBE。选择单播,是因为链路层映射仍然已知;此时要验证的是“这条已知路径还能否工作”,而不是重新询问“谁拥有这个 IPv6 地址”。后一个问题才需要组播地址解析。

这套顺序让怀疑的成本跟随使用发生。时间只降低置信度,流量才让怀疑变得紧迫,DELAY 先利用现成的业务信号,PROBE 最后才付出控制报文成本。

30 秒也不是所有节点共同敲响的钟

RFC 4861 给出 30 秒的基础可达时间、1 秒的重传定时器、5 秒的首次探测延迟和默认 3 次单播请求。但实际 ReachableTime 会在基础值的 0.5 到 1.5 倍之间随机取值。Router Advertisement 还可以提供非零的基础可达时间和重传时间。

随机化避免同一链路上的大量设备同时让证据过期、同时探测。它也说明,“30 秒后死亡”从来不是协议规则。

路由器可以通过通告影响计时参数,却不能用通告本身证明可达。谁能调整证据保鲜期,与什么事实能构成正向证据,被有意分开了。

三次快速探测有时制造更多故障

在 RFC 4861 的原始概念状态机中,PROBE 按 RetransTimer 发送单播请求;达到上限仍无回答,就删除邻居缓存条目。采用默认值时,这意味着间隔一秒的三次发送。之后,主机可以改选另一个路由器,或者通过组播重新解析直连邻居。

存在多个独立默认路由器时,迅速转移很有价值。若只有唯一下一跳,短暂的二层中断可能轻易超过这个窗口。删除条目不会凭空产生替代路径,反而会把定向单播探测变成更昂贵的组播发现。

RFC 6583 展示了这类反馈如何伤害真实业务。IPv6 /64 中几乎无限的空地址可以诱发大量地址解析;如果这些新建请求挤掉了对既有邻居的 NUD 维护或对探测的回答,正在使用的条目会被清除,随后产生更多组播解析,已有流量也会中断。因此,它建议让面向活跃目的地的 NUD 工作优先于对可能不存在邻居的试探。

2014 年的 RFC 7048 直接把问题称作“NUD 太心急”。它引入概念状态 UNREACHABLE。达到原来的失败阈值后,条目不再被视为“已知可达”,下一跳选择可以试用其他路由器;但缓存仍可保留链路层地址,在没有更好路径时继续发送,并以指数退避方式继续探测。

探测最终要切换到组播,以发现对方是否更换了链路层地址;若已经没有报文使用该条目,则可停止探测。RFC 7048 的示例在第 1、4、13、40 秒安排重试,并给出 60 秒作为可能的最大间隔。它是一种合规算法示例,不是所有设备的实测默认值。

UNREACHABLE 把改选与放弃拆开

更新的关键不是单纯“多等几秒”,而是承认两个问题不应共享一个答案:是否应当优先选择其他下一跳?是否应当停止尝试当前邻居?

若有独立的替代路由器,前者需要快;若当前邻居是唯一出口,后者应当更有耐心。生成树收敛、短暂无线丢失或接口恢复都可能比三秒更久。指数退避既保留恢复机会,又避免持续轰炸链路。

证据标准没有因此降低。solicited 回答或可靠的上层进展仍能让状态恢复为 REACHABLE,未被请求的通告仍然不能。RFC 7048 改的是探测失败之后的处置,不是什么可以冒充成功。

DAD 使用相同报文,回答不同问题

RFC 4862 也用 Neighbor Solicitation 和 Neighbor Advertisement 做重复地址检测。报文相同,不代表判断相同。

DAD 发生在单播地址正式分配之前,询问候选地址是否已有其他节点使用;NUD 发生在一个邻居已经被选中并承载流量之后,询问缓存映射所指向的正向路径是否还工作。DAD 中的有界沉默可以让 tentative 地址投入使用。NUD 中的沉默只让证据变旧,之后还要由实际使用触发 DELAY 与 PROBE。

二者都不证明身份,也不授予所有权。其可靠性来自把观察范围和状态后果限制得足够清楚。

来源与证据边界

历史与状态机来自 RFC 1970、2461 和 4861。RFC 4862 划清 DAD 边界,RFC 6583 记录控制面压力,RFC 7048 修订恢复行为。这些文件不能证明当前厂商默认值、部署比例、缓存规模、故障率或任何具名网络的合规情况。