位置: IT常识 - 正文

Rust Aya 编写 eBPF 程序(rust编程指南)

编辑:rootadmin
本文地址:https://www.ebpf.top/post/ebpf_rust_aya 1. 前言 Linux 内核 6.1 版本中有一个非常引人注意的变化:引入了对 Rust 编程语言的支持。Rust 是一种系统编程语言,Rust 通过提供非常强大的编译时保证和对内存生命周期的明确控制。在内核开 ...

推荐整理分享Rust Aya 编写 eBPF 程序(rust编程指南),希望有所帮助,仅作参考,欢迎阅读内容。

文章相关热门搜索词:rust编译wasm,rust 编译成so,rust eac ban,rust编译wasm,rust 编译成so,rust编程指南,rust编程,rust 编译成so,内容如对您有帮助,希望把文章链接给更多的朋友!

本文地址:https://www.ebpf.top/post/ebpf_rust_aya

1. 前言

Linux 内核 6.1 版本中有一个非常引人注意的变化:引入了对 Rust 编程语言的支持。Rust 是一种系统编程语言,Rust 通过提供非常强大的编译时保证和对内存生命周期的明确控制。在内核开发中引入 Rust 语言,将会为内核开发的早期带来更多的安全保障。eBPF 是在内核中基于事件运行用户自定义程序的技术,其验证器机制可以保障运行在内核中 eBPF 程序的安全性。

Rust 与 eBPF 有着一个共同的目标:保证内核安全,只是两者侧重的维度有所不同。

尽管使用 Rust 编写 eBPF 程序多数情况下都需要通过不安全的方式在内核进行内存读写,但是基于 Rust 和 Aya ,的确能够给我们带来一个快速和高效的开发体验,这包括自动生成整个程序框架(eBPF 程序及对应的用户空间代码)、参数检查确认、错误处理、统一的相关构建和管理方式等等 。

Aya 是一个以可操作性和开发者体验为重点的 eBPF 库,完全是在 Rust 基础上建立的,只使用 libc 包来执行系统调用。Aya 官方仓库地址为 https://github.com/aya-rs/aya/,当前版本为 v0.1.11,项目还处于偏早期。基于 Aya 库开发 eBPF 程序可以给我们带来以下的便利:

基于 Rust 的 Cargo 工具来管理、构建和测试项目;支持 CO-RE 直接生成与 Rust 与内核文件的绑定;用户工具代码(Rust)与运行在的内核中的 eBPF 代码轻松共享代码;对于 LLVM、libbpf、bcc 等完全没有任何依赖;

本文仅是基于 Aya 编写 eBPF 程序及用户空间程序的生成和测试的过程记录,不涉及到对于生成 Rust 代码的详细解读。

2. Rust 开发环境搭建2.1 创建 VM 虚拟机

为了使用 Rust 进行 eBPF 程序编写,那么我们首先需要在本地搭建一个 Rust 开发环境。这里我仍然采用 multipass 工具快速搭建一个 Ubuntu 22.04 LTS 的环境。

$ multipass launch --name rust-aya -d 20G

默认磁盘为 5G,比较容易造成磁盘空间满,因此这里将磁盘空间大小设置为 20G,你可以根据自己的情况调整。

对于已经创建的 mulipass 实例可以在创建后进行调整,则需要 multipass 版本大于 1.10,而且需要调整的实例处于停止状态,详细可参见调整实例配置,例如 multipass set local.rust-aya.cpus=4 或 multipass set local.rust-aya.memory=8G 分别用于调整实例的 CPU 和 MEM 大小。

2.2 安装 Rust 开发环境

通常情况下,Rust 开发环境推荐通过 rustup 工具管理,我们可以通过以下命令快速安装该工具:

$ curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

一般情况下我们选择默认选项安装。整个安装过程会下载一个脚本完成 rustup 工具安装,同时也会安装最新的 Rust 稳定版本。如果安装顺利,我们可以在最后看到如下的信息:

...stable-x86_64-unknown-linux-gnu installed - rustc 1.65.0 (897e37553 2022-11-02)Rust is installed now. Great!To get started you may need to restart your current shell.This would reload your PATH environment variable to includeCargo's bin directory ($HOME/.cargo/bin).To configure your current shell, run:source "$HOME/.cargo/env"

在 rustup 工具安装完成后,我们可以使用其安装 Rust 稳定版(实际上默认已经安装)和 nightly ,其中 nightly 为开发者体验新功能的发布通道,Rust 2021 年开始支持编译 eBPF,当前使用 Aya 需要基于 Rust Nightly 版本。

Rust 有 3 个发布通道:

NightlyBetaStable(稳定版)

大部分 Rust 开发者主要采用稳定版通道,不过希望实验新功能的开发者可能会使用 nightly 或 beta 版。详情参见附录 G:Rust 是如何开发的与 “Nightly Rust”

$ source "$HOME/.cargo/env"$ rustup install stable # rustup 命令已经默认安装info: syncing channel updates for 'stable-x86_64-unknown-linux-gnu' stable-x86_64-unknown-linux-gnu unchanged - rustc 1.65.0 (897e37553 2022-11-02)info: checking for self-updates$ rustup toolchain install nightly --component rust-src...info: installing component 'rustfmt' nightly-x86_64-unknown-linux-gnu installed - rustc 1.67.0-nightly (09508489e 2022-11-04)info: checking for self-updates$ rustup toolchain liststable-x86_64-unknown-linux-gnu (default)nightly-x86_64-unknown-linux-gnu

安装 nightly 以后我们可以使用 rustup toolchain list 查看本地开发环境的开发工具链。

2.3 安装 bpf-linker 依赖 和 bpftool 工具

为了使用 Aya,我们还需要安装依赖包 bpf-linker,但其依赖与 LLVM/Clang 等工具,因此我们也需要提前安装:

$ sudo apt-get update$ sudo apt-get install llvm clang -y$ cargo install bpf-linker

最后,为了生成内核数据结构的绑定,我们还必须安装 bpftool,可以从发行版中安装或从源代码中构建,这里我选用发行版安装方式(基于 Ubuntu 22.04),源码安装可参考 bpftool 仓库说明文档:

$ sudo apt install linux-tools-common linux-tools-5.15.0-52-generic linux-cloud-tools-5.15.0-52-generic -y

支持我们完成了基于 Aya 开发的整个环境及依赖的安装。

3. Aya 向导创建 eBPF 程序3.1 使用向导创建项目

Aya 提供了一套模版向导用于创建 eBPF 对应的程序类型,向导创建依赖于 cargo-generate,因此我们需要在运行程序向导前提前安装:

$ cargo install cargo-generate

我在安装 cargo-generate 过程中遇到了如下的错误,主要是由于依赖 openssl 库问题导致,如果你也遇到类似问题可参考 cargo-generate 安装指南 和 Rust OpenSSL 文档,如果一切顺利,则可忽略此处的提示。

...warning: build failed, waiting for other jobs to finish...error: failed to compile `cargo-generate v0.16.0`, intermediate artifacts can be found at `/tmp/cargo-install8NrREg...$ sudo apt install openssl pkg-config libssl-dev gcc m4 ca-certificates make perl -y# 重新安装即可Rust  Aya 编写 eBPF 程序(rust编程指南)

在完成依赖后,我们就可以使用向导来创建 eBPF 项目,这里以 XDP 类型程序为例:

$ cargo generate https://github.com/aya-rs/aya-template

这里我们输入项目名称 myapp,eBPF 程序类型选择 xdp,完成相关设定后,向导会自动帮我们创建一个名为 myapp 的 Rust 项目,项目包括了一个最简单的 XDP 类型的 eBPF 程序及相对应的用户空间程序。 myapp 目录的整体夹头如下所示:

├── Cargo.lock├── Cargo.toml├── README.md├── myapp # 用户空间程序│ ├── Cargo.toml│ └── src│ └── main.rs├── myapp-common # eBPF 程序与用户空间程序复用的代码库│ ├── Cargo.toml│ └── src│ └── lib.rs├── myapp-ebpf # eBPF 程序│ ├── Cargo.lock│ ├── Cargo.toml│ ├── rust-toolchain.toml│ └── src│ └── main.rs└── xtask # build 相关的代码 ├── Cargo.toml └── src ├── build_ebpf.rs ├── main.rs └── run.rs8 directories, 15 files

生成的 eBPF 程序位于 myapp-ebpf/src 目录下,文件名为 main.rs,完整内容如下所示:

$ cat myapp-ebpf/src/main.rs#![no_std]#![no_main]use aya_bpf::{ bindings::xdp_action, macros::xdp, programs::XdpContext,};use aya_log_ebpf::info;#[xdp(name="myapp")]pub fn myapp(ctx: XdpContext) -> u32 { match try_myapp(ctx) { Ok(ret) => ret, Err(_) => xdp_action::XDP_ABORTED, }}fn try_myapp(ctx: XdpContext) -> Result<u32, u32> { info!(&ctx, "received a packet"); // 每接受到一个数据包则打印一个日志 Ok(xdp_action::XDP_PASS)}#[panic_handler]fn panic(_info: &core::panic::PanicInfo) -> ! { unsafe { core::hint::unreachable_unchecked() }}3.2 编译 eBPF 程序

首先,我们使用 cargo 工具编译 eBPF 对应的程序:

$ cd myapp$ cargo xtask build-ebpf... Compiling myapp-ebpf v0.1.0 (/home/ubuntu/myapp/myapp-ebpf) Running `rustc --crate-name myapp --edition=2021 src/main.rs --error-format=json \ --json=diagnostic-rendered-ansi,artifacts,future-incompat --crate-type bin \ --emit=dep-info,link -C opt-level=3 -C panic=abort -C lto -C codegen-units=1 -C metadata=dd6140d48c387b43 -C extra-filename=-dd6140d48c387b43 \ --out-dir \... -Z unstable-options \ Finished dev [optimized] target(s) in 11.76s

编译完成后,对应的程序保存在 target 目录下:

~/myapp$ ls -hl target/bpfel-unknown-none/debug/...-rw-rw-r-- 2 ubuntu ubuntu 3.5K Nov 6 22:24 myapp~/myapp$ file target/bpfel-unknown-none/debug/myapptarget/bpfel-unknown-none/debug/myapp: ELF 64-bit LSB relocatable, eBPF, version 1 (SYSV), not stripped/myapp$ llvm-objdump -S target/bpfel-unknown-none/debug/myapptarget/bpfel-unknown-none/debug/myapp:file format elf64-bpfDisassembly of section xdp/myapp:0000000000000000 <myapp>:... 242:bf 61 00 00 00 00 00 00r1 = r6 243:18 02 00 00 00 00 00 00 00 00 00 00 00 00 00 00r2 = 0 ll 245:18 03 00 00 ff ff ff ff 00 00 00 00 00 00 00 00r3 = 4294967295 ll 247:bf 04 00 00 00 00 00 00r4 = r0 248:b7 05 00 00 aa 00 00 00r5 = 170 249:85 00 00 00 19 00 00 00call 25

至此,已经完成了 eBPF 程序的编译工作,接着我们需要继续编译用户空间代码。

3.3 运行用户空间程序

我们可以直接使用 cargo 命令来运行用户空间程序:

$ RUST_LOG=info cargo xtask run... Finished dev [unoptimized + debuginfo] target(s) in 8.38sError: failed to attach the XDP program with default flags - try changing XdpFlags::default() to XdpFlags::SKB_MODECaused by: unknown network interface eth0

RUST_LOG=info 为设置日志级别的环境变量,默认为 warn,但向导生成的代码打印的日志级别默认为 info,因此需要运行时制定,否则可能会出现程序运行查看不到日志的情况。

cargo xtask run 命令会直接编译用户空间代码并运行,但是运行过程中我们发现出现错误 unknown network interface eth0,这是因为默认生成的程序指定将 XDP 程序加载到 eth0 网卡,而我们的 VM 默认网卡不为 eth0 导致,这里我们明确制定网卡使用 lo 测试,再次运行结果如下:

$ RUST_LOG=info cargo xtask run -- --iface lo... Finished dev [optimized] target(s) in 0.19s Finished dev [unoptimized + debuginfo] target(s) in 0.12s[2022-11-05T16:25:27Z INFO myapp] Waiting for Ctrl-C...

这次可以发现用户空间程序已经正常运行,并且将对应的 eBPF 程序加载至内核中。

$ sudo bpftool prog list42: xdp name myapp tag 2929f83b3be0f64b gplloaded_at 2022-11-06T22:42:54+0800 uid 0xlated 2016B jited 1151B memlock 4096B map_ids 14,13,15$ ip link show1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 xdpgeneric qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 prog/xdp id 42 # <=== 加载的 eBPF 程序 id 42

我们启动网卡在 lo 网卡的 ping 包验证:

我们可以看到当我们在另外一个窗口在本地端口运行 ping -c 1 127.0.0.1 命令的同时,在运行用户空间 myapp 的程序日志中打印了对应的日志 received a packet。

至此,我们就完成了整个基于 Aya 最简单 XDP 程序的验证,如果你打算进阶一步打印报文日志或者对特定包进行对齐,则可以参考 Aya Book 中对应的章节。

4. 总结

通过对于 Aya 整个过程中的使用,我们可以发现使用 Aya 开发 eBPF 程序的确给我们带来了诸多的便利,通过向导搭建了整个项目的基本框架,并且实现了编译、加载等相关的管理工作,特别是对于新手入门更加友好。默认生成的用户空间代码与 eBPF 代码实现了一定程度的代码复用,特别是日志相关的打印更加便捷。同时,该项目当前的文档还不是特别完整,诸如 Probe/Tracepoint/XDP 等程序类型的文档还在完善中,如果你有兴趣也欢迎投入到相关的建设中。更多介绍可参考 Aya: Rust 风格的 eBPF 伙伴。

同时,也期待 libbpf-bootstrap 项目能够早日实现 Aya 向导式的 eBPF 程序代码创建,这对于编写 eBPF 相关的程序的确提供了快速上手的体验。

参考

一篇 Rust 的 30 分钟介绍

https://aya-rs.dev/

LWN: Aya: writing BPF in Rust 2021-6-15

Aya: your tRusty eBPF companion 2022-6-22 【翻译】Aya: Rust 风格的 eBPF 伙伴

Adding BPF target support to the Rust compiler

Rust and Tell - Berlin - Aya: Extending the Linux Kernel with eBPF and Rust by Michal Rostecki 2022-10-24

Writing an eBPF/XDP load-balancer in Rust

Wanting to use BPF with Rust (Part 1)

本文链接地址:https://www.jiuchutong.com/zhishi/310734.html 转载请保留说明!

上一篇:可视化调试某个js对象的属性UI插件 class HTUI(可视化调参)

下一篇:《Python项目开发实战》PDF高清版下载(python项目开发案例集锦pdf百度网盘)

  • 网易云一起听怎么添加歌(网易云一起听怎么发朋友圈)

    网易云一起听怎么添加歌(网易云一起听怎么发朋友圈)

  • 微信记录删除了怎么恢复聊天记录(微信记录删除了还能找到吗)

    微信记录删除了怎么恢复聊天记录(微信记录删除了还能找到吗)

  • 华为mate40发布日期(华为mate50pro发布会)

    华为mate40发布日期(华为mate50pro发布会)

  • 华为p40pro和华为mate40pro的区别(华为p40pro和华为p60pro参数对比)

    华为p40pro和华为mate40pro的区别(华为p40pro和华为p60pro参数对比)

  • 苹果8p屏幕刷新率(苹果8p屏幕刷新率多少hz)

    苹果8p屏幕刷新率(苹果8p屏幕刷新率多少hz)

  • 无法验证app需要互联网连接以认证(无法验证app需要互联网连接以验证是否信任开发者苹果8)

    无法验证app需要互联网连接以认证(无法验证app需要互联网连接以验证是否信任开发者苹果8)

  • 京东一年升级补贴是什么(京东商城升级)

    京东一年升级补贴是什么(京东商城升级)

  • 大连苹果保修查询多长时间(大连苹果保修查询电话)

    大连苹果保修查询多长时间(大连苹果保修查询电话)

  • 华为截屏怎么设置敲击(华为截屏怎么设置三指)

    华为截屏怎么设置敲击(华为截屏怎么设置三指)

  • 地址错了已发货可以改地址吗(地址错了已发货改地址后有钱吗)

    地址错了已发货可以改地址吗(地址错了已发货改地址后有钱吗)

  • 快手卡是怎么回事(快手卡的不行)

    快手卡是怎么回事(快手卡的不行)

  • cpu内存是什么意思啊(cpu内存是内存条吗)

    cpu内存是什么意思啊(cpu内存是内存条吗)

  • 苹果8plus是双卡吗(苹果8plus是双卡槽吗)

    苹果8plus是双卡吗(苹果8plus是双卡槽吗)

  • oled 柔性 硬性区别(柔性oled和硬性oled有啥区别)

    oled 柔性 硬性区别(柔性oled和硬性oled有啥区别)

  • 微店二维码在哪里生成(微店二微码怎么出来)

    微店二维码在哪里生成(微店二微码怎么出来)

  • 苹果手机震动怎么调(苹果手机震动怎么不振了)

    苹果手机震动怎么调(苹果手机震动怎么不振了)

  • 小米mde6s手机怎么关机(小米mde6如何进入recovery)

    小米mde6s手机怎么关机(小米mde6如何进入recovery)

  • 如何使用微信支付(如何使用微信支付方式)

    如何使用微信支付(如何使用微信支付方式)

  • 淘宝盖楼是什么意思(淘宝盖楼有什么用)

    淘宝盖楼是什么意思(淘宝盖楼有什么用)

  • 爱奇艺预约是什么情况(爱奇艺会员预约收费吗)

    爱奇艺预约是什么情况(爱奇艺会员预约收费吗)

  • vue和react的主要区别(vue跟react区别)

    vue和react的主要区别(vue跟react区别)

  • 华为有没有测量距离(华为有没有测量血压的手表)

    华为有没有测量距离(华为有没有测量血压的手表)

  • 小米怎样解除听筒模式(小米怎样解除听筒设置)

    小米怎样解除听筒模式(小米怎样解除听筒设置)

  • ipad专业视频剪辑软件(ipad2021剪视频)

    ipad专业视频剪辑软件(ipad2021剪视频)

  • 苹果系统怎么降级(苹果系统怎么降级版本)

    苹果系统怎么降级(苹果系统怎么降级版本)

  • 饿了么如何投诉骑手(饿了么如何投诉骑手超时)

    饿了么如何投诉骑手(饿了么如何投诉骑手超时)

  • 取得的证券投资业绩
  • 什么是工程销项表
  • 银行承兑汇票和支票的区别
  • 银行的划分标准
  • 酒类许可证过期了去哪里换证
  • 未达起征点销售额和小微企业免税销售额
  • 期末存货采用成本与可变现净值孰低法
  • 进出口企业外汇收支平衡
  • 公章未备案是否不合法
  • 普通发票不能抵扣进项税额怎么做账
  • 高速费用支付宝的怎么开票
  • 税金及附加包括个人所得税吗
  • 一般纳税人暂估成本的账务处理
  • 研发费用的社保怎么做
  • 企业营改增后的会计处理有何变化
  • 收到别的公司的转账支票
  • 可转换债券发行主体
  • 收到赔偿怎么做账
  • 融资租赁收到租金不确认收入
  • 水费税收分类编码
  • 独生子女补贴是给父母还是子女的
  • 收到汽车报废补贴怎么做账?
  • 删除打印机如何添加
  • 公司收到项目投资款怎么做账 项目结束后需要退本金
  • win10如何设置快捷键截图
  • 如何修改win10系统电脑密码
  • 入库材料未付款属于什么会计科目
  • 增值税发票作废后还能查到吗
  • 企业出售房产土地增值税怎么计算
  • thinkphp生成html
  • 电子发票有哪些版本
  • 数学建模心态崩了
  • vgremove命令
  • 补缴以前年度企业所得税如何做账
  • 待抵扣进项税额的账务处理
  • 图书的税率有免税的吗
  • 上个月的留底税这个使用,会计分录
  • 装饰公司的开票范围
  • mysql需要转义的特殊字符
  • mongodb数据查询
  • 织梦logo
  • 计提加计抵减额在财务报表里哪里体现
  • 接受捐赠的增值税计入会计利润吗
  • 装修费用进什么科目
  • 公司的房租发票怎么记账
  • 收购分公司有什么要求
  • 会计凭证的审核的注意事项有哪些
  • 会计如何建账做账
  • 残保金是交上一年的吗
  • 2021年会计做账报税详细流程
  • windowsxp开机启动项在哪里设置
  • QQExternal.exe是什么进程?QQExternal.exe进程为什么被运行?
  • ubuntu 14.4
  • linux咋用
  • 电脑上dell是什么意思
  • win7任务栏高度可以改变
  • neo是什么意思中文翻译
  • win8怎么添加wifi
  • win8.1专业版怎么升级成win10
  • Win8系统32位和64位哪个好应该如何选择
  • [置顶]电影名字《收件人不详》
  • linux保存
  • 修改系统用户名为英文
  • unity灯光烘培
  • unity 更新
  • js能实现的简单效果
  • jQuery获取checkbox选中的值
  • javascript基础笔记
  • js中的类是什么
  • python asyncio await
  • 大征期和小征期的区别
  • 重庆车辆检测费多少钱
  • 内蒙古自治区耕地保养条例
  • 小规模纳税企业的增值税税率一律为3%
  • 已经开具的电子专票怎么重新下载
  • 社保信息怎么补全
  • 个人所得税税单下载
  • 关于船舶吨税的最新法律规范
  • 18个税种征税范围
  • 供给侧改革什么样的劳动力
  • 免责声明:网站部分图片文字素材来源于网络,如有侵权,请及时告知,我们会第一时间删除,谢谢! 邮箱:opceo@qq.com

    鄂ICP备2023003026号

    网站地图: 企业信息 工商信息 财税知识 网络常识 编程技术

    友情链接: 武汉网站建设