主题
DET44:不查表,算出来
前三章的所有插件都在做同一件事:查表。包进来,查会话表;查不到,新建一条。 这一章的 det44 反其道而行。
换一种思路
映射不是"分配"出来的,是算出来的。给定内网地址,公网地址和端口区间是一个纯函数的输出; 反过来,给定公网地址和端口,也能算回内网地址。
这个性质带来一个运营商最看重的能力:可追溯性。下一篇专门讲它。
配置
应用配置
bash
./labctl reset base
./labctl apply base 09三条命令:
bash
vppctl det44 plugin enable
vppctl det44 add in 10.10.0.0/24 out 203.0.113.100/32
vppctl set interface det44 inside host-eth1 outside host-eth2命令形态和 nat44 有三处不同
text
1. 给的是**前缀**,不是地址池
nat44: nat44 add address 203.0.113.100 - 203.0.113.110
det44: det44 add in <内网前缀> out <公网前缀>
2. 内外侧关键字是 inside/outside,不是 in/out
nat44: set interface nat44 in host-eth1 out host-eth2
det44: set interface det44 inside host-eth1 outside host-eth2
3. 没有"地址池"的概念,也就没有 twice-nat、静态映射、负载均衡这些东西算出来的配额
bash
./labctl vppctl base show det44 mappingstext
NAT44 deterministic mappings:
in 10.10.0.0/24 out 203.0.113.100/32
outside address sharing ratio: 256
number of ports per inside host: 252
sessions number: 0两个数字决定了一切:
text
可用端口 64512(1024 - 65535)
÷ 共享比 256(一个 /24 有 256 台主机,对 1 个公网地址)
= 每台主机 252 个端口算法
端口块的起点是一个简单公式:
text
端口起点 = 1024 + 主机序号 × 每主机端口数亲自验证
bash
./labctl vppctl base det44 forward 10.10.0.11实测与公式逐个吻合:
text
内网地址 预期 实际
─────────── ───────────── ─────────────────────────────
10.10.0.0 <1024-1275> 203.0.113.100:<1024-1275>
10.10.0.1 <1276-1527> 203.0.113.100:<1276-1527>
10.10.0.11 <3796-4047> 203.0.113.100:<3796-4047>
10.10.0.12 <4048-4299> 203.0.113.100:<4048-4299>
10.10.0.255 <65284-65535> 203.0.113.100:<65284-65535>10.10.0.11 的序号是 11,1024 + 11 × 252 = 3796。分毫不差。
多个公网地址时
地址也是算出来的:
text
公网地址 = 公网前缀起点 + (主机序号 ÷ 共享比)
端口起点 = 1024 + (主机序号 mod 共享比) × 每主机端口数把 /24 内网配到 /28 公网(16 个地址,共享比 16):
text
10.10.0.0 → 203.0.113.96:<1024-5055>
10.10.0.15 → 203.0.113.96:<61504-65535> ← 第 16 台,仍是 .96
10.10.0.16 → 203.0.113.97:<1024-5055> ← 第 17 台,换到 .97
10.10.0.31 → 203.0.113.97:<61504-65535>
10.10.0.32 → 203.0.113.98:<1024-5055>
10.10.0.255 → 203.0.113.111:<61504-65535>每 16 台主机换一个地址,端口区间在每个地址内重新从 1024 开始。
真实流量确实落在算出来的块里
text
h1 的块:203.0.113.100:<3796-4047>
h2 的块:203.0.113.100:<4048-4299>
h1 实测端口:3995 3881 3813 ← 全在 3796-4047
h2 实测端口:4127 4295 ← 全在 4048-4299共享比就是全部的取舍
DET44 只有一个可调参数:共享比。它由内外前缀的大小之比决定。
text
内网 /24(256 台) 公网 共享比 每主机端口 能撑的并发
──────────────────── ─────────── ─────── ───────── ────────────
10.10.0.0/24 /32 (1 个) 256 252 每台 ~2 个应用
10.10.0.0/24 /30 (4 个) 64 1008 每台 ~10 个应用
10.10.0.0/24 /28 (16 个) 16 4032 每台很宽裕
10.10.0.0/24 /24 (256个) 1 64512 等于一人一地址端口配额是硬的,用完就断
这是 DET44 和前面所有插件最本质的区别。
nat44-ed 里某台主机端口用完了,还能从地址池里另一个地址借。 DET44 不能借 —— 每台主机的端口块是算死的,用完就是用完, 新连接直接失败,哪怕隔壁主机的块空着一大半。
252 个端口听起来不少,但一个现代网页可能就开几十条连接。 按 252 算,一台设备同时开两三个页面就到顶了。
所以共享比是个必须认真算的账,不是随手填的。
怎么估共享比
text
每主机端口数 = 64512 / 共享比
需要的端口数 ≈ 用户峰值并发会话数 × 安全系数(建议 1.5~2)
例:用户峰值 150 条并发会话,取系数 2 → 需要 300 端口
64512 / 300 ≈ 215 → 共享比取 128(向下取 2 的幂)
即:每 128 个用户配 1 个公网地址比 nat44 的估算更严格 —— nat44 里"某个用户偶尔超标"能被池子吸收, DET44 里超标就是直接失败。
会话表还在,但角色变了
DET44 仍然有会话表:
bash
./labctl vppctl base show det44 sessionstext
NAT44 deterministic sessions:
in 10.10.0.11:38 out 203.0.113.100:3834 external host 203.0.113.11:0
state: icmp-active expire: 111但它的角色完全不同了:
text
nat44-ed/ei 的会话表 det44 的会话表
────────────────────── ──────────────────────
承担地址端口的分配决策 只记录活跃连接
查不到就要新建(慢路径) 地址端口早就算好了
表满 = 服务中断 表只影响回程匹配超时配置是独立的一套:
bash
vppctl show det44 timeouts
vppctl set det44 timeouts udp 120 tcp established 3600 tcp transitory 120 icmp 30
vppctl set det44 timeouts reset值和 nat44 默认一样(UDP 300 / TCP 已建立 7440 / TCP 中间态 240 / ICMP 60), 但是分开配的 —— set nat timeout 不影响 det44。
一个会让 VPP 崩溃的配置
内网前缀不能超过 /19
实测在 VPP 26.06 上,det44 add 的内网前缀一旦大到 /18(16384 台主机), VPP 会当场段错误崩溃。而且是执行命令的瞬间就崩,不需要有流量。
阶梯测试结果:
text
内网前缀 主机数 每主机端口 结果
──────── ─────── ───────── ──────────
/24 256 252 OK
/23 512 126 OK
/22 1024 63 OK
/20 4096 15 OK
/19 8192 7 OK
/18 16384 3 VPP 崩溃崩溃栈显示问题出在添加映射时的内存分配,而不是转发路径:
text
#4 clib_mem_heap_alloc_aligned
#5 _vec_alloc_internal
#6 det44_out2in_node_fn_x86_64_v4 ← det44 插件
#8 vlib_cli_input ← 由 CLI 命令直接触发不是端口数太少的问题。 我们验证过:/18 内网配 /28 公网 (每主机 63 个端口,和 /22 → /32 那次一样宽裕)同样崩溃。 所以驱动因素是主机数,det44 会为前缀内的每一台主机预分配状态。
实践建议:一条 det44 add 的内网前缀不要超过 /19。 需要覆盖更大的地址空间,就拆成多条映射:
bash
vppctl det44 add in 10.10.0.0/19 out 203.0.113.0/27
vppctl det44 add in 10.10.32.0/19 out 203.0.113.32/27崩了怎么恢复
bash
./labctl down base && ./labctl up base容器会以 Exited (134) 停下(134 = 128 + 6,SIGABRT), restart-policy: no 意味着不会自动重启。
更麻烦的一个坑:det44 会污染接口,且无法在线清理
做完 det44 实验必须重建容器,否则 nat44 全部失效
这个坑比上面那个崩溃更阴险,因为它不报错。
DET44 在启用时会往接口的 feature arc 上注册 det44-in2out 处理节点。 问题是:
text
det44 plugin disable → 接口列表清空了,但 feature 节点还在
set interface det44 ... del → 不但没摘掉,计数反而 +1
再 enable 再 disable → 计数继续累积实测过程:
bash
vppctl show interface features host-eth1 | grep -c det44-in2outtext
初始 0
配好 det44 后 1
执行 set interface ... del 2 ← 变多了
det44 plugin disable 0 ← 有时能清掉,有时清不掉残留的 det44-in2out 会抢在 nat44 前面拦包。后果是:
text
./labctl apply base 01 → 配置成功
./labctl vppctl base show nat44 interfaces
NAT44 interfaces:
host-eth1 in
host-eth2 out → 看起来完全正常
实际流量 → 全部不通配置一切正常、计数器也没有异常,但流量就是不走。 第一次遇到时几乎不可能猜到是上一轮 det44 实验的残留。
没有在线清理的办法。 唯一的解法是重建容器:
bash
./labctl down base && ./labctl up base更糟的是,在残留状态下继续操作 det44 和 nat44 的组合命令, 还可能直接把 VPP 打崩(崩溃栈同样指向 vlib_cli_input)。
本教程的实验脚本已经加了防护
reset.sh 每次都会检查这个残留,脏了就直接中止并告诉你怎么恢复:
text
✗ 接口上残留着 det44 的 feature 节点。
这是 VPP 26.06 的一个 bug:det44 插件关闭后,它注册在接口上的
det44-in2out 节点不会被摘掉,会继续抢在 nat44 前面拦包。
症状是 nat44-ed 的实验全部不通,但 show 出来的配置一切正常。
没有在线清理的办法,必须重建容器:
./down.sh && ./up.sh第 09 步的 apply 和 verify 也都会提醒你这一点。
对生产环境的启示
不要指望在一台运行中的 VPP 上"试试 det44,不合适再换回 nat44"。 在 26.06 上,这个切换需要重启 VPP 进程。
选型必须在上线前定好。真要评估,用一台独立设备或实验环境。
和 nat44 的对照
text
┌──────────────┬────────────────────────┬────────────────────────┐
│ │ nat44-ed / nat44-ei │ det44 │
├──────────────┼────────────────────────┼────────────────────────┤
│ 映射来源 │ 查表分配 │ 算法计算 │
│ 端口配额 │ 弹性,可从池里借 │ 固定,用完就断 │
│ 可追溯性 │ 靠日志(TB 级存储) │ 一条命令算出来 │
│ 状态开销 │ 每会话都要存分配决策 │ 只存活跃连接 │
│ 静态映射 │ 有 │ 无 │
│ twice-NAT │ ED 有 │ 无 │
│ 负载均衡 │ ED 有 │ 无 │
│ VRF 多租户 │ ED 有 │ 无(只有 inside/outside vrf)│
│ 会话高可用 │ EI 有 │ 无 │
└──────────────┴────────────────────────┴────────────────────────┘DET44 是一个功能极简、专为一个目的服务的插件。 它放弃了几乎所有花哨能力,换来可追溯性和极低的状态开销。
小结
| 核心思想 | 映射用算法算出来,不查表分配 |
| 配置 | det44 add in <内网前缀> out <公网前缀> + set interface det44 inside/outside |
| 端口公式 | 1024 + 主机序号 × (64512 / 共享比) |
| 唯一可调参数 | 共享比,由内外前缀大小之比决定 |
| 最大限制 | 端口配额固定,用完不能借,超标直接失败 |
| 致命坑一 | 内网前缀 ≥ /18 会让 VPP 崩溃,拆成多条 /19 |
| 致命坑二 | 会往接口注册 feature 节点且无法在线摘除,用完必须重建 VPP |
| 功能缺失 | 无静态映射、无 twice-NAT、无负载均衡、无 HA |
下一篇:可追溯性 —— DET44 存在的全部理由。