主题
ABF:用 ACL 驱动转发
前两篇的 ACL 只做一件事:放行或丢弃。ABF(ACL Based Forwarding) 把 ACL 的匹配结果用在另一个地方 —— 决定包往哪走。
这就是通常说的策略路由(Policy-Based Routing): 不按目的地址查路由表,而是按更丰富的条件选择下一跳。
什么时候需要它
普通路由只看目的地址。但实际网络里经常需要按别的维度分流:
text
· 多出口:研发部门走专线,其他部门走普通宽带
· 服务链:把特定流量先导到防火墙 / IDS / 缓存,再放行
· 按业务分流:视频流量走高带宽链路,控制流量走低时延链路
· 灰度引流:把某个源网段的流量导到新集群这些条件(源地址、端口、协议)路由表都表达不了,但 ACL 可以。
配置
bash
# 1. 先建一条 ACL 来描述"哪些流量"
set acl-plugin acl permit src 10.10.0.12/32 dst 203.0.113.11/32
# 2. 建策略:命中这条 ACL 的包,改走这个下一跳
abf policy add id 1 acl <ACL索引> via 203.0.113.12 host-eth2
# 3. 挂到接口
abf attach ip4 policy 1 host-eth1
# 查看
show abf policy
show abf attach host-eth1abf policy 里的 via 部分和路由的 via 语法一致, 可以指定下一跳地址、出接口、甚至多路径。
实测
应用配置
bash
./labctl reset base
./labctl apply base 14这个实验刻意不开 NAT
原因见下文"和 NAT 的相互作用"那一节 —— 开了 NAT 之后, ABF 的 ACL 必须写转换后的地址,会让现象变得难以解释。 先在没有 NAT 的干净环境里看清 ABF 本身。
:::
策略生效后:
text
h1 → s1(ACL 不匹配,正常路由)
[s1 tcp/9000] 我看到你的地址是 10.10.0.11:36727
h2 → s1(ACL 匹配,被引到 s2 的下一跳)
(不通)trace 里能看到下一跳确实被改了:
text
00:26:22:597226: abf-input-ip4
tx_sw_if_index 2 dpo-idx 18 :
ipv4 via 203.0.113.12 host-eth2 ...
^^^^^^^^^^^^^^ 下一跳变成了 s2为什么 h2 "不通"才是成功
本实验的拓扑里 s1 和 s2 在同一个二层网段上。ABF 改的是下一跳, 不是目的地址 —— 包被送到了 s2 的 MAC,但 IP 头里的目的地址还是 s1 的 203.0.113.11。s2 发现这不是自己的地址,直接丢弃。
所以"h2 不通、h1 正常"恰恰证明了 ABF 在按 ACL 选择性引流。
真实场景里下一跳会是一台真正的路由设备(防火墙、另一个出口路由器), 它会继续按目的地址转发,流量能正常到达。
ABF 和路由的关系
ABF 的优先级高于普通路由,但它不改变路由表:
text
包进来
↓
abf-input-ip4 ── 命中 ACL?── 是 → 用策略里的下一跳
↓ (跳过 ip4-lookup 的结果)
否
↓
ip4-lookup ── 正常查路由表这带来一个实用性质:ABF 策略删掉之后,流量立刻回到正常路由, 不需要恢复任何路由配置。
bash
vppctl abf attach ip4 policy 1 host-eth1 del和 NAT 的相互作用
ABF 在 NAT 之后执行,ACL 要写转换后的地址
这是上一篇那个坑的又一种表现。
带 NAT 时把同样的策略挂上,会发现完全不生效:
text
h2 → s1(ACL 匹配 src 10.10.0.12)
[s1 tcp/9000] 我看到你的地址是 203.0.113.1:40217 ← 照常走了原路trace 揭示了原因:
text
NAT44_IN2OUT_ED_SLOW_PATH ... translation result 'success'
abf-input-ip4 ← ABF 在 NAT 之后
ip4-rewrite
ipv4 via 203.0.113.11 host-eth2 ← 下一跳没变包到达 abf-input-ip4 时,源地址已经被 NAT 改成 203.0.113.1 了, ACL 里写的 src 10.10.0.12/32 自然匹配不上。
要在 NAT 环境里用 ABF,ACL 只能匹配 NAT 之后仍然成立的字段 —— 目的地址、目的端口,或者转换后的源地址(但那样就区分不了具体是哪台内网主机了)。
如果一定要按内网源地址分流,得把 ABF 挂在 NAT 之前的位置, 或者换个思路:用 VRF 把不同租户/部门隔开(第 2 章), 每个 VRF 走自己的出口。
和 PNAT 的区别
PNAT 也能做"把这类流量导到别处",但两者本质不同:
text
┌──────────────┬────────────────────────┬──────────────────────────┐
│ │ ABF │ PNAT │
├──────────────┼────────────────────────┼──────────────────────────┤
│ 改什么 │ 只改**下一跳** │ 改**报文字段**(地址/端口)│
│ 报文内容 │ 一个字节都不动 │ 被改写 │
│ 匹配能力 │ 完整 ACL(多条规则) │ 单条五元组 │
│ 规则数量 │ 一个策略可含多条 ACL 规则 │ 每接口每方向仅 1 条 │
│ 对端看到 │ 原始地址 │ 改写后的地址 │
└──────────────┴────────────────────────┴──────────────────────────┘一句话区分:ABF 是"换条路走",PNAT 是"换个身份走"。
需要对端看到原始地址、只想改变路径 → ABF。 需要改写地址端口 → PNAT 或 NAT。
小结
| 定位 | 策略路由:按 ACL 匹配结果决定下一跳 |
| 配置 | abf policy add id N acl M via <下一跳> <接口> + abf attach ip4 policy N <接口> |
| 改什么 | 只改下一跳,报文内容不变 |
| 优先级 | 高于普通路由;策略删掉即恢复 |
| 与 NAT | ABF 在 NAT 之后执行,ACL 要写转换后的字段 |
| 典型用途 | 多出口分流、服务链、灰度引流 |
下一篇:uRPF —— 三层场景下防源地址欺骗的正解。