主题
地址池
接口地址伪装的天花板是一个地址的端口数。这一篇讲怎么突破它, 以及一个几乎所有人第一次配地址池时都会问的问题:外网怎么知道这些地址在哪。
解决的问题
三种情况下你需要独立地址池:
- 容量不够 —— 一个地址约 64512 个可用端口,人均 100 条并发会话就是几百个用户封顶
- 想把业务流量和管理流量分开 —— 转换用池地址,设备管理用接口地址,抓包时一眼分得清
- 要按租户分配不同地址 —— 多租户场景下,不同 VRF 用不同的池
配置
应用配置
bash
./labctl reset base
./labctl apply base 02bash
vppctl nat44 plugin enable
vppctl set interface nat44 in host-eth1 out host-eth2
vppctl nat44 add address 203.0.113.100 - 203.0.113.102地址池的写法:
bash
nat44 add address 203.0.113.100 # 单个地址
nat44 add address 203.0.113.100 - 203.0.113.110 # 一段范围
nat44 add address 203.0.113.100 - 203.0.113.110 tenant-vrf 10 # 绑定到 VRF
nat44 add address 203.0.113.200 twice-nat # 用于 twice-NAT 的独立池
nat44 add address 203.0.113.100 del # 删除别和接口地址伪装混用
技术上两者可以共存,但那样"这个包为什么用了这个地址"会变得很难讲清楚。 所以实验步骤的 apply.sh 里,配地址池前会先把接口地址从池里摘掉:
bash
nat44 add interface address host-eth2 del生产环境里同样建议二选一。
那个必然会遇到的问题:外网怎么知道池地址在哪
池里的地址 203.0.113.100-102 并没有配在任何接口上。s1 收到一个源地址是 203.0.113.101 的包,要回包时会问:这个地址的 MAC 是多少? 然后发 ARP 请求。
谁来应答?
如果换成 Linux + iptables,你多半得手工配 proxy-arp 或者在接口上加辅助地址。 VPP 不用 —— 它在你执行 nat44 add address 的那一刻,就把这些地址装进了 FIB。
亲自看一眼
bash
./labctl vppctl base show ip fib 203.0.113.100text
203.0.113.100/32 fib:0 index:28 locks:2
nat-low refs:1 entry-flags:connected,exclusive,local,
path-list:[47] locks:2 flags:local,exclusive,
path:[74] ip4 weight=1 pref=0 receive:
[@0]: dpo-receive: 203.0.113.100 on host-eth2三个关键词:
local—— VPP 认为这是自己的地址dpo-receive—— 收到目的是这个地址的包,交给本机处理(而不是转发)on host-eth2—— 关联在出接口上,所以 VPP 会在这个接口上替它应答 ARP
验证一下 s1 的 ARP 表:
bash
./labctl vppctl base show nat44 addresses # 先产生一些流量
ssh chenzhong@192.168.49.182 'docker exec clab-natbase-s1 ip neigh'text
203.0.113.102 dev eth1 lladdr aa:c1:ab:40:e9:0d ref 1 REACHABLE
203.0.113.1 dev eth1 lladdr aa:c1:ab:40:e9:0d STALE
203.0.113.101 dev eth1 lladdr aa:c1:ab:40:e9:0d ref 1 DELAY池地址和接口地址指向同一个 MAC —— 都是 VPP 在应答。零配置。
如果池地址不在直连网段呢
上面这套只在池地址属于出接口所在网段时才够用。如果你的池是一段独立网段 (比如出接口是 198.51.100.1/30 的点对点链路,池是 203.0.113.0/24), 就没有 ARP 的事了 —— 需要上游路由器有一条指向本设备的路由, 把这段地址的流量送过来。这在运营商环境里是常态,通常靠 BGP 或静态路由宣告。
验证
跑自检
bash
./labctl verify base 02text
内网主机 转换后地址
─────────────── ─────────────────────
10.10.0.11 (h1) 203.0.113.101:42803
10.10.0.12 (h2) 203.0.113.102:45373两台内网主机落到了不同的池地址上。
VPP 是怎么挑池地址的
不是轮询,也不是随机 —— 是按内网地址算的。同一个内网地址的所有会话, 会稳定地落在同一个池地址上。
这个性质有实际意义:
text
✓ 好处
· 服务器端看到的源地址稳定,依赖源 IP 的会话保持不会失效
· 排障时"这个用户用哪个公网地址出去"是确定的,日志好对
· 某些风控/限流按源 IP 计数,稳定映射不会误伤
✗ 代价
· 分布不均匀。哈希撞在一起时,两台内网主机会共用一个池地址,
而另一个池地址闲着
· 池地址数量少时尤其明显(我们只有 3 个)自己验证稳定性
反复让 h1 连几次,看池地址会不会变:
bash
for i in 1 2 3; do
ssh chenzhong@192.168.49.182 \
'docker exec clab-natbase-h1 nc -w 2 203.0.113.11 9000'
done地址应该每次都一样,只有端口在变。
容量与监控
bash
./labctl vppctl base show nat44 addresses
./labctl vppctl base show nat44 summarytext
NAT44 pool addresses:
203.0.113.100
tenant VRF independent
203.0.113.101
tenant VRF independent
203.0.113.102
tenant VRF independentnat44-ed 不显示每地址的端口占用
nat44-ei 的 show nat44 ei addresses 会带上 N busy tcp ports 这样的统计, 但 ED 没有。想在 ED 下判断端口压力,只能靠:
show nat44 summary的会话总数(逼近max translations per thread就危险了)show errors里的分配失败计数
这是 ED 在可观测性上的一个实际短板,规划监控时要注意。
容量估算:
text
可用端口 ≈ 64512 × 池地址数
支持用户数 ≈ 可用端口 / 人均并发会话数
例:3 个地址,人均 100 条会话
64512 × 3 / 100 ≈ 1900 个用户池地址数量的经验法则
哈希分布不均是常态。规划时按峰值需求的 1.3~1.5 倍配池大小, 不要卡着理论值配 —— 否则会出现"总容量看起来够,但某个池地址先被打满"的情况。
什么时候不该用地址池
text
✓ 适合 ✗ 不适合
────────────────────────────── ────────────────────────────
用户规模超过单地址容量 只有一个公网地址可用
需要区分业务流量和管理流量 公网地址是动态的(DHCP)
多租户,按 VRF 分配不同池 —— 池地址写死了,地址一变就失效
上游能为这段地址路由过来 上游不肯为你多宣告一段地址最后一条在实际项目里最常卡住:地址池是一段需要被路由到你这台设备的地址。 在企业环境里这通常意味着要和网络组协调,不是配一条命令就完事。
小结
| 命令 | nat44 add address <起> - <止> |
| ARP 怎么办 | 不用管,VPP 自动把池地址装成 FIB local,代答 ARP |
| 地址怎么挑 | 按内网地址哈希,同一内网主机稳定用同一池地址 |
| 容量 | ≈ 64512 × 池地址数个端口 |
| 监控短板 | ED 不显示每地址端口占用,只能看会话总数和错误计数 |
下一篇:静态映射与端口转发 —— 让外网能主动连进来。