Skip to content

使用 aya-tool

源代码

本章示例的完整代码可在此处找到。

在许多情况下,您需要使用正在运行的Linux内核在其源代码中使用的类型定义。例如,您可能需要定义task_struct,因为您即将编写一个接收新调度进程/任务信息的BPF程序。Aya并没有提供这种结构的定义。应该怎么做才能获得这种定义呢?而且我们需要Rust中的定义,而不是C语言中的。

这就是aya-tool的设计初衷。它是一个允许为特定内核结构生成Rust绑定的工具。

可以通过以下命令进行安装:

$ cargo install bindgen-cli
$ cargo install --git https://github.com/aya-rs/aya -- aya-tool

确保您的系统中安装了bpftoolbindgen,否则aya-tool将无法工作。

命令的语法是:

$ aya-tool
aya-tool 

USAGE:
    aya-tool <SUBCOMMAND>

OPTIONS:
    -h, --help    打印帮助信息

SUBCOMMANDS:
    generate    使用bpftool生成内核类型的Rust绑定
    help        打印此消息或给定子命令的帮助信息

假设我们想要生成task_struct的Rust定义。假设您的项目叫做myapp。您的用户空间部分在myapp子目录中,您的eBPF部分在myapp-ebpf中。我们需要为eBPF部分生成绑定,可以通过以下命令完成:

$ aya-tool generate task_struct > myapp-ebpf/src/vmlinux.rs

为多个类型生成

您也可以指定多个类型进行生成,例如:

$ aya-tool generate task_struct dentry > vmlinux.rs
但在接下来的示例中,我们将只关注task_struct

然后我们可以在我们的eBPF程序中使用mod vmlinuxvmlinux作为一个模块,就像这样:

myapp-ebpf/src/main.rs
#![no_std]
#![no_main]

#[allow(non_upper_case_globals)]
#[allow(non_snake_case)]
#[allow(non_camel_case_types)]
#[allow(dead_code)]
mod vmlinux;

use aya_ebpf::{
    cty::{c_int, c_ulong},
    macros::{lsm, map},
    maps::HashMap,
    programs::LsmContext,
};

use vmlinux::task_struct;

#[map]
static PROCESSES: HashMap<i32, i32> = HashMap::with_max_entries(32768, 0);

#[lsm(hook = "task_alloc")]
pub fn task_alloc(ctx: LsmContext) -> i32 {
    match unsafe { try_task_alloc(ctx) } {
        Ok(ret) => ret,
        Err(ret) => ret,
    }
}

unsafe fn try_task_alloc(ctx: LsmContext) -> Result<i32, i32> {
    let task: *const task_struct = ctx.arg(0);
    let _clone_flags: c_ulong = ctx.arg(1);
    let retval: c_int = ctx.arg(2);

    // Save the PID of a new process in map.
    let pid = (*task).pid;
    PROCESSES.insert(&pid, &pid, 0).map_err(|e| e as i32)?;

    // Handle results of previous LSM programs.
    if retval != 0 {
        return Ok(retval);
    }

    Ok(0)
}

#[panic_handler]
fn panic(_info: &core::panic::PanicInfo) -> ! {
    unsafe { core::hint::unreachable_unchecked() }
}

可移植性和不同的内核版本

通过名为BPF CO-RE的机制,aya-tool生成的结构在不同的Linux内核版本之间是可移植的。这些结构不是简单地从内核头文件中生成的。然而,目标内核(无论版本如何)都应该启用CONFIG_DEBUG_INFO_BTF选项。