摘要

  • 9 月 4 日发布的 FreeBSD GRAND 实现说明,回顾的是 3 月已提交的代码工作,并非宣布 9 月推出新版本。
  • 后续提交把主动通知与延迟回复的计数、保留和替换规则区分开来;这比“支持提前发现地址”更值得运维验收关注。

一项优化最容易展示的,通常是它成功的那一次。新地址刚配置好,通知已经送达,路由器有了映射,首个回程包不必再等一次组播查询。困难的部分在旁边:别的请求也在等待回复,地址可能又变了,先前排队的通知究竟该保留、替换,还是取消?

Seyed Pouria Mousavizadeh Tehrani 在 9 月 4 日的 RIPE Labs 文章中说明了 FreeBSD 对 Gratuitous Neighbor Discovery(GRAND)的实现。它处理的是一个方向不对称的问题:IPv6 主机已经知道默认路由器的链路层地址,可以向外发包;路由器却可能还不知道如何把返回流量交给主机刚启用的全局地址。

这时,路由器必须先解析邻居地址。等待期间的缓存有限,连接开头便可能出现延迟或丢包。让主机主动提供映射,可以把部分工作提前,但不能只实现“发出通知”这一半。

队列里装的是不同的责任

新闻日期必须与代码日期分开。初始提交发生在 3 月 5 日,加入新全局地址完成重复地址检测后的通知、链路层地址变化处理以及排队机制。3 月 19 日提交的后续调整,则明确区分 GRAND 和延迟发送的请求回复。

后续提交说明提出:同一接口地址已有待发的 GRAND 通知时,取消旧项并复用其存储;非 GRAND 回复不沿用通知发送后的额外保留时间;计算 GRAND 限额时,不把非 GRAND 项算进去。这里不是说正常回复不受任何资源约束,而是说一类消息的限额不应自动成为另一类消息的限额。

这种区别有实际含义。新通知可能取代关于同一地址的旧通知;另一条回复却可能对应另一位请求者。只因为两者都叫 Neighbor Advertisement,就把它们当成可以互相覆盖的重复工作,会掩盖取消操作究竟取消了什么。这个判断是对设计取舍的分析,并非本文发现了某次生产故障,也不代表已经验证了补丁中的所有并发交错。

共用队列基础设施,不等于所有消息采用相同策略。它也不代表存在两条物理网络路径,更不意味着回复获得了绝对优先级。值得核查的是:在主动通知密集出现时,本来就该回答的请求是否仍按自己的规则得到处理。

对方收到、接受并保留,提前通知才有用

RFC 9131在 2021 年给出了协议层面的改动:主机提供新全局地址信息,路由器对携带所需链路层信息的有效通告建立原本不存在的邻居缓存项,状态设为 STALE。它没有把主动通告变成已确认可达的证明,也没有推翻已有缓存项的全部处理规则。

这需要发送端和接收端配合。主机发了消息,不能证明消息到达;消息到达,也不能证明路由器采用了相应的新建表项行为。重复通知需要间隔,目标是第一跳路由器,而不是用无限广播换取安心。

更早的 RFC 4861已经规定了多地址通告的发送节奏,以及任播、代理回复的延迟考虑。通知丢失本来就是必须容纳的情况。队列和定时器不是写在协议旁边的细枝末节,而是优化如何与共享链路相处的一部分。

还有两个直接的反例:通知成功后,路由器清空了缓存;地址长时间不用,表项被回收,随后又开始通信。RFC 9131 明确承认这些情况仍可能留下地址解析缺口。因此,GRAND 不能替代普通邻居发现、缓冲和后续可达性检查。

合理的验收应把新地址通知与延迟回复混在一起观察,还应覆盖排队期间删除地址、通知未送达、缓存清空,以及适用时的多第一跳路由器。它们是本文提出的检查问题,不是已经运行的实验。本文没有安装或编译 FreeBSD,没有进行抓包或性能测试,也不据此断言任何发行版本的覆盖率、时延收益或故障发生率。

这次说明的价值,在于把一个小优化背后的维护工作摊开了:提前完成某项工作,不能靠悄悄改变另一项工作的待遇来实现。