searchusermenu
  • 发布文章
  • 消息中心
点赞
收藏
评论
分享
原创

bpf系统调用分析

2025-06-12 08:59:45
1
0

用户空间所有的BPF相关函数(如libbpf库提供的接口)最终都会通过bpf()系统调用与内核交互

 

下面是一个简单的例子,展示如何直接使用bpf()系统调用加ZAI一个BPF程序,以及如何用libbpf封装后的函数实现相同功能:

1. ​​直接使用 bpf() 系统调用的例子​​

 

#include <linux/bpf.h>
#include <sys/syscall.h>
#include <unistd.h>
#include <stdio.h>
#include <errno.h>

// 封装bpf系统调用(实际使用时建议用libbpf)
int bpf_syscall(enum bpf_cmd cmd, union bpf_attr *attr) {
    return syscall(__NR_bpf, cmd, attr, sizeof(*attr));
}

int main() {
    union bpf_attr attr = {};
    
    // 示例:通过BPF_PROG_LOAD命令加ZAI一个空程序(实际需填充字节码)
    attr.prog_type = BPF_PROG_TYPE_KPROBE;  // 程序类型
    attr.insns = (__u64)NULL;               // 指令数组(实际需填充有效指令)
    attr.insn_cnt = 0;                      // 指令数量(实际需>0)
    attr.license = (__u64)"GPL";            // 许可证
    
    int fd = bpf_syscall(BPF_PROG_LOAD, &attr);
    if (fd < 0) {
        perror("BPF_PROG_LOAD failed");
        return 1;
    }
    printf("BPF程序加ZAI成功,fd=%d\n", fd);
    return 0;
}

 

bpf()系统调用通过union bpf_attr传递参数,根据不同的cmd(如BPF_PROG_LOAD)解释该结构体的字段。
实际使用时需要填充有效的BPF指令(如从.o文件读取),这里简化了流程。

 

​​使用 libbpf 封装的等价例子​​

#include <bpf/bpf.h>
#include <bpf/libbpf.h>
#include <stdio.h>

int main() {
    struct bpf_object *obj;
    struct bpf_program *prog;
    
    // 1. 打开BPF对象文件(libbpf会解析并调用bpf()系统调用)
    obj = bpf_object__open_file("example.o", NULL);
    if (!obj) {
        fprintf(stderr, "无法打开BPF对象文件\n");
        return 1;
    }
    
    // 2. 加ZAI BPF程序到内核(内部调用BPF_PROG_LOAD)
    if (bpf_object__load(obj)) {
        fprintf(stderr, "加ZAI BPF程序失败\n");
        return 1;
    }
    
    // 3. 获取程序fd(libbpf已通过bpf()获取)
    prog = bpf_object__find_program_by_name(obj, "my_prog");
    int fd = bpf_program__fd(prog);
    printf("BPF程序加ZAI成功,fd=%d\n", fd);
    
    bpf_object__close(obj);
    return 0;
}

 

libbpf封装了bpf()系统调用的细节:
1. bpf_object__open_file解析ELF文件,提取BPF程序和映射。
2. bpf_object__load内部调用bpf(BPF_PROG_LOAD)加ZAI程序。
3.  bpf_program__fd返回程序的文件描述符(由内核通过bpf()分配)。

关键对比

操作 直接调用bpf() 使用libbpf
加ZAI BPF程序 手动填充union bpf_attr,调用BPF_PROG_LOAD bpf_object__load()自动处理
指令传递 需手动构造指令数组 .o文件自动解析
映射创建 调用BPF_MAP_CREATE bpf_map__fd()封装
错误处理 需手动检查errno 提供更友好的错误信息


总结


​​底层​​:所有BPF操作最终通过bpf()系统调用完成。
​​上层​​:libbpf等库封装了复杂性(如ELF解析、指令修正、映射管理),推荐优先使用。直接调用bpf()通常仅用于特殊场景或学习目的。

0条评论
作者已关闭评论
y****n
11文章数
0粉丝数
y****n
11 文章 | 0 粉丝
原创

bpf系统调用分析

2025-06-12 08:59:45
1
0

用户空间所有的BPF相关函数(如libbpf库提供的接口)最终都会通过bpf()系统调用与内核交互

 

下面是一个简单的例子,展示如何直接使用bpf()系统调用加ZAI一个BPF程序,以及如何用libbpf封装后的函数实现相同功能:

1. ​​直接使用 bpf() 系统调用的例子​​

 

#include <linux/bpf.h>
#include <sys/syscall.h>
#include <unistd.h>
#include <stdio.h>
#include <errno.h>

// 封装bpf系统调用(实际使用时建议用libbpf)
int bpf_syscall(enum bpf_cmd cmd, union bpf_attr *attr) {
    return syscall(__NR_bpf, cmd, attr, sizeof(*attr));
}

int main() {
    union bpf_attr attr = {};
    
    // 示例:通过BPF_PROG_LOAD命令加ZAI一个空程序(实际需填充字节码)
    attr.prog_type = BPF_PROG_TYPE_KPROBE;  // 程序类型
    attr.insns = (__u64)NULL;               // 指令数组(实际需填充有效指令)
    attr.insn_cnt = 0;                      // 指令数量(实际需>0)
    attr.license = (__u64)"GPL";            // 许可证
    
    int fd = bpf_syscall(BPF_PROG_LOAD, &attr);
    if (fd < 0) {
        perror("BPF_PROG_LOAD failed");
        return 1;
    }
    printf("BPF程序加ZAI成功,fd=%d\n", fd);
    return 0;
}

 

bpf()系统调用通过union bpf_attr传递参数,根据不同的cmd(如BPF_PROG_LOAD)解释该结构体的字段。
实际使用时需要填充有效的BPF指令(如从.o文件读取),这里简化了流程。

 

​​使用 libbpf 封装的等价例子​​

#include <bpf/bpf.h>
#include <bpf/libbpf.h>
#include <stdio.h>

int main() {
    struct bpf_object *obj;
    struct bpf_program *prog;
    
    // 1. 打开BPF对象文件(libbpf会解析并调用bpf()系统调用)
    obj = bpf_object__open_file("example.o", NULL);
    if (!obj) {
        fprintf(stderr, "无法打开BPF对象文件\n");
        return 1;
    }
    
    // 2. 加ZAI BPF程序到内核(内部调用BPF_PROG_LOAD)
    if (bpf_object__load(obj)) {
        fprintf(stderr, "加ZAI BPF程序失败\n");
        return 1;
    }
    
    // 3. 获取程序fd(libbpf已通过bpf()获取)
    prog = bpf_object__find_program_by_name(obj, "my_prog");
    int fd = bpf_program__fd(prog);
    printf("BPF程序加ZAI成功,fd=%d\n", fd);
    
    bpf_object__close(obj);
    return 0;
}

 

libbpf封装了bpf()系统调用的细节:
1. bpf_object__open_file解析ELF文件,提取BPF程序和映射。
2. bpf_object__load内部调用bpf(BPF_PROG_LOAD)加ZAI程序。
3.  bpf_program__fd返回程序的文件描述符(由内核通过bpf()分配)。

关键对比

操作 直接调用bpf() 使用libbpf
加ZAI BPF程序 手动填充union bpf_attr,调用BPF_PROG_LOAD bpf_object__load()自动处理
指令传递 需手动构造指令数组 .o文件自动解析
映射创建 调用BPF_MAP_CREATE bpf_map__fd()封装
错误处理 需手动检查errno 提供更友好的错误信息


总结


​​底层​​:所有BPF操作最终通过bpf()系统调用完成。
​​上层​​:libbpf等库封装了复杂性(如ELF解析、指令修正、映射管理),推荐优先使用。直接调用bpf()通常仅用于特殊场景或学习目的。

文章来自个人专栏
文章 | 订阅
0条评论
作者已关闭评论
作者已关闭评论
0
0