Core refactor of Map API

Build completing tests passing

Refactor the Map API to better align
with the aya programs API.  Specifically
remove all internal locking mechanisms
and custom Deref/DerefMut implementations.
They are replaced with a Map enum
and AsRef/AsMut implementations.

All Try_From implementations have been moved
to standardized enums, with a slightly
special one for PerfEventArray's.

Also cleanup/fix all associated tests and
documentation.

Signed-off-by: Andrew Stoycos <astoycos@redhat.com>
pull/397/head
Andrew Stoycos 2 years ago
parent 0a9c9960e4
commit 1aefa2e5e6

@ -90,7 +90,7 @@ impl BpfLogger {
logger: T, logger: T,
) -> Result<BpfLogger, Error> { ) -> Result<BpfLogger, Error> {
let logger = Arc::new(logger); let logger = Arc::new(logger);
let mut logs: AsyncPerfEventArray<_> = bpf.map_mut("AYA_LOGS")?.try_into()?; let mut logs: AsyncPerfEventArray<_> = bpf.take_map("AYA_LOGS")?.try_into()?;
for cpu_id in online_cpus().map_err(Error::InvalidOnlineCpu)? { for cpu_id in online_cpus().map_err(Error::InvalidOnlineCpu)? {
let mut buf = logs.open(cpu_id, None)?; let mut buf = logs.open(cpu_id, None)?;

@ -13,10 +13,10 @@ use thiserror::Error;
use crate::{ use crate::{
generated::{ generated::{
bpf_map_type::BPF_MAP_TYPE_PERF_EVENT_ARRAY, AYA_PERF_EVENT_IOC_DISABLE, bpf_map_type::*, AYA_PERF_EVENT_IOC_DISABLE, AYA_PERF_EVENT_IOC_ENABLE,
AYA_PERF_EVENT_IOC_ENABLE, AYA_PERF_EVENT_IOC_SET_BPF, AYA_PERF_EVENT_IOC_SET_BPF,
}, },
maps::{Map, MapError, MapLock, MapRef, MapRefMut}, maps::{Map, MapData, MapError},
obj::{ obj::{
btf::{Btf, BtfError}, btf::{Btf, BtfError},
MapKind, Object, ParseError, ProgramSection, MapKind, Object, ParseError, ProgramSection,
@ -451,7 +451,7 @@ impl<'a> BpfLoader<'a> {
} }
} }
} }
let mut map = Map { let mut map = MapData {
obj, obj,
fd: None, fd: None,
pinned: false, pinned: false,
@ -638,14 +638,41 @@ impl<'a> BpfLoader<'a> {
(name, program) (name, program)
}) })
.collect(); .collect();
let maps = maps let maps: Result<HashMap<String, Map>, BpfError> = maps.drain().map(parse_map).collect();
.drain()
.map(|(name, map)| (name, MapLock::new(map))) Ok(Bpf {
.collect(); maps: maps?,
Ok(Bpf { maps, programs }) programs,
})
} }
} }
fn parse_map(data: (String, MapData)) -> Result<(String, Map), BpfError> {
let name = data.0;
let map = data.1;
let map_type = map.map_type().map_err(BpfError::MapError)?;
let map = match map_type {
BPF_MAP_TYPE_ARRAY => Ok(Map::Array(map)),
BPF_MAP_TYPE_PERCPU_ARRAY => Ok(Map::PerCpuArray(map)),
BPF_MAP_TYPE_PROG_ARRAY => Ok(Map::ProgramArray(map)),
BPF_MAP_TYPE_HASH => Ok(Map::HashMap(map)),
BPF_MAP_TYPE_PERCPU_HASH => Ok(Map::PerCpuHashMap(map)),
BPF_MAP_TYPE_PERF_EVENT_ARRAY => Ok(Map::PerfEventArray(map)),
BPF_MAP_TYPE_SOCKHASH => Ok(Map::SockHash(map)),
BPF_MAP_TYPE_SOCKMAP => Ok(Map::SockMap(map)),
BPF_MAP_TYPE_BLOOM_FILTER => Ok(Map::BloomFilter(map)),
BPF_MAP_TYPE_LPM_TRIE => Ok(Map::LpmTrie(map)),
BPF_MAP_TYPE_STACK => Ok(Map::Stack(map)),
BPF_MAP_TYPE_STACK_TRACE => Ok(Map::StackTraceMap(map)),
BPF_MAP_TYPE_QUEUE => Ok(Map::Queue(map)),
m => Err(BpfError::MapError(MapError::InvalidMapType {
map_type: m as u32,
})),
}?;
Ok((name, map))
}
impl<'a> Default for BpfLoader<'a> { impl<'a> Default for BpfLoader<'a> {
fn default() -> Self { fn default() -> Self {
BpfLoader::new() BpfLoader::new()
@ -655,7 +682,7 @@ impl<'a> Default for BpfLoader<'a> {
/// The main entry point into the library, used to work with eBPF programs and maps. /// The main entry point into the library, used to work with eBPF programs and maps.
#[derive(Debug)] #[derive(Debug)]
pub struct Bpf { pub struct Bpf {
maps: HashMap<String, MapLock>, maps: HashMap<String, Map>,
programs: HashMap<String, Program>, programs: HashMap<String, Program>,
} }
@ -717,19 +744,11 @@ impl Bpf {
/// ///
/// # Errors /// # Errors
/// ///
/// Returns [`MapError::MapNotFound`] if the map does not exist. If the map is already borrowed /// Returns [`MapError::MapNotFound`] if the map does not exist.
/// mutably with [map_mut](Self::map_mut) then [`MapError::BorrowError`] is returned. pub fn map(&self, name: &str) -> Result<&Map, MapError> {
pub fn map(&self, name: &str) -> Result<MapRef, MapError> { self.maps.get(name).ok_or_else(|| MapError::MapNotFound {
self.maps name: name.to_owned(),
.get(name) })
.ok_or_else(|| MapError::MapNotFound {
name: name.to_owned(),
})
.and_then(|lock| {
lock.try_read().map_err(|_| MapError::BorrowError {
name: name.to_owned(),
})
})
} }
/// Returns a mutable reference to the map with the given name. /// Returns a mutable reference to the map with the given name.
@ -742,19 +761,32 @@ impl Bpf {
/// ///
/// # Errors /// # Errors
/// ///
/// Returns [`MapError::MapNotFound`] if the map does not exist. If the map is already borrowed /// Returns [`MapError::MapNotFound`] if the map does not exist.
/// mutably with [map_mut](Self::map_mut) then [`MapError::BorrowError`] is returned. pub fn map_mut(&mut self, name: &str) -> Result<&mut Map, MapError> {
pub fn map_mut(&self, name: &str) -> Result<MapRefMut, MapError> {
self.maps self.maps
.get(name) .get_mut(name)
.ok_or_else(|| MapError::MapNotFound { .ok_or_else(|| MapError::MapNotFound {
name: name.to_owned(), name: name.to_owned(),
}) })
.and_then(|lock| { }
lock.try_write().map_err(|_| MapError::BorrowError {
name: name.to_owned(), /// Returns a map with the given name.
}) ///
}) /// WARNING: This transfers ownership of the map to the user.
///
/// The returned type is mostly opaque. In order to do anything useful with it you need to
/// convert it to a [typed map](crate::maps).
///
/// For more details and examples on maps and their usage, see the [maps module
/// documentation][crate::maps].
///
/// # Errors
///
/// Returns [`MapError::MapNotFound`] if the map does not exist.
pub fn take_map(&mut self, name: &str) -> Result<Map, MapError> {
self.maps.remove(name).ok_or_else(|| MapError::MapNotFound {
name: name.to_owned(),
})
} }
/// An iterator over all the maps. /// An iterator over all the maps.
@ -764,22 +796,14 @@ impl Bpf {
/// # let mut bpf = aya::Bpf::load(&[])?; /// # let mut bpf = aya::Bpf::load(&[])?;
/// for (name, map) in bpf.maps() { /// for (name, map) in bpf.maps() {
/// println!( /// println!(
/// "found map `{}` of type `{:?}`", /// "found map `{}`",
/// name, /// name,
/// map?.map_type().unwrap()
/// ); /// );
/// } /// }
/// # Ok::<(), aya::BpfError>(()) /// # Ok::<(), aya::BpfError>(())
/// ``` /// ```
pub fn maps(&self) -> impl Iterator<Item = (&str, Result<MapRef, MapError>)> { pub fn maps(&self) -> impl Iterator<Item = (&str, Result<&Map, MapError>)> {
let ret = self.maps.iter().map(|(name, lock)| { self.maps.iter().map(|(name, map)| (name.as_str(), Ok(map)))
(
name.as_str(),
lock.try_read()
.map_err(|_| MapError::BorrowError { name: name.clone() }),
)
});
ret
} }
/// Returns a reference to the program with the given name. /// Returns a reference to the program with the given name.

@ -1,12 +1,11 @@
use std::{ use std::{
convert::{AsMut, AsRef},
marker::PhantomData, marker::PhantomData,
mem, mem,
ops::{Deref, DerefMut},
}; };
use crate::{ use crate::{
generated::bpf_map_type::BPF_MAP_TYPE_ARRAY, maps::{array, IterableMap, MapData, MapError},
maps::{IterableMap, Map, MapError, MapRef, MapRefMut},
sys::{bpf_map_lookup_elem, bpf_map_update_elem}, sys::{bpf_map_lookup_elem, bpf_map_update_elem},
Pod, Pod,
}; };
@ -22,38 +21,35 @@ use crate::{
/// ///
/// # Examples /// # Examples
/// ```no_run /// ```no_run
/// # let bpf = aya::Bpf::load(&[])?; /// # let mut bpf = aya::Bpf::load(&[])?;
/// use aya::maps::Array; /// use aya::maps::Array;
/// ///
/// let mut array = Array::try_from(bpf.map_mut("ARRAY")?)?; /// let mut array: Array<_, u32> = bpf.map_mut("ARRAY")?.try_into()?;
/// array.set(1, 42, 0)?; /// array.set(1, 42, 0)?;
/// assert_eq!(array.get(&1, 0)?, 42); /// assert_eq!(array.get(&1, 0)?, 42);
/// # Ok::<(), aya::BpfError>(()) /// # Ok::<(), aya::BpfError>(())
/// ``` /// ```
#[doc(alias = "BPF_MAP_TYPE_ARRAY")] #[doc(alias = "BPF_MAP_TYPE_ARRAY")]
pub struct Array<T: Deref<Target = Map>, V: Pod> { pub struct Array<T, V: Pod> {
inner: T, inner: T,
_v: PhantomData<V>, _v: PhantomData<V>,
} }
impl<T: Deref<Target = Map>, V: Pod> Array<T, V> { impl<T: AsRef<MapData>, V: Pod> Array<T, V> {
fn new(map: T) -> Result<Array<T, V>, MapError> { pub(crate) fn new(map: T) -> Result<Array<T, V>, MapError> {
let map_type = map.obj.map_type(); let data = map.as_ref();
if map_type != BPF_MAP_TYPE_ARRAY as u32 {
return Err(MapError::InvalidMapType { map_type });
}
let expected = mem::size_of::<u32>(); let expected = mem::size_of::<u32>();
let size = map.obj.key_size() as usize; let size = data.obj.key_size() as usize;
if size != expected { if size != expected {
return Err(MapError::InvalidKeySize { size, expected }); return Err(MapError::InvalidKeySize { size, expected });
} }
let expected = mem::size_of::<V>(); let expected = mem::size_of::<V>();
let size = map.obj.value_size() as usize; let size = data.obj.value_size() as usize;
if size != expected { if size != expected {
return Err(MapError::InvalidValueSize { size, expected }); return Err(MapError::InvalidValueSize { size, expected });
} }
let _fd = map.fd_or_err()?; let _fd = data.fd_or_err()?;
Ok(Array { Ok(Array {
inner: map, inner: map,
@ -65,7 +61,7 @@ impl<T: Deref<Target = Map>, V: Pod> Array<T, V> {
/// ///
/// This corresponds to the value of `bpf_map_def::max_entries` on the eBPF side. /// This corresponds to the value of `bpf_map_def::max_entries` on the eBPF side.
pub fn len(&self) -> u32 { pub fn len(&self) -> u32 {
self.inner.obj.max_entries() self.inner.as_ref().obj.max_entries()
} }
/// Returns the value stored at the given index. /// Returns the value stored at the given index.
@ -75,8 +71,9 @@ impl<T: Deref<Target = Map>, V: Pod> Array<T, V> {
/// Returns [`MapError::OutOfBounds`] if `index` is out of bounds, [`MapError::SyscallError`] /// Returns [`MapError::OutOfBounds`] if `index` is out of bounds, [`MapError::SyscallError`]
/// if `bpf_map_lookup_elem` fails. /// if `bpf_map_lookup_elem` fails.
pub fn get(&self, index: &u32, flags: u64) -> Result<V, MapError> { pub fn get(&self, index: &u32, flags: u64) -> Result<V, MapError> {
self.check_bounds(*index)?; let data = self.inner.as_ref();
let fd = self.inner.fd_or_err()?; array::check_bounds(data, *index)?;
let fd = data.fd_or_err()?;
let value = bpf_map_lookup_elem(fd, index, flags).map_err(|(_, io_error)| { let value = bpf_map_lookup_elem(fd, index, flags).map_err(|(_, io_error)| {
MapError::SyscallError { MapError::SyscallError {
@ -92,18 +89,9 @@ impl<T: Deref<Target = Map>, V: Pod> Array<T, V> {
pub fn iter(&self) -> impl Iterator<Item = Result<V, MapError>> + '_ { pub fn iter(&self) -> impl Iterator<Item = Result<V, MapError>> + '_ {
(0..self.len()).map(move |i| self.get(&i, 0)) (0..self.len()).map(move |i| self.get(&i, 0))
} }
fn check_bounds(&self, index: u32) -> Result<(), MapError> {
let max_entries = self.inner.obj.max_entries();
if index >= self.inner.obj.max_entries() {
Err(MapError::OutOfBounds { index, max_entries })
} else {
Ok(())
}
}
} }
impl<T: Deref<Target = Map> + DerefMut<Target = Map>, V: Pod> Array<T, V> { impl<T: AsMut<MapData>, V: Pod> Array<T, V> {
/// Sets the value of the element at the given index. /// Sets the value of the element at the given index.
/// ///
/// # Errors /// # Errors
@ -111,8 +99,9 @@ impl<T: Deref<Target = Map> + DerefMut<Target = Map>, V: Pod> Array<T, V> {
/// Returns [`MapError::OutOfBounds`] if `index` is out of bounds, [`MapError::SyscallError`] /// Returns [`MapError::OutOfBounds`] if `index` is out of bounds, [`MapError::SyscallError`]
/// if `bpf_map_update_elem` fails. /// if `bpf_map_update_elem` fails.
pub fn set(&mut self, index: u32, value: V, flags: u64) -> Result<(), MapError> { pub fn set(&mut self, index: u32, value: V, flags: u64) -> Result<(), MapError> {
let fd = self.inner.fd_or_err()?; let data = self.inner.as_mut();
self.check_bounds(index)?; array::check_bounds(data, index)?;
let fd = data.fd_or_err()?;
bpf_map_update_elem(fd, Some(&index), &value, flags).map_err(|(_, io_error)| { bpf_map_update_elem(fd, Some(&index), &value, flags).map_err(|(_, io_error)| {
MapError::SyscallError { MapError::SyscallError {
call: "bpf_map_update_elem".to_owned(), call: "bpf_map_update_elem".to_owned(),
@ -123,28 +112,12 @@ impl<T: Deref<Target = Map> + DerefMut<Target = Map>, V: Pod> Array<T, V> {
} }
} }
impl<T: Deref<Target = Map>, V: Pod> IterableMap<u32, V> for Array<T, V> { impl<T: AsRef<MapData>, V: Pod> IterableMap<u32, V> for Array<T, V> {
fn map(&self) -> &Map { fn map(&self) -> &MapData {
&self.inner self.inner.as_ref()
} }
fn get(&self, index: &u32) -> Result<V, MapError> { fn get(&self, index: &u32) -> Result<V, MapError> {
self.get(index, 0) self.get(index, 0)
} }
} }
impl<V: Pod> TryFrom<MapRef> for Array<MapRef, V> {
type Error = MapError;
fn try_from(a: MapRef) -> Result<Array<MapRef, V>, MapError> {
Array::new(a)
}
}
impl<V: Pod> TryFrom<MapRefMut> for Array<MapRefMut, V> {
type Error = MapError;
fn try_from(a: MapRefMut) -> Result<Array<MapRefMut, V>, MapError> {
Array::new(a)
}
}

@ -4,6 +4,17 @@ mod array;
mod per_cpu_array; mod per_cpu_array;
mod program_array; mod program_array;
pub use array::Array; pub use array::*;
pub use per_cpu_array::PerCpuArray; pub use per_cpu_array::PerCpuArray;
pub use program_array::ProgramArray; pub use program_array::ProgramArray;
use crate::maps::{MapData, MapError};
pub(crate) fn check_bounds(map: &MapData, index: u32) -> Result<(), MapError> {
let max_entries = map.obj.max_entries();
if index >= map.obj.max_entries() {
Err(MapError::OutOfBounds { index, max_entries })
} else {
Ok(())
}
}

@ -1,12 +1,11 @@
use std::{ use std::{
convert::{AsMut, AsRef},
marker::PhantomData, marker::PhantomData,
mem, mem,
ops::{Deref, DerefMut},
}; };
use crate::{ use crate::{
generated::bpf_map_type::BPF_MAP_TYPE_PERCPU_ARRAY, maps::{array, IterableMap, MapData, MapError, PerCpuValues},
maps::{IterableMap, Map, MapError, MapRef, MapRefMut, PerCpuValues},
sys::{bpf_map_lookup_elem_per_cpu, bpf_map_update_elem_per_cpu}, sys::{bpf_map_lookup_elem_per_cpu, bpf_map_update_elem_per_cpu},
Pod, Pod,
}; };
@ -31,11 +30,11 @@ use crate::{
/// # #[error(transparent)] /// # #[error(transparent)]
/// # Bpf(#[from] aya::BpfError) /// # Bpf(#[from] aya::BpfError)
/// # } /// # }
/// # let bpf = aya::Bpf::load(&[])?; /// # let mut bpf = aya::Bpf::load(&[])?;
/// use aya::maps::{PerCpuArray, PerCpuValues}; /// use aya::maps::{PerCpuArray, PerCpuValues};
/// use aya::util::nr_cpus; /// use aya::util::nr_cpus;
/// ///
/// let mut array = PerCpuArray::try_from(bpf.map_mut("ARRAY")?)?; /// let mut array: PerCpuArray<_,u32> = bpf.map_mut("ARRAY")?.try_into()?;
/// ///
/// // set array[1] = 42 for all cpus /// // set array[1] = 42 for all cpus
/// let nr_cpus = nr_cpus()?; /// let nr_cpus = nr_cpus()?;
@ -50,29 +49,26 @@ use crate::{
/// # Ok::<(), Error>(()) /// # Ok::<(), Error>(())
/// ``` /// ```
#[doc(alias = "BPF_MAP_TYPE_PERCPU_ARRAY")] #[doc(alias = "BPF_MAP_TYPE_PERCPU_ARRAY")]
pub struct PerCpuArray<T: Deref<Target = Map>, V: Pod> { pub struct PerCpuArray<T, V: Pod> {
inner: T, inner: T,
_v: PhantomData<V>, _v: PhantomData<V>,
} }
impl<T: Deref<Target = Map>, V: Pod> PerCpuArray<T, V> { impl<T: AsRef<MapData>, V: Pod> PerCpuArray<T, V> {
fn new(map: T) -> Result<PerCpuArray<T, V>, MapError> { pub(crate) fn new(map: T) -> Result<PerCpuArray<T, V>, MapError> {
let map_type = map.obj.map_type(); let data = map.as_ref();
if map_type != BPF_MAP_TYPE_PERCPU_ARRAY as u32 {
return Err(MapError::InvalidMapType { map_type });
}
let expected = mem::size_of::<u32>(); let expected = mem::size_of::<u32>();
let size = map.obj.key_size() as usize; let size = data.obj.key_size() as usize;
if size != expected { if size != expected {
return Err(MapError::InvalidKeySize { size, expected }); return Err(MapError::InvalidKeySize { size, expected });
} }
let expected = mem::size_of::<V>(); let expected = mem::size_of::<V>();
let size = map.obj.value_size() as usize; let size = data.obj.value_size() as usize;
if size != expected { if size != expected {
return Err(MapError::InvalidValueSize { size, expected }); return Err(MapError::InvalidValueSize { size, expected });
} }
let _fd = map.fd_or_err()?; let _fd = data.fd_or_err()?;
Ok(PerCpuArray { Ok(PerCpuArray {
inner: map, inner: map,
@ -84,7 +80,7 @@ impl<T: Deref<Target = Map>, V: Pod> PerCpuArray<T, V> {
/// ///
/// This corresponds to the value of `bpf_map_def::max_entries` on the eBPF side. /// This corresponds to the value of `bpf_map_def::max_entries` on the eBPF side.
pub fn len(&self) -> u32 { pub fn len(&self) -> u32 {
self.inner.obj.max_entries() self.inner.as_ref().obj.max_entries()
} }
/// Returns a slice of values - one for each CPU - stored at the given index. /// Returns a slice of values - one for each CPU - stored at the given index.
@ -94,8 +90,9 @@ impl<T: Deref<Target = Map>, V: Pod> PerCpuArray<T, V> {
/// Returns [`MapError::OutOfBounds`] if `index` is out of bounds, [`MapError::SyscallError`] /// Returns [`MapError::OutOfBounds`] if `index` is out of bounds, [`MapError::SyscallError`]
/// if `bpf_map_lookup_elem` fails. /// if `bpf_map_lookup_elem` fails.
pub fn get(&self, index: &u32, flags: u64) -> Result<PerCpuValues<V>, MapError> { pub fn get(&self, index: &u32, flags: u64) -> Result<PerCpuValues<V>, MapError> {
self.check_bounds(*index)?; let data = self.inner.as_ref();
let fd = self.inner.fd_or_err()?; array::check_bounds(data, *index)?;
let fd = data.fd_or_err()?;
let value = bpf_map_lookup_elem_per_cpu(fd, index, flags).map_err(|(_, io_error)| { let value = bpf_map_lookup_elem_per_cpu(fd, index, flags).map_err(|(_, io_error)| {
MapError::SyscallError { MapError::SyscallError {
@ -111,18 +108,9 @@ impl<T: Deref<Target = Map>, V: Pod> PerCpuArray<T, V> {
pub fn iter(&self) -> impl Iterator<Item = Result<PerCpuValues<V>, MapError>> + '_ { pub fn iter(&self) -> impl Iterator<Item = Result<PerCpuValues<V>, MapError>> + '_ {
(0..self.len()).map(move |i| self.get(&i, 0)) (0..self.len()).map(move |i| self.get(&i, 0))
} }
fn check_bounds(&self, index: u32) -> Result<(), MapError> {
let max_entries = self.inner.obj.max_entries();
if index >= self.inner.obj.max_entries() {
Err(MapError::OutOfBounds { index, max_entries })
} else {
Ok(())
}
}
} }
impl<T: Deref<Target = Map> + DerefMut<Target = Map>, V: Pod> PerCpuArray<T, V> { impl<T: AsMut<MapData>, V: Pod> PerCpuArray<T, V> {
/// Sets the values - one for each CPU - at the given index. /// Sets the values - one for each CPU - at the given index.
/// ///
/// # Errors /// # Errors
@ -130,8 +118,10 @@ impl<T: Deref<Target = Map> + DerefMut<Target = Map>, V: Pod> PerCpuArray<T, V>
/// Returns [`MapError::OutOfBounds`] if `index` is out of bounds, [`MapError::SyscallError`] /// Returns [`MapError::OutOfBounds`] if `index` is out of bounds, [`MapError::SyscallError`]
/// if `bpf_map_update_elem` fails. /// if `bpf_map_update_elem` fails.
pub fn set(&mut self, index: u32, values: PerCpuValues<V>, flags: u64) -> Result<(), MapError> { pub fn set(&mut self, index: u32, values: PerCpuValues<V>, flags: u64) -> Result<(), MapError> {
let fd = self.inner.fd_or_err()?; let data = self.inner.as_mut();
self.check_bounds(index)?; array::check_bounds(data, index)?;
let fd = data.fd_or_err()?;
bpf_map_update_elem_per_cpu(fd, &index, &values, flags).map_err(|(_, io_error)| { bpf_map_update_elem_per_cpu(fd, &index, &values, flags).map_err(|(_, io_error)| {
MapError::SyscallError { MapError::SyscallError {
call: "bpf_map_update_elem".to_owned(), call: "bpf_map_update_elem".to_owned(),
@ -142,28 +132,12 @@ impl<T: Deref<Target = Map> + DerefMut<Target = Map>, V: Pod> PerCpuArray<T, V>
} }
} }
impl<T: Deref<Target = Map>, V: Pod> IterableMap<u32, PerCpuValues<V>> for PerCpuArray<T, V> { impl<T: AsRef<MapData>, V: Pod> IterableMap<u32, PerCpuValues<V>> for PerCpuArray<T, V> {
fn map(&self) -> &Map { fn map(&self) -> &MapData {
&self.inner self.inner.as_ref()
} }
fn get(&self, index: &u32) -> Result<PerCpuValues<V>, MapError> { fn get(&self, index: &u32) -> Result<PerCpuValues<V>, MapError> {
self.get(index, 0) self.get(index, 0)
} }
} }
impl<V: Pod> TryFrom<MapRef> for PerCpuArray<MapRef, V> {
type Error = MapError;
fn try_from(a: MapRef) -> Result<PerCpuArray<MapRef, V>, MapError> {
PerCpuArray::new(a)
}
}
impl<V: Pod> TryFrom<MapRefMut> for PerCpuArray<MapRefMut, V> {
type Error = MapError;
fn try_from(a: MapRefMut) -> Result<PerCpuArray<MapRefMut, V>, MapError> {
PerCpuArray::new(a)
}
}

@ -1,14 +1,13 @@
//! An array of eBPF program file descriptors used as a jump table. //! An array of eBPF program file descriptors used as a jump table.
use std::{ use std::{
convert::{AsMut, AsRef},
mem, mem,
ops::{Deref, DerefMut},
os::unix::prelude::{AsRawFd, RawFd}, os::unix::prelude::{AsRawFd, RawFd},
}; };
use crate::{ use crate::{
generated::bpf_map_type::BPF_MAP_TYPE_PROG_ARRAY, maps::{array, MapData, MapError, MapKeys},
maps::{Map, MapError, MapKeys, MapRef, MapRefMut},
programs::ProgramFd, programs::ProgramFd,
sys::{bpf_map_delete_elem, bpf_map_update_elem}, sys::{bpf_map_delete_elem, bpf_map_update_elem},
}; };
@ -29,7 +28,7 @@ use crate::{
/// use aya::maps::ProgramArray; /// use aya::maps::ProgramArray;
/// use aya::programs::CgroupSkb; /// use aya::programs::CgroupSkb;
/// ///
/// let mut prog_array = ProgramArray::try_from(bpf.map_mut("JUMP_TABLE")?)?; /// let mut prog_array: ProgramArray<_> = bpf.take_map("JUMP_TABLE")?.try_into()?;
/// let prog_0: &CgroupSkb = bpf.program("example_prog_0").unwrap().try_into()?; /// let prog_0: &CgroupSkb = bpf.program("example_prog_0").unwrap().try_into()?;
/// let prog_0_fd = prog_0.fd().unwrap(); /// let prog_0_fd = prog_0.fd().unwrap();
/// let prog_1: &CgroupSkb = bpf.program("example_prog_1").unwrap().try_into()?; /// let prog_1: &CgroupSkb = bpf.program("example_prog_1").unwrap().try_into()?;
@ -49,28 +48,25 @@ use crate::{
/// # Ok::<(), aya::BpfError>(()) /// # Ok::<(), aya::BpfError>(())
/// ``` /// ```
#[doc(alias = "BPF_MAP_TYPE_PROG_ARRAY")] #[doc(alias = "BPF_MAP_TYPE_PROG_ARRAY")]
pub struct ProgramArray<T: Deref<Target = Map>> { pub struct ProgramArray<T> {
inner: T, inner: T,
} }
impl<T: Deref<Target = Map>> ProgramArray<T> { impl<T: AsRef<MapData>> ProgramArray<T> {
fn new(map: T) -> Result<ProgramArray<T>, MapError> { pub(crate) fn new(map: T) -> Result<ProgramArray<T>, MapError> {
let map_type = map.obj.map_type(); let data = map.as_ref();
if map_type != BPF_MAP_TYPE_PROG_ARRAY as u32 {
return Err(MapError::InvalidMapType { map_type });
}
let expected = mem::size_of::<u32>(); let expected = mem::size_of::<u32>();
let size = map.obj.key_size() as usize; let size = data.obj.key_size() as usize;
if size != expected { if size != expected {
return Err(MapError::InvalidKeySize { size, expected }); return Err(MapError::InvalidKeySize { size, expected });
} }
let expected = mem::size_of::<RawFd>(); let expected = mem::size_of::<RawFd>();
let size = map.obj.value_size() as usize; let size = data.obj.value_size() as usize;
if size != expected { if size != expected {
return Err(MapError::InvalidValueSize { size, expected }); return Err(MapError::InvalidValueSize { size, expected });
} }
let _fd = map.fd_or_err()?; let _fd = data.fd_or_err()?;
Ok(ProgramArray { inner: map }) Ok(ProgramArray { inner: map })
} }
@ -78,27 +74,19 @@ impl<T: Deref<Target = Map>> ProgramArray<T> {
/// An iterator over the indices of the array that point to a program. The iterator item type /// An iterator over the indices of the array that point to a program. The iterator item type
/// is `Result<u32, MapError>`. /// is `Result<u32, MapError>`.
pub fn indices(&self) -> MapKeys<'_, u32> { pub fn indices(&self) -> MapKeys<'_, u32> {
MapKeys::new(&self.inner) MapKeys::new(self.inner.as_ref())
}
fn check_bounds(&self, index: u32) -> Result<(), MapError> {
let max_entries = self.inner.obj.max_entries();
if index >= self.inner.obj.max_entries() {
Err(MapError::OutOfBounds { index, max_entries })
} else {
Ok(())
}
} }
} }
impl<T: Deref<Target = Map> + DerefMut<Target = Map>> ProgramArray<T> { impl<T: AsMut<MapData>> ProgramArray<T> {
/// Sets the target program file descriptor for the given index in the jump table. /// Sets the target program file descriptor for the given index in the jump table.
/// ///
/// When an eBPF program calls `bpf_tail_call(ctx, prog_array, index)`, control /// When an eBPF program calls `bpf_tail_call(ctx, prog_array, index)`, control
/// flow will jump to `program`. /// flow will jump to `program`.
pub fn set(&mut self, index: u32, program: ProgramFd, flags: u64) -> Result<(), MapError> { pub fn set(&mut self, index: u32, program: ProgramFd, flags: u64) -> Result<(), MapError> {
let fd = self.inner.fd_or_err()?; let data = self.inner.as_mut();
self.check_bounds(index)?; array::check_bounds(data, index)?;
let fd = data.fd_or_err()?;
let prog_fd = program.as_raw_fd(); let prog_fd = program.as_raw_fd();
bpf_map_update_elem(fd, Some(&index), &prog_fd, flags).map_err(|(_, io_error)| { bpf_map_update_elem(fd, Some(&index), &prog_fd, flags).map_err(|(_, io_error)| {
@ -115,8 +103,10 @@ impl<T: Deref<Target = Map> + DerefMut<Target = Map>> ProgramArray<T> {
/// Calling `bpf_tail_call(ctx, prog_array, index)` on an index that has been cleared returns an /// Calling `bpf_tail_call(ctx, prog_array, index)` on an index that has been cleared returns an
/// error. /// error.
pub fn clear_index(&mut self, index: &u32) -> Result<(), MapError> { pub fn clear_index(&mut self, index: &u32) -> Result<(), MapError> {
let fd = self.inner.fd_or_err()?; let data = self.inner.as_mut();
self.check_bounds(*index)?; array::check_bounds(data, *index)?;
let fd = self.inner.as_mut().fd_or_err()?;
bpf_map_delete_elem(fd, index) bpf_map_delete_elem(fd, index)
.map(|_| ()) .map(|_| ())
.map_err(|(_, io_error)| MapError::SyscallError { .map_err(|(_, io_error)| MapError::SyscallError {
@ -125,19 +115,3 @@ impl<T: Deref<Target = Map> + DerefMut<Target = Map>> ProgramArray<T> {
}) })
} }
} }
impl TryFrom<MapRef> for ProgramArray<MapRef> {
type Error = MapError;
fn try_from(a: MapRef) -> Result<ProgramArray<MapRef>, MapError> {
ProgramArray::new(a)
}
}
impl TryFrom<MapRefMut> for ProgramArray<MapRefMut> {
type Error = MapError;
fn try_from(a: MapRefMut) -> Result<ProgramArray<MapRefMut>, MapError> {
ProgramArray::new(a)
}
}

@ -1,11 +1,10 @@
//! A Bloom Filter. //! A Bloom Filter.
use std::{marker::PhantomData, ops::Deref}; use std::{convert::AsRef, marker::PhantomData};
use core::mem; use core::mem;
use crate::{ use crate::{
generated::bpf_map_type::BPF_MAP_TYPE_BLOOM_FILTER, maps::{MapData, MapError},
maps::{Map, MapError, MapRef, MapRefMut},
sys::{bpf_map_lookup_elem_ptr, bpf_map_push_elem}, sys::{bpf_map_lookup_elem_ptr, bpf_map_push_elem},
Pod, Pod,
}; };
@ -19,10 +18,10 @@ use crate::{
/// # Examples /// # Examples
/// ///
/// ```no_run /// ```no_run
/// # let bpf = aya::Bpf::load(&[])?; /// # let mut bpf = aya::Bpf::load(&[])?;
/// use aya::maps::bloom_filter::BloomFilter; /// use aya::maps::bloom_filter::BloomFilter;
/// ///
/// let mut bloom_filter = BloomFilter::try_from(bpf.map_mut("BLOOM_FILTER")?)?; /// let mut bloom_filter: BloomFilter<_,u32> = bpf.map_mut("BLOOM_FILTER")?.try_into()?;
/// ///
/// bloom_filter.insert(1, 0)?; /// bloom_filter.insert(1, 0)?;
/// ///
@ -33,27 +32,21 @@ use crate::{
/// ``` /// ```
#[doc(alias = "BPF_MAP_TYPE_BLOOM_FILTER")] #[doc(alias = "BPF_MAP_TYPE_BLOOM_FILTER")]
pub struct BloomFilter<T: Deref<Target = Map>, V: Pod> { pub struct BloomFilter<T, V: Pod> {
inner: T, inner: T,
_v: PhantomData<V>, _v: PhantomData<V>,
} }
impl<T: Deref<Target = Map>, V: Pod> BloomFilter<T, V> { impl<T: AsRef<MapData>, V: Pod> BloomFilter<T, V> {
pub(crate) fn new(map: T) -> Result<BloomFilter<T, V>, MapError> { pub(crate) fn new(map: T) -> Result<BloomFilter<T, V>, MapError> {
let map_type = map.obj.map_type(); let data = map.as_ref();
// validate the map definition
if map_type != BPF_MAP_TYPE_BLOOM_FILTER as u32 {
return Err(MapError::InvalidMapType { map_type });
}
let size = mem::size_of::<V>(); let size = mem::size_of::<V>();
let expected = map.obj.value_size() as usize; let expected = data.obj.value_size() as usize;
if size != expected { if size != expected {
return Err(MapError::InvalidValueSize { size, expected }); return Err(MapError::InvalidValueSize { size, expected });
}; };
let _ = map.fd_or_err()?; let _ = data.fd_or_err()?;
Ok(BloomFilter { Ok(BloomFilter {
inner: map, inner: map,
@ -63,7 +56,7 @@ impl<T: Deref<Target = Map>, V: Pod> BloomFilter<T, V> {
/// Query the existence of the element. /// Query the existence of the element.
pub fn contains(&self, mut value: &V, flags: u64) -> Result<(), MapError> { pub fn contains(&self, mut value: &V, flags: u64) -> Result<(), MapError> {
let fd = self.inner.deref().fd_or_err()?; let fd = self.inner.as_ref().fd_or_err()?;
bpf_map_lookup_elem_ptr::<u32, _>(fd, None, &mut value, flags) bpf_map_lookup_elem_ptr::<u32, _>(fd, None, &mut value, flags)
.map_err(|(_, io_error)| MapError::SyscallError { .map_err(|(_, io_error)| MapError::SyscallError {
@ -76,7 +69,7 @@ impl<T: Deref<Target = Map>, V: Pod> BloomFilter<T, V> {
/// Inserts a value into the map. /// Inserts a value into the map.
pub fn insert(&self, value: V, flags: u64) -> Result<(), MapError> { pub fn insert(&self, value: V, flags: u64) -> Result<(), MapError> {
let fd = self.inner.deref().fd_or_err()?; let fd = self.inner.as_ref().fd_or_err()?;
bpf_map_push_elem(fd, &value, flags).map_err(|(_, io_error)| MapError::SyscallError { bpf_map_push_elem(fd, &value, flags).map_err(|(_, io_error)| MapError::SyscallError {
call: "bpf_map_push_elem".to_owned(), call: "bpf_map_push_elem".to_owned(),
io_error, io_error,
@ -85,38 +78,6 @@ impl<T: Deref<Target = Map>, V: Pod> BloomFilter<T, V> {
} }
} }
impl<V: Pod> TryFrom<MapRef> for BloomFilter<MapRef, V> {
type Error = MapError;
fn try_from(a: MapRef) -> Result<BloomFilter<MapRef, V>, MapError> {
BloomFilter::new(a)
}
}
impl<V: Pod> TryFrom<MapRefMut> for BloomFilter<MapRefMut, V> {
type Error = MapError;
fn try_from(a: MapRefMut) -> Result<BloomFilter<MapRefMut, V>, MapError> {
BloomFilter::new(a)
}
}
impl<'a, V: Pod> TryFrom<&'a Map> for BloomFilter<&'a Map, V> {
type Error = MapError;
fn try_from(a: &'a Map) -> Result<BloomFilter<&'a Map, V>, MapError> {
BloomFilter::new(a)
}
}
impl<'a, V: Pod> TryFrom<&'a mut Map> for BloomFilter<&'a mut Map, V> {
type Error = MapError;
fn try_from(a: &'a mut Map) -> Result<BloomFilter<&'a mut Map, V>, MapError> {
BloomFilter::new(a)
}
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
@ -126,6 +87,7 @@ mod tests {
bpf_cmd, bpf_cmd,
bpf_map_type::{BPF_MAP_TYPE_BLOOM_FILTER, BPF_MAP_TYPE_PERF_EVENT_ARRAY}, bpf_map_type::{BPF_MAP_TYPE_BLOOM_FILTER, BPF_MAP_TYPE_PERF_EVENT_ARRAY},
}, },
maps::{Map, MapData},
obj, obj,
sys::{override_syscall, SysResult, Syscall}, sys::{override_syscall, SysResult, Syscall},
}; };
@ -154,7 +116,7 @@ mod tests {
#[test] #[test]
fn test_wrong_value_size() { fn test_wrong_value_size() {
let map = Map { let map = MapData {
obj: new_obj_map(), obj: new_obj_map(),
fd: None, fd: None,
pinned: false, pinned: false,
@ -171,7 +133,7 @@ mod tests {
#[test] #[test]
fn test_try_from_wrong_map() { fn test_try_from_wrong_map() {
let map = Map { let map_data = MapData {
obj: obj::Map::Legacy(obj::LegacyMap { obj: obj::Map::Legacy(obj::LegacyMap {
def: bpf_map_def { def: bpf_map_def {
map_type: BPF_MAP_TYPE_PERF_EVENT_ARRAY as u32, map_type: BPF_MAP_TYPE_PERF_EVENT_ARRAY as u32,
@ -190,15 +152,17 @@ mod tests {
btf_fd: None, btf_fd: None,
}; };
let map = Map::PerfEventArray(map_data);
assert!(matches!( assert!(matches!(
BloomFilter::<_, u32>::try_from(&map), BloomFilter::<_, u32>::try_from(&map),
Err(MapError::InvalidMapType { .. }) Err(MapError::UnexpectedMapType)
)); ));
} }
#[test] #[test]
fn test_new_not_created() { fn test_new_not_created() {
let mut map = Map { let mut map = MapData {
obj: new_obj_map(), obj: new_obj_map(),
fd: None, fd: None,
pinned: false, pinned: false,
@ -213,7 +177,7 @@ mod tests {
#[test] #[test]
fn test_new_ok() { fn test_new_ok() {
let mut map = Map { let mut map = MapData {
obj: new_obj_map(), obj: new_obj_map(),
fd: Some(42), fd: Some(42),
pinned: false, pinned: false,
@ -225,12 +189,14 @@ mod tests {
#[test] #[test]
fn test_try_from_ok() { fn test_try_from_ok() {
let map = Map { let map_data = MapData {
obj: new_obj_map(), obj: new_obj_map(),
fd: Some(42), fd: Some(42),
pinned: false, pinned: false,
btf_fd: None, btf_fd: None,
}; };
let map = Map::BloomFilter(map_data);
assert!(BloomFilter::<_, u32>::try_from(&map).is_ok()) assert!(BloomFilter::<_, u32>::try_from(&map).is_ok())
} }
@ -238,7 +204,7 @@ mod tests {
fn test_insert_syscall_error() { fn test_insert_syscall_error() {
override_syscall(|_| sys_error(EFAULT)); override_syscall(|_| sys_error(EFAULT));
let mut map = Map { let mut map = MapData {
obj: new_obj_map(), obj: new_obj_map(),
fd: Some(42), fd: Some(42),
pinned: false, pinned: false,
@ -262,7 +228,7 @@ mod tests {
_ => sys_error(EFAULT), _ => sys_error(EFAULT),
}); });
let mut map = Map { let mut map = MapData {
obj: new_obj_map(), obj: new_obj_map(),
fd: Some(42), fd: Some(42),
pinned: false, pinned: false,
@ -276,7 +242,7 @@ mod tests {
#[test] #[test]
fn test_contains_syscall_error() { fn test_contains_syscall_error() {
override_syscall(|_| sys_error(EFAULT)); override_syscall(|_| sys_error(EFAULT));
let map = Map { let map = MapData {
obj: new_obj_map(), obj: new_obj_map(),
fd: Some(42), fd: Some(42),
pinned: false, pinned: false,
@ -299,7 +265,7 @@ mod tests {
} => sys_error(ENOENT), } => sys_error(ENOENT),
_ => sys_error(EFAULT), _ => sys_error(EFAULT),
}); });
let map = Map { let map = MapData {
obj: new_obj_map(), obj: new_obj_map(),
fd: Some(42), fd: Some(42),
pinned: false, pinned: false,

@ -1,11 +1,10 @@
use std::{ use std::{
convert::{AsMut, AsRef},
marker::PhantomData, marker::PhantomData,
ops::{Deref, DerefMut},
}; };
use crate::{ use crate::{
generated::bpf_map_type::{BPF_MAP_TYPE_HASH, BPF_MAP_TYPE_LRU_HASH}, maps::{hash_map, IterableMap, MapData, MapError, MapIter, MapKeys},
maps::{hash_map, IterableMap, Map, MapError, MapIter, MapKeys, MapRef, MapRefMut},
sys::bpf_map_lookup_elem, sys::bpf_map_lookup_elem,
Pod, Pod,
}; };
@ -19,10 +18,10 @@ use crate::{
/// # Examples /// # Examples
/// ///
/// ```no_run /// ```no_run
/// # let bpf = aya::Bpf::load(&[])?; /// # let mut bpf = aya::Bpf::load(&[])?;
/// use aya::maps::HashMap; /// use aya::maps::HashMap;
/// ///
/// let mut redirect_ports = HashMap::try_from(bpf.map_mut("REDIRECT_PORTS")?)?; /// let mut redirect_ports: HashMap<_, u32, u32> = bpf.map_mut("REDIRECT_PORTS")?.try_into()?;
/// ///
/// // redirect port 80 to 8080 /// // redirect port 80 to 8080
/// redirect_ports.insert(80, 8080, 0); /// redirect_ports.insert(80, 8080, 0);
@ -32,22 +31,18 @@ use crate::{
/// ``` /// ```
#[doc(alias = "BPF_MAP_TYPE_HASH")] #[doc(alias = "BPF_MAP_TYPE_HASH")]
#[doc(alias = "BPF_MAP_TYPE_LRU_HASH")] #[doc(alias = "BPF_MAP_TYPE_LRU_HASH")]
pub struct HashMap<T: Deref<Target = Map>, K, V> { #[derive(Debug)]
pub struct HashMap<T, K, V> {
inner: T, inner: T,
_k: PhantomData<K>, _k: PhantomData<K>,
_v: PhantomData<V>, _v: PhantomData<V>,
} }
impl<T: Deref<Target = Map>, K: Pod, V: Pod> HashMap<T, K, V> { impl<T: AsRef<MapData>, K: Pod, V: Pod> HashMap<T, K, V> {
pub(crate) fn new(map: T) -> Result<HashMap<T, K, V>, MapError> { pub(crate) fn new(map: T) -> Result<HashMap<T, K, V>, MapError> {
let map_type = map.obj.map_type(); let data = map.as_ref();
hash_map::check_kv_size::<K, V>(data)?;
// validate the map definition let _ = data.fd_or_err()?;
if map_type != BPF_MAP_TYPE_HASH as u32 && map_type != BPF_MAP_TYPE_LRU_HASH as u32 {
return Err(MapError::InvalidMapType { map_type });
}
hash_map::check_kv_size::<K, V>(&map)?;
let _ = map.fd_or_err()?;
Ok(HashMap { Ok(HashMap {
inner: map, inner: map,
@ -58,7 +53,7 @@ impl<T: Deref<Target = Map>, K: Pod, V: Pod> HashMap<T, K, V> {
/// Returns a copy of the value associated with the key. /// Returns a copy of the value associated with the key.
pub fn get(&self, key: &K, flags: u64) -> Result<V, MapError> { pub fn get(&self, key: &K, flags: u64) -> Result<V, MapError> {
let fd = self.inner.deref().fd_or_err()?; let fd = self.inner.as_ref().fd_or_err()?;
let value = bpf_map_lookup_elem(fd, key, flags).map_err(|(_, io_error)| { let value = bpf_map_lookup_elem(fd, key, flags).map_err(|(_, io_error)| {
MapError::SyscallError { MapError::SyscallError {
call: "bpf_map_lookup_elem".to_owned(), call: "bpf_map_lookup_elem".to_owned(),
@ -77,25 +72,25 @@ impl<T: Deref<Target = Map>, K: Pod, V: Pod> HashMap<T, K, V> {
/// An iterator visiting all keys in arbitrary order. The iterator element /// An iterator visiting all keys in arbitrary order. The iterator element
/// type is `Result<K, MapError>`. /// type is `Result<K, MapError>`.
pub fn keys(&self) -> MapKeys<'_, K> { pub fn keys(&self) -> MapKeys<'_, K> {
MapKeys::new(&self.inner) MapKeys::new(self.inner.as_ref())
} }
} }
impl<T: DerefMut<Target = Map>, K: Pod, V: Pod> HashMap<T, K, V> { impl<T: AsMut<MapData>, K: Pod, V: Pod> HashMap<T, K, V> {
/// Inserts a key-value pair into the map. /// Inserts a key-value pair into the map.
pub fn insert(&mut self, key: K, value: V, flags: u64) -> Result<(), MapError> { pub fn insert(&mut self, key: K, value: V, flags: u64) -> Result<(), MapError> {
hash_map::insert(&mut self.inner, key, value, flags) hash_map::insert(self.inner.as_mut(), key, value, flags)
} }
/// Removes a key from the map. /// Removes a key from the map.
pub fn remove(&mut self, key: &K) -> Result<(), MapError> { pub fn remove(&mut self, key: &K) -> Result<(), MapError> {
hash_map::remove(&mut self.inner, key) hash_map::remove(self.inner.as_mut(), key)
} }
} }
impl<T: Deref<Target = Map>, K: Pod, V: Pod> IterableMap<K, V> for HashMap<T, K, V> { impl<T: AsRef<MapData>, K: Pod, V: Pod> IterableMap<K, V> for HashMap<T, K, V> {
fn map(&self) -> &Map { fn map(&self) -> &MapData {
&self.inner self.inner.as_ref()
} }
fn get(&self, key: &K) -> Result<V, MapError> { fn get(&self, key: &K) -> Result<V, MapError> {
@ -103,38 +98,6 @@ impl<T: Deref<Target = Map>, K: Pod, V: Pod> IterableMap<K, V> for HashMap<T, K,
} }
} }
impl<K: Pod, V: Pod> TryFrom<MapRef> for HashMap<MapRef, K, V> {
type Error = MapError;
fn try_from(a: MapRef) -> Result<HashMap<MapRef, K, V>, MapError> {
HashMap::new(a)
}
}
impl<K: Pod, V: Pod> TryFrom<MapRefMut> for HashMap<MapRefMut, K, V> {
type Error = MapError;
fn try_from(a: MapRefMut) -> Result<HashMap<MapRefMut, K, V>, MapError> {
HashMap::new(a)
}
}
impl<'a, K: Pod, V: Pod> TryFrom<&'a Map> for HashMap<&'a Map, K, V> {
type Error = MapError;
fn try_from(a: &'a Map) -> Result<HashMap<&'a Map, K, V>, MapError> {
HashMap::new(a)
}
}
impl<'a, K: Pod, V: Pod> TryFrom<&'a mut Map> for HashMap<&'a mut Map, K, V> {
type Error = MapError;
fn try_from(a: &'a mut Map) -> Result<HashMap<&'a mut Map, K, V>, MapError> {
HashMap::new(a)
}
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use std::io; use std::io;
@ -145,8 +108,9 @@ mod tests {
bpf_map_def, bpf_map_def,
generated::{ generated::{
bpf_attr, bpf_cmd, bpf_attr, bpf_cmd,
bpf_map_type::{BPF_MAP_TYPE_HASH, BPF_MAP_TYPE_PERF_EVENT_ARRAY}, bpf_map_type::{BPF_MAP_TYPE_HASH, BPF_MAP_TYPE_LRU_HASH},
}, },
maps::{Map, MapData},
obj, obj,
sys::{override_syscall, SysResult, Syscall}, sys::{override_syscall, SysResult, Syscall},
}; };
@ -175,7 +139,7 @@ mod tests {
#[test] #[test]
fn test_wrong_key_size() { fn test_wrong_key_size() {
let map = Map { let map = MapData {
obj: new_obj_map(), obj: new_obj_map(),
fd: None, fd: None,
pinned: false, pinned: false,
@ -192,7 +156,7 @@ mod tests {
#[test] #[test]
fn test_wrong_value_size() { fn test_wrong_value_size() {
let map = Map { let map = MapData {
obj: new_obj_map(), obj: new_obj_map(),
fd: None, fd: None,
pinned: false, pinned: false,
@ -209,34 +173,42 @@ mod tests {
#[test] #[test]
fn test_try_from_wrong_map() { fn test_try_from_wrong_map() {
let map = Map { let map_data = MapData {
obj: obj::Map::Legacy(obj::LegacyMap { obj: new_obj_map(),
def: bpf_map_def { fd: None,
map_type: BPF_MAP_TYPE_PERF_EVENT_ARRAY as u32, pinned: false,
key_size: 4, btf_fd: None,
value_size: 4, };
max_entries: 1024,
..Default::default() let map = Map::Array(map_data);
}, assert!(matches!(
section_index: 0, HashMap::<_, u8, u32>::try_from(&map),
symbol_index: 0, Err(MapError::UnexpectedMapType)
data: Vec::new(), ));
kind: obj::MapKind::Other, }
}),
#[test]
fn test_try_from_wrong_map_values() {
let map_data = MapData {
obj: new_obj_map(),
fd: None, fd: None,
pinned: false, pinned: false,
btf_fd: None, btf_fd: None,
}; };
let map = Map::HashMap(map_data);
assert!(matches!( assert!(matches!(
HashMap::<_, u32, u32>::try_from(&map), HashMap::<_, u32, u16>::try_from(&map),
Err(MapError::InvalidMapType { .. }) Err(MapError::InvalidValueSize {
size: 2,
expected: 4
})
)); ));
} }
#[test] #[test]
fn test_new_not_created() { fn test_new_not_created() {
let mut map = Map { let mut map = MapData {
obj: new_obj_map(), obj: new_obj_map(),
fd: None, fd: None,
pinned: false, pinned: false,
@ -251,7 +223,7 @@ mod tests {
#[test] #[test]
fn test_new_ok() { fn test_new_ok() {
let mut map = Map { let mut map = MapData {
obj: new_obj_map(), obj: new_obj_map(),
fd: Some(42), fd: Some(42),
pinned: false, pinned: false,
@ -263,18 +235,20 @@ mod tests {
#[test] #[test]
fn test_try_from_ok() { fn test_try_from_ok() {
let map = Map { let map_data = MapData {
obj: new_obj_map(), obj: new_obj_map(),
fd: Some(42), fd: Some(42),
pinned: false, pinned: false,
btf_fd: None, btf_fd: None,
}; };
let map = Map::HashMap(map_data);
assert!(HashMap::<_, u32, u32>::try_from(&map).is_ok()) assert!(HashMap::<_, u32, u32>::try_from(&map).is_ok())
} }
#[test] #[test]
fn test_try_from_ok_lru() { fn test_try_from_ok_lru() {
let map = Map { let map_data = MapData {
obj: obj::Map::Legacy(obj::LegacyMap { obj: obj::Map::Legacy(obj::LegacyMap {
def: bpf_map_def { def: bpf_map_def {
map_type: BPF_MAP_TYPE_LRU_HASH as u32, map_type: BPF_MAP_TYPE_LRU_HASH as u32,
@ -293,6 +267,8 @@ mod tests {
btf_fd: None, btf_fd: None,
}; };
let map = Map::HashMap(map_data);
assert!(HashMap::<_, u32, u32>::try_from(&map).is_ok()) assert!(HashMap::<_, u32, u32>::try_from(&map).is_ok())
} }
@ -300,7 +276,7 @@ mod tests {
fn test_insert_syscall_error() { fn test_insert_syscall_error() {
override_syscall(|_| sys_error(EFAULT)); override_syscall(|_| sys_error(EFAULT));
let mut map = Map { let mut map = MapData {
obj: new_obj_map(), obj: new_obj_map(),
fd: Some(42), fd: Some(42),
pinned: false, pinned: false,
@ -324,7 +300,7 @@ mod tests {
_ => sys_error(EFAULT), _ => sys_error(EFAULT),
}); });
let mut map = Map { let mut map = MapData {
obj: new_obj_map(), obj: new_obj_map(),
fd: Some(42), fd: Some(42),
pinned: false, pinned: false,
@ -339,7 +315,7 @@ mod tests {
fn test_remove_syscall_error() { fn test_remove_syscall_error() {
override_syscall(|_| sys_error(EFAULT)); override_syscall(|_| sys_error(EFAULT));
let mut map = Map { let mut map = MapData {
obj: new_obj_map(), obj: new_obj_map(),
fd: Some(42), fd: Some(42),
pinned: false, pinned: false,
@ -363,7 +339,7 @@ mod tests {
_ => sys_error(EFAULT), _ => sys_error(EFAULT),
}); });
let mut map = Map { let mut map = MapData {
obj: new_obj_map(), obj: new_obj_map(),
fd: Some(42), fd: Some(42),
pinned: false, pinned: false,
@ -377,7 +353,7 @@ mod tests {
#[test] #[test]
fn test_get_syscall_error() { fn test_get_syscall_error() {
override_syscall(|_| sys_error(EFAULT)); override_syscall(|_| sys_error(EFAULT));
let map = Map { let map = MapData {
obj: new_obj_map(), obj: new_obj_map(),
fd: Some(42), fd: Some(42),
pinned: false, pinned: false,
@ -400,7 +376,7 @@ mod tests {
} => sys_error(ENOENT), } => sys_error(ENOENT),
_ => sys_error(EFAULT), _ => sys_error(EFAULT),
}); });
let map = Map { let map = MapData {
obj: new_obj_map(), obj: new_obj_map(),
fd: Some(42), fd: Some(42),
pinned: false, pinned: false,
@ -437,7 +413,7 @@ mod tests {
} => sys_error(ENOENT), } => sys_error(ENOENT),
_ => sys_error(EFAULT), _ => sys_error(EFAULT),
}); });
let map = Map { let map = MapData {
obj: new_obj_map(), obj: new_obj_map(),
fd: Some(42), fd: Some(42),
pinned: false, pinned: false,
@ -486,7 +462,7 @@ mod tests {
_ => sys_error(EFAULT), _ => sys_error(EFAULT),
}); });
let map = Map { let map = MapData {
obj: new_obj_map(), obj: new_obj_map(),
fd: Some(42), fd: Some(42),
pinned: false, pinned: false,
@ -519,7 +495,7 @@ mod tests {
} }
_ => sys_error(EFAULT), _ => sys_error(EFAULT),
}); });
let map = Map { let map = MapData {
obj: new_obj_map(), obj: new_obj_map(),
fd: Some(42), fd: Some(42),
pinned: false, pinned: false,
@ -554,7 +530,7 @@ mod tests {
} => lookup_elem(attr), } => lookup_elem(attr),
_ => sys_error(EFAULT), _ => sys_error(EFAULT),
}); });
let map = Map { let map = MapData {
obj: new_obj_map(), obj: new_obj_map(),
fd: Some(42), fd: Some(42),
pinned: false, pinned: false,
@ -592,7 +568,7 @@ mod tests {
} }
_ => sys_error(EFAULT), _ => sys_error(EFAULT),
}); });
let map = Map { let map = MapData {
obj: new_obj_map(), obj: new_obj_map(),
fd: Some(42), fd: Some(42),
pinned: false, pinned: false,
@ -631,7 +607,7 @@ mod tests {
} => lookup_elem(attr), } => lookup_elem(attr),
_ => sys_error(EFAULT), _ => sys_error(EFAULT),
}); });
let map = Map { let map = MapData {
obj: new_obj_map(), obj: new_obj_map(),
fd: Some(42), fd: Some(42),
pinned: false, pinned: false,
@ -676,7 +652,7 @@ mod tests {
} }
_ => sys_error(EFAULT), _ => sys_error(EFAULT),
}); });
let map = Map { let map = MapData {
obj: new_obj_map(), obj: new_obj_map(),
fd: Some(42), fd: Some(42),
pinned: false, pinned: false,

@ -2,7 +2,7 @@
use std::mem; use std::mem;
use crate::{ use crate::{
maps::{Map, MapError}, maps::MapError,
sys::{bpf_map_delete_elem, bpf_map_update_elem}, sys::{bpf_map_delete_elem, bpf_map_update_elem},
}; };
@ -13,7 +13,9 @@ mod per_cpu_hash_map;
pub use hash_map::*; pub use hash_map::*;
pub use per_cpu_hash_map::*; pub use per_cpu_hash_map::*;
pub(crate) fn check_kv_size<K, V>(map: &Map) -> Result<(), MapError> { use super::MapData;
pub(crate) fn check_kv_size<K, V>(map: &MapData) -> Result<(), MapError> {
let size = mem::size_of::<K>(); let size = mem::size_of::<K>();
let expected = map.obj.key_size() as usize; let expected = map.obj.key_size() as usize;
if size != expected { if size != expected {
@ -27,7 +29,12 @@ pub(crate) fn check_kv_size<K, V>(map: &Map) -> Result<(), MapError> {
Ok(()) Ok(())
} }
pub(crate) fn insert<K, V>(map: &mut Map, key: K, value: V, flags: u64) -> Result<(), MapError> { pub(crate) fn insert<K, V>(
map: &mut MapData,
key: K,
value: V,
flags: u64,
) -> Result<(), MapError> {
let fd = map.fd_or_err()?; let fd = map.fd_or_err()?;
bpf_map_update_elem(fd, Some(&key), &value, flags).map_err(|(_, io_error)| { bpf_map_update_elem(fd, Some(&key), &value, flags).map_err(|(_, io_error)| {
MapError::SyscallError { MapError::SyscallError {
@ -39,7 +46,7 @@ pub(crate) fn insert<K, V>(map: &mut Map, key: K, value: V, flags: u64) -> Resul
Ok(()) Ok(())
} }
pub(crate) fn remove<K>(map: &mut Map, key: &K) -> Result<(), MapError> { pub(crate) fn remove<K>(map: &mut MapData, key: &K) -> Result<(), MapError> {
let fd = map.fd_or_err()?; let fd = map.fd_or_err()?;
bpf_map_delete_elem(fd, key) bpf_map_delete_elem(fd, key)
.map(|_| ()) .map(|_| ())

@ -1,14 +1,12 @@
//! Per-CPU hash map. //! Per-CPU hash map.
use std::{ use std::{
convert::{AsMut, AsRef},
marker::PhantomData, marker::PhantomData,
ops::{Deref, DerefMut},
}; };
use crate::{ use crate::{
generated::bpf_map_type::{BPF_MAP_TYPE_LRU_PERCPU_HASH, BPF_MAP_TYPE_PERCPU_HASH}, generated::bpf_map_type::{BPF_MAP_TYPE_LRU_PERCPU_HASH, BPF_MAP_TYPE_PERCPU_HASH},
maps::{ maps::{hash_map, IterableMap, MapData, MapError, MapIter, MapKeys, PerCpuValues},
hash_map, IterableMap, Map, MapError, MapIter, MapKeys, MapRef, MapRefMut, PerCpuValues,
},
sys::{bpf_map_lookup_elem_per_cpu, bpf_map_update_elem_per_cpu}, sys::{bpf_map_lookup_elem_per_cpu, bpf_map_update_elem_per_cpu},
Pod, Pod,
}; };
@ -42,15 +40,16 @@ use crate::{
/// ``` /// ```
#[doc(alias = "BPF_MAP_TYPE_LRU_PERCPU_HASH")] #[doc(alias = "BPF_MAP_TYPE_LRU_PERCPU_HASH")]
#[doc(alias = "BPF_MAP_TYPE_PERCPU_HASH")] #[doc(alias = "BPF_MAP_TYPE_PERCPU_HASH")]
pub struct PerCpuHashMap<T: Deref<Target = Map>, K: Pod, V: Pod> { pub struct PerCpuHashMap<T, K: Pod, V: Pod> {
inner: T, inner: T,
_k: PhantomData<K>, _k: PhantomData<K>,
_v: PhantomData<V>, _v: PhantomData<V>,
} }
impl<T: Deref<Target = Map>, K: Pod, V: Pod> PerCpuHashMap<T, K, V> { impl<T: AsRef<MapData>, K: Pod, V: Pod> PerCpuHashMap<T, K, V> {
pub(crate) fn new(map: T) -> Result<PerCpuHashMap<T, K, V>, MapError> { pub(crate) fn new(map: T) -> Result<PerCpuHashMap<T, K, V>, MapError> {
let map_type = map.obj.map_type(); let data = map.as_ref();
let map_type = data.obj.map_type();
// validate the map definition // validate the map definition
if map_type != BPF_MAP_TYPE_PERCPU_HASH as u32 if map_type != BPF_MAP_TYPE_PERCPU_HASH as u32
@ -58,8 +57,8 @@ impl<T: Deref<Target = Map>, K: Pod, V: Pod> PerCpuHashMap<T, K, V> {
{ {
return Err(MapError::InvalidMapType { map_type }); return Err(MapError::InvalidMapType { map_type });
} }
hash_map::check_kv_size::<K, V>(&map)?; hash_map::check_kv_size::<K, V>(data)?;
let _ = map.fd_or_err()?; let _ = data.fd_or_err()?;
Ok(PerCpuHashMap { Ok(PerCpuHashMap {
inner: map, inner: map,
@ -70,7 +69,7 @@ impl<T: Deref<Target = Map>, K: Pod, V: Pod> PerCpuHashMap<T, K, V> {
/// Returns a slice of values - one for each CPU - associated with the key. /// Returns a slice of values - one for each CPU - associated with the key.
pub fn get(&self, key: &K, flags: u64) -> Result<PerCpuValues<V>, MapError> { pub fn get(&self, key: &K, flags: u64) -> Result<PerCpuValues<V>, MapError> {
let fd = self.inner.deref().fd_or_err()?; let fd = self.inner.as_ref().fd_or_err()?;
let values = bpf_map_lookup_elem_per_cpu(fd, key, flags).map_err(|(_, io_error)| { let values = bpf_map_lookup_elem_per_cpu(fd, key, flags).map_err(|(_, io_error)| {
MapError::SyscallError { MapError::SyscallError {
call: "bpf_map_lookup_elem".to_owned(), call: "bpf_map_lookup_elem".to_owned(),
@ -89,11 +88,11 @@ impl<T: Deref<Target = Map>, K: Pod, V: Pod> PerCpuHashMap<T, K, V> {
/// An iterator visiting all keys in arbitrary order. The iterator element /// An iterator visiting all keys in arbitrary order. The iterator element
/// type is `Result<K, MapError>`. /// type is `Result<K, MapError>`.
pub fn keys(&self) -> MapKeys<'_, K> { pub fn keys(&self) -> MapKeys<'_, K> {
MapKeys::new(&self.inner) MapKeys::new(self.inner.as_ref())
} }
} }
impl<T: DerefMut<Target = Map>, K: Pod, V: Pod> PerCpuHashMap<T, K, V> { impl<T: AsMut<MapData>, K: Pod, V: Pod> PerCpuHashMap<T, K, V> {
/// Inserts a slice of values - one for each CPU - for the given key. /// Inserts a slice of values - one for each CPU - for the given key.
/// ///
/// # Examples /// # Examples
@ -108,13 +107,13 @@ impl<T: DerefMut<Target = Map>, K: Pod, V: Pod> PerCpuHashMap<T, K, V> {
/// # #[error(transparent)] /// # #[error(transparent)]
/// # Bpf(#[from] aya::BpfError) /// # Bpf(#[from] aya::BpfError)
/// # } /// # }
/// # let bpf = aya::Bpf::load(&[])?; /// # let mut bpf = aya::Bpf::load(&[])?;
/// use aya::maps::{PerCpuHashMap, PerCpuValues}; /// use aya::maps::{PerCpuHashMap, PerCpuValues};
/// use aya::util::nr_cpus; /// use aya::util::nr_cpus;
/// ///
/// const RETRIES: u8 = 1; /// const RETRIES: u8 = 1;
/// ///
/// let mut hm = PerCpuHashMap::<_, u8, u32>::try_from(bpf.map_mut("PER_CPU_STORAGE")?)?; /// let mut hm: PerCpuHashMap::<_, u8, u32> = bpf.map_mut("PER_CPU_STORAGE")?.try_into()?;
/// hm.insert( /// hm.insert(
/// RETRIES, /// RETRIES,
/// PerCpuValues::try_from(vec![3u32; nr_cpus()?])?, /// PerCpuValues::try_from(vec![3u32; nr_cpus()?])?,
@ -123,7 +122,7 @@ impl<T: DerefMut<Target = Map>, K: Pod, V: Pod> PerCpuHashMap<T, K, V> {
/// # Ok::<(), Error>(()) /// # Ok::<(), Error>(())
/// ``` /// ```
pub fn insert(&mut self, key: K, values: PerCpuValues<V>, flags: u64) -> Result<(), MapError> { pub fn insert(&mut self, key: K, values: PerCpuValues<V>, flags: u64) -> Result<(), MapError> {
let fd = self.inner.fd_or_err()?; let fd = self.inner.as_mut().fd_or_err()?;
bpf_map_update_elem_per_cpu(fd, &key, &values, flags).map_err(|(_, io_error)| { bpf_map_update_elem_per_cpu(fd, &key, &values, flags).map_err(|(_, io_error)| {
MapError::SyscallError { MapError::SyscallError {
call: "bpf_map_update_elem".to_owned(), call: "bpf_map_update_elem".to_owned(),
@ -136,50 +135,16 @@ impl<T: DerefMut<Target = Map>, K: Pod, V: Pod> PerCpuHashMap<T, K, V> {
/// Removes a key from the map. /// Removes a key from the map.
pub fn remove(&mut self, key: &K) -> Result<(), MapError> { pub fn remove(&mut self, key: &K) -> Result<(), MapError> {
hash_map::remove(&mut self.inner, key) hash_map::remove(self.inner.as_mut(), key)
} }
} }
impl<T: Deref<Target = Map>, K: Pod, V: Pod> IterableMap<K, PerCpuValues<V>> impl<T: AsRef<MapData>, K: Pod, V: Pod> IterableMap<K, PerCpuValues<V>> for PerCpuHashMap<T, K, V> {
for PerCpuHashMap<T, K, V> fn map(&self) -> &MapData {
{ self.inner.as_ref()
fn map(&self) -> &Map {
&self.inner
} }
fn get(&self, key: &K) -> Result<PerCpuValues<V>, MapError> { fn get(&self, key: &K) -> Result<PerCpuValues<V>, MapError> {
PerCpuHashMap::get(self, key, 0) PerCpuHashMap::get(self, key, 0)
} }
} }
impl<K: Pod, V: Pod> TryFrom<MapRef> for PerCpuHashMap<MapRef, K, V> {
type Error = MapError;
fn try_from(a: MapRef) -> Result<PerCpuHashMap<MapRef, K, V>, MapError> {
PerCpuHashMap::new(a)
}
}
impl<K: Pod, V: Pod> TryFrom<MapRefMut> for PerCpuHashMap<MapRefMut, K, V> {
type Error = MapError;
fn try_from(a: MapRefMut) -> Result<PerCpuHashMap<MapRefMut, K, V>, MapError> {
PerCpuHashMap::new(a)
}
}
impl<'a, K: Pod, V: Pod> TryFrom<&'a Map> for PerCpuHashMap<&'a Map, K, V> {
type Error = MapError;
fn try_from(a: &'a Map) -> Result<PerCpuHashMap<&'a Map, K, V>, MapError> {
PerCpuHashMap::new(a)
}
}
impl<'a, K: Pod, V: Pod> TryFrom<&'a mut Map> for PerCpuHashMap<&'a mut Map, K, V> {
type Error = MapError;
fn try_from(a: &'a mut Map) -> Result<PerCpuHashMap<&'a mut Map, K, V>, MapError> {
PerCpuHashMap::new(a)
}
}

@ -1,9 +1,12 @@
//! A LPM Trie. //! A LPM Trie.
use std::{marker::PhantomData, mem, ops::Deref}; use std::{
convert::{AsMut, AsRef},
marker::PhantomData,
mem,
};
use crate::{ use crate::{
generated::bpf_map_type::BPF_MAP_TYPE_LPM_TRIE, maps::{IterableMap, MapData, MapError},
maps::{IterableMap, Map, MapError, MapRef, MapRefMut},
sys::{bpf_map_delete_elem, bpf_map_lookup_elem, bpf_map_update_elem}, sys::{bpf_map_delete_elem, bpf_map_lookup_elem, bpf_map_update_elem},
Pod, Pod,
}; };
@ -17,11 +20,11 @@ use crate::{
/// # Examples /// # Examples
/// ///
/// ```no_run /// ```no_run
/// # let bpf = aya::Bpf::load(&[])?; /// # let mut bpf = aya::Bpf::load(&[])?;
/// use aya::maps::lpm_trie::{LpmTrie, Key}; /// use aya::maps::lpm_trie::{LpmTrie, Key};
/// use std::net::Ipv4Addr; /// use std::net::Ipv4Addr;
/// ///
/// let mut trie = LpmTrie::try_from(bpf.map_mut("LPM_TRIE")?)?; /// let mut trie: LpmTrie<_,u32,u32> = bpf.map_mut("LPM_TRIE")?.try_into()?;
/// let ipaddr = Ipv4Addr::new(8, 8, 8, 8); /// let ipaddr = Ipv4Addr::new(8, 8, 8, 8);
/// // The following represents a key for the "8.8.8.8/16" subnet. /// // The following represents a key for the "8.8.8.8/16" subnet.
/// // The first argument - the prefix length - represents how many bytes should be matched against. The second argument is the actual data to be matched. /// // The first argument - the prefix length - represents how many bytes should be matched against. The second argument is the actual data to be matched.
@ -43,7 +46,7 @@ use crate::{
/// ``` /// ```
#[doc(alias = "BPF_MAP_TYPE_LPM_TRIE")] #[doc(alias = "BPF_MAP_TYPE_LPM_TRIE")]
pub struct LpmTrie<T: Deref<Target = Map>, K, V> { pub struct LpmTrie<T, K, V> {
inner: T, inner: T,
_k: PhantomData<K>, _k: PhantomData<K>,
_v: PhantomData<V>, _v: PhantomData<V>,
@ -96,26 +99,21 @@ impl<K: Pod> Clone for Key<K> {
// A Pod impl is required as Key struct is a key for a map. // A Pod impl is required as Key struct is a key for a map.
unsafe impl<K: Pod> Pod for Key<K> {} unsafe impl<K: Pod> Pod for Key<K> {}
impl<T: Deref<Target = Map>, K: Pod, V: Pod> LpmTrie<T, K, V> { impl<T: AsRef<MapData>, K: Pod, V: Pod> LpmTrie<T, K, V> {
pub(crate) fn new(map: T) -> Result<LpmTrie<T, K, V>, MapError> { pub(crate) fn new(map: T) -> Result<LpmTrie<T, K, V>, MapError> {
let map_type = map.obj.map_type(); let data = map.as_ref();
// validate the map definition
if map_type != BPF_MAP_TYPE_LPM_TRIE as u32 {
return Err(MapError::InvalidMapType { map_type });
}
let size = mem::size_of::<Key<K>>(); let size = mem::size_of::<Key<K>>();
let expected = map.obj.key_size() as usize; let expected = data.obj.key_size() as usize;
if size != expected { if size != expected {
return Err(MapError::InvalidKeySize { size, expected }); return Err(MapError::InvalidKeySize { size, expected });
} }
let size = mem::size_of::<V>(); let size = mem::size_of::<V>();
let expected = map.obj.value_size() as usize; let expected = data.obj.value_size() as usize;
if size != expected { if size != expected {
return Err(MapError::InvalidValueSize { size, expected }); return Err(MapError::InvalidValueSize { size, expected });
}; };
let _ = map.fd_or_err()?; let _ = data.fd_or_err()?;
Ok(LpmTrie { Ok(LpmTrie {
inner: map, inner: map,
@ -126,7 +124,7 @@ impl<T: Deref<Target = Map>, K: Pod, V: Pod> LpmTrie<T, K, V> {
/// Returns a copy of the value associated with the longest prefix matching key in the LpmTrie. /// Returns a copy of the value associated with the longest prefix matching key in the LpmTrie.
pub fn get(&self, key: &Key<K>, flags: u64) -> Result<V, MapError> { pub fn get(&self, key: &Key<K>, flags: u64) -> Result<V, MapError> {
let fd = self.inner.deref().fd_or_err()?; let fd = self.inner.as_ref().fd_or_err()?;
let value = bpf_map_lookup_elem(fd, key, flags).map_err(|(_, io_error)| { let value = bpf_map_lookup_elem(fd, key, flags).map_err(|(_, io_error)| {
MapError::SyscallError { MapError::SyscallError {
call: "bpf_map_lookup_elem".to_owned(), call: "bpf_map_lookup_elem".to_owned(),
@ -135,10 +133,12 @@ impl<T: Deref<Target = Map>, K: Pod, V: Pod> LpmTrie<T, K, V> {
})?; })?;
value.ok_or(MapError::KeyNotFound) value.ok_or(MapError::KeyNotFound)
} }
}
impl<T: AsMut<MapData>, K: Pod, V: Pod> LpmTrie<T, K, V> {
/// Inserts a key value pair into the map. /// Inserts a key value pair into the map.
pub fn insert(&self, key: &Key<K>, value: V, flags: u64) -> Result<(), MapError> { pub fn insert(&mut self, key: &Key<K>, value: V, flags: u64) -> Result<(), MapError> {
let fd = self.inner.deref().fd_or_err()?; let fd = self.inner.as_mut().fd_or_err()?;
bpf_map_update_elem(fd, Some(key), &value, flags).map_err(|(_, io_error)| { bpf_map_update_elem(fd, Some(key), &value, flags).map_err(|(_, io_error)| {
MapError::SyscallError { MapError::SyscallError {
call: "bpf_map_update_elem".to_owned(), call: "bpf_map_update_elem".to_owned(),
@ -152,8 +152,8 @@ impl<T: Deref<Target = Map>, K: Pod, V: Pod> LpmTrie<T, K, V> {
/// Removes an element from the map. /// Removes an element from the map.
/// ///
/// Both the prefix and data must match exactly - this method does not do a longest prefix match. /// Both the prefix and data must match exactly - this method does not do a longest prefix match.
pub fn remove(&self, key: &Key<K>) -> Result<(), MapError> { pub fn remove(&mut self, key: &Key<K>) -> Result<(), MapError> {
let fd = self.inner.deref().fd_or_err()?; let fd = self.inner.as_mut().fd_or_err()?;
bpf_map_delete_elem(fd, key) bpf_map_delete_elem(fd, key)
.map(|_| ()) .map(|_| ())
.map_err(|(_, io_error)| MapError::SyscallError { .map_err(|(_, io_error)| MapError::SyscallError {
@ -163,9 +163,9 @@ impl<T: Deref<Target = Map>, K: Pod, V: Pod> LpmTrie<T, K, V> {
} }
} }
impl<T: Deref<Target = Map>, K: Pod, V: Pod> IterableMap<K, V> for LpmTrie<T, K, V> { impl<T: AsRef<MapData>, K: Pod, V: Pod> IterableMap<K, V> for LpmTrie<T, K, V> {
fn map(&self) -> &Map { fn map(&self) -> &MapData {
&self.inner self.inner.as_ref()
} }
fn get(&self, key: &K) -> Result<V, MapError> { fn get(&self, key: &K) -> Result<V, MapError> {
@ -174,38 +174,6 @@ impl<T: Deref<Target = Map>, K: Pod, V: Pod> IterableMap<K, V> for LpmTrie<T, K,
} }
} }
impl<K: Pod, V: Pod> TryFrom<MapRef> for LpmTrie<MapRef, K, V> {
type Error = MapError;
fn try_from(a: MapRef) -> Result<LpmTrie<MapRef, K, V>, MapError> {
LpmTrie::new(a)
}
}
impl<K: Pod, V: Pod> TryFrom<MapRefMut> for LpmTrie<MapRefMut, K, V> {
type Error = MapError;
fn try_from(a: MapRefMut) -> Result<LpmTrie<MapRefMut, K, V>, MapError> {
LpmTrie::new(a)
}
}
impl<'a, K: Pod, V: Pod> TryFrom<&'a Map> for LpmTrie<&'a Map, K, V> {
type Error = MapError;
fn try_from(a: &'a Map) -> Result<LpmTrie<&'a Map, K, V>, MapError> {
LpmTrie::new(a)
}
}
impl<'a, K: Pod, V: Pod> TryFrom<&'a mut Map> for LpmTrie<&'a mut Map, K, V> {
type Error = MapError;
fn try_from(a: &'a mut Map) -> Result<LpmTrie<&'a mut Map, K, V>, MapError> {
LpmTrie::new(a)
}
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
@ -215,6 +183,7 @@ mod tests {
bpf_cmd, bpf_cmd,
bpf_map_type::{BPF_MAP_TYPE_LPM_TRIE, BPF_MAP_TYPE_PERF_EVENT_ARRAY}, bpf_map_type::{BPF_MAP_TYPE_LPM_TRIE, BPF_MAP_TYPE_PERF_EVENT_ARRAY},
}, },
maps::{Map, MapData},
obj, obj,
sys::{override_syscall, SysResult, Syscall}, sys::{override_syscall, SysResult, Syscall},
}; };
@ -243,7 +212,7 @@ mod tests {
#[test] #[test]
fn test_wrong_key_size() { fn test_wrong_key_size() {
let map = Map { let map = MapData {
obj: new_obj_map(), obj: new_obj_map(),
fd: None, fd: None,
pinned: false, pinned: false,
@ -260,7 +229,7 @@ mod tests {
#[test] #[test]
fn test_wrong_value_size() { fn test_wrong_value_size() {
let map = Map { let map = MapData {
obj: new_obj_map(), obj: new_obj_map(),
fd: None, fd: None,
pinned: false, pinned: false,
@ -277,7 +246,7 @@ mod tests {
#[test] #[test]
fn test_try_from_wrong_map() { fn test_try_from_wrong_map() {
let map = Map { let map_data = MapData {
obj: obj::Map::Legacy(obj::LegacyMap { obj: obj::Map::Legacy(obj::LegacyMap {
def: bpf_map_def { def: bpf_map_def {
map_type: BPF_MAP_TYPE_PERF_EVENT_ARRAY as u32, map_type: BPF_MAP_TYPE_PERF_EVENT_ARRAY as u32,
@ -296,15 +265,17 @@ mod tests {
pinned: false, pinned: false,
}; };
let map = Map::PerfEventArray(map_data);
assert!(matches!( assert!(matches!(
LpmTrie::<_, u32, u32>::try_from(&map), LpmTrie::<_, u32, u32>::try_from(&map),
Err(MapError::InvalidMapType { .. }) Err(MapError::UnexpectedMapType)
)); ));
} }
#[test] #[test]
fn test_new_not_created() { fn test_new_not_created() {
let mut map = Map { let mut map = MapData {
obj: new_obj_map(), obj: new_obj_map(),
fd: None, fd: None,
pinned: false, pinned: false,
@ -319,7 +290,7 @@ mod tests {
#[test] #[test]
fn test_new_ok() { fn test_new_ok() {
let mut map = Map { let mut map = MapData {
obj: new_obj_map(), obj: new_obj_map(),
fd: Some(42), fd: Some(42),
pinned: false, pinned: false,
@ -331,12 +302,14 @@ mod tests {
#[test] #[test]
fn test_try_from_ok() { fn test_try_from_ok() {
let map = Map { let map_data = MapData {
obj: new_obj_map(), obj: new_obj_map(),
fd: Some(42), fd: Some(42),
pinned: false, pinned: false,
btf_fd: None, btf_fd: None,
}; };
let map = Map::LpmTrie(map_data);
assert!(LpmTrie::<_, u32, u32>::try_from(&map).is_ok()) assert!(LpmTrie::<_, u32, u32>::try_from(&map).is_ok())
} }
@ -344,13 +317,13 @@ mod tests {
fn test_insert_syscall_error() { fn test_insert_syscall_error() {
override_syscall(|_| sys_error(EFAULT)); override_syscall(|_| sys_error(EFAULT));
let mut map = Map { let mut map = MapData {
obj: new_obj_map(), obj: new_obj_map(),
fd: Some(42), fd: Some(42),
pinned: false, pinned: false,
btf_fd: None, btf_fd: None,
}; };
let trie = LpmTrie::<_, u32, u32>::new(&mut map).unwrap(); let mut trie = LpmTrie::<_, u32, u32>::new(&mut map).unwrap();
let ipaddr = Ipv4Addr::new(8, 8, 8, 8); let ipaddr = Ipv4Addr::new(8, 8, 8, 8);
let key = Key::new(16, u32::from(ipaddr).to_be()); let key = Key::new(16, u32::from(ipaddr).to_be());
assert!(matches!( assert!(matches!(
@ -369,14 +342,14 @@ mod tests {
_ => sys_error(EFAULT), _ => sys_error(EFAULT),
}); });
let mut map = Map { let mut map = MapData {
obj: new_obj_map(), obj: new_obj_map(),
fd: Some(42), fd: Some(42),
pinned: false, pinned: false,
btf_fd: None, btf_fd: None,
}; };
let trie = LpmTrie::<_, u32, u32>::new(&mut map).unwrap(); let mut trie = LpmTrie::<_, u32, u32>::new(&mut map).unwrap();
let ipaddr = Ipv4Addr::new(8, 8, 8, 8); let ipaddr = Ipv4Addr::new(8, 8, 8, 8);
let key = Key::new(16, u32::from(ipaddr).to_be()); let key = Key::new(16, u32::from(ipaddr).to_be());
assert!(trie.insert(&key, 1, 0).is_ok()); assert!(trie.insert(&key, 1, 0).is_ok());
@ -386,13 +359,13 @@ mod tests {
fn test_remove_syscall_error() { fn test_remove_syscall_error() {
override_syscall(|_| sys_error(EFAULT)); override_syscall(|_| sys_error(EFAULT));
let mut map = Map { let mut map = MapData {
obj: new_obj_map(), obj: new_obj_map(),
fd: Some(42), fd: Some(42),
pinned: false, pinned: false,
btf_fd: None, btf_fd: None,
}; };
let trie = LpmTrie::<_, u32, u32>::new(&mut map).unwrap(); let mut trie = LpmTrie::<_, u32, u32>::new(&mut map).unwrap();
let ipaddr = Ipv4Addr::new(8, 8, 8, 8); let ipaddr = Ipv4Addr::new(8, 8, 8, 8);
let key = Key::new(16, u32::from(ipaddr).to_be()); let key = Key::new(16, u32::from(ipaddr).to_be());
assert!(matches!( assert!(matches!(
@ -411,13 +384,13 @@ mod tests {
_ => sys_error(EFAULT), _ => sys_error(EFAULT),
}); });
let mut map = Map { let mut map = MapData {
obj: new_obj_map(), obj: new_obj_map(),
fd: Some(42), fd: Some(42),
pinned: false, pinned: false,
btf_fd: None, btf_fd: None,
}; };
let trie = LpmTrie::<_, u32, u32>::new(&mut map).unwrap(); let mut trie = LpmTrie::<_, u32, u32>::new(&mut map).unwrap();
let ipaddr = Ipv4Addr::new(8, 8, 8, 8); let ipaddr = Ipv4Addr::new(8, 8, 8, 8);
let key = Key::new(16, u32::from(ipaddr).to_be()); let key = Key::new(16, u32::from(ipaddr).to_be());
assert!(trie.remove(&key).is_ok()); assert!(trie.remove(&key).is_ok());
@ -426,7 +399,7 @@ mod tests {
#[test] #[test]
fn test_get_syscall_error() { fn test_get_syscall_error() {
override_syscall(|_| sys_error(EFAULT)); override_syscall(|_| sys_error(EFAULT));
let map = Map { let map = MapData {
obj: new_obj_map(), obj: new_obj_map(),
fd: Some(42), fd: Some(42),
pinned: false, pinned: false,
@ -451,7 +424,7 @@ mod tests {
} => sys_error(ENOENT), } => sys_error(ENOENT),
_ => sys_error(EFAULT), _ => sys_error(EFAULT),
}); });
let map = Map { let map = MapData {
obj: new_obj_map(), obj: new_obj_map(),
fd: Some(42), fd: Some(42),
pinned: false, pinned: false,

@ -1,81 +0,0 @@
use parking_lot::{RwLock, RwLockReadGuard, RwLockWriteGuard};
use std::{
mem,
ops::{Deref, DerefMut},
sync::Arc,
};
use crate::maps::Map;
pub(crate) struct MapLockError;
/* FIXME: write a full RwLock implementation that doesn't use borrowing guards
* so that try_read() and try_write() don't have to use the ugly lifetime
* extension hack */
#[derive(Debug)]
pub(crate) struct MapLock {
inner: Arc<RwLock<Map>>,
}
impl MapLock {
pub(crate) fn new(map: Map) -> MapLock {
MapLock {
inner: Arc::new(RwLock::new(map)),
}
}
pub(crate) fn try_read(&self) -> Result<MapRef, MapLockError> {
let lock: Option<RwLockReadGuard<'static, Map>> =
unsafe { mem::transmute(self.inner.try_read()) };
lock.map(|guard| MapRef {
_lock: self.inner.clone(),
guard,
})
.ok_or(MapLockError)
}
pub(crate) fn try_write(&self) -> Result<MapRefMut, MapLockError> {
let lock: Option<RwLockWriteGuard<'static, Map>> =
unsafe { mem::transmute(self.inner.try_write()) };
lock.map(|guard| MapRefMut {
_lock: self.inner.clone(),
guard,
})
.ok_or(MapLockError)
}
}
/// A borrowed reference to a BPF map.
pub struct MapRef {
_lock: Arc<RwLock<Map>>,
guard: RwLockReadGuard<'static, Map>,
}
/// A mutable borrowed reference to a BPF map.
pub struct MapRefMut {
_lock: Arc<RwLock<Map>>,
guard: RwLockWriteGuard<'static, Map>,
}
impl Deref for MapRef {
type Target = Map;
fn deref(&self) -> &Map {
&self.guard
}
}
impl Deref for MapRefMut {
type Target = Map;
fn deref(&self) -> &Map {
&self.guard
}
}
impl DerefMut for MapRefMut {
fn deref_mut(&mut self) -> &mut Map {
&mut self.guard
}
}

@ -4,22 +4,25 @@
//! used to setup and share data with eBPF programs. When you call //! used to setup and share data with eBPF programs. When you call
//! [`Bpf::load_file`](crate::Bpf::load_file) or //! [`Bpf::load_file`](crate::Bpf::load_file) or
//! [`Bpf::load`](crate::Bpf::load), all the maps defined in the eBPF code get //! [`Bpf::load`](crate::Bpf::load), all the maps defined in the eBPF code get
//! initialized and can then be accessed using [`Bpf::map`](crate::Bpf::map) and //! initialized and can then be accessed using [`Bpf::map`](crate::Bpf::map),
//! [`Bpf::map_mut`](crate::Bpf::map_mut). //! [`Bpf::map_mut`](crate::Bpf::map_mut), [`Bpf::take_map`](crate::Bpf::map)
//! or [`Bpf::map_mut`](crate::Bpf::take_map).
//! //!
//! # Typed maps //! # Typed maps
//! //!
//! The eBPF API includes many map types each supporting different operations. //! The eBPF API includes many map types each supporting different operations.
//! [`Bpf::map`](crate::Bpf::map) and [`Bpf::map_mut`](crate::Bpf::map_mut) always return the //! [`Bpf::map`](crate::Bpf::map), [`Bpf::map_mut`](crate::Bpf::map_mut), and
//! opaque [`MapRef`] and [`MapRefMut`] types respectively. Those two types can be converted to //! [`Bpf::map_mut`](crate::Bpf::take_map) always return the
//! *typed maps* using the [`TryFrom`](std::convert::TryFrom) trait. For example: //! opaque [`&Map`], [`&mut Map`], and [`Map`] types respectively. Those three types can be converted to
//! *typed maps* using the [`TryFrom`](std::convert::TryFrom) or [`TryInto`](std::convert::TryInto)
//! trait. For example:
//! //!
//! ```no_run //! ```no_run
//! # let mut bpf = aya::Bpf::load(&[])?; //! # let mut bpf = aya::Bpf::load(&[])?;
//! use aya::maps::SockMap; //! use aya::maps::SockMap;
//! use aya::programs::SkMsg; //! use aya::programs::SkMsg;
//! //!
//! let intercept_egress = SockMap::try_from(bpf.map_mut("INTERCEPT_EGRESS")?)?; //! let intercept_egress: SockMap<_> = bpf.take_map("INTERCEPT_EGRESS")?.try_into()?;
//! let prog: &mut SkMsg = bpf.program_mut("intercept_egress_packet").unwrap().try_into()?; //! let prog: &mut SkMsg = bpf.program_mut("intercept_egress_packet").unwrap().try_into()?;
//! prog.load()?; //! prog.load()?;
//! prog.attach(&intercept_egress)?; //! prog.attach(&intercept_egress)?;
@ -32,6 +35,7 @@
//! versa. Because of that, all map values must be plain old data and therefore //! versa. Because of that, all map values must be plain old data and therefore
//! implement the [Pod] trait. //! implement the [Pod] trait.
use std::{ use std::{
convert::{AsMut, AsRef},
ffi::CString, ffi::CString,
fmt, io, fmt, io,
marker::PhantomData, marker::PhantomData,
@ -58,8 +62,6 @@ use crate::{
PinningType, Pod, PinningType, Pod,
}; };
mod map_lock;
pub mod array; pub mod array;
pub mod bloom_filter; pub mod bloom_filter;
pub mod hash_map; pub mod hash_map;
@ -71,8 +73,11 @@ pub mod stack;
pub mod stack_trace; pub mod stack_trace;
pub use array::{Array, PerCpuArray, ProgramArray}; pub use array::{Array, PerCpuArray, ProgramArray};
pub use bloom_filter::BloomFilter;
pub use hash_map::{HashMap, PerCpuHashMap}; pub use hash_map::{HashMap, PerCpuHashMap};
pub use map_lock::*; pub use lpm_trie::LpmTrie;
#[cfg(any(feature = "async", doc))]
pub use perf::AsyncPerfEventArray;
pub use perf::PerfEventArray; pub use perf::PerfEventArray;
pub use queue::Queue; pub use queue::Queue;
pub use sock::{SockHash, SockMap}; pub use sock::{SockHash, SockMap};
@ -174,20 +179,6 @@ pub enum MapError {
io_error: io::Error, io_error: io::Error,
}, },
/// Map is borrowed mutably
#[error("map `{name}` is borrowed mutably")]
BorrowError {
/// Map name
name: String,
},
/// Map is already borrowed
#[error("map `{name}` is already borrowed")]
BorrowMutError {
/// Map name
name: String,
},
/// Could not pin map by name /// Could not pin map by name
#[error("map `{name:?}` requested pinning by name. pinning failed")] #[error("map `{name:?}` requested pinning by name. pinning failed")]
PinError { PinError {
@ -197,6 +188,10 @@ pub enum MapError {
#[source] #[source]
error: PinError, error: PinError,
}, },
/// The map is not of the expected type.
#[error("unexpected map type")]
UnexpectedMapType,
} }
/// A map file descriptor. /// A map file descriptor.
@ -243,11 +238,181 @@ fn maybe_warn_rlimit() {
} }
} }
/// eBPF map types.
#[derive(Debug)]
pub enum Map {
/// A ['Array`] map
Array(MapData),
/// A [`PerCpuArray`] map
PerCpuArray(MapData),
/// A [`ProgramArray`] map
ProgramArray(MapData),
/// A [`HashMap`] map
HashMap(MapData),
/// A ['PerCpuHashMap'] map
PerCpuHashMap(MapData),
/// A [`PerfEventArray`] map
PerfEventArray(MapData),
/// A [`SockMap`] map
SockMap(MapData),
/// A [`SockHash`] map
SockHash(MapData),
/// A [`BloomFilter`] map
BloomFilter(MapData),
/// A [`LpmTrie`] map
LpmTrie(MapData),
/// A [`Stack`] map
Stack(MapData),
/// A [`StackTrace`] map
StackTraceMap(MapData),
/// A [`Queue`] map
Queue(MapData),
}
macro_rules! impl_try_from_map {
($($tx:ident from Map::$ty:ident),+ $(,)?) => {
$(
impl<'a> TryFrom<&'a Map> for $tx<&'a MapData> {
type Error = MapError;
fn try_from(map: &'a Map) -> Result<$tx<&'a MapData>, MapError> {
match map {
Map::$ty(m) => {
$tx::<&'a MapData>::new(m)
},
_ => Err(MapError::UnexpectedMapType),
}
}
}
impl<'a,> TryFrom<&'a mut Map> for $tx<&'a mut MapData> {
type Error = MapError;
fn try_from(map: &'a mut Map) -> Result<$tx<&'a mut MapData>, MapError> {
match map {
Map::$ty(m) => {
$tx::<&'a mut MapData>::new(m)
},
_ => Err(MapError::UnexpectedMapType),
}
}
}
impl TryFrom<Map> for $tx<MapData> {
type Error = MapError;
fn try_from(map: Map) -> Result<$tx<MapData>, MapError> {
match map {
Map::$ty(m) => {
$tx::<MapData>::new(m)
},
_ => Err(MapError::UnexpectedMapType),
}
}
}
)+
}
}
impl_try_from_map!(
ProgramArray from Map::ProgramArray,
SockMap from Map::SockMap,
PerfEventArray from Map::PerfEventArray,
StackTraceMap from Map::StackTraceMap,
);
#[cfg(feature = "async")]
#[cfg_attr(docsrs, doc(cfg(feature = "async")))]
impl_try_from_map!(
AsyncPerfEventArray from Map::PerfEventArray,
);
macro_rules! impl_try_from_map_generic_key_or_value {
($($ty:ident),+ $(,)?) => {
$(
impl<'a, V:Pod> TryFrom<&'a Map> for $ty<&'a MapData, V> {
type Error = MapError;
fn try_from(map: &'a Map) -> Result<$ty<&'a MapData , V>, MapError> {
match map {
Map::$ty(m) => {
$ty::<&'a MapData,V>::new(m)
},
_ => Err(MapError::UnexpectedMapType),
}
}
}
impl<'a,V: Pod> TryFrom<&'a mut Map> for $ty<&'a mut MapData, V> {
type Error = MapError;
fn try_from(map: &'a mut Map) -> Result<$ty<&'a mut MapData, V>, MapError> {
match map {
Map::$ty(m) => {
$ty::<&'a mut MapData,V>::new(m)
},
_ => Err(MapError::UnexpectedMapType),
}
}
}
impl<V: Pod> TryFrom<Map> for $ty<MapData, V> {
type Error = MapError;
fn try_from(map: Map) -> Result<$ty<MapData, V>, MapError> {
match map {
Map::$ty(m) => {
$ty::<MapData,V>::new(m)
},
_ => Err(MapError::UnexpectedMapType),
}
}
}
)+
}
}
impl_try_from_map_generic_key_or_value!(Array, PerCpuArray, SockHash, BloomFilter, Queue, Stack,);
macro_rules! impl_try_from_map_generic_key_and_value {
($($ty:ident),+ $(,)?) => {
$(
impl<'a, V: Pod, K: Pod> TryFrom<&'a Map> for $ty<&'a MapData, V, K> {
type Error = MapError;
fn try_from(map: &'a Map) -> Result<$ty<&'a MapData,V,K>, MapError> {
match map {
Map::$ty(m) => {
$ty::<&'a MapData,V,K>::new(m)
},
_ => Err(MapError::UnexpectedMapType),
}
}
}
impl<'a,V: Pod,K: Pod> TryFrom<&'a mut Map> for $ty<&'a mut MapData, V, K> {
type Error = MapError;
fn try_from(map: &'a mut Map) -> Result<$ty<&'a mut MapData, V, K>, MapError> {
match map {
Map::$ty(m) => {
$ty::<&'a mut MapData,V,K>::new(m)
},
_ => Err(MapError::UnexpectedMapType),
}
}
}
)+
}
}
impl_try_from_map_generic_key_and_value!(HashMap, PerCpuHashMap, LpmTrie);
/// A generic handle to a BPF map. /// A generic handle to a BPF map.
/// ///
/// You should never need to use this unless you're implementing a new map type. /// You should never need to use this unless you're implementing a new map type.
#[derive(Debug)] #[derive(Debug, Clone)]
pub struct Map { pub struct MapData {
pub(crate) obj: obj::Map, pub(crate) obj: obj::Map,
pub(crate) fd: Option<RawFd>, pub(crate) fd: Option<RawFd>,
pub(crate) btf_fd: Option<RawFd>, pub(crate) btf_fd: Option<RawFd>,
@ -255,7 +420,19 @@ pub struct Map {
pub pinned: bool, pub pinned: bool,
} }
impl Map { impl AsRef<MapData> for MapData {
fn as_ref(&self) -> &MapData {
self
}
}
impl AsMut<MapData> for MapData {
fn as_mut(&mut self) -> &mut MapData {
self
}
}
impl MapData {
/// Creates a new map with the provided `name` /// Creates a new map with the provided `name`
pub fn create(&mut self, name: &str) -> Result<RawFd, MapError> { pub fn create(&mut self, name: &str) -> Result<RawFd, MapError> {
if self.fd.is_some() { if self.fd.is_some() {
@ -303,7 +480,7 @@ impl Map {
} }
/// Loads a map from a pinned path in bpffs. /// Loads a map from a pinned path in bpffs.
pub fn from_pin<P: AsRef<Path>>(path: P) -> Result<Map, MapError> { pub fn from_pin<P: AsRef<Path>>(path: P) -> Result<MapData, MapError> {
let path_string = let path_string =
CString::new(path.as_ref().to_string_lossy().into_owned()).map_err(|e| { CString::new(path.as_ref().to_string_lossy().into_owned()).map_err(|e| {
MapError::PinError { MapError::PinError {
@ -324,7 +501,7 @@ impl Map {
io_error, io_error,
})?; })?;
Ok(Map { Ok(MapData {
obj: parse_map_info(info, PinningType::ByName), obj: parse_map_info(info, PinningType::ByName),
fd: Some(fd), fd: Some(fd),
btf_fd: None, btf_fd: None,
@ -337,13 +514,13 @@ impl Map {
/// If loading from a BPF Filesystem (bpffs) you should use [`Map::from_pin`]. /// If loading from a BPF Filesystem (bpffs) you should use [`Map::from_pin`].
/// This API is intended for cases where you have received a valid BPF FD from some other means. /// This API is intended for cases where you have received a valid BPF FD from some other means.
/// For example, you received an FD over Unix Domain Socket. /// For example, you received an FD over Unix Domain Socket.
pub fn from_fd(fd: RawFd) -> Result<Map, MapError> { pub fn from_fd(fd: RawFd) -> Result<MapData, MapError> {
let info = bpf_map_get_info_by_fd(fd).map_err(|io_error| MapError::SyscallError { let info = bpf_map_get_info_by_fd(fd).map_err(|io_error| MapError::SyscallError {
call: "BPF_OBJ_GET".to_owned(), call: "BPF_OBJ_GET".to_owned(),
io_error, io_error,
})?; })?;
Ok(Map { Ok(MapData {
obj: parse_map_info(info, PinningType::None), obj: parse_map_info(info, PinningType::None),
fd: Some(fd), fd: Some(fd),
btf_fd: None, btf_fd: None,
@ -389,7 +566,7 @@ impl Map {
} }
} }
impl Drop for Map { impl Drop for MapData {
fn drop(&mut self) { fn drop(&mut self) {
// TODO: Replace this with an OwnedFd once that is stabilized. // TODO: Replace this with an OwnedFd once that is stabilized.
if let Some(fd) = self.fd.take() { if let Some(fd) = self.fd.take() {
@ -401,7 +578,7 @@ impl Drop for Map {
/// An iterable map /// An iterable map
pub trait IterableMap<K: Pod, V> { pub trait IterableMap<K: Pod, V> {
/// Get a generic map handle /// Get a generic map handle
fn map(&self) -> &Map; fn map(&self) -> &MapData;
/// Get the value for the provided `key` /// Get the value for the provided `key`
fn get(&self, key: &K) -> Result<V, MapError>; fn get(&self, key: &K) -> Result<V, MapError>;
@ -409,13 +586,13 @@ pub trait IterableMap<K: Pod, V> {
/// Iterator returned by `map.keys()`. /// Iterator returned by `map.keys()`.
pub struct MapKeys<'coll, K: Pod> { pub struct MapKeys<'coll, K: Pod> {
map: &'coll Map, map: &'coll MapData,
err: bool, err: bool,
key: Option<K>, key: Option<K>,
} }
impl<'coll, K: Pod> MapKeys<'coll, K> { impl<'coll, K: Pod> MapKeys<'coll, K> {
fn new(map: &'coll Map) -> MapKeys<'coll, K> { fn new(map: &'coll MapData) -> MapKeys<'coll, K> {
MapKeys { MapKeys {
map, map,
err: false, err: false,
@ -643,6 +820,7 @@ mod tests {
use crate::{ use crate::{
bpf_map_def, bpf_map_def,
generated::{bpf_cmd, bpf_map_type::BPF_MAP_TYPE_HASH}, generated::{bpf_cmd, bpf_map_type::BPF_MAP_TYPE_HASH},
maps::MapData,
obj::MapKind, obj::MapKind,
sys::{override_syscall, Syscall}, sys::{override_syscall, Syscall},
}; };
@ -665,8 +843,8 @@ mod tests {
}) })
} }
fn new_map() -> Map { fn new_map() -> MapData {
Map { MapData {
obj: new_obj_map(), obj: new_obj_map(),
fd: None, fd: None,
pinned: false, pinned: false,

@ -1,6 +1,6 @@
use bytes::BytesMut; use bytes::BytesMut;
use std::{ use std::{
ops::DerefMut, convert::AsMut,
os::unix::prelude::{AsRawFd, RawFd}, os::unix::prelude::{AsRawFd, RawFd},
}; };
@ -12,7 +12,7 @@ use tokio::io::unix::AsyncFd;
use crate::maps::{ use crate::maps::{
perf::{Events, PerfBufferError, PerfEventArray, PerfEventArrayBuffer}, perf::{Events, PerfBufferError, PerfEventArray, PerfEventArrayBuffer},
Map, MapError, MapRefMut, MapData, MapError,
}; };
/// A `Future` based map that can be used to receive events from eBPF programs using the linux /// A `Future` based map that can be used to receive events from eBPF programs using the linux
@ -45,7 +45,7 @@ use crate::maps::{
/// # } /// # }
/// # #[cfg(feature = "async_tokio")] /// # #[cfg(feature = "async_tokio")]
/// # async fn try_main() -> Result<(), Error> { /// # async fn try_main() -> Result<(), Error> {
/// # let bpf = aya::Bpf::load(&[])?; /// # let mut bpf = aya::Bpf::load(&[])?;
/// use aya::maps::perf::{AsyncPerfEventArray, PerfBufferError}; /// use aya::maps::perf::{AsyncPerfEventArray, PerfBufferError};
/// use aya::util::online_cpus; /// use aya::util::online_cpus;
/// use futures::future; /// use futures::future;
@ -53,7 +53,7 @@ use crate::maps::{
/// use tokio::task; // or async_std::task /// use tokio::task; // or async_std::task
/// ///
/// // try to convert the PERF_ARRAY map to an AsyncPerfEventArray /// // try to convert the PERF_ARRAY map to an AsyncPerfEventArray
/// let mut perf_array = AsyncPerfEventArray::try_from(bpf.map_mut("PERF_ARRAY")?)?; /// let mut perf_array: AsyncPerfEventArray<_> =bpf.take_map("PERF_ARRAY")?.try_into()?;
/// ///
/// for cpu_id in online_cpus()? { /// for cpu_id in online_cpus()? {
/// // open a separate perf buffer for each cpu /// // open a separate perf buffer for each cpu
@ -85,11 +85,11 @@ use crate::maps::{
/// # } /// # }
/// ``` /// ```
#[doc(alias = "BPF_MAP_TYPE_PERF_EVENT_ARRAY")] #[doc(alias = "BPF_MAP_TYPE_PERF_EVENT_ARRAY")]
pub struct AsyncPerfEventArray<T: DerefMut<Target = Map>> { pub struct AsyncPerfEventArray<T> {
perf_map: PerfEventArray<T>, perf_map: PerfEventArray<T>,
} }
impl<T: DerefMut<Target = Map>> AsyncPerfEventArray<T> { impl<T: AsMut<MapData> + AsRef<MapData>> AsyncPerfEventArray<T> {
/// Opens the perf buffer at the given index. /// Opens the perf buffer at the given index.
/// ///
/// The returned buffer will receive all the events eBPF programs send at the given index. /// The returned buffer will receive all the events eBPF programs send at the given index.
@ -112,8 +112,8 @@ impl<T: DerefMut<Target = Map>> AsyncPerfEventArray<T> {
} }
} }
impl<T: DerefMut<Target = Map>> AsyncPerfEventArray<T> { impl<T: AsRef<MapData>> AsyncPerfEventArray<T> {
fn new(map: T) -> Result<AsyncPerfEventArray<T>, MapError> { pub(crate) fn new(map: T) -> Result<AsyncPerfEventArray<T>, MapError> {
Ok(AsyncPerfEventArray { Ok(AsyncPerfEventArray {
perf_map: PerfEventArray::new(map)?, perf_map: PerfEventArray::new(map)?,
}) })
@ -127,7 +127,7 @@ impl<T: DerefMut<Target = Map>> AsyncPerfEventArray<T> {
/// ///
/// See the [`AsyncPerfEventArray` documentation](AsyncPerfEventArray) for an overview of how to /// See the [`AsyncPerfEventArray` documentation](AsyncPerfEventArray) for an overview of how to
/// use perf buffers. /// use perf buffers.
pub struct AsyncPerfEventArrayBuffer<T: DerefMut<Target = Map>> { pub struct AsyncPerfEventArrayBuffer<T> {
buf: PerfEventArrayBuffer<T>, buf: PerfEventArrayBuffer<T>,
#[cfg(feature = "async_tokio")] #[cfg(feature = "async_tokio")]
@ -138,7 +138,7 @@ pub struct AsyncPerfEventArrayBuffer<T: DerefMut<Target = Map>> {
} }
#[cfg(any(feature = "async_tokio"))] #[cfg(any(feature = "async_tokio"))]
impl<T: DerefMut<Target = Map>> AsyncPerfEventArrayBuffer<T> { impl<T: AsMut<MapData> + AsRef<MapData>> AsyncPerfEventArrayBuffer<T> {
/// Reads events from the buffer. /// Reads events from the buffer.
/// ///
/// This method reads events into the provided slice of buffers, filling /// This method reads events into the provided slice of buffers, filling
@ -168,7 +168,7 @@ impl<T: DerefMut<Target = Map>> AsyncPerfEventArrayBuffer<T> {
} }
#[cfg(all(not(feature = "async_tokio"), feature = "async_std"))] #[cfg(all(not(feature = "async_tokio"), feature = "async_std"))]
impl<T: DerefMut<Target = Map>> AsyncPerfEventArrayBuffer<T> { impl<T: AsMut<MapData> + AsRef<MapData>> AsyncPerfEventArrayBuffer<T> {
/// Reads events from the buffer. /// Reads events from the buffer.
/// ///
/// This method reads events into the provided slice of buffers, filling /// This method reads events into the provided slice of buffers, filling
@ -195,11 +195,3 @@ impl<T: DerefMut<Target = Map>> AsyncPerfEventArrayBuffer<T> {
} }
} }
} }
impl TryFrom<MapRefMut> for AsyncPerfEventArray<MapRefMut> {
type Error = MapError;
fn try_from(a: MapRefMut) -> Result<AsyncPerfEventArray<MapRefMut>, MapError> {
AsyncPerfEventArray::new(a)
}
}

@ -2,7 +2,8 @@
//! //!
//! [`perf`]: https://perf.wiki.kernel.org/index.php/Main_Page. //! [`perf`]: https://perf.wiki.kernel.org/index.php/Main_Page.
use std::{ use std::{
ops::DerefMut, convert::AsMut,
ops::Deref,
os::unix::io::{AsRawFd, RawFd}, os::unix::io::{AsRawFd, RawFd},
sync::Arc, sync::Arc,
}; };
@ -10,10 +11,9 @@ use std::{
use bytes::BytesMut; use bytes::BytesMut;
use crate::{ use crate::{
generated::bpf_map_type::BPF_MAP_TYPE_PERF_EVENT_ARRAY,
maps::{ maps::{
perf::{Events, PerfBuffer, PerfBufferError}, perf::{Events, PerfBuffer, PerfBufferError},
Map, MapError, MapRefMut, MapData, MapError,
}, },
sys::bpf_map_update_elem, sys::bpf_map_update_elem,
util::page_size, util::page_size,
@ -26,12 +26,12 @@ use crate::{
/// ///
/// See the [`PerfEventArray` documentation](PerfEventArray) for an overview of how to use /// See the [`PerfEventArray` documentation](PerfEventArray) for an overview of how to use
/// perf buffers. /// perf buffers.
pub struct PerfEventArrayBuffer<T: DerefMut<Target = Map>> { pub struct PerfEventArrayBuffer<T> {
_map: Arc<T>, _map: Arc<T>,
buf: PerfBuffer, buf: PerfBuffer,
} }
impl<T: DerefMut<Target = Map>> PerfEventArrayBuffer<T> { impl<T: AsMut<MapData> + AsRef<MapData>> PerfEventArrayBuffer<T> {
/// Returns true if the buffer contains events that haven't been read. /// Returns true if the buffer contains events that haven't been read.
pub fn readable(&self) -> bool { pub fn readable(&self) -> bool {
self.buf.readable() self.buf.readable()
@ -55,7 +55,7 @@ impl<T: DerefMut<Target = Map>> PerfEventArrayBuffer<T> {
} }
} }
impl<T: DerefMut<Target = Map>> AsRawFd for PerfEventArrayBuffer<T> { impl<T: AsMut<MapData> + AsRef<MapData>> AsRawFd for PerfEventArrayBuffer<T> {
fn as_raw_fd(&self) -> RawFd { fn as_raw_fd(&self) -> RawFd {
self.buf.as_raw_fd() self.buf.as_raw_fd()
} }
@ -83,15 +83,15 @@ impl<T: DerefMut<Target = Map>> AsRawFd for PerfEventArrayBuffer<T> {
/// ///
/// ```no_run /// ```no_run
/// # use aya::maps::perf::PerfEventArrayBuffer; /// # use aya::maps::perf::PerfEventArrayBuffer;
/// # use aya::maps::Map; /// # use aya::maps::MapData;
/// # use std::ops::DerefMut; /// # use std::convert::AsMut;
/// # struct Poll<T> { _t: std::marker::PhantomData<T> }; /// # struct Poll<T> { _t: std::marker::PhantomData<T> };
/// # impl<T: DerefMut<Target=Map>> Poll<T> { /// # impl<T: AsMut<MapData>> Poll<T> {
/// # fn poll_readable(&self) -> &mut [PerfEventArrayBuffer<T>] { /// # fn poll_readable(&self) -> &mut [PerfEventArrayBuffer<T>] {
/// # &mut [] /// # &mut []
/// # } /// # }
/// # } /// # }
/// # fn poll_buffers<T: DerefMut<Target=Map>>(bufs: Vec<PerfEventArrayBuffer<T>>) -> Poll<T> { /// # fn poll_buffers<T: AsMut<MapData>>(bufs: Vec<PerfEventArrayBuffer<T>>) -> Poll<T> {
/// # Poll { _t: std::marker::PhantomData } /// # Poll { _t: std::marker::PhantomData }
/// # } /// # }
/// # #[derive(thiserror::Error, Debug)] /// # #[derive(thiserror::Error, Debug)]
@ -105,12 +105,12 @@ impl<T: DerefMut<Target = Map>> AsRawFd for PerfEventArrayBuffer<T> {
/// # #[error(transparent)] /// # #[error(transparent)]
/// # PerfBuf(#[from] aya::maps::perf::PerfBufferError), /// # PerfBuf(#[from] aya::maps::perf::PerfBufferError),
/// # } /// # }
/// # let bpf = aya::Bpf::load(&[])?; /// # let mut bpf = aya::Bpf::load(&[])?;
/// use aya::maps::PerfEventArray; /// use aya::maps::PerfEventArray;
/// use aya::util::online_cpus; /// use aya::util::online_cpus;
/// use bytes::BytesMut; /// use bytes::BytesMut;
/// ///
/// let mut perf_array = PerfEventArray::try_from(bpf.map_mut("EVENTS")?)?; /// let mut perf_array: PerfEventArray<_> = bpf.map_mut("EVENTS")?.try_into()?;
/// ///
/// // eBPF programs are going to write to the EVENTS perf array, using the id of the CPU they're /// // eBPF programs are going to write to the EVENTS perf array, using the id of the CPU they're
/// // running on as the array index. /// // running on as the array index.
@ -155,25 +155,23 @@ impl<T: DerefMut<Target = Map>> AsRawFd for PerfEventArrayBuffer<T> {
/// [tokio]: https://docs.rs/tokio /// [tokio]: https://docs.rs/tokio
/// [async-std]: https://docs.rs/async-std /// [async-std]: https://docs.rs/async-std
#[doc(alias = "BPF_MAP_TYPE_PERF_EVENT_ARRAY")] #[doc(alias = "BPF_MAP_TYPE_PERF_EVENT_ARRAY")]
pub struct PerfEventArray<T: DerefMut<Target = Map>> { pub struct PerfEventArray<T> {
map: Arc<T>, map: Arc<T>,
page_size: usize, page_size: usize,
} }
impl<T: DerefMut<Target = Map>> PerfEventArray<T> { impl<T: AsRef<MapData>> PerfEventArray<T> {
pub(crate) fn new(map: T) -> Result<PerfEventArray<T>, MapError> { pub(crate) fn new(map: T) -> Result<PerfEventArray<T>, MapError> {
let map_type = map.obj.map_type(); let _fd = map.as_ref().fd_or_err()?;
if map_type != BPF_MAP_TYPE_PERF_EVENT_ARRAY as u32 {
return Err(MapError::InvalidMapType { map_type });
}
let _fd = map.fd_or_err()?;
Ok(PerfEventArray { Ok(PerfEventArray {
map: Arc::new(map), map: Arc::new(map),
page_size: page_size(), page_size: page_size(),
}) })
} }
}
impl<T: AsMut<MapData> + AsRef<MapData>> PerfEventArray<T> {
/// Opens the perf buffer at the given index. /// Opens the perf buffer at the given index.
/// ///
/// The returned buffer will receive all the events eBPF programs send at the given index. /// The returned buffer will receive all the events eBPF programs send at the given index.
@ -185,7 +183,8 @@ impl<T: DerefMut<Target = Map>> PerfEventArray<T> {
// FIXME: keep track of open buffers // FIXME: keep track of open buffers
// this cannot fail as new() checks that the fd is open // this cannot fail as new() checks that the fd is open
let map_fd = self.map.fd_or_err().unwrap(); let map_data: &MapData = self.map.deref().as_ref();
let map_fd = map_data.fd_or_err().unwrap();
let buf = PerfBuffer::open(index, self.page_size, page_count.unwrap_or(2))?; let buf = PerfBuffer::open(index, self.page_size, page_count.unwrap_or(2))?;
bpf_map_update_elem(map_fd, Some(&index), &buf.as_raw_fd(), 0) bpf_map_update_elem(map_fd, Some(&index), &buf.as_raw_fd(), 0)
.map_err(|(_, io_error)| io_error)?; .map_err(|(_, io_error)| io_error)?;
@ -196,11 +195,3 @@ impl<T: DerefMut<Target = Map>> PerfEventArray<T> {
}) })
} }
} }
impl TryFrom<MapRefMut> for PerfEventArray<MapRefMut> {
type Error = MapError;
fn try_from(a: MapRefMut) -> Result<PerfEventArray<MapRefMut>, MapError> {
PerfEventArray::new(a)
}
}

@ -1,13 +1,12 @@
//! A FIFO queue. //! A FIFO queue.
use std::{ use std::{
convert::{AsMut, AsRef},
marker::PhantomData, marker::PhantomData,
mem, mem,
ops::{Deref, DerefMut},
}; };
use crate::{ use crate::{
generated::bpf_map_type::BPF_MAP_TYPE_QUEUE, maps::{MapData, MapError},
maps::{Map, MapError, MapRef, MapRefMut},
sys::{bpf_map_lookup_and_delete_elem, bpf_map_push_elem}, sys::{bpf_map_lookup_and_delete_elem, bpf_map_push_elem},
Pod, Pod,
}; };
@ -20,39 +19,36 @@ use crate::{
/// ///
/// # Examples /// # Examples
/// ```no_run /// ```no_run
/// # let bpf = aya::Bpf::load(&[])?; /// # let mut bpf = aya::Bpf::load(&[])?;
/// use aya::maps::Queue; /// use aya::maps::Queue;
/// ///
/// let mut queue = Queue::try_from(bpf.map_mut("ARRAY")?)?; /// let mut queue: Queue<_, u32> = bpf.map_mut("ARRAY")?.try_into()?;
/// queue.push(42, 0)?; /// queue.push(42, 0)?;
/// queue.push(43, 0)?; /// queue.push(43, 0)?;
/// assert_eq!(queue.pop(0)?, 42); /// assert_eq!(queue.pop(0)?, 42);
/// # Ok::<(), aya::BpfError>(()) /// # Ok::<(), aya::BpfError>(())
/// ``` /// ```
#[doc(alias = "BPF_MAP_TYPE_QUEUE")] #[doc(alias = "BPF_MAP_TYPE_QUEUE")]
pub struct Queue<T: Deref<Target = Map>, V: Pod> { pub struct Queue<T, V: Pod> {
inner: T, inner: T,
_v: PhantomData<V>, _v: PhantomData<V>,
} }
impl<T: Deref<Target = Map>, V: Pod> Queue<T, V> { impl<T: AsRef<MapData>, V: Pod> Queue<T, V> {
fn new(map: T) -> Result<Queue<T, V>, MapError> { pub(crate) fn new(map: T) -> Result<Queue<T, V>, MapError> {
let map_type = map.obj.map_type(); let data = map.as_ref();
if map_type != BPF_MAP_TYPE_QUEUE as u32 {
return Err(MapError::InvalidMapType { map_type });
}
let expected = 0; let expected = 0;
let size = map.obj.key_size() as usize; let size = data.obj.key_size() as usize;
if size != expected { if size != expected {
return Err(MapError::InvalidKeySize { size, expected }); return Err(MapError::InvalidKeySize { size, expected });
} }
let expected = mem::size_of::<V>(); let expected = mem::size_of::<V>();
let size = map.obj.value_size() as usize; let size = data.obj.value_size() as usize;
if size != expected { if size != expected {
return Err(MapError::InvalidValueSize { size, expected }); return Err(MapError::InvalidValueSize { size, expected });
} }
let _fd = map.fd_or_err()?; let _fd = data.fd_or_err()?;
Ok(Queue { Ok(Queue {
inner: map, inner: map,
@ -64,11 +60,11 @@ impl<T: Deref<Target = Map>, V: Pod> Queue<T, V> {
/// ///
/// This corresponds to the value of `bpf_map_def::max_entries` on the eBPF side. /// This corresponds to the value of `bpf_map_def::max_entries` on the eBPF side.
pub fn capacity(&self) -> u32 { pub fn capacity(&self) -> u32 {
self.inner.obj.max_entries() self.inner.as_ref().obj.max_entries()
} }
} }
impl<T: Deref<Target = Map> + DerefMut<Target = Map>, V: Pod> Queue<T, V> { impl<T: AsMut<MapData>, V: Pod> Queue<T, V> {
/// Removes the first element and returns it. /// Removes the first element and returns it.
/// ///
/// # Errors /// # Errors
@ -76,7 +72,7 @@ impl<T: Deref<Target = Map> + DerefMut<Target = Map>, V: Pod> Queue<T, V> {
/// Returns [`MapError::ElementNotFound`] if the queue is empty, [`MapError::SyscallError`] /// Returns [`MapError::ElementNotFound`] if the queue is empty, [`MapError::SyscallError`]
/// if `bpf_map_lookup_and_delete_elem` fails. /// if `bpf_map_lookup_and_delete_elem` fails.
pub fn pop(&mut self, flags: u64) -> Result<V, MapError> { pub fn pop(&mut self, flags: u64) -> Result<V, MapError> {
let fd = self.inner.fd_or_err()?; let fd = self.inner.as_mut().fd_or_err()?;
let value = bpf_map_lookup_and_delete_elem::<u32, _>(fd, None, flags).map_err( let value = bpf_map_lookup_and_delete_elem::<u32, _>(fd, None, flags).map_err(
|(_, io_error)| MapError::SyscallError { |(_, io_error)| MapError::SyscallError {
@ -93,7 +89,7 @@ impl<T: Deref<Target = Map> + DerefMut<Target = Map>, V: Pod> Queue<T, V> {
/// ///
/// [`MapError::SyscallError`] if `bpf_map_update_elem` fails. /// [`MapError::SyscallError`] if `bpf_map_update_elem` fails.
pub fn push(&mut self, value: V, flags: u64) -> Result<(), MapError> { pub fn push(&mut self, value: V, flags: u64) -> Result<(), MapError> {
let fd = self.inner.fd_or_err()?; let fd = self.inner.as_mut().fd_or_err()?;
bpf_map_push_elem(fd, &value, flags).map_err(|(_, io_error)| MapError::SyscallError { bpf_map_push_elem(fd, &value, flags).map_err(|(_, io_error)| MapError::SyscallError {
call: "bpf_map_push_elem".to_owned(), call: "bpf_map_push_elem".to_owned(),
io_error, io_error,
@ -101,19 +97,3 @@ impl<T: Deref<Target = Map> + DerefMut<Target = Map>, V: Pod> Queue<T, V> {
Ok(()) Ok(())
} }
} }
impl<V: Pod> TryFrom<MapRef> for Queue<MapRef, V> {
type Error = MapError;
fn try_from(a: MapRef) -> Result<Queue<MapRef, V>, MapError> {
Queue::new(a)
}
}
impl<V: Pod> TryFrom<MapRefMut> for Queue<MapRefMut, V> {
type Error = MapError;
fn try_from(a: MapRefMut) -> Result<Queue<MapRefMut, V>, MapError> {
Queue::new(a)
}
}

@ -1,14 +1,11 @@
use std::{ use std::{
convert::{AsMut, AsRef},
marker::PhantomData, marker::PhantomData,
ops::{Deref, DerefMut},
os::unix::io::{AsRawFd, RawFd}, os::unix::io::{AsRawFd, RawFd},
}; };
use crate::{ use crate::{
generated::bpf_map_type::BPF_MAP_TYPE_SOCKHASH, maps::{hash_map, sock::SocketMap, IterableMap, MapData, MapError, MapIter, MapKeys},
maps::{
hash_map, sock::SocketMap, IterableMap, Map, MapError, MapIter, MapKeys, MapRef, MapRefMut,
},
sys::bpf_map_lookup_elem, sys::bpf_map_lookup_elem,
Pod, Pod,
}; };
@ -47,7 +44,7 @@ use crate::{
/// use aya::maps::SockHash; /// use aya::maps::SockHash;
/// use aya::programs::SkMsg; /// use aya::programs::SkMsg;
/// ///
/// let mut intercept_egress = SockHash::try_from(bpf.map_mut("INTERCEPT_EGRESS")?)?; /// let mut intercept_egress: SockHash<_, u32> = bpf.take_map("INTERCEPT_EGRESS")?.try_into()?;
/// let prog: &mut SkMsg = bpf.program_mut("intercept_egress_packet").unwrap().try_into()?; /// let prog: &mut SkMsg = bpf.program_mut("intercept_egress_packet").unwrap().try_into()?;
/// prog.load()?; /// prog.load()?;
/// prog.attach(&intercept_egress)?; /// prog.attach(&intercept_egress)?;
@ -60,21 +57,16 @@ use crate::{
/// # Ok::<(), Error>(()) /// # Ok::<(), Error>(())
/// ``` /// ```
#[doc(alias = "BPF_MAP_TYPE_SOCKHASH")] #[doc(alias = "BPF_MAP_TYPE_SOCKHASH")]
pub struct SockHash<T: Deref<Target = Map>, K> { pub struct SockHash<T, K> {
inner: T, inner: T,
_k: PhantomData<K>, _k: PhantomData<K>,
} }
impl<T: Deref<Target = Map>, K: Pod> SockHash<T, K> { impl<T: AsRef<MapData>, K: Pod> SockHash<T, K> {
pub(crate) fn new(map: T) -> Result<SockHash<T, K>, MapError> { pub(crate) fn new(map: T) -> Result<SockHash<T, K>, MapError> {
let map_type = map.obj.map_type(); let data = map.as_ref();
hash_map::check_kv_size::<K, u32>(data)?;
// validate the map definition let _ = data.fd_or_err()?;
if map_type != BPF_MAP_TYPE_SOCKHASH as u32 {
return Err(MapError::InvalidMapType { map_type });
}
hash_map::check_kv_size::<K, u32>(&map)?;
let _ = map.fd_or_err()?;
Ok(SockHash { Ok(SockHash {
inner: map, inner: map,
@ -84,7 +76,7 @@ impl<T: Deref<Target = Map>, K: Pod> SockHash<T, K> {
/// Returns the fd of the socket stored at the given key. /// Returns the fd of the socket stored at the given key.
pub fn get(&self, key: &K, flags: u64) -> Result<RawFd, MapError> { pub fn get(&self, key: &K, flags: u64) -> Result<RawFd, MapError> {
let fd = self.inner.deref().fd_or_err()?; let fd = self.inner.as_ref().fd_or_err()?;
let value = bpf_map_lookup_elem(fd, key, flags).map_err(|(_, io_error)| { let value = bpf_map_lookup_elem(fd, key, flags).map_err(|(_, io_error)| {
MapError::SyscallError { MapError::SyscallError {
call: "bpf_map_lookup_elem".to_owned(), call: "bpf_map_lookup_elem".to_owned(),
@ -103,25 +95,25 @@ impl<T: Deref<Target = Map>, K: Pod> SockHash<T, K> {
/// An iterator visiting all keys in arbitrary order. The iterator element /// An iterator visiting all keys in arbitrary order. The iterator element
/// type is `Result<K, MapError>`. /// type is `Result<K, MapError>`.
pub fn keys(&self) -> MapKeys<'_, K> { pub fn keys(&self) -> MapKeys<'_, K> {
MapKeys::new(&self.inner) MapKeys::new(self.inner.as_ref())
} }
} }
impl<T: DerefMut<Target = Map>, K: Pod> SockHash<T, K> { impl<T: AsMut<MapData>, K: Pod> SockHash<T, K> {
/// Inserts a socket under the given key. /// Inserts a socket under the given key.
pub fn insert<I: AsRawFd>(&mut self, key: K, value: I, flags: u64) -> Result<(), MapError> { pub fn insert<I: AsRawFd>(&mut self, key: K, value: I, flags: u64) -> Result<(), MapError> {
hash_map::insert(&mut self.inner, key, value.as_raw_fd(), flags) hash_map::insert(self.inner.as_mut(), key, value.as_raw_fd(), flags)
} }
/// Removes a socket from the map. /// Removes a socket from the map.
pub fn remove(&mut self, key: &K) -> Result<(), MapError> { pub fn remove(&mut self, key: &K) -> Result<(), MapError> {
hash_map::remove(&mut self.inner, key) hash_map::remove(self.inner.as_mut(), key)
} }
} }
impl<T: Deref<Target = Map>, K: Pod> IterableMap<K, RawFd> for SockHash<T, K> { impl<T: AsRef<MapData>, K: Pod> IterableMap<K, RawFd> for SockHash<T, K> {
fn map(&self) -> &Map { fn map(&self) -> &MapData {
&self.inner self.inner.as_ref()
} }
fn get(&self, key: &K) -> Result<RawFd, MapError> { fn get(&self, key: &K) -> Result<RawFd, MapError> {
@ -129,24 +121,8 @@ impl<T: Deref<Target = Map>, K: Pod> IterableMap<K, RawFd> for SockHash<T, K> {
} }
} }
impl<T: DerefMut<Target = Map>, K: Pod> SocketMap for SockHash<T, K> { impl<T: AsRef<MapData>, K: Pod> SocketMap for SockHash<T, K> {
fn fd_or_err(&self) -> Result<RawFd, MapError> { fn fd_or_err(&self) -> Result<RawFd, MapError> {
self.inner.fd_or_err() self.inner.as_ref().fd_or_err()
}
}
impl<K: Pod> TryFrom<MapRef> for SockHash<MapRef, K> {
type Error = MapError;
fn try_from(a: MapRef) -> Result<SockHash<MapRef, K>, MapError> {
SockHash::new(a)
}
}
impl<K: Pod> TryFrom<MapRefMut> for SockHash<MapRefMut, K> {
type Error = MapError;
fn try_from(a: MapRefMut) -> Result<SockHash<MapRefMut, K>, MapError> {
SockHash::new(a)
} }
} }

@ -1,14 +1,13 @@
//! An array of eBPF program file descriptors used as a jump table. //! An array of eBPF program file descriptors used as a jump table.
use std::{ use std::{
convert::{AsMut, AsRef},
mem, mem,
ops::{Deref, DerefMut},
os::unix::{io::AsRawFd, prelude::RawFd}, os::unix::{io::AsRawFd, prelude::RawFd},
}; };
use crate::{ use crate::{
generated::bpf_map_type::BPF_MAP_TYPE_SOCKMAP, maps::{sock::SocketMap, MapData, MapError, MapKeys},
maps::{sock::SocketMap, Map, MapError, MapKeys, MapRef, MapRefMut},
sys::{bpf_map_delete_elem, bpf_map_update_elem}, sys::{bpf_map_delete_elem, bpf_map_update_elem},
}; };
@ -32,35 +31,32 @@ use crate::{
/// use aya::maps::SockMap; /// use aya::maps::SockMap;
/// use aya::programs::SkSkb; /// use aya::programs::SkSkb;
/// ///
/// let intercept_ingress = SockMap::try_from(bpf.map_mut("INTERCEPT_INGRESS")?)?; /// let intercept_ingress: SockMap<_> = bpf.take_map("INTERCEPT_INGRESS")?.try_into()?;
/// let prog: &mut SkSkb = bpf.program_mut("intercept_ingress_packet").unwrap().try_into()?; /// let prog: &mut SkSkb = bpf.program_mut("intercept_ingress_packet").unwrap().try_into()?;
/// prog.load()?; /// prog.load()?;
/// prog.attach(&intercept_ingress)?; /// prog.attach(&intercept_ingress)?;
/// # Ok::<(), aya::BpfError>(()) /// # Ok::<(), aya::BpfError>(())
/// ``` /// ```
#[doc(alias = "BPF_MAP_TYPE_SOCKMAP")] #[doc(alias = "BPF_MAP_TYPE_SOCKMAP")]
pub struct SockMap<T: Deref<Target = Map>> { pub struct SockMap<T: AsRef<MapData>> {
pub(crate) inner: T, pub(crate) inner: T,
} }
impl<T: Deref<Target = Map>> SockMap<T> { impl<T: AsRef<MapData>> SockMap<T> {
fn new(map: T) -> Result<SockMap<T>, MapError> { pub(crate) fn new(map: T) -> Result<SockMap<T>, MapError> {
let map_type = map.obj.map_type(); let data = map.as_ref();
if map_type != BPF_MAP_TYPE_SOCKMAP as u32 {
return Err(MapError::InvalidMapType { map_type });
}
let expected = mem::size_of::<u32>(); let expected = mem::size_of::<u32>();
let size = map.obj.key_size() as usize; let size = data.obj.key_size() as usize;
if size != expected { if size != expected {
return Err(MapError::InvalidKeySize { size, expected }); return Err(MapError::InvalidKeySize { size, expected });
} }
let expected = mem::size_of::<RawFd>(); let expected = mem::size_of::<RawFd>();
let size = map.obj.value_size() as usize; let size = data.obj.value_size() as usize;
if size != expected { if size != expected {
return Err(MapError::InvalidValueSize { size, expected }); return Err(MapError::InvalidValueSize { size, expected });
} }
let _fd = map.fd_or_err()?; let _fd = data.fd_or_err()?;
Ok(SockMap { inner: map }) Ok(SockMap { inner: map })
} }
@ -68,12 +64,12 @@ impl<T: Deref<Target = Map>> SockMap<T> {
/// An iterator over the indices of the array that point to a program. The iterator item type /// An iterator over the indices of the array that point to a program. The iterator item type
/// is `Result<u32, MapError>`. /// is `Result<u32, MapError>`.
pub fn indices(&self) -> MapKeys<'_, u32> { pub fn indices(&self) -> MapKeys<'_, u32> {
MapKeys::new(&self.inner) MapKeys::new(self.inner.as_ref())
} }
fn check_bounds(&self, index: u32) -> Result<(), MapError> { fn check_bounds(&self, index: u32) -> Result<(), MapError> {
let max_entries = self.inner.obj.max_entries(); let max_entries = self.inner.as_ref().obj.max_entries();
if index >= self.inner.obj.max_entries() { if index >= self.inner.as_ref().obj.max_entries() {
Err(MapError::OutOfBounds { index, max_entries }) Err(MapError::OutOfBounds { index, max_entries })
} else { } else {
Ok(()) Ok(())
@ -81,10 +77,10 @@ impl<T: Deref<Target = Map>> SockMap<T> {
} }
} }
impl<T: Deref<Target = Map> + DerefMut<Target = Map>> SockMap<T> { impl<T: AsRef<MapData> + AsMut<MapData>> SockMap<T> {
/// Stores a socket into the map. /// Stores a socket into the map.
pub fn set<I: AsRawFd>(&mut self, index: u32, socket: &I, flags: u64) -> Result<(), MapError> { pub fn set<I: AsRawFd>(&mut self, index: u32, socket: &I, flags: u64) -> Result<(), MapError> {
let fd = self.inner.fd_or_err()?; let fd = self.inner.as_ref().fd_or_err()?;
self.check_bounds(index)?; self.check_bounds(index)?;
bpf_map_update_elem(fd, Some(&index), &socket.as_raw_fd(), flags).map_err( bpf_map_update_elem(fd, Some(&index), &socket.as_raw_fd(), flags).map_err(
|(_, io_error)| MapError::SyscallError { |(_, io_error)| MapError::SyscallError {
@ -97,7 +93,7 @@ impl<T: Deref<Target = Map> + DerefMut<Target = Map>> SockMap<T> {
/// Removes the socket stored at `index` from the map. /// Removes the socket stored at `index` from the map.
pub fn clear_index(&mut self, index: &u32) -> Result<(), MapError> { pub fn clear_index(&mut self, index: &u32) -> Result<(), MapError> {
let fd = self.inner.fd_or_err()?; let fd = self.inner.as_ref().fd_or_err()?;
self.check_bounds(*index)?; self.check_bounds(*index)?;
bpf_map_delete_elem(fd, index) bpf_map_delete_elem(fd, index)
.map(|_| ()) .map(|_| ())
@ -108,24 +104,8 @@ impl<T: Deref<Target = Map> + DerefMut<Target = Map>> SockMap<T> {
} }
} }
impl<T: Deref<Target = Map> + DerefMut<Target = Map>> SocketMap for SockMap<T> { impl<T: AsRef<MapData> + AsMut<MapData>> SocketMap for SockMap<T> {
fn fd_or_err(&self) -> Result<RawFd, MapError> { fn fd_or_err(&self) -> Result<RawFd, MapError> {
self.inner.fd_or_err() self.inner.as_ref().fd_or_err()
}
}
impl TryFrom<MapRef> for SockMap<MapRef> {
type Error = MapError;
fn try_from(a: MapRef) -> Result<SockMap<MapRef>, MapError> {
SockMap::new(a)
}
}
impl TryFrom<MapRefMut> for SockMap<MapRefMut> {
type Error = MapError;
fn try_from(a: MapRefMut) -> Result<SockMap<MapRefMut>, MapError> {
SockMap::new(a)
} }
} }

@ -1,13 +1,12 @@
//! A LIFO stack. //! A LIFO stack.
use std::{ use std::{
convert::{AsMut, AsRef},
marker::PhantomData, marker::PhantomData,
mem, mem,
ops::{Deref, DerefMut},
}; };
use crate::{ use crate::{
generated::bpf_map_type::BPF_MAP_TYPE_STACK, maps::{MapData, MapError},
maps::{Map, MapError, MapRef, MapRefMut},
sys::{bpf_map_lookup_and_delete_elem, bpf_map_update_elem}, sys::{bpf_map_lookup_and_delete_elem, bpf_map_update_elem},
Pod, Pod,
}; };
@ -20,39 +19,36 @@ use crate::{
/// ///
/// # Examples /// # Examples
/// ```no_run /// ```no_run
/// # let bpf = aya::Bpf::load(&[])?; /// # let mut bpf = aya::Bpf::load(&[])?;
/// use aya::maps::Stack; /// use aya::maps::Stack;
/// ///
/// let mut stack = Stack::try_from(bpf.map_mut("STACK")?)?; /// let mut stack: Stack<_, u32> = bpf.map_mut("STACK")?.try_into()?;
/// stack.push(42, 0)?; /// stack.push(42, 0)?;
/// stack.push(43, 0)?; /// stack.push(43, 0)?;
/// assert_eq!(stack.pop(0)?, 43); /// assert_eq!(stack.pop(0)?, 43);
/// # Ok::<(), aya::BpfError>(()) /// # Ok::<(), aya::BpfError>(())
/// ``` /// ```
#[doc(alias = "BPF_MAP_TYPE_STACK")] #[doc(alias = "BPF_MAP_TYPE_STACK")]
pub struct Stack<T: Deref<Target = Map>, V: Pod> { pub struct Stack<T, V: Pod> {
inner: T, inner: T,
_v: PhantomData<V>, _v: PhantomData<V>,
} }
impl<T: Deref<Target = Map>, V: Pod> Stack<T, V> { impl<T: AsRef<MapData>, V: Pod> Stack<T, V> {
fn new(map: T) -> Result<Stack<T, V>, MapError> { pub(crate) fn new(map: T) -> Result<Stack<T, V>, MapError> {
let map_type = map.obj.map_type(); let data = map.as_ref();
if map_type != BPF_MAP_TYPE_STACK as u32 {
return Err(MapError::InvalidMapType { map_type });
}
let expected = 0; let expected = 0;
let size = map.obj.key_size() as usize; let size = data.obj.key_size() as usize;
if size != expected { if size != expected {
return Err(MapError::InvalidKeySize { size, expected }); return Err(MapError::InvalidKeySize { size, expected });
} }
let expected = mem::size_of::<V>(); let expected = mem::size_of::<V>();
let size = map.obj.value_size() as usize; let size = data.obj.value_size() as usize;
if size != expected { if size != expected {
return Err(MapError::InvalidValueSize { size, expected }); return Err(MapError::InvalidValueSize { size, expected });
} }
let _fd = map.fd_or_err()?; let _fd = data.fd_or_err()?;
Ok(Stack { Ok(Stack {
inner: map, inner: map,
@ -64,11 +60,11 @@ impl<T: Deref<Target = Map>, V: Pod> Stack<T, V> {
/// ///
/// This corresponds to the value of `bpf_map_def::max_entries` on the eBPF side. /// This corresponds to the value of `bpf_map_def::max_entries` on the eBPF side.
pub fn capacity(&self) -> u32 { pub fn capacity(&self) -> u32 {
self.inner.obj.max_entries() self.inner.as_ref().obj.max_entries()
} }
} }
impl<T: Deref<Target = Map> + DerefMut<Target = Map>, V: Pod> Stack<T, V> { impl<T: AsMut<MapData>, V: Pod> Stack<T, V> {
/// Removes the last element and returns it. /// Removes the last element and returns it.
/// ///
/// # Errors /// # Errors
@ -76,7 +72,7 @@ impl<T: Deref<Target = Map> + DerefMut<Target = Map>, V: Pod> Stack<T, V> {
/// Returns [`MapError::ElementNotFound`] if the stack is empty, [`MapError::SyscallError`] /// Returns [`MapError::ElementNotFound`] if the stack is empty, [`MapError::SyscallError`]
/// if `bpf_map_lookup_and_delete_elem` fails. /// if `bpf_map_lookup_and_delete_elem` fails.
pub fn pop(&mut self, flags: u64) -> Result<V, MapError> { pub fn pop(&mut self, flags: u64) -> Result<V, MapError> {
let fd = self.inner.fd_or_err()?; let fd = self.inner.as_mut().fd_or_err()?;
let value = bpf_map_lookup_and_delete_elem::<u32, _>(fd, None, flags).map_err( let value = bpf_map_lookup_and_delete_elem::<u32, _>(fd, None, flags).map_err(
|(_, io_error)| MapError::SyscallError { |(_, io_error)| MapError::SyscallError {
@ -93,7 +89,7 @@ impl<T: Deref<Target = Map> + DerefMut<Target = Map>, V: Pod> Stack<T, V> {
/// ///
/// [`MapError::SyscallError`] if `bpf_map_update_elem` fails. /// [`MapError::SyscallError`] if `bpf_map_update_elem` fails.
pub fn push(&mut self, value: V, flags: u64) -> Result<(), MapError> { pub fn push(&mut self, value: V, flags: u64) -> Result<(), MapError> {
let fd = self.inner.fd_or_err()?; let fd = self.inner.as_mut().fd_or_err()?;
bpf_map_update_elem(fd, None::<&u32>, &value, flags).map_err(|(_, io_error)| { bpf_map_update_elem(fd, None::<&u32>, &value, flags).map_err(|(_, io_error)| {
MapError::SyscallError { MapError::SyscallError {
call: "bpf_map_update_elem".to_owned(), call: "bpf_map_update_elem".to_owned(),
@ -103,19 +99,3 @@ impl<T: Deref<Target = Map> + DerefMut<Target = Map>, V: Pod> Stack<T, V> {
Ok(()) Ok(())
} }
} }
impl<V: Pod> TryFrom<MapRef> for Stack<MapRef, V> {
type Error = MapError;
fn try_from(a: MapRef) -> Result<Stack<MapRef, V>, MapError> {
Stack::new(a)
}
}
impl<V: Pod> TryFrom<MapRefMut> for Stack<MapRefMut, V> {
type Error = MapError;
fn try_from(a: MapRefMut) -> Result<Stack<MapRefMut, V>, MapError> {
Stack::new(a)
}
}

@ -1,11 +1,10 @@
//! A hash map of kernel or user space stack traces. //! A hash map of kernel or user space stack traces.
//! //!
//! See [`StackTraceMap`] for documentation and examples. //! See [`StackTraceMap`] for documentation and examples.
use std::{collections::BTreeMap, fs, io, mem, ops::Deref, path::Path, str::FromStr}; use std::{collections::BTreeMap, convert::AsRef, fs, io, mem, path::Path, str::FromStr};
use crate::{ use crate::{
generated::bpf_map_type::BPF_MAP_TYPE_STACK_TRACE, maps::{IterableMap, MapData, MapError, MapIter, MapKeys},
maps::{IterableMap, Map, MapError, MapIter, MapKeys, MapRef, MapRefMut},
sys::bpf_map_lookup_elem_ptr, sys::bpf_map_lookup_elem_ptr,
}; };
@ -68,14 +67,11 @@ pub struct StackTraceMap<T> {
max_stack_depth: usize, max_stack_depth: usize,
} }
impl<T: Deref<Target = Map>> StackTraceMap<T> { impl<T: AsRef<MapData>> StackTraceMap<T> {
fn new(map: T) -> Result<StackTraceMap<T>, MapError> { pub(crate) fn new(map: T) -> Result<StackTraceMap<T>, MapError> {
let map_type = map.obj.map_type(); let data = map.as_ref();
if map_type != BPF_MAP_TYPE_STACK_TRACE as u32 {
return Err(MapError::InvalidMapType { map_type });
}
let expected = mem::size_of::<u32>(); let expected = mem::size_of::<u32>();
let size = map.obj.key_size() as usize; let size = data.obj.key_size() as usize;
if size != expected { if size != expected {
return Err(MapError::InvalidKeySize { size, expected }); return Err(MapError::InvalidKeySize { size, expected });
} }
@ -87,11 +83,11 @@ impl<T: Deref<Target = Map>> StackTraceMap<T> {
io_error, io_error,
} }
})?; })?;
let size = map.obj.value_size() as usize; let size = data.obj.value_size() as usize;
if size > max_stack_depth * mem::size_of::<u64>() { if size > max_stack_depth * mem::size_of::<u64>() {
return Err(MapError::InvalidValueSize { size, expected }); return Err(MapError::InvalidValueSize { size, expected });
} }
let _fd = map.fd_or_err()?; let _fd = data.fd_or_err()?;
Ok(StackTraceMap { Ok(StackTraceMap {
inner: map, inner: map,
@ -106,7 +102,7 @@ impl<T: Deref<Target = Map>> StackTraceMap<T> {
/// Returns [`MapError::KeyNotFound`] if there is no stack trace with the /// Returns [`MapError::KeyNotFound`] if there is no stack trace with the
/// given `stack_id`, or [`MapError::SyscallError`] if `bpf_map_lookup_elem` fails. /// given `stack_id`, or [`MapError::SyscallError`] if `bpf_map_lookup_elem` fails.
pub fn get(&self, stack_id: &u32, flags: u64) -> Result<StackTrace, MapError> { pub fn get(&self, stack_id: &u32, flags: u64) -> Result<StackTrace, MapError> {
let fd = self.inner.fd_or_err()?; let fd = self.inner.as_ref().fd_or_err()?;
let mut frames = vec![0; self.max_stack_depth]; let mut frames = vec![0; self.max_stack_depth];
bpf_map_lookup_elem_ptr(fd, Some(stack_id), frames.as_mut_ptr(), flags) bpf_map_lookup_elem_ptr(fd, Some(stack_id), frames.as_mut_ptr(), flags)
@ -140,13 +136,13 @@ impl<T: Deref<Target = Map>> StackTraceMap<T> {
/// An iterator visiting all the stack_ids in arbitrary order. The iterator element /// An iterator visiting all the stack_ids in arbitrary order. The iterator element
/// type is `Result<u32, MapError>`. /// type is `Result<u32, MapError>`.
pub fn stack_ids(&self) -> MapKeys<'_, u32> { pub fn stack_ids(&self) -> MapKeys<'_, u32> {
MapKeys::new(&self.inner) MapKeys::new(self.inner.as_ref())
} }
} }
impl<T: Deref<Target = Map>> IterableMap<u32, StackTrace> for StackTraceMap<T> { impl<T: AsRef<MapData>> IterableMap<u32, StackTrace> for StackTraceMap<T> {
fn map(&self) -> &Map { fn map(&self) -> &MapData {
&self.inner self.inner.as_ref()
} }
fn get(&self, index: &u32) -> Result<StackTrace, MapError> { fn get(&self, index: &u32) -> Result<StackTrace, MapError> {
@ -154,23 +150,7 @@ impl<T: Deref<Target = Map>> IterableMap<u32, StackTrace> for StackTraceMap<T> {
} }
} }
impl TryFrom<MapRef> for StackTraceMap<MapRef> { impl<'a, T: AsRef<MapData>> IntoIterator for &'a StackTraceMap<T> {
type Error = MapError;
fn try_from(a: MapRef) -> Result<StackTraceMap<MapRef>, MapError> {
StackTraceMap::new(a)
}
}
impl TryFrom<MapRefMut> for StackTraceMap<MapRefMut> {
type Error = MapError;
fn try_from(a: MapRefMut) -> Result<StackTraceMap<MapRefMut>, MapError> {
StackTraceMap::new(a)
}
}
impl<'a, T: Deref<Target = Map>> IntoIterator for &'a StackTraceMap<T> {
type Item = Result<(u32, StackTrace), MapError>; type Item = Result<(u32, StackTrace), MapError>;
type IntoIter = MapIter<'a, u32, StackTrace, StackTraceMap<T>>; type IntoIter = MapIter<'a, u32, StackTrace, StackTraceMap<T>>;

@ -9,7 +9,7 @@ use crate::{
bpf_insn, BPF_CALL, BPF_JMP, BPF_K, BPF_PSEUDO_CALL, BPF_PSEUDO_FUNC, BPF_PSEUDO_MAP_FD, bpf_insn, BPF_CALL, BPF_JMP, BPF_K, BPF_PSEUDO_CALL, BPF_PSEUDO_FUNC, BPF_PSEUDO_MAP_FD,
BPF_PSEUDO_MAP_VALUE, BPF_PSEUDO_MAP_VALUE,
}, },
maps::Map, maps::MapData,
obj::{Function, Object, Program}, obj::{Function, Object, Program},
BpfError, BpfError,
}; };
@ -62,7 +62,7 @@ pub(crate) struct Symbol {
} }
impl Object { impl Object {
pub fn relocate_maps(&mut self, maps: &HashMap<String, Map>) -> Result<(), BpfError> { pub fn relocate_maps(&mut self, maps: &HashMap<String, MapData>) -> Result<(), BpfError> {
let maps_by_section = maps let maps_by_section = maps
.iter() .iter()
.map(|(name, map)| (map.obj.section_index(), (name.as_str(), map))) .map(|(name, map)| (map.obj.section_index(), (name.as_str(), map)))
@ -122,8 +122,8 @@ impl Object {
fn relocate_maps<'a, I: Iterator<Item = &'a Relocation>>( fn relocate_maps<'a, I: Iterator<Item = &'a Relocation>>(
fun: &mut Function, fun: &mut Function,
relocations: I, relocations: I,
maps_by_section: &HashMap<usize, (&str, &Map)>, maps_by_section: &HashMap<usize, (&str, &MapData)>,
maps_by_symbol: &HashMap<usize, (&str, &Map)>, maps_by_symbol: &HashMap<usize, (&str, &MapData)>,
symbol_table: &HashMap<usize, Symbol>, symbol_table: &HashMap<usize, Symbol>,
text_section_index: Option<usize>, text_section_index: Option<usize>,
) -> Result<(), RelocationError> { ) -> Result<(), RelocationError> {
@ -438,6 +438,7 @@ fn insn_is_call(ins: &bpf_insn) -> bool {
mod test { mod test {
use crate::{ use crate::{
bpf_map_def, bpf_map_def,
maps::MapData,
obj::{self, BtfMap, LegacyMap, MapKind}, obj::{self, BtfMap, LegacyMap, MapKind},
BtfMapDef, BtfMapDef,
}; };
@ -460,8 +461,8 @@ mod test {
unsafe { std::ptr::read_unaligned(bytes.as_ptr() as *const _) } unsafe { std::ptr::read_unaligned(bytes.as_ptr() as *const _) }
} }
fn fake_legacy_map(fd: i32, symbol_index: usize) -> Map { fn fake_legacy_map(fd: i32, symbol_index: usize) -> MapData {
Map { MapData {
obj: obj::Map::Legacy(LegacyMap { obj: obj::Map::Legacy(LegacyMap {
def: bpf_map_def { def: bpf_map_def {
..Default::default() ..Default::default()
@ -477,8 +478,8 @@ mod test {
} }
} }
fn fake_btf_map(fd: i32, symbol_index: usize) -> Map { fn fake_btf_map(fd: i32, symbol_index: usize) -> MapData {
Map { MapData {
obj: obj::Map::Btf(BtfMap { obj: obj::Map::Btf(BtfMap {
def: BtfMapDef { def: BtfMapDef {
..Default::default() ..Default::default()

@ -40,7 +40,7 @@ use crate::{
/// use aya::maps::SockHash; /// use aya::maps::SockHash;
/// use aya::programs::SkMsg; /// use aya::programs::SkMsg;
/// ///
/// let mut intercept_egress = SockHash::try_from(bpf.map_mut("INTERCEPT_EGRESS")?)?; /// let mut intercept_egress: SockHash<_, u32> = bpf.take_map("INTERCEPT_EGRESS")?.try_into()?;
/// let prog: &mut SkMsg = bpf.program_mut("intercept_egress_packet").unwrap().try_into()?; /// let prog: &mut SkMsg = bpf.program_mut("intercept_egress_packet").unwrap().try_into()?;
/// prog.load()?; /// prog.load()?;
/// prog.attach(&intercept_egress)?; /// prog.attach(&intercept_egress)?;

@ -38,7 +38,7 @@ pub enum SkSkbKind {
/// use aya::maps::SockMap; /// use aya::maps::SockMap;
/// use aya::programs::SkSkb; /// use aya::programs::SkSkb;
/// ///
/// let intercept_ingress = SockMap::try_from(bpf.map_mut("INTERCEPT_INGRESS")?)?; /// let intercept_ingress: SockMap<_> = bpf.take_map("INTERCEPT_INGRESS")?.try_into()?;
/// let prog: &mut SkSkb = bpf.program_mut("intercept_ingress_packet").unwrap().try_into()?; /// let prog: &mut SkSkb = bpf.program_mut("intercept_ingress_packet").unwrap().try_into()?;
/// prog.load()?; /// prog.load()?;
/// prog.attach(&intercept_ingress)?; /// prog.attach(&intercept_ingress)?;

@ -2,7 +2,7 @@ use std::{process::Command, thread, time};
use aya::{ use aya::{
include_bytes_aligned, include_bytes_aligned,
maps::{Array, MapRefMut}, maps::Array,
programs::{ programs::{
links::{FdLink, PinnedLink}, links::{FdLink, PinnedLink},
TracePoint, Xdp, XdpFlags, TracePoint, Xdp, XdpFlags,
@ -36,8 +36,8 @@ fn multiple_btf_maps() -> anyhow::Result<()> {
include_bytes_aligned!("../../../../target/bpfel-unknown-none/debug/multimap-btf.bpf.o"); include_bytes_aligned!("../../../../target/bpfel-unknown-none/debug/multimap-btf.bpf.o");
let mut bpf = Bpf::load(bytes)?; let mut bpf = Bpf::load(bytes)?;
let map_1: Array<MapRefMut, u64> = Array::try_from(bpf.map_mut("map_1")?)?; let map_1: Array<_, u64> = bpf.take_map("map_1")?.try_into()?;
let map_2: Array<MapRefMut, u64> = Array::try_from(bpf.map_mut("map_2")?)?; let map_2: Array<_, u64> = bpf.take_map("map_2")?.try_into()?;
let prog: &mut TracePoint = bpf.program_mut("tracepoint").unwrap().try_into().unwrap(); let prog: &mut TracePoint = bpf.program_mut("tracepoint").unwrap().try_into().unwrap();
prog.load().unwrap(); prog.load().unwrap();

Loading…
Cancel
Save