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

如何在另一用户态程序中获取eBPF Maps的MAP FD

问题描述

我已在网络接口上挂载了eBPF XDP程序(port_filter_kern.c):

  • port_filter_kern.c:丢弃发往特定端口的入站流量,端口号以键的形式存储在名为port_map的eBPF map中。
  • port_filter_user.c:负责将eBPF程序加载到指定接口,读取端口号文本文件后更新port_map,代码片段如下:
map_fd = bpf_object__find_map_fd_by_name(obj, "port_map");
printf("map_fd %d ",map_fd);  // 打印map的文件描述符
int result = bpf_map_update_elem(map_fd, &portkey, &value, BPF_ANY);

现在需要通过另一个用户态程序port_filter_runtime.c,在运行时从用户输入/文本文件获取端口号,更新同一个port_map,从而丢弃新增端口的入站流量。但尝试以下两种方式获取的map FD和第一个程序打印的FD不一致,无法正确更新:

方式一:

struct bpf_object *obj = bpf_object__open_file("port_filter_kern.o", NULL);
struct bpf_map *map = bpf_object__find_map_by_name(obj, "port_map");
int map_fd = bpf_map__fd(map);

printf("map_fd %d ",map_fd);  // 打印map的文件描述符

方式二:

struct bpf_object *obj = bpf_object__open_file("port_filter_kern.o", NULL);
int map_fd = bpf_object__find_map_fd_by_name(obj, "port_map");

printf("map_fd %d ",map_fd); // 打印map的文件描述符
解决方案

你之前的方法错误在于:bpf_object__open_file只是从目标文件创建了一个新的BPF对象实例,对应的是未加载到内核的map定义,而非已经由port_filter_user.c加载到内核中的那个实际map实例,因此得到的FD完全不同。

要访问内核中已存在的port_map,需要直接通过map的名称查找内核中的实例,而不是重新打开目标文件。以下是两种可行的实现方式:

方法1:使用libbpf的bpf_get_map_fd_by_name函数

libbpf提供了直接通过名称获取内核中已存在map的FD的函数,代码示例:

#include <bpf/libbpf.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>

int main() {
    int map_fd = bpf_get_map_fd_by_name("port_map");
    if (map_fd < 0) {
        fprintf(stderr, "Failed to get map FD: %s\n", strerror(-map_fd));
        return 1;
    }
    printf("map_fd %d\n", map_fd);

    // 示例:添加端口8080到过滤列表
    __u32 portkey = 8080;
    __u32 value = 1; // 假设value非0即表示需要丢弃该端口流量
    int result = bpf_map_update_elem(map_fd, &portkey, &value, BPF_ANY);
    if (result < 0) {
        fprintf(stderr, "Failed to update map: %s\n", strerror(errno));
        close(map_fd);
        return 1;
    }

    close(map_fd);
    return 0;
}

编译时需要链接libbpf相关库:

gcc port_filter_runtime.c -o port_filter_runtime -lbpf -lelf -lz

方法2:通过sysfs手动查找并打开map

如果你的libbpf版本较低不支持bpf_get_map_fd_by_name,可以通过BPF文件系统手动查找:

  1. 确保BPF文件系统已挂载:mount -t bpf bpf /sys/fs/bpf/
  2. 直接打开/sys/fs/bpf/下对应port_map的文件(如果是命名map会直接以名称作为文件名),代码示例:
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/stat.h>
#include <errno.h>

int main() {
    const char* map_path = "/sys/fs/bpf/port_map";
    int map_fd = open(map_path, O_RDWR);
    if (map_fd < 0) {
        fprintf(stderr, "Failed to open map: %s\n", strerror(errno));
        return 1;
    }
    printf("map_fd %d\n", map_fd);

    // 后续更新map的逻辑同上
    close(map_fd);
    return 0;
}
注意事项
  • 运行程序的用户需要足够权限(通常为root或拥有CAP_BPF权限);
  • 如果port_map未设置命名属性,无法通过名称直接查找,可在第一个程序加载时将map ID写入文件,供第二个程序读取后通过/sys/fs/bpf/map_{ID}路径打开;
  • 更新map时注意键值的类型要和内核程序中定义的port_map一致。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 06:01:04