Skip to content

EI 的完整行为画像

第 1 章已经把 EI 和 ED 最核心的差异实测出来了: 会话粒度和过滤行为。这一篇补齐剩下的部分 —— EI 独有的端口分配算法和每用户配额, 以及它们为什么是选 EI 的实际理由。

先回顾核心差异

text
  ┌──────────────┬────────────────────────┬────────────────────────┐
  │              │ nat44-ed(端点相关)     │ nat44-ei(端点无关)     │
  ├──────────────┼────────────────────────┼────────────────────────┤
  │ 会话键        │ 内网端 + 外网端(5 元组)│ 只有内网端(3 元组)      │
  │ 一个内网端口   │ 每个目的一条会话         │ 一条会话服务所有目的      │
  │   访问两个目的 │                        │                        │
  │ 外部主机换源   │ 丢弃                   │ 送达                    │
  │   端口打进来   │                        │                        │
  │ P2P 打洞      │ 不可行,需中继           │ 可行                    │
  │ 端口利用率     │ 高(同端口可对多目的复用)│ 低(一端口对所有目的占用)│
  └──────────────┴────────────────────────┴────────────────────────┘

这些差异都能在实验里复现:

bash
./labctl apply base 04 && ./labctl verify base 04

命令不通用,每条都多一个 ei

这是上手 EI 时第一个绊脚石。两套插件的命令完全平行但互不通用

用途nat44-ednat44-ei
启用插件nat44 plugin enablenat44 ei plugin enable
地址池nat44 add address ...nat44 ei add address ...
接口地址nat44 add interface address ...nat44 ei add interface address ...
内外侧划分set interface nat44 in X out Yset interface nat44 **ei** in X out Y
静态映射nat44 add static mapping ...nat44 ei add static mapping ...
看会话show nat44 sessionsshow nat44 ei sessions
删会话nat44 del session ... external-host ...nat44 ei del session ...(不需要 external-host)

最容易踩的是接口那条

用 ED 的写法去配 EI,报错信息很不友好:

text
set interface nat44: add host-eth1 failed

它不会告诉你"你应该加个 ei"。正确写法:

bash
vppctl set interface nat44 ei in host-eth1 out host-eth2

删会话那一行的差异不是巧合

ED 删会话必须带 external-host,EI 不用 —— 因为EI 的会话键里压根没有外网端。 这个细节可以反过来当作判断依据:如果你不确定手上这台设备在跑哪个插件, 试一条不带 external-hostdel session 就知道了。

EI 独有能力之一:端口分配算法

ED 的端口分配是写死的(保留优先,冲突才换)。EI 允许换算法:

bash
vppctl nat44 ei addr-port-assignment-alg <算法> [参数]
vppctl show nat44 ei addr-port-assignment-alg

VPP 26.06 上实测可用的只有两个:

text
  default                        默认,端口保留优先
  port-range <起> - <止>          把外部端口限定在指定范围

文档里常提到的 map-e 在 26.06 上不可用

试这两个都会被拒:

text
nat44 ei addr-port-assignment-alg: unknown input 'map-e'
nat44 ei addr-port-assignment-alg: unknown input 'random'

另外注意 port-range 必须带参数,光写算法名也会报 unknown input。

port-range 实测

应用配置

bash
./labctl reset base
./labctl apply base 08
./labctl verify base 08
bash
vppctl nat44 ei addr-port-assignment-alg port-range 1024 - 2047
text
NAT address and port: port-range
  start-port 1024 end-port 2047

连五次,看外部端口:

text
  实测到的外部端口:1887 1330 1769 1844 1283
✓ 全部落在 1024-2047 内

什么时候需要限制端口范围

text
  ✓ 和上游防火墙 / ACL 配合
    只放行这一段端口,缩小暴露面

  ✓ 多台 NAT 设备共用同一个公网地址
    各自分一段,互不冲突 —— 这是把一个地址切给多台设备用的办法

  ✓ 便于识别
    抓包和日志里一眼认出"这是我们 NAT 出去的流量"

代价是可用端口大幅减少

1024-2047 只有 1024 个端口。按人均 100 条并发会话算, 一个地址只够十来个用户 —— 而不限制时是几百个。

范围切得越窄,能撑的用户越少。这个账必须提前算, 不然上线后会以 out of ports 的形式爆出来。

EI 独有能力之二:每用户会话配额

这是 EI 在共享环境里最有价值的能力,ED 完全没有对应功能

对比两个插件的启用参数就一目了然:

text
ED:  nat44 plugin enable [sessions <n>] [inside-vrf <id>] [outside-vrf <id>]
                          ^^^^^^^^^^^^ 只有全局上限

EI:  nat44 ei plugin enable [sessions <n>] [users <n>] [user-sessions <n>]
                                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                                            还能限制"每个用户占多少"

为什么这很重要

ED 只有一个全局的会话上限。这意味着:

一个人可以把全楼的网搞坏,而且很难定位到是谁。

EI 的 user-sessions 给每个内网主机划了独立配额,一个人再狠也只能占自己那份。

实测

bash
vppctl nat44 ei plugin enable users 10 user-sessions 3

让 h1 发 10 条不同源端口的流:

text
  h1 发 10 条不同源端口的流(配额是 3)
    NAT44 sessions:
    -------- thread 0 vpp_main: 3 sessions --------
      10.10.0.11: 3 dynamic translations, 0 static translations
✓ h1 只建成了 3 条会话,配额生效

再让 h2 也发 10 条,验证配额是按用户独立的:

text
  h2 也发 10 条流
    NAT44 sessions:
    -------- thread 0 vpp_main: 6 sessions --------
      10.10.0.11: 3 dynamic translations, 0 static translations
      10.10.0.12: 3 dynamic translations, 0 static translations
✓ h2 同样拿到 3 条 —— 配额按用户独立计算

两个主机各占 3 条,互不影响。

被配额挡下的会话不记任何计数器

show errors看不到配额拒绝。这和会话表满(maximum sessions exceeded) 或端口耗尽(out of ports)都不一样 —— 那两个有明确的错误计数。

排查"某个用户老是连不上"时,只能对比:

bash
./labctl vppctl base show nat44 ei sessions

看那个用户的 N dynamic translations 是不是正好卡在配额值上。

users 和 user-sessions 要一起规划

bash
nat44 ei plugin enable users 10 user-sessions 3
                             ^^          ^^
                       最多几个用户   每人几条会话

users 是用户表的容量。超过这个数量的新用户会被拒绝 —— 注意是拒绝新用户,不是挤掉老用户。所以 users 要按内网主机总数留足余量。

总容量粗算:users × user-sessions,且不能超过 sessions 全局上限。

EI 的会话表长什么样

EI 的会话显示是按用户聚合的,和 ED 的平铺列表完全不同:

bash
./labctl vppctl base show nat44 ei sessions
text
NAT44 sessions:
-------- thread 0 vpp_main: 6 sessions --------
  10.10.0.11: 3 dynamic translations, 0 static translations
  10.10.0.12: 3 dynamic translations, 0 static translations

想看每条会话的细节要加 detail

bash
./labctl vppctl base show nat44 ei sessions detail
text
  10.10.0.11: 3 dynamic translations, 0 static translations
    i2o 10.10.0.11 proto udp port 23456 fib 0
  o2i 203.0.113.1 proto udp port 22324 fib 0
       index 0
       last heard 1502.54
       total pkts 4, total bytes 230
       dynamic translation

对比 ED 的会话少了两样东西:

  • 没有 external host —— 这就是端点无关的字面含义
  • 没有 i2o / o2i flow 的 match+rewrite 明细 —— EI 的改写规则由键直接推导, 不需要预先算好存下来

还有一个好处:show nat44 ei addresses 会显示每个地址的端口占用

text
NAT44 pool addresses:
203.0.113.1
  tenant VRF independent
  0 busy other ports
  0 busy udp ports
  0 busy tcp ports
  0 busy icmp ports

ED 的 show nat44 addresses 没有这几行。想在 ED 下判断"哪个池地址快满了" 只能靠间接手段 —— 这是第 2 章提过的 ED 可观测性短板, 在 EI 这里不存在。

超时是同一套

EI 和 ED 共用同一组超时配置:

bash
vppctl show nat timeouts          # 注意不是 show nat44 ei timeouts
text
udp timeout: 300sec
tcp-established timeout: 7440sec
tcp-transitory timeout: 240sec
icmp timeout: 60sec

show nat44 ei timeouts 也能看,显示同样的值。) 调整方式和第 2 章讲的完全一样。

小结

EI 独有说明
端口分配算法port-range <起> - <止>;26.06 上 map-e / random 不可用
每用户会话配额users N user-sessions M,防止单用户吃光会话表
每地址端口占用可见show nat44 ei addresses 带 busy ports 统计
会话高可用下一篇
P2P 打洞可行第 1 章
EI 的代价说明
端口利用率低一个外部端口一旦被占,对所有目的都被占
安全性弱外部主机换源端口能打进来
功能少没有 twice-NAT、负载均衡映射、VRF 多租户表

下一篇:会话高可用 —— EI 最有分量的独有能力。

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