-
Notifications
You must be signed in to change notification settings - Fork 290
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(aya): Add iterator program type
BPF iterators[0] are a way to dump kernel data into user-space and an alternative to `/proc` filesystem. This change adds support for BPF iterators on the user-space side. It provides a possibility to retrieve the outputs of BPF iterator programs both from sync and async Rust code. [0] https://docs.kernel.org/bpf/bpf_iterators.html
- Loading branch information
1 parent
e423fce
commit 9165e7f
Showing
15 changed files
with
543 additions
and
7 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,160 @@ | ||
//! Iterators. | ||
use std::os::fd::{AsFd, BorrowedFd}; | ||
|
||
use crate::{ | ||
generated::{bpf_attach_type::BPF_TRACE_ITER, bpf_link_type, bpf_prog_type}, | ||
obj::btf::{Btf, BtfKind}, | ||
programs::{ | ||
define_link_wrapper, load_program, FdLink, LinkError, PerfLinkIdInner, PerfLinkInner, | ||
ProgramData, ProgramError, | ||
}, | ||
sys::{bpf_create_iter, bpf_link_create, bpf_link_get_info_by_fd, LinkTarget, SyscallError}, | ||
}; | ||
|
||
/// An eBPF iterator which allows to dump into user space. | ||
/// | ||
/// It can be seen as an alternative to `/proc` filesystem, as it offers more | ||
/// flexibility about what information should be retrieved and how it should be | ||
/// formatted. | ||
/// | ||
/// # Minimum kernel version | ||
/// | ||
/// The minimum kernel version required to use this feature is 5.8. | ||
/// | ||
/// # Examples | ||
/// | ||
/// ## Non-async Rust | ||
/// | ||
/// ```no_run | ||
/// use std::io::{BufRead, BufReader}; | ||
/// use aya::{programs::{Iter, ProgramError}, BtfError, Btf, Ebpf}; | ||
/// # let mut ebpf = Ebpf::load_file("ebpf_programs.o")?; | ||
/// | ||
/// let btf = Btf::from_sys_fs()?; | ||
/// let program: &mut Iter = ebpf.program_mut("iter_prog").unwrap().try_into()?; | ||
/// program.load("task", &btf)?; | ||
/// | ||
/// let link_id = program.attach()?; | ||
/// let link = program.take_link(link_id)?; | ||
/// let file = link.into_file()?; | ||
/// let reader = BufReader::new(file); | ||
/// | ||
/// let mut lines = reader.lines(); | ||
/// for line in lines { | ||
/// let line = line?; | ||
/// println!("{line}"); | ||
/// } | ||
/// # Ok::<(), Box<dyn std::error::Error>>(()) | ||
/// ``` | ||
#[derive(Debug)] | ||
pub struct Iter { | ||
pub(crate) data: ProgramData<IterLink>, | ||
} | ||
|
||
impl Iter { | ||
/// Loads the program inside the kernel. | ||
pub fn load(&mut self, iter_type: &str, btf: &Btf) -> Result<(), ProgramError> { | ||
self.data.expected_attach_type = Some(BPF_TRACE_ITER); | ||
let type_name = format!("bpf_iter_{iter_type}"); | ||
self.data.attach_btf_id = | ||
Some(btf.id_by_type_name_kind(type_name.as_str(), BtfKind::Func)?); | ||
load_program(bpf_prog_type::BPF_PROG_TYPE_TRACING, &mut self.data) | ||
} | ||
|
||
/// Attaches the program. | ||
/// | ||
/// The returned value can be used to detach, see [`Iter::detach`]. | ||
pub fn attach(&mut self) -> Result<IterLinkId, ProgramError> { | ||
let prog_fd = self.fd()?; | ||
let prog_fd = prog_fd.as_fd(); | ||
let link_fd = bpf_link_create(prog_fd, LinkTarget::Iter, BPF_TRACE_ITER, None, 0, None) | ||
.map_err(|(_, io_error)| SyscallError { | ||
call: "bpf_link_create", | ||
io_error, | ||
})?; | ||
|
||
self.data | ||
.links | ||
.insert(IterLink::new(PerfLinkInner::FdLink(FdLink::new(link_fd)))) | ||
} | ||
|
||
/// Detaches the program. | ||
/// | ||
/// See [`Iter::attach`]. | ||
pub fn detach(&mut self, link_id: IterLinkId) -> Result<(), ProgramError> { | ||
self.data.links.remove(link_id) | ||
} | ||
|
||
/// Takes ownership of the link referenced by the provided link_id. | ||
/// | ||
/// The caller takes the responsibility of managing the lifetime of the | ||
/// link. When the returned `IterLink` is dropped, the link is detached. | ||
pub fn take_link(&mut self, link_id: IterLinkId) -> Result<IterLink, ProgramError> { | ||
self.data.take_link(link_id) | ||
} | ||
} | ||
|
||
/// An iterator descriptor. | ||
#[derive(Debug)] | ||
pub struct IterFd { | ||
fd: crate::MockableFd, | ||
} | ||
|
||
impl AsFd for IterFd { | ||
fn as_fd(&self) -> BorrowedFd<'_> { | ||
let Self { fd } = self; | ||
fd.as_fd() | ||
} | ||
} | ||
|
||
impl TryFrom<IterLink> for FdLink { | ||
type Error = LinkError; | ||
|
||
fn try_from(value: IterLink) -> Result<Self, Self::Error> { | ||
if let PerfLinkInner::FdLink(fd) = value.into_inner() { | ||
Ok(fd) | ||
} else { | ||
Err(LinkError::InvalidLink) | ||
} | ||
} | ||
} | ||
|
||
impl TryFrom<FdLink> for IterLink { | ||
type Error = LinkError; | ||
|
||
fn try_from(fd_link: FdLink) -> Result<Self, Self::Error> { | ||
let info = bpf_link_get_info_by_fd(fd_link.fd.as_fd())?; | ||
if info.type_ == (bpf_link_type::BPF_LINK_TYPE_ITER as u32) { | ||
return Ok(Self::new(PerfLinkInner::FdLink(fd_link))); | ||
} | ||
Err(LinkError::InvalidLink) | ||
} | ||
} | ||
|
||
define_link_wrapper!( | ||
/// The link used by [Iter] programs. | ||
IterLink, | ||
/// The type returned by [Iter::attach]. Can be passed to [Iter::detach]. | ||
IterLinkId, | ||
PerfLinkInner, | ||
PerfLinkIdInner | ||
); | ||
|
||
impl IterLink { | ||
/// Converts [IterLink] into a [std::fs::File]. That file can be used to | ||
/// retrieve the outputs of the iterator program. | ||
pub fn into_file(self) -> Result<std::fs::File, LinkError> { | ||
if let PerfLinkInner::FdLink(fd) = self.into_inner() { | ||
let fd = bpf_create_iter(fd.fd.as_fd()).map_err(|(_, error)| { | ||
LinkError::SyscallError(SyscallError { | ||
call: "bpf_iter_create", | ||
io_error: error, | ||
}) | ||
})?; | ||
let file: std::fs::File = fd.into_inner().into(); | ||
Ok(file) | ||
} else { | ||
Err(LinkError::InvalidLink) | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.