Skip to content

到底该选哪个

三章的实测结果汇总成一张决策表,外加几个 EI 侧还没提过的选项, 以及一个会让 VPP 崩溃的坑。

先看硬约束

有些需求只有一个插件能满足。碰到这些,没得选:

text
  只能用 nat44-ei                        只能用 nat44-ed
  ────────────────────────────────       ──────────────────────────────
  · 切换时已建立连接不能断                 · twice-NAT(源和目的一起改)
    → 只有 EI 有会话高可用
      (配合 VRRP 实测可做到 0 丢失)                  → 非对称路由场景必需

  · 必须支持 P2P 打洞                     · 负载均衡静态映射
    → VoIP、视频会议、游戏联机               → 一个公网端口分流多后端

  · 要限制单个用户的会话数                 · VRF 多租户表
    → 只有 EI 有 user-sessions              → 地址重叠的多租户

  · 要限定外部端口范围                     · 需要更强的入向安全性
    → 只有 EI 有 port-range 算法             → 外部主机换端口进不来

这两列各自都是对方完全没有的能力,不是"做得好一点"的差别。

没有硬约束时的权衡

text
  ┌────────────────┬──────────────────────┬──────────────────────┐
  │                │ nat44-ed             │ nat44-ei             │
  ├────────────────┼──────────────────────┼──────────────────────┤
  │ 端口利用率      │ 高                    │ 低                   │
  │                │ 同一端口可对多个目的复用 │ 一端口占用即对所有目的占用│
  ├────────────────┼──────────────────────┼──────────────────────┤
  │ 入向安全性      │ 强                    │ 弱                   │
  │                │ 五元组全对上才放行      │ 地址对上就放行         │
  ├────────────────┼──────────────────────┼──────────────────────┤
  │ P2P 体验        │ 差,需走中继           │ 好,可打洞            │
  ├────────────────┼──────────────────────┼──────────────────────┤
  │ 可观测性        │ 弱                    │ 强                   │
  │                │ 看不到每地址端口占用     │ 有 busy ports 统计     │
  ├────────────────┼──────────────────────┼──────────────────────┤
  │ 功能丰富度      │ 高                    │ 低                   │
  ├────────────────┼──────────────────────┼──────────────────────┤
  │ 会话表结构      │ 平铺,含完整改写规则     │ 按用户聚合            │
  └────────────────┴──────────────────────┴──────────────────────┘

一句话概括这个权衡:ED 更省资源更安全,EI 对用户体验更友好、更可控。

按场景选

几个典型场景的答案:

场景选择理由
家用 / 小型办公网关EI用户会用视频通话和游戏,P2P 体验优先
企业出口,有服务对外发布ED要端口转发、可能要 twice-NAT,安全性优先
运营商 CGNED 或 DET44端口利用率是第一位的;可追溯性见第 4 章
多租户托管ED需要 VRF 隔离重叠地址
需要双机热备的关键出口EI会话 HA 是硬约束
不确定EDVPP 的默认主力实现,功能最全,社区用得最多

EI 侧还没提过的几个选项

mss-clamping

TCP 建连时双方协商 MSS。如果路径上有隧道(VPN、GRE、PPPoE)导致实际 MTU 变小, 而两端协商出的 MSS 又太大,就会出现"小包能通、大包不通"的经典故障。 mss-clamping 让 NAT 设备在转发 SYN 时把 MSS 改小。

bash
vppctl nat44 ei mss-clamping 1400
vppctl show nat44 ei mss-clamping
text
mss-clamping 1400

ED 侧和 EI 侧是两个独立的设置

VPP 有两条 mss-clamping 命令,作用于不同的插件:

bash
vppctl nat mss-clamping 1400          # 作用于 nat44-ed
vppctl nat44 ei mss-clamping 1400     # 作用于 nat44-ei

它们互不影响,而且各自都有 show

bash
vppctl show nat mss-clamping          # ED 侧
vppctl show nat44 ei mss-clamping     # EI 侧

配 ED 侧却去查 EI 侧的状态,会看到 disabled 而误以为没生效。

还有一个和 NAT 无关的接口级 MSS clamping

bash
vppctl set interface tcp-mss-clamp <> ip4 rx ip4-mss 1400 ip6 disable ip6-mss 0
vppctl show interface tcp-mss-clamp

这个不依赖任何 NAT 插件,直接挂在接口上,必须指定方向rx / tx)。 它在隧道场景里是标准做法 —— 第 10 章有完整实测, 能在 trace 里看到 SYN 的 MSS 从 1460 被改成 1400。

forwarding

和 ED 的 nat44 forwarding 语义一样:让匹配不到转换规则的流量不经翻译直接转发。

bash
vppctl nat44 ei forwarding enable

用法和注意事项见第 2 章那一节 —— 最重要的一条是:外网侧必须真的有回内网的路由,否则打开了也没用。

static-mapping-only:别用,会让 VPP 崩溃

VPP 26.06 上这个选项会导致 SIGSEGV

nat44 ei plugin enable 有个 static-mapping-only 选项, 意思是"只做静态映射,不建动态会话"。

实测在 VPP 26.06 上,它会让 VPP 段错误崩溃,而且稳定复现:

bash
vppctl nat44 ei plugin enable static-mapping-only
vppctl set interface nat44 ei in host-eth1 out host-eth2
# 此时任何一个从外网侧进来的包都会打崩 VPP

容器日志里的崩溃栈:

text
received signal SIGSEGV, PC 0x..., faulting address 0x...
#0  clib_bihash_search_8_8 + 0x3f
      from /lib/x86_64-linux-gnu/libvnet.so.26.06
#1  nat44_ei_out2in_node_fn_x86_64_v4 + 0x4a9f8
      from /usr/lib/x86_64-linux-gnu/vpp_plugins/nat44_ei_plugin.so
#2  vlib_main + 0x22b9
/usr/local/bin/netlab-start.sh: line 100: 69 Aborted (core dumped) /usr/bin/vpp ...

崩在 EI 的 out2in 处理节点里查哈希表的地方 —— 看起来是 static-mapping-only 模式下某张表没有被初始化,out2in 路径却照样去查它。

结论:在 26.06 上不要用这个选项。 想达到"只允许静态映射"的效果, 更安全的做法是正常启用插件,只是不配任何动态地址池 —— 没有池,动态会话自然建不起来(会记 out of ports), 而且不会崩。

顺带一提:帮助文本里有个拼写错误

text
nat44 ei plugin <enable ... [static-mappig-only [connection-tracking]|out2in-dpo] ...>
                             ^^^^^^^^^^^^^^^^^^ 少了一个 n

实际接受的是正确拼写 static-mapping-only,按帮助里的拼法输入会被拒绝。 不过既然它会崩,这个拼写问题也就无所谓了。

崩了怎么恢复

如果不小心触发了崩溃:

bash
./labctl down base && ./labctl up base

容器会以 Exited (134) 状态停下(134 = 128 + 6,SIGABRT)。 restart-policy: no 意味着它不会自动重启,需要重建。

这也是一堂实战课

生产环境里 VPP 崩溃时,第一件事是保住现场:

bash
docker logs <容器> 2>&1 | tail -50      # 崩溃栈在这里

崩溃栈里最有价值的是 #1 那一帧 —— 它指出是哪个插件的哪个 graph node 出的问题。像上面这样能直接锁定到 nat44_ei_out2in_node_fn, 排查方向就非常明确了。

两个插件能不能同时用

不能。它们会抢同一批接口,配置命令也互不通用。

本教程所有实验步骤开头都调用一个 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
                    有硬约束?

          ┌─────────────┴─────────────┐
          │                           │
     会话 HA / P2P /            twice-NAT / 负载均衡 /
     用户配额 / 端口范围           VRF 多租户 / 强安全
          │                           │
      nat44-ei                    nat44-ed
          │                           │
          └─────────────┬─────────────┘

                   都没有硬约束

                  默认选 nat44-ed
              (功能最全,社区主力)

第 3 章到此结束。EI 的全部图景:

text
  行为    会话粒度粗、过滤宽松、P2P 友好、端口利用率低
  独有    会话 HA · 每用户配额 · 端口范围算法 · 每地址端口占用可见
  缺失    twice-NAT · 负载均衡映射 · VRF 多租户
  雷区    static-mapping-only 会让 26.06 崩溃

其中"会话 HA"这一项,配合 VRRP 才是完整方案 —— 实测切换时 18 次心跳零丢失,而只有 VRRP 没有会话同步时切换即断。

接下来第 4 章进入运营商级 NAT:det44 确定性 NAT。 它走的是完全不同的路子 —— 不查表,用算法直接算出映射, 代价是端口利用率固定,好处是可追溯性和极低的状态开销。

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