主题
典型故障速查
这一篇把前面七章遇到的所有故障汇总成一张可查的表。 每一条都是在实验环境里真实触发过的,不是照抄文档。
有计数器签名的故障
这类最好办 —— show errors | grep -i nat 直接给出方向。
text
┌──────────────────────────────┬──────────────────────────────────────────┐
│ 计数器 │ 可能原因 │
├──────────────────────────────┼──────────────────────────────────────────┤
│ no translation │ ① 内外侧接口配反 │
│ │ ② 外部主动连入但没有静态映射(正常拒绝) │
│ │ ③ 会话已老化,对端还在发 │
├──────────────────────────────┼──────────────────────────────────────────┤
│ out of ports │ ① 压根没配地址池 │
│ │ ② 池里端口真的用完了 │
│ │ ③ 哈希不均,某个池地址先满而总量还够 │
├──────────────────────────────┼──────────────────────────────────────────┤
│ maximum sessions exceeded │ 会话表满,调 nat44 plugin enable sessions │
├──────────────────────────────┼──────────────────────────────────────────┤
│ non-SYN packet try to │ ① 会话老化后对端还在发(最常见) │
│ create session │ ② 发夹弯没配通,客户端对错误端口回了 RST │
├──────────────────────────────┼──────────────────────────────────────────┤
│ unsupported ICMP type │ ICMP 差错报文里内嵌的包头解析不了 │
└──────────────────────────────┴──────────────────────────────────────────┘亲手触发前三种
bash
./labctl reset base
./labctl apply base 11
./labctl verify base 11这个实验依次注入四种故障,每种都打印现象、配置、计数器签名和诊断要点。
no translation 的三种成因怎么区分
text
① 内外侧配反
show nat44 interfaces 里的 in/out 和物理拓扑对不上
→ 修配置
② 外部主动连入无映射
这是**正常行为**,不是故障。计数器会持续缓慢增长
(互联网上总有人在扫端口)
→ 不用管;真要放行就配静态映射
③ 会话老化
计数器突然开始快速增长,而且只影响长连接
→ 对比 show nat timeouts 和应用的保活间隔区分 ② 和 ③ 的实用方法:看计数器增长速率。 背景扫描是每分钟几个,会话老化引发的是每秒几十上百。
out of ports 的第三种最难查
前两种一眼可见(show nat44 addresses 是空的,或者会话数顶到上限)。 第三种很阴险:
text
show nat44 summary → total sessions 离上限还很远
show nat44 addresses → 池里有好几个地址
但某些用户就是连不上原因是地址池那一篇讲的按内网地址哈希选池地址 —— 哈希撞在一起的用户挤在同一个池地址上,那个地址的端口先耗尽。
nat44-ed 看不到每地址的端口占用
bash
vppctl show nat44 ei addresses # EI 有 busy ports 统计
vppctl show nat44 addresses # ED 没有所以在 ED 下确认这个问题只能靠间接手段:把 show nat44 sessions 导出, 按外部地址聚合计数。这是 ED 的可观测性短板。
没有计数器的静默故障
这类才是真正折磨人的 —— 配置看起来完全正常,计数器一片干净,流量就是不通。 前面七章一共撞上五种。
① VRF NAT 漏配 vrf route
bash
vppctl show nat44 vrf tablestext
table 1:
[0] vrf-id 0
table 2:
← 空的租户 2 立刻断网,但 show errors 里没有任何 NAT 计数。 因为包不是死在 NAT 节点,而是翻译完之后在路由查找阶段找不到出口被丢的。
识别方法:VRF 场景下某个租户不通而 NAT 计数器干净 → 先查 vrf route。
详见VRF 多租户。
② 外部地址没有路由(nat66 / pnat)
nat44 的地址池会被 VPP 装进 FIB 当作本地地址并代答 ARP, 但 nat66 和 pnat 的外部地址不会。
识别方法:去对端看邻居表。
bash
ssh ... 'docker exec clab-nat64-s6 ip -6 neigh'text
2001:db8:2::99 dev eth1 ref 1 probes 6 INCOMPLETE
^^^^^^^^^^INCOMPLETE 就是签名 —— 对端一直在问"谁是这个地址",没人回答。
③ HA 备机地址池不匹配
主备 HA 状态都显示正常,同步报文在链路上跑,但备机会话数是 0。
识别方法:在备机上抓 trace。
text
00:01:29:611776: nat44-ei-ha
nat44-ei-ha: 0 events from 10.99.0.1
^^^^^^^^ 报文到了,但一个会话事件都没带心跳在跑、事件是空的 → 两边地址池对不上,同步过来的会话被静默丢弃。
详见会话高可用。
④ det44 残留的 feature 节点
做过 det44 实验之后,nat44 的所有实验会全部失效 —— 配置显示正常,流量全不通。
识别方法:
bash
vppctl show interface features host-eth1 | grep det44text
det44-in2out
det44-in2outdet44 plugin disable 不会摘掉这些节点,而且 set interface det44 ... del 会让计数变多。没有在线清理的办法,只能重建 VPP。
详见 DET44。
⑤ ACL 或 policer 残留
做完 ACL / QoS 实验后直接跑 NAT,会看到 NAT 配置一切正常但流量不通, 而 show errors | grep -i nat 干干净净。
识别方法:换个关键字看计数器。
bash
vppctl show errors | grep -iE 'acl|policer'text
49 acl-plugin-in-ip4-fa ACL deny packets error以及看接口上挂了什么:
bash
vppctl show acl-plugin interface
vppctl show interface features host-eth1nat44 plugin disable 管不到 ACL 和 policer —— 它们是独立的 feature, 必须单独摘。详见第 8 章。
⑥ 对端没有回程路由
最朴素的一种,也最容易被忽略:VPP 什么都没做错,包正常发出去了, 但对端不知道怎么回。
识别方法:trace 显示包走到了 host-ethX-output(即已发出), 但对端没有响应。这时问题不在 VPP,去对端查路由。
第 11 步实验专门演示了这一种:把地址池换成 198.51.100.7, s1 完全不知道这个网段怎么回。
静默故障的通用判据
计数器干净 + 不通 这个组合本身就是信息量:它说明 "VPP 认为自己做对了"。所以要把注意力从 VPP 移开:
text
1. trace 看包有没有正常发出(走到 host-ethX-output)
发出了 → 查对端:路由、ARP/ND、防火墙
没发出 → 查 VPP:feature 残留、VRF 路由、pcap trace drop
2. 去对端看 ip route / ip neigh
3. 回来看 show interface features 有没有意外的节点让 VPP 崩溃的三个操作
这三个都在 VPP 26.06 上稳定复现,而且都是执行 CLI 命令的瞬间就崩, 不需要有流量。
text
┌────────────────────────────────────────┬──────────────────────────────┐
│ 操作 │ 崩溃栈顶 │
├────────────────────────────────────────┼──────────────────────────────┤
│ nat44 ei plugin enable │ nat44_ei_out2in_node_fn │
│ static-mapping-only + 外网侧来包 │ │
├────────────────────────────────────────┼──────────────────────────────┤
│ det44 add in <前缀 ≥ /18> out ... │ det44_out2in_node_fn │
│ │ (分配失败,主机数驱动) │
├────────────────────────────────────────┼──────────────────────────────┤
│ set pnat translation ... del │ pnat_output_node_fn │
│ (删除一条**不存在**的规则) │ │
├────────────────────────────────────────┼──────────────────────────────┤
│ policer input unapply <未挂载的 policer> │ (见第 9 章) │
├────────────────────────────────────────┼──────────────────────────────┤
│ 先删隧道接口、再删引用它的路由 │ vnet_ip_mroute_cmd │
└────────────────────────────────────────┴──────────────────────────────┘
::: tip 这五个崩溃有同一个模式
**对一个"已经不在那儿"的对象执行删除/摘除操作。**
```text
删不存在的 pnat 规则
摘未挂载的 policer
删已被删除接口所引用的路由反过来,"删一个完全不存在的名字"往往是安全的 (policer del 会返回 "No such policer")。危险的是那种 系统认为它存在、但内部引用已经断掉的中间状态。
写自动化脚本的通用原则:先查状态,再操作。 本教程所有 *_clean 函数都是这么写的。 :::
::: danger 第三个最容易踩
"先删旧规则再配新的"是写幂等脚本最自然的写法,而 PNAT 又没有 clear all 命令。
本教程的 `apply.sh` 用 `require_clean_pnat` 检查规则数为 0,绝不盲删。
详见 [PNAT](/06-others/pnat)。
:::
### 崩了怎么处理
```bash
# 看崩溃栈 —— 最有价值的是 #1 那一帧,它指出是哪个插件哪个节点
docker logs <容器名> 2>&1 | tail -50
# 容器会以 Exited (134) 停下(134 = 128 + 6,SIGABRT)
docker ps -a --filter name=<容器名>
# restart-policy: no,不会自动重启,需要重建
./labctl down base && ./labctl up base各插件的互斥关系
配置前先确认没有冲突。这些都是实测的:
text
┌───────────────────┬────────────────────────────────────────────────┐
│ 组合 │ 结果 │
├───────────────────┼────────────────────────────────────────────────┤
│ nat44-ed + nat44-ei│ 抢同一批接口,会打架 │
│ nat64 + nat66 │ 同一内网接口上互斥,**nat66 盖住 nat64** │
│ │ 好消息:disable 能干净恢复,不用重建 │
│ det44 + 任何 nat44 │ det44 的 feature 残留会让 nat44 失效,**必须重建** │
└───────────────────┴────────────────────────────────────────────────┘本教程所有实验步骤开头都调用 nat44_clean,把三个 NAT 插件全关掉再启用需要的那个:
bash
nat44_clean() {
vcq nat44 plugin disable >/dev/null
vcq nat44 ei plugin disable >/dev/null
vcq det44 plugin disable >/dev/null
}切换插件会清空所有配置和会话
plugin disable 连带清掉接口归属、地址池、静态映射和整张会话表。 ED 和 EI 之间没有平滑迁移路径 —— 切换就是一次彻底的业务中断。
容易误判为故障的正常现象
最后是一组"看着像坏了其实没坏"的情况,避免白折腾。
text
┌──────────────────────────────────────┬────────────────────────────────┐
│ 现象 │ 其实是 │
├──────────────────────────────────────┼────────────────────────────────┤
│ 刚配好 NAT,第一个 ping 超时 │ ARP 未解析,ip4-glean 发请求并丢包 │
│ │ 第二个包起就正常 │
├──────────────────────────────────────┼────────────────────────────────┤
│ show nat44 summary 里 timed out > 0 │ 懒回收正常现象,不是故障 │
├──────────────────────────────────────┼────────────────────────────────┤
│ identity mapping 多出一行乱码地址 │ 显示层读了未用字段,无害 │
│ local 64.154.183.118:... │ │
├──────────────────────────────────────┼────────────────────────────────┤
│ 接口形式的静态映射显示成两行 │ 一条是解析后的,一条是你配的接口形式 │
├──────────────────────────────────────┼────────────────────────────────┤
│ 负载均衡 12 次连接落 10:2 │ 五元组哈希,小样本偏差正常 │
│ │ 60 次会收敛到 32:28 │
├──────────────────────────────────────┼────────────────────────────────┤
│ 会话表里 protcol 拼错 │ VPP 输出的拼写错误,别按正确拼法 grep│
└──────────────────────────────────────┴────────────────────────────────┘排障命令清单
按使用频率排序,遇到问题从上往下走:
bash
# 配置
vppctl show nat44 interfaces
vppctl show nat44 addresses
vppctl show nat44 static mappings
vppctl show nat44 summary
# 计数器(诊断第一站)
vppctl show errors | grep -i nat
# 会话
vppctl show nat44 sessions
vppctl nat44 del session in <addr>:<port> tcp external-host <addr>:<port>
# 逐跳
vppctl clear trace
vppctl trace add af-packet-input 20
vppctl show trace
# 丢包
vppctl pcap trace drop max 100 file drops.pcap
# 意外的 feature 节点
vppctl show interface features host-eth1
# 性能
vppctl clear runtime && vppctl show runtime
# 崩溃后
docker logs <容器名> 2>&1 | tail -50小结
诊断 NAT 故障的固定动作:
text
1. show nat44 interfaces 配置和拓扑对得上吗
2. show errors | grep -i nat 有签名就照表处理
3. 计数器干净 → trace 包发出去了吗
4. 发出去了 → 查对端 路由、ARP/ND
5. 没发出去 → pcap trace drop 谁丢的
6. 都正常还不通 → 查 feature 有没有插件残留第 2 步能解决大部分问题。真正难的是那五种静默故障, 它们的共同点是问题不在 NAT 逻辑本身,而在路由、邻居解析或插件状态上。
下一篇:性能真相 —— 这套实验环境能测什么、不能测什么。