如何在两个独立程序间共享BPF Map?
BPF程序间共享Map问题求助
作为BPF新手,我编写了两组用户态程序及对应的BPF程序,代码编译运行正常,但两个程序各自创建了Map实例,并未共享同一Map。我怀疑第二个用户态程序在复用文件描述符时存在错误,恳请帮助。
第一组程序
用户态代码(user_space.c)
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <linux/bpf.h> #include <bpf/libbpf.h> #include <signal.h> struct bpf_object *obj; // Signal handler to handle Ctrl+C void cleanup_and_exit(int sig) { fprintf(stderr, "Received signal %d. Cleaning up...\n", sig); if (obj) { bpf_object__close(obj); } exit(0); } int main(void) { // Install the signal handler signal(SIGINT, cleanup_and_exit); // Create BPF map struct bpf_map *map; obj = bpf_object__open_file("bpf_program.o", NULL); if (!obj) { fprintf(stderr, "Error loading BPF object file\n"); return 1; } map = bpf_map__next(NULL, obj); if (!map) { fprintf(stderr, "Error finding BPF map\n"); bpf_object__close(obj); return 1; } // Update map attributes bpf_map__set_type(map, BPF_MAP_TYPE_HASH); bpf_map__set_key_size(map, sizeof(int)); bpf_map__set_value_size(map, sizeof(long)); bpf_map__set_max_entries(map, 1024); // Load BPF object and create the map if (bpf_object__load(obj)) { fprintf(stderr, "Error loading BPF object\n"); bpf_object__close(obj); return 1; } printf("BPF map created and loaded successfully\n"); // Print the file descriptor of the map printf("File Descriptor of BPF map: %d\n", bpf_map__fd(map)); // Insert a value into the map int key = 42; long value = 123; if (bpf_map_update_elem(bpf_map__fd(map), &key, &value, BPF_ANY) != 0) { perror("Error inserting value into BPF map"); bpf_object__close(obj); return 1; } printf("Value inserted into BPF map successfully\n"); // Keep the program running while (1) { sleep(1); } return 0; }
对应的BPF程序(bpf_program.c)
#include <linux/bpf.h> #include <bpf/bpf_helpers.h> struct bpf_map_def SEC("maps") my_map = { .type = BPF_MAP_TYPE_HASH, .key_size = sizeof(int), .value_size = sizeof(long), .max_entries = 1024, }; char _license[] SEC("license") = "GPL";
第二组程序
用户态代码(user_space1.c)
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <errno.h> #include <bpf/libbpf.h> #include <bpf/bpf.h> #define MAX_ENTRIES 1024 int main(void) { // Open the BPF object file struct bpf_object *obj; obj = bpf_object__open_file("bpf_program1.o", NULL); if (!obj) { fprintf(stderr, "Error opening BPF object file: %s\n", strerror(errno)); return 1; } // Load the BPF object if (bpf_object__load(obj)) { fprintf(stderr, "Error loading BPF object: %s\n", strerror(errno)); bpf_object__close(obj); return 1; } // Find the map by name struct bpf_map *map = bpf_object__find_map_by_name(obj, "my_map"); if (!map) { fprintf(stderr, "Error finding BPF map by name: %s\n", strerror(errno)); bpf_object__close(obj); return 1; } // Retrieve the file descriptor of the BPF map int map_fd = bpf_map__fd(map); if (map_fd < 0) { fprintf(stderr, "Error obtaining file descriptor for BPF map: %s\n", strerror(errno)); bpf_object__close(obj); return 1; } printf("BPF map found successfully with FD: %d\n", map_fd); // Reuse the BPF map file descriptor if (bpf_map__reuse_fd(map, map_fd) != 0) { fprintf(stderr, "Error reusing BPF map file descriptor: %s\n", strerror(errno)); bpf_object__close(obj); return 1; } // Allocate memory for keys and values int keys[MAX_ENTRIES]; long values[MAX_ENTRIES]; // Declare 'next_key' before the loop int next_key; // Iterate over all entries in the BPF map int key; long value; int i = 0; while (bpf_map_get_next_key(map_fd, &key, &next_key) == 0) { if (bpf_map_lookup_elem(map_fd, &key, &value) == 0) { keys[i] = key; values[i] = value; i++; } key = next_key; } // Print all key-value pairs printf("All values in the BPF map:\n"); for (int j = 0; j < i; j++) { printf("Key: %d, Value: %ld\n", keys[j], values[j]); } // Keep the program running sleep(10); // Clean up bpf_object__close(obj); return 0; }
对应的BPF程序(bpf_program1.c)
#include <linux/bpf.h> #include <bpf/bpf_helpers.h> struct bpf_map_def SEC("maps") my_map = { .type = BPF_MAP_TYPE_HASH, .key_size = sizeof(int), .value_size = sizeof(long), .max_entries = 1024, }; char _license[] SEC("license") = "GPL";
问题分析与解决方案
核心错误点
第二个程序在执行bpf_object__load时,已经创建了一个新的my_map实例,后续调用bpf_map__reuse_fd只是复用自己刚创建的Map的FD,完全没有关联到第一个程序创建的Map。内核会为每个加载的BPF对象中定义的Map创建新实例,除非明确指定复用已存在的Map。
正确的共享方式
方式1:通过Map名称直接获取已有Map(推荐)
不需要加载第二个BPF对象(如果只是读取Map的话),直接调用bpf_map_get_fd_by_name获取第一个程序创建的Map的FD,然后进行操作。修改后的第二组用户态代码如下:
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <errno.h> #include <bpf/libbpf.h> #include <bpf/bpf.h> #define MAX_ENTRIES 1024 int main(void) { // 直接通过名称获取已存在的BPF Map的FD int map_fd = bpf_map_get_fd_by_name("my_map"); if (map_fd < 0) { fprintf(stderr, "Error getting map FD by name: %s\n", strerror(errno)); return 1; } printf("Got existing map FD: %d\n", map_fd); // 遍历Map条目 int keys[MAX_ENTRIES]; long values[MAX_ENTRIES]; int i = 0; // 首次调用bpf_map_get_next_key时,prev_key要传NULL int *prev_key = NULL; int curr_key; long value; while (bpf_map_get_next_key(map_fd, prev_key, &curr_key) == 0) { if (bpf_map_lookup_elem(map_fd, &curr_key, &value) == 0) { keys[i] = curr_key; values[i] = value; i++; } prev_key = &curr_key; } // 打印结果 printf("All values in the BPF map:\n"); for (int j = 0; j < i; j++) { printf("Key: %d, Value: %ld\n", keys[j], values[j]); } sleep(10); close(map_fd); return 0; }
方式2:复用已有Map加载BPF程序
如果第二个程序需要加载自己的BPF程序并共享Map,需要在加载BPF对象前,先获取已有Map的FD,然后调用bpf_map__reuse_fd绑定,再执行bpf_object__load。示例修改如下:
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <errno.h> #include <bpf/libbpf.h> #include <bpf/bpf.h> #define MAX_ENTRIES 1024 int main(void) { // 先获取已有Map的FD int existing_map_fd = bpf_map_get_fd_by_name("my_map"); if (existing_map_fd < 0) { fprintf(stderr, "Error getting existing map FD: %s\n", strerror(errno)); return 1; } // 打开BPF对象但不加载 struct bpf_object *obj = bpf_object__open_file("bpf_program1.o", NULL); if (!obj) { fprintf(stderr, "Error opening BPF object file: %s\n", strerror(errno)); close(existing_map_fd); return 1; } // 找到Map定义 struct bpf_map *map = bpf_object__find_map_by_name(obj, "my_map"); if (!map) { fprintf(stderr, "Error finding map in object: %s\n", strerror(errno)); bpf_object__close(obj); close(existing_map_fd); return 1; } // 复用已有Map的FD,再加载BPF对象 if (bpf_map__reuse_fd(map, existing_map_fd) != 0) { fprintf(stderr, "Error reusing map FD: %s\n", strerror(errno)); bpf_object__close(obj); close(existing_map_fd); return 1; } if (bpf_object__load(obj)) { fprintf(stderr, "Error loading BPF object: %s\n", strerror(errno)); bpf_object__close(obj); close(existing_map_fd); return 1; } // 后续操作Map int map_fd = bpf_map__fd(map); // ... (和之前的遍历逻辑一致) bpf_object__close(obj); close(existing_map_fd); return 0; }
额外注意事项
- 确保两个程序运行时使用相同的Map名称,且第一个程序创建的Map未被销毁(即第一个程序仍在运行,或Map设置了
BPF_F_NO_PREALLOC等持久化属性)。 - 原代码中
bpf_map_get_next_key的调用存在错误:首次调用时prev_key应该传NULL,否则会无法获取第一个条目。
内容的提问来源于stack exchange,提问作者Krzysztof Michalak
相关产品推荐
相关产品推荐

