这是一篇“日常排查记录”。只写可验证的事实、证据链和最小修复,不写玄学。
TL;DR
- 现象:跨 VLAN
ping超时;目标机本地抓包却能看到echo reply已经发出。 - 根因 1(决定性):PVE 刻意以 OpenWrt(
192.168.22.13)作为默认网关做 QoS/流量处理,但 没有为其它内网 VLAN 配置显式路由,导致回程流量走默认路由“拐进” OpenWrt,主网关看不到 reply(典型非对称路径)。 - 根因 2(放大器):OpenWrt 把
lanzone 开了masq=1,把内网互访流量也 SNAT 改源成192.168.22.13,让路径与会话变得不可预期。 - 修复:
- 保留 PVE 默认网关为 OpenWrt(
192.168.22.13),但为内网网段(如192.168.11.0/24、192.168.183.0/24)添加静态路由指向主网关(192.168.22.1) - OpenWrt 关闭
lanzone 的masq
- 保留 PVE 默认网关为 OpenWrt(
- 预防:内网只路由不 NAT;如果默认网关必须指向旁路(QoS/代理),就把“内网路由”和“公网默认路由”明确拆开;用
tcpdump+ip route get走 SOP。
背景(拓扑与角色)
家庭网络是多 VLAN:
- Cloud Gateway Fiber(主网关):负责三层路由与 VLAN 间转发
- VLAN11:
192.168.11.0/24(GW192.168.11.1) - VLAN22(PVE/实验):
192.168.22.0/24(GW192.168.22.1) - VLAN183:
192.168.183.0/24(GW192.168.183.1)
- VLAN11:
- OpenWrt(旁路/二级网关):
192.168.22.13/24(br-lan,fw3 + iptables,带旁路代理脚本) - PVE:
192.168.22.12/24(vmbr0) - 测试机:
192.168.183.235(VLAN183)192.168.11.29(VLAN11)
简化数据路径(正常设计)应该是:
- VLAN183 ↔ VLAN22:都由 Fiber 做三层转发
- OpenWrt 如果要做“上网/代理出口”,应该只在真正的
wan出口做 NAT/代理,而不是改写内网互访流量
用 shell 画出拓扑与数据路径(ASCII)
下面这个脚本不会改任何配置,只是把拓扑和两条关键路径打印出来,方便读者“看见数据怎么走”:
bash#!/usr/bin/env bashset -euo pipefail# Print the topology and the two paths (bad vs fixed).cat <<'EOF'+------------------------------+| Cloud Gateway Fiber (L3) || VLAN11: 192.168.11.1 || VLAN22: 192.168.22.1 || VLAN183: 192.168.183.1 |+---------------+--------------+|VLAN22|+----------------+----------------+| |+----------v-----------+ +----------v-----------+| OpenWrt (side GW) | | PVE || 192.168.22.13 | | 192.168.22.12 || QoS / traffic mgmt | | vmbr0 |+----------------------+ +----------------------+Clients:VLAN183 host: 192.168.183.235VLAN11 host: 192.168.11.29Problem #1 (before):192.168.183.235 -> Fiber -> PVEPVE reply -> (default gw) OpenWrt -> [NAT/proxy/unknown] -> ??? (Fiber never sees the reply)Fix idea:Keep PVE default gw = OpenWrt (for QoS),but route internal subnets via Fiber.Problem #2 (amplifier):OpenWrt LAN masquerade (SNAT) rewrites east-west traffic,making internal routing/session behavior unpredictable.EOF
事件与影响
事件 1:VLAN183 ping 不通 PVE
- 发起端:
192.168.183.235执行ping 192.168.22.12一直超时 - PVE 本机抓包能看到:
ICMP echo request到达ICMP echo reply发出
- 但在主网关 Fiber(
br22/br0)抓包只看到 request,看不到 reply
这意味着:PVE 的 reply 根本没走回 Fiber —— 问题不是“主网关丢包”,而是“回程路径压根没经过主网关”。
事件 2:修复后,VLAN11 仍 ping 不通 PVE
192.168.11.29ping 不通192.168.22.12- 但可以 ping 通
192.168.22.13(OpenWrt)
这暴露出第二个问题:OpenWrt 的 NAT 行为在破坏内网互访的可预期性。
排查过程(证据链)
1)先证明主网关本身可用
在 Fiber 上验证:
- Fiber 能 ping 通
192.168.183.235与192.168.22.12 ip route显示192.168.22.0/24与192.168.183.0/24为直连
结论:Fiber 的基础三层与直连网段没问题。
2)逐跳抓包:定位“reply 消失在哪一跳”
抓包观察到:
- PVE 本机:request/reply 都存在(说明 PVE 会回包)
- Fiber 的
br22/br0:只有 request,没有 reply
结论:reply 在到达 Fiber 之前就“拐走了”。
3)用 ip route get 让路由决策自己说话
在 PVE 上:
ip route显示默认路由:default via 192.168.22.13 dev vmbr0ip route get 192.168.183.235显示:via 192.168.22.13
关键结论(问题 1 根因):PVE 没有到其它内网 VLAN 的显式路由,因此对 192.168.183.0/24 的回包自然走默认路由交给 OpenWrt。只要 OpenWrt 这边出现 NAT/代理/错误路由中的任意一种,主网关就可能完全看不到 reply。
这就是典型的非对称路由:
- 正向:
183 → Fiber → 22 → PVE(正常) - 回程:
PVE → OpenWrt → (NAT/代理/错误路由/黑盒)(不可控)
4)验证 OpenWrt 的防火墙实现与 NAT 配置
为了排除“背后还有一套规则系统”的不确定性,确认 OpenWrt 是 fw3 + iptables(无 nftables),然后检查到:
lanzone 开启了masq='1'
关键结论(问题 2 根因):OpenWrt 把内网互访也做了 SNAT,源地址被改成 192.168.22.13,会让跨 VLAN 的会话与回程路径变得混乱(尤其叠加旁路代理/策略导流时)。
解决方法(最小改动)
修复 1:保留默认网关为 OpenWrt,但把“内网路由”显式指回主网关 Fiber
需求前提:PVE 默认网关 必须是 192.168.22.13(OpenWrt),因为你要在 OpenWrt 上做 QoS/流量处理;那就别动默认路由,改成“内网网段走 Fiber,其他流量仍走 OpenWrt”。最简单且最可控的做法是给 PVE 加静态路由。
临时验证(示例只覆盖本次出现问题的 VLAN11/VLAN183,可按你的实际 VLAN 增加):
bash# Keep default via OpenWrt for QoS / traffic management# default via 192.168.22.13# Route internal VLANs via the primary L3 gateway (Fiber)ip route replace 192.168.183.0/24 via 192.168.22.1 dev vmbr0ip route replace 192.168.11.0/24 via 192.168.22.1 dev vmbr0
验证思路:
ip route get 192.168.183.235应该显示via 192.168.22.1- 在 Fiber 的
br22/br0上应该能抓到echo reply
持久化(Proxmox 常见在 /etc/network/interfaces 的 vmbr0,用 post-up 写死最直接):
bashpost-up ip route replace 192.168.183.0/24 via 192.168.22.1 dev vmbr0post-up ip route replace 192.168.11.0/24 via 192.168.22.1 dev vmbr0post-down ip route del 192.168.183.0/24 via 192.168.22.1 dev vmbr0 || truepost-down ip route del 192.168.11.0/24 via 192.168.22.1 dev vmbr0 || true
验证:
- Fiber 的
br22/br0能抓到echo reply 192.168.183.235→ping 192.168.22.12恢复
修复 2:关闭 OpenWrt 的 lan zone NAT
bashuci set firewall.@zone[0].masq='0'uci commit firewall/etc/init.d/firewall restart
验证:
192.168.11.29→ping 192.168.22.12恢复- 内网互访源 IP 保持真实,后续排障和访问控制都更简单
预防措施(别再制造“网络玄学”)
- 内网之间只路由,不做 NAT
lan/ 内网 zones:masq=0- 只有真正的公网出口(
wan)才masq=1
- 如果默认网关必须指向旁路(QoS/代理),就把路由拆清楚
- 默认路由可以指向 OpenWrt,但 所有内网网段必须有显式静态路由 指回主网关(或用策略路由按目的网段分流)
- 原则很简单:内网东西向流量走“可预期的三层”,不要让它掉进 NAT/代理黑盒
- 固定排障 SOP(Standard Operating Procedure:标准排查流程)
- 这句话的意思是:遇到类似“跨 VLAN ping 不通”的问题,不要靠猜,按同一套步骤用证据把问题钉死。
- 第一步:先用抓包回答 3 个问题:request 到没到?目标回没回?reply 消失在哪一跳?
- 在目标机上:
tcpdump -ni vmbr0 icmp - 在主网关上(目标 VLAN 口 / 发起 VLAN 口):
tcpdump -ni br22 icmp、tcpdump -ni br0 icmp
- 在目标机上:
- 第二步:用路由决策输出替代“想当然”
- 在 PVE 上:
ip route+ip route get 192.168.183.235 - 在 OpenWrt/Fiber 上:
ip route get 192.168.183.235(确认下一跳到底是谁)
- 在 PVE 上:
- 第三步:优先把数据路径变简单
- 内网互访先恢复为“纯路由、真实源地址、可预期回程”,再去叠加 QoS/代理/策略导流
- 旁路代理要“明确排除内网网段”
- 内网网段不应被透明导入 VPN/隧道
- 先保证纯路由可用,再谈代理与加速
一句话教训
当你觉得“ICMP 在搞幽灵”的时候,大概率不是协议栈坏了,而是你把默认网关/NAT 配成了黑盒。
Comments