feat(ebpf):[WIP] add eBPF support (#948)

* feat(kprobe): Add basic kprobe support for x86_64

* feat: add ebpf support (#912)

- 实现bpf()一部分命令,包括几种基本map,相关的helper函数
- 实现部分perf相关的数据结构
- 暂时为文件实现简单mmap
- 实现一个使用kprobe统计syscall 调用次数的ebpf程序

对eBPF支持程度(基本):

- 简单的eBPF程序(没有指定特殊的Map)
- 使用内核已经实现的Map的eBPF程序
- 可以和kprobe配合使用
- 内核Map相关的接口定义已经实现,添加新的Map较为简单

不支持的功能:
- 区分不同的eBPF程序类型(Network/Cgroup)并限定可调用的helper函数集
- 与内核其它跟踪机制配合(tracepoint)
- 其它helper和Map


todo

- [ ]  修改mmap,需要讨论,因为这个和块缓存层相关
- [x]  添加文档
- [x]  修复可能的错误
- [x] 增加rbpf版本信息

* feat: add /sys/devices/system/cpu/possible file

* feat: add /sys/devices/system/cpu/online
This commit is contained in:
linfeng
2024-10-25 15:59:57 +08:00
committed by GitHub
parent 80c9e8f8f0
commit fae6e9ade4
126 changed files with 29529 additions and 62 deletions

View File

@ -0,0 +1,60 @@
use aya::maps::HashMap;
use aya::programs::KProbe;
use aya::{include_bytes_aligned, Ebpf};
use aya_log::EbpfLogger;
use log::{info, warn};
use std::error::Error;
use tokio::task::yield_now;
use tokio::{signal, time};
#[tokio::main(flavor = "current_thread")]
async fn main() -> Result<(), Box<dyn Error>> {
env_logger::builder()
.filter_level(log::LevelFilter::Warn)
.format_timestamp(None)
.init();
let mut bpf = Ebpf::load(include_bytes_aligned!(
"../syscall_ebpf/target/bpfel-unknown-none/release/syscall_ebpf"
))?;
// create a async task to read the log
if let Err(e) = EbpfLogger::init(&mut bpf) {
// This can happen if you remove all log statements from your eBPF program.
warn!("failed to initialize eBPF logger: {}", e);
}
let program: &mut KProbe = bpf.program_mut("syscall_ebpf").unwrap().try_into()?;
program.load()?;
program.attach("dragonos_kernel::syscall::Syscall::handle", 0)?;
info!("attacch the kprobe to dragonos_kernel::syscall::Syscall::handle");
// print the value of the blocklist per 5 seconds
tokio::spawn(async move {
let blocklist: HashMap<_, u32, u32> =
HashMap::try_from(bpf.map("SYSCALL_LIST").unwrap()).unwrap();
let mut now = time::Instant::now();
loop {
let new_now = time::Instant::now();
let duration = new_now.duration_since(now);
if duration.as_secs() >= 5 {
println!("------------SYSCALL_LIST----------------");
let iter = blocklist.iter();
for item in iter {
if let Ok((key, value)) = item {
println!("syscall: {:?}, count: {:?}", key, value);
}
}
println!("----------------------------------------");
now = new_now;
}
yield_now().await;
}
});
info!("Waiting for Ctrl-C...");
signal::ctrl_c().await?;
info!("Exiting...");
Ok(())
}