目的地址变成 IPv6 后,主机还会广播 ARP 查询网关吗?一个接口已经有 fe80:: 开头的地址,是否说明它拿到了可跨网络通信的地址?收到路由器通告,又是否等于同时获得地址、直连前缀和默认路由?

这些问题不能仅用“地址从三十二位增加到一百二十八位”回答。第 07 篇建立了前缀与下一跳的关系,本篇保持这一关系,观察 IPv6 如何表达地址范围、发现邻居和取得配置。真实实验使用静态地址,SLAAC 与路由器通告另以规范和条件表解释。

地址文本与作用范围

IPv6 地址通常写成八组十六位十六进制数。连续的零可以按规则压缩,但压缩只改变文本表示,不改变地址本身。例如 2001:db8:8:1::2 与展开后的八组写法是同一个一百二十八位值;前缀长度仍表示固定多少位。

本篇的 2001:db8:8:1::/642001:db8:8:2::/64 是两个不同的文档示例地址块,来自 RFC 3849 保留的范围,仅用于隔离实验。不会把它们配置到公网,也不因名字中出现 IPv6 就声称它们可被全球路由。

RFC 4291 §2.5.6定义链路本地地址范围 fe80::/10。这类地址用于所在链路的通信,路由器不得将源或目的为链路本地地址的报文转发到另一条链路。它可以作为相邻路由器的下一跳地址,却不是跨越多个网络的最终服务地址。

同一台主机有多个接口时,不同链路上都可能存在 fe80::1fe80::1%eth0 中的 %eth0 为本地操作提供作用域选择,不属于在线 IPv6 地址的一百二十八位。RFC 4007 §11讨论这种 zone 标识;把带百分号的文本直接当成报文字段会混淆两种表示。

邻居发现不是 ARP 换一种地址

IPv6 通过邻居发现协议 NDP 完成地址解析等工作。Neighbor Solicitation(NS)和 Neighbor Advertisement(NA)是 ICMPv6 消息,类型分别为 135、136;NDP 还包括路由器发现和邻居可达性检测,范围比单纯取得 MAC 更广。

在冷邻居解析的典型以太网场景中,发送者将 NS 发往由目标地址导出的 solicited-node multicast 地址。这个目标是当前下一跳,而不一定是数据报的最终目的地。第 06 篇中“先选路由,再解析下一跳”的关系仍然成立,变化的是链路上的协议交换。

RFC 4861 §7.2.2说明解析时的请求过程。后续可达性探测可以采用单播,因此不能把每个 NS 都描述成多播,也不能因为看到 NS 就认定它一定来自空邻居缓存。

假设默认下一跳为 fe80::1,其低二十四位是 00:00:01,相应 solicited-node multicast 为 ff02::1:ff00:1。在以太网上,RFC 2464 §7规定 IPv6 多播映射到 33:33 加目的 IPv6 地址的低三十二位;这个例子对应 33:33:ff:00:00:01

1
2
3
4
5
数据报最终目的:2001:db8:8:2::2
路由选定下一跳:fe80::1,出口 eth0
NS Target: fe80::1
NS IPv6 目的: ff02::1:ff00:1
NS 以太网目的:33:33:ff:00:00:01

以上先给出字段推导。它不能替代抓包,尤其不能证明某个目标已回应;真实观察还需对照 NA、邻居表和后续应用回包。

通告中的三个独立判断

Router Advertisement(RA)可以携带默认路由器信息与 Prefix Information Option(PIO)。收到同一份消息,并不意味着里面的所有信息只有一个开关。

RA 的 Router Lifetime 表示发送者作为默认路由器的有效期。PIO 的 L 位影响 on-link 前缀信息,A 位影响无状态地址自动配置 SLAAC。前缀自身还有相关有效期;不能把 Router Lifetime 当成整份通告里所有状态的共同到期时间。

RFC 4861 §4.2、§4.6.2分别定义这些字段。特别是 L=0 并不宣布该前缀一定在链路之外,它只是没有通过这一位作出 on-link 声明。其他已有信息仍可能影响判断。

设接口没有此前的相关状态,收到语法与来源检查均合格的 RA,PIO 前缀及寿命也满足处理条件,可以按下表分别推演:

输入条件 从这些字段能推导的变化 不能直接推出的结论
Router Lifetime 为正 发送者可进入默认路由器选择相关状态 PIO 必然用于生成地址
Router Lifetime 为零 不将发送者作为有效默认路由器保留 PIO 的信息也全部失效
L=1、A=0 可以提供 on-link 信息,不依此生成 SLAAC 地址 接口已取得该前缀下的自动地址
L=0、A=1 可参与 SLAAC 条件检查,没有据此声明 on-link 该前缀必然 off-link
L=1、A=1 分别处理 on-link 与地址配置 地址立刻可用、外部网络已经可达

这是一张协议条件表,不是本次运行的 RA 实验结果。它刻意省略已有状态更新、寿命防护及多路由器选择,使用前提不能从表中删除。

SLAAC 与重复地址检测

SLAAC 不能简化为“收到任意前缀就拼上 MAC”。RFC 4862 §5.5.3要求检查 A 位、前缀与接口标识长度、寿命等条件。地址形成方式与接口标识策略也有关,不应把所有 IPv6 地址都写成由 MAC 直接推导。

一个地址被加入接口配置后,还可能处于 tentative 状态。重复地址检测 DAD 用于检查拟使用地址是否出现冲突;它与正常通信时解析下一跳并非同一个目的。看到 NS 时,应结合源地址、Target 和地址状态判断用途,不能把 DAD 请求统计成应用流量触发的解析。

RFC 4862 §5.4的 DAD 也涉及手动配置的单播地址,并存在禁用等例外。因此“只有自动配置才需要 DAD”和“任意系统永远会执行 DAD”都过于绝对。检测没有发现冲突,也不保证此后永远不会发生地址冲突。

本篇脚本等待实验地址不再 tentative,再开始应用发送。它不通过关闭 DAD 来回避等待,但也没有注入重复地址;等待通过只说明这次启动条件满足,不能宣称已测试冲突处理分支。

隔离的 IPv6 转发路径

沿用第 06 篇的三节点形状,为两条链路配置不同的 IPv6 前缀。A、B 的默认路由使用各自链路上 R 的链路本地地址。即使两个出口旁都写 fe80::1,它们也位于不同链路。

1
2
3
4
A                                  R                                B
2001:db8:8:1::2/64 ─── 2001:db8:8:1::1/64
2001:db8:8:2::1/64 ─── 2001:db8:8:2::2/64
默认经 fe80::1 dev eth0 默认经 fe80::1 dev eth0

附件 lab.py 在专用 Linux 虚拟机内创建自己的网络命名空间和 veth,转发设置只作用于 R 的命名空间。没有修改宿主默认路由,也不接入物理接口或生产网络。复跑需要该环境已有 Python 与 iproute2,以及相应网络管理权限。

1
sudo python3 source/_posts/2026-09-19-计算机网络08-IPv6改了什么/lab.py

程序保存路由、邻居表和原始帧,以自建 UDP 服务回显作为本次应用往返检查。抓包解码只面向脚本产生的已知报文格式,不是能处理任意扩展首部的通用 IPv6 分析器。

本次捕获与邻居表

完整记录见 run.jsonl。本次运行环境为 Linux 6.18.10-200.fc43.aarch64、Python 3.14.3、iproute2 6.14.0。脚本手动设置链路本地地址,并用 addrgenmode none 避免再生成额外地址;这与关闭 DAD 不同。

初始表并不是整个空数组:其中已有 ff02::16ff02::2ff02::1:ff00:2 三个多播映射,状态为 NOARP。查询路由后的表相同。这些条目没有证明网关已经解析;本实验应检查的条件是没有单播邻居,尤其没有 fe80::1 的已解析映射。

NOARP 是 Linux 邻居状态名称,不能因名字中有 ARP 就说这次 IPv6 使用了 ARP 协议。过滤多播只是为了验证冷单播解析的前提,原始日志仍保留全部条目,避免隐藏观察范围。

本次观察 结果
路由查询 下一跳 fe80::1,出口 eth0
NS Target 为 fe80::1,IPv6 目的为 ff02::1:ff00:1
NS 的 Ethernet 目的 33:33:ff:00:00:01
发出的 UDP 数据帧 IPv6 目的为 2001:db8:8:2::2,MAC 目的为 R 的 02:00:00:00:08:01
应用与最终单播邻居 20 字节回显相等;唯一单播邻居为 fe80::1,状态 REACHABLE

原始记录共四帧:NS、NA、UDP 请求与回显。NA 的 Target 同样为 fe80::1。包字段、邻居变化与回显载荷相互对应,说明的是这一次隔离转发过程;单独一个 NA 不能证明远端应用完成了处理。

脚本结束时停止自己创建的子进程,删除本次三个命名空间并核对清理结果。没有执行全局清理,也没有改写其他命名空间。

双栈与分片职责

双栈表示环境可以分别运行 IPv4 与 IPv6,不表示一个族成功就能证明另一个族成功。地址来源、路由、邻居发现及返回路径应分开检查。DNS 记录和应用选择哪个地址,又是后续章节的问题;本篇命令直接指定实验地址。

第 06 篇的 IPv4 实验使用 ARP 解析网关,本篇 IPv6 实验使用 NDP。两者都区分最终目的地与当前下一跳。IPv4 广播 ARP 与 NS 使用不同报文格式,一个地址族的邻居项也不能说明另一个地址族的状态。

IPv6 还有明确的分片职责区别:RFC 8200 §4.5、§5规定分片由源节点完成,中途路由器不执行分片。这不等于路径永远不会遇到 MTU 问题。本篇只发送小载荷,没有触发 Packet Too Big,也没有验证 PMTUD;相关故障实验留到第 09 篇。

验证边界

实验地址与默认路由均为静态设置,没有发送或处理 RA,没有运行 SLAAC 地址生成实验。NDP 解析成功不能补足这些缺口,协议条件表也不是抓包输出。

应用回显仅证明该隔离拓扑的一次 IPv6 往返。它不能代表公网、物理设备、生产服务或吞吐性能;也没有覆盖真实双栈地址选择、扩展首部组合、重复地址冲突和过大报文处理。内核与工具版本随原始记录保存,不能把本次行为不加条件地推广到其他实现。

练习

第一题:下一跳变成 fe80::1234:5678,计算 solicited-node multicast 和对应以太网多播 MAC。NS 的 Target 是否也要变成这个多播地址?

校验:低二十四位为 34:56:78,对应 ff02::1:ff34:567833:33:ff:34:56:78;Target 仍是待解析的单播地址 fe80::1234:5678。请求发给谁和请求询问哪个地址是不同字段。

第二题:收到 Router Lifetime=0、PIO L=1、A=0、前缀寿命为正的有效 RA,能否概括成“这份 RA 没有任何作用”?若接口此前没有该前缀的自动地址,这份 PIO 是否要求创建一个?

校验:不能忽略全部信息;默认路由器与 on-link 前缀分别处理。A=0 不据此生成 SLAAC 地址。答案依赖题设中的有效性与初始状态,不包括其他配置来源已经安装地址的情况。

参考资料