feat: support tracepoint-based ebpf programs (#1190)

* feat: support tracepoint-based ebpf programs

Signed-off-by: Godones <chenlinfeng25@outlook.com>

* remove licenses

Signed-off-by: Godones <chenlinfeng25@outlook.com>

* feat: Supplement tracepoint related files

fix some warnings
add docs for tracepoint

Signed-off-by: Godones <chenlinfeng25@outlook.com>

---------

Signed-off-by: Godones <chenlinfeng25@outlook.com>
Co-authored-by: longjin <longjin@DragonOS.org>
This commit is contained in:
linfeng
2025-06-14 17:34:45 +08:00
committed by GitHub
parent 8471e4173e
commit 6b581d4dd8
31 changed files with 1868 additions and 60 deletions

View File

@ -0,0 +1,44 @@
[package]
name = "mytrace"
version = "0.1.0"
edition = "2021"
license.workspace = true
[dependencies]
mytrace-common = { path = "../mytrace-common", features = ["user"] }
anyhow = { workspace = true, default-features = true }
aya = { workspace = true }
aya-log = { workspace = true }
env_logger = { workspace = true }
libc = { workspace = true }
log = { workspace = true }
tokio = { workspace = true, features = [
"macros",
"rt",
"rt-multi-thread",
"net",
"signal",
"time"
] }
[build-dependencies]
anyhow = { workspace = true }
aya-build = { workspace = true }
# TODO(https://github.com/rust-lang/cargo/issues/12375): this should be an artifact dependency, but
# it's not possible to tell cargo to use `-Z build-std` to build it. We cargo-in-cargo in the build
# script to build this, but we want to teach cargo about the dependecy so that cache invalidation
# works properly.
#
# Note also that https://github.com/rust-lang/cargo/issues/10593 occurs when `target = ...` is added
# to an artifact dependency; it seems possible to work around that by setting `resolver = "1"` in
# Cargo.toml in the workspace root.
#
# Finally note that *any* usage of `artifact = ...` in *any* Cargo.toml in the workspace breaks
# workflows with stable cargo; stable cargo outright refuses to load manifests that use unstable
# features.
mytrace-ebpf = { path = "../mytrace-ebpf" }
[[bin]]
name = "mytrace"
path = "src/main.rs"

View File

@ -0,0 +1,14 @@
use anyhow::{anyhow, Context as _};
use aya_build::cargo_metadata;
fn main() -> anyhow::Result<()> {
let cargo_metadata::Metadata { packages, .. } = cargo_metadata::MetadataCommand::new()
.no_deps()
.exec()
.context("MetadataCommand::exec")?;
let ebpf_package = packages
.into_iter()
.find(|cargo_metadata::Package { name, .. }| name == "mytrace-ebpf")
.ok_or_else(|| anyhow!("mytrace-ebpf package not found"))?;
aya_build::build_ebpf([ebpf_package])
}

View File

@ -0,0 +1,62 @@
use aya::programs::TracePoint;
#[rustfmt::skip]
use log::{debug, warn};
use tokio::{signal, task::yield_now, time};
#[tokio::main(flavor = "current_thread")]
async fn main() -> anyhow::Result<()> {
// env_logger::init();
env_logger::builder()
.filter_level(log::LevelFilter::Info)
.format_timestamp(None)
.init();
// Bump the memlock rlimit. This is needed for older kernels that don't use the
// new memcg based accounting, see https://lwn.net/Articles/837122/
let rlim = libc::rlimit {
rlim_cur: libc::RLIM_INFINITY,
rlim_max: libc::RLIM_INFINITY,
};
let ret = unsafe { libc::setrlimit(libc::RLIMIT_MEMLOCK, &rlim) };
if ret != 0 {
debug!("remove limit on locked memory failed, ret is: {ret}");
}
// This will include your eBPF object file as raw bytes at compile-time and load it at
// runtime. This approach is recommended for most real-world use cases. If you would
// like to specify the eBPF program at runtime rather than at compile-time, you can
// reach for `Bpf::load_file` instead.
let mut ebpf = aya::Ebpf::load(aya::include_bytes_aligned!(concat!(
env!("OUT_DIR"),
"/mytrace"
)))?;
if let Err(e) = aya_log::EbpfLogger::init(&mut ebpf) {
// This can happen if you remove all log statements from your eBPF program.
warn!("failed to initialize eBPF logger: {e}");
}
let program: &mut TracePoint = ebpf.program_mut("mytrace").unwrap().try_into()?;
program.load()?;
program.attach("syscalls", "sys_enter_openat")?;
tokio::spawn(async move {
let mut now = time::Instant::now();
loop {
let new_now = time::Instant::now();
let duration = new_now.duration_since(now);
if duration.as_secs() >= 2 {
// open a file to trigger the tracepoint
log::info!("Triggering tracepoint by opening /bin");
let bin = std::fs::File::open("/bin").unwrap();
drop(bin);
now = new_now;
}
yield_now().await;
}
});
let ctrl_c = signal::ctrl_c();
println!("Waiting for Ctrl-C...");
ctrl_c.await?;
println!("Exiting...");
Ok(())
}