BPF CO-RE:一份 eBPF 程序怎样适配不同 Linux 内核?
TL;DR
BPF CO-RE 借助 BTF 类型信息和加载时重定位,减少 eBPF 程序因内核结构变化而反复编译的负担。本文解释它搬动的是哪些“结构偏移”,以及为什么 CO-RE 不等于任何内核、任何机器都能直接运行。
BPF CO-RE 借助 BTF 类型信息和加载时重定位,减少 eBPF 程序因内核结构变化而反复编译的负担。本文解释它搬动的是哪些“结构偏移”,以及为什么 CO-RE 不等于任何内核、任何机器都能直接运行。

eBPF 程序常常需要读取内核中的数据结构,例如进程、网络包或调度信息。但 Linux 内核会随着版本、配置和架构变化调整结构布局:字段可能移动,类型也可能发生变化。若程序把字段偏移写死,换一台机器或升级内核就可能读错位置。BPF CO-RE 的目标,是让这类程序少一些“每台机器重新编译”的负担。
编译时留下可调整的线索
CO-RE 是 Compile Once – Run Everywhere 的缩写。它依赖 BTF(BPF Type Format)等类型信息:目标内核提供自身类型和字段布局的描述;编译出来的 eBPF 对象则包含重定位记录,指出程序依赖了哪些类型或字段。加载器读取目标内核的 BTF,再把这些记录调整为该内核实际的布局。
可以把它想成一份可以自动校正的地图。程序不只记下“目标字段在第 24 个字节”,而是留下“我要访问这个类型里的这个字段”的语义线索。运行前,加载器对照目标内核的类型地图,重新计算访问位置。Linux 的 BPF LLVM 重定位文档展示了对象文件如何记录符号和偏移,以及加载时为何需要解析这些重定位。
“一次编译”仍有适用边界
CO-RE 解决的是一类重要的布局变化问题,并不意味着任意 eBPF 程序都能在所有 Linux 系统上工作。目标内核需要提供合适的 BTF 信息;程序使用的 helper、kfunc、挂载点、权限和配置也必须存在。架构差异、内核功能差异或安全策略限制,仍可能导致加载失败,或者要求开发者提供不同实现路径。
另外,CO-RE 不会替程序验证逻辑正确性。字段偏移被正确重定位,只说明程序更可能读到预期字段,不代表数据语义、并发时序或边界检查都没有问题。读取内核数据仍要遵循 verifier 的安全约束,加载流程也需要适当权限。
它的价值在于把“字段在哪儿”从编译时硬编码,改为加载时根据类型信息适配。对可观测性工具、网络诊断和系统分析程序来说,这能显著降低维护成本。理解 CO-RE 时,可以记住三件事:对象文件留下重定位、目标内核暴露类型信息、加载器据此做适配;这三环缺一不可。



