eBPF libbpf:BPF程序挂载后能否关闭bpf_object实例?
libbpf bpf_object与bpf_link生命周期核心说明
核心结论
按照示例里的现代libbpf(0.3+版本)开发流程完成程序挂载后,可以安全调用bpf_object__close(obj)释放对应bpf对象实例,但存在明确的使用边界;而*bpf_link实例必须全程被正确持有,不能随意释放或丢弃*。
底层逻辑拆解
要理清楚生命周期规则,首先得明白两类对象在用户态、内核态的本质差异:
- 内核侧的所有BPF实体(BPF程序、挂载生成的bpf_link、BPF map)都是基于匿名文件描述符实现的,自带独立引用计数:谁持有对应实体的fd,内核就算谁有一个有效引用,只要对应fd没被全部关闭,内核就不会回收这些实体,和用户态的结构体本身有没有被释放没有强制绑定关系。
bpf_object__close(obj)的实际执行逻辑是:释放用户态维护的bpf_object结构体内存、关闭它内部持有的所有BPF fd、卸载那些没有被其他引用额外持有的BPF程序和map结构。- 示例中
bpf_program__attach(prog)返回的独立struct bpf_link对象,是libbpf单独在堆上分配的结构,自身持有对应挂载点的独立fd,和原来的bpf_object不存在内部的强绑定引用关系。
不同场景的实际行为
- 程序成功通过独立
bpf_link完成挂载后,调用bpf_object__close(obj)不会导致内核中的BPF程序被卸载,也不会让挂载失效:因为此时BPF程序本身被bpf_link持有强引用计数,哪怕原来bpf_object持有的程序fd被关闭,内核也不会回收这个程序。 - 这种操作的硬限制是:一旦调用
bpf_object__close(obj),你就没法再通过bpf_object提供的接口(比如按名字查找map、读取程序元数据)操作关联的BPF资源了。如果后续需要持续操作对应的BPF map,必须在关闭obj之前,通过bpf_map__fd()拿到map的fd,把fd独立出来脱离obj的管理范围,否则obj释放时会自动关闭map的fd,导致后续map操作直接失效。 bpf_link实例绝对不能随意处置:一旦对应的link被主动调用bpf_link__destroy()销毁,或者因为指针丢失导致对应fd永久泄漏(这种情况虽然程序还在内核挂着,但用户态永远没法正常解绑了),内核会立刻触发解绑流程,把BPF程序从对应钩子点摘下来,程序就再也没法处理对应事件了。
常见踩坑提醒
- 上面的结论只适用于示例中返回独立
struct bpf_link的现代libbpf API。如果用的是老版本的attach接口(直接返回int类型的attach fd、不生成独立link结构),attach的fd是存在bpf_object内部的,这时候调用bpf_object__close(obj)会直接关闭attach fd,触发程序解绑,绝对不能提前关obj。 - 关闭obj之后,之前拿到的
bpf_program、bpf_map这类从obj衍生出来的用户态指针全部变成野指针,绝对不能再通过这些指针调用任何libbpf接口,不然会直接触发内存访问错误。
内容的提问来源于stack exchange,提问作者Mark
相关产品推荐
相关产品推荐

