use std::{
fs::File,
os::fd::{AsFd, BorrowedFd},
};
use aya_obj::{
btf::{Btf, BtfKind},
generated::{
bpf_attach_type::BPF_TRACE_ITER, bpf_link_type::BPF_LINK_TYPE_ITER,
bpf_prog_type::BPF_PROG_TYPE_TRACING,
},
};
use crate::{
programs::{
FdLink, LinkError, PerfLinkIdInner, PerfLinkInner, ProgramData, ProgramError, ProgramType,
define_link_wrapper, impl_try_from_fdlink, impl_try_into_fdlink,
load_program_with_attach_type,
},
sys::{LinkTarget, SyscallError, bpf_create_iter, bpf_link_create},
};
#[derive(Debug)]
pub struct Iter {
pub(crate) data: ProgramData<IterLink>,
}
impl Iter {
pub const PROGRAM_TYPE: ProgramType = ProgramType::Tracing;
pub fn load(&mut self, iter_type: &str, btf: &Btf) -> Result<(), ProgramError> {
let Self { data } = self;
let type_name = format!("bpf_iter_{iter_type}");
data.attach_btf_id = Some(btf.id_by_type_name_kind(type_name.as_str(), BtfKind::Func)?);
load_program_with_attach_type(BPF_PROG_TYPE_TRACING, BPF_TRACE_ITER, data)
}
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, 0, None).map_err(
|io_error| SyscallError {
call: "bpf_link_create",
io_error,
},
)?;
self.data
.links
.insert(IterLink::new(PerfLinkInner::Fd(FdLink::new(link_fd))))
}
}
#[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_try_into_fdlink!(IterLink, PerfLinkInner);
impl_try_from_fdlink!(IterLink, PerfLinkInner, BPF_LINK_TYPE_ITER);
define_link_wrapper!(IterLink, IterLinkId, PerfLinkInner, PerfLinkIdInner, Iter);
impl IterLink {
pub fn into_file(self) -> Result<File, LinkError> {
if let PerfLinkInner::Fd(fd) = self.into_inner() {
let fd = bpf_create_iter(fd.fd.as_fd()).map_err(|io_error| {
LinkError::SyscallError(SyscallError {
call: "bpf_iter_create",
io_error,
})
})?;
Ok(fd.into_inner().into())
} else {
Err(LinkError::InvalidLink)
}
}
}