diff --git a/aya-log/src/lib.rs b/aya-log/src/lib.rs index 9dcbb2f5..421ce2a0 100644 --- a/aya-log/src/lib.rs +++ b/aya-log/src/lib.rs @@ -60,12 +60,11 @@ use std::{ const MAP_NAME: &str = "AYA_LOGS"; use aya::{ - loaded_programs, maps::{ perf::{AsyncPerfEventArray, Events, PerfBufferError}, Map, MapData, MapError, MapInfo, }, - programs::ProgramError, + programs::{loaded_programs, ProgramError}, util::online_cpus, Ebpf, Pod, }; @@ -137,19 +136,21 @@ impl EbpfLogger { ) -> Result { let program_info = loaded_programs() .filter_map(|info| info.ok()) - .find(|info| info.id() == program_id) + .find(|info| info.id().is_some_and(|id| id.get() == program_id)) .ok_or(Error::ProgramNotFound)?; + let map = program_info .map_ids() .map_err(Error::ProgramError)? + .expect("`map_ids` field in `bpf_prog_info` not available") .iter() - .filter_map(|id| MapInfo::from_id(*id).ok()) + .filter_map(|id| MapInfo::from_id(id.get()).ok()) .find(|map_info| match map_info.name_as_str() { Some(name) => name == MAP_NAME, None => false, }) .ok_or(Error::MapNotFound)?; - let map = MapData::from_id(map.id()).map_err(Error::MapError)?; + let map = MapData::from_id(map.id().unwrap().get()).map_err(Error::MapError)?; Self::read_logs_async(Map::PerfEventArray(map), logger)?; diff --git a/aya-obj/src/lib.rs b/aya-obj/src/lib.rs index ea0e5670..c6e3a45c 100644 --- a/aya-obj/src/lib.rs +++ b/aya-obj/src/lib.rs @@ -87,6 +87,7 @@ mod std { pub mod btf; pub mod generated; +pub mod links; pub mod maps; pub mod obj; pub mod programs; diff --git a/aya-obj/src/links.rs b/aya-obj/src/links.rs new file mode 100644 index 00000000..b01e60db --- /dev/null +++ b/aya-obj/src/links.rs @@ -0,0 +1,100 @@ +//! Link type bindings. + +use crate::{ + generated::{bpf_attach_type, bpf_link_type}, + InvalidTypeBinding, +}; + +impl TryFrom for bpf_link_type { + type Error = InvalidTypeBinding; + + fn try_from(link_type: u32) -> Result { + 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 for bpf_attach_type { + type Error = InvalidTypeBinding; + + fn try_from(attach_type: u32) -> Result { + 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 }), + }) + } +} diff --git a/aya-obj/src/maps.rs b/aya-obj/src/maps.rs index ca85bba7..3eb82409 100644 --- a/aya-obj/src/maps.rs +++ b/aya-obj/src/maps.rs @@ -5,16 +5,10 @@ use core::mem; #[cfg(not(feature = "std"))] use crate::std; -use crate::EbpfSectionKind; - -/// Invalid map type encontered -pub struct InvalidMapTypeError { - /// The map type - pub map_type: u32, -} +use crate::{EbpfSectionKind, InvalidTypeBinding}; impl TryFrom for crate::generated::bpf_map_type { - type Error = InvalidMapTypeError; + type Error = InvalidTypeBinding; fn try_from(map_type: u32) -> Result { use crate::generated::bpf_map_type::*; @@ -31,7 +25,6 @@ impl TryFrom for crate::generated::bpf_map_type { x if x == BPF_MAP_TYPE_LRU_HASH as u32 => BPF_MAP_TYPE_LRU_HASH, x if x == BPF_MAP_TYPE_LRU_PERCPU_HASH as u32 => BPF_MAP_TYPE_LRU_PERCPU_HASH, x if x == BPF_MAP_TYPE_LPM_TRIE as u32 => BPF_MAP_TYPE_LPM_TRIE, - x if x == BPF_MAP_TYPE_BLOOM_FILTER as u32 => BPF_MAP_TYPE_BLOOM_FILTER, x if x == BPF_MAP_TYPE_ARRAY_OF_MAPS as u32 => BPF_MAP_TYPE_ARRAY_OF_MAPS, x if x == BPF_MAP_TYPE_HASH_OF_MAPS as u32 => BPF_MAP_TYPE_HASH_OF_MAPS, x if x == BPF_MAP_TYPE_DEVMAP as u32 => BPF_MAP_TYPE_DEVMAP, @@ -42,7 +35,6 @@ impl TryFrom for crate::generated::bpf_map_type { x if x == BPF_MAP_TYPE_CGROUP_STORAGE_DEPRECATED as u32 => { BPF_MAP_TYPE_CGROUP_STORAGE_DEPRECATED } - x if x == BPF_MAP_TYPE_CGRP_STORAGE as u32 => BPF_MAP_TYPE_CGRP_STORAGE, x if x == BPF_MAP_TYPE_REUSEPORT_SOCKARRAY as u32 => BPF_MAP_TYPE_REUSEPORT_SOCKARRAY, x if x == BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE_DEPRECATED as u32 => { BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE_DEPRECATED @@ -58,7 +50,8 @@ impl TryFrom for crate::generated::bpf_map_type { x if x == BPF_MAP_TYPE_BLOOM_FILTER as u32 => BPF_MAP_TYPE_BLOOM_FILTER, x if x == BPF_MAP_TYPE_USER_RINGBUF as u32 => BPF_MAP_TYPE_USER_RINGBUF, x if x == BPF_MAP_TYPE_CGRP_STORAGE as u32 => BPF_MAP_TYPE_CGRP_STORAGE, - _ => return Err(InvalidMapTypeError { map_type }), + x if x == BPF_MAP_TYPE_ARENA as u32 => BPF_MAP_TYPE_ARENA, + _ => return Err(InvalidTypeBinding { value: map_type }), }) } } diff --git a/aya-obj/src/obj.rs b/aya-obj/src/obj.rs index 429388a0..e4be87da 100644 --- a/aya-obj/src/obj.rs +++ b/aya-obj/src/obj.rs @@ -47,6 +47,8 @@ pub struct Features { bpf_cookie: bool, cpumap_prog_id: bool, devmap_prog_id: bool, + prog_info_map_ids: bool, + prog_info_gpl_compatible: bool, btf: Option, } @@ -61,6 +63,8 @@ impl Features { bpf_cookie: bool, cpumap_prog_id: bool, devmap_prog_id: bool, + prog_info_map_ids: bool, + prog_info_gpl_compatible: bool, btf: Option, ) -> Self { Self { @@ -71,11 +75,16 @@ impl Features { bpf_cookie, cpumap_prog_id, devmap_prog_id, + prog_info_map_ids, + prog_info_gpl_compatible, btf, } } - /// Returns whether BPF program names are supported. + /// Returns whether BPF program names and map names are supported. + /// + /// Although the feature probe performs the check for program name, we can use this to also + /// detect if map name is supported since they were both introduced in the same commit. pub fn bpf_name(&self) -> bool { self.bpf_name } @@ -110,6 +119,16 @@ impl Features { self.devmap_prog_id } + /// Returns whether `bpf_prog_info` supports `nr_map_ids` & `map_ids` fields. + pub fn prog_info_map_ids(&self) -> bool { + self.prog_info_map_ids + } + + /// Returns whether `bpf_prog_info` supports `gpl_compatible` field. + pub fn prog_info_gpl_compatible(&self) -> bool { + self.prog_info_gpl_compatible + } + /// If BTF is supported, returns which BTF features are supported. pub fn btf(&self) -> Option<&BtfFeatures> { self.btf.as_ref() @@ -987,6 +1006,12 @@ pub enum ParseError { NoBTF, } +/// Invalid bindings to the bpf type from the parsed/received value. +pub struct InvalidTypeBinding { + /// The value parsed/received. + pub value: T, +} + /// The kind of an ELF section. #[derive(Debug, Copy, Clone, Eq, PartialEq)] pub enum EbpfSectionKind { diff --git a/aya-obj/src/programs/mod.rs b/aya-obj/src/programs/mod.rs index 6b66b005..b6e91e7a 100644 --- a/aya-obj/src/programs/mod.rs +++ b/aya-obj/src/programs/mod.rs @@ -3,6 +3,7 @@ pub mod cgroup_sock; pub mod cgroup_sock_addr; pub mod cgroup_sockopt; +mod types; pub mod xdp; pub use cgroup_sock::CgroupSockAttachType; diff --git a/aya-obj/src/programs/types.rs b/aya-obj/src/programs/types.rs new file mode 100644 index 00000000..792f562b --- /dev/null +++ b/aya-obj/src/programs/types.rs @@ -0,0 +1,51 @@ +//! Program type bindings. + +use crate::{ + generated::bpf_prog_type::{self, *}, + InvalidTypeBinding, +}; + +impl TryFrom for bpf_prog_type { + type Error = InvalidTypeBinding; + + fn try_from(prog_type: u32) -> Result { + 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 }), + }) + } +} diff --git a/aya/src/bpf.rs b/aya/src/bpf.rs index 99d8e0d2..8a189476 100644 --- a/aya/src/bpf.rs +++ b/aya/src/bpf.rs @@ -21,8 +21,8 @@ use thiserror::Error; use crate::{ generated::{ - bpf_map_type, bpf_map_type::*, AYA_PERF_EVENT_IOC_DISABLE, AYA_PERF_EVENT_IOC_ENABLE, - AYA_PERF_EVENT_IOC_SET_BPF, + bpf_map_type::{self, *}, + AYA_PERF_EVENT_IOC_DISABLE, AYA_PERF_EVENT_IOC_ENABLE, AYA_PERF_EVENT_IOC_SET_BPF, }, maps::{Map, MapData, MapError}, obj::{ @@ -39,9 +39,9 @@ use crate::{ bpf_load_btf, is_bpf_cookie_supported, is_bpf_global_data_supported, is_btf_datasec_supported, is_btf_decl_tag_supported, is_btf_enum64_supported, is_btf_float_supported, is_btf_func_global_supported, is_btf_func_supported, - is_btf_supported, is_btf_type_tag_supported, is_perf_link_supported, - is_probe_read_kernel_supported, is_prog_id_supported, is_prog_name_supported, - retry_with_verifier_logs, + is_btf_supported, is_btf_type_tag_supported, is_info_gpl_compatible_supported, + is_info_map_ids_supported, is_perf_link_supported, is_probe_read_kernel_supported, + is_prog_id_supported, is_prog_name_supported, retry_with_verifier_logs, }, util::{bytes_of, bytes_of_slice, page_size, possible_cpus, POSSIBLE_CPUS}, }; @@ -96,6 +96,8 @@ fn detect_features() -> Features { is_bpf_cookie_supported(), is_prog_id_supported(BPF_MAP_TYPE_CPUMAP), is_prog_id_supported(BPF_MAP_TYPE_DEVMAP), + is_info_map_ids_supported(), + is_info_gpl_compatible_supported(), btf, ); debug!("BPF Feature Detection: {:#?}", f); diff --git a/aya/src/lib.rs b/aya/src/lib.rs index c35bf597..3278d3dc 100644 --- a/aya/src/lib.rs +++ b/aya/src/lib.rs @@ -91,7 +91,6 @@ use aya_obj::generated; pub use bpf::*; pub use obj::btf::{Btf, BtfError}; pub use object::Endianness; -pub use programs::loaded_programs; #[doc(hidden)] pub use sys::netlink_set_link_up; diff --git a/aya/src/maps/info.rs b/aya/src/maps/info.rs new file mode 100644 index 00000000..1d15dc6f --- /dev/null +++ b/aya/src/maps/info.rs @@ -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 { + 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 { + 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 { + 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::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::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::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::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 { + 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>(path: P) -> Result { + 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> { + 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 for MapType { + type Error = MapError; + + fn try_from(map_type: bpf_map_type) -> Result { + 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, + }) + } + }) + } +} diff --git a/aya/src/maps/mod.rs b/aya/src/maps/mod.rs index 431064d8..752bd9ff 100644 --- a/aya/src/maps/mod.rs +++ b/aya/src/maps/mod.rs @@ -59,28 +59,26 @@ use std::{ ptr, }; -use aya_obj::generated::bpf_map_type; +use aya_obj::{generated::bpf_map_type, InvalidTypeBinding}; use libc::{getrlimit, rlim_t, rlimit, RLIMIT_MEMLOCK, RLIM_INFINITY}; use log::warn; -use obj::maps::InvalidMapTypeError; use thiserror::Error; use crate::{ - generated::bpf_map_info, obj::{self, parse_map_info, EbpfSectionKind}, pin::PinError, sys::{ - bpf_create_map, bpf_get_object, bpf_map_freeze, bpf_map_get_fd_by_id, - bpf_map_get_info_by_fd, bpf_map_get_next_key, bpf_map_update_elem_ptr, bpf_pin_object, - iter_map_ids, SyscallError, + bpf_create_map, bpf_get_object, bpf_map_freeze, bpf_map_get_fd_by_id, bpf_map_get_next_key, + bpf_map_update_elem_ptr, bpf_pin_object, SyscallError, }, - util::{bytes_of_bpf_name, nr_cpus, KernelVersion}, + util::{nr_cpus, KernelVersion}, PinningType, Pod, }; pub mod array; pub mod bloom_filter; pub mod hash_map; +mod info; pub mod lpm_trie; pub mod perf; pub mod queue; @@ -93,6 +91,7 @@ pub mod xdp; pub use array::{Array, PerCpuArray, ProgramArray}; pub use bloom_filter::BloomFilter; pub use hash_map::{HashMap, PerCpuHashMap}; +pub use info::{loaded_maps, MapInfo, MapType}; pub use lpm_trie::LpmTrie; #[cfg(any(feature = "async_tokio", feature = "async_std"))] #[cfg_attr(docsrs, doc(cfg(any(feature = "async_tokio", feature = "async_std"))))] @@ -203,13 +202,10 @@ pub enum MapError { }, } -// Note that this is not just derived using #[from] because InvalidMapTypeError cannot implement -// Error due the the fact that aya-obj is no_std and error_in_core is not stabilized -// (https://github.com/rust-lang/rust/issues/103765). -impl From for MapError { - fn from(e: InvalidMapTypeError) -> Self { - let InvalidMapTypeError { map_type } = e; - Self::InvalidMapType { map_type } +impl From> for MapError { + fn from(e: InvalidTypeBinding) -> Self { + let InvalidTypeBinding { value } = e; + Self::InvalidMapType { map_type: value } } } @@ -951,119 +947,6 @@ impl Deref for PerCpuValues { } } -/// Provides information about a loaded map, like name, id and size. -#[derive(Debug)] -pub struct MapInfo(bpf_map_info); - -impl MapInfo { - fn new_from_fd(fd: BorrowedFd<'_>) -> Result { - let info = bpf_map_get_info_by_fd(fd.as_fd())?; - Ok(Self(info)) - } - - /// Loads map info from a map id. - pub fn from_id(id: u32) -> Result { - bpf_map_get_fd_by_id(id) - .map_err(MapError::from) - .and_then(|fd| Self::new_from_fd(fd.as_fd())) - } - - /// The name of the map, limited to 16 bytes. - pub fn name(&self) -> &[u8] { - bytes_of_bpf_name(&self.0.name) - } - - /// The name of the map as a &str. If the name is not valid unicode, None is returned. - pub fn name_as_str(&self) -> Option<&str> { - std::str::from_utf8(self.name()).ok() - } - - /// The id for this map. Each map has a unique id. - pub fn id(&self) -> u32 { - self.0.id - } - - /// The map type as defined by the linux kernel enum - /// [`bpf_map_type`](https://elixir.bootlin.com/linux/v6.4.4/source/include/uapi/linux/bpf.h#L905). - pub fn map_type(&self) -> u32 { - self.0.type_ - } - - /// The key size for this map. - pub fn key_size(&self) -> u32 { - self.0.key_size - } - - /// The value size for this map. - pub fn value_size(&self) -> u32 { - self.0.value_size - } - - /// The maximum number of entries in this map. - pub fn max_entries(&self) -> u32 { - self.0.max_entries - } - - /// The flags for this map. - pub fn map_flags(&self) -> u32 { - self.0.map_flags - } - - /// 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. - pub fn fd(&self) -> Result { - 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. - pub fn from_pin>(path: P) -> Result { - 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 over all loaded bpf maps. -/// -/// This differs from [`crate::Ebpf::maps`] since it will return all maps -/// listed on the host system and not only maps for a specific [`crate::Ebpf`] instance. -/// -/// # 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> { - iter_map_ids().map(|id| { - let id = id?; - MapInfo::from_id(id) - }) -} - #[cfg(test)] mod test_utils { use crate::{ @@ -1334,11 +1217,11 @@ mod tests { .map(|map_info| { let map_info = map_info.unwrap(); ( - map_info.id(), - map_info.key_size(), - map_info.value_size(), + map_info.id().unwrap().get(), + map_info.key_size().unwrap().get(), + map_info.value_size().unwrap().get(), map_info.map_flags(), - map_info.max_entries(), + map_info.max_entries().unwrap().get(), map_info.fd().unwrap().as_fd().as_raw_fd(), ) }) diff --git a/aya/src/programs/info.rs b/aya/src/programs/info.rs new file mode 100644 index 00000000..dbcfba3f --- /dev/null +++ b/aya/src/programs/info.rs @@ -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 { + 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 { + 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::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::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::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::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 { + 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 { + // 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>, 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 { + 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::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::new(self.0.verified_insns) + } + + /// How much memory in bytes has been allocated and locked for the program. + pub fn memory_locked(&self) -> Result { + 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 { + 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>(path: P) -> Result { + 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 { + 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> { + 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 for ProgramType { + type Error = ProgramError; + + fn try_from(prog_type: bpf_prog_type) -> Result { + 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), + }) + } +} diff --git a/aya/src/programs/mod.rs b/aya/src/programs/mod.rs index 898070e5..d0ce82d9 100644 --- a/aya/src/programs/mod.rs +++ b/aya/src/programs/mod.rs @@ -37,6 +37,7 @@ //! [`maps`]: crate::maps // modules we don't export +mod info; mod probe; mod utils; @@ -71,13 +72,13 @@ pub mod xdp; use std::{ ffi::CString, io, - num::NonZeroU32, os::fd::{AsFd, AsRawFd, BorrowedFd}, path::{Path, PathBuf}, sync::Arc, - time::{Duration, SystemTime}, }; +use info::impl_info; +pub use info::{loaded_programs, ProgramInfo, ProgramType}; use libc::ENOSPC; use thiserror::Error; @@ -115,18 +116,13 @@ use crate::{ maps::MapError, obj::{self, btf::BtfError, VerifierLog}, pin::PinError, - programs::{ - links::*, - perf_attach::*, - utils::{boot_time, get_fdinfo}, - }, + programs::{links::*, perf_attach::*}, sys::{ bpf_btf_get_fd_by_id, bpf_get_object, bpf_link_get_fd_by_id, bpf_link_get_info_by_fd, - bpf_load_program, bpf_pin_object, bpf_prog_get_fd_by_id, bpf_prog_get_info_by_fd, - bpf_prog_query, iter_link_ids, iter_prog_ids, retry_with_verifier_logs, - EbpfLoadProgramAttrs, SyscallError, + bpf_load_program, bpf_pin_object, bpf_prog_get_fd_by_id, bpf_prog_query, iter_link_ids, + retry_with_verifier_logs, EbpfLoadProgramAttrs, SyscallError, }, - util::{bytes_of_bpf_name, KernelVersion}, + util::KernelVersion, VerifierLogLevel, }; @@ -242,7 +238,7 @@ impl AsFd for ProgramFd { } } -/// eBPF program type. +/// The various eBPF programs. #[derive(Debug)] pub enum Program { /// A [`KProbe`] program @@ -296,34 +292,30 @@ pub enum Program { } impl Program { - /// Returns the low level program type. - pub fn prog_type(&self) -> bpf_prog_type { - use crate::generated::bpf_prog_type::*; + /// Returns the program type. + pub fn prog_type(&self) -> ProgramType { match self { - Self::KProbe(_) => BPF_PROG_TYPE_KPROBE, - Self::UProbe(_) => BPF_PROG_TYPE_KPROBE, - Self::TracePoint(_) => BPF_PROG_TYPE_TRACEPOINT, - Self::SocketFilter(_) => BPF_PROG_TYPE_SOCKET_FILTER, - Self::Xdp(_) => BPF_PROG_TYPE_XDP, - Self::SkMsg(_) => BPF_PROG_TYPE_SK_MSG, - Self::SkSkb(_) => BPF_PROG_TYPE_SK_SKB, - Self::SockOps(_) => BPF_PROG_TYPE_SOCK_OPS, - Self::SchedClassifier(_) => BPF_PROG_TYPE_SCHED_CLS, - Self::CgroupSkb(_) => BPF_PROG_TYPE_CGROUP_SKB, - Self::CgroupSysctl(_) => BPF_PROG_TYPE_CGROUP_SYSCTL, - Self::CgroupSockopt(_) => BPF_PROG_TYPE_CGROUP_SOCKOPT, - Self::LircMode2(_) => BPF_PROG_TYPE_LIRC_MODE2, - Self::PerfEvent(_) => BPF_PROG_TYPE_PERF_EVENT, - Self::RawTracePoint(_) => BPF_PROG_TYPE_RAW_TRACEPOINT, - Self::Lsm(_) => BPF_PROG_TYPE_LSM, - Self::BtfTracePoint(_) => BPF_PROG_TYPE_TRACING, - Self::FEntry(_) => BPF_PROG_TYPE_TRACING, - Self::FExit(_) => BPF_PROG_TYPE_TRACING, - Self::Extension(_) => BPF_PROG_TYPE_EXT, - Self::CgroupSockAddr(_) => BPF_PROG_TYPE_CGROUP_SOCK_ADDR, - Self::SkLookup(_) => BPF_PROG_TYPE_SK_LOOKUP, - Self::CgroupSock(_) => BPF_PROG_TYPE_CGROUP_SOCK, - Self::CgroupDevice(_) => BPF_PROG_TYPE_CGROUP_DEVICE, + Self::KProbe(_) | Self::UProbe(_) => ProgramType::KProbe, + Self::TracePoint(_) => ProgramType::TracePoint, + Self::SocketFilter(_) => ProgramType::SocketFilter, + Self::Xdp(_) => ProgramType::Xdp, + Self::SkMsg(_) => ProgramType::SkMsg, + Self::SkSkb(_) => ProgramType::SkSkb, + Self::SockOps(_) => ProgramType::SockOps, + Self::SchedClassifier(_) => ProgramType::SchedClassifier, + Self::CgroupSkb(_) => ProgramType::CgroupSkb, + Self::CgroupSysctl(_) => ProgramType::CgroupSysctl, + Self::CgroupSockopt(_) => ProgramType::CgroupSockopt, + Self::LircMode2(_) => ProgramType::LircMode2, + Self::PerfEvent(_) => ProgramType::PerfEvent, + Self::RawTracePoint(_) => ProgramType::RawTracePoint, + Self::Lsm(_) => ProgramType::Lsm, + Self::BtfTracePoint(_) | Self::FEntry(_) | Self::FExit(_) => ProgramType::Tracing, + Self::Extension(_) => ProgramType::Extension, + Self::CgroupSockAddr(_) => ProgramType::CgroupSockAddr, + Self::SkLookup(_) => ProgramType::SkLookup, + Self::CgroupSock(_) => ProgramType::CgroupSock, + Self::CgroupDevice(_) => ProgramType::CgroupDevice, } } @@ -952,26 +944,6 @@ impl_try_from_program!( CgroupDevice, ); -/// 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 [`Program`] to it's corresponding [`ProgramInfo`] -/// metadata. -macro_rules! impl_info { - ($($struct_name:ident),+ $(,)?) => { - $( - impl $struct_name { - /// Returns the file descriptor of this Program. - pub fn info(&self) -> Result { - let ProgramFd(fd) = self.fd()?; - - ProgramInfo::new_from_fd(fd.as_fd()) - } - } - )+ - } -} - impl_info!( KProbe, UProbe, @@ -999,180 +971,6 @@ impl_info!( CgroupDevice, ); -/// Provides information about a loaded program, like name, id and statistics -#[doc(alias = "bpf_prog_info")] -#[derive(Debug)] -pub struct ProgramInfo(bpf_prog_info); - -impl ProgramInfo { - fn new_from_fd(fd: BorrowedFd<'_>) -> Result { - let info = bpf_prog_get_info_by_fd(fd, &mut [])?; - Ok(Self(info)) - } - - /// The name of the program as was provided when it was load. This is limited to 16 bytes - pub fn name(&self) -> &[u8] { - bytes_of_bpf_name(&self.0.name) - } - - /// The name of the program as a &str. If the name was not valid unicode, None is returned. - pub fn name_as_str(&self) -> Option<&str> { - std::str::from_utf8(self.name()).ok() - } - - /// The id for this program. Each program has a unique id. - pub fn id(&self) -> u32 { - self.0.id - } - - /// The program tag. - /// - /// The program 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. - pub fn tag(&self) -> u64 { - u64::from_be_bytes(self.0.tag) - } - - /// The program type as defined by the linux kernel enum - /// [`bpf_prog_type`](https://elixir.bootlin.com/linux/v6.4.4/source/include/uapi/linux/bpf.h#L948). - pub fn program_type(&self) -> u32 { - self.0.type_ - } - - /// Returns true if the program is defined with a GPL-compatible license. - pub fn gpl_compatible(&self) -> bool { - self.0.gpl_compatible() != 0 - } - - /// The ids of the maps used by the program. - pub fn map_ids(&self) -> Result, ProgramError> { - let ProgramFd(fd) = self.fd()?; - let mut map_ids = vec![0u32; self.0.nr_map_ids as usize]; - - bpf_prog_get_info_by_fd(fd.as_fd(), &mut map_ids)?; - - Ok(map_ids) - } - - /// The btf id for the program. - pub fn btf_id(&self) -> Option { - NonZeroU32::new(self.0.btf_id) - } - - /// The size in bytes of the program's translated eBPF bytecode, which is - /// the bytecode after it has been passed though the verifier where it was - /// possibly modified by the kernel. - pub fn size_translated(&self) -> u32 { - self.0.xlated_prog_len - } - - /// The size in bytes of the program's JIT-compiled machine code. - pub fn size_jitted(&self) -> u32 { - self.0.jited_prog_len - } - - /// How much memory in bytes has been allocated and locked for the program. - pub fn memory_locked(&self) -> Result { - get_fdinfo(self.fd()?.as_fd(), "memlock") - } - - /// 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. - pub fn verified_instruction_count(&self) -> u32 { - self.0.verified_insns - } - - /// The time the program was loaded. - pub fn loaded_at(&self) -> SystemTime { - boot_time() + Duration::from_nanos(self.0.load_time) - } - - /// 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. - pub fn fd(&self) -> Result { - let Self(info) = self; - let fd = bpf_prog_get_fd_by_id(info.id)?; - Ok(ProgramFd(fd)) - } - - /// 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). - 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). - pub fn run_count(&self) -> u64 { - self.0.run_cnt - } - - /// Loads a program from a pinned path in bpffs. - pub fn from_pin>(path: P) -> Result { - 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, - })?; - - let info = bpf_prog_get_info_by_fd(fd.as_fd(), &mut [])?; - Ok(Self(info)) - } -} - -/// Returns an iterator over all loaded bpf programs. -/// -/// This differs from [`crate::Ebpf::programs`] since it will return all programs -/// listed on the host system and not only programs a specific [`crate::Ebpf`] instance. -/// -/// # 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> { - 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)) -} - // TODO(https://github.com/aya-rs/aya/issues/645): this API is currently used in tests. Stabilize // and remove doc(hidden). #[doc(hidden)] diff --git a/aya/src/sys/bpf.rs b/aya/src/sys/bpf.rs index 01bad1a3..8d07b70c 100644 --- a/aya/src/sys/bpf.rs +++ b/aya/src/sys/bpf.rs @@ -32,7 +32,7 @@ use crate::{ }, sys::{syscall, SysResult, Syscall, SyscallError}, util::KernelVersion, - Btf, Pod, VerifierLogLevel, BPF_OBJ_NAME_LEN, + Btf, Pod, VerifierLogLevel, BPF_OBJ_NAME_LEN, FEATURES, }; pub(crate) fn bpf_create_map( @@ -105,6 +105,7 @@ pub(crate) fn bpf_pin_object(fd: BorrowedFd<'_>, path: &CStr) -> SysResult sys_bpf(bpf_cmd::BPF_OBJ_PIN, &mut attr) } +/// Introduced in kernel v4.4. pub(crate) fn bpf_get_object(path: &CStr) -> SysResult { let mut attr = unsafe { mem::zeroed::() }; let u = unsafe { &mut attr.__bindgen_anon_4 }; @@ -499,6 +500,7 @@ pub(crate) fn bpf_prog_query( ret } +/// Introduced in kernel v4.13. pub(crate) fn bpf_prog_get_fd_by_id(prog_id: u32) -> Result { let mut attr = unsafe { mem::zeroed::() }; @@ -513,6 +515,7 @@ pub(crate) fn bpf_prog_get_fd_by_id(prog_id: u32) -> Result( fd: BorrowedFd<'_>, init: F, @@ -541,16 +544,22 @@ fn bpf_obj_get_info_by_fd( } } +/// Introduced in kernel v4.13. pub(crate) fn bpf_prog_get_info_by_fd( fd: BorrowedFd<'_>, map_ids: &mut [u32], ) -> Result { + // An `E2BIG` error can occur on kernels below v4.15 when handing over a large struct where the + // extra space is not all-zero bytes. bpf_obj_get_info_by_fd(fd, |info: &mut bpf_prog_info| { - info.nr_map_ids = map_ids.len() as _; - info.map_ids = map_ids.as_mut_ptr() as _; + if FEATURES.prog_info_map_ids() { + info.nr_map_ids = map_ids.len() as _; + info.map_ids = map_ids.as_mut_ptr() as _; + } }) } +/// Introduced in kernel v4.13. pub(crate) fn bpf_map_get_fd_by_id(map_id: u32) -> Result { let mut attr = unsafe { mem::zeroed::() }; @@ -694,6 +703,62 @@ pub(crate) fn is_prog_name_supported() -> bool { bpf_prog_load(&mut attr).is_ok() } +/// Tests whether `nr_map_ids` & `map_ids` fields in `bpf_prog_info` is available. +pub(crate) fn is_info_map_ids_supported() -> bool { + let mut attr = unsafe { mem::zeroed::() }; + let u = unsafe { &mut attr.__bindgen_anon_3 }; + + u.prog_type = bpf_prog_type::BPF_PROG_TYPE_SOCKET_FILTER as u32; + + let prog: &[u8] = &[ + 0xb7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov64 r0 = 0 + 0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // exit + ]; + let insns = copy_instructions(prog).unwrap(); + u.insn_cnt = insns.len() as u32; + u.insns = insns.as_ptr() as u64; + + let gpl = b"GPL\0"; + u.license = gpl.as_ptr() as u64; + + let prog_fd = match bpf_prog_load(&mut attr) { + Ok(fd) => fd, + Err(_) => return false, + }; + bpf_obj_get_info_by_fd(prog_fd.as_fd(), |info: &mut bpf_prog_info| { + info.nr_map_ids = 1 + }) + .is_ok() +} + +/// Tests whether `gpl_compatible` field in `bpf_prog_info` is available. +pub(crate) fn is_info_gpl_compatible_supported() -> bool { + let mut attr = unsafe { mem::zeroed::() }; + let u = unsafe { &mut attr.__bindgen_anon_3 }; + + u.prog_type = bpf_prog_type::BPF_PROG_TYPE_SOCKET_FILTER as u32; + + let prog: &[u8] = &[ + 0xb7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov64 r0 = 0 + 0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // exit + ]; + let insns = copy_instructions(prog).unwrap(); + u.insn_cnt = insns.len() as u32; + u.insns = insns.as_ptr() as u64; + + let gpl = b"GPL\0"; + u.license = gpl.as_ptr() as u64; + + let prog_fd = match bpf_prog_load(&mut attr) { + Ok(fd) => fd, + Err(_) => return false, + }; + if let Ok::(info) = bpf_obj_get_info_by_fd(prog_fd.as_fd(), |_| {}) { + return info.gpl_compatible() != 0; + } + false +} + pub(crate) fn is_probe_read_kernel_supported() -> bool { let mut attr = unsafe { mem::zeroed::() }; let u = unsafe { &mut attr.__bindgen_anon_3 }; @@ -1093,6 +1158,7 @@ fn iter_obj_ids( }) } +/// Introduced in kernel v4.13. pub(crate) fn iter_prog_ids() -> impl Iterator> { iter_obj_ids(bpf_cmd::BPF_PROG_GET_NEXT_ID, "bpf_prog_get_next_id") } @@ -1101,6 +1167,7 @@ pub(crate) fn iter_link_ids() -> impl Iterator> iter_obj_ids(bpf_cmd::BPF_LINK_GET_NEXT_ID, "bpf_link_get_next_id") } +/// Introduced in kernel v4.13. pub(crate) fn iter_map_ids() -> impl Iterator> { iter_obj_ids(bpf_cmd::BPF_MAP_GET_NEXT_ID, "bpf_map_get_next_id") } diff --git a/aya/src/util.rs b/aya/src/util.rs index 17371460..18de6002 100644 --- a/aya/src/util.rs +++ b/aya/src/util.rs @@ -3,6 +3,7 @@ use std::{ collections::BTreeMap, error::Error, ffi::{CStr, CString}, + fmt::Display, fs::{self, File}, io::{self, BufRead, BufReader}, mem, @@ -177,6 +178,12 @@ impl KernelVersion { } } +impl Display for KernelVersion { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}.{}.{}", self.major, self.minor, self.patch) + } +} + const ONLINE_CPUS: &str = "/sys/devices/system/cpu/online"; pub(crate) const POSSIBLE_CPUS: &str = "/sys/devices/system/cpu/possible"; diff --git a/test/integration-ebpf/Cargo.toml b/test/integration-ebpf/Cargo.toml index 2c5e7b2e..a69595da 100644 --- a/test/integration-ebpf/Cargo.toml +++ b/test/integration-ebpf/Cargo.toml @@ -64,3 +64,7 @@ path = "src/ring_buf.rs" [[bin]] name = "memmove_test" path = "src/memmove_test.rs" + +[[bin]] +name = "simple_prog" +path = "src/simple_prog.rs" diff --git a/test/integration-ebpf/src/map_test.rs b/test/integration-ebpf/src/map_test.rs index 242207b8..e3fc28bc 100644 --- a/test/integration-ebpf/src/map_test.rs +++ b/test/integration-ebpf/src/map_test.rs @@ -1,29 +1,34 @@ +// Socket Filter program for testing with an arbitrary program with maps. +// This is mainly used in tests with consideration for old kernels. + #![no_std] #![no_main] use aya_ebpf::{ - bindings::xdp_action, - macros::{map, xdp}, - maps::Array, - programs::XdpContext, + macros::{map, socket_filter}, + maps::{Array, HashMap}, + programs::SkBuffContext, }; +// Introduced in kernel v3.19. #[map] static FOO: Array = Array::::with_max_entries(10, 0); +// Introduced in kernel v3.19. #[map(name = "BAR")] -static BAZ: Array = Array::::with_max_entries(10, 0); +static BAZ: HashMap = HashMap::::with_max_entries(8, 0); -#[xdp(frags)] -pub fn pass(ctx: XdpContext) -> u32 { - match unsafe { try_pass(ctx) } { - Ok(ret) => ret, - Err(_) => xdp_action::XDP_ABORTED, - } -} +// Introduced in kernel v3.19. +#[socket_filter] +pub fn simple_prog(_ctx: SkBuffContext) -> i64 { + // So that these maps show up under the `map_ids` field. + FOO.get(0); + // If we use the literal value `0` instead of the local variable `i`, then an additional + // `.rodata` map will be associated with the program. + let i = 0; + BAZ.get_ptr(&i); -unsafe fn try_pass(_ctx: XdpContext) -> Result { - Ok(xdp_action::XDP_PASS) + 0 } #[cfg(not(test))] diff --git a/test/integration-ebpf/src/simple_prog.rs b/test/integration-ebpf/src/simple_prog.rs new file mode 100644 index 00000000..98725dce --- /dev/null +++ b/test/integration-ebpf/src/simple_prog.rs @@ -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 {} +} diff --git a/test/integration-test/src/lib.rs b/test/integration-test/src/lib.rs index 4b55f3a1..fc31e6c2 100644 --- a/test/integration-test/src/lib.rs +++ b/test/integration-test/src/lib.rs @@ -23,6 +23,7 @@ pub const REDIRECT: &[u8] = include_bytes_aligned!(concat!(env!("OUT_DIR"), "/re pub const XDP_SEC: &[u8] = include_bytes_aligned!(concat!(env!("OUT_DIR"), "/xdp_sec")); pub const RING_BUF: &[u8] = include_bytes_aligned!(concat!(env!("OUT_DIR"), "/ring_buf")); pub const MEMMOVE_TEST: &[u8] = include_bytes_aligned!(concat!(env!("OUT_DIR"), "/memmove_test")); +pub const SIMPLE_PROG: &[u8] = include_bytes_aligned!(concat!(env!("OUT_DIR"), "/simple_prog")); #[cfg(test)] mod tests; diff --git a/test/integration-test/src/tests.rs b/test/integration-test/src/tests.rs index f37d54bb..db99e095 100644 --- a/test/integration-test/src/tests.rs +++ b/test/integration-test/src/tests.rs @@ -1,6 +1,7 @@ mod bpf_probe_read; mod btf_relocations; mod elf; +mod info; mod load; mod log; mod rbpf; diff --git a/test/integration-test/src/tests/info.rs b/test/integration-test/src/tests/info.rs new file mode 100644 index 00000000..e90b31b1 --- /dev/null +++ b/test/integration-test/src/tests/info.rs @@ -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); + 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() +} diff --git a/test/integration-test/src/tests/load.rs b/test/integration-test/src/tests/load.rs index 8ff13757..60025092 100644 --- a/test/integration-test/src/tests/load.rs +++ b/test/integration-test/src/tests/load.rs @@ -1,10 +1,4 @@ -use std::{ - convert::TryInto as _, - fs::remove_file, - path::Path, - thread, - time::{Duration, SystemTime}, -}; +use std::{convert::TryInto as _, fs::remove_file, path::Path, thread, time::Duration}; use aya::{ maps::Array, @@ -144,7 +138,7 @@ fn poll_loaded_program_id(name: &str) -> impl Iterator> + '_ // program in the middle of a `loaded_programs()` call. loaded_programs() .filter_map(|prog| prog.ok()) - .find_map(|prog| (prog.name() == name.as_bytes()).then(|| prog.id())) + .find_map(|prog| (prog.name() == name.as_bytes()).then(|| prog.id().unwrap().get())) }) } @@ -221,42 +215,6 @@ fn unload_xdp() { assert_unloaded("pass"); } -#[test] -fn test_loaded_at() { - let mut bpf = Ebpf::load(crate::TEST).unwrap(); - let prog: &mut Xdp = bpf.program_mut("pass").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 = prog.info().unwrap().loaded_at(); - 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); - 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 unload_kprobe() { let mut bpf = Ebpf::load(crate::TEST).unwrap(); diff --git a/test/integration-test/src/tests/smoke.rs b/test/integration-test/src/tests/smoke.rs index b5bb30a2..0d57aea9 100644 --- a/test/integration-test/src/tests/smoke.rs +++ b/test/integration-test/src/tests/smoke.rs @@ -1,6 +1,5 @@ use aya::{ - maps::loaded_maps, - programs::{loaded_programs, Extension, TracePoint, Xdp, XdpFlags}, + programs::{Extension, TracePoint, Xdp, XdpFlags}, util::KernelVersion, Ebpf, EbpfLoader, }; @@ -70,59 +69,3 @@ fn extension() { .load(pass.fd().unwrap().try_clone().unwrap(), "xdp_pass") .unwrap(); } - -#[test] -fn list_loaded_programs() { - // Load a program. - let mut bpf = Ebpf::load(crate::PASS).unwrap(); - let dispatcher: &mut Xdp = bpf.program_mut("pass").unwrap().try_into().unwrap(); - dispatcher.load().unwrap(); - dispatcher.attach("lo", XdpFlags::default()).unwrap(); - - // Ensure the loaded_programs() api doesn't panic. - let prog = loaded_programs() - .map(|p| p.unwrap()) - .find(|p| p.name_as_str().unwrap() == "pass") - .unwrap(); - - // Ensure all relevant helper functions don't panic. - prog.name(); - prog.id(); - prog.tag(); - prog.program_type(); - prog.gpl_compatible(); - prog.map_ids().unwrap(); - prog.btf_id(); - prog.size_translated(); - prog.memory_locked().unwrap(); - prog.verified_instruction_count(); - prog.loaded_at(); - prog.fd().unwrap(); - prog.run_time(); - prog.run_count(); -} - -#[test] -fn list_loaded_maps() { - // Load a program with maps. - let mut bpf = Ebpf::load(crate::MAP_TEST).unwrap(); - let dispatcher: &mut Xdp = bpf.program_mut("pass").unwrap().try_into().unwrap(); - dispatcher.load().unwrap(); - dispatcher.attach("lo", XdpFlags::default()).unwrap(); - - // Ensure the loaded_maps() api doesn't panic and retrieve a map. - let map = loaded_maps() - .map(|m| m.unwrap()) - .find(|m| m.name_as_str().unwrap() == "FOO") - .unwrap(); - - // Ensure all relevant helper functions don't panic. - map.name(); - map.id(); - map.map_type(); - map.key_size(); - map.value_size(); - map.max_entries(); - map.map_flags(); - map.fd().unwrap(); -} diff --git a/test/integration-test/src/utils.rs b/test/integration-test/src/utils.rs index 28b68d4a..27c41ad8 100644 --- a/test/integration-test/src/utils.rs +++ b/test/integration-test/src/utils.rs @@ -70,3 +70,62 @@ impl Drop for NetNsGuard { println!("Exited network namespace {}", self.name); } } + +/// Performs `assert!` macro. If the assertion fails and host kernel version +/// is above feature version, then fail test. +macro_rules! kernel_assert { + ($cond:expr, $version:expr $(,)?) => { + let pass: bool = $cond; + if !pass { + let feat_version: aya::util::KernelVersion = $version; + let current = aya::util::KernelVersion::current().unwrap(); + let cond_literal = stringify!($cond); + if current >= feat_version { + // Host kernel is expected to have the feat but does not + panic!( + r#" assertion `{cond_literal}` failed: expected host kernel v{current} to have v{feat_version} feature"#, + ); + } else { + // Continue with tests since host is not expected to have feat + eprintln!( + r#"ignoring assertion at {}:{} + assertion `{cond_literal}` failed: continuing since host kernel v{current} is not expected to have v{feat_version} feature"#, + file!(), line!(), + ); + } + } + }; +} + +pub(crate) use kernel_assert; + +/// Performs `assert_eq!` macro. If the assertion fails and host kernel version +/// is above feature version, then fail test. +macro_rules! kernel_assert_eq { + ($left:expr, $right:expr, $version:expr $(,)?) => { + if $left != $right { + let feat_version: aya::util::KernelVersion = $version; + let current = aya::util::KernelVersion::current().unwrap(); + if current >= feat_version { + // Host kernel is expected to have the feat but does not + panic!( + r#" assertion `left == right` failed: expected host kernel v{current} to have v{feat_version} feature + left: {:?} + right: {:?}"#, + $left, $right, + ); + } else { + // Continue with tests since host is not expected to have feat + eprintln!( + r#"ignoring assertion at {}:{} + assertion `left == right` failed: continuing since host kernel v{current} is not expected to have v{feat_version} feature + left: {:?} + right: {:?}"#, + file!(), line!(), $left, $right, + ); + } + } + }; +} + +pub(crate) use kernel_assert_eq; diff --git a/xtask/public-api/aya-obj.txt b/xtask/public-api/aya-obj.txt index 10e93ce2..f46d106f 100644 --- a/xtask/public-api/aya-obj.txt +++ b/xtask/public-api/aya-obj.txt @@ -1458,6 +1458,9 @@ impl core::convert::From aya_obj::generated::bpf_attach_type impl core::convert::From for aya_obj::generated::bpf_attach_type pub fn aya_obj::generated::bpf_attach_type::from(value: aya_obj::programs::xdp::XdpAttachType) -> Self +impl core::convert::TryFrom for aya_obj::generated::bpf_attach_type +pub type aya_obj::generated::bpf_attach_type::Error = aya_obj::InvalidTypeBinding +pub fn aya_obj::generated::bpf_attach_type::try_from(attach_type: u32) -> core::result::Result impl core::fmt::Debug for aya_obj::generated::bpf_attach_type pub fn aya_obj::generated::bpf_attach_type::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result impl core::hash::Hash for aya_obj::generated::bpf_attach_type @@ -1593,6 +1596,9 @@ pub fn aya_obj::generated::bpf_link_type::clone(&self) -> aya_obj::generated::bp impl core::cmp::Eq for aya_obj::generated::bpf_link_type impl core::cmp::PartialEq for aya_obj::generated::bpf_link_type pub fn aya_obj::generated::bpf_link_type::eq(&self, other: &aya_obj::generated::bpf_link_type) -> bool +impl core::convert::TryFrom for aya_obj::generated::bpf_link_type +pub type aya_obj::generated::bpf_link_type::Error = aya_obj::InvalidTypeBinding +pub fn aya_obj::generated::bpf_link_type::try_from(link_type: u32) -> core::result::Result impl core::fmt::Debug for aya_obj::generated::bpf_link_type pub fn aya_obj::generated::bpf_link_type::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result impl core::hash::Hash for aya_obj::generated::bpf_link_type @@ -1673,7 +1679,7 @@ impl core::cmp::Eq for aya_obj::generated::bpf_map_type impl core::cmp::PartialEq for aya_obj::generated::bpf_map_type pub fn aya_obj::generated::bpf_map_type::eq(&self, other: &aya_obj::generated::bpf_map_type) -> bool impl core::convert::TryFrom for aya_obj::generated::bpf_map_type -pub type aya_obj::generated::bpf_map_type::Error = aya_obj::maps::InvalidMapTypeError +pub type aya_obj::generated::bpf_map_type::Error = aya_obj::InvalidTypeBinding pub fn aya_obj::generated::bpf_map_type::try_from(map_type: u32) -> core::result::Result impl core::fmt::Debug for aya_obj::generated::bpf_map_type pub fn aya_obj::generated::bpf_map_type::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result @@ -1749,6 +1755,9 @@ pub fn aya_obj::generated::bpf_prog_type::clone(&self) -> aya_obj::generated::bp impl core::cmp::Eq for aya_obj::generated::bpf_prog_type impl core::cmp::PartialEq for aya_obj::generated::bpf_prog_type pub fn aya_obj::generated::bpf_prog_type::eq(&self, other: &aya_obj::generated::bpf_prog_type) -> bool +impl core::convert::TryFrom for aya_obj::generated::bpf_prog_type +pub type aya_obj::generated::bpf_prog_type::Error = aya_obj::InvalidTypeBinding +pub fn aya_obj::generated::bpf_prog_type::try_from(prog_type: u32) -> core::result::Result impl core::fmt::Debug for aya_obj::generated::bpf_prog_type pub fn aya_obj::generated::bpf_prog_type::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result impl core::hash::Hash for aya_obj::generated::bpf_prog_type @@ -6603,6 +6612,7 @@ pub type aya_obj::generated::_bindgen_ty_7 = core::ffi::c_uint pub type aya_obj::generated::_bindgen_ty_8 = core::ffi::c_uint pub type aya_obj::generated::_bindgen_ty_9 = core::ffi::c_uint pub type aya_obj::generated::_bindgen_ty_92 = core::ffi::c_uint +pub mod aya_obj::links pub mod aya_obj::maps pub enum aya_obj::maps::Map pub aya_obj::maps::Map::Btf(aya_obj::maps::BtfMap) @@ -6806,30 +6816,6 @@ impl core::clone::CloneToUninit for aya_obj::maps::BtfMapDef where T: core::c pub unsafe fn aya_obj::maps::BtfMapDef::clone_to_uninit(&self, dst: *mut T) impl core::convert::From for aya_obj::maps::BtfMapDef pub fn aya_obj::maps::BtfMapDef::from(t: T) -> T -pub struct aya_obj::maps::InvalidMapTypeError -pub aya_obj::maps::InvalidMapTypeError::map_type: u32 -impl core::marker::Freeze for aya_obj::maps::InvalidMapTypeError -impl core::marker::Send for aya_obj::maps::InvalidMapTypeError -impl core::marker::Sync for aya_obj::maps::InvalidMapTypeError -impl core::marker::Unpin for aya_obj::maps::InvalidMapTypeError -impl core::panic::unwind_safe::RefUnwindSafe for aya_obj::maps::InvalidMapTypeError -impl core::panic::unwind_safe::UnwindSafe for aya_obj::maps::InvalidMapTypeError -impl core::convert::Into for aya_obj::maps::InvalidMapTypeError where U: core::convert::From -pub fn aya_obj::maps::InvalidMapTypeError::into(self) -> U -impl core::convert::TryFrom for aya_obj::maps::InvalidMapTypeError where U: core::convert::Into -pub type aya_obj::maps::InvalidMapTypeError::Error = core::convert::Infallible -pub fn aya_obj::maps::InvalidMapTypeError::try_from(value: U) -> core::result::Result>::Error> -impl core::convert::TryInto for aya_obj::maps::InvalidMapTypeError where U: core::convert::TryFrom -pub type aya_obj::maps::InvalidMapTypeError::Error = >::Error -pub fn aya_obj::maps::InvalidMapTypeError::try_into(self) -> core::result::Result>::Error> -impl core::any::Any for aya_obj::maps::InvalidMapTypeError where T: 'static + core::marker::Sized -pub fn aya_obj::maps::InvalidMapTypeError::type_id(&self) -> core::any::TypeId -impl core::borrow::Borrow for aya_obj::maps::InvalidMapTypeError where T: core::marker::Sized -pub fn aya_obj::maps::InvalidMapTypeError::borrow(&self) -> &T -impl core::borrow::BorrowMut for aya_obj::maps::InvalidMapTypeError where T: core::marker::Sized -pub fn aya_obj::maps::InvalidMapTypeError::borrow_mut(&mut self) -> &mut T -impl core::convert::From for aya_obj::maps::InvalidMapTypeError -pub fn aya_obj::maps::InvalidMapTypeError::from(t: T) -> T pub struct aya_obj::maps::LegacyMap pub aya_obj::maps::LegacyMap::data: alloc::vec::Vec pub aya_obj::maps::LegacyMap::def: aya_obj::maps::bpf_map_def @@ -7123,6 +7109,8 @@ pub fn aya_obj::Features::bpf_probe_read_kernel(&self) -> bool pub fn aya_obj::Features::btf(&self) -> core::option::Option<&aya_obj::btf::BtfFeatures> pub fn aya_obj::Features::cpumap_prog_id(&self) -> bool pub fn aya_obj::Features::devmap_prog_id(&self) -> bool +pub fn aya_obj::Features::prog_info_gpl_compatible(&self) -> bool +pub fn aya_obj::Features::prog_info_map_ids(&self) -> bool impl core::default::Default for aya_obj::Features pub fn aya_obj::Features::default() -> aya_obj::Features impl core::fmt::Debug for aya_obj::Features @@ -7191,6 +7179,30 @@ impl core::clone::CloneToUninit for aya_obj::Function where T: core::clone::C pub unsafe fn aya_obj::Function::clone_to_uninit(&self, dst: *mut T) impl core::convert::From for aya_obj::Function pub fn aya_obj::Function::from(t: T) -> T +pub struct aya_obj::obj::InvalidTypeBinding +pub aya_obj::obj::InvalidTypeBinding::value: T +impl core::marker::Freeze for aya_obj::InvalidTypeBinding where T: core::marker::Freeze +impl core::marker::Send for aya_obj::InvalidTypeBinding where T: core::marker::Send +impl core::marker::Sync for aya_obj::InvalidTypeBinding where T: core::marker::Sync +impl core::marker::Unpin for aya_obj::InvalidTypeBinding where T: core::marker::Unpin +impl core::panic::unwind_safe::RefUnwindSafe for aya_obj::InvalidTypeBinding where T: core::panic::unwind_safe::RefUnwindSafe +impl core::panic::unwind_safe::UnwindSafe for aya_obj::InvalidTypeBinding where T: core::panic::unwind_safe::UnwindSafe +impl core::convert::Into for aya_obj::InvalidTypeBinding where U: core::convert::From +pub fn aya_obj::InvalidTypeBinding::into(self) -> U +impl core::convert::TryFrom for aya_obj::InvalidTypeBinding where U: core::convert::Into +pub type aya_obj::InvalidTypeBinding::Error = core::convert::Infallible +pub fn aya_obj::InvalidTypeBinding::try_from(value: U) -> core::result::Result>::Error> +impl core::convert::TryInto for aya_obj::InvalidTypeBinding where U: core::convert::TryFrom +pub type aya_obj::InvalidTypeBinding::Error = >::Error +pub fn aya_obj::InvalidTypeBinding::try_into(self) -> core::result::Result>::Error> +impl core::any::Any for aya_obj::InvalidTypeBinding where T: 'static + core::marker::Sized +pub fn aya_obj::InvalidTypeBinding::type_id(&self) -> core::any::TypeId +impl core::borrow::Borrow for aya_obj::InvalidTypeBinding where T: core::marker::Sized +pub fn aya_obj::InvalidTypeBinding::borrow(&self) -> &T +impl core::borrow::BorrowMut for aya_obj::InvalidTypeBinding where T: core::marker::Sized +pub fn aya_obj::InvalidTypeBinding::borrow_mut(&mut self) -> &mut T +impl core::convert::From for aya_obj::InvalidTypeBinding +pub fn aya_obj::InvalidTypeBinding::from(t: T) -> T pub struct aya_obj::obj::Object pub aya_obj::obj::Object::btf: core::option::Option pub aya_obj::obj::Object::btf_ext: core::option::Option @@ -7957,6 +7969,8 @@ pub fn aya_obj::Features::bpf_probe_read_kernel(&self) -> bool pub fn aya_obj::Features::btf(&self) -> core::option::Option<&aya_obj::btf::BtfFeatures> pub fn aya_obj::Features::cpumap_prog_id(&self) -> bool pub fn aya_obj::Features::devmap_prog_id(&self) -> bool +pub fn aya_obj::Features::prog_info_gpl_compatible(&self) -> bool +pub fn aya_obj::Features::prog_info_map_ids(&self) -> bool impl core::default::Default for aya_obj::Features pub fn aya_obj::Features::default() -> aya_obj::Features impl core::fmt::Debug for aya_obj::Features @@ -8025,6 +8039,30 @@ impl core::clone::CloneToUninit for aya_obj::Function where T: core::clone::C pub unsafe fn aya_obj::Function::clone_to_uninit(&self, dst: *mut T) impl core::convert::From for aya_obj::Function pub fn aya_obj::Function::from(t: T) -> T +pub struct aya_obj::InvalidTypeBinding +pub aya_obj::InvalidTypeBinding::value: T +impl core::marker::Freeze for aya_obj::InvalidTypeBinding where T: core::marker::Freeze +impl core::marker::Send for aya_obj::InvalidTypeBinding where T: core::marker::Send +impl core::marker::Sync for aya_obj::InvalidTypeBinding where T: core::marker::Sync +impl core::marker::Unpin for aya_obj::InvalidTypeBinding where T: core::marker::Unpin +impl core::panic::unwind_safe::RefUnwindSafe for aya_obj::InvalidTypeBinding where T: core::panic::unwind_safe::RefUnwindSafe +impl core::panic::unwind_safe::UnwindSafe for aya_obj::InvalidTypeBinding where T: core::panic::unwind_safe::UnwindSafe +impl core::convert::Into for aya_obj::InvalidTypeBinding where U: core::convert::From +pub fn aya_obj::InvalidTypeBinding::into(self) -> U +impl core::convert::TryFrom for aya_obj::InvalidTypeBinding where U: core::convert::Into +pub type aya_obj::InvalidTypeBinding::Error = core::convert::Infallible +pub fn aya_obj::InvalidTypeBinding::try_from(value: U) -> core::result::Result>::Error> +impl core::convert::TryInto for aya_obj::InvalidTypeBinding where U: core::convert::TryFrom +pub type aya_obj::InvalidTypeBinding::Error = >::Error +pub fn aya_obj::InvalidTypeBinding::try_into(self) -> core::result::Result>::Error> +impl core::any::Any for aya_obj::InvalidTypeBinding where T: 'static + core::marker::Sized +pub fn aya_obj::InvalidTypeBinding::type_id(&self) -> core::any::TypeId +impl core::borrow::Borrow for aya_obj::InvalidTypeBinding where T: core::marker::Sized +pub fn aya_obj::InvalidTypeBinding::borrow(&self) -> &T +impl core::borrow::BorrowMut for aya_obj::InvalidTypeBinding where T: core::marker::Sized +pub fn aya_obj::InvalidTypeBinding::borrow_mut(&mut self) -> &mut T +impl core::convert::From for aya_obj::InvalidTypeBinding +pub fn aya_obj::InvalidTypeBinding::from(t: T) -> T pub struct aya_obj::Object pub aya_obj::Object::btf: core::option::Option pub aya_obj::Object::btf_ext: core::option::Option diff --git a/xtask/public-api/aya.txt b/xtask/public-api/aya.txt index b47fc579..2b0c37fd 100644 --- a/xtask/public-api/aya.txt +++ b/xtask/public-api/aya.txt @@ -1371,8 +1371,8 @@ impl core::convert::From for aya::programs::ProgramError pub fn aya::programs::ProgramError::from(source: aya::maps::MapError) -> Self impl core::convert::From for aya::maps::MapError pub fn aya::maps::MapError::from(source: aya::sys::SyscallError) -> Self -impl core::convert::From for aya::maps::MapError -pub fn aya::maps::MapError::from(e: aya_obj::maps::InvalidMapTypeError) -> Self +impl core::convert::From> for aya::maps::MapError +pub fn aya::maps::MapError::from(e: aya_obj::obj::InvalidTypeBinding) -> Self impl core::convert::From for aya::maps::MapError pub fn aya::maps::MapError::from(source: std::io::error::Error) -> Self impl core::error::Error for aya::maps::MapError @@ -1405,6 +1405,80 @@ impl core::borrow::BorrowMut for aya::maps::MapError where T: core::marker pub fn aya::maps::MapError::borrow_mut(&mut self) -> &mut T impl core::convert::From for aya::maps::MapError pub fn aya::maps::MapError::from(t: T) -> T +#[non_exhaustive] pub enum aya::maps::MapType +pub aya::maps::MapType::Arena = 33 +pub aya::maps::MapType::Array = 2 +pub aya::maps::MapType::ArrayOfMaps = 12 +pub aya::maps::MapType::BloomFilter = 30 +pub aya::maps::MapType::CgroupArray = 8 +pub aya::maps::MapType::CgroupStorage = 19 +pub aya::maps::MapType::CgrpStorage = 32 +pub aya::maps::MapType::CpuMap = 16 +pub aya::maps::MapType::DevMap = 14 +pub aya::maps::MapType::DevMapHash = 25 +pub aya::maps::MapType::Hash = 1 +pub aya::maps::MapType::HashOfMaps = 13 +pub aya::maps::MapType::InodeStorage = 28 +pub aya::maps::MapType::LpmTrie = 11 +pub aya::maps::MapType::LruHash = 9 +pub aya::maps::MapType::LruPerCpuHash = 10 +pub aya::maps::MapType::PerCpuArray = 6 +pub aya::maps::MapType::PerCpuCgroupStorage = 21 +pub aya::maps::MapType::PerCpuHash = 5 +pub aya::maps::MapType::PerfEventArray = 4 +pub aya::maps::MapType::ProgramArray = 3 +pub aya::maps::MapType::Queue = 22 +pub aya::maps::MapType::ReuseportSockArray = 20 +pub aya::maps::MapType::RingBuf = 27 +pub aya::maps::MapType::SkStorage = 24 +pub aya::maps::MapType::SockHash = 18 +pub aya::maps::MapType::SockMap = 15 +pub aya::maps::MapType::Stack = 23 +pub aya::maps::MapType::StackTrace = 7 +pub aya::maps::MapType::StructOps = 26 +pub aya::maps::MapType::TaskStorage = 29 +pub aya::maps::MapType::Unspecified = 0 +pub aya::maps::MapType::UserRingBuf = 31 +pub aya::maps::MapType::XskMap = 17 +impl core::clone::Clone for aya::maps::MapType +pub fn aya::maps::MapType::clone(&self) -> aya::maps::MapType +impl core::cmp::PartialEq for aya::maps::MapType +pub fn aya::maps::MapType::eq(&self, other: &aya::maps::MapType) -> bool +impl core::convert::TryFrom for aya::maps::MapType +pub type aya::maps::MapType::Error = aya::maps::MapError +pub fn aya::maps::MapType::try_from(map_type: aya_obj::generated::linux_bindings_x86_64::bpf_map_type) -> core::result::Result +impl core::fmt::Debug for aya::maps::MapType +pub fn aya::maps::MapType::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +impl core::marker::Copy for aya::maps::MapType +impl core::marker::StructuralPartialEq for aya::maps::MapType +impl core::marker::Freeze for aya::maps::MapType +impl core::marker::Send for aya::maps::MapType +impl core::marker::Sync for aya::maps::MapType +impl core::marker::Unpin for aya::maps::MapType +impl core::panic::unwind_safe::RefUnwindSafe for aya::maps::MapType +impl core::panic::unwind_safe::UnwindSafe for aya::maps::MapType +impl core::convert::Into for aya::maps::MapType where U: core::convert::From +pub fn aya::maps::MapType::into(self) -> U +impl core::convert::TryFrom for aya::maps::MapType where U: core::convert::Into +pub type aya::maps::MapType::Error = core::convert::Infallible +pub fn aya::maps::MapType::try_from(value: U) -> core::result::Result>::Error> +impl core::convert::TryInto for aya::maps::MapType where U: core::convert::TryFrom +pub type aya::maps::MapType::Error = >::Error +pub fn aya::maps::MapType::try_into(self) -> core::result::Result>::Error> +impl alloc::borrow::ToOwned for aya::maps::MapType where T: core::clone::Clone +pub type aya::maps::MapType::Owned = T +pub fn aya::maps::MapType::clone_into(&self, target: &mut T) +pub fn aya::maps::MapType::to_owned(&self) -> T +impl core::any::Any for aya::maps::MapType where T: 'static + core::marker::Sized +pub fn aya::maps::MapType::type_id(&self) -> core::any::TypeId +impl core::borrow::Borrow for aya::maps::MapType where T: core::marker::Sized +pub fn aya::maps::MapType::borrow(&self) -> &T +impl core::borrow::BorrowMut for aya::maps::MapType where T: core::marker::Sized +pub fn aya::maps::MapType::borrow_mut(&mut self) -> &mut T +impl core::clone::CloneToUninit for aya::maps::MapType where T: core::clone::Clone +pub unsafe fn aya::maps::MapType::clone_to_uninit(&self, dst: *mut T) +impl core::convert::From for aya::maps::MapType +pub fn aya::maps::MapType::from(t: T) -> T pub struct aya::maps::Array impl, V: aya::Pod> aya::maps::array::Array pub fn aya::maps::array::Array::get(&self, index: &u32, flags: u64) -> core::result::Result @@ -1801,14 +1875,14 @@ impl aya::maps::MapInfo pub fn aya::maps::MapInfo::fd(&self) -> core::result::Result pub fn aya::maps::MapInfo::from_id(id: u32) -> core::result::Result pub fn aya::maps::MapInfo::from_pin>(path: P) -> core::result::Result -pub fn aya::maps::MapInfo::id(&self) -> u32 -pub fn aya::maps::MapInfo::key_size(&self) -> u32 +pub fn aya::maps::MapInfo::id(&self) -> core::option::Option +pub fn aya::maps::MapInfo::key_size(&self) -> core::option::Option pub fn aya::maps::MapInfo::map_flags(&self) -> u32 -pub fn aya::maps::MapInfo::map_type(&self) -> u32 -pub fn aya::maps::MapInfo::max_entries(&self) -> u32 +pub fn aya::maps::MapInfo::map_type(&self) -> core::result::Result +pub fn aya::maps::MapInfo::max_entries(&self) -> core::option::Option pub fn aya::maps::MapInfo::name(&self) -> &[u8] pub fn aya::maps::MapInfo::name_as_str(&self) -> core::option::Option<&str> -pub fn aya::maps::MapInfo::value_size(&self) -> u32 +pub fn aya::maps::MapInfo::value_size(&self) -> core::option::Option impl core::fmt::Debug for aya::maps::MapInfo pub fn aya::maps::MapInfo::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result impl core::marker::Freeze for aya::maps::MapInfo @@ -6644,7 +6718,7 @@ impl aya::programs::Program pub fn aya::programs::Program::fd(&self) -> core::result::Result<&aya::programs::ProgramFd, aya::programs::ProgramError> pub fn aya::programs::Program::info(&self) -> core::result::Result pub fn aya::programs::Program::pin>(&mut self, path: P) -> core::result::Result<(), aya::pin::PinError> -pub fn aya::programs::Program::prog_type(&self) -> aya_obj::generated::linux_bindings_x86_64::bpf_prog_type +pub fn aya::programs::Program::prog_type(&self) -> aya::programs::ProgramType pub fn aya::programs::Program::unload(self) -> core::result::Result<(), aya::programs::ProgramError> impl core::fmt::Debug for aya::programs::Program pub fn aya::programs::Program::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result @@ -6892,6 +6966,79 @@ impl core::borrow::BorrowMut for aya::programs::ProgramError where T: core pub fn aya::programs::ProgramError::borrow_mut(&mut self) -> &mut T impl core::convert::From for aya::programs::ProgramError pub fn aya::programs::ProgramError::from(t: T) -> T +#[non_exhaustive] pub enum aya::programs::ProgramType +pub aya::programs::ProgramType::CgroupDevice = 15 +pub aya::programs::ProgramType::CgroupSkb = 8 +pub aya::programs::ProgramType::CgroupSock = 9 +pub aya::programs::ProgramType::CgroupSockAddr = 18 +pub aya::programs::ProgramType::CgroupSockopt = 25 +pub aya::programs::ProgramType::CgroupSysctl = 23 +pub aya::programs::ProgramType::Extension = 28 +pub aya::programs::ProgramType::FlowDissector = 22 +pub aya::programs::ProgramType::KProbe = 2 +pub aya::programs::ProgramType::LircMode2 = 20 +pub aya::programs::ProgramType::Lsm = 29 +pub aya::programs::ProgramType::LwtInput = 10 +pub aya::programs::ProgramType::LwtOutput = 11 +pub aya::programs::ProgramType::LwtSeg6local = 19 +pub aya::programs::ProgramType::LwtXmit = 12 +pub aya::programs::ProgramType::Netfilter = 32 +pub aya::programs::ProgramType::PerfEvent = 7 +pub aya::programs::ProgramType::RawTracePoint = 17 +pub aya::programs::ProgramType::RawTracePointWritable = 24 +pub aya::programs::ProgramType::SchedAction = 4 +pub aya::programs::ProgramType::SchedClassifier = 3 +pub aya::programs::ProgramType::SkLookup = 30 +pub aya::programs::ProgramType::SkMsg = 16 +pub aya::programs::ProgramType::SkReuseport = 21 +pub aya::programs::ProgramType::SkSkb = 14 +pub aya::programs::ProgramType::SockOps = 13 +pub aya::programs::ProgramType::SocketFilter = 1 +pub aya::programs::ProgramType::StructOps = 27 +pub aya::programs::ProgramType::Syscall = 31 +pub aya::programs::ProgramType::TracePoint = 5 +pub aya::programs::ProgramType::Tracing = 26 +pub aya::programs::ProgramType::Unspecified = 0 +pub aya::programs::ProgramType::Xdp = 6 +impl core::clone::Clone for aya::programs::ProgramType +pub fn aya::programs::ProgramType::clone(&self) -> aya::programs::ProgramType +impl core::cmp::PartialEq for aya::programs::ProgramType +pub fn aya::programs::ProgramType::eq(&self, other: &aya::programs::ProgramType) -> bool +impl core::convert::TryFrom for aya::programs::ProgramType +pub type aya::programs::ProgramType::Error = aya::programs::ProgramError +pub fn aya::programs::ProgramType::try_from(prog_type: aya_obj::generated::linux_bindings_x86_64::bpf_prog_type) -> core::result::Result +impl core::fmt::Debug for aya::programs::ProgramType +pub fn aya::programs::ProgramType::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +impl core::marker::Copy for aya::programs::ProgramType +impl core::marker::StructuralPartialEq for aya::programs::ProgramType +impl core::marker::Freeze for aya::programs::ProgramType +impl core::marker::Send for aya::programs::ProgramType +impl core::marker::Sync for aya::programs::ProgramType +impl core::marker::Unpin for aya::programs::ProgramType +impl core::panic::unwind_safe::RefUnwindSafe for aya::programs::ProgramType +impl core::panic::unwind_safe::UnwindSafe for aya::programs::ProgramType +impl core::convert::Into for aya::programs::ProgramType where U: core::convert::From +pub fn aya::programs::ProgramType::into(self) -> U +impl core::convert::TryFrom for aya::programs::ProgramType where U: core::convert::Into +pub type aya::programs::ProgramType::Error = core::convert::Infallible +pub fn aya::programs::ProgramType::try_from(value: U) -> core::result::Result>::Error> +impl core::convert::TryInto for aya::programs::ProgramType where U: core::convert::TryFrom +pub type aya::programs::ProgramType::Error = >::Error +pub fn aya::programs::ProgramType::try_into(self) -> core::result::Result>::Error> +impl alloc::borrow::ToOwned for aya::programs::ProgramType where T: core::clone::Clone +pub type aya::programs::ProgramType::Owned = T +pub fn aya::programs::ProgramType::clone_into(&self, target: &mut T) +pub fn aya::programs::ProgramType::to_owned(&self) -> T +impl core::any::Any for aya::programs::ProgramType where T: 'static + core::marker::Sized +pub fn aya::programs::ProgramType::type_id(&self) -> core::any::TypeId +impl core::borrow::Borrow for aya::programs::ProgramType where T: core::marker::Sized +pub fn aya::programs::ProgramType::borrow(&self) -> &T +impl core::borrow::BorrowMut for aya::programs::ProgramType where T: core::marker::Sized +pub fn aya::programs::ProgramType::borrow_mut(&mut self) -> &mut T +impl core::clone::CloneToUninit for aya::programs::ProgramType where T: core::clone::Clone +pub unsafe fn aya::programs::ProgramType::clone_to_uninit(&self, dst: *mut T) +impl core::convert::From for aya::programs::ProgramType +pub fn aya::programs::ProgramType::from(t: T) -> T pub enum aya::programs::SamplePolicy pub aya::programs::SamplePolicy::Frequency(u64) pub aya::programs::SamplePolicy::Period(u64) @@ -7913,22 +8060,23 @@ pub fn aya::programs::ProgramFd::from(t: T) -> T pub struct aya::programs::ProgramInfo(_) impl aya::programs::ProgramInfo pub fn aya::programs::ProgramInfo::btf_id(&self) -> core::option::Option +pub fn aya::programs::ProgramInfo::created_by_uid(&self) -> core::option::Option pub fn aya::programs::ProgramInfo::fd(&self) -> core::result::Result pub fn aya::programs::ProgramInfo::from_pin>(path: P) -> core::result::Result -pub fn aya::programs::ProgramInfo::gpl_compatible(&self) -> bool -pub fn aya::programs::ProgramInfo::id(&self) -> u32 -pub fn aya::programs::ProgramInfo::loaded_at(&self) -> std::time::SystemTime -pub fn aya::programs::ProgramInfo::map_ids(&self) -> core::result::Result, aya::programs::ProgramError> +pub fn aya::programs::ProgramInfo::gpl_compatible(&self) -> core::option::Option +pub fn aya::programs::ProgramInfo::id(&self) -> core::option::Option +pub fn aya::programs::ProgramInfo::loaded_at(&self) -> core::option::Option +pub fn aya::programs::ProgramInfo::map_ids(&self) -> core::result::Result>, aya::programs::ProgramError> pub fn aya::programs::ProgramInfo::memory_locked(&self) -> core::result::Result pub fn aya::programs::ProgramInfo::name(&self) -> &[u8] pub fn aya::programs::ProgramInfo::name_as_str(&self) -> core::option::Option<&str> -pub fn aya::programs::ProgramInfo::program_type(&self) -> u32 +pub fn aya::programs::ProgramInfo::program_type(&self) -> core::result::Result pub fn aya::programs::ProgramInfo::run_count(&self) -> u64 pub fn aya::programs::ProgramInfo::run_time(&self) -> core::time::Duration -pub fn aya::programs::ProgramInfo::size_jitted(&self) -> u32 -pub fn aya::programs::ProgramInfo::size_translated(&self) -> u32 -pub fn aya::programs::ProgramInfo::tag(&self) -> u64 -pub fn aya::programs::ProgramInfo::verified_instruction_count(&self) -> u32 +pub fn aya::programs::ProgramInfo::size_jitted(&self) -> core::option::Option +pub fn aya::programs::ProgramInfo::size_translated(&self) -> core::option::Option +pub fn aya::programs::ProgramInfo::tag(&self) -> core::option::Option +pub fn aya::programs::ProgramInfo::verified_instruction_count(&self) -> core::option::Option impl core::fmt::Debug for aya::programs::ProgramInfo pub fn aya::programs::ProgramInfo::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result impl core::marker::Freeze for aya::programs::ProgramInfo @@ -8765,6 +8913,8 @@ impl core::cmp::PartialOrd for aya::util::KernelVersion pub fn aya::util::KernelVersion::partial_cmp(&self, other: &aya::util::KernelVersion) -> core::option::Option impl core::fmt::Debug for aya::util::KernelVersion pub fn aya::util::KernelVersion::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +impl core::fmt::Display for aya::util::KernelVersion +pub fn aya::util::KernelVersion::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result impl core::marker::Copy for aya::util::KernelVersion impl core::marker::StructuralPartialEq for aya::util::KernelVersion impl core::marker::Freeze for aya::util::KernelVersion @@ -8789,6 +8939,8 @@ impl alloc::borrow::ToOwned for aya::util::KernelVersion where T: core::clone pub type aya::util::KernelVersion::Owned = T pub fn aya::util::KernelVersion::clone_into(&self, target: &mut T) pub fn aya::util::KernelVersion::to_owned(&self) -> T +impl alloc::string::ToString for aya::util::KernelVersion where T: core::fmt::Display + core::marker::Sized +pub fn aya::util::KernelVersion::to_string(&self) -> alloc::string::String impl core::any::Any for aya::util::KernelVersion where T: 'static + core::marker::Sized pub fn aya::util::KernelVersion::type_id(&self) -> core::any::TypeId impl core::borrow::Borrow for aya::util::KernelVersion where T: core::marker::Sized @@ -9089,7 +9241,6 @@ impl aya::Pod for u8 impl aya::Pod for aya::maps::lpm_trie::Key impl aya::Pod for [T; N] pub fn aya::features() -> &'static aya_obj::obj::Features -pub fn aya::loaded_programs() -> impl core::iter::traits::iterator::Iterator> pub type aya::Bpf = aya::Ebpf pub type aya::BpfError = aya::EbpfError pub type aya::BpfLoader<'a> = aya::EbpfLoader<'a>