前言

eBPF是一项革命性的技术,可以在Linux内核中运行沙盒程序,而无需重新编译内核或加载内核模块。它能够在许多内核 hook 点安全地执行字节码,主要应用在云原生网络、安全、跟踪监控等方面。

eBPF 基金会 (https://ebpf.io) 是一个为 eBPF 技术而创建的非盈利性组织,隶属于 Linux 基金会,其意在推动 eBPF 更好地发展,使其得到更加广泛的运用。

下面我将介绍如何在Rust中开发基于eBPF技术的应用示例。(该示例教程主要面向具备Rust开发基础的同学)

(一)环境准备

一台VM或Linux系统主机

推荐系统:Ubuntu20.04

内存:4G以上

Rust开发工具链:v1.56~

(二)安装llvm13(编译bpf字节码需要)

apt-get update
apt-get -y install wget build-essential software-properties-common lsb-release libelf-dev linux-headers-generic pkg-config
wget https://apt.llvm.org/llvm.sh
chmod +x llvm.sh
./llvm.sh 13
rm -f ./llvm.sh
//检验是否安装成功,输出版本号表示安装成功
llvm-config-13 --version | grep 13

(三)安装 cargo-bpf脚手架

cargo install cargo-bpf --no-default-features --features=llvm13

(四)应用示例

#1、创建用户空间代码目录
cargo new bpfdemo
cd bpfdemo
#2、创建bpf代码目录
cargo bpf new probes
ls
>>Cargo.lock Cargo.toml probes src
#3、编写一个openmonitor bpf程序 输出系统打开的文件
cd probes
cargo bpf add openmonitor
cd src
ls
>>lib.rs openmonitor
cd openmonitor
nano main.rs

完整openmonitor/main.rs代码如下:

#![no_std]
#![no_main] use probes::openmonitor::*;
use redbpf_probes::kprobe::prelude::*; program!(0xFFFFFFFE, "GPL"); #[map]
static mut OPEN_PATHS: PerfMap<OpenPath> = PerfMap::with_max_entries(1024); #[kprobe]
fn do_sys_open(regs: Registers) {
let mut path = OpenPath::default();
unsafe {
let filename = regs.parm2() as *const u8;
if bpf_probe_read_user_str(
path.filename.as_mut_ptr() as *mut _,
path.filename.len() as u32,
filename as *const _,
) <= 0
{
bpf_trace_printk(b"error on bpf_probe_read_user_str\0");
return;
}
OPEN_PATHS.insert(regs.ctx, &path);
}
}

完整openmonitor/mod.rs代码如下

pub const PATHLEN: usize = 256;

#[repr(C)]
#[derive(Debug, Clone)]
pub struct OpenPath {
pub filename: [u8; PATHLEN],
} impl Default for OpenPath {
fn default() -> OpenPath {
OpenPath {
filename: [0; PATHLEN],
}
}
}
#4.在probes目录下编译bpf程序,生成openmonitor.elf文件
cargo bpf build --target-dir=../target
ls ../target/bpf/programs/openmonitor/openmonitor.elf #5.在用户空间代码中使用bpf程序,获取系统打开文件
cd ../src
nano main.rs

完整bpfdemo/src/main.rs代码如下

use futures::stream::StreamExt;
use std::{ffi::CStr, ptr};
use tracing::Level;
use tracing_subscriber::FmtSubscriber; use redbpf::load::Loader; use probes::openmonitor::OpenPath; fn probe_code() -> &'static [u8] {
include_bytes!(concat!(
env!("CARGO_MANIFEST_DIR"),
"/target/bpf/programs/openmonitor/openmonitor.elf"
))
} #[tokio::main(flavor = "current_thread")]
async fn main() {
let subscriber = FmtSubscriber::builder()
.with_max_level(Level::WARN)
.finish();
tracing::subscriber::set_global_default(subscriber).unwrap(); let mut loaded = Loader::load(probe_code()).expect("error on Loader::load"); let probe = loaded
.kprobe_mut("do_sys_open")
.expect("error on Loaded::kprobe_mut");
probe
.attach_kprobe("do_sys_open", 0)
.expect("error on KProbe::attach_kprobe");
probe
.attach_kprobe("do_sys_openat2", 0)
.expect("error on KProbe::attach_kprobe"); while let Some((map_name, events)) = loaded.events.next().await {
if map_name == "OPEN_PATHS" {
for event in events {
let open_path = unsafe { ptr::read(event.as_ptr() as *const OpenPath) };
unsafe {
let cfilename = CStr::from_ptr(open_path.filename.as_ptr() as *const _);
println!("{}", cfilename.to_string_lossy());
};
}
}
}
}
#6.在bpfdemo目录下编译运行
cargo build
cargo run #将会输出系统实时打开的文件
>>
/proc/driver/nvidia/params
/dev/nvidia0
/proc/driver/nvidia/params
/dev/nvidia0
/proc/driver/nvidia/params
/dev/nvidia0
/etc/localtime
/lib/x86_64-linux-gnu/libcuda.so.1
/lib/x86_64-linux-gnu/libm.so.6
/etc/netconfig
/sys/fs/cgroup/unified/system.slice/systemd-udevd.service/cgroup.procs
/sys/fs/cgroup/unified/system.slice/systemd-udevd.service/cgroup.threads
/proc/3084/cmdline
/proc/3729/cmdline
/proc/3994/cmdline
/proc/8823/cmdline
/proc/2231364/cmdline
/proc/2431788/cmdline
/proc/2560949/cmdline
/sys/class/hwmon
/sys/class/hwmon/hwmon6
/sys/class/hwmon/hwmon4
/sys/class/hwmon/hwmon2
/sys/class/hwmon/hwmon0
/sys/class/hwmon/hwmon7
/sys/class/hwmon/hwmon5

完毕!

Rust如何开发eBPF应用(一)?的更多相关文章

  1. Rust Aya 编写 eBPF 程序

    本文地址:https://www.ebpf.top/post/ebpf_rust_aya 1. 前言 Linux 内核 6.1 版本中有一个非常引人注意的变化:引入了对 Rust 编程语言的支持.Ru ...

  2. Rust语言开发

    Rust开发 第一个程序 fn main() { println!("Hello, world!"); // 带!号的都是宏 并不是函数 } fn main() { let nam ...

  3. 专访Rust——由Mozilla开发的系统编程语言(目标人群就是那些纠结的C++程序员,甚至也是他们自己)

    Rust是由Mozilla开发的专门用来编写高性能应用程序的系统编程语言.以下是对Rust的创始人——Graydon Hoare的采访. Graydon Hoare,自称为职业编程语言工程师,从200 ...

  4. Rust语言

    Rust语言 https://doc.rust-lang.org/stable/book/ http://www.phperz.com/article/15/0717/141560.html Rust ...

  5. InfoQ中文站特供稿件:Rust编程语言的核心部件

    本文为InfoQ中文站特供稿件.首发地址为: http://www.infoq.com/cn/articles/rust-core-components .如需转载.请与InfoQ中文站联系. 原文发 ...

  6. Rust语言——无虚拟机、无垃圾收集器、无运行时、无空指针/野指针/内存越界/缓冲区溢出/段错误、无数据竞争

    2006年,编程语言工程师Graydon Hoare利用业余时间启动了Rust语言项目.该项目充分借鉴了C/C++/Java/Python等语言的经验,试图在保持良好性能的同时,克服以往编程语言所存在 ...

  7. 我持续推动Rust语言支持Windows XP系统

    前言 Rust好像长期以来不支持Windows XP系统.有不少用户发帖提议官方支持XP,基本上都被Rust官方开发人员明白的拒绝了.他们的对话大致上是以这种形式開始和结束的(当中乙方代表官方及其拥趸 ...

  8. SQLite为何要用C语言来开发?

    SQLite 选择 C 语言的理由是?为什么不选择 Go 或者 Rust? C 语言是最好的 SQLite 在 2000 年 5 月 29 日发布,并一直使用 C 语言实现.C 语言一直是实现 SQL ...

  9. eBPF Tracing 入门教程与实例

    原文链接 Learn eBPF Tracing: Tutorial and Examples译者 弃余 在 LPC'18(Linux Plumber's conference) 会议上,至少有24个关 ...

随机推荐

  1. 06分频计数器之LED闪烁1

    一设计功能是:让LED灯每1秒亮一次,再灭一秒,闪烁时间周期为2秒. 二分频的介绍: (一)设计方式:IP核和自己动手写. (二)对于分频的构成:一个是计数器,还有时钟翻转.方法一是计满整个周期,一半 ...

  2. 开源电调blheli / blheli_s分析

    一. 启动阶段分析 启动阶段需完成24次换相,超过24次之后进入初始运行阶段,该阶段持续12次换相周期(每个周期6次换相),完成后进入正常运转阶段 二. 换相时间分析 总体思想是根据电机运行状态计算前 ...

  3. 一致性检验评价方法kappa

    最近在做眼底图像的无监督分类,使用的数据集辣子kaggle的Diabetic Retinopathy,简称DR,中文称糖尿病型眼底疾病. 最后的评估方法是二次加权kappa.以前没接触过,网上也没有具 ...

  4. Nature | 易基因DNA甲基化测序助力人多能干细胞向胚胎全能8细胞的人工诱导

    北京时间2022年3月22日凌晨,<Nature>期刊在线刊登了由中国科学院广州生物医学与健康研究所等单位牵头,深圳市易基因科技有限公司.中国科学技术大学等单位参与,应用人多能干细胞向胚胎 ...

  5. python 常用内置函数简介

    1.作用域相关内置函数globals()--获取全局变量的字典locals()--获取执行本方法所在命名空间内的局部变量的字典 2.和调用相关callable(o),o是参数,看这个变量是不是可调用. ...

  6. mac 安装shell

    https://blog.csdn.net/weixin_41937552/article/details/108565705

  7. Redis 集群,集群的原理是什么?

    1).Redis Sentinal 着眼于高可用,在 master 宕机时会自动将 slave 提升为master,继续提供服务. 2).Redis Cluster 着眼于扩展性,在单个 redis ...

  8. 面试问题之C++语言:如何避免内存泄漏?

    转载于:https://www.php.cn/csharp-article-416104.html 1.不要手动管理内存,可以尝试在适用的情况下使用智能指针. 2.使用string而不是char*.s ...

  9. 说说对 SQL 语句优化有哪些方法?

    1.Where 子句中:where 表之间的连接必须写在其他 Where 条件之前,那些可 以过滤掉最大数量记录的条件必须写在 Where 子句的末尾.HAVING 最后. 2.用 EXISTS 替代 ...

  10. 两个相同的对象会有不同的的 hash code 吗?

    不能,根据 hash code 的规定,这是不可能的.