在 IPv6 的官方 RFC 4861 标准中,设备主动向网络宣告自己 IP 的行为,有一个极其正统的专有名词:Unsolicited Neighbor Advertisement (非请求的邻居宣告,简称 Unsolicited NA)。
它相当于 IPv4 时代大名鼎鼎的 Gratuitous ARP (免费 ARP)。
1. 理论上的“标准做法”是怎么样的?
在一个没有被机房阉割的标准网络环境里,优雅的流程是全自动的:
- 当你的网卡(无论是物理机还是虚拟机)刚配置上 IP 并启动时。
- 操作系统内核会自动向局域网广播一个 Unsolicited NA 包。
- 这个包的意思是:“大家好,我不需要任何人问,我现在主动告诉大家,IP
::300对应的 MAC 地址是 XXX,请各位更新缓存!” - 路由器和交换机收到后,立刻更新底层的转发表,网络瞬间畅通。
2. 为什么在你的架构里,这个“标准”失效了?
正如我们上一回合推演的:你的 KVM 虚拟机内核确实发出了这个标准的 Unsolicited NA 宣告。
但是!KVM 发出的这个宣告,被死死地困在了 vmbr1 这个内网隔音室里。
你的宿主机(网关)听到了,但出于 IPv6 的核心安全规范(链路本地组播不可跨网段路由),宿主机绝对不会把这个宣告包转发到公网口 vmbr0 去。
这就导致机房路由器永远听不到 KVM 的宣告。而我们安装的 ndppd 又是个只会“被动回答”的老实人。
3. 宿主机代理宣告的“优雅/标准”实现方案
既然必须由宿主机出面“代打”,我们就不能每次都手动敲代码。在 Proxmox VE 的生态里,最优雅、最符合系统工程标准的方法,是利用 PVE 的 Hook Script(生命周期钩子脚本)。
也就是让系统在 KVM 300 开机启动的瞬间,自动由宿主机向外网口发送标准的 Unsolicited NA。
优雅实现步骤(只需一次配置):
第一步:在宿主机准备宣告工具
确保宿主机安装了 ndisc6 工具包(你之前用过 ndsend,应该已经有了):
apt install ndisc6
第二步:创建 PVE 挂载脚本
PVE 允许你在虚拟机启动、停止时自动执行宿主机的命令。
在宿主机创建一个脚本文件:
mkdir -p /var/lib/vz/snippets
nano /var/lib/vz/snippets/ipv6-announce.pl
填入以下极其轻量级的 Perl 钩子代码(这不仅优雅,而且是 Proxmox 官方推荐的高级玩法):
#!/usr/bin/perl
use strict;
use warnings;
my $vmid = shift;
my $phase = shift;
# 当虚拟机启动完成时 (post-start)
if ($phase eq 'post-start') {
if ($vmid eq '300') {
print "VM $vmid started. Sending Unsolicited NA to datacenter router...\n";
# 由宿主机用自己的 MAC,代表 ::300 主动向公网发宣告!
system("ndsend 2602:fcc0:7777:3b33::300 vmbr0");
}
}
赋予执行权限:
chmod +x /var/lib/vz/snippets/ipv6-announce.pl
第三步:将脚本绑定给 KVM 300
在宿主机执行这条命令,把脚本挂载到你的虚拟机上:
qm set 300 -hookscript local:snippets/ipv6-announce.pl
4. 终极真相:协议的优雅抵不过现实的残酷
配置完上述 Hook 脚本后,每次 KVM 开机,宿主机都会极其标准、优雅地向机房发送一次主动宣告。这完全符合 IPv6 的规范。
但是,我必须对你坦诚一个极其残酷的现实:
就算你开机时宣告得再完美,机房路由器的缓存是有老化时间(Aging Time)的(通常是 5 到 30 分钟)。
一旦过了这段时间,如果你没有向外发包,机房路由器就会把你的 ::300 遗忘。按照标准协议,它此时应该主动发一个 NS 询问你还在不在(这时 ndppd 就可以回答了)。
但如果你的机房路由器是个连 NS 都不发的“奇葩”,那么 30 分钟后,你依然会断网。此时的“优雅做法”就不管用了,你只能被迫写一个 crontab,每隔 5 分钟死皮赖脸地向外发一次 ndsend,这被称为 "Keep-alive Heartbeat"(保活心跳)。
一句话总结:
- 标准做法:Unsolicited NA (
ndsend)。 - 优雅工程实现:Proxmox 生命周期钩子(Hook Script)开机自动触发。
- 真正的企业级终极优雅:不用这些底层花招,直接让机房做三层静态路由(Static Route),或者我们在宿主机上用 Nginx 反代内网 IPv4。