Skip to content

feat: ebpf support multi thread - #11836

Open
yuanchaoa wants to merge 2 commits into
v6.6from
66-ebpf-support-multi-thread
Open

feat: ebpf support multi thread#11836
yuanchaoa wants to merge 2 commits into
v6.6from
66-ebpf-support-multi-thread

Conversation

@yuanchaoa

Copy link
Copy Markdown
Contributor

This PR is for:

  • Agent

feat: eBPF supports multi-threading

Checklist

  • Added unit test.

Backport to branches

  • 6.6

@yuanchaoa

Copy link
Copy Markdown
Contributor Author

@claude @codex review一下当前pr中的代码修改,结论使用中文

@claude

claude Bot commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

Claude finished @yuanchaoa's task in 14m 41s —— View job


进度

  • 阅读仓库说明与 PR 上下文
  • 审查 origin/v6.6...HEAD 的代码修改
  • 输出中文评审结论

评审结论

我这轮静态审查里确认了 1 个阻塞问题,建议修复后再合入。

发现的问题

  1. agent/benches/labeler.rs:267 当前 bench 代码无法编译
    FirstPath::endpoint_fast_get() 的签名已经变成了 7 个参数,最后需要传 l2_end_0: bool(见 agent/src/policy/first_path.rs:736),但 benchmark 里的调用仍然只传了 6 个参数:
    first.endpoint_fast_get(1, EndpointTableType::Ebpf, key.src_ip, key.dst_ip, 2, 0);

    这会导致 cargo bench --no-run / cargo check --benches 直接失败,属于明确的编译回归。

    Fix this →

补充说明

  • 这次主要做的是静态代码审查,重点看了 agent/src/ebpf_dispatcher.rsagent/src/policy/*agent/src/trident.rs 以及配置文档相关改动。
  • 我尝试继续跑 Rust 定向测试,但当前环境下 cargo test 需要额外权限批准,因此这轮没有实际执行测试命令;如果你愿意,我可以在拿到权限后继续补跑 cargo test / cargo check --benches 做进一步确认。

@yuanchaoa
yuanchaoa force-pushed the 66-ebpf-support-multi-thread branch from 7f34742 to dc75dec Compare July 29, 2026 06:47
@yuanchaoa

Copy link
Copy Markdown
Contributor Author

@claude review一下当前pr中的代码修改,结论使用中文

@claude

claude Bot commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

Claude finished @yuanchaoa's task in 21m 33s —— View job


进度

  • 阅读仓库说明与 PR 上下文
  • 审查 origin/v6.6...HEAD 的代码修改
  • 输出中文评审结论

评审结论

这轮静态审查里,我确认了 1 个阻塞问题,建议修复后再合入。

发现的问题

  1. OTel 入口新增了对共享 fast-path cache 的无锁写入,会在并发请求下引入数据竞争
    agent/src/integration_collector.rs:549-551 现在改为调用 Policy::lookup_from_otel(),而这条路径会进入 agent/src/policy/policy.rs:390-460,最终走到 agent/src/policy/fast_path.rs:238,524,528,566 上那张全局共享的 otel_table,并通过 endpoint_fast_get()/endpoint_fast_add() 对其做读写。

    问题在于 Integration Collector 是异步 HTTP 服务,多个 OTel 请求可以并发执行;这里拿的是 Arc<PolicyGetter>,底层仍然是共享的 Policy 裸指针,没有任何锁或线程隔离。以前这条 OTel 路径只做只读的 endpoint 计算,这次改动把它变成了共享可变状态访问,因此在并发上报时可能出现 cache 状态损坏、错误 endpoint 结果,甚至直接崩溃。

    Fix this →

补充说明

  • 这次主要看了 agent/src/ebpf_dispatcher.rsagent/src/policy/*agent/src/trident.rsagent/src/integration_collector.rs 以及配置接线相关改动。
  • 我这轮没有实际执行 cargo test / cargo check;结论基于静态代码审查。

@yuanchaoa
yuanchaoa force-pushed the 66-ebpf-support-multi-thread branch from dc75dec to c488af1 Compare July 29, 2026 08:34
@yuanchaoa

Copy link
Copy Markdown
Contributor Author

@claude review一下当前pr中的代码修改,结论使用中文

@claude

claude Bot commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

Claude finished @yuanchaoa's task in 8m 21s —— View job


进度

  • 阅读仓库说明与 PR 上下文
  • 审查 origin/v6.6...HEAD 的代码修改
  • 输出中文评审结论

评审结论

这轮静态审查里,我确认了 2 个阻塞问题,建议修复后再合入。

发现的问题

  1. OTel 新增 fast-path 之后,仍然把共享 Policy 暴露给并发 HTTP 请求,存在竞态和未定义行为
    agent/src/integration_collector.rs:549-551 现在会在每个 OTel 请求里调用 Policy::lookup_from_otel();而 MetricServer 把同一个 Arc<PolicyGetter> 克隆进每个 hyper 请求处理协程(agent/src/integration_collector.rs:1239-1289),PolicyGetter 本身又是基于裸指针并 unsafe impl Send + Sync 的共享可变访问(agent/src/policy/policy.rs:626-636)。这条新路径会进入 lookup_endpoint() 并写 endpoint_fast_add/get 的 OTel cache,同时还会继续访问 nats[fast_index] 等可变状态(agent/src/policy/policy.rs:399-460,519-565)。

    结果是:并发上报两个 OTel trace 时,会有多个请求同时拿到同一个 &mut Policy,这是明确的竞态;轻则 endpoint / GPID 命中错乱,重则直接触发内存未定义行为。这个问题是当前 PR 新引入的,因为之前 OTel 路径没有这层共享 fast-path 写入。

    Fix this →

  2. interface_regex 已被改成 agent_restart 语义,但本次实现并不会在 Local 模式下真正触发重启或重建 dispatcher
    文档和模板已经把 inputs.cbpf.af_packet.interface_regex 标成了 agent_restartserver/agent_config/README.md:2531, server/agent_config/template.yaml:1903),并说明当它导致 dispatcher 线程数变化时需要重启。但代码里 ConfigHandler 只是简单更新该字符串(agent/src/config/handler.rs:3086-3091),没有把它加入 restart_agent 原因集合;与此同时,component_on_config_change() 在 Local 模式下也删掉了原先的 dispatcher retain/rebuild 逻辑,只会对现有 dispatcher 调 on_tap_interface_change() 然后 policy_setter.reset_queue()agent/src/trident.rs:1279-1309)。

    这意味着:如果用户把 interface_regex 从匹配 1 块网卡改成匹配 2 块,或者让它跨 namespace 多匹配出新的采集目标,agent 既不会重启,也不会补建新的 dispatcher / queue,新增网卡流量会继续漏采,直到人工重启。这个行为和这次 PR 自己更新后的文档承诺不一致。

    Fix this →

补充说明

  • agent/benches/labeler.rs 里 bench 对新接口签名的适配已经补上了,这次没有再看到上轮提到的 bench 编译回归。
  • 我这轮没有实际执行 cargo check / cargo test;当前环境下相关命令需要额外权限批准,所以结论基于静态代码审查。

@yuanchaoa
yuanchaoa force-pushed the 66-ebpf-support-multi-thread branch from c488af1 to fc823bb Compare July 29, 2026 09:36
@yuanchaoa

Copy link
Copy Markdown
Contributor Author

@claude review一下当前pr中的代码修改,结论使用中文

@claude

claude Bot commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

Claude finished @yuanchaoa's task in 13m 51s —— View job


进度

  • 阅读仓库说明与 PR 上下文
  • 审查 origin/v6.6...HEAD 的代码修改
  • 输出中文评审结论

评审结论

这轮静态审查里,我确认了 2 个阻塞问题,建议修复后再合入。

发现的问题

  1. OTel 新增 fast-path 后,当前实现把共享 Policy 暴露给并发 HTTP 请求,存在明确竞态
    agent/src/integration_collector.rs:549-551 现在会在每个 OTel 请求里调用 Policy::lookup_from_otel();但 MetricServer 会把同一个 Arc<PolicyGetter> 克隆进并发的 hyper 请求处理协程(agent/src/integration_collector.rs:1239-1289)。PolicyGetter 又是通过裸指针伪造 &mut Policy,并直接 unsafe impl Send + Syncagent/src/policy/policy.rs:651-662)。这条新路径最终会写共享的 OTel fast-path cache(agent/src/policy/fast_path.rs:236-238,555,600)。

    结果是两个 OTel 请求并发命中时,会同时修改同一份 Policy / otel_table。轻则 endpoint / GPID 命中错乱,重则可能触发未定义行为。fast_path.rs 里的注释已经写明这张表“must be accessed by an otel dispatcher thread”,但当前 collector 并没有做串行化。

    Fix this →

  2. interface_regex 已改成 agent_restart 语义,但 Local 模式运行时并不会真正重启或重建 dispatcher 拓扑
    文档和模板已经把 inputs.cbpf.af_packet.interface_regex 标成了 agent_restart,并明确写了“当配置导致 dispatcher 线程数变化时才会重启”(server/agent_config/README.md:2530-2558, server/agent_config/template.yaml:1906-1925)。但代码里 ConfigHandler 只是简单替换字符串(agent/src/config/handler.rs:3086-3096),没有把它加入 restart_agent 原因集合;与此同时,component_on_config_change() 在 Local 模式下也只是对现有 dispatcher 调 on_tap_interface_change(),最后 reset_queue()agent/src/trident.rs:1279-1309),并不会按新的 regex 重新创建或销毁 dispatcher / queue。

    这意味着:如果用户把 interface_regex 从匹配 1 块网卡改成匹配 2 块,或者新增/删减了命中的 namespace / NIC,当前 agent 仍然保持旧的 dispatcher 布局,新增采集目标不会被补建,删除的布局也不会被回收,行为和这次 PR 自己更新后的文档承诺不一致。

    Fix this →

补充说明

  • 仓库内这次没有发现额外的 CLAUDE.md 约束文件可供遵循。
  • agent/benches/labeler.rs 里 bench 对新接口签名的适配已经在当前版本补上了,这次没有再看到我前几轮提到的 bench 编译回归。
  • 这轮没有实际执行 cargo check / cargo test,结论基于静态代码审查。

@yuanchaoa
yuanchaoa force-pushed the 66-ebpf-support-multi-thread branch from fc823bb to cdeb134 Compare July 29, 2026 10:25
@yuanchaoa

Copy link
Copy Markdown
Contributor Author

@claude review一下当前pr中的代码修改,结论使用中文

@claude

claude Bot commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

Claude finished @yuanchaoa's task in 21m 56s —— View job


进度

  • 阅读仓库说明与 PR 上下文
  • 理解本次 review 诉求并确认审查范围
  • 审查 origin/v6.6...HEAD 的代码修改
  • 输出中文评审结论

评审结论

这轮静态审查里,我确认了 2 个阻塞问题,建议修复后再合入。

发现的问题

  1. 普通流量的 GPID/NAT 查询现在读不到新同步的数据,等价于把 GPID enrichment 静默关掉了
    agent/src/policy/policy.rs:564-623 里,普通流量路径 lookup_gpid_entry() 现在固定从 self.nats[packet.fast_index][protocol] 读取(agent/src/policy/policy.rs:564-577),但同一个文件里的 update_gpids() 并没有再把新表写回 self.nats,而是只更新了 nats_cachesotel_natsagent/src/policy/policy.rs:594-623)。我在当前文件里没有看到任何地方会把 nats_caches 刷回 self.nats
    结果是:平台同步到新的 GPID/NAT 映射后,非 OTel 的普通包 / eBPF 流量仍然只会查到初始化时那份空表,gpid_0/gpid_1 和 NAT 真实地址补全会持续缺失;只有 OTel 路径还会命中单独的 otel_nats。这是明确的功能回归。
    Fix this →

  2. interface_regex 被文档标成 agent_restart,但当前热更新路径仍然不会为“新变成可采集”的 netns / dispatcher 布局补建线程
    启动阶段只会为 get_listener_links() 非空的 namespace 创建 dispatcher:agent/src/trident.rs:2055-2064 会先枚举 extra_netns_regex 命中的 netns,再在 agent/src/trident.rs:2090-2097 / 2170-2172 基于这些结果决定 interfaces_and_ns.len(),并据此创建 Policy / dispatcher 数量。与此同时,文档已经把 inputs.cbpf.af_packet.interface_regex 标成 agent_restart,并明确说“只有当配置导致 dispatcher 线程数变化时才会重启”(server/agent_config/README.md:2530-2572server/agent_config/template.yaml 同步更新)。
    但运行时更新这项配置时,agent/src/config/handler.rs:3086-3096 只是替换字符串;agent/src/trident.rs:1279-1309 也只会对现有 dispatcher_componentson_tap_interface_change(),且只在 dispatcher_components.is_empty() 时处理 root namespace 的“0 变 1”场景。对于更常见的情况——例如配置了 extra_netns_regex,某个 netns 启动时因为 interface_regex 不匹配而没有创建 dispatcher,后来把 regex 放宽后这个 netns 开始有可采集网卡——当前代码不会新建 dispatcher,也不会触发重启,导致该 netns 的流量继续漏采,直到人工重启 agent。
    Fix this →

补充说明

  • 仓库内这次没有发现额外的 CLAUDE.md 约束文件可供遵循。
  • 这轮没有实际执行 cargo check / cargo test;结论基于静态代码审查。

@yuanchaoa
yuanchaoa force-pushed the 66-ebpf-support-multi-thread branch from cdeb134 to 7dc9bca Compare July 29, 2026 10:52
@yuanchaoa

Copy link
Copy Markdown
Contributor Author

@claude review一下当前pr中的代码修改,结论使用中文

@claude

claude Bot commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

Claude finished @yuanchaoa's task in 16m 42s —— View job


进度

  • 初始化 review 清单
  • 阅读仓库说明与 CLAUDE.md
  • 审查 origin/v6.6...HEAD 的代码修改
  • 输出中文评审结论

评审结论

这轮静态审查里,我确认了 2 个阻塞问题,建议修复后再合入。

发现的问题

  1. eBPF 多线程模式把同一份 Policy 暴露给多个 collector 线程并发写,当前实现存在明确竞态/未定义行为
    inputs.ebpf.tunning.collector_queue_count 现在会直接映射成 eBPF collector 的 queue_countagent/src/config/handler.rs:2427-2428),EbpfCollector::start() 会按这个值启动多个 ebpf-collector-* 线程(agent/src/ebpf_dispatcher.rs:1551-1568)。但每个线程拿到的 EbpfDispatcher 都只是浅拷贝,同一个 PolicyGetter 会被复制进每个线程(agent/src/ebpf_dispatcher.rs:340-351),随后再传给各自的 FlowMapagent/src/ebpf_dispatcher.rs:473-485)。PolicyGetter 本身又是基于裸指针并 unsafe impl Send + Sync,且 policy() 直接返回 &mut Policyagent/src/policy/policy.rs:657-668)。
    这意味着:只要把 collector_queue_count 配成大于 1,多个 eBPF collector 线程就会并发把同一块 Policy 伪造成多个 &mut 并同时修改 fast-path / GPID 等共享状态。轻则策略命中和 endpoint 标注错乱,重则直接触发内存未定义行为。这和 PR 的“支持多线程”目标正面冲突。
    Fix this →

  2. interface_regex 已被文档标成 agent_restart,但当前热更新路径仍不会为“新变成可采集”的 namespace / NIC 补建 dispatcher
    文档和模板已经把 inputs.cbpf.af_packet.interface_regex 标成 agent_restart,并明确说明“只有当配置导致 dispatcher 线程数变化时才会重启”(server/agent_config/README.md:2530-2572server/agent_config/template.yaml:1906-1925)。但运行时更新这项配置时,ConfigHandler 只是替换字符串(agent/src/config/handler.rs:3086-3096);随后 component_on_config_change() 在 Local 模式下也只会刷新现有 dispatcher 的监听网卡(agent/src/trident.rs:1279-1309)。与此同时,启动阶段只有在某个 namespace 当时已经匹配到接口时,才会把它放进 interfaces_and_ns 并创建 dispatcher(agent/src/trident.rs:2055-2064, agent/src/trident.rs:2090-2097)。
    结果是:如果某个 netns / NIC 在启动时因为 interface_regex 不匹配而没有创建 dispatcher,后续再把 regex 放宽,当前热更新路径既不会重启 agent,也不会新建 dispatcher,这部分流量会继续漏采直到人工重启。当前运行时行为和这次 PR 自己更新后的文档承诺不一致。
    Fix this →

补充说明

  • 仓库内这次没有发现额外的 CLAUDE.md 约束文件可供遵循。
  • agent/benches/labeler.rs:267-275endpoint_fast_get() 新签名的适配已经补上了,这次没有再看到前几轮提到的 bench 编译回归。
  • 这轮没有实际执行 cargo check / cargo test;结论基于静态代码审查。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant