等成本路由为何让 VPN 故障难以察觉
当多条隧道成本相同时,每个流可能走不同的一条。ping 成功并不能说明你的应用实际使用的路径。
有用户报告:内部应用在一台机器上可用,在另一台上却失败,而你从网关执行的 ping 两种情况都成功。在存在多条等成本隧道时,这并不矛盾。每个流都会被放到各自的下一条跳上,所以你的探测和用户的会话可能只是在走不同的路径。下面的步骤先复现这一选择,然后再动手改动。
一次 ping,多条可能的路径
当一条路由在同一成本下有多条下一跳时,路由器必须为每个数据包选择一条。大多数实现会对包头中的字段做哈希,通常是源地址和目的地址连同协议与端口,好让响应留在同一条路径上。不同的应用,甚至同一应用的不同连接,都会产生不同的哈希。
这就是来自网关的诊断说明不了什么的原因。网关自己的探测有它自己的地址和端口,因此也有它自己的哈希。它可能落在健康的隧道上,而用户却一直落在损坏的那条上。
平台如何选择下一跳
与其猜测,不如复现这个选择。询问内核:对于与故障会话相同的源和目的,它会使用哪条路由。这种查找会包含普通目的查找所忽略的字段。也从一个正常的客户端执行一次,然后比较两个答案:
ip route get 10.20.5.7 from 10.20.0.14
较新的 iproute2 版本还接受协议和目的端口,当哈希包含这些字段时这一点很关键。把该输出与正常客户端上同样的查找做对比,差异就是你所缺的证据。
| Observation | Likely cause | First check |
|---|---|---|
| Ping works, application fails | A different flow hash selects another tunnel | Per-flow lookup from the client's address |
| Some users fail, others do not | One tunnel lacks a prefix or selector | Compare both tunnels' installed routes |
| Fails only at larger sizes | Tunnels have different effective MTU | Probe the same size over each path |
| Fails after a reconnect | Stateful asymmetry between paths | Session state on both gateways |
跟踪失败的流,而不是路由表
路由表列出了两条隧道,按定义看是正确的。问题在于每条隧道在被选中之后对数据包做了什么。确认两者承载相同的受保护前缀、相同的转发许可,并且回程路径能到达同一个客户端。
注意中间的有状态设备。如果请求从一条隧道出去,响应却从另一条回来,从未见过原始流的防火墙或 NAT 就会把它丢弃。两条隧道各自都在正确转发流量,连接却依然失败。
还要检查每条路径的 MTU。带额外封装的路径会缩小可用尺寸,某个传输在一条隧道上成功,到了另一条上就会正好在较小那条断裂的尺寸处卡住。
一次只比较一条路径
在设计允许维护的情况下,停用一条隧道并重复用户的任务。如果故障消失,问题就属于你移除的那条路径,下一步是对比它与相邻隧道的配置,而不是重新审视路由表。
比较真实的应用,而不是反复 ping。记录故障是否跟随某条特定的下一跳、某个数据包大小,或重连之后的某种转变,因为这三类模式指向不同的修复方式。
最后,写清楚为什么这些路径被视为等价,以及故障应当如何把其中一条停用。只有当路径真的可以互换时,多路径才是安全的,而这是一个值得检查而不是假定的设计论断。