WireGuard 卡顿:MTU 上限还是缺失的转发规则?
服务器之外完全不通,是转发或回程路由的问题。小请求能用而大请求卡住,正是包大小的特征。
只要 WireGuard 表现异常就下调 MTU,这个习惯会掩盖另一种故障。不转发报文的网关和承载不了大包的通路,会给出可以区分的形态:前者两个方向、任何大小都失败,后者小请求能过、大请求必死。在改动任何数字之前,先确认你面对的是哪一种。测试很便宜,却能排除一半可能的原因。
两种故障,两种形态
转发问题会在服务器之后立刻显现。握手成功,隧道地址有响应,而网关之后即使发一个小请求也完全不通。包到了服务器却没被转出去,或者回程根本没有路由。
大小问题只在超过某个阈值后出现。DNS、TCP 握手和很小的 API 调用都正常,而文件下载或大响应会挂住。能放下的包端到端走通了,放不下的包在某处被丢弃,却没有任何可用的报告。
这些描述指向不同的人、不同的配置文件,所以先测量形态比猜测更有价值。只 ping 一下网关无法把两者分开。
在缩小任何数值之前,先排除转发
要测试网关之外的目的地,而不是网关本身。ping 服务器的隧道地址只能证明接口是通的、能到达终结隧道的那台机器。更广网络的流量,取决于那台机器是否开启 IP 转发,以及防火墙是否放行被转发的流。两者都必须成立,任何一项不成立,结果都是同样的沉默。
回程路由同样重要。如果目的网络不知道如何到达客户端的隧道地址,请求会到达而响应会消失,客户端报告的超时看起来和转发被丢弃一模一样。
在设计使用地址转换的地方,转换规则就是那条回程的一部分。追查 MTU 问题时把规则删掉,会把本来能用的设计变成坏掉的设计,所以改动之前先读现有规则。
测量断裂从哪里开始
先读取转发状态和过滤规则。这些都是只读检查,回答的是那个便宜的问题:
sysctl net.ipv4.ip_forward
sudo iptables -S FORWARD
ip route get 10.30.0.9
然后用不分片位,从客户端向网关之外的主机探测大小:
ping -M do -s 1200 10.30.0.9
ping -M do -s 1400 10.30.0.9
如果第一个探测通过、第二个因分片错误失败,通路就是在告诉你它可用的大小。如果两个都不通,你面对的是转发或路由,而 MTU 并不是该改的变量。
| Observation | Points toward | Where to look |
|---|---|---|
| Nothing beyond the gateway works | Forwarding or return route | Forwarding flag, filter rules, routing table |
| Small works, large stalls | Packet size on the path | Tunnel MTU and the link underneath |
| Only names fail | DNS resolution | The resolver configured for the tunnel |
| Works sometimes | Multiple paths or state expiry | Flow selection and NAT state |
修复你已证明的那一层
当故障在转发时,修正就是一条转发规则或一条路由,并且按设计允许的范围写得尽量窄。当故障在大小上时,修正是一个把这条通路上的封装算进去的 MTU,而且只用在需要它的接口上,不是用在 fleet 里的每个网卡。
无论哪种情况,之后都用同一个目的地重做同一件事。原来的大传输现在能完成,说明改动打中了出问题的那一层。如果只有小探测变好,你只是处理了症状,真正的限制还在原处。
把改动之前观察到的形态写下来。这一行记在修复方案旁边,正是它让下一个人不会去下调一个从来不是问题的 MTU。