aya,int-test: revamp MapInfo be more friendly with older kernels

Adds detection for whether a field is available in `MapInfo`:
- For `map_type()`, we treturn new enum `MapType` instead of the integer
  representation.
- For fields that can't be zero, we return `Option<NonZero*>` type.
- For `name_as_str()`, it now uses the feature probe `bpf_name()` to
  detect if field is available.
  Although the feature probe checks for program name, it can also be
  used for map name since they were both introduced in the same commit.
pull/1007/head
tyrone-wu 2 months ago
parent 88f5ac3114
commit fbb09304a2
No known key found for this signature in database
GPG Key ID: 978B1A1B79210AD6

@ -150,7 +150,7 @@ impl EbpfLogger {
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)?;

@ -81,7 +81,10 @@ impl Features {
}
}
/// 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
}

@ -0,0 +1,413 @@
//! Metadata information about an eBPF map.
use std::{
ffi::CString,
num::NonZeroU32,
os::fd::{AsFd as _, BorrowedFd},
path::Path,
};
use aya_obj::generated::{bpf_map_info, bpf_map_type};
use super::{MapError, MapFd};
use crate::{
sys::{
bpf_get_object, bpf_map_get_fd_by_id, bpf_map_get_info_by_fd, iter_map_ids, SyscallError,
},
util::bytes_of_bpf_name,
FEATURES,
};
/// Provides Provides metadata information about a loaded eBPF map.
#[doc(alias = "bpf_map_info")]
#[derive(Debug)]
pub struct MapInfo(pub(crate) bpf_map_info);
impl MapInfo {
pub(crate) fn new_from_fd(fd: BorrowedFd<'_>) -> Result<Self, MapError> {
let info = bpf_map_get_info_by_fd(fd.as_fd())?;
Ok(Self(info))
}
/// Loads map info from a map ID.
///
/// Uses kernel v4.13 features.
pub fn from_id(id: u32) -> Result<Self, MapError> {
bpf_map_get_fd_by_id(id)
.map_err(MapError::from)
.and_then(|fd| Self::new_from_fd(fd.as_fd()))
}
/// The type of map.
///
/// Introduced in kernel v4.13.
pub fn map_type(&self) -> Result<MapType, MapError> {
bpf_map_type::try_from(self.0.type_)
.unwrap_or(bpf_map_type::__MAX_BPF_MAP_TYPE)
.try_into()
}
/// The unique ID for this map.
///
/// `None` is returned if the field is not available.
///
/// Introduced in kernel v4.13.
pub fn id(&self) -> Option<NonZeroU32> {
NonZeroU32::new(self.0.id)
}
/// The key size for this map in bytes.
///
/// `None` is returned if the field is not available.
///
/// Introduced in kernel v4.13.
pub fn key_size(&self) -> Option<NonZeroU32> {
NonZeroU32::new(self.0.key_size)
}
/// The value size for this map in bytes.
///
/// `None` is returned if the field is not available.
///
/// Introduced in kernel v4.13.
pub fn value_size(&self) -> Option<NonZeroU32> {
NonZeroU32::new(self.0.value_size)
}
/// The maximum number of entries in this map.
///
/// `None` is returned if the field is not available.
///
/// Introduced in kernel v4.13.
pub fn max_entries(&self) -> Option<NonZeroU32> {
NonZeroU32::new(self.0.max_entries)
}
/// The flags used in loading this map.
///
/// Introduced in kernel v4.13.
pub fn map_flags(&self) -> u32 {
self.0.map_flags
}
/// The name of the map, limited to 16 bytes.
///
/// Introduced in kernel v4.15.
pub fn name(&self) -> &[u8] {
bytes_of_bpf_name(&self.0.name)
}
/// The name of the map as a &str.
///
/// `None` is returned if the name was not valid unicode or if field is not available.
///
/// Introduced in kernel v4.15.
pub fn name_as_str(&self) -> Option<&str> {
let name = std::str::from_utf8(self.name()).ok();
if let Some(name_str) = name {
// Char in program name was introduced in the same commit as map name
if FEATURES.bpf_name() || !name_str.is_empty() {
return name;
}
}
None
}
/// Returns a file descriptor referencing the map.
///
/// The returned file descriptor can be closed at any time and doing so does
/// not influence the life cycle of the map.
///
/// Uses kernel v4.13 features.
pub fn fd(&self) -> Result<MapFd, MapError> {
let Self(info) = self;
let fd = bpf_map_get_fd_by_id(info.id)?;
Ok(MapFd::from_fd(fd))
}
/// Loads a map from a pinned path in bpffs.
///
/// Uses kernel v4.4 and v4.13 features.
pub fn from_pin<P: AsRef<Path>>(path: P) -> Result<Self, MapError> {
use std::os::unix::ffi::OsStrExt as _;
// TODO: avoid this unwrap by adding a new error variant.
let path_string = CString::new(path.as_ref().as_os_str().as_bytes()).unwrap();
let fd = bpf_get_object(&path_string).map_err(|(_, io_error)| SyscallError {
call: "BPF_OBJ_GET",
io_error,
})?;
Self::new_from_fd(fd.as_fd())
}
}
/// Returns an iterator of [`MapInfo`] over all eBPF maps on the host.
///
/// Unlike [`Ebpf::maps`](crate::Ebpf::maps), this includes all maps on the host system, not
/// just those tied to a specific [`crate::Ebpf`] instance.
///
/// Uses kernel v4.13 features.
///
/// # Example
/// ```
/// # use aya::maps::loaded_maps;
/// #
/// for m in loaded_maps() {
/// match m {
/// Ok(map) => println!("{:?}", map.name_as_str()),
/// Err(e) => println!("Error iterating maps: {:?}", e),
/// }
/// }
/// ```
///
/// # Errors
///
/// Returns [`MapError::SyscallError`] if any of the syscalls required to either get
/// next map id, get the map fd, or the [`MapInfo`] fail.
///
/// In cases where iteration can't be performed, for example the caller does not have the necessary
/// privileges, a single item will be yielded containing the error that occurred.
pub fn loaded_maps() -> impl Iterator<Item = Result<MapInfo, MapError>> {
iter_map_ids().map(|id| {
let id = id?;
MapInfo::from_id(id)
})
}
/// The type of eBPF map.
#[non_exhaustive]
#[doc(alias = "bpf_map_type")]
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum MapType {
/// An unspecified program type.
Unspecified = bpf_map_type::BPF_MAP_TYPE_UNSPEC as isize,
/// A Hash map type. See [`HashMap`](super::hash_map::HashMap) for the map implementation.
///
/// Introduced in kernel v3.19.
#[doc(alias = "BPF_MAP_TYPE_HASH")]
Hash = bpf_map_type::BPF_MAP_TYPE_HASH as isize,
/// An Array map type. See [`Array`](super::array::Array) for the map implementation.
///
/// Introduced in kernel v3.19.
#[doc(alias = "BPF_MAP_TYPE_ARRAY")]
Array = bpf_map_type::BPF_MAP_TYPE_ARRAY as isize,
/// A Program Array map type. See [`ProgramArray`](super::array::ProgramArray) for the map
/// implementation.
///
/// Introduced in kernel v4.2.
#[doc(alias = "BPF_MAP_TYPE_PROG_ARRAY")]
ProgramArray = bpf_map_type::BPF_MAP_TYPE_PROG_ARRAY as isize,
/// A Perf Event Array map type. See [`PerfEventArray`](super::perf::PerfEventArray) and
/// [`AsyncPerfEventArray`](super::perf::AsyncPerfEventArray) for the map implementations.
///
/// Introduced in kernel v4.3.
#[doc(alias = "BPF_MAP_TYPE_PERF_EVENT_ARRAY")]
PerfEventArray = bpf_map_type::BPF_MAP_TYPE_PERF_EVENT_ARRAY as isize,
/// A per-CPU Hash map type. See [`PerCpuHashMap`](super::hash_map::PerCpuHashMap) for the map
/// implementation.
///
/// Introduced in kernel v4.6.
#[doc(alias = "BPF_MAP_TYPE_PERCPU_HASH")]
PerCpuHash = bpf_map_type::BPF_MAP_TYPE_PERCPU_HASH as isize,
/// A per-CPU Array map type. See [`PerCpuArray`](super::array::PerCpuArray) for the map
/// implementation.
///
/// Introduced in kernel v4.6.
#[doc(alias = "BPF_MAP_TYPE_PERCPU_ARRAY")]
PerCpuArray = bpf_map_type::BPF_MAP_TYPE_PERCPU_ARRAY as isize,
/// A Stack Trace map type. See [`StackTraceMap`](super::stack_trace::StackTraceMap) for the map
/// implementation.
///
/// Introduced in kernel v4.6.
#[doc(alias = "BPF_MAP_TYPE_STACK_TRACE")]
StackTrace = bpf_map_type::BPF_MAP_TYPE_STACK_TRACE as isize,
/// A cGroup Array map type.
///
/// Introduced in kernel v4.8.
#[doc(alias = "BPF_MAP_TYPE_CGROUP_ARRAY")]
CgroupArray = bpf_map_type::BPF_MAP_TYPE_CGROUP_ARRAY as isize,
/// A Least Recently Used (LRU) Hash map type. See [`HashMap`](super::hash_map::HashMap) for
/// the map implementation.
///
/// Introduced in kernel v4.10.
#[doc(alias = "BPF_MAP_TYPE_LRU_HASH")]
LruHash = bpf_map_type::BPF_MAP_TYPE_LRU_HASH as isize,
/// A Least Recently Used (LRU) per-CPU Hash map type. See
/// [`PerCpuHashMap`](super::hash_map::PerCpuHashMap) for the map implementation.
///
/// Introduced in kernel v4.10.
#[doc(alias = "BPF_MAP_TYPE_LRU_PERCPU_HASH")]
LruPerCpuHash = bpf_map_type::BPF_MAP_TYPE_LRU_PERCPU_HASH as isize,
/// A Longest Prefix Match (LPM) Trie map type. See [`LpmTrie`](super::lpm_trie::LpmTrie) for
/// the map implementation.
///
/// Introduced in kernel v4.11.
#[doc(alias = "BPF_MAP_TYPE_LPM_TRIE")]
LpmTrie = bpf_map_type::BPF_MAP_TYPE_LPM_TRIE as isize,
/// An Array of Maps map type.
///
/// Introduced in kernel v4.12.
#[doc(alias = "BPF_MAP_TYPE_ARRAY_OF_MAPS")]
ArrayOfMaps = bpf_map_type::BPF_MAP_TYPE_ARRAY_OF_MAPS as isize,
/// A Hash of Maps map type.
///
/// Introduced in kernel v4.12.
#[doc(alias = "BPF_MAP_TYPE_HASH_OF_MAPS")]
HashOfMaps = bpf_map_type::BPF_MAP_TYPE_HASH_OF_MAPS as isize,
/// A Device Map type. See [`DevMap`](super::xdp::DevMap) for the map implementation.
///
/// Introduced in kernel v4.14.
#[doc(alias = "BPF_MAP_TYPE_DEVMAP")]
DevMap = bpf_map_type::BPF_MAP_TYPE_DEVMAP as isize,
/// A Socket Map type. See [`SockMap`](super::sock::SockMap) for the map implementation.
///
/// Introduced in kernel v4.14.
#[doc(alias = "BPF_MAP_TYPE_SOCKMAP")]
SockMap = bpf_map_type::BPF_MAP_TYPE_SOCKMAP as isize,
/// A CPU Map type. See [`CpuMap`](super::xdp::CpuMap) for the map implementation.
///
/// Introduced in kernel v4.15.
#[doc(alias = "BPF_MAP_TYPE_CPUMAP")]
CpuMap = bpf_map_type::BPF_MAP_TYPE_CPUMAP as isize,
/// An XDP Socket Map type. See [`XskMap`](super::xdp::XskMap) for the map implementation.
///
/// Introduced in kernel v4.18.
#[doc(alias = "BPF_MAP_TYPE_XSKMAP")]
XskMap = bpf_map_type::BPF_MAP_TYPE_XSKMAP as isize,
/// A Socket Hash map type. See [`SockHash`](super::sock::SockHash) for the map implementation.
///
/// Introduced in kernel v4.18.
#[doc(alias = "BPF_MAP_TYPE_SOCKHASH")]
SockHash = bpf_map_type::BPF_MAP_TYPE_SOCKHASH as isize,
/// A cGroup Storage map type.
///
/// Introduced in kernel v4.19.
// #[deprecated]
#[doc(alias = "BPF_MAP_TYPE_CGROUP_STORAGE")]
#[doc(alias = "BPF_MAP_TYPE_CGROUP_STORAGE_DEPRECATED")]
CgroupStorage = bpf_map_type::BPF_MAP_TYPE_CGROUP_STORAGE as isize,
/// A Reuseport Socket Array map type.
///
/// Introduced in kernel v4.19.
#[doc(alias = "BPF_MAP_TYPE_REUSEPORT_SOCKARRAY")]
ReuseportSockArray = bpf_map_type::BPF_MAP_TYPE_REUSEPORT_SOCKARRAY as isize,
/// A per-CPU cGroup Storage map type.
///
/// Introduced in kernel v4.20.
#[doc(alias = "BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE")]
#[doc(alias = "BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE_DEPRECATED")]
PerCpuCgroupStorage = bpf_map_type::BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE as isize,
/// A Queue map type. See [`Queue`](super::queue::Queue) for the map implementation.
///
/// Introduced in kernel v4.20.
#[doc(alias = "BPF_MAP_TYPE_QUEUE")]
Queue = bpf_map_type::BPF_MAP_TYPE_QUEUE as isize,
/// A Stack map type. See [`Stack`](super::stack::Stack) for the map implementation.
///
/// Introduced in kernel v4.20.
#[doc(alias = "BPF_MAP_TYPE_STACK")]
Stack = bpf_map_type::BPF_MAP_TYPE_STACK as isize,
/// A Socket-local Storage map type.
///
/// Introduced in kernel v5.2.
#[doc(alias = "BPF_MAP_TYPE_SK_STORAGE")]
SkStorage = bpf_map_type::BPF_MAP_TYPE_SK_STORAGE as isize,
/// A Device Hash Map type. See [`DevMapHash`](super::xdp::DevMapHash) for the map
/// implementation.
///
/// Introduced in kernel v5.4.
#[doc(alias = "BPF_MAP_TYPE_DEVMAP_HASH")]
DevMapHash = bpf_map_type::BPF_MAP_TYPE_DEVMAP_HASH as isize,
/// A Struct Ops map type.
///
/// Introduced in kernel v5.6.
#[doc(alias = "BPF_MAP_TYPE_STRUCT_OPS")]
StructOps = bpf_map_type::BPF_MAP_TYPE_STRUCT_OPS as isize,
/// A Ring Buffer map type. See [`RingBuf`](super::ring_buf::RingBuf) for the map
/// implementation.
///
/// Introduced in kernel v5.8.
#[doc(alias = "BPF_MAP_TYPE_RINGBUF")]
RingBuf = bpf_map_type::BPF_MAP_TYPE_RINGBUF as isize,
/// An Inode Storage map type.
///
/// Introduced in kernel v5.10.
#[doc(alias = "BPF_MAP_TYPE_INODE_STORAGE")]
InodeStorage = bpf_map_type::BPF_MAP_TYPE_INODE_STORAGE as isize,
/// A Task Storage map type.
///
/// Introduced in kernel v5.11.
#[doc(alias = "BPF_MAP_TYPE_TASK_STORAGE")]
TaskStorage = bpf_map_type::BPF_MAP_TYPE_TASK_STORAGE as isize,
/// A Bloom Filter map type. See [`BloomFilter`](super::bloom_filter::BloomFilter) for the map
/// implementation.
///
/// Introduced in kernel v5.16.
#[doc(alias = "BPF_MAP_TYPE_BLOOM_FILTER")]
BloomFilter = bpf_map_type::BPF_MAP_TYPE_BLOOM_FILTER as isize,
/// A User Ring Buffer map type.
///
/// Introduced in kernel v6.1.
#[doc(alias = "BPF_MAP_TYPE_USER_RINGBUF")]
UserRingBuf = bpf_map_type::BPF_MAP_TYPE_USER_RINGBUF as isize,
/// A cGroup Storage map type.
///
/// Introduced in kernel v6.2.
#[doc(alias = "BPF_MAP_TYPE_CGRP_STORAGE")]
CgrpStorage = bpf_map_type::BPF_MAP_TYPE_CGRP_STORAGE as isize,
/// An Arena map type.
///
/// Introduced in kernel v6.9.
#[doc(alias = "BPF_MAP_TYPE_ARENA")]
Arena = bpf_map_type::BPF_MAP_TYPE_ARENA as isize,
}
impl TryFrom<bpf_map_type> for MapType {
type Error = MapError;
fn try_from(map_type: bpf_map_type) -> Result<Self, Self::Error> {
use bpf_map_type::*;
Ok(match map_type {
BPF_MAP_TYPE_UNSPEC => Self::Unspecified,
BPF_MAP_TYPE_HASH => Self::Hash,
BPF_MAP_TYPE_ARRAY => Self::Array,
BPF_MAP_TYPE_PROG_ARRAY => Self::ProgramArray,
BPF_MAP_TYPE_PERF_EVENT_ARRAY => Self::PerfEventArray,
BPF_MAP_TYPE_PERCPU_HASH => Self::PerCpuHash,
BPF_MAP_TYPE_PERCPU_ARRAY => Self::PerCpuArray,
BPF_MAP_TYPE_STACK_TRACE => Self::StackTrace,
BPF_MAP_TYPE_CGROUP_ARRAY => Self::CgroupArray,
BPF_MAP_TYPE_LRU_HASH => Self::LruHash,
BPF_MAP_TYPE_LRU_PERCPU_HASH => Self::LruPerCpuHash,
BPF_MAP_TYPE_LPM_TRIE => Self::LpmTrie,
BPF_MAP_TYPE_ARRAY_OF_MAPS => Self::ArrayOfMaps,
BPF_MAP_TYPE_HASH_OF_MAPS => Self::HashOfMaps,
BPF_MAP_TYPE_DEVMAP => Self::DevMap,
BPF_MAP_TYPE_SOCKMAP => Self::SockMap,
BPF_MAP_TYPE_CPUMAP => Self::CpuMap,
BPF_MAP_TYPE_XSKMAP => Self::XskMap,
BPF_MAP_TYPE_SOCKHASH => Self::SockHash,
BPF_MAP_TYPE_CGROUP_STORAGE_DEPRECATED => Self::CgroupStorage,
BPF_MAP_TYPE_REUSEPORT_SOCKARRAY => Self::ReuseportSockArray,
BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE_DEPRECATED => Self::PerCpuCgroupStorage,
BPF_MAP_TYPE_QUEUE => Self::Queue,
BPF_MAP_TYPE_STACK => Self::Stack,
BPF_MAP_TYPE_SK_STORAGE => Self::SkStorage,
BPF_MAP_TYPE_DEVMAP_HASH => Self::DevMapHash,
BPF_MAP_TYPE_STRUCT_OPS => Self::StructOps,
BPF_MAP_TYPE_RINGBUF => Self::RingBuf,
BPF_MAP_TYPE_INODE_STORAGE => Self::InodeStorage,
BPF_MAP_TYPE_TASK_STORAGE => Self::TaskStorage,
BPF_MAP_TYPE_BLOOM_FILTER => Self::BloomFilter,
BPF_MAP_TYPE_USER_RINGBUF => Self::UserRingBuf,
BPF_MAP_TYPE_CGRP_STORAGE => Self::CgrpStorage,
BPF_MAP_TYPE_ARENA => Self::Arena,
__MAX_BPF_MAP_TYPE => {
return Err(MapError::InvalidMapType {
map_type: map_type as u32,
})
}
})
}
}

@ -65,21 +65,20 @@ use log::warn;
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;
@ -92,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"))))]
@ -947,121 +947,6 @@ impl<T: Pod> Deref for PerCpuValues<T> {
}
}
/// 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<Self, MapError> {
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<Self, MapError> {
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<MapFd, MapError> {
let Self(info) = self;
let fd = bpf_map_get_fd_by_id(info.id)?;
Ok(MapFd::from_fd(fd))
}
/// Loads a map from a pinned path in bpffs.
pub fn from_pin<P: AsRef<Path>>(path: P) -> Result<Self, MapError> {
use std::os::unix::ffi::OsStrExt as _;
// TODO: avoid this unwrap by adding a new error variant.
let path_string = CString::new(path.as_ref().as_os_str().as_bytes()).unwrap();
let fd = bpf_get_object(&path_string).map_err(|(_, io_error)| SyscallError {
call: "BPF_OBJ_GET",
io_error,
})?;
Self::new_from_fd(fd.as_fd())
}
}
/// Returns an iterator 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.
///
/// Uses kernel v4.13 features.
///
/// # Example
/// ```
/// # use aya::maps::loaded_maps;
///
/// for m in loaded_maps() {
/// match m {
/// Ok(map) => println!("{:?}", map.name_as_str()),
/// Err(e) => println!("Error iterating maps: {:?}", e),
/// }
/// }
/// ```
///
/// # Errors
///
/// Returns [`MapError::SyscallError`] if any of the syscalls required to either get
/// next map id, get the map fd, or the [`MapInfo`] fail. In cases where
/// iteration can't be performed, for example the caller does not have the necessary privileges,
/// a single item will be yielded containing the error that occurred.
pub fn loaded_maps() -> impl Iterator<Item = Result<MapInfo, MapError>> {
iter_map_ids().map(|id| {
let id = id?;
MapInfo::from_id(id)
})
}
#[cfg(test)]
mod test_utils {
use crate::{
@ -1332,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(),
)
})

@ -3,13 +3,12 @@
use std::{fs, panic, path::Path, time::SystemTime};
use aya::{
maps::{loaded_maps, MapError},
maps::{loaded_maps, Array, HashMap, IterableMap as _, MapError, MapType},
programs::{loaded_programs, ProgramError, ProgramType, SocketFilter, TracePoint},
sys::enable_stats,
util::KernelVersion,
Ebpf,
};
use aya_obj::generated::bpf_map_type;
use libc::EINVAL;
use crate::utils::{kernel_assert, kernel_assert_eq};
@ -233,7 +232,7 @@ fn list_loaded_maps() {
let prog: &mut SocketFilter = bpf.program_mut("simple_prog").unwrap().try_into().unwrap();
prog.load().unwrap();
// Ensure the loaded_maps() api doesn't panic and retrieve loaded maps.
// 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 {
@ -250,64 +249,94 @@ fn list_loaded_maps() {
}
panic!("{err}");
}
let mut maps: Vec<_> = maps.filter_map(|m| m.ok()).collect();
// There's not a good way to extract our maps of interest with load order being
// non-deterministic. Since we are trying to be more considerate of older kernels, we should
// only rely on v4.13 feats.
// Expected sort order should be: `BAR`, `aya_global` (if avail), `FOO`
maps.sort_unstable_by_key(|m| (m.map_type(), m.id()));
// Ensure program has the 2 maps.
if let Ok(info) = prog.info() {
let map_ids = info.map_ids().unwrap();
kernel_assert!(map_ids.is_some(), KernelVersion::new(4, 15, 0));
if let Some(map_ids) = map_ids {
// 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() == id.get()),
"expected `loaded_maps()` to have `map_ids` from program"
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 = maps.first().unwrap();
let hash: HashMap<_, u32, u8> = HashMap::try_from(bpf.map("BAR").unwrap()).unwrap();
let hash = hash.map().info().unwrap();
kernel_assert_eq!(
bpf_map_type::BPF_MAP_TYPE_HASH as u32,
hash.map_type(),
KernelVersion::new(4, 13, 0)
MapType::Hash,
hash.map_type().unwrap_or(MapType::Unspecified),
KernelVersion::new(4, 13, 0),
);
kernel_assert!(hash.id() > 0, KernelVersion::new(4, 13, 0));
kernel_assert_eq!(4, hash.key_size(), KernelVersion::new(4, 13, 0));
kernel_assert_eq!(1, hash.value_size(), KernelVersion::new(4, 13, 0));
kernel_assert_eq!(8, hash.max_entries(), KernelVersion::new(4, 13, 0));
kernel_assert_eq!(
"BAR",
hash.name_as_str().unwrap(),
KernelVersion::new(4, 15, 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 = maps.last().unwrap();
let array: Array<_, u32> = Array::try_from(bpf.map("FOO").unwrap()).unwrap();
let array = array.map().info().unwrap();
kernel_assert_eq!(
bpf_map_type::BPF_MAP_TYPE_ARRAY as u32,
array.map_type(),
KernelVersion::new(4, 13, 0)
MapType::Array,
array.map_type().unwrap_or(MapType::Unspecified),
KernelVersion::new(4, 13, 0),
);
kernel_assert!(array.id() > 0, KernelVersion::new(4, 13, 0));
kernel_assert_eq!(4, array.key_size(), KernelVersion::new(4, 13, 0));
kernel_assert_eq!(4, array.value_size(), KernelVersion::new(4, 13, 0));
kernel_assert_eq!(10, array.max_entries(), KernelVersion::new(4, 13, 0));
kernel_assert_eq!(
"FOO",
array.name_as_str().unwrap(),
KernelVersion::new(4, 15, 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();

@ -1405,6 +1405,80 @@ impl<T> core::borrow::BorrowMut<T> for aya::maps::MapError where T: core::marker
pub fn aya::maps::MapError::borrow_mut(&mut self) -> &mut T
impl<T> core::convert::From<T> 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<aya_obj::generated::linux_bindings_x86_64::bpf_map_type> 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<Self, Self::Error>
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<T, U> core::convert::Into<U> for aya::maps::MapType where U: core::convert::From<T>
pub fn aya::maps::MapType::into(self) -> U
impl<T, U> core::convert::TryFrom<U> for aya::maps::MapType where U: core::convert::Into<T>
pub type aya::maps::MapType::Error = core::convert::Infallible
pub fn aya::maps::MapType::try_from(value: U) -> core::result::Result<T, <T as core::convert::TryFrom<U>>::Error>
impl<T, U> core::convert::TryInto<U> for aya::maps::MapType where U: core::convert::TryFrom<T>
pub type aya::maps::MapType::Error = <U as core::convert::TryFrom<T>>::Error
pub fn aya::maps::MapType::try_into(self) -> core::result::Result<U, <U as core::convert::TryFrom<T>>::Error>
impl<T> 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<T> 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<T> core::borrow::Borrow<T> for aya::maps::MapType where T: core::marker::Sized
pub fn aya::maps::MapType::borrow(&self) -> &T
impl<T> core::borrow::BorrowMut<T> for aya::maps::MapType where T: core::marker::Sized
pub fn aya::maps::MapType::borrow_mut(&mut self) -> &mut T
impl<T> 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<T> core::convert::From<T> for aya::maps::MapType
pub fn aya::maps::MapType::from(t: T) -> T
pub struct aya::maps::Array<T, V: aya::Pod>
impl<T: core::borrow::Borrow<aya::maps::MapData>, V: aya::Pod> aya::maps::array::Array<T, V>
pub fn aya::maps::array::Array<T, V>::get(&self, index: &u32, flags: u64) -> core::result::Result<V, aya::maps::MapError>
@ -1801,14 +1875,14 @@ impl aya::maps::MapInfo
pub fn aya::maps::MapInfo::fd(&self) -> core::result::Result<aya::maps::MapFd, aya::maps::MapError>
pub fn aya::maps::MapInfo::from_id(id: u32) -> core::result::Result<Self, aya::maps::MapError>
pub fn aya::maps::MapInfo::from_pin<P: core::convert::AsRef<std::path::Path>>(path: P) -> core::result::Result<Self, aya::maps::MapError>
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<core::num::nonzero::NonZeroU32>
pub fn aya::maps::MapInfo::key_size(&self) -> core::option::Option<core::num::nonzero::NonZeroU32>
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<aya::maps::MapType, aya::maps::MapError>
pub fn aya::maps::MapInfo::max_entries(&self) -> core::option::Option<core::num::nonzero::NonZeroU32>
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<core::num::nonzero::NonZeroU32>
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

Loading…
Cancel
Save