eBPF 动态 Map
BPF 动态 Map是 eBPF 中支持运行时动态创建、销毁、调整大小的 Map 类型区别于传统静态 Map编译时固定大小、固定键值类型。它是 Linux 5.10 内核引入的核心能力彻底解决了传统 eBPF Map 「静态不灵活、资源浪费、无法动态扩容」的痛点广泛用于云原生、网络观测、安全监控等场景。动态创建 / 销毁无需在 BPF 程序编译时定义可在用户态用bpf_map_create()随时创建、关闭销毁动态调整大小支持运行时扩容 / 缩容部分类型动态类型键值大小、Map 最大元素数都可在运行时指定内核版本要求Linux 5.10主流发行版CentOS 8/Ubuntu 20.04已支持动态 Map vs 传统静态 Map特性传统静态 MapBPF 动态 Map创建时机编译时固定定义运行时动态创建大小 / 键值类型编译时写死运行时自由指定生命周期随 BPF 程序 / 挂载点独立生命周期手动管理内核依赖全版本支持Linux 5.10共享能力可共享但不灵活天然支持多程序 / 进程共享支持的动态 Map 类型所有标准 BPF Map 都支持动态创建最常用BPF_MAP_TYPE_HASH哈希表最常用BPF_MAP_TYPE_ARRAY数组 MapBPF_MAP_TYPE_PERCPU_HASH / PERCPU_ARRAYPer-CPU 高性能 MapBPF_MAP_TYPE_RINGBUF高性能环形缓冲区观测数据上报动态 Map 核心 API用户态 C 语言动态 Map 完全通过用户态系统调用创建 / 操作BPF 程序通过文件描述符 (fd)访问。1. 创建动态 Map#include bpf/bpf.h #include bpf/libbpf.h // 核心函数动态创建 Map int bpf_map_create(enum bpf_map_type map_type, const char *map_name, // Map 名称调试用 __u32 key_size, // 键大小字节 __u32 value_size, // 值大小字节 __u32 max_entries, // 最大元素数 const struct bpf_map_create_attr *attr);返回值Map 文件描述符fd后续所有操作都用这个 fd关闭close(fd)会自动销毁 Map无引用时2. 操作动态 Map// 增/改 int bpf_map_update_elem(int fd, const void *key, const void *value, __u64 flags); // 查 int bpf_map_lookup_elem(int fd, const void *key, void *value); // 删 int bpf_map_delete_elem(int fd, const void *key);完整可运行示例场景用户态动态创建 HASH MapBPF 程序读取 Map 数据1. BPF 程序内核态dyn_map.bpf.cBPF 程序不定义 Map只通过外部 fd引用动态 Map// 用 extern 声明外部动态 Map核心 struct { __uint(type, BPF_MAP_TYPE_HASH); __type(key, __u32); __type(value, __u64); } dyn_map SEC(.maps); // 跟踪点读取动态 Map 数据 SEC(tracepoint/syscalls/sys_enter_open) int trace_enter_open(struct trace_event_raw_sys_enter* ctx) { __u32 key 100; __u64 *val; // 从动态 Map 中查找值 val bpf_map_lookup_elem(dyn_map, key); if (val) { bpf_printk(dyn map value: %llu\n, *val); } return 0; } char LICENSE[] SEC(license) GPL;2. 用户态程序加载 BPF 创建动态 Mapdyn_map.c#include stdio.h #include stdlib.h #include libbpf/libbpf.h #include dyn_map.skel.h int main() { struct dyn_map_bpf *skel; int map_fd, err; __u32 key 100; __u64 value 9988; // 1. 加载 BPF 骨架程序 skel dyn_map_bpf__open_and_load(); if (!skel) { fprintf(stderr, 加载 BPF 失败\n); return 1; } // 2. 动态创建 HASH Map运行时指定参数 map_fd bpf_map_create( BPF_MAP_TYPE_HASH, // Map 类型 my_dynamic_map, // 名称 sizeof(__u32), // 键大小 sizeof(__u64), // 值大小 1024, // 最大元素数 NULL // 扩展属性 ); if (map_fd 0) { perror(创建动态 Map 失败); return 1; } printf(动态 Map 创建成功fd%d\n, map_fd); // 3. 向动态 Map 写入数据 bpf_map_update_elem(map_fd, key, value, BPF_ANY); // 4. 将动态 Map 绑定到 BPF 程序替换 extern Map skel-maps.dyn_map bpf_map__from_fd(map_fd); // 5. 附加跟踪点 err dyn_map_bpf__attach(skel); if (err) { fprintf(stderr, 附加失败\n); return 1; } printf(运行中... 按 CtrlC 退出\n); pause(); // 清理 dyn_map_bpf__destroy(skel); close(map_fd); return 0; }BPF 程序中动态创建 Map进阶内核 5.18 支持BPF 程序内部动态创建 Map使用bpf_map_new()/bpf_map_put()实现内核态动态 Map// 内核态动态创建 Map struct bpf_map *map bpf_map_new( BPF_MAP_TYPE_HASH, sizeof(__u32), sizeof(__u64), 128, 0 ); // 使用完释放 bpf_map_put(map);适用场景BPF 程序按需创建临时 Map用完即销毁。动态 Map 高级特性1. Map 共享动态 Map 天生支持共享多个 BPF 程序可绑定同一个 Map fd多进程可通过bpf_map_get_fd_by_id()根据 Map ID 共享2. 内核态 / 用户态双向操作用户态创建、增删改查内核态查找、更新、删除完美解耦「资源管理」和「数据处理」3. 持久化与命名支持BPF FS 命名/sys/fs/bpf/my_map重启前持久化支持bpf_map_get_fd_by_name()按名获取使用限制与注意事项内核版本最低Linux 5.10动态创建全类型5.18 支持内核态创建权限需要CAP_BPF、CAP_PERFMON权限root 运行资源限制受/proc/sys/kernel/bpf_*系统参数限制生命周期最后一个 fd 关闭后Map 自动销毁总结动态 Map 运行时创建 灵活配置 独立生命周期彻底替代静态 Map核心用法用户态用bpf_map_create()创建 → 绑定到 BPF 程序 → 双向操作适用场景动态观测、多程序共享数据、按需分配内存、云原生可观测性依赖Linux 5.10、libbpf 1.0