主题
identity mapping:别让 NAT 吃掉设备自己的流量
这一篇解决一个很容易踩、但踩到时完全摸不着头脑的问题: NAT 网关配好之后,这台设备自己的服务突然连不上了。
问题是怎么产生的
回想接口地址伪装那一步:
bash
vppctl nat44 add interface address host-eth2这条命令把出接口地址 203.0.113.1 加进了地址池。从此以后,所有目的地址是 203.0.113.1 的入向包,都会被当成"某个内网主机的回包",交给 out2in 分支去查会话表。
但这台设备自己也要对外提供服务 —— BGP、SSH、SNMP、BFD、监控 agent…… 这些流量的目的地址同样是 203.0.113.1,同样会掉进 out2in 分支, 同样查不到会话,同样被丢掉。
NAT 设备并不知道这个包是发给它自己的。它眼里只有"池地址 + 查表"。
亲眼看一次
应用配置
bash
./labctl reset base
./labctl apply base 05这一步会在 VPP 自己的 dataplane netns 里起一个监听 tcp/1179 的服务 (用 1179 是为了让人联想到 BGP 的 179),然后配上 identity mapping。
跑自检
bash
./labctl verify base 05自检会先拆掉 identity mapping 看失败现象,再加回来看成功现象。
没有 identity mapping 时:
text
s1 尝试连接 VPP 自己的服务 203.0.113.1:1179 ...
✓ 连不上 —— 流量被 NAT 的 out2in 分支拦下了
丢包计数: 3 nat44-ed-out2in-slowpath no translation error服务明明在监听:
bash
./labctl sh base nat
# 在容器里:
ip netns exec dataplane ss -lntp | grep 1179text
LISTEN 0 16 0.0.0.0:1179 0.0.0.0:* users:(("python3",pid=937,fd=4))加上 identity mapping 之后:
bash
vppctl nat44 add identity mapping external host-eth2 tcp 1179text
VPP 自己的服务回话:我看到你的地址是 203.0.113.11:35549
✓ 看到的是 s1 的真实地址,说明源地址也没被动过通了,而且源地址原样保留 —— identity mapping 的语义就是完全不翻译,原样放行。
命令
bash
nat44 add identity mapping <ip4-addr>|external <interface> \
[<protocol> <port>] [vrf <table-id>] [del]三种常见写法:
bash
# 1. 按接口 + 协议端口(推荐)—— 接口地址变了会自动跟随
nat44 add identity mapping external host-eth2 tcp 179
# 2. 按具体地址 + 协议端口
nat44 add identity mapping 203.0.113.1 tcp 179
# 3. 只给地址,不给协议端口 —— 这个地址的所有流量都不翻译
nat44 add identity mapping 203.0.113.100第三种要慎用:它把整个地址从翻译里摘了出去。如果这个地址还在地址池里, 就会出现"池里有它但用不上"的尴尬局面。
生产环境该给哪些端口配
凡是这台设备自己监听、且需要从外网访问的端口,都要配:
| 服务 | 端口 | 备注 |
|---|---|---|
| BGP | tcp/179 | 和上游对等体建邻居 |
| SSH | tcp/22 | 带外管理走管理口的话可以不配 |
| SNMP | udp/161 | 监控轮询 |
| BFD | udp/3784, 3785 | 快速故障检测 |
| NETCONF | tcp/830 | 自动化配置 |
漏配的典型症状是"NAT 上线后监控告警说设备失联,但业务流量正常"。
一个会吓人的显示
配完之后 show nat44 static mappings 会看到两行:
text
NAT44 static mappings:
identity mapping TCP 203.0.113.1:1179 vrf 0
TCP local 64.154.183.118:1179 external host-eth2:1179 vrf -1第二行那个 local 64.154.183.118 是哪来的?它不是你配的,也不是任何真实地址。
原因是:按接口声明的映射会以"待解析"形式(vrf -1)额外存一份, 而 identity mapping 压根不用 local 字段,VPP 却照样把这块内存当地址打印出来了。 这是显示层的问题,不影响功能 —— 重复添加删除,这个值也不会变。
不要试图去删那一行
它和第一行是同一条配置。用你添加时的完整命令加 del 才能删掉:
bash
vppctl nat44 add identity mapping external host-eth2 tcp 1179 del和其他方案的比较
除了 identity mapping,还有两条路能让设备自己的服务不被 NAT 影响:
text
方案 优点 缺点
────────────────────────── ────────────────── ────────────────────────
identity mapping 精确,只豁免指定端口 每个服务都要配一条
地址变化自动跟随
管理流量走独立的带外管理口 彻底隔离,最干净 需要多一个物理/逻辑口
BGP 这类必须走业务口的没法用
用地址池代替接口地址伪装 设备地址天然不在池里 需要多一段公网地址
(见地址池那一篇) 上游要为这段地址路由第三条其实是最省心的:只要转换地址和设备地址不是同一个,这个问题根本不会出现。 所以规模稍大的部署普遍用独立地址池,而不是接口地址伪装。
identity mapping 主要服务于"只有一个公网地址、又必须在这个地址上跑服务"的场景 —— 也就是小型网关和边缘设备。
小结
| 解决什么 | 出接口地址被当池地址后,设备自身服务被 out2in 分支误伤 |
| 命令 | nat44 add identity mapping external <接口> <协议> <端口> |
| 语义 | 完全不翻译,源和目的都原样放行 |
| 症状签名 | no translation 计数上涨,同时设备自身服务从外部连不上 |
| 显示怪象 | 会多出一行 local <乱码地址> 的待解析条目,无害 |
| 更省心的替代 | 用独立地址池,让设备地址天然不在池里 |
下一篇:负载均衡映射 —— 一个公网端口分流给多台内网服务器。