Skip to content

典型故障速查

这一篇把前面七章遇到的所有故障汇总成一张可查的表。 每一条都是在实验环境里真实触发过的,不是照抄文档。

有计数器签名的故障

这类最好办 —— 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 tables
text
table 1:
[0] vrf-id 0
table 2:
       ← 空的

租户 2 立刻断网,但 show errors没有任何 NAT 计数。 因为包不是死在 NAT 节点,而是翻译完之后在路由查找阶段找不到出口被丢的。

识别方法:VRF 场景下某个租户不通而 NAT 计数器干净 → 先查 vrf route

详见VRF 多租户

② 外部地址没有路由(nat66 / pnat)

nat44 的地址池会被 VPP 装进 FIB 当作本地地址并代答 ARP, 但 nat66pnat 的外部地址不会

识别方法:去对端看邻居表。

bash
ssh ... 'docker exec clab-nat64-s6 ip -6 neigh'
text
2001:db8:2::99 dev eth1  ref 1 probes 6 INCOMPLETE
                                        ^^^^^^^^^^

INCOMPLETE 就是签名 —— 对端一直在问"谁是这个地址",没人回答。

详见 nat66pnat

③ 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 det44
text
  det44-in2out
  det44-in2out

det44 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-eth1

nat44 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 逻辑本身,而在路由、邻居解析或插件状态上。

下一篇:性能真相 —— 这套实验环境能测什么、不能测什么。

实验环境基于 netlab + containerlab + VPP 26.06