Awesome-GitHub-Repo icon indicating copy to clipboard operation
Awesome-GitHub-Repo copied to clipboard

【开源自荐】Wasm-bpf:在 WebAssembly 中构建和运行 eBPF 程序的工具链与运行时

Open yunwei37 opened this issue 2 years ago • 0 comments

  • 项目名称:Wasm-bpf:eBPF 的 WebAssembly 工具链与运行时,在 Wasm 中构建和运行 eBPF 程序
  • 项目地址:https://github.com/eunomia-bpf/wasm-bpf
  • 项目简介 (100 字以内):

Wasm-bpf 是一个 WebAssembly eBPF 库和运行时, 基于 CO-RE(一次编写 – 到处运行) libbpfwasm-micro-runtime 实现,利用 Wasm 来完成 eBPF 程序的构建、分发、运行流程,在浏览器外的 Wasm 沙箱中运行轻量级的 eBPF 应用。

  • 项目描述:

Wasm 最初是以浏览器安全沙盒为目的开发的,发展到目前为止,WebAssembly 已经成为一个用于云原生软件组件的高性能、跨平台和多语言软件沙箱环境,Wasm 轻量级容器也非常适合作为下一代无服务器平台运行时。另一个令人兴奋的趋势是 eBPF 的兴起,它使云原生开发人员能够构建安全的网络、服务网格和多种可观测性组件,并且它也在逐步渗透和深入到内核的各个组件,提供更强大的内核态可编程交互能力。

现在,借助 Wasm-bpf 编译工具链和运行时,我们可以使用 Wasm 将 eBPF 程序编写为跨平台的模块,同时使用 C/C++ 或 Rust 来编写 Wasm-eBPF 程序并发布。通过在 WebAssembly 中使用 eBPF 程序,我们不仅能让 Wasm 应用享受到 eBPF 的高性能和对系统接口的访问能力,还可以让 eBPF 程序使用到 Wasm 的沙箱、灵活性、跨平台性、和动态加载,并且使用 Wasm 的 OCI 镜像来方便、快捷地分发和管理 eBPF 程序。结合这两种技术,我们将会给 eBPF 和 Wasm 生态来一个全新的开发体验!

  • 亮点:

  • 通用: 给 WASM 提供大部分的 eBPF 功能。 比如从 ring buffer 或者 perf buffer 中获取数据、 通过 maps 提供 内核 eBPF 和 用户态 Wasm 程序之间的双向通信、 动态 加载, 附加 或者 解除附加 eBPF程序等。 支持大量的 eBPF 程序类型和 map 类型, 覆盖了用于 tracing(跟踪), networking(网络), security(安全) 的使用场景。

  • 高性能: 对于复杂数据类型,没有额外的 序列化 开销。 通过 共享内存 来避免在 Host 和 WASM 端之间的额外数据拷贝。

  • 简单便捷的开发体验: 提供和 libbpf-bootstrap 相似的开发体验, 自动生成 Wasm-eBPF 的 skeleton 头文件以及用于绑定的 类型 定义。

  • 非常轻量: 编译完成的二进制文件只有 1.5 MB 的大小,编译好的 WASM 模块只有 ~90K ,远远比传统的以容器方式分发和运行 eBPF 程序来的轻量,同时保持良好的隔离性和沙箱特性。你可以非常容易地使用任何语言,在任何平台上建立你自己的 Wasm-eBPF 运行时,使用相同的工具链来构建应用!

WASI-bpf

  • 演示视频:https://www.bilibili.com/video/BV1vD4y1P78S/
  • 示例代码:

使用 C/C++ 在 Wasm 中构建 eBPF 应用,将 eBPF 字节码加载到内核并处理内核返回的对应的数据

    /* Load and verify BPF application */
    skel = bootstrap_bpf__open();
    if (!skel) {
        fprintf(stderr, "Failed to open and load BPF skeleton\n");
        return 1;
    }

    /* Parameterize BPF code with minimum duration parameter */
    skel->rodata->min_duration_ns = env.min_duration_ms * 1000000ULL;

    /* Load & verify BPF programs */
    err = bootstrap_bpf__load(skel);
    if (err) {
        fprintf(stderr, "Failed to load and verify BPF skeleton\n");
        goto cleanup;
    }

    /* Attach tracepoints */
    err = bootstrap_bpf__attach(skel);
    if (err) {
        fprintf(stderr, "Failed to attach BPF skeleton\n");
        goto cleanup;
    }

使用 Rust 在 Wasm 中编写 eBPF 应用:


extern "C" fn handle_event(_ctx: u32, data: u32, _data_sz: u32) {
    let event_slice = unsafe { slice::from_raw_parts(data as *const Event, 1) };
    let event = &event_slice[0];
    let pid = event.pid;
    let ppid = event.ppid;
    let exit_code = event.exit_code;
    if event.exit_event == 1 {
        print!(
            "{:<8} {:<5} {:<16} {:<7} {:<7} [{}]",
            "TIME",
            "EXIT",
            unsafe { CStr::from_ptr(event.comm.as_ptr() as *const i8) }
                .to_str()
                .unwrap(),
            pid,
            ppid,
            exit_code
        );
        ...
}

一行命令从云端的 Github Packages 中下载并运行 eBPF 程序,或通过 Github Packages 发布:

# push to Github Packages
ecli push https://ghcr.io/eunomia-bpf/sigsnoop:latest
# pull from Github Packages
ecli pull https://ghcr.io/eunomia-bpf/sigsnoop:latest
# run eBPF program
ecli run https://ghcr.io/eunomia-bpf/sigsnoop:latest
  • 后续更新计划:
    • 继续完善多种语言支持;
    • 支持更完善的 eBPF 特性;
    • 探索更多的应用场景;

yunwei37 avatar Feb 17 '23 12:02 yunwei37