前言

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. [SPDK/NVMe存储技术分析]008 - RDMA概述

    毫无疑问地,用来取代iSCSI/iSER(iSCSI Extensions for RDMA)技术的NVMe over Fabrics着实让RDMA又火了一把.在介绍NVMe over Fabrics ...

  2. CF1485X Codeforces Round #701

    D Multiples and Power Differences (构造) 题目大意:给一个n*m的矩阵a,a[i][j]在1到16之间.现在要构造矩阵b,需要满足如下条件: 1.b[i][j]在1 ...

  3. HyBird App(混合应用)核心原理JSBridge

    目录 app分类 HyBird App(混合应用) JSBridge介绍 优势及应用场景 JsBridge的核心 1.Web端调用Native端代码 1.1 拦截URL Schema 1.2 注入ap ...

  4. java常见面试问题总结

    JDK1.7 并发的HashMap为什么会引起死循环? hashmap如何解决hash冲突,为什么hashmap中的链表需要转成红黑树? hashmap什么时候会触发扩容? jdk1.8之前并发操作h ...

  5. 为什么枚举单例在 Java 中更好?

    枚举单例是使用一个实例在 Java 中实现单例模式的新方法.虽然Java中的单例模式存在很长时间,但枚举单例是相对较新的概念,在引入Enum作为关键字和功能之后,从Java5开始在实践中.本文与之前关 ...

  6. Ribbon和Feign的区别?

    1.Ribbon都是调用其他服务的,但方式不同.2.启动类注解不同,Ribbon是@RibbonClient feign的是@EnableFeignClients3.服务指定的位置不同,Ribbon是 ...

  7. JVM内存模型小结

    JVM运行时的数据区域划分图如下,该图是JVM内存模型最主要的内容. 从图中可以看出来,JVM将内存主要划分为五个部分:程序计数器.Java虚拟机栈.本地方法栈.Java堆和方法区.这些被划分为用途不 ...

  8. Springboot添加静态资源映射addResourceHandlers,可实现url访问

    @Configuration //public class WebMvcConfiger extends WebMvcConfigurerAdapter { public class WebMvcCo ...

  9. 相对路径在IEAD中的位置

    相对路径在IEAD中的位置 工具栏-->Run -->Edit Configurations -->Working directory-->就是了 这里是直接到软件的地址:剩下 ...

  10. 关于CPU、指令集、架构、芯片的一些科普

    作者:王强链接:https://zhuanlan.zhihu.com/p/19893066来源:知乎 随着智能设备的广泛普及,这几年媒体上越来越多的出现关于"架构""AR ...