mirror of https://github.com/aya-rs/aya
Merge pull request #1007 from tyrone-wu/aya/info-api
aya,aya-obj,integration-test: add better support in `ProgramInfo` & `MapInfo` for old kernelspull/1018/head
commit
15eb935bce
@ -0,0 +1,100 @@
|
|||||||
|
//! Link type bindings.
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
generated::{bpf_attach_type, bpf_link_type},
|
||||||
|
InvalidTypeBinding,
|
||||||
|
};
|
||||||
|
|
||||||
|
impl TryFrom<u32> for bpf_link_type {
|
||||||
|
type Error = InvalidTypeBinding<u32>;
|
||||||
|
|
||||||
|
fn try_from(link_type: u32) -> Result<Self, Self::Error> {
|
||||||
|
use bpf_link_type::*;
|
||||||
|
Ok(match link_type {
|
||||||
|
x if x == BPF_LINK_TYPE_UNSPEC as u32 => BPF_LINK_TYPE_UNSPEC,
|
||||||
|
x if x == BPF_LINK_TYPE_RAW_TRACEPOINT as u32 => BPF_LINK_TYPE_RAW_TRACEPOINT,
|
||||||
|
x if x == BPF_LINK_TYPE_TRACING as u32 => BPF_LINK_TYPE_TRACING,
|
||||||
|
x if x == BPF_LINK_TYPE_CGROUP as u32 => BPF_LINK_TYPE_CGROUP,
|
||||||
|
x if x == BPF_LINK_TYPE_ITER as u32 => BPF_LINK_TYPE_ITER,
|
||||||
|
x if x == BPF_LINK_TYPE_NETNS as u32 => BPF_LINK_TYPE_NETNS,
|
||||||
|
x if x == BPF_LINK_TYPE_XDP as u32 => BPF_LINK_TYPE_XDP,
|
||||||
|
x if x == BPF_LINK_TYPE_PERF_EVENT as u32 => BPF_LINK_TYPE_PERF_EVENT,
|
||||||
|
x if x == BPF_LINK_TYPE_KPROBE_MULTI as u32 => BPF_LINK_TYPE_KPROBE_MULTI,
|
||||||
|
x if x == BPF_LINK_TYPE_STRUCT_OPS as u32 => BPF_LINK_TYPE_STRUCT_OPS,
|
||||||
|
x if x == BPF_LINK_TYPE_NETFILTER as u32 => BPF_LINK_TYPE_NETFILTER,
|
||||||
|
x if x == BPF_LINK_TYPE_TCX as u32 => BPF_LINK_TYPE_TCX,
|
||||||
|
x if x == BPF_LINK_TYPE_UPROBE_MULTI as u32 => BPF_LINK_TYPE_UPROBE_MULTI,
|
||||||
|
x if x == BPF_LINK_TYPE_NETKIT as u32 => BPF_LINK_TYPE_NETKIT,
|
||||||
|
_ => return Err(InvalidTypeBinding { value: link_type }),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryFrom<u32> for bpf_attach_type {
|
||||||
|
type Error = InvalidTypeBinding<u32>;
|
||||||
|
|
||||||
|
fn try_from(attach_type: u32) -> Result<Self, Self::Error> {
|
||||||
|
use bpf_attach_type::*;
|
||||||
|
Ok(match attach_type {
|
||||||
|
x if x == BPF_CGROUP_INET_INGRESS as u32 => BPF_CGROUP_INET_INGRESS,
|
||||||
|
x if x == BPF_CGROUP_INET_EGRESS as u32 => BPF_CGROUP_INET_EGRESS,
|
||||||
|
x if x == BPF_CGROUP_INET_SOCK_CREATE as u32 => BPF_CGROUP_INET_SOCK_CREATE,
|
||||||
|
x if x == BPF_CGROUP_SOCK_OPS as u32 => BPF_CGROUP_SOCK_OPS,
|
||||||
|
x if x == BPF_SK_SKB_STREAM_PARSER as u32 => BPF_SK_SKB_STREAM_PARSER,
|
||||||
|
x if x == BPF_SK_SKB_STREAM_VERDICT as u32 => BPF_SK_SKB_STREAM_VERDICT,
|
||||||
|
x if x == BPF_CGROUP_DEVICE as u32 => BPF_CGROUP_DEVICE,
|
||||||
|
x if x == BPF_SK_MSG_VERDICT as u32 => BPF_SK_MSG_VERDICT,
|
||||||
|
x if x == BPF_CGROUP_INET4_BIND as u32 => BPF_CGROUP_INET4_BIND,
|
||||||
|
x if x == BPF_CGROUP_INET6_BIND as u32 => BPF_CGROUP_INET6_BIND,
|
||||||
|
x if x == BPF_CGROUP_INET4_CONNECT as u32 => BPF_CGROUP_INET4_CONNECT,
|
||||||
|
x if x == BPF_CGROUP_INET6_CONNECT as u32 => BPF_CGROUP_INET6_CONNECT,
|
||||||
|
x if x == BPF_CGROUP_INET4_POST_BIND as u32 => BPF_CGROUP_INET4_POST_BIND,
|
||||||
|
x if x == BPF_CGROUP_INET6_POST_BIND as u32 => BPF_CGROUP_INET6_POST_BIND,
|
||||||
|
x if x == BPF_CGROUP_UDP4_SENDMSG as u32 => BPF_CGROUP_UDP4_SENDMSG,
|
||||||
|
x if x == BPF_CGROUP_UDP6_SENDMSG as u32 => BPF_CGROUP_UDP6_SENDMSG,
|
||||||
|
x if x == BPF_LIRC_MODE2 as u32 => BPF_LIRC_MODE2,
|
||||||
|
x if x == BPF_FLOW_DISSECTOR as u32 => BPF_FLOW_DISSECTOR,
|
||||||
|
x if x == BPF_CGROUP_SYSCTL as u32 => BPF_CGROUP_SYSCTL,
|
||||||
|
x if x == BPF_CGROUP_UDP4_RECVMSG as u32 => BPF_CGROUP_UDP4_RECVMSG,
|
||||||
|
x if x == BPF_CGROUP_UDP6_RECVMSG as u32 => BPF_CGROUP_UDP6_RECVMSG,
|
||||||
|
x if x == BPF_CGROUP_GETSOCKOPT as u32 => BPF_CGROUP_GETSOCKOPT,
|
||||||
|
x if x == BPF_CGROUP_SETSOCKOPT as u32 => BPF_CGROUP_SETSOCKOPT,
|
||||||
|
x if x == BPF_TRACE_RAW_TP as u32 => BPF_TRACE_RAW_TP,
|
||||||
|
x if x == BPF_TRACE_FENTRY as u32 => BPF_TRACE_FENTRY,
|
||||||
|
x if x == BPF_TRACE_FEXIT as u32 => BPF_TRACE_FEXIT,
|
||||||
|
x if x == BPF_MODIFY_RETURN as u32 => BPF_MODIFY_RETURN,
|
||||||
|
x if x == BPF_LSM_MAC as u32 => BPF_LSM_MAC,
|
||||||
|
x if x == BPF_TRACE_ITER as u32 => BPF_TRACE_ITER,
|
||||||
|
x if x == BPF_CGROUP_INET4_GETPEERNAME as u32 => BPF_CGROUP_INET4_GETPEERNAME,
|
||||||
|
x if x == BPF_CGROUP_INET6_GETPEERNAME as u32 => BPF_CGROUP_INET6_GETPEERNAME,
|
||||||
|
x if x == BPF_CGROUP_INET4_GETSOCKNAME as u32 => BPF_CGROUP_INET4_GETSOCKNAME,
|
||||||
|
x if x == BPF_CGROUP_INET6_GETSOCKNAME as u32 => BPF_CGROUP_INET6_GETSOCKNAME,
|
||||||
|
x if x == BPF_XDP_DEVMAP as u32 => BPF_XDP_DEVMAP,
|
||||||
|
x if x == BPF_CGROUP_INET_SOCK_RELEASE as u32 => BPF_CGROUP_INET_SOCK_RELEASE,
|
||||||
|
x if x == BPF_XDP_CPUMAP as u32 => BPF_XDP_CPUMAP,
|
||||||
|
x if x == BPF_SK_LOOKUP as u32 => BPF_SK_LOOKUP,
|
||||||
|
x if x == BPF_XDP as u32 => BPF_XDP,
|
||||||
|
x if x == BPF_SK_SKB_VERDICT as u32 => BPF_SK_SKB_VERDICT,
|
||||||
|
x if x == BPF_SK_REUSEPORT_SELECT as u32 => BPF_SK_REUSEPORT_SELECT,
|
||||||
|
x if x == BPF_SK_REUSEPORT_SELECT_OR_MIGRATE as u32 => {
|
||||||
|
BPF_SK_REUSEPORT_SELECT_OR_MIGRATE
|
||||||
|
}
|
||||||
|
x if x == BPF_PERF_EVENT as u32 => BPF_PERF_EVENT,
|
||||||
|
x if x == BPF_TRACE_KPROBE_MULTI as u32 => BPF_TRACE_KPROBE_MULTI,
|
||||||
|
x if x == BPF_LSM_CGROUP as u32 => BPF_LSM_CGROUP,
|
||||||
|
x if x == BPF_STRUCT_OPS as u32 => BPF_STRUCT_OPS,
|
||||||
|
x if x == BPF_NETFILTER as u32 => BPF_NETFILTER,
|
||||||
|
x if x == BPF_TCX_INGRESS as u32 => BPF_TCX_INGRESS,
|
||||||
|
x if x == BPF_TCX_EGRESS as u32 => BPF_TCX_EGRESS,
|
||||||
|
x if x == BPF_TRACE_UPROBE_MULTI as u32 => BPF_TRACE_UPROBE_MULTI,
|
||||||
|
x if x == BPF_CGROUP_UNIX_CONNECT as u32 => BPF_CGROUP_UNIX_CONNECT,
|
||||||
|
x if x == BPF_CGROUP_UNIX_SENDMSG as u32 => BPF_CGROUP_UNIX_SENDMSG,
|
||||||
|
x if x == BPF_CGROUP_UNIX_RECVMSG as u32 => BPF_CGROUP_UNIX_RECVMSG,
|
||||||
|
x if x == BPF_CGROUP_UNIX_GETPEERNAME as u32 => BPF_CGROUP_UNIX_GETPEERNAME,
|
||||||
|
x if x == BPF_CGROUP_UNIX_GETSOCKNAME as u32 => BPF_CGROUP_UNIX_GETSOCKNAME,
|
||||||
|
x if x == BPF_NETKIT_PRIMARY as u32 => BPF_NETKIT_PRIMARY,
|
||||||
|
x if x == BPF_NETKIT_PEER as u32 => BPF_NETKIT_PEER,
|
||||||
|
_ => return Err(InvalidTypeBinding { value: attach_type }),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,51 @@
|
|||||||
|
//! Program type bindings.
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
generated::bpf_prog_type::{self, *},
|
||||||
|
InvalidTypeBinding,
|
||||||
|
};
|
||||||
|
|
||||||
|
impl TryFrom<u32> for bpf_prog_type {
|
||||||
|
type Error = InvalidTypeBinding<u32>;
|
||||||
|
|
||||||
|
fn try_from(prog_type: u32) -> Result<Self, Self::Error> {
|
||||||
|
Ok(match prog_type {
|
||||||
|
x if x == BPF_PROG_TYPE_UNSPEC as u32 => BPF_PROG_TYPE_UNSPEC,
|
||||||
|
x if x == BPF_PROG_TYPE_SOCKET_FILTER as u32 => BPF_PROG_TYPE_SOCKET_FILTER,
|
||||||
|
x if x == BPF_PROG_TYPE_KPROBE as u32 => BPF_PROG_TYPE_KPROBE,
|
||||||
|
x if x == BPF_PROG_TYPE_SCHED_CLS as u32 => BPF_PROG_TYPE_SCHED_CLS,
|
||||||
|
x if x == BPF_PROG_TYPE_SCHED_ACT as u32 => BPF_PROG_TYPE_SCHED_ACT,
|
||||||
|
x if x == BPF_PROG_TYPE_TRACEPOINT as u32 => BPF_PROG_TYPE_TRACEPOINT,
|
||||||
|
x if x == BPF_PROG_TYPE_XDP as u32 => BPF_PROG_TYPE_XDP,
|
||||||
|
x if x == BPF_PROG_TYPE_PERF_EVENT as u32 => BPF_PROG_TYPE_PERF_EVENT,
|
||||||
|
x if x == BPF_PROG_TYPE_CGROUP_SKB as u32 => BPF_PROG_TYPE_CGROUP_SKB,
|
||||||
|
x if x == BPF_PROG_TYPE_CGROUP_SOCK as u32 => BPF_PROG_TYPE_CGROUP_SOCK,
|
||||||
|
x if x == BPF_PROG_TYPE_LWT_IN as u32 => BPF_PROG_TYPE_LWT_IN,
|
||||||
|
x if x == BPF_PROG_TYPE_LWT_OUT as u32 => BPF_PROG_TYPE_LWT_OUT,
|
||||||
|
x if x == BPF_PROG_TYPE_LWT_XMIT as u32 => BPF_PROG_TYPE_LWT_XMIT,
|
||||||
|
x if x == BPF_PROG_TYPE_SOCK_OPS as u32 => BPF_PROG_TYPE_SOCK_OPS,
|
||||||
|
x if x == BPF_PROG_TYPE_SK_SKB as u32 => BPF_PROG_TYPE_SK_SKB,
|
||||||
|
x if x == BPF_PROG_TYPE_CGROUP_DEVICE as u32 => BPF_PROG_TYPE_CGROUP_DEVICE,
|
||||||
|
x if x == BPF_PROG_TYPE_SK_MSG as u32 => BPF_PROG_TYPE_SK_MSG,
|
||||||
|
x if x == BPF_PROG_TYPE_RAW_TRACEPOINT as u32 => BPF_PROG_TYPE_RAW_TRACEPOINT,
|
||||||
|
x if x == BPF_PROG_TYPE_CGROUP_SOCK_ADDR as u32 => BPF_PROG_TYPE_CGROUP_SOCK_ADDR,
|
||||||
|
x if x == BPF_PROG_TYPE_LWT_SEG6LOCAL as u32 => BPF_PROG_TYPE_LWT_SEG6LOCAL,
|
||||||
|
x if x == BPF_PROG_TYPE_LIRC_MODE2 as u32 => BPF_PROG_TYPE_LIRC_MODE2,
|
||||||
|
x if x == BPF_PROG_TYPE_SK_REUSEPORT as u32 => BPF_PROG_TYPE_SK_REUSEPORT,
|
||||||
|
x if x == BPF_PROG_TYPE_FLOW_DISSECTOR as u32 => BPF_PROG_TYPE_FLOW_DISSECTOR,
|
||||||
|
x if x == BPF_PROG_TYPE_CGROUP_SYSCTL as u32 => BPF_PROG_TYPE_CGROUP_SYSCTL,
|
||||||
|
x if x == BPF_PROG_TYPE_RAW_TRACEPOINT_WRITABLE as u32 => {
|
||||||
|
BPF_PROG_TYPE_RAW_TRACEPOINT_WRITABLE
|
||||||
|
}
|
||||||
|
x if x == BPF_PROG_TYPE_CGROUP_SOCKOPT as u32 => BPF_PROG_TYPE_CGROUP_SOCKOPT,
|
||||||
|
x if x == BPF_PROG_TYPE_TRACING as u32 => BPF_PROG_TYPE_TRACING,
|
||||||
|
x if x == BPF_PROG_TYPE_STRUCT_OPS as u32 => BPF_PROG_TYPE_STRUCT_OPS,
|
||||||
|
x if x == BPF_PROG_TYPE_EXT as u32 => BPF_PROG_TYPE_EXT,
|
||||||
|
x if x == BPF_PROG_TYPE_LSM as u32 => BPF_PROG_TYPE_LSM,
|
||||||
|
x if x == BPF_PROG_TYPE_SK_LOOKUP as u32 => BPF_PROG_TYPE_SK_LOOKUP,
|
||||||
|
x if x == BPF_PROG_TYPE_SYSCALL as u32 => BPF_PROG_TYPE_SYSCALL,
|
||||||
|
x if x == BPF_PROG_TYPE_NETFILTER as u32 => BPF_PROG_TYPE_NETFILTER,
|
||||||
|
_ => return Err(InvalidTypeBinding { value: prog_type }),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,413 @@
|
|||||||
|
//! Metadata information about an eBPF map.
|
||||||
|
|
||||||
|
use std::{
|
||||||
|
ffi::CString,
|
||||||
|
num::NonZeroU32,
|
||||||
|
os::fd::{AsFd as _, BorrowedFd},
|
||||||
|
path::Path,
|
||||||
|
};
|
||||||
|
|
||||||
|
use aya_obj::generated::{bpf_map_info, bpf_map_type};
|
||||||
|
|
||||||
|
use super::{MapError, MapFd};
|
||||||
|
use crate::{
|
||||||
|
sys::{
|
||||||
|
bpf_get_object, bpf_map_get_fd_by_id, bpf_map_get_info_by_fd, iter_map_ids, SyscallError,
|
||||||
|
},
|
||||||
|
util::bytes_of_bpf_name,
|
||||||
|
FEATURES,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Provides Provides metadata information about a loaded eBPF map.
|
||||||
|
#[doc(alias = "bpf_map_info")]
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct MapInfo(pub(crate) bpf_map_info);
|
||||||
|
|
||||||
|
impl MapInfo {
|
||||||
|
pub(crate) fn new_from_fd(fd: BorrowedFd<'_>) -> Result<Self, MapError> {
|
||||||
|
let info = bpf_map_get_info_by_fd(fd.as_fd())?;
|
||||||
|
Ok(Self(info))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Loads map info from a map ID.
|
||||||
|
///
|
||||||
|
/// Uses kernel v4.13 features.
|
||||||
|
pub fn from_id(id: u32) -> Result<Self, MapError> {
|
||||||
|
bpf_map_get_fd_by_id(id)
|
||||||
|
.map_err(MapError::from)
|
||||||
|
.and_then(|fd| Self::new_from_fd(fd.as_fd()))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The type of map.
|
||||||
|
///
|
||||||
|
/// Introduced in kernel v4.13.
|
||||||
|
pub fn map_type(&self) -> Result<MapType, MapError> {
|
||||||
|
bpf_map_type::try_from(self.0.type_)
|
||||||
|
.unwrap_or(bpf_map_type::__MAX_BPF_MAP_TYPE)
|
||||||
|
.try_into()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The unique ID for this map.
|
||||||
|
///
|
||||||
|
/// `None` is returned if the field is not available.
|
||||||
|
///
|
||||||
|
/// Introduced in kernel v4.13.
|
||||||
|
pub fn id(&self) -> Option<NonZeroU32> {
|
||||||
|
NonZeroU32::new(self.0.id)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The key size for this map in bytes.
|
||||||
|
///
|
||||||
|
/// `None` is returned if the field is not available.
|
||||||
|
///
|
||||||
|
/// Introduced in kernel v4.13.
|
||||||
|
pub fn key_size(&self) -> Option<NonZeroU32> {
|
||||||
|
NonZeroU32::new(self.0.key_size)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The value size for this map in bytes.
|
||||||
|
///
|
||||||
|
/// `None` is returned if the field is not available.
|
||||||
|
///
|
||||||
|
/// Introduced in kernel v4.13.
|
||||||
|
pub fn value_size(&self) -> Option<NonZeroU32> {
|
||||||
|
NonZeroU32::new(self.0.value_size)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The maximum number of entries in this map.
|
||||||
|
///
|
||||||
|
/// `None` is returned if the field is not available.
|
||||||
|
///
|
||||||
|
/// Introduced in kernel v4.13.
|
||||||
|
pub fn max_entries(&self) -> Option<NonZeroU32> {
|
||||||
|
NonZeroU32::new(self.0.max_entries)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The flags used in loading this map.
|
||||||
|
///
|
||||||
|
/// Introduced in kernel v4.13.
|
||||||
|
pub fn map_flags(&self) -> u32 {
|
||||||
|
self.0.map_flags
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The name of the map, limited to 16 bytes.
|
||||||
|
///
|
||||||
|
/// Introduced in kernel v4.15.
|
||||||
|
pub fn name(&self) -> &[u8] {
|
||||||
|
bytes_of_bpf_name(&self.0.name)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The name of the map as a &str.
|
||||||
|
///
|
||||||
|
/// `None` is returned if the name was not valid unicode or if field is not available.
|
||||||
|
///
|
||||||
|
/// Introduced in kernel v4.15.
|
||||||
|
pub fn name_as_str(&self) -> Option<&str> {
|
||||||
|
let name = std::str::from_utf8(self.name()).ok();
|
||||||
|
if let Some(name_str) = name {
|
||||||
|
// Char in program name was introduced in the same commit as map name
|
||||||
|
if FEATURES.bpf_name() || !name_str.is_empty() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns a file descriptor referencing the map.
|
||||||
|
///
|
||||||
|
/// The returned file descriptor can be closed at any time and doing so does
|
||||||
|
/// not influence the life cycle of the map.
|
||||||
|
///
|
||||||
|
/// Uses kernel v4.13 features.
|
||||||
|
pub fn fd(&self) -> Result<MapFd, MapError> {
|
||||||
|
let Self(info) = self;
|
||||||
|
let fd = bpf_map_get_fd_by_id(info.id)?;
|
||||||
|
Ok(MapFd::from_fd(fd))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Loads a map from a pinned path in bpffs.
|
||||||
|
///
|
||||||
|
/// Uses kernel v4.4 and v4.13 features.
|
||||||
|
pub fn from_pin<P: AsRef<Path>>(path: P) -> Result<Self, MapError> {
|
||||||
|
use std::os::unix::ffi::OsStrExt as _;
|
||||||
|
|
||||||
|
// TODO: avoid this unwrap by adding a new error variant.
|
||||||
|
let path_string = CString::new(path.as_ref().as_os_str().as_bytes()).unwrap();
|
||||||
|
let fd = bpf_get_object(&path_string).map_err(|(_, io_error)| SyscallError {
|
||||||
|
call: "BPF_OBJ_GET",
|
||||||
|
io_error,
|
||||||
|
})?;
|
||||||
|
|
||||||
|
Self::new_from_fd(fd.as_fd())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns an iterator of [`MapInfo`] over all eBPF maps on the host.
|
||||||
|
///
|
||||||
|
/// Unlike [`Ebpf::maps`](crate::Ebpf::maps), this includes all maps on the host system, not
|
||||||
|
/// just those tied to a specific [`crate::Ebpf`] instance.
|
||||||
|
///
|
||||||
|
/// Uses kernel v4.13 features.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
/// ```
|
||||||
|
/// # use aya::maps::loaded_maps;
|
||||||
|
/// #
|
||||||
|
/// for m in loaded_maps() {
|
||||||
|
/// match m {
|
||||||
|
/// Ok(map) => println!("{:?}", map.name_as_str()),
|
||||||
|
/// Err(e) => println!("Error iterating maps: {:?}", e),
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// # Errors
|
||||||
|
///
|
||||||
|
/// Returns [`MapError::SyscallError`] if any of the syscalls required to either get
|
||||||
|
/// next map id, get the map fd, or the [`MapInfo`] fail.
|
||||||
|
///
|
||||||
|
/// In cases where iteration can't be performed, for example the caller does not have the necessary
|
||||||
|
/// privileges, a single item will be yielded containing the error that occurred.
|
||||||
|
pub fn loaded_maps() -> impl Iterator<Item = Result<MapInfo, MapError>> {
|
||||||
|
iter_map_ids().map(|id| {
|
||||||
|
let id = id?;
|
||||||
|
MapInfo::from_id(id)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The type of eBPF map.
|
||||||
|
#[non_exhaustive]
|
||||||
|
#[doc(alias = "bpf_map_type")]
|
||||||
|
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||||
|
pub enum MapType {
|
||||||
|
/// An unspecified program type.
|
||||||
|
Unspecified = bpf_map_type::BPF_MAP_TYPE_UNSPEC as isize,
|
||||||
|
/// A Hash map type. See [`HashMap`](super::hash_map::HashMap) for the map implementation.
|
||||||
|
///
|
||||||
|
/// Introduced in kernel v3.19.
|
||||||
|
#[doc(alias = "BPF_MAP_TYPE_HASH")]
|
||||||
|
Hash = bpf_map_type::BPF_MAP_TYPE_HASH as isize,
|
||||||
|
/// An Array map type. See [`Array`](super::array::Array) for the map implementation.
|
||||||
|
///
|
||||||
|
/// Introduced in kernel v3.19.
|
||||||
|
#[doc(alias = "BPF_MAP_TYPE_ARRAY")]
|
||||||
|
Array = bpf_map_type::BPF_MAP_TYPE_ARRAY as isize,
|
||||||
|
/// A Program Array map type. See [`ProgramArray`](super::array::ProgramArray) for the map
|
||||||
|
/// implementation.
|
||||||
|
///
|
||||||
|
/// Introduced in kernel v4.2.
|
||||||
|
#[doc(alias = "BPF_MAP_TYPE_PROG_ARRAY")]
|
||||||
|
ProgramArray = bpf_map_type::BPF_MAP_TYPE_PROG_ARRAY as isize,
|
||||||
|
/// A Perf Event Array map type. See [`PerfEventArray`](super::perf::PerfEventArray) and
|
||||||
|
/// [`AsyncPerfEventArray`](super::perf::AsyncPerfEventArray) for the map implementations.
|
||||||
|
///
|
||||||
|
/// Introduced in kernel v4.3.
|
||||||
|
#[doc(alias = "BPF_MAP_TYPE_PERF_EVENT_ARRAY")]
|
||||||
|
PerfEventArray = bpf_map_type::BPF_MAP_TYPE_PERF_EVENT_ARRAY as isize,
|
||||||
|
/// A per-CPU Hash map type. See [`PerCpuHashMap`](super::hash_map::PerCpuHashMap) for the map
|
||||||
|
/// implementation.
|
||||||
|
///
|
||||||
|
/// Introduced in kernel v4.6.
|
||||||
|
#[doc(alias = "BPF_MAP_TYPE_PERCPU_HASH")]
|
||||||
|
PerCpuHash = bpf_map_type::BPF_MAP_TYPE_PERCPU_HASH as isize,
|
||||||
|
/// A per-CPU Array map type. See [`PerCpuArray`](super::array::PerCpuArray) for the map
|
||||||
|
/// implementation.
|
||||||
|
///
|
||||||
|
/// Introduced in kernel v4.6.
|
||||||
|
#[doc(alias = "BPF_MAP_TYPE_PERCPU_ARRAY")]
|
||||||
|
PerCpuArray = bpf_map_type::BPF_MAP_TYPE_PERCPU_ARRAY as isize,
|
||||||
|
/// A Stack Trace map type. See [`StackTraceMap`](super::stack_trace::StackTraceMap) for the map
|
||||||
|
/// implementation.
|
||||||
|
///
|
||||||
|
/// Introduced in kernel v4.6.
|
||||||
|
#[doc(alias = "BPF_MAP_TYPE_STACK_TRACE")]
|
||||||
|
StackTrace = bpf_map_type::BPF_MAP_TYPE_STACK_TRACE as isize,
|
||||||
|
/// A cGroup Array map type.
|
||||||
|
///
|
||||||
|
/// Introduced in kernel v4.8.
|
||||||
|
#[doc(alias = "BPF_MAP_TYPE_CGROUP_ARRAY")]
|
||||||
|
CgroupArray = bpf_map_type::BPF_MAP_TYPE_CGROUP_ARRAY as isize,
|
||||||
|
/// A Least Recently Used (LRU) Hash map type. See [`HashMap`](super::hash_map::HashMap) for
|
||||||
|
/// the map implementation.
|
||||||
|
///
|
||||||
|
/// Introduced in kernel v4.10.
|
||||||
|
#[doc(alias = "BPF_MAP_TYPE_LRU_HASH")]
|
||||||
|
LruHash = bpf_map_type::BPF_MAP_TYPE_LRU_HASH as isize,
|
||||||
|
/// A Least Recently Used (LRU) per-CPU Hash map type. See
|
||||||
|
/// [`PerCpuHashMap`](super::hash_map::PerCpuHashMap) for the map implementation.
|
||||||
|
///
|
||||||
|
/// Introduced in kernel v4.10.
|
||||||
|
#[doc(alias = "BPF_MAP_TYPE_LRU_PERCPU_HASH")]
|
||||||
|
LruPerCpuHash = bpf_map_type::BPF_MAP_TYPE_LRU_PERCPU_HASH as isize,
|
||||||
|
/// A Longest Prefix Match (LPM) Trie map type. See [`LpmTrie`](super::lpm_trie::LpmTrie) for
|
||||||
|
/// the map implementation.
|
||||||
|
///
|
||||||
|
/// Introduced in kernel v4.11.
|
||||||
|
#[doc(alias = "BPF_MAP_TYPE_LPM_TRIE")]
|
||||||
|
LpmTrie = bpf_map_type::BPF_MAP_TYPE_LPM_TRIE as isize,
|
||||||
|
/// An Array of Maps map type.
|
||||||
|
///
|
||||||
|
/// Introduced in kernel v4.12.
|
||||||
|
#[doc(alias = "BPF_MAP_TYPE_ARRAY_OF_MAPS")]
|
||||||
|
ArrayOfMaps = bpf_map_type::BPF_MAP_TYPE_ARRAY_OF_MAPS as isize,
|
||||||
|
/// A Hash of Maps map type.
|
||||||
|
///
|
||||||
|
/// Introduced in kernel v4.12.
|
||||||
|
#[doc(alias = "BPF_MAP_TYPE_HASH_OF_MAPS")]
|
||||||
|
HashOfMaps = bpf_map_type::BPF_MAP_TYPE_HASH_OF_MAPS as isize,
|
||||||
|
/// A Device Map type. See [`DevMap`](super::xdp::DevMap) for the map implementation.
|
||||||
|
///
|
||||||
|
/// Introduced in kernel v4.14.
|
||||||
|
#[doc(alias = "BPF_MAP_TYPE_DEVMAP")]
|
||||||
|
DevMap = bpf_map_type::BPF_MAP_TYPE_DEVMAP as isize,
|
||||||
|
/// A Socket Map type. See [`SockMap`](super::sock::SockMap) for the map implementation.
|
||||||
|
///
|
||||||
|
/// Introduced in kernel v4.14.
|
||||||
|
#[doc(alias = "BPF_MAP_TYPE_SOCKMAP")]
|
||||||
|
SockMap = bpf_map_type::BPF_MAP_TYPE_SOCKMAP as isize,
|
||||||
|
/// A CPU Map type. See [`CpuMap`](super::xdp::CpuMap) for the map implementation.
|
||||||
|
///
|
||||||
|
/// Introduced in kernel v4.15.
|
||||||
|
#[doc(alias = "BPF_MAP_TYPE_CPUMAP")]
|
||||||
|
CpuMap = bpf_map_type::BPF_MAP_TYPE_CPUMAP as isize,
|
||||||
|
/// An XDP Socket Map type. See [`XskMap`](super::xdp::XskMap) for the map implementation.
|
||||||
|
///
|
||||||
|
/// Introduced in kernel v4.18.
|
||||||
|
#[doc(alias = "BPF_MAP_TYPE_XSKMAP")]
|
||||||
|
XskMap = bpf_map_type::BPF_MAP_TYPE_XSKMAP as isize,
|
||||||
|
/// A Socket Hash map type. See [`SockHash`](super::sock::SockHash) for the map implementation.
|
||||||
|
///
|
||||||
|
/// Introduced in kernel v4.18.
|
||||||
|
#[doc(alias = "BPF_MAP_TYPE_SOCKHASH")]
|
||||||
|
SockHash = bpf_map_type::BPF_MAP_TYPE_SOCKHASH as isize,
|
||||||
|
/// A cGroup Storage map type.
|
||||||
|
///
|
||||||
|
/// Introduced in kernel v4.19.
|
||||||
|
// #[deprecated]
|
||||||
|
#[doc(alias = "BPF_MAP_TYPE_CGROUP_STORAGE")]
|
||||||
|
#[doc(alias = "BPF_MAP_TYPE_CGROUP_STORAGE_DEPRECATED")]
|
||||||
|
CgroupStorage = bpf_map_type::BPF_MAP_TYPE_CGROUP_STORAGE as isize,
|
||||||
|
/// A Reuseport Socket Array map type.
|
||||||
|
///
|
||||||
|
/// Introduced in kernel v4.19.
|
||||||
|
#[doc(alias = "BPF_MAP_TYPE_REUSEPORT_SOCKARRAY")]
|
||||||
|
ReuseportSockArray = bpf_map_type::BPF_MAP_TYPE_REUSEPORT_SOCKARRAY as isize,
|
||||||
|
/// A per-CPU cGroup Storage map type.
|
||||||
|
///
|
||||||
|
/// Introduced in kernel v4.20.
|
||||||
|
#[doc(alias = "BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE")]
|
||||||
|
#[doc(alias = "BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE_DEPRECATED")]
|
||||||
|
PerCpuCgroupStorage = bpf_map_type::BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE as isize,
|
||||||
|
/// A Queue map type. See [`Queue`](super::queue::Queue) for the map implementation.
|
||||||
|
///
|
||||||
|
/// Introduced in kernel v4.20.
|
||||||
|
#[doc(alias = "BPF_MAP_TYPE_QUEUE")]
|
||||||
|
Queue = bpf_map_type::BPF_MAP_TYPE_QUEUE as isize,
|
||||||
|
/// A Stack map type. See [`Stack`](super::stack::Stack) for the map implementation.
|
||||||
|
///
|
||||||
|
/// Introduced in kernel v4.20.
|
||||||
|
#[doc(alias = "BPF_MAP_TYPE_STACK")]
|
||||||
|
Stack = bpf_map_type::BPF_MAP_TYPE_STACK as isize,
|
||||||
|
/// A Socket-local Storage map type.
|
||||||
|
///
|
||||||
|
/// Introduced in kernel v5.2.
|
||||||
|
#[doc(alias = "BPF_MAP_TYPE_SK_STORAGE")]
|
||||||
|
SkStorage = bpf_map_type::BPF_MAP_TYPE_SK_STORAGE as isize,
|
||||||
|
/// A Device Hash Map type. See [`DevMapHash`](super::xdp::DevMapHash) for the map
|
||||||
|
/// implementation.
|
||||||
|
///
|
||||||
|
/// Introduced in kernel v5.4.
|
||||||
|
#[doc(alias = "BPF_MAP_TYPE_DEVMAP_HASH")]
|
||||||
|
DevMapHash = bpf_map_type::BPF_MAP_TYPE_DEVMAP_HASH as isize,
|
||||||
|
/// A Struct Ops map type.
|
||||||
|
///
|
||||||
|
/// Introduced in kernel v5.6.
|
||||||
|
#[doc(alias = "BPF_MAP_TYPE_STRUCT_OPS")]
|
||||||
|
StructOps = bpf_map_type::BPF_MAP_TYPE_STRUCT_OPS as isize,
|
||||||
|
/// A Ring Buffer map type. See [`RingBuf`](super::ring_buf::RingBuf) for the map
|
||||||
|
/// implementation.
|
||||||
|
///
|
||||||
|
/// Introduced in kernel v5.8.
|
||||||
|
#[doc(alias = "BPF_MAP_TYPE_RINGBUF")]
|
||||||
|
RingBuf = bpf_map_type::BPF_MAP_TYPE_RINGBUF as isize,
|
||||||
|
/// An Inode Storage map type.
|
||||||
|
///
|
||||||
|
/// Introduced in kernel v5.10.
|
||||||
|
#[doc(alias = "BPF_MAP_TYPE_INODE_STORAGE")]
|
||||||
|
InodeStorage = bpf_map_type::BPF_MAP_TYPE_INODE_STORAGE as isize,
|
||||||
|
/// A Task Storage map type.
|
||||||
|
///
|
||||||
|
/// Introduced in kernel v5.11.
|
||||||
|
#[doc(alias = "BPF_MAP_TYPE_TASK_STORAGE")]
|
||||||
|
TaskStorage = bpf_map_type::BPF_MAP_TYPE_TASK_STORAGE as isize,
|
||||||
|
/// A Bloom Filter map type. See [`BloomFilter`](super::bloom_filter::BloomFilter) for the map
|
||||||
|
/// implementation.
|
||||||
|
///
|
||||||
|
/// Introduced in kernel v5.16.
|
||||||
|
#[doc(alias = "BPF_MAP_TYPE_BLOOM_FILTER")]
|
||||||
|
BloomFilter = bpf_map_type::BPF_MAP_TYPE_BLOOM_FILTER as isize,
|
||||||
|
/// A User Ring Buffer map type.
|
||||||
|
///
|
||||||
|
/// Introduced in kernel v6.1.
|
||||||
|
#[doc(alias = "BPF_MAP_TYPE_USER_RINGBUF")]
|
||||||
|
UserRingBuf = bpf_map_type::BPF_MAP_TYPE_USER_RINGBUF as isize,
|
||||||
|
/// A cGroup Storage map type.
|
||||||
|
///
|
||||||
|
/// Introduced in kernel v6.2.
|
||||||
|
#[doc(alias = "BPF_MAP_TYPE_CGRP_STORAGE")]
|
||||||
|
CgrpStorage = bpf_map_type::BPF_MAP_TYPE_CGRP_STORAGE as isize,
|
||||||
|
/// An Arena map type.
|
||||||
|
///
|
||||||
|
/// Introduced in kernel v6.9.
|
||||||
|
#[doc(alias = "BPF_MAP_TYPE_ARENA")]
|
||||||
|
Arena = bpf_map_type::BPF_MAP_TYPE_ARENA as isize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryFrom<bpf_map_type> for MapType {
|
||||||
|
type Error = MapError;
|
||||||
|
|
||||||
|
fn try_from(map_type: bpf_map_type) -> Result<Self, Self::Error> {
|
||||||
|
use bpf_map_type::*;
|
||||||
|
Ok(match map_type {
|
||||||
|
BPF_MAP_TYPE_UNSPEC => Self::Unspecified,
|
||||||
|
BPF_MAP_TYPE_HASH => Self::Hash,
|
||||||
|
BPF_MAP_TYPE_ARRAY => Self::Array,
|
||||||
|
BPF_MAP_TYPE_PROG_ARRAY => Self::ProgramArray,
|
||||||
|
BPF_MAP_TYPE_PERF_EVENT_ARRAY => Self::PerfEventArray,
|
||||||
|
BPF_MAP_TYPE_PERCPU_HASH => Self::PerCpuHash,
|
||||||
|
BPF_MAP_TYPE_PERCPU_ARRAY => Self::PerCpuArray,
|
||||||
|
BPF_MAP_TYPE_STACK_TRACE => Self::StackTrace,
|
||||||
|
BPF_MAP_TYPE_CGROUP_ARRAY => Self::CgroupArray,
|
||||||
|
BPF_MAP_TYPE_LRU_HASH => Self::LruHash,
|
||||||
|
BPF_MAP_TYPE_LRU_PERCPU_HASH => Self::LruPerCpuHash,
|
||||||
|
BPF_MAP_TYPE_LPM_TRIE => Self::LpmTrie,
|
||||||
|
BPF_MAP_TYPE_ARRAY_OF_MAPS => Self::ArrayOfMaps,
|
||||||
|
BPF_MAP_TYPE_HASH_OF_MAPS => Self::HashOfMaps,
|
||||||
|
BPF_MAP_TYPE_DEVMAP => Self::DevMap,
|
||||||
|
BPF_MAP_TYPE_SOCKMAP => Self::SockMap,
|
||||||
|
BPF_MAP_TYPE_CPUMAP => Self::CpuMap,
|
||||||
|
BPF_MAP_TYPE_XSKMAP => Self::XskMap,
|
||||||
|
BPF_MAP_TYPE_SOCKHASH => Self::SockHash,
|
||||||
|
BPF_MAP_TYPE_CGROUP_STORAGE_DEPRECATED => Self::CgroupStorage,
|
||||||
|
BPF_MAP_TYPE_REUSEPORT_SOCKARRAY => Self::ReuseportSockArray,
|
||||||
|
BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE_DEPRECATED => Self::PerCpuCgroupStorage,
|
||||||
|
BPF_MAP_TYPE_QUEUE => Self::Queue,
|
||||||
|
BPF_MAP_TYPE_STACK => Self::Stack,
|
||||||
|
BPF_MAP_TYPE_SK_STORAGE => Self::SkStorage,
|
||||||
|
BPF_MAP_TYPE_DEVMAP_HASH => Self::DevMapHash,
|
||||||
|
BPF_MAP_TYPE_STRUCT_OPS => Self::StructOps,
|
||||||
|
BPF_MAP_TYPE_RINGBUF => Self::RingBuf,
|
||||||
|
BPF_MAP_TYPE_INODE_STORAGE => Self::InodeStorage,
|
||||||
|
BPF_MAP_TYPE_TASK_STORAGE => Self::TaskStorage,
|
||||||
|
BPF_MAP_TYPE_BLOOM_FILTER => Self::BloomFilter,
|
||||||
|
BPF_MAP_TYPE_USER_RINGBUF => Self::UserRingBuf,
|
||||||
|
BPF_MAP_TYPE_CGRP_STORAGE => Self::CgrpStorage,
|
||||||
|
BPF_MAP_TYPE_ARENA => Self::Arena,
|
||||||
|
__MAX_BPF_MAP_TYPE => {
|
||||||
|
return Err(MapError::InvalidMapType {
|
||||||
|
map_type: map_type as u32,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,548 @@
|
|||||||
|
//! Metadata information about an eBPF program.
|
||||||
|
|
||||||
|
use std::{
|
||||||
|
ffi::CString,
|
||||||
|
num::{NonZeroU32, NonZeroU64},
|
||||||
|
os::fd::{AsFd as _, BorrowedFd},
|
||||||
|
path::Path,
|
||||||
|
time::{Duration, SystemTime},
|
||||||
|
};
|
||||||
|
|
||||||
|
use aya_obj::generated::{bpf_prog_info, bpf_prog_type};
|
||||||
|
|
||||||
|
use super::{
|
||||||
|
utils::{boot_time, get_fdinfo},
|
||||||
|
ProgramError, ProgramFd,
|
||||||
|
};
|
||||||
|
use crate::{
|
||||||
|
sys::{
|
||||||
|
bpf_get_object, bpf_prog_get_fd_by_id, bpf_prog_get_info_by_fd, iter_prog_ids, SyscallError,
|
||||||
|
},
|
||||||
|
util::bytes_of_bpf_name,
|
||||||
|
FEATURES,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Provides metadata information about a loaded eBPF program.
|
||||||
|
///
|
||||||
|
/// Introduced in kernel v4.13.
|
||||||
|
#[doc(alias = "bpf_prog_info")]
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct ProgramInfo(pub(crate) bpf_prog_info);
|
||||||
|
|
||||||
|
impl ProgramInfo {
|
||||||
|
pub(crate) fn new_from_fd(fd: BorrowedFd<'_>) -> Result<Self, ProgramError> {
|
||||||
|
let info = bpf_prog_get_info_by_fd(fd, &mut [])?;
|
||||||
|
Ok(Self(info))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The type of program.
|
||||||
|
///
|
||||||
|
/// Introduced in kernel v4.13.
|
||||||
|
pub fn program_type(&self) -> Result<ProgramType, ProgramError> {
|
||||||
|
bpf_prog_type::try_from(self.0.type_)
|
||||||
|
.unwrap_or(bpf_prog_type::__MAX_BPF_PROG_TYPE)
|
||||||
|
.try_into()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The unique ID for this program.
|
||||||
|
///
|
||||||
|
/// `None` is returned if the field is not available.
|
||||||
|
///
|
||||||
|
/// Introduced in kernel v4.13.
|
||||||
|
pub fn id(&self) -> Option<NonZeroU32> {
|
||||||
|
NonZeroU32::new(self.0.id)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The program tag.
|
||||||
|
///
|
||||||
|
/// The tag is a SHA sum of the program's instructions which be used as an alternative to
|
||||||
|
/// [`Self::id()`]. A program's ID can vary every time it's loaded or unloaded, but the tag
|
||||||
|
/// will remain the same.
|
||||||
|
///
|
||||||
|
/// `None` is returned if the field is not available.
|
||||||
|
///
|
||||||
|
/// Introduced in kernel v4.13.
|
||||||
|
pub fn tag(&self) -> Option<NonZeroU64> {
|
||||||
|
NonZeroU64::new(u64::from_be_bytes(self.0.tag))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The size in bytes of the program's JIT-compiled machine code.
|
||||||
|
///
|
||||||
|
/// Note that this field is only updated when BPF JIT compiler is enabled. Kernels v4.15 and
|
||||||
|
/// above may already have it enabled by default.
|
||||||
|
///
|
||||||
|
/// `None` is returned if the field is not available, or if the JIT compiler is not enabled.
|
||||||
|
///
|
||||||
|
/// Introduced in kernel v4.13.
|
||||||
|
pub fn size_jitted(&self) -> Option<NonZeroU32> {
|
||||||
|
NonZeroU32::new(self.0.jited_prog_len)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The size in bytes of the program's translated eBPF bytecode.
|
||||||
|
///
|
||||||
|
/// The translated bytecode is after it has been passed though the verifier where it was
|
||||||
|
/// possibly modified by the kernel.
|
||||||
|
///
|
||||||
|
/// `None` is returned if the field is not available.
|
||||||
|
///
|
||||||
|
/// Introduced in kernel v4.15.
|
||||||
|
pub fn size_translated(&self) -> Option<NonZeroU32> {
|
||||||
|
NonZeroU32::new(self.0.xlated_prog_len)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The time when the program was loaded.
|
||||||
|
///
|
||||||
|
/// `None` is returned if the field is not available.
|
||||||
|
///
|
||||||
|
/// Introduced in kernel v4.15.
|
||||||
|
pub fn loaded_at(&self) -> Option<SystemTime> {
|
||||||
|
if self.0.load_time > 0 {
|
||||||
|
Some(boot_time() + Duration::from_nanos(self.0.load_time))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The user ID of the process who loaded the program.
|
||||||
|
///
|
||||||
|
/// `None` is returned if the field is not available.
|
||||||
|
///
|
||||||
|
/// Introduced in kernel v4.15.
|
||||||
|
pub fn created_by_uid(&self) -> Option<u32> {
|
||||||
|
// This field was introduced in the same commit as `load_time`.
|
||||||
|
if self.0.load_time > 0 {
|
||||||
|
Some(self.0.created_by_uid)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The IDs of the maps used by the program.
|
||||||
|
///
|
||||||
|
/// `None` is returned if the field is not available.
|
||||||
|
///
|
||||||
|
/// Introduced in kernel v4.15.
|
||||||
|
pub fn map_ids(&self) -> Result<Option<Vec<NonZeroU32>>, ProgramError> {
|
||||||
|
if FEATURES.prog_info_map_ids() {
|
||||||
|
let mut map_ids = vec![0u32; self.0.nr_map_ids as usize];
|
||||||
|
bpf_prog_get_info_by_fd(self.fd()?.as_fd(), &mut map_ids)?;
|
||||||
|
|
||||||
|
Ok(Some(
|
||||||
|
map_ids
|
||||||
|
.into_iter()
|
||||||
|
.map(|id| NonZeroU32::new(id).unwrap())
|
||||||
|
.collect(),
|
||||||
|
))
|
||||||
|
} else {
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The name of the program as was provided when it was load. This is limited to 16 bytes.
|
||||||
|
///
|
||||||
|
/// Introduced in kernel v4.15.
|
||||||
|
pub fn name(&self) -> &[u8] {
|
||||||
|
bytes_of_bpf_name(&self.0.name)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The name of the program as a &str.
|
||||||
|
///
|
||||||
|
/// `None` is returned if the name was not valid unicode or if field is not available.
|
||||||
|
///
|
||||||
|
/// Introduced in kernel v4.15.
|
||||||
|
pub fn name_as_str(&self) -> Option<&str> {
|
||||||
|
let name = std::str::from_utf8(self.name()).ok();
|
||||||
|
if let Some(name_str) = name {
|
||||||
|
if FEATURES.bpf_name() || !name_str.is_empty() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns true if the program is defined with a GPL-compatible license.
|
||||||
|
///
|
||||||
|
/// `None` is returned if the field is not available.
|
||||||
|
///
|
||||||
|
/// Introduced in kernel v4.18.
|
||||||
|
pub fn gpl_compatible(&self) -> Option<bool> {
|
||||||
|
if FEATURES.prog_info_gpl_compatible() {
|
||||||
|
Some(self.0.gpl_compatible() != 0)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The BTF ID for the program.
|
||||||
|
///
|
||||||
|
/// Introduced in kernel v5.0.
|
||||||
|
pub fn btf_id(&self) -> Option<NonZeroU32> {
|
||||||
|
NonZeroU32::new(self.0.btf_id)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The accumulated time that the program has been actively running.
|
||||||
|
///
|
||||||
|
/// This is not to be confused with the duration since the program was
|
||||||
|
/// first loaded on the host.
|
||||||
|
///
|
||||||
|
/// Note this field is only updated for as long as
|
||||||
|
/// [`enable_stats`](crate::sys::enable_stats) is enabled
|
||||||
|
/// with [`Stats::RunTime`](crate::sys::Stats::RunTime).
|
||||||
|
///
|
||||||
|
/// Introduced in kernel v5.1.
|
||||||
|
pub fn run_time(&self) -> Duration {
|
||||||
|
Duration::from_nanos(self.0.run_time_ns)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The accumulated execution count of the program.
|
||||||
|
///
|
||||||
|
/// Note this field is only updated for as long as
|
||||||
|
/// [`enable_stats`](crate::sys::enable_stats) is enabled
|
||||||
|
/// with [`Stats::RunTime`](crate::sys::Stats::RunTime).
|
||||||
|
///
|
||||||
|
/// Introduced in kernel v5.1.
|
||||||
|
pub fn run_count(&self) -> u64 {
|
||||||
|
self.0.run_cnt
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The number of verified instructions in the program.
|
||||||
|
///
|
||||||
|
/// This may be less than the total number of instructions in the compiled program due to dead
|
||||||
|
/// code elimination in the verifier.
|
||||||
|
///
|
||||||
|
/// `None` is returned if the field is not available.
|
||||||
|
///
|
||||||
|
/// Introduced in kernel v5.16.
|
||||||
|
pub fn verified_instruction_count(&self) -> Option<NonZeroU32> {
|
||||||
|
NonZeroU32::new(self.0.verified_insns)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// How much memory in bytes has been allocated and locked for the program.
|
||||||
|
pub fn memory_locked(&self) -> Result<u32, ProgramError> {
|
||||||
|
get_fdinfo(self.fd()?.as_fd(), "memlock")
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns a file descriptor referencing the program.
|
||||||
|
///
|
||||||
|
/// The returned file descriptor can be closed at any time and doing so does
|
||||||
|
/// not influence the life cycle of the program.
|
||||||
|
///
|
||||||
|
/// Uses kernel v4.13 features.
|
||||||
|
pub fn fd(&self) -> Result<ProgramFd, ProgramError> {
|
||||||
|
let Self(info) = self;
|
||||||
|
let fd = bpf_prog_get_fd_by_id(info.id)?;
|
||||||
|
Ok(ProgramFd(fd))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Loads a program from a pinned path in bpffs.
|
||||||
|
///
|
||||||
|
/// Uses kernel v4.4 and v4.13 features.
|
||||||
|
pub fn from_pin<P: AsRef<Path>>(path: P) -> Result<Self, ProgramError> {
|
||||||
|
use std::os::unix::ffi::OsStrExt as _;
|
||||||
|
|
||||||
|
// TODO: avoid this unwrap by adding a new error variant.
|
||||||
|
let path_string = CString::new(path.as_ref().as_os_str().as_bytes()).unwrap();
|
||||||
|
let fd = bpf_get_object(&path_string).map_err(|(_, io_error)| SyscallError {
|
||||||
|
call: "BPF_OBJ_GET",
|
||||||
|
io_error,
|
||||||
|
})?;
|
||||||
|
|
||||||
|
Self::new_from_fd(fd.as_fd())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns information about a loaded program with the [`ProgramInfo`] structure.
|
||||||
|
///
|
||||||
|
/// This information is populated at load time by the kernel and can be used
|
||||||
|
/// to correlate a given [`crate::programs::Program`] to it's corresponding [`ProgramInfo`]
|
||||||
|
/// metadata.
|
||||||
|
macro_rules! impl_info {
|
||||||
|
($($struct_name:ident),+ $(,)?) => {
|
||||||
|
$(
|
||||||
|
impl $struct_name {
|
||||||
|
/// Returns metadata information of this program.
|
||||||
|
///
|
||||||
|
/// Uses kernel v4.13 features.
|
||||||
|
pub fn info(&self) -> Result<ProgramInfo, ProgramError> {
|
||||||
|
let ProgramFd(fd) = self.fd()?;
|
||||||
|
ProgramInfo::new_from_fd(fd.as_fd())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)+
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) use impl_info;
|
||||||
|
|
||||||
|
/// Returns an iterator of [`ProgramInfo`] over all eBPF programs loaded on the host.
|
||||||
|
///
|
||||||
|
/// Unlike [`Ebpf::programs`](crate::Ebpf::programs), this includes **all** programs on the host
|
||||||
|
/// system, not just those tied to a specific [`crate::Ebpf`] instance.
|
||||||
|
///
|
||||||
|
/// Uses kernel v4.13 features.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
/// ```
|
||||||
|
/// # use aya::programs::loaded_programs;
|
||||||
|
/// #
|
||||||
|
/// for p in loaded_programs() {
|
||||||
|
/// match p {
|
||||||
|
/// Ok(program) => println!("{}", String::from_utf8_lossy(program.name())),
|
||||||
|
/// Err(e) => println!("Error iterating programs: {:?}", e),
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// # Errors
|
||||||
|
///
|
||||||
|
/// Returns [`ProgramError::SyscallError`] if any of the syscalls required to either get
|
||||||
|
/// next program id, get the program fd, or the [`ProgramInfo`] fail.
|
||||||
|
///
|
||||||
|
/// In cases where iteration can't be performed, for example the caller does not have the necessary
|
||||||
|
/// privileges, a single item will be yielded containing the error that occurred.
|
||||||
|
pub fn loaded_programs() -> impl Iterator<Item = Result<ProgramInfo, ProgramError>> {
|
||||||
|
iter_prog_ids()
|
||||||
|
.map(|id| {
|
||||||
|
let id = id?;
|
||||||
|
bpf_prog_get_fd_by_id(id)
|
||||||
|
})
|
||||||
|
.map(|fd| {
|
||||||
|
let fd = fd?;
|
||||||
|
bpf_prog_get_info_by_fd(fd.as_fd(), &mut [])
|
||||||
|
})
|
||||||
|
.map(|result| result.map(ProgramInfo).map_err(Into::into))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The type of eBPF program.
|
||||||
|
#[non_exhaustive]
|
||||||
|
#[doc(alias = "bpf_prog_type")]
|
||||||
|
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||||
|
pub enum ProgramType {
|
||||||
|
/// An unspecified program type.
|
||||||
|
Unspecified = bpf_prog_type::BPF_PROG_TYPE_UNSPEC as isize,
|
||||||
|
/// A Socket Filter program type. See [`SocketFilter`](super::socket_filter::SocketFilter)
|
||||||
|
/// for the program implementation.
|
||||||
|
///
|
||||||
|
/// Introduced in kernel v3.19.
|
||||||
|
#[doc(alias = "BPF_PROG_TYPE_SOCKET_FILTER")]
|
||||||
|
SocketFilter = bpf_prog_type::BPF_PROG_TYPE_SOCKET_FILTER as isize,
|
||||||
|
/// A Kernel Probe program type. See [`KProbe`](super::kprobe::KProbe) and
|
||||||
|
/// [`UProbe`](super::uprobe::UProbe) for the program implementations.
|
||||||
|
///
|
||||||
|
/// Introduced in kernel v4.1.
|
||||||
|
#[doc(alias = "BPF_PROG_TYPE_KPROBE")]
|
||||||
|
KProbe = bpf_prog_type::BPF_PROG_TYPE_KPROBE as isize,
|
||||||
|
/// A Traffic Control (TC) Classifier program type. See
|
||||||
|
/// [`SchedClassifier`](super::tc::SchedClassifier) for the program implementation.
|
||||||
|
///
|
||||||
|
/// Introduced in kernel v4.1.
|
||||||
|
#[doc(alias = "BPF_PROG_TYPE_SCHED_CLS")]
|
||||||
|
SchedClassifier = bpf_prog_type::BPF_PROG_TYPE_SCHED_CLS as isize,
|
||||||
|
/// A Traffic Control (TC) Action program type.
|
||||||
|
///
|
||||||
|
/// Introduced in kernel v4.1.
|
||||||
|
#[doc(alias = "BPF_PROG_TYPE_SCHED_ACT")]
|
||||||
|
SchedAction = bpf_prog_type::BPF_PROG_TYPE_SCHED_ACT as isize,
|
||||||
|
/// A Tracepoint program type. See [`TracePoint`](super::trace_point::TracePoint) for the
|
||||||
|
/// program implementation.
|
||||||
|
///
|
||||||
|
/// Introduced in kernel v4.7.
|
||||||
|
#[doc(alias = "BPF_PROG_TYPE_TRACEPOINT")]
|
||||||
|
TracePoint = bpf_prog_type::BPF_PROG_TYPE_TRACEPOINT as isize,
|
||||||
|
/// An Express Data Path (XDP) program type. See [`Xdp`](super::xdp::Xdp) for the program
|
||||||
|
/// implementation.
|
||||||
|
///
|
||||||
|
/// Introduced in kernel v4.8.
|
||||||
|
#[doc(alias = "BPF_PROG_TYPE_XDP")]
|
||||||
|
Xdp = bpf_prog_type::BPF_PROG_TYPE_XDP as isize,
|
||||||
|
/// A Perf Event program type. See [`PerfEvent`](super::perf_event::PerfEvent) for the program
|
||||||
|
/// implementation.
|
||||||
|
///
|
||||||
|
/// Introduced in kernel v4.9.
|
||||||
|
#[doc(alias = "BPF_PROG_TYPE_PERF_EVENT")]
|
||||||
|
PerfEvent = bpf_prog_type::BPF_PROG_TYPE_PERF_EVENT as isize,
|
||||||
|
/// A cGroup Socket Buffer program type. See [`CgroupSkb`](super::cgroup_skb::CgroupSkb) for
|
||||||
|
/// the program implementation.
|
||||||
|
///
|
||||||
|
/// Introduced in kernel v4.10.
|
||||||
|
#[doc(alias = "BPF_PROG_TYPE_CGROUP_SKB")]
|
||||||
|
CgroupSkb = bpf_prog_type::BPF_PROG_TYPE_CGROUP_SKB as isize,
|
||||||
|
/// A cGroup Socket program type. See [`CgroupSock`](super::cgroup_sock::CgroupSock) for the
|
||||||
|
/// program implementation.
|
||||||
|
///
|
||||||
|
/// Introduced in kernel v4.10.
|
||||||
|
#[doc(alias = "BPF_PROG_TYPE_CGROUP_SOCK")]
|
||||||
|
CgroupSock = bpf_prog_type::BPF_PROG_TYPE_CGROUP_SOCK as isize,
|
||||||
|
/// A Lightweight Tunnel (LWT) Input program type.
|
||||||
|
///
|
||||||
|
/// Introduced in kernel v4.10.
|
||||||
|
#[doc(alias = "BPF_PROG_TYPE_LWT_IN")]
|
||||||
|
LwtInput = bpf_prog_type::BPF_PROG_TYPE_LWT_IN as isize,
|
||||||
|
/// A Lightweight Tunnel (LWT) Output program type.
|
||||||
|
///
|
||||||
|
/// Introduced in kernel v4.10.
|
||||||
|
#[doc(alias = "BPF_PROG_TYPE_LWT_OUT")]
|
||||||
|
LwtOutput = bpf_prog_type::BPF_PROG_TYPE_LWT_OUT as isize,
|
||||||
|
/// A Lightweight Tunnel (LWT) Transmit program type.
|
||||||
|
///
|
||||||
|
/// Introduced in kernel v4.10.
|
||||||
|
#[doc(alias = "BPF_PROG_TYPE_LWT_XMIT")]
|
||||||
|
LwtXmit = bpf_prog_type::BPF_PROG_TYPE_LWT_XMIT as isize,
|
||||||
|
/// A Socket Operation program type. See [`SockOps`](super::sock_ops::SockOps) for the program
|
||||||
|
/// implementation.
|
||||||
|
///
|
||||||
|
/// Introduced in kernel v4.13.
|
||||||
|
#[doc(alias = "BPF_PROG_TYPE_SOCK_OPS")]
|
||||||
|
SockOps = bpf_prog_type::BPF_PROG_TYPE_SOCK_OPS as isize,
|
||||||
|
/// A Socket-to-Socket Buffer program type. See [`SkSkb`](super::sk_skb::SkSkb) for the program
|
||||||
|
/// implementation.
|
||||||
|
///
|
||||||
|
/// Introduced in kernel v4.14.
|
||||||
|
#[doc(alias = "BPF_PROG_TYPE_SK_SKB")]
|
||||||
|
SkSkb = bpf_prog_type::BPF_PROG_TYPE_SK_SKB as isize,
|
||||||
|
/// A cGroup Device program type. See [`CgroupDevice`](super::cgroup_device::CgroupDevice)
|
||||||
|
/// for the program implementation.
|
||||||
|
///
|
||||||
|
/// Introduced in kernel v4.15.
|
||||||
|
#[doc(alias = "BPF_PROG_TYPE_CGROUP_DEVICE")]
|
||||||
|
CgroupDevice = bpf_prog_type::BPF_PROG_TYPE_CGROUP_DEVICE as isize,
|
||||||
|
/// A Socket Message program type. See [`SkMsg`](super::sk_msg::SkMsg) for the program
|
||||||
|
/// implementation.
|
||||||
|
///
|
||||||
|
/// Introduced in kernel v4.17.
|
||||||
|
#[doc(alias = "BPF_PROG_TYPE_SK_MSG")]
|
||||||
|
SkMsg = bpf_prog_type::BPF_PROG_TYPE_SK_MSG as isize,
|
||||||
|
/// A Raw Tracepoint program type. See [`RawTracePoint`](super::raw_trace_point::RawTracePoint)
|
||||||
|
/// for the program implementation.
|
||||||
|
///
|
||||||
|
/// Introduced in kernel v4.17.
|
||||||
|
#[doc(alias = "BPF_PROG_TYPE_RAW_TRACEPOINT")]
|
||||||
|
RawTracePoint = bpf_prog_type::BPF_PROG_TYPE_RAW_TRACEPOINT as isize,
|
||||||
|
/// A cGroup Socket Address program type. See
|
||||||
|
/// [`CgroupSockAddr`](super::cgroup_sock_addr::CgroupSockAddr) for the program implementation.
|
||||||
|
///
|
||||||
|
/// Introduced in kernel v4.17.
|
||||||
|
#[doc(alias = "BPF_PROG_TYPE_CGROUP_SOCK_ADDR")]
|
||||||
|
CgroupSockAddr = bpf_prog_type::BPF_PROG_TYPE_CGROUP_SOCK_ADDR as isize,
|
||||||
|
/// A Lightweight Tunnel (LWT) Seg6local program type.
|
||||||
|
///
|
||||||
|
/// Introduced in kernel v4.18.
|
||||||
|
#[doc(alias = "BPF_PROG_TYPE_LWT_SEG6LOCAL")]
|
||||||
|
LwtSeg6local = bpf_prog_type::BPF_PROG_TYPE_LWT_SEG6LOCAL as isize,
|
||||||
|
/// A Linux Infrared Remote Control (LIRC) Mode2 program type. See
|
||||||
|
/// [`LircMode2`](super::lirc_mode2::LircMode2) for the program implementation.
|
||||||
|
///
|
||||||
|
/// Introduced in kernel v4.18.
|
||||||
|
#[doc(alias = "BPF_PROG_TYPE_LIRC_MODE2")]
|
||||||
|
LircMode2 = bpf_prog_type::BPF_PROG_TYPE_LIRC_MODE2 as isize,
|
||||||
|
/// A Socket Reuseport program type.
|
||||||
|
///
|
||||||
|
/// Introduced in kernel v4.19.
|
||||||
|
#[doc(alias = "BPF_PROG_TYPE_SK_REUSEPORT")]
|
||||||
|
SkReuseport = bpf_prog_type::BPF_PROG_TYPE_SK_REUSEPORT as isize,
|
||||||
|
/// A Flow Dissector program type.
|
||||||
|
///
|
||||||
|
/// Introduced in kernel v4.20.
|
||||||
|
#[doc(alias = "BPF_PROG_TYPE_FLOW_DISSECTOR")]
|
||||||
|
FlowDissector = bpf_prog_type::BPF_PROG_TYPE_FLOW_DISSECTOR as isize,
|
||||||
|
/// A cGroup Sysctl program type. See [`CgroupSysctl`](super::cgroup_sysctl::CgroupSysctl) for
|
||||||
|
/// the program implementation.
|
||||||
|
///
|
||||||
|
/// Introduced in kernel v5.2.
|
||||||
|
#[doc(alias = "BPF_PROG_TYPE_CGROUP_SYSCTL")]
|
||||||
|
CgroupSysctl = bpf_prog_type::BPF_PROG_TYPE_CGROUP_SYSCTL as isize,
|
||||||
|
/// A Writable Raw Tracepoint program type.
|
||||||
|
///
|
||||||
|
/// Introduced in kernel v5.2.
|
||||||
|
#[doc(alias = "BPF_PROG_TYPE_RAW_TRACEPOINT_WRITABLE")]
|
||||||
|
RawTracePointWritable = bpf_prog_type::BPF_PROG_TYPE_RAW_TRACEPOINT_WRITABLE as isize,
|
||||||
|
/// A cGroup Socket Option program type. See [`CgroupSockopt`](super::cgroup_sockopt::CgroupSockopt)
|
||||||
|
/// for the program implementation.
|
||||||
|
///
|
||||||
|
/// Introduced in kernel v5.3.
|
||||||
|
#[doc(alias = "BPF_PROG_TYPE_CGROUP_SOCKOPT")]
|
||||||
|
CgroupSockopt = bpf_prog_type::BPF_PROG_TYPE_CGROUP_SOCKOPT as isize,
|
||||||
|
/// A Tracing program type. See [`FEntry`](super::fentry::FEntry), [`FExit`](super::fexit::FExit),
|
||||||
|
/// and [`BtfTracePoint`](super::tp_btf::BtfTracePoint) for the program implementations.
|
||||||
|
///
|
||||||
|
/// Introduced in kernel v5.5.
|
||||||
|
#[doc(alias = "BPF_PROG_TYPE_TRACING")]
|
||||||
|
Tracing = bpf_prog_type::BPF_PROG_TYPE_TRACING as isize,
|
||||||
|
/// A Struct Ops program type.
|
||||||
|
///
|
||||||
|
/// Introduced in kernel v5.6.
|
||||||
|
#[doc(alias = "BPF_PROG_TYPE_STRUCT_OPS")]
|
||||||
|
StructOps = bpf_prog_type::BPF_PROG_TYPE_STRUCT_OPS as isize,
|
||||||
|
/// A Extension program type. See [`Extension`](super::extension::Extension) for the program
|
||||||
|
/// implementation.
|
||||||
|
///
|
||||||
|
/// Introduced in kernel v5.6.
|
||||||
|
#[doc(alias = "BPF_PROG_TYPE_EXT")]
|
||||||
|
Extension = bpf_prog_type::BPF_PROG_TYPE_EXT as isize,
|
||||||
|
/// A Linux Security Module (LSM) program type. See [`Lsm`](super::lsm::Lsm) for the program
|
||||||
|
/// implementation.
|
||||||
|
///
|
||||||
|
/// Introduced in kernel v5.7.
|
||||||
|
#[doc(alias = "BPF_PROG_TYPE_LSM")]
|
||||||
|
Lsm = bpf_prog_type::BPF_PROG_TYPE_LSM as isize,
|
||||||
|
/// A Socket Lookup program type. See [`SkLookup`](super::sk_lookup::SkLookup) for the program
|
||||||
|
/// implementation.
|
||||||
|
///
|
||||||
|
/// Introduced in kernel v5.9.
|
||||||
|
#[doc(alias = "BPF_PROG_TYPE_SK_LOOKUP")]
|
||||||
|
SkLookup = bpf_prog_type::BPF_PROG_TYPE_SK_LOOKUP as isize,
|
||||||
|
/// A Syscall program type.
|
||||||
|
///
|
||||||
|
/// Introduced in kernel v5.14.
|
||||||
|
#[doc(alias = "BPF_PROG_TYPE_SYSCALL")]
|
||||||
|
Syscall = bpf_prog_type::BPF_PROG_TYPE_SYSCALL as isize,
|
||||||
|
/// A Netfilter program type.
|
||||||
|
///
|
||||||
|
/// Introduced in kernel v6.4.
|
||||||
|
#[doc(alias = "BPF_PROG_TYPE_NETFILTER")]
|
||||||
|
Netfilter = bpf_prog_type::BPF_PROG_TYPE_NETFILTER as isize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryFrom<bpf_prog_type> for ProgramType {
|
||||||
|
type Error = ProgramError;
|
||||||
|
|
||||||
|
fn try_from(prog_type: bpf_prog_type) -> Result<Self, Self::Error> {
|
||||||
|
use bpf_prog_type::*;
|
||||||
|
Ok(match prog_type {
|
||||||
|
BPF_PROG_TYPE_UNSPEC => Self::Unspecified,
|
||||||
|
BPF_PROG_TYPE_SOCKET_FILTER => Self::SocketFilter,
|
||||||
|
BPF_PROG_TYPE_KPROBE => Self::KProbe,
|
||||||
|
BPF_PROG_TYPE_SCHED_CLS => Self::SchedClassifier,
|
||||||
|
BPF_PROG_TYPE_SCHED_ACT => Self::SchedAction,
|
||||||
|
BPF_PROG_TYPE_TRACEPOINT => Self::TracePoint,
|
||||||
|
BPF_PROG_TYPE_XDP => Self::Xdp,
|
||||||
|
BPF_PROG_TYPE_PERF_EVENT => Self::PerfEvent,
|
||||||
|
BPF_PROG_TYPE_CGROUP_SKB => Self::CgroupSkb,
|
||||||
|
BPF_PROG_TYPE_CGROUP_SOCK => Self::CgroupSock,
|
||||||
|
BPF_PROG_TYPE_LWT_IN => Self::LwtInput,
|
||||||
|
BPF_PROG_TYPE_LWT_OUT => Self::LwtOutput,
|
||||||
|
BPF_PROG_TYPE_LWT_XMIT => Self::LwtXmit,
|
||||||
|
BPF_PROG_TYPE_SOCK_OPS => Self::SockOps,
|
||||||
|
BPF_PROG_TYPE_SK_SKB => Self::SkSkb,
|
||||||
|
BPF_PROG_TYPE_CGROUP_DEVICE => Self::CgroupDevice,
|
||||||
|
BPF_PROG_TYPE_SK_MSG => Self::SkMsg,
|
||||||
|
BPF_PROG_TYPE_RAW_TRACEPOINT => Self::RawTracePoint,
|
||||||
|
BPF_PROG_TYPE_CGROUP_SOCK_ADDR => Self::CgroupSockAddr,
|
||||||
|
BPF_PROG_TYPE_LWT_SEG6LOCAL => Self::LwtSeg6local,
|
||||||
|
BPF_PROG_TYPE_LIRC_MODE2 => Self::LircMode2,
|
||||||
|
BPF_PROG_TYPE_SK_REUSEPORT => Self::SkReuseport,
|
||||||
|
BPF_PROG_TYPE_FLOW_DISSECTOR => Self::FlowDissector,
|
||||||
|
BPF_PROG_TYPE_CGROUP_SYSCTL => Self::CgroupSysctl,
|
||||||
|
BPF_PROG_TYPE_RAW_TRACEPOINT_WRITABLE => Self::RawTracePointWritable,
|
||||||
|
BPF_PROG_TYPE_CGROUP_SOCKOPT => Self::CgroupSockopt,
|
||||||
|
BPF_PROG_TYPE_TRACING => Self::Tracing,
|
||||||
|
BPF_PROG_TYPE_STRUCT_OPS => Self::StructOps,
|
||||||
|
BPF_PROG_TYPE_EXT => Self::Extension,
|
||||||
|
BPF_PROG_TYPE_LSM => Self::Lsm,
|
||||||
|
BPF_PROG_TYPE_SK_LOOKUP => Self::SkLookup,
|
||||||
|
BPF_PROG_TYPE_SYSCALL => Self::Syscall,
|
||||||
|
BPF_PROG_TYPE_NETFILTER => Self::Netfilter,
|
||||||
|
__MAX_BPF_PROG_TYPE => return Err(ProgramError::UnexpectedProgramType),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,19 @@
|
|||||||
|
// Socket Filter program for testing with an arbitrary program.
|
||||||
|
// This is mainly used in tests with consideration for old kernels.
|
||||||
|
|
||||||
|
#![no_std]
|
||||||
|
#![no_main]
|
||||||
|
|
||||||
|
use aya_ebpf::{macros::socket_filter, programs::SkBuffContext};
|
||||||
|
|
||||||
|
// Introduced in kernel v3.19.
|
||||||
|
#[socket_filter]
|
||||||
|
pub fn simple_prog(_ctx: SkBuffContext) -> i64 {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(test))]
|
||||||
|
#[panic_handler]
|
||||||
|
fn panic(_info: &core::panic::PanicInfo) -> ! {
|
||||||
|
loop {}
|
||||||
|
}
|
@ -0,0 +1,362 @@
|
|||||||
|
//! Tests the Info API.
|
||||||
|
|
||||||
|
use std::{fs, panic, path::Path, time::SystemTime};
|
||||||
|
|
||||||
|
use aya::{
|
||||||
|
maps::{loaded_maps, Array, HashMap, IterableMap as _, MapError, MapType},
|
||||||
|
programs::{loaded_programs, ProgramError, ProgramType, SocketFilter, TracePoint},
|
||||||
|
sys::enable_stats,
|
||||||
|
util::KernelVersion,
|
||||||
|
Ebpf,
|
||||||
|
};
|
||||||
|
use libc::EINVAL;
|
||||||
|
|
||||||
|
use crate::utils::{kernel_assert, kernel_assert_eq};
|
||||||
|
|
||||||
|
const BPF_JIT_ENABLE: &str = "/proc/sys/net/core/bpf_jit_enable";
|
||||||
|
const BPF_STATS_ENABLED: &str = "/proc/sys/kernel/bpf_stats_enabled";
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_loaded_programs() {
|
||||||
|
// Load a program.
|
||||||
|
// Since we are only testing the programs for their metadata, there is no need to "attach" them.
|
||||||
|
let mut bpf = Ebpf::load(crate::SIMPLE_PROG).unwrap();
|
||||||
|
let prog: &mut SocketFilter = bpf.program_mut("simple_prog").unwrap().try_into().unwrap();
|
||||||
|
prog.load().unwrap();
|
||||||
|
let test_prog = prog.info().unwrap();
|
||||||
|
|
||||||
|
// Ensure loaded program doesn't panic
|
||||||
|
let mut programs = loaded_programs().peekable();
|
||||||
|
if let Err(err) = programs.peek().unwrap() {
|
||||||
|
if let ProgramError::SyscallError(err) = &err {
|
||||||
|
// Skip entire test since feature not available
|
||||||
|
if err
|
||||||
|
.io_error
|
||||||
|
.raw_os_error()
|
||||||
|
.is_some_and(|errno| errno == EINVAL)
|
||||||
|
{
|
||||||
|
eprintln!(
|
||||||
|
"ignoring test completely as `loaded_programs()` is not available on the host"
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
panic!("{err}");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Loaded programs should contain our test program
|
||||||
|
let mut programs = programs.filter_map(|prog| prog.ok());
|
||||||
|
kernel_assert!(
|
||||||
|
programs.any(|prog| prog.id() == test_prog.id()),
|
||||||
|
KernelVersion::new(4, 13, 0)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_program_info() {
|
||||||
|
// Kernels below v4.15 have been observed to have `bpf_jit_enable` disabled by default.
|
||||||
|
let previously_enabled = is_sysctl_enabled(BPF_JIT_ENABLE);
|
||||||
|
// Restore to previous state when panic occurs.
|
||||||
|
let prev_panic = panic::take_hook();
|
||||||
|
panic::set_hook(Box::new(move |panic_info| {
|
||||||
|
if !previously_enabled {
|
||||||
|
disable_sysctl_param(BPF_JIT_ENABLE);
|
||||||
|
}
|
||||||
|
prev_panic(panic_info);
|
||||||
|
}));
|
||||||
|
let jit_enabled = previously_enabled || enable_sysctl_param(BPF_JIT_ENABLE);
|
||||||
|
|
||||||
|
let mut bpf = Ebpf::load(crate::SIMPLE_PROG).unwrap();
|
||||||
|
let prog: &mut SocketFilter = bpf.program_mut("simple_prog").unwrap().try_into().unwrap();
|
||||||
|
prog.load().unwrap();
|
||||||
|
let test_prog = prog.info().unwrap();
|
||||||
|
|
||||||
|
// Test `bpf_prog_info` fields.
|
||||||
|
kernel_assert_eq!(
|
||||||
|
ProgramType::SocketFilter,
|
||||||
|
test_prog.program_type().unwrap_or(ProgramType::Unspecified),
|
||||||
|
KernelVersion::new(4, 13, 0),
|
||||||
|
);
|
||||||
|
kernel_assert!(test_prog.id().is_some(), KernelVersion::new(4, 13, 0));
|
||||||
|
kernel_assert!(test_prog.tag().is_some(), KernelVersion::new(4, 13, 0));
|
||||||
|
if jit_enabled {
|
||||||
|
kernel_assert!(
|
||||||
|
test_prog.size_jitted().is_some(),
|
||||||
|
KernelVersion::new(4, 13, 0),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
kernel_assert!(
|
||||||
|
test_prog.size_translated().is_some(),
|
||||||
|
KernelVersion::new(4, 13, 0),
|
||||||
|
);
|
||||||
|
kernel_assert!(
|
||||||
|
test_prog.loaded_at().is_some(),
|
||||||
|
KernelVersion::new(4, 15, 0),
|
||||||
|
);
|
||||||
|
kernel_assert!(
|
||||||
|
test_prog.created_by_uid().is_some_and(|uid| uid == 0),
|
||||||
|
KernelVersion::new(4, 15, 0),
|
||||||
|
);
|
||||||
|
let maps = test_prog.map_ids().unwrap();
|
||||||
|
kernel_assert!(
|
||||||
|
maps.is_some_and(|ids| ids.is_empty()),
|
||||||
|
KernelVersion::new(4, 15, 0),
|
||||||
|
);
|
||||||
|
kernel_assert!(
|
||||||
|
test_prog
|
||||||
|
.name_as_str()
|
||||||
|
.is_some_and(|name| name == "simple_prog"),
|
||||||
|
KernelVersion::new(4, 15, 0),
|
||||||
|
);
|
||||||
|
kernel_assert!(
|
||||||
|
test_prog.gpl_compatible().is_some_and(|gpl| gpl),
|
||||||
|
KernelVersion::new(4, 18, 0),
|
||||||
|
);
|
||||||
|
kernel_assert!(
|
||||||
|
test_prog.verified_instruction_count().is_some(),
|
||||||
|
KernelVersion::new(5, 16, 0),
|
||||||
|
);
|
||||||
|
|
||||||
|
// We can't reliably test these fields since `0` can be interpreted as the actual value or
|
||||||
|
// unavailable.
|
||||||
|
test_prog.btf_id();
|
||||||
|
|
||||||
|
// Ensure rest of the fields do not panic.
|
||||||
|
test_prog.memory_locked().unwrap();
|
||||||
|
test_prog.fd().unwrap();
|
||||||
|
|
||||||
|
// Restore to previous state
|
||||||
|
if !previously_enabled {
|
||||||
|
disable_sysctl_param(BPF_JIT_ENABLE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_loaded_at() {
|
||||||
|
let mut bpf: Ebpf = Ebpf::load(crate::SIMPLE_PROG).unwrap();
|
||||||
|
let prog: &mut SocketFilter = bpf.program_mut("simple_prog").unwrap().try_into().unwrap();
|
||||||
|
|
||||||
|
// SystemTime is not monotonic, which can cause this test to flake. We don't expect the clock
|
||||||
|
// timestamp to continuously jump around, so we add some retries. If the test is ever correct,
|
||||||
|
// we know that the value returned by loaded_at() was reasonable relative to SystemTime::now().
|
||||||
|
let mut failures = Vec::new();
|
||||||
|
for _ in 0..5 {
|
||||||
|
let t1 = SystemTime::now();
|
||||||
|
prog.load().unwrap();
|
||||||
|
|
||||||
|
let t2 = SystemTime::now();
|
||||||
|
let loaded_at = match prog.info().unwrap().loaded_at() {
|
||||||
|
Some(time) => time,
|
||||||
|
None => {
|
||||||
|
eprintln!("ignoring test completely as `load_time` field of `bpf_prog_info` is not available on the host");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
prog.unload().unwrap();
|
||||||
|
|
||||||
|
let range = t1..t2;
|
||||||
|
if range.contains(&loaded_at) {
|
||||||
|
failures.clear();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
failures.push(LoadedAtRange(loaded_at, range));
|
||||||
|
}
|
||||||
|
assert!(
|
||||||
|
failures.is_empty(),
|
||||||
|
"loaded_at was not in range: {failures:?}",
|
||||||
|
);
|
||||||
|
|
||||||
|
struct LoadedAtRange(SystemTime, std::ops::Range<SystemTime>);
|
||||||
|
impl std::fmt::Debug for LoadedAtRange {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
let Self(loaded_at, range) = self;
|
||||||
|
write!(f, "{range:?}.contains({loaded_at:?})")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_prog_stats() {
|
||||||
|
// Test depends on whether trace point exists.
|
||||||
|
if !Path::new("/sys/kernel/debug/tracing/events/syscalls/sys_enter_bpf").exists() {
|
||||||
|
eprintln!(
|
||||||
|
"ignoring test completely as `syscalls/sys_enter_bpf` is not available on the host"
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let stats_fd = enable_stats(aya::sys::Stats::RunTime).ok();
|
||||||
|
// Restore to previous state when panic occurs.
|
||||||
|
let previously_enabled = is_sysctl_enabled(BPF_STATS_ENABLED);
|
||||||
|
let prev_panic = panic::take_hook();
|
||||||
|
panic::set_hook(Box::new(move |panic_info| {
|
||||||
|
if !previously_enabled {
|
||||||
|
disable_sysctl_param(BPF_STATS_ENABLED);
|
||||||
|
}
|
||||||
|
prev_panic(panic_info);
|
||||||
|
}));
|
||||||
|
|
||||||
|
let stats_enabled =
|
||||||
|
stats_fd.is_some() || previously_enabled || enable_sysctl_param(BPF_STATS_ENABLED);
|
||||||
|
if !stats_enabled {
|
||||||
|
eprintln!("ignoring test completely as bpf stats could not be enabled on the host");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut bpf = Ebpf::load(crate::TEST).unwrap();
|
||||||
|
let prog: &mut TracePoint = bpf
|
||||||
|
.program_mut("test_tracepoint")
|
||||||
|
.unwrap()
|
||||||
|
.try_into()
|
||||||
|
.unwrap();
|
||||||
|
prog.load().unwrap();
|
||||||
|
prog.attach("syscalls", "sys_enter_bpf").unwrap();
|
||||||
|
let test_prog = prog.info().unwrap();
|
||||||
|
|
||||||
|
kernel_assert!(
|
||||||
|
test_prog.run_time().as_nanos() > 0,
|
||||||
|
KernelVersion::new(5, 1, 0)
|
||||||
|
);
|
||||||
|
kernel_assert!(test_prog.run_count() > 0, KernelVersion::new(5, 1, 0));
|
||||||
|
|
||||||
|
// Restore to previous state
|
||||||
|
if !previously_enabled {
|
||||||
|
disable_sysctl_param(BPF_STATS_ENABLED);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn list_loaded_maps() {
|
||||||
|
// Load a program with maps.
|
||||||
|
let mut bpf: Ebpf = Ebpf::load(crate::MAP_TEST).unwrap();
|
||||||
|
let prog: &mut SocketFilter = bpf.program_mut("simple_prog").unwrap().try_into().unwrap();
|
||||||
|
prog.load().unwrap();
|
||||||
|
|
||||||
|
// Ensure the loaded_maps() api doesn't panic
|
||||||
|
let mut maps = loaded_maps().peekable();
|
||||||
|
if let Err(err) = maps.peek().unwrap() {
|
||||||
|
if let MapError::SyscallError(err) = &err {
|
||||||
|
if err
|
||||||
|
.io_error
|
||||||
|
.raw_os_error()
|
||||||
|
.is_some_and(|errno| errno == EINVAL)
|
||||||
|
{
|
||||||
|
eprintln!(
|
||||||
|
"ignoring test completely as `loaded_maps()` is not available on the host"
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
panic!("{err}");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Loaded maps should contain our test maps
|
||||||
|
let maps: Vec<_> = maps.filter_map(|m| m.ok()).collect();
|
||||||
|
if let Ok(info) = &prog.info() {
|
||||||
|
if let Some(map_ids) = info.map_ids().unwrap() {
|
||||||
|
assert_eq!(2, map_ids.len());
|
||||||
|
for id in map_ids.iter() {
|
||||||
|
assert!(
|
||||||
|
maps.iter().any(|m| &m.id().unwrap() == id),
|
||||||
|
"expected `loaded_maps()` to have `map_ids` from program",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let hash: HashMap<_, u32, u8> = HashMap::try_from(bpf.map("BAR").unwrap()).unwrap();
|
||||||
|
let hash_id = hash.map().info().unwrap().id();
|
||||||
|
kernel_assert!(
|
||||||
|
maps.iter().any(|map| map.id() == hash_id),
|
||||||
|
KernelVersion::new(4, 13, 0),
|
||||||
|
);
|
||||||
|
|
||||||
|
let array: Array<_, u32> = Array::try_from(bpf.map("FOO").unwrap()).unwrap();
|
||||||
|
let array_id = array.map().info().unwrap().id();
|
||||||
|
kernel_assert!(
|
||||||
|
maps.iter().any(|map| map.id() == array_id),
|
||||||
|
KernelVersion::new(4, 13, 0),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_map_info() {
|
||||||
|
let mut bpf: Ebpf = Ebpf::load(crate::MAP_TEST).unwrap();
|
||||||
|
let prog: &mut SocketFilter = bpf.program_mut("simple_prog").unwrap().try_into().unwrap();
|
||||||
|
prog.load().unwrap();
|
||||||
|
|
||||||
|
// Test `bpf_map_info` fields.
|
||||||
|
let hash: HashMap<_, u32, u8> = HashMap::try_from(bpf.map("BAR").unwrap()).unwrap();
|
||||||
|
let hash = hash.map().info().unwrap();
|
||||||
|
kernel_assert_eq!(
|
||||||
|
MapType::Hash,
|
||||||
|
hash.map_type().unwrap_or(MapType::Unspecified),
|
||||||
|
KernelVersion::new(4, 13, 0),
|
||||||
|
);
|
||||||
|
kernel_assert!(hash.id().is_some(), KernelVersion::new(4, 13, 0));
|
||||||
|
kernel_assert!(
|
||||||
|
hash.key_size().is_some_and(|size| size.get() == 4),
|
||||||
|
KernelVersion::new(4, 13, 0),
|
||||||
|
);
|
||||||
|
kernel_assert!(
|
||||||
|
hash.value_size().is_some_and(|size| size.get() == 1),
|
||||||
|
KernelVersion::new(4, 13, 0),
|
||||||
|
);
|
||||||
|
kernel_assert!(
|
||||||
|
hash.max_entries().is_some_and(|size| size.get() == 8),
|
||||||
|
KernelVersion::new(4, 13, 0),
|
||||||
|
);
|
||||||
|
kernel_assert!(
|
||||||
|
hash.name_as_str().is_some_and(|name| name == "BAR"),
|
||||||
|
KernelVersion::new(4, 15, 0),
|
||||||
|
);
|
||||||
|
|
||||||
|
hash.map_flags();
|
||||||
|
hash.fd().unwrap();
|
||||||
|
|
||||||
|
let array: Array<_, u32> = Array::try_from(bpf.map("FOO").unwrap()).unwrap();
|
||||||
|
let array = array.map().info().unwrap();
|
||||||
|
kernel_assert_eq!(
|
||||||
|
MapType::Array,
|
||||||
|
array.map_type().unwrap_or(MapType::Unspecified),
|
||||||
|
KernelVersion::new(4, 13, 0),
|
||||||
|
);
|
||||||
|
kernel_assert!(array.id().is_some(), KernelVersion::new(4, 13, 0));
|
||||||
|
kernel_assert!(
|
||||||
|
array.key_size().is_some_and(|size| size.get() == 4),
|
||||||
|
KernelVersion::new(4, 13, 0),
|
||||||
|
);
|
||||||
|
kernel_assert!(
|
||||||
|
array.value_size().is_some_and(|size| size.get() == 4),
|
||||||
|
KernelVersion::new(4, 13, 0),
|
||||||
|
);
|
||||||
|
kernel_assert!(
|
||||||
|
array.max_entries().is_some_and(|size| size.get() == 10),
|
||||||
|
KernelVersion::new(4, 13, 0),
|
||||||
|
);
|
||||||
|
kernel_assert!(
|
||||||
|
array.name_as_str().is_some_and(|name| name == "FOO"),
|
||||||
|
KernelVersion::new(4, 15, 0),
|
||||||
|
);
|
||||||
|
|
||||||
|
array.map_flags();
|
||||||
|
array.fd().unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Whether sysctl parameter is enabled in the `/proc` file.
|
||||||
|
fn is_sysctl_enabled(path: &str) -> bool {
|
||||||
|
match fs::read_to_string(path) {
|
||||||
|
Ok(contents) => contents.chars().next().is_some_and(|c| c == '1'),
|
||||||
|
Err(_) => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Enable sysctl parameter through procfs.
|
||||||
|
fn enable_sysctl_param(path: &str) -> bool {
|
||||||
|
fs::write(path, b"1").is_ok()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Disable sysctl parameter through procfs.
|
||||||
|
fn disable_sysctl_param(path: &str) -> bool {
|
||||||
|
fs::write(path, b"0").is_ok()
|
||||||
|
}
|
Loading…
Reference in New Issue