Skip to content

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-eth1

abf 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 <接口>
改什么只改下一跳,报文内容不变
优先级高于普通路由;策略删掉即恢复
与 NATABF 在 NAT 之后执行,ACL 要写转换后的字段
典型用途多出口分流、服务链、灰度引流

下一篇:uRPF —— 三层场景下防源地址欺骗的正解。

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