You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在两个独立程序间共享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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.04 06:57:03