作者:余彤,郑雨生eBPF(extendedBerkeleyPacketFilter)是一个高性能的内核虚拟机,可以在信息中运行。随着计算机技术的不断发展,eBPF变得越来越强大,已经成为各种高效在线诊断和跟踪系统以及构建安全网络和服务网格的重要组成部分。WebAssembly(Wasm)最初是为了浏览器安全沙箱而开发的。至此,WebAssembly已经成为云原生软件组件的高性能、跨平台、多语言的软件沙箱环境。Wasm是一个轻量级容器,也非常适合作为下一代无服务器平台的运行时,或者在边缘计算等资源受限场景中高效执行。现在,借助Wasm-bpf编译工具链和运行时,我们可以使用Wasm将eBPF程序编写为跨平台模块,用C/C++和Rust编写程序。通过在WebAssembly中使用eBPF程序,我们不仅可以让Wasm应用程序获得eBPF的高性能和系统接口的访问权限,还可以让eBPF程序享受Wasm的沙箱、灵活性、跨平台和动态加载能力,并使用Wasm的OCI镜像方便快捷地分发和管理eBPF程序。例如,像docker一样,您可以通过单个命令从云端获取Wasm轻量级容器镜像并运行任何eBPF程序。通过结合这两种技术,我们将为eBPF和Wasm生态带来全新的开发体验!使用Wasm-bpf工具链在Wasm中编写、动态加载、分发和运行eBPF程序在之前的两篇短文中,我们已经介绍了Wasm-bpf的设计思想以及如何使用C/C++编写eBPF程序Wasm:Wasm-bpf:搭建Webassembly和eBPF内核之间的可编程桥梁:https://mp.weixin.qq.com/s/2I...在WebAssembly中使用C/C++和libbpf编写eBPF程序:https://zhuanlan.zhihu.com/p/...基于Wasm,我们可以使用多种语言构建eBPF应用,并以统一轻量级的方式进行管理和发布。以我们构建的示例应用bootstrap.wasm为例,使用C/C++构建的镜像最小大小仅为~90K,易于通过网络分发,并且可以在更短的时间内动态部署加载到另一台机器上小于100ms并运行,并保留了轻量级容器的隔离特性。运行时不需要内核特定版本的头文件、LLVM、clang等依赖,也不需要做任何消耗资源的重量级编译工作。对于Rust,编译后的产品会稍微大一些,大约2M。本文将以Rust语言为例进行讨论:使用Rust编写eBPF程序并编译成Wasm模块使用OCI镜像发布、部署和管理eBPF程序以获得类似Docker的体验我们在中提供了几个示例程序仓库,对应观察、网络、安全等各种场景都可以使用。编写eBPF程序并编译为Wasm的一般流程一般来说,在非Wasm沙箱用户空间,使用libbpf-bootstrap脚手架,可以快速轻松地构建C/C++的BPF应用程序。编译、构建和运行一个eBPF程序(无论使用什么语言),通常包括以下步骤:编写内核态eBPF程序的代码,一般使用C/C++或Rust语言,用clang编译器或相关工具链(实现跨内核版本移植,需要包含BTF信息)。在用户态开发程序中,编写相应的加载、控制、挂载、数据处理逻辑;在实际运行阶段,将eBPF程序从用户态加载到内核中并真正执行。用Rust编写eBPF程序并编译成WasmRust可能是WebAssembly生态系统中支持最好的语言。Rust不仅支持多个WebAssembly编译目标,而且wasmtime、Spin、Wagi和许多其他WebAssembly工具都是用Rust编写的。因此,我们也提供了用Rust开发的示例:Wasm和WASI的Rust生态系统非常棒许多Wasm工具都是用Rust编写的,这意味着有很多代码可以重用。在支持其他语言之前,Spin通常具有Rust特性支持。Wasmtime是用Rust编写的,通常具有领先于其他运行时的最先进的功能。有许多现成的Rust库可以在WebAssembly中使用。由于Cargo灵活的构建系统,一些Crates甚至有特殊的功能标志来启用Wasm功能(例如Chrono)。由于Rust的内存管理技术,Rust的二进制文件大小与同类语言相比较小。我们还提供了一个RusteBPFSDK,可以用来用Rust编写eBPFuserland程序并编译成Wasm。借助aya-rs提供的相关工具链支持,内核态eBPF程序也可以用Rust编写,不过这里,我们复用了之前用C语言编写的内核态程序。首先我们需要使用rust提供的wasi工具链新建一个工程:rustuptargetaddwasm32-wasicargonewrust-helloworld之后我们可以使用Makefile运行make完成整个编译过程,生成bootstrap.bpf。oeBPF字节代码文件。使用wit-bindgen为内核模式和Wasm模块之间的通信生成类型信息。wit-bindgen项目是一组专注于WebAssembly并使用组件模型语言的绑定生成器。*.wi??t文件中描述了绑定,这些文件描述了Wasm模块导入和导出的功能和接口。我们可以将其绑定生成多种语言的类型定义,用于在内核态eBPF和用户态Wasm模块之间传递数据。我们首先需要在Cargo.toml配置文件中添加wasm-bpf-binding和wit-bindgen-guest-rust依赖:wasm-bpf-binding={path="wasm-bpf-binding"}这个包提供了wasm-bpf运行时提供的功能绑定到Wasm模块,用于加载和控制eBPF程序。wasm-bpf-binding在wasm-bpf存储库中提供。[dependencies]wit-bindgen-guest-rust={git="https://github.com/bytecodealliance/wit-bindgen",version="0.3.0"}[patch.crates-io]wit-component={git="https://github.com/bytecodealliance/wasm-tools",version="0.5.0",rev="9640d187a73a516c42b532cf2a10ba5403df5946"}wit-parser={git="https://github.com/bytecodealliance/wasm-tools",version="0.5.0",rev="9640d187a73a516c42b532cf2a10ba5403df5946"}这个包支持使用wit文件为Rust客户端生成绑定。使用这个包,我们不再需要手动运行wit-bindgen。接下来,我们使用btf2wit工具从BTF信息生成wit文件。可以使用cargoinstallbtf2wit安装我们提供的btf2wit工具,编译生成wit信息:cdbtfclang-targetbpf-gevent-def.c-c-oevent.def.obtf2witevent.def.o-oevent-def。witcp*.wit../wit/其中event-def.c是一个C程序文件,里面包含了我们需要的结构信息。BTF中仅记录了导出符号中使用的结构。C结构生成的wit信息大致如下::list,filename:list,exit-event:s8,}}wit-bindgen-guest-rust会自动为wit文件夹中的所有类型信息生成rust类型,例如:#[repr(C,packed)]#[derive(Debug,Copy,Clone)]structEvent{pid:i32,ppid:i32,exit_code:u32,__pad0:[u8;4],duration_ns:u64,comm:[u8;16],文件名:[u8;127],exit_event:u8,}编写运行在WASI上的用户态加载处理代码,需要在main.rs中添加#![no_main]属性,main函数需要采用类似如下的形式:#[export_name="__main_argc_argv"]fnmain(_env_json:u32,_str_len:i32)->i32{return0;}用户态加载挂载代码,类似C/C++:letobj_ptr=binding::wasm_load_bpf_object(bpf_object.as_ptr()作为u32,bpf_object.len()作为i32);ifobj_ptr==0{println!("未能加载bpf对象");返回1;}乐tattach_result=binding::wasm_attach_bpf_program(obj_ptr,"handle_exec\0".as_ptr()asu32,"\0".as_ptr()asu32,);...轮询环形缓冲区:letmap_fd=binding::wasm_bpf_map_fd_by_name(obj_ptr,"rb\0".as_ptr()asu32);ifmap_fd<0{println!("获取地图fd失败:{}",map_fd);返回1;}//绑定::wasmletbuffer=[0u8;256];loop{//轮询缓冲区binding::wasm_bpf_buffer_poll(obj_ptr,map_fd,handle_eventasi32,0,buffer.as_ptr()asu32,buffer.len()asi32,100,);}使用handler接收返回值:extern"C"fnhandle_event(_ctx:u32,data:u32,_data_sz:u32){letevent_slice=unsafe{slice::from_raw_parts(dataas*constEvent,1)};让事件=&event_slice[0];让pid=event.pid;让ppid=event.ppid;升etexit_code=event.exit_code;如果event.exit_event==1{print!("{:<8}{:<5}{:<16}{:<7}{:<7}[{}]","TIME","EXIT",不安全{CStr::from_ptr(event.comm.as_ptr()as*consti8)}.to_str().unwrap(),pid,ppid,exit_code);...}接下即可使用cargo编译运行:$cargobuild--targetwasi32-wasm$sudowasm-bpf./target/wasm32-wasi/debug/rust-helloworld.wasmTIMEEXECsh18024533666/bin/shTIMEEXECwhich180246180245/usr/bin/whichTIMEEXITwhich180246180245[0](1ms)TIMEEXITsh18024533666[0](3ms)TIMEEXECsh18024733666/bin/shTIMEEXECps180248180247/usr/bin/psTIME退出ps180248180247[0](23ms)TIMEEXITsh18024733666[0](25ms)TIMEEXECsh18024933666/bin/shTIMEEXECcpuUsage.sh180250180249/root/.vscode-server-insiders/bin/a7d49b0f35f50e460835a55d20a00a735d1665a3Container管理和OpenImage容器释放镜像使用/sh协议(OCI)是一种轻量级、开放的治理结构,它定义了容器技术的规范和标准。它是在Linux基金会的支持下成立的,由各大软件公司组成。为容器格式和运行时创建开放的行业标准。这包括用于与容器注册表一起工作的API,正式名称为OCI分发规范(又名“分发规范”)。Docker还宣布了其与WebAssembly(Docker+Wasm)集成的第一个技术预览,并表示该公司已作为投票成员加入字节码联盟。Docker+Wasm使开发人员可以更轻松地快速构建针对Wasm运行时的应用程序。借助Wasm的相关生态,可以非常方便地发布、下载和管理eBPF程序。例如使用wasm-to-oci工具,可以将Wasm程序打包为OCI镜像,获得类似docker的体验:wasm-to-ocipushtestdata/hello.wasm.azurecr.io/wasm-to-oci:v1wasm-to-ocipull.azurecr.io/wasm-to-oci:v1--outtest.wasm我们也已经集成到eunomia-bpf的ecli工具中了。您可以使用一行命令从云端的GithubPackages下载并运行eBPF程序,或者通过GithubPackages发布:#pushtoGithubPackageseclipushhttps://ghcr.io/eunomia-bpf/sigsnoop:latest#pull从GithubPackageseclipullhttps://ghcr.io/eunomia-bpf/sigsnoop:latest#runeBPFprogramclirunhttps://ghcr.io/eunomia-bpf/sigsnoop:latest我们已经在LMP的eBPFHub中了项目中,有一些尝试创建符合OCI标准的Wasm-eBPF应用程序,并使用ORAS来简化和扩展eBPF应用程序的开发、分发、加载和运行能力[11],并使用多种不同的语言同时在Wasm上为eBPF开发用户态数据处理插件的实践。基于最新的Wasm-bpf框架,可以继续进行更多的探索性工作。我们希望尝试为eBPF和Wasm程序构建一个完整的包管理系统,以及更多可以探索的应用场景。总结本文以Rust语言为例,讨论使用Rust编写eBPF程序并编译成Wasm模块,并使用OCI镜像发布、部署和管理eBPF程序,获得类似Docker的体验。更完整的代码可以参考我们的Github仓库:https://github.com/eunomia-bp...接下来,我们将继续完善在Wasm中开发和运行多语言eBPF程序的体验,提供更完整的示例和用户态开发库/工具链,以及更具体的应用场景。参考资料wasm-bpfGithub开源地址:https://github.com/eunomia-bp...什么是eBPF:https://ebpf.io/what-is-ebpfWASI-eBPF:https://github。com/WebAssembl...龙蜥社区eBPF技术探索SIGhttps://openanolis.cn/sig/ebp...eunomia-bpf项目:https://github.com/eunomia-bp...eunomia-bpf项目dragonGitee镜像:https://gitee.com/anolis/eunomiaWasm-bpf:搭建Webassembly与eBPF内核可编程的桥梁:https://mp.weixin.qq.com/s/2I...当WASM遇见eBPF:使用WebAssembly编写、分发、加载和运行eBPF程序:https://zhuanlan.zhihu.com/p/...Docker+Wasm技术预览:https://zhuanlan.zhihu.com/p/...LMPeBPF-Hub:https://github.com/linuxkerne...wasm-to-oci:https://github.com/engineerd/...btf2wit:https://github.com/eunomia-bp……