dpdk acl更新

82 阅读4分钟

在前一篇文章中,当控制面更新一条 ACL 规则时,如何更新给数据面- 掘金
介绍了dpdk中 基于trie tree的acl的实现,更新一条acl配置时,要重新构建trie tree。但是重新构建应该不是在控制平面,而是control-dp。 可以参考控制平面和数据平面各自角色功能 - 掘金

通常由 control-dp 线程负责 ACL 规则重建

1. 为什么是 control-dp

在典型的 DPDK 多线程架构中:


+-----------------------------+
| Main Lcore (control-dp)     |
|  - 接收控制面消息            |
|  - 解析规则、重建 ACL Trie   |
|  - 管理定时器、统计上报      |
+-----------------------------+
              |
              v
+-----------------------------+    +-----------------------------+
| Worker Lcore 0 (data plane) |    | Worker Lcore N (data plane) |
|  - 收包、ACL 匹配、转发      |    |  - 收包、ACL 匹配、转发      |
|  - 使用共享的 acl_ctx        |    |  - 使用共享的 acl_ctx        |
+-----------------------------+    +-----------------------------+
  • control-dp(通常运行在 main lcore)是数据面中唯一与控制面通信的入口

  • 它负责:

    • 接收控制面通过 IPC/共享内存发来的规则更新;
    • 验证、解析规则;
    • 调用 rte_acl_build() 重建整个 Trie 结构
    • 原子发布新 acl_ctx 给所有 worker;
  • 所以:✅ 是的,Trie Tree 的重建通常在 control-dp 线程中完成


✅ 二、control-dp 是否要“存储所有规则”?

分两个层面看:

1. 是否需要“规则原始数据”?✅ 是的

  • control-dp 必须持有当前生效的所有 ACL 规则的副本(如 struct acl_rule rules[]);

  • 原因:

    • 每次更新(增/删/改)时,需要基于完整规则集重建 rte_acl_ctx
    • DPDK rte_acl 不支持“只添加一条规则”,必须传入全部规则数组
    • 所以 control-dp 必须维护一个规则数据库(rule DB) ,用于下次重建。

🔹 类比:就像编译器需要源代码才能重新编译可执行文件。

2. 是否需要“运行时匹配结构”(Trie)?✅ 是的

  • control-dp 本身不参与报文转发,但它需要:

    • 调用 rte_acl_build(acl_ctx, rules, n) —— 这个过程会在内存中构建 Trie
    • 构建完成后,将 acl_ctx 发布给 worker 线程;
  • 所以:control-dp 在重建期间会临时持有 Trie 结构,但构建完成后,它只保留规则数据,而 Trie 主要由 worker 使用


✅ 三、内存布局示意图

text
深色版本
+--------------------------------------------------+
|               Shared Memory Region               |
|                                                  |
|  +---------------------+                         |
|  | Rule DB (Raw Rules)  | ← control-dp 维护       |
|  | [rule1, rule2, ...]  |                        |
|  +---------------------+                         |
|                                                  |
|  +---------------------+                         |
|  | Current acl_ctx      | ← 所有 worker 共享使用   |
|  | (Trie structure)     |                        |
|  +---------------------+                         |
|                                                  |
|  +---------------------+                         |
|  | Pending acl_ctx      | ← control-dp 构建中     |
|  | (new Trie)           | (双缓冲)              |
|  +---------------------+                         |
|                                                  |
+--------------------------------------------------+
  • control-dp

    • 读写 Rule DB
    • 创建 Pending acl_ctx
    • 构建完成后,原子替换 Current acl_ctx
  • worker

    • 只读 Current acl_ctx,用于 rte_acl_classify()

✅ 四、为什么不把“规则重建”放在控制面?

你可能会问:既然 control-dp 要存规则、要重建 Trie,为什么不干脆让控制面来做?

答案:性能与解耦的权衡

方案优点缺点
控制面重建 Trie,下发二进制结构worker 无需重建,更新快控制面压力大;二进制兼容性问题;跨进程指针无效
control-dp 重建 Trie✅ 数据面自主;避免跨进程复杂性;可利用 SIMD 优化control-dp 需要存规则和重建能力

主流选择是后者:让 control-dp 负责重建,原因:

  • 避免控制面成为性能瓶颈;
  • 避免传输巨大的二进制结构(如 10 万条规则的 Trie 占几十 MB);
  • 允许数据面根据本地 CPU 特性(如 AVX-512)优化构建过程。

✅ 五、如何优化 control-dp 的资源开销?

虽然 control-dp 需要存储规则和重建 Trie,但可以通过以下方式优化:

1. 双缓冲(Double Buffering)

  • 维护两个 acl_ctxcurrent 和 pending
  • control-dp 在 pending 上构建;
  • 构建完成后,原子切换指针;
  • 旧 current 延迟释放(等待 worker 不再引用);

2. 异步重建

  • control-dp 收到规则更新后,不立即重建
  • 标记“规则已变更”,在低负载时重建;
  • 避免影响转发性能。

3. 增量分类器替代 rte_acl

  • 使用支持增量更新的分类器(如 VPP classify、BPF map);
  • control-dp 只需插入单条规则,无需重建整个 Trie;
  • 内存和 CPU 开销大幅降低。

4. 规则压缩

  • 合并等价规则;
  • 使用 prefix sharing 减少 Trie 节点数;
  • 降低内存占用。

✅ 六、总结:回答你的问题

“重建 Trie Tree 是不是在 control-dp 中?”

是的control-dp 是数据面中唯一适合做这件事的线程,它负责接收规则、重建 Trie、发布新上下文。

“那它岂不是也要存储所有的规则?”

是的,但它必须这么做

  • 它需要规则原始数据来调用 rte_acl_build()
  • 它需要临时构建 Trie,但不参与转发;
  • 这是  “功能完整性” 与 “性能隔离” 之间的合理权衡

🔁 类比:就像一个“工厂的质检员”,他不直接生产产品(转发),但需要图纸(规则)和检测设备(Trie)来确保生产线(worker)使用的工具是正确的。


💡 最佳实践建议

目标建议
减少 control-dp 开销使用支持增量更新的分类器(如 VPP classify、BPF)
提高更新实时性双缓冲 + 原子切换
降低内存占用规则压缩、共享前缀
避免阻塞转发异步重建、低优先级任务队列

这种设计是现代高性能网络系统的标准模式,理解它有助于构建更健壮的数据面架构。