IPv6 数据包过大:为什么大文件 VPN 传输会卡住
小响应能到达,大传输却在同一条隧道里卡住。发送方从未学到路径大小,而一条被过滤的控制消息解释了原因。
用 ping 能通,浏览器能加载小页面,文件传输却卡住,而且都走同一条 IPv6 隧道。这种模式通常说明发送方从未学到路径的真实大小,而不是隧道太慢。IPv6 期望路由器用 Packet Too Big 消息报告问题,而封装会在数据包到达外部网络之前增加开销。如果该消息被过滤,发送方就会一直重复一个无法通过的大小。
小请求,大卡顿
隧道会把每个数据包再包进一层首部,因此内部可用大小小于外部大小。封装前按物理链路尺寸选定的数据包,封装后就会过大。IPv4 路由器可以在途中分片,而 IPv6 路由器不会代发送方分片,所以发送方必须自行调整。这种调整完全取决于能否收到反馈。
只要丢一条消息,就足以造成典型症状:握手和小响应成功,而目录列表或上传每次都卡在同一点。用户把它描述成 VPN 很慢,日志里也看不出认证有任何问题。两种观察都准确,但都无法定位故障。
Packet Too Big 是反馈,不是流量
ICMPv6 Packet Too Big 消息携带下一跳能够接受的大小,发送方用它来调低自己的估计。过滤它等于拿走路标,然后责怪司机。丢弃所有 ICMPv6 的规则看似严格,却会破坏每一条需要它的链路上的路径发现。这条消息是关于路径的控制信息,不是应用负载。
选择性过滤仍然合理。回显请求和邻居发现与错误消息扮演不同角色,策略可以区别对待。应遵循平台文档中给出的过滤指导,而不是全盘接受或丢弃整个协议,因为 RFC 8201 规定了这种反馈如何驱动路径发现。
分别检查两种地址族
单独测试 IPv6,因为 IPv4 传输成功并不能证明 IPv6 路径没有问题。然后在大传输卡住时捕获控制消息。两份记录合起来,要么显示反馈正在离开,要么证明它从未到达。
ping -6 -M do -s 1400 host.internal
ip -6 route get 2001:db8:2::10
sudo tcpdump -ni any 'icmp6 and ip6[40] == 2'
探测程序发送一个设置了不分片位的数据包,并报告它在哪个大小上失败,这个数字就是隧道必须容纳的大小。路由查询会指出承载目标的接口,因此你知道哪条链路的 MTU 生效。捕获会过滤 ICMPv6 类型 2,即 Packet Too Big 消息,并显示它是否到达本主机。如果消息出现在捕获中而传输仍然卡住,说明发送方忽略了它,这就把排查从网络转向协议栈。
拿到证据之后再调整隧道大小
降低隧道 MTU 可以掩盖被过滤的消息并让症状消失,代价是每个数据包的开销更大。这是绕过而非诊断,应该排在捕获之后,而不是取代捕获。任意取一个很低的值也不会明显破坏什么,所以它能在配置里存在多年。要有意识地修改,记录取值,并说明是哪次测量证明了它。
如果你能控制网关,应当检查丢弃该消息的规则,而不是关闭防火墙。修正一条规则比开一个策略例外更窄,日后也更容易辩护。同样的道理适用于超时:并非每次卡住都是大小问题,而捕获正是区分两者的手段。