You need to enable JavaScript to run this app. 如何实现两个内核态BPF程序间的BPF map共享
优惠活动
大模型
产品
解决方案
定价
更多

如何实现两个内核态BPF程序间的BPF map共享

跨独立内核态BPF程序共享map的可落地实现

针对“一个BPF程序定义map、另一个独立BPF程序纯内核态访问,全程不依赖用户态中转map句柄”的场景,不需要走“用户态拿到map fd再转发给第二个程序”的通用方案,借助内核原生的全局map符号绑定能力就能实现,以下是可直接复用的代码示例和注意事项。

核心机制说明:只要map不设置私有标记、全局可见,同权限命名空间下的独立BPF程序可以在加载阶段直接通过全局符号完成map绑定,整个读写流程全在内核态完成,不需要用户态介入map的访问路径。

定义map的BPF程序侧实现

定义map的程序需要把map声明为全局可见,不能加私有修饰,示例代码:

// 文件名:map_producer.bpf.c
#include <vmlinux.h>
#include <bpf/bpf_helpers.h>

// 全局共享map,不使用static修饰,无私有标记
struct {
    __uint(type, BPF_MAP_TYPE_HASH);
    __uint(max_entries, 1024);
    __type(key, u32);
    __type(value, u64);
} shared_pid_counter SEC(".maps");

// 示例:该BPF程序挂载进程调度点,持续写入计数
SEC("tp_btf/sched_switch")
int BPF_PROG(sched_counter, bool preempt, struct task_struct *prev, struct task_struct *next)
{
    u32 current_pid = next->pid;
    u64 *cnt = bpf_map_lookup_elem(&shared_pid_counter, &current_pid);
    if (cnt) {
        *cnt += 1;
    } else {
        u64 init_val = 1;
        bpf_map_update_elem(&shared_pid_counter, &current_pid, &init_val, BPF_ANY);
    }
    return 0;
}

char LICENSE[] SEC("license") = "GPL";

侧端注意事项:

  • 不能给map加static修饰,加了会被编译器识别为程序私有,其他程序无法匹配到符号
  • 不能在map的flags字段设置BPF_F_PRIVATE,该标记会强制map和所属程序强绑定,拒绝跨程序引用
  • map必须放在标准的.maps段内,不能自定义段名

独立访问map的BPF程序侧实现

访问map的程序不需要实际申请map内存,只需要通过extern声明匹配全局符号,内核加载器会自动完成和已有map的绑定,示例代码:

// 文件名:map_consumer.bpf.c
#include <vmlinux.h>
#include <bpf/bpf_helpers.h>

// 仅做extern符号声明,不实际分配map内存
extern struct {
    __uint(type, BPF_MAP_TYPE_HASH);
    __uint(max_entries, 1024);
    __type(key, u32);
    __type(value, u64);
} shared_pid_counter SEC(".maps");

// 示例:该BPF程序是完全独立的字节码,挂载系统调用入口读取map值
SEC("tp_btf/sys_enter")
int BPF_PROG(sys_reader, struct pt_regs *regs, long id)
{
    u32 current_pid = bpf_get_current_pid_tgid() >> 32;
    u64 *cnt = bpf_map_lookup_elem(&shared_pid_counter, &current_pid);
    if (cnt) {
        bpf_printk("PID %d 累计调度次数: %llu", current_pid, *cnt);
    }
    return 0;
}

char LICENSE[] SEC("license") = "GPL";

侧端注意事项:

  • extern声明的map参数(类型、最大条目数、key/value长度)必须和定义端完全一致,内核校验阶段不匹配会直接拒绝加载
  • 两个程序的license必须兼容,跨程序的符号引用会经过eBPF权限校验,license不匹配会被拦截
  • 不需要用户态在两个程序之间做任何map句柄转发,整个map的读写流程全在内核态完成

加载流程的硬约束

  • 加载顺序必须固定:先加载定义端的程序(持有map所有权的程序),再加载访问端的程序。如果顺序颠倒,内核找不到对应的全局map符号,会直接导致访问端程序加载失败
  • 内核版本要求:需要内核版本 >= 5.8,更早的版本不支持跨独立BPF程序的全局map符号引用,只能通过用户态中转fd的方式实现共享
  • 边界说明:如果两个BPF程序是编译在同一个字节码对象文件内的多探针共享map,本质属于单程序内的资源共享,不属于跨独立BPF程序的场景

内容的提问来源于stack exchange,提问作者pyang

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.25 04:15:03