IPv6 的故障往往被归咎于协议本身,而真正的原因却是导致故障的数据包大小。两个协议族处理超大包的方式确实不同,而隧道正是让这一差异变得关键的地方。IPv4 路由器在规则允许时可以分片,而 IPv6 路由器在途中根本不允许分片。IPv6 改为通知发送方,并期待发送方做出反应。此后出现的一切问题,都取决于那条消息是否送达。

两个协议族各自做什么

这张表用四行概括了机制,其中一行解释了大部分困惑。

BehaviourIPv4IPv6
Router fragments an oversized packetAllowed while DF is clearNever
Signal returned to the senderICMP Fragmentation NeededICMPv6 Packet Too Big
Size that must always work68 bytes1280 bytes
Fragmentation possibleRouters or sourceSource only

IPv6 既没有途中分片,也没有可清除的 DF 标志,因此当包过大时没有任何退路。必须告知发送方,而发送方必须相信这一点。

隧道悄悄收窄了路径

VPN 在数据包离开主机之前添加外层报头,加密时还会加上完整性数据。内层包可能仍能装进它所看到的接口 MTU,而外层包却超出了下一跳链路的限制,这正是该问题最先出现在隧道里的原因。请有意下调隧道接口的 MTU,或在路径上钳制 TCP MSS,并写下你选择的数值和理由。

ESP 的开销取决于模式和算法,因此 正确的隧道 MTU 是算出来的,而不是沿用惯例。无论选择什么,都必须为完整的 1280 字节内层 IPv6 数据包留出空间,因为每条 IPv6 链路都必须能承载这么多。无法承载 1280 字节 IPv6 的隧道不是调优问题,而是该协议族的断路。当 MTU 数值从仅支持 IPv4 的部署中照搬过来时,消失的正是这一约束。

为什么症状表现为卡住

故障并不是干净的报错,所以常常被误诊。TCP 握手完成,小响应也能到达,而一旦开始大响应或大批量上传,连接就停滞,因为那才是第一批大到会被丢弃的包。SSH 能连上,却在第一次大量输出时卡住;页面头部加载成功,正文却永远传不完。

如果 ICMPv6 的“包过大”消息被过滤,发送方永远不会得知,只能反复重试同样的大小。这是黑洞而不是慢路径,它的特征是可复现的大小边界,而不是随机丢包。允许相关控制流量通过是可用 IPv6 部署的一部分,而不是人情。

不要关掉自己路径所依赖的消息,再把结果说成 IPv6 的故障。同样的道理适用于 IPv4 的 Fragmentation Needed 消息,它们同样不受防火墙作者欢迎,也同样必不可少。

先测量边界,再修复相应的层

与其猜测,不如探测:在 IPv4 上使用 don't-fragment 标志,在 IPv6 上使用固定载荷大小,并记录响应在哪里停止。ping -M do -s 1472和ping -6 -s 1400足以确定问题的形态,而tracepath会报告沿途发现的路由 MTU。

然后修复掌管这个数字的层:隧道接口的 MTU、针对 TCP 的 MSS 钳制,或者路径本身。IPv6 规则的参考是 RFC 8200,它读起来比它所预防的事故要短。

测试应用实际使用的协议族,因为双栈名称可能在一个协议族上应答而在另一个上不应答,应用也可能在网络变化后切换。记下你测试的地址,因为针对 A 记录的结果并不能说明 AAAA 记录的情况。

把大小边界当作证据

可复现的大小边界是少数能精确复现的网络故障之一:同样的字节数、同样的来源,每次都一样。这使它成为礼物而不是谜团,也意味着修复可以被验证,而不必靠期望。

把发现的 MTU、你配置的隧道 MTU 以及证明差异的测试写进工单。下一个人会在另一条链路上遇到同样的算术。

相关文章