mirror of https://github.com/aya-rs/aya
Support for fentry and fexit programs
fentry and fexit programs are similar to kprobe and kretprobe, but they are newer and they have practically zero overhead to call before or after kernel function. Also, fexit programs are focused on access to arguments rather than the return value. Those kind of programs were introduced in the following patchset: https://lwn.net/Articles/804112/ Signed-off-by: Michal Rostecki <mrostecki@opensuse.org>pull/143/head
parent
54b0c67795
commit
7e2fcd1d6d
@ -0,0 +1,67 @@
|
||||
//! fentry programs.
|
||||
use crate::{
|
||||
generated::{bpf_attach_type::BPF_TRACE_FENTRY, bpf_prog_type::BPF_PROG_TYPE_TRACING},
|
||||
obj::btf::{Btf, BtfKind},
|
||||
programs::{load_program, utils::attach_raw_tracepoint, LinkRef, ProgramData, ProgramError},
|
||||
};
|
||||
|
||||
/// A program that can be attached to the entry point of (almost) any kernel
|
||||
/// function.
|
||||
///
|
||||
/// [`FEntry`] programs are similar to [kprobes](crate::programs::KProbe), but
|
||||
/// the difference is that fentry has practically zero overhead to call before
|
||||
/// kernel function. Fentry programs can be also attaached to other eBPF
|
||||
/// programs.
|
||||
///
|
||||
/// # Minimum kernel version
|
||||
///
|
||||
/// The minimum kernel version required to use this feature is 5.5.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```no_run
|
||||
/// # #[derive(thiserror::Error, Debug)]
|
||||
/// # enum Error {
|
||||
/// # #[error(transparent)]
|
||||
/// # BtfError(#[from] aya::BtfError),
|
||||
/// # #[error(transparent)]
|
||||
/// # Program(#[from] aya::programs::ProgramError),
|
||||
/// # #[error(transparent)]
|
||||
/// # Bpf(#[from] aya::BpfError),
|
||||
/// # }
|
||||
/// # let mut bpf = Bpf::load_file("ebpf_programs.o")?;
|
||||
/// use aya::{Bpf, programs::FEntry, BtfError, Btf};
|
||||
/// use std::convert::TryInto;
|
||||
///
|
||||
/// let btf = Btf::from_sys_fs()?;
|
||||
/// let program: &mut FEntry = bpf.program_mut("filename_lookup").unwrap().try_into()?;
|
||||
/// program.load("filename_lookup", &btf)?;
|
||||
/// program.attach()?;
|
||||
/// # Ok::<(), Error>(())
|
||||
/// ```
|
||||
#[derive(Debug)]
|
||||
#[doc(alias = "BPF_TRACE_FENTRY")]
|
||||
#[doc(alias = "BPF_PROG_TYPE_TRACING")]
|
||||
pub struct FEntry {
|
||||
pub(crate) data: ProgramData,
|
||||
}
|
||||
|
||||
impl FEntry {
|
||||
/// Loads the program inside the kernel.
|
||||
///
|
||||
/// See also [`Program::load`](crate::programs::Program::load).
|
||||
///
|
||||
/// Loads the program so it's executed when the kernel function `fn_name`
|
||||
/// is entered. The `btf` argument must contain the BTF info for the
|
||||
/// running kernel.
|
||||
pub fn load(&mut self, fn_name: &str, btf: &Btf) -> Result<(), ProgramError> {
|
||||
self.data.expected_attach_type = Some(BPF_TRACE_FENTRY);
|
||||
self.data.attach_btf_id = Some(btf.id_by_type_name_kind(fn_name, BtfKind::Func)?);
|
||||
load_program(BPF_PROG_TYPE_TRACING, &mut self.data)
|
||||
}
|
||||
|
||||
/// Attaches the program
|
||||
pub fn attach(&mut self) -> Result<LinkRef, ProgramError> {
|
||||
attach_raw_tracepoint(&mut self.data, None)
|
||||
}
|
||||
}
|
@ -0,0 +1,67 @@
|
||||
//! fexit programs.
|
||||
use crate::{
|
||||
generated::{bpf_attach_type::BPF_TRACE_FEXIT, bpf_prog_type::BPF_PROG_TYPE_TRACING},
|
||||
obj::btf::{Btf, BtfKind},
|
||||
programs::{load_program, utils::attach_raw_tracepoint, LinkRef, ProgramData, ProgramError},
|
||||
};
|
||||
|
||||
/// A program that can be attached to the exit point of (almost) anny kernel
|
||||
/// function.
|
||||
///
|
||||
/// [`FExit`] programs are similar to [kretprobes](crate::programs::KProbe),
|
||||
/// but the difference is that fexit has practically zero overhead to call
|
||||
/// before kernel function. Fexit programs can be also attached to other eBPF
|
||||
/// programs.
|
||||
///
|
||||
/// # Minimum kernel version
|
||||
///
|
||||
/// The minimum kernel version required to use this feature is 5.5.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```no_run
|
||||
/// # #[derive(thiserror::Error, Debug)]
|
||||
/// # enum Error {
|
||||
/// # #[error(transparent)]
|
||||
/// # BtfError(#[from] aya::BtfError),
|
||||
/// # #[error(transparent)]
|
||||
/// # Program(#[from] aya::programs::ProgramError),
|
||||
/// # #[error(transparent)]
|
||||
/// # Bpf(#[from] aya::BpfError),
|
||||
/// # }
|
||||
/// # let mut bpf = Bpf::load_file("ebpf_programs.o")?;
|
||||
/// use aya::{Bpf, programs::FExit, BtfError, Btf};
|
||||
/// use std::convert::TryInto;
|
||||
///
|
||||
/// let btf = Btf::from_sys_fs()?;
|
||||
/// let program: &mut FExit = bpf.program_mut("filename_lookup").unwrap().try_into()?;
|
||||
/// program.load("filename_lookup", &btf)?;
|
||||
/// program.attach()?;
|
||||
/// # Ok::<(), Error>(())
|
||||
/// ```
|
||||
#[derive(Debug)]
|
||||
#[doc(alias = "BPF_TRACE_FEXIT")]
|
||||
#[doc(alias = "BPF_PROG_TYPE_TRACING")]
|
||||
pub struct FExit {
|
||||
pub(crate) data: ProgramData,
|
||||
}
|
||||
|
||||
impl FExit {
|
||||
/// Loads the program inside the kernel.
|
||||
///
|
||||
/// See also [`Program::load`](crate::programs::Program::load).
|
||||
///
|
||||
/// Loads the program so it's executed when the kernel function `fn_name`
|
||||
/// is exited. The `btf` argument must contain the BTF info for the running
|
||||
/// kernel.
|
||||
pub fn load(&mut self, fn_name: &str, btf: &Btf) -> Result<(), ProgramError> {
|
||||
self.data.expected_attach_type = Some(BPF_TRACE_FEXIT);
|
||||
self.data.attach_btf_id = Some(btf.id_by_type_name_kind(fn_name, BtfKind::Func)?);
|
||||
load_program(BPF_PROG_TYPE_TRACING, &mut self.data)
|
||||
}
|
||||
|
||||
/// Attaches the program
|
||||
pub fn attach(&mut self) -> Result<LinkRef, ProgramError> {
|
||||
attach_raw_tracepoint(&mut self.data, None)
|
||||
}
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
//! Common functions shared between multiple eBPF program types.
|
||||
use std::{ffi::CStr, os::unix::io::RawFd};
|
||||
|
||||
use crate::{
|
||||
programs::{FdLink, LinkRef, ProgramData, ProgramError},
|
||||
sys::bpf_raw_tracepoint_open,
|
||||
};
|
||||
|
||||
/// Attaches the program to a raw tracepoint.
|
||||
pub(crate) fn attach_raw_tracepoint(
|
||||
program_data: &mut ProgramData,
|
||||
tp_name: Option<&CStr>,
|
||||
) -> Result<LinkRef, ProgramError> {
|
||||
let prog_fd = program_data.fd_or_err()?;
|
||||
|
||||
let pfd = bpf_raw_tracepoint_open(tp_name, prog_fd).map_err(|(_code, io_error)| {
|
||||
ProgramError::SyscallError {
|
||||
call: "bpf_raw_tracepoint_open".to_owned(),
|
||||
io_error,
|
||||
}
|
||||
})? as RawFd;
|
||||
|
||||
Ok(program_data.link(FdLink { fd: Some(pfd) }))
|
||||
}
|
@ -0,0 +1,43 @@
|
||||
use core::ffi::c_void;
|
||||
|
||||
use crate::{args::FromBtfArgument, BpfContext};
|
||||
|
||||
pub struct FEntryContext {
|
||||
ctx: *mut c_void,
|
||||
}
|
||||
|
||||
impl FEntryContext {
|
||||
pub fn new(ctx: *mut c_void) -> FEntryContext {
|
||||
FEntryContext { ctx }
|
||||
}
|
||||
|
||||
/// Returns the `n`th argument to passed to the probe function, starting from 0.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```no_run
|
||||
/// # #![allow(non_camel_case_types)]
|
||||
/// # #![allow(dead_code)]
|
||||
/// # use aya_bpf::{cty::c_int, programs::FEntryContext};
|
||||
/// # type pid_t = c_int;
|
||||
/// # struct task_struct {
|
||||
/// # pid: pid_t,
|
||||
/// # }
|
||||
/// unsafe fn try_fentry_try_to_wake_up(ctx: FEntryContext) -> Result<u32, u32> {
|
||||
/// let tp: *const task_struct = ctx.arg(0);
|
||||
///
|
||||
/// // Do something with tp
|
||||
///
|
||||
/// Ok(0)
|
||||
/// }
|
||||
/// ```
|
||||
pub unsafe fn arg<T: FromBtfArgument>(&self, n: usize) -> T {
|
||||
T::from_argument(self.ctx as *const _, n)
|
||||
}
|
||||
}
|
||||
|
||||
impl BpfContext for FEntryContext {
|
||||
fn as_ptr(&self) -> *mut c_void {
|
||||
self.ctx
|
||||
}
|
||||
}
|
@ -0,0 +1,43 @@
|
||||
use core::ffi::c_void;
|
||||
|
||||
use crate::{args::FromBtfArgument, BpfContext};
|
||||
|
||||
pub struct FExitContext {
|
||||
ctx: *mut c_void,
|
||||
}
|
||||
|
||||
impl FExitContext {
|
||||
pub fn new(ctx: *mut c_void) -> FExitContext {
|
||||
FExitContext { ctx }
|
||||
}
|
||||
|
||||
/// Returns the `n`th argument to passed to the probe function, starting from 0.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```no_run
|
||||
/// # #![allow(non_camel_case_types)]
|
||||
/// # #![allow(dead_code)]
|
||||
/// # use aya_bpf::{cty::c_int, programs::FExitContext};
|
||||
/// # type pid_t = c_int;
|
||||
/// # struct task_struct {
|
||||
/// # pid: pid_t,
|
||||
/// # }
|
||||
/// unsafe fn try_filename_lookup(ctx: FExitContext) -> Result<u32, u32> {
|
||||
/// let tp: *const task_struct = ctx.arg(0);
|
||||
///
|
||||
/// // Do something with tp
|
||||
///
|
||||
/// Ok(0)
|
||||
/// }
|
||||
/// ```
|
||||
pub unsafe fn arg<T: FromBtfArgument>(&self, n: usize) -> T {
|
||||
T::from_argument(self.ctx as *const _, n)
|
||||
}
|
||||
}
|
||||
|
||||
impl BpfContext for FExitContext {
|
||||
fn as_ptr(&self) -> *mut c_void {
|
||||
self.ctx
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue