Merge pull request #397 from astoycos/refactor-map-api2

Refactor map API
pull/420/head
Alessandro Decina 2 years ago committed by GitHub
commit d6cb1a16ad
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -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").unwrap().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)?;

@ -34,4 +34,4 @@ async_std = ["async-io", "async"]
[package.metadata.docs.rs] [package.metadata.docs.rs]
all-features = true all-features = true
rustdoc-args = ["--cfg", "docsrs"] rustdoc-args = ["--cfg", "docsrs","-D", "warnings"]

@ -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, 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,43 @@ 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 = bpf_map_type::try_from(map.obj.map_type())?;
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 | BPF_MAP_TYPE_LRU_PERCPU_HASH => {
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 +684,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>,
} }
@ -714,22 +743,8 @@ impl Bpf {
/// ///
/// For more details and examples on maps and their usage, see the [maps module /// For more details and examples on maps and their usage, see the [maps module
/// documentation][crate::maps]. /// documentation][crate::maps].
/// pub fn map(&self, name: &str) -> Option<&Map> {
/// # Errors self.maps.get(name)
///
/// Returns [`MapError::MapNotFound`] if the map does not exist. If the map is already borrowed
/// mutably with [map_mut](Self::map_mut) then [`MapError::BorrowError`] is returned.
pub fn map(&self, name: &str) -> Result<MapRef, MapError> {
self.maps
.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.
@ -739,22 +754,24 @@ impl Bpf {
/// ///
/// For more details and examples on maps and their usage, see the [maps module /// For more details and examples on maps and their usage, see the [maps module
/// documentation][crate::maps]. /// documentation][crate::maps].
pub fn map_mut(&mut self, name: &str) -> Option<&mut Map> {
self.maps.get_mut(name)
}
/// Takes ownership of a map with the given name.
/// ///
/// # Errors /// Use this when borrowing with [`map`](crate::Bpf::map) or [`map_mut`](crate::Bpf::map_mut)
/// is not possible (eg when using the map from an async task). The returned
/// map will be closed on `Drop`, therefore the caller is responsible for
/// managing its lifetime.
/// ///
/// Returns [`MapError::MapNotFound`] if the map does not exist. If the map is already borrowed /// The returned type is mostly opaque. In order to do anything useful with it you need to
/// mutably with [map_mut](Self::map_mut) then [`MapError::BorrowError`] is returned. /// convert it to a [typed map](crate::maps).
pub fn map_mut(&self, name: &str) -> Result<MapRefMut, MapError> { ///
self.maps /// For more details and examples on maps and their usage, see the [maps module
.get(name) /// documentation][crate::maps].
.ok_or_else(|| MapError::MapNotFound { pub fn take_map(&mut self, name: &str) -> Option<Map> {
name: name.to_owned(), self.maps.remove(name)
})
.and_then(|lock| {
lock.try_write().map_err(|_| MapError::BorrowError {
name: name.to_owned(),
})
})
} }
/// An iterator over all the maps. /// An iterator over all the maps.
@ -764,22 +781,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, &Map)> {
let ret = self.maps.iter().map(|(name, lock)| { self.maps.iter().map(|(name, map)| (name.as_str(), 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,10 @@
use std::{ use std::{
convert::{AsMut, AsRef},
marker::PhantomData, marker::PhantomData,
mem,
ops::{Deref, DerefMut},
}; };
use crate::{ use crate::{
generated::bpf_map_type::BPF_MAP_TYPE_ARRAY, maps::{check_bounds, check_kv_size, 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 +20,26 @@ 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::try_from(bpf.map_mut("ARRAY").unwrap())?;
/// 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 { check_kv_size::<u32, V>(data)?;
return Err(MapError::InvalidMapType { map_type });
}
let expected = mem::size_of::<u32>();
let size = map.obj.key_size() as usize;
if size != expected {
return Err(MapError::InvalidKeySize { size, expected });
}
let expected = mem::size_of::<V>(); let _fd = data.fd_or_err()?;
let size = map.obj.value_size() as usize;
if size != expected {
return Err(MapError::InvalidValueSize { size, expected });
}
let _fd = map.fd_or_err()?;
Ok(Array { Ok(Array {
inner: map, inner: map,
@ -65,7 +51,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 +61,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()?; 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 +79,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 +89,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)?; 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 +102,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,6 @@ 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;

@ -1,12 +1,10 @@
use std::{ use std::{
convert::{AsMut, AsRef},
marker::PhantomData, marker::PhantomData,
mem,
ops::{Deref, DerefMut},
}; };
use crate::{ use crate::{
generated::bpf_map_type::BPF_MAP_TYPE_PERCPU_ARRAY, maps::{check_bounds, check_kv_size, 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 +29,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::try_from(bpf.map_mut("ARRAY").unwrap())?;
/// ///
/// // 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 +48,17 @@ 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 { check_kv_size::<u32, V>(data)?;
return Err(MapError::InvalidMapType { map_type });
}
let expected = mem::size_of::<u32>();
let size = map.obj.key_size() as usize;
if size != expected {
return Err(MapError::InvalidKeySize { size, expected });
}
let expected = mem::size_of::<V>(); let _fd = data.fd_or_err()?;
let size = map.obj.value_size() as usize;
if size != expected {
return Err(MapError::InvalidValueSize { size, expected });
}
let _fd = map.fd_or_err()?;
Ok(PerCpuArray { Ok(PerCpuArray {
inner: map, inner: map,
@ -84,7 +70,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 +80,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()?; 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 +98,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 +108,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)?; 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 +122,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,12 @@
//! 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::{
mem, convert::{AsMut, AsRef},
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::{check_bounds, check_kv_size, 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 +27,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::try_from(bpf.take_map("JUMP_TABLE").unwrap())?;
/// 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 +47,16 @@ 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 { check_kv_size::<u32, RawFd>(data)?;
return Err(MapError::InvalidMapType { map_type });
}
let expected = mem::size_of::<u32>();
let size = map.obj.key_size() as usize;
if size != expected {
return Err(MapError::InvalidKeySize { size, expected });
}
let expected = mem::size_of::<RawFd>(); let _fd = data.fd_or_err()?;
let size = map.obj.value_size() as usize;
if size != expected {
return Err(MapError::InvalidValueSize { size, expected });
}
let _fd = map.fd_or_err()?;
Ok(ProgramArray { inner: map }) Ok(ProgramArray { inner: map })
} }
@ -78,27 +64,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)?; 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 +93,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)?; 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 +105,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,8 @@
//! A Bloom Filter. //! A Bloom Filter.
use std::{marker::PhantomData, ops::Deref}; use std::{convert::AsRef, marker::PhantomData};
use core::mem;
use crate::{ use crate::{
generated::bpf_map_type::BPF_MAP_TYPE_BLOOM_FILTER, maps::{check_v_size, 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 +16,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::try_from(bpf.map_mut("BLOOM_FILTER").unwrap())?;
/// ///
/// bloom_filter.insert(1, 0)?; /// bloom_filter.insert(1, 0)?;
/// ///
@ -33,27 +30,17 @@ 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();
check_v_size::<V>(data)?;
// 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 expected = map.obj.value_size() as usize;
if 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 +50,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 +63,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 +72,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 +81,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 +110,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 +127,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,6 +146,8 @@ 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::InvalidMapType { .. })
@ -198,7 +156,7 @@ mod tests {
#[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 +171,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 +183,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 +198,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 +222,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 +236,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 +259,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::{check_kv_size, 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::try_from(bpf.map_mut("REDIRECT_PORTS").unwrap())?;
/// ///
/// // 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();
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 {
map_type: BPF_MAP_TYPE_PERF_EVENT_ARRAY as u32,
key_size: 4,
value_size: 4,
max_entries: 1024,
..Default::default()
},
section_index: 0,
symbol_index: 0,
data: Vec::new(),
kind: obj::MapKind::Other,
}),
fd: None, fd: None,
pinned: false, pinned: false,
btf_fd: None, btf_fd: None,
}; };
let map = Map::Array(map_data);
assert!(matches!( assert!(matches!(
HashMap::<_, u32, u32>::try_from(&map), HashMap::<_, u8, u32>::try_from(&map),
Err(MapError::InvalidMapType { .. }) Err(MapError::InvalidMapType { .. })
)); ));
} }
#[test]
fn test_try_from_wrong_map_values() {
let map_data = MapData {
obj: new_obj_map(),
fd: None,
pinned: false,
btf_fd: None,
};
let map = Map::HashMap(map_data);
assert!(matches!(
HashMap::<_, u32, u16>::try_from(&map),
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,

@ -1,8 +1,6 @@
//! Hash map types. //! Hash map types.
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,21 +11,14 @@ 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;
let size = mem::size_of::<K>();
let expected = map.obj.key_size() as usize;
if size != expected {
return Err(MapError::InvalidKeySize { size, expected });
}
let size = mem::size_of::<V>();
let expected = map.obj.value_size() as usize;
if size != expected {
return Err(MapError::InvalidValueSize { size, expected });
};
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 +30,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,13 +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},
maps::{ maps::{
hash_map, IterableMap, Map, MapError, MapIter, MapKeys, MapRef, MapRefMut, PerCpuValues, check_kv_size, hash_map, IterableMap, MapData, MapError, MapIter, MapKeys, 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,
@ -26,13 +25,13 @@ use crate::{
/// # Examples /// # Examples
/// ///
/// ```no_run /// ```no_run
/// # let bpf = aya::Bpf::load(&[])?; /// # let mut bpf = aya::Bpf::load(&[])?;
/// use aya::maps::PerCpuHashMap; /// use aya::maps::PerCpuHashMap;
/// ///
/// const CPU_IDS: u8 = 1; /// const CPU_IDS: u8 = 1;
/// const WAKEUPS: u8 = 2; /// const WAKEUPS: u8 = 2;
/// ///
/// let mut hm = PerCpuHashMap::<_, u8, u32>::try_from(bpf.map("COUNTERS")?)?; /// let mut hm = PerCpuHashMap::<_, u8, u32>::try_from(bpf.map_mut("PER_CPU_STORAGE").unwrap())?;
/// let cpu_ids = unsafe { hm.get(&CPU_IDS, 0)? }; /// let cpu_ids = unsafe { hm.get(&CPU_IDS, 0)? };
/// let wakeups = unsafe { hm.get(&WAKEUPS, 0)? }; /// let wakeups = unsafe { hm.get(&WAKEUPS, 0)? };
/// for (cpu_id, wakeups) in cpu_ids.iter().zip(wakeups.iter()) { /// for (cpu_id, wakeups) in cpu_ids.iter().zip(wakeups.iter()) {
@ -42,24 +41,18 @@ 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();
check_kv_size::<K, V>(data)?;
// validate the map definition let _ = data.fd_or_err()?;
if map_type != BPF_MAP_TYPE_PERCPU_HASH as u32
&& map_type != BPF_MAP_TYPE_LRU_PERCPU_HASH as u32
{
return Err(MapError::InvalidMapType { map_type });
}
hash_map::check_kv_size::<K, V>(&map)?;
let _ = map.fd_or_err()?;
Ok(PerCpuHashMap { Ok(PerCpuHashMap {
inner: map, inner: map,
@ -70,7 +63,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 +82,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 +101,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>::try_from(bpf.map_mut("PER_CPU_STORAGE").unwrap())?;
/// hm.insert( /// hm.insert(
/// RETRIES, /// RETRIES,
/// PerCpuValues::try_from(vec![3u32; nr_cpus()?])?, /// PerCpuValues::try_from(vec![3u32; nr_cpus()?])?,
@ -123,7 +116,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 +129,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::{check_kv_size, 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::try_from(bpf.map_mut("LPM_TRIE").unwrap())?;
/// 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,12 @@ 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();
check_kv_size::<Key<K>, V>(data)?;
// 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 expected = map.obj.key_size() as usize;
if size != expected {
return Err(MapError::InvalidKeySize { size, expected });
}
let size = mem::size_of::<V>();
let expected = map.obj.value_size() as usize;
if 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 +115,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 +124,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 +143,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 +154,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 +165,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 +174,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 +203,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 +220,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 +237,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,6 +256,8 @@ 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::InvalidMapType { .. })
@ -304,7 +266,7 @@ mod tests {
#[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 +281,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 +293,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 +308,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 +333,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 +350,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 +375,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 +390,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 +415,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,25 +4,30 @@
//! 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), or [`Bpf::take_map`](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::take_map`](crate::Bpf::take_map) always return the
//! *typed maps* using the [`TryFrom`](std::convert::TryFrom) trait. For example: //! opaque [`&Map`](crate::maps::Map), [`&mut Map`](crate::maps::Map), and [`Map`](crate::maps::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::try_from(bpf.map_mut("INTERCEPT_EGRESS").unwrap())?;
//! let map_fd = intercept_egress.fd()?;
//! 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(map_fd)?;
//!
//! # Ok::<(), aya::BpfError>(()) //! # Ok::<(), aya::BpfError>(())
//! ``` //! ```
//! //!
@ -32,6 +37,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 +64,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 +75,12 @@ 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(feature = "async")]
#[cfg_attr(docsrs, doc(cfg(feature = "async")))]
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};
@ -82,13 +90,6 @@ pub use stack_trace::StackTraceMap;
#[derive(Error, Debug)] #[derive(Error, Debug)]
/// Errors occuring from working with Maps /// Errors occuring from working with Maps
pub enum MapError { pub enum MapError {
/// Unable to find the map
#[error("map `{name}` not found ")]
MapNotFound {
/// Map name
name: String,
},
/// Invalid map type encontered /// Invalid map type encontered
#[error("invalid map type {map_type}")] #[error("invalid map type {map_type}")]
InvalidMapType { InvalidMapType {
@ -174,20 +175,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 {
@ -243,11 +230,234 @@ 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 [`StackTraceMap`] map
StackTraceMap(MapData),
/// A [`Queue`] map
Queue(MapData),
}
impl Map {
/// Returns the low level map type.
fn map_type(&self) -> u32 {
match self {
Map::Array(map) => map.obj.map_type(),
Map::PerCpuArray(map) => map.obj.map_type(),
Map::ProgramArray(map) => map.obj.map_type(),
Map::HashMap(map) => map.obj.map_type(),
Map::PerCpuHashMap(map) => map.obj.map_type(),
Map::PerfEventArray(map) => map.obj.map_type(),
Map::SockHash(map) => map.obj.map_type(),
Map::SockMap(map) => map.obj.map_type(),
Map::BloomFilter(map) => map.obj.map_type(),
Map::LpmTrie(map) => map.obj.map_type(),
Map::Stack(map) => map.obj.map_type(),
Map::StackTraceMap(map) => map.obj.map_type(),
Map::Queue(map) => map.obj.map_type(),
}
}
}
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::new(m)
},
_ => Err(MapError::InvalidMapType{ map_type: map.map_type()}),
}
}
}
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::new(m)
},
_ => Err(MapError::InvalidMapType{ map_type: map.map_type()}),
}
}
}
impl TryFrom<Map> for $tx<MapData> {
type Error = MapError;
fn try_from(map: Map) -> Result<$tx<MapData>, MapError> {
match map {
Map::$ty(m) => {
$tx::new(m)
},
_ => Err(MapError::InvalidMapType{ map_type: map.map_type()}),
}
}
}
)+
}
}
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::new(m)
},
_ => Err(MapError::InvalidMapType{ map_type: map.map_type()}),
}
}
}
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::new(m)
},
_ => Err(MapError::InvalidMapType{ map_type: map.map_type()}),
}
}
}
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::new(m)
},
_ => Err(MapError::InvalidMapType{ map_type: map.map_type()}),
}
}
}
)+
}
}
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::new(m)
},
_ => Err(MapError::InvalidMapType{ map_type: map.map_type()}),
}
}
}
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::new(m)
},
_ => Err(MapError::InvalidMapType{ map_type: map.map_type()}),
}
}
}
)+
}
}
impl_try_from_map_generic_key_and_value!(HashMap, PerCpuHashMap, LpmTrie);
pub(crate) fn check_bounds(map: &MapData, index: u32) -> Result<(), MapError> {
let max_entries = map.obj.max_entries();
if index >= max_entries {
Err(MapError::OutOfBounds { index, max_entries })
} else {
Ok(())
}
}
pub(crate) fn check_kv_size<K, V>(map: &MapData) -> Result<(), MapError> {
let size = mem::size_of::<K>();
let expected = map.obj.key_size() as usize;
if size != expected {
return Err(MapError::InvalidKeySize { size, expected });
}
let size = mem::size_of::<V>();
let expected = map.obj.value_size() as usize;
if size != expected {
return Err(MapError::InvalidValueSize { size, expected });
};
Ok(())
}
pub(crate) fn check_v_size<V>(map: &MapData) -> Result<(), MapError> {
let size = mem::size_of::<V>();
let expected = map.obj.value_size() as usize;
if size != expected {
return Err(MapError::InvalidValueSize { size, expected });
};
Ok(())
}
/// 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)]
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 +465,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 +525,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 +546,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,
@ -334,16 +556,16 @@ impl Map {
/// Loads a map from a [`RawFd`]. /// Loads a map from a [`RawFd`].
/// ///
/// 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`](crate::maps::MapData::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,
@ -351,11 +573,6 @@ impl Map {
}) })
} }
/// Returns the [`bpf_map_type`] of this map
pub fn map_type(&self) -> Result<bpf_map_type, MapError> {
bpf_map_type::try_from(self.obj.map_type())
}
pub(crate) fn fd_or_err(&self) -> Result<RawFd, MapError> { pub(crate) fn fd_or_err(&self) -> Result<RawFd, MapError> {
self.fd.ok_or(MapError::NotCreated) self.fd.ok_or(MapError::NotCreated)
} }
@ -389,7 +606,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() {
@ -398,10 +615,26 @@ impl Drop for Map {
} }
} }
impl Clone for MapData {
fn clone(&self) -> MapData {
MapData {
obj: self.obj.clone(),
fd: {
if let Some(fd) = self.fd {
unsafe { Some(libc::dup(fd)) };
}
None
},
btf_fd: self.btf_fd,
pinned: self.pinned,
}
}
}
/// 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 +642,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,
@ -538,6 +771,7 @@ impl TryFrom<u32> for bpf_map_type {
}) })
} }
} }
pub(crate) struct PerCpuKernelMem { pub(crate) struct PerCpuKernelMem {
bytes: Vec<u8>, bytes: Vec<u8>,
} }
@ -643,6 +877,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 +900,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::try_from(bpf.take_map("PERF_ARRAY").unwrap())?;
/// ///
/// 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)
}
}

@ -1,6 +1,6 @@
//! Ring buffer types used to receive events from eBPF programs using the linux `perf` API. //! Ring buffer types used to receive events from eBPF programs using the linux `perf` API.
//! //!
//! See the [`PerfEventArray`] and [`AsyncPerfEventArray`]. //! See the [`PerfEventArray`](crate::maps::PerfEventArray) and [`AsyncPerfEventArray`](crate::maps::perf::AsyncPerfEventArray).
#[cfg(any(feature = "async"))] #[cfg(any(feature = "async"))]
#[cfg_attr(docsrs, doc(cfg(feature = "async")))] #[cfg_attr(docsrs, doc(cfg(feature = "async")))]
mod async_perf_event_array; mod async_perf_event_array;

@ -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::try_from(bpf.map_mut("EVENTS").unwrap())?;
/// ///
/// // 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,11 @@
//! A FIFO queue. //! A FIFO queue.
use std::{ use std::{
convert::{AsMut, AsRef},
marker::PhantomData, marker::PhantomData,
mem,
ops::{Deref, DerefMut},
}; };
use crate::{ use crate::{
generated::bpf_map_type::BPF_MAP_TYPE_QUEUE, maps::{check_kv_size, 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 +18,27 @@ 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::try_from(bpf.map_mut("ARRAY").unwrap())?;
/// 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 { check_kv_size::<(), V>(data)?;
return Err(MapError::InvalidMapType { map_type });
}
let expected = 0;
let size = map.obj.key_size() as usize;
if size != expected {
return Err(MapError::InvalidKeySize { size, expected });
}
let expected = mem::size_of::<V>(); let _fd = data.fd_or_err()?;
let size = map.obj.value_size() as usize;
if size != expected {
return Err(MapError::InvalidValueSize { size, expected });
}
let _fd = map.fd_or_err()?;
Ok(Queue { Ok(Queue {
inner: map, inner: map,
@ -64,11 +50,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 +62,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 +79,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 +87,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)
}
}

@ -2,15 +2,17 @@
mod sock_hash; mod sock_hash;
mod sock_map; mod sock_map;
use std::os::unix::io::RawFd;
use crate::maps::MapError;
pub use sock_hash::SockHash; pub use sock_hash::SockHash;
pub use sock_map::SockMap; pub use sock_map::SockMap;
/// Shared behaviour between [`SockHash`] and [`SockMap`] use std::os::unix::io::{AsRawFd, RawFd};
pub trait SocketMap {
/// Returns a [`Result`] containg the map fd or an error if there is none /// A socket map file descriptor.
fn fd_or_err(&self) -> Result<RawFd, MapError>; #[derive(Copy, Clone)]
pub struct SockMapFd(RawFd);
impl AsRawFd for SockMapFd {
fn as_raw_fd(&self) -> RawFd {
self.0
}
} }

@ -1,13 +1,12 @@
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::{ maps::{
hash_map, sock::SocketMap, IterableMap, Map, MapError, MapIter, MapKeys, MapRef, MapRefMut, check_kv_size, hash_map, sock::SockMapFd, IterableMap, MapData, MapError, MapIter, MapKeys,
}, },
sys::bpf_map_lookup_elem, sys::bpf_map_lookup_elem,
Pod, Pod,
@ -47,12 +46,16 @@ 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>::try_from(bpf.map("INTERCEPT_EGRESS").unwrap())?;
/// let map_fd = intercept_egress.fd()?;
///
/// 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(map_fd)?;
/// ///
/// let mut client = TcpStream::connect("127.0.0.1:1234")?; /// let mut client = TcpStream::connect("127.0.0.1:1234")?;
/// let mut intercept_egress = SockHash::try_from(bpf.map_mut("INTERCEPT_EGRESS").unwrap())?;
///
/// intercept_egress.insert(1234, client.as_raw_fd(), 0)?; /// intercept_egress.insert(1234, client.as_raw_fd(), 0)?;
/// ///
/// // the write will be intercepted /// // the write will be intercepted
@ -60,21 +63,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();
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 +82,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,50 +101,36 @@ 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())
}
/// Returns the map's file descriptor.
///
/// The returned file descriptor can be used to attach programs that work with
/// socket maps, like [`SkMsg`](crate::programs::SkMsg) and [`SkSkb`](crate::programs::SkSkb).
pub fn fd(&self) -> Result<SockMapFd, MapError> {
Ok(SockMapFd(self.inner.as_ref().fd_or_err()?))
} }
} }
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> {
SockHash::get(self, key, 0) SockHash::get(self, key, 0)
} }
} }
impl<T: DerefMut<Target = Map>, K: Pod> SocketMap for SockHash<T, K> {
fn fd_or_err(&self) -> Result<RawFd, MapError> {
self.inner.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,12 @@
//! 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::{
mem, convert::{AsMut, AsRef},
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::{check_bounds, check_kv_size, sock::SockMapFd, 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 +30,26 @@ 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::try_from(bpf.map("INTERCEPT_INGRESS").unwrap())?;
/// let map_fd = intercept_ingress.fd()?;
///
/// 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(map_fd)?;
///
/// # 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> {
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 { check_kv_size::<u32, RawFd>(data)?;
return Err(MapError::InvalidMapType { map_type });
}
let expected = mem::size_of::<u32>();
let size = map.obj.key_size() as usize;
if size != expected {
return Err(MapError::InvalidKeySize { size, expected });
}
let expected = mem::size_of::<RawFd>(); let _fd = data.fd_or_err()?;
let size = map.obj.value_size() as usize;
if size != expected {
return Err(MapError::InvalidValueSize { size, expected });
}
let _fd = map.fd_or_err()?;
Ok(SockMap { inner: map }) Ok(SockMap { inner: map })
} }
@ -68,24 +57,24 @@ 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> { /// Returns the map's file descriptor.
let max_entries = self.inner.obj.max_entries(); ///
if index >= self.inner.obj.max_entries() { /// The returned file descriptor can be used to attach programs that work with
Err(MapError::OutOfBounds { index, max_entries }) /// socket maps, like [`SkMsg`](crate::programs::SkMsg) and [`SkSkb`](crate::programs::SkSkb).
} else { pub fn fd(&self) -> Result<SockMapFd, MapError> {
Ok(()) Ok(SockMapFd(self.inner.as_ref().fd_or_err()?))
}
} }
} }
impl<T: Deref<Target = Map> + DerefMut<Target = Map>> SockMap<T> { impl<T: 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 data = self.inner.as_mut();
self.check_bounds(index)?; let fd = data.fd_or_err()?;
check_bounds(data, 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 {
call: "bpf_map_update_elem".to_owned(), call: "bpf_map_update_elem".to_owned(),
@ -97,8 +86,9 @@ 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 data = self.inner.as_mut();
self.check_bounds(*index)?; let fd = data.fd_or_err()?;
check_bounds(data, *index)?;
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 {
@ -107,25 +97,3 @@ impl<T: Deref<Target = Map> + DerefMut<Target = Map>> SockMap<T> {
}) })
} }
} }
impl<T: Deref<Target = Map> + DerefMut<Target = Map>> SocketMap for SockMap<T> {
fn fd_or_err(&self) -> Result<RawFd, MapError> {
self.inner.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,11 @@
//! A LIFO stack. //! A LIFO stack.
use std::{ use std::{
convert::{AsMut, AsRef},
marker::PhantomData, marker::PhantomData,
mem,
ops::{Deref, DerefMut},
}; };
use crate::{ use crate::{
generated::bpf_map_type::BPF_MAP_TYPE_STACK, maps::{check_kv_size, 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 +18,27 @@ 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::try_from(bpf.map_mut("STACK").unwrap())?;
/// 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 { check_kv_size::<(), V>(data)?;
return Err(MapError::InvalidMapType { map_type });
}
let expected = 0;
let size = map.obj.key_size() as usize;
if size != expected {
return Err(MapError::InvalidKeySize { size, expected });
}
let expected = mem::size_of::<V>(); let _fd = data.fd_or_err()?;
let size = map.obj.value_size() as usize;
if size != expected {
return Err(MapError::InvalidValueSize { size, expected });
}
let _fd = map.fd_or_err()?;
Ok(Stack { Ok(Stack {
inner: map, inner: map,
@ -64,11 +50,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 +62,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 +79,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 +89,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,
}; };
@ -36,7 +35,7 @@ use crate::{
/// use aya::maps::StackTraceMap; /// use aya::maps::StackTraceMap;
/// use aya::util::kernel_symbols; /// use aya::util::kernel_symbols;
/// ///
/// let mut stack_traces = StackTraceMap::try_from(bpf.map("STACK_TRACES")?)?; /// let mut stack_traces = StackTraceMap::try_from(bpf.map("STACK_TRACES").unwrap())?;
/// // load kernel symbols from /proc/kallsyms /// // load kernel symbols from /proc/kallsyms
/// let ksyms = kernel_symbols()?; /// let ksyms = kernel_symbols()?;
/// ///
@ -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()

@ -1,7 +1,10 @@
//! Skmsg programs. //! Skmsg programs.
use std::os::unix::io::AsRawFd;
use crate::{ use crate::{
generated::{bpf_attach_type::BPF_SK_MSG_VERDICT, bpf_prog_type::BPF_PROG_TYPE_SK_MSG}, generated::{bpf_attach_type::BPF_SK_MSG_VERDICT, bpf_prog_type::BPF_PROG_TYPE_SK_MSG},
maps::sock::SocketMap, maps::sock::SockMapFd,
programs::{ programs::{
define_link_wrapper, load_program, ProgAttachLink, ProgAttachLinkId, ProgramData, define_link_wrapper, load_program, ProgAttachLink, ProgAttachLinkId, ProgramData,
ProgramError, ProgramError,
@ -40,12 +43,16 @@ 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 intercept_egress: SockHash<_, u32> = bpf.map("INTERCEPT_EGRESS").unwrap().try_into()?;
/// let map_fd = intercept_egress.fd()?;
///
/// 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(map_fd)?;
/// ///
/// let mut client = TcpStream::connect("127.0.0.1:1234")?; /// let mut client = TcpStream::connect("127.0.0.1:1234")?;
/// let mut intercept_egress: SockHash<_, u32> = bpf.map_mut("INTERCEPT_EGRESS").unwrap().try_into()?;
///
/// intercept_egress.insert(1234, client.as_raw_fd(), 0)?; /// intercept_egress.insert(1234, client.as_raw_fd(), 0)?;
/// ///
/// // the write will be intercepted /// // the write will be intercepted
@ -71,9 +78,9 @@ impl SkMsg {
/// Attaches the program to the given sockmap. /// Attaches the program to the given sockmap.
/// ///
/// The returned value can be used to detach, see [SkMsg::detach]. /// The returned value can be used to detach, see [SkMsg::detach].
pub fn attach(&mut self, map: &dyn SocketMap) -> Result<SkMsgLinkId, ProgramError> { pub fn attach(&mut self, map: SockMapFd) -> Result<SkMsgLinkId, ProgramError> {
let prog_fd = self.data.fd_or_err()?; let prog_fd = self.data.fd_or_err()?;
let map_fd = map.fd_or_err()?; let map_fd = map.as_raw_fd();
bpf_prog_attach(prog_fd, map_fd, BPF_SK_MSG_VERDICT).map_err(|(_, io_error)| { bpf_prog_attach(prog_fd, map_fd, BPF_SK_MSG_VERDICT).map_err(|(_, io_error)| {
ProgramError::SyscallError { ProgramError::SyscallError {

@ -1,10 +1,13 @@
//! Skskb programs. //! Skskb programs.
use std::os::unix::io::AsRawFd;
use crate::{ use crate::{
generated::{ generated::{
bpf_attach_type::{BPF_SK_SKB_STREAM_PARSER, BPF_SK_SKB_STREAM_VERDICT}, bpf_attach_type::{BPF_SK_SKB_STREAM_PARSER, BPF_SK_SKB_STREAM_VERDICT},
bpf_prog_type::BPF_PROG_TYPE_SK_SKB, bpf_prog_type::BPF_PROG_TYPE_SK_SKB,
}, },
maps::sock::SocketMap, maps::sock::SockMapFd,
programs::{ programs::{
define_link_wrapper, load_program, ProgAttachLink, ProgAttachLinkId, ProgramData, define_link_wrapper, load_program, ProgAttachLink, ProgAttachLinkId, ProgramData,
ProgramError, ProgramError,
@ -38,10 +41,13 @@ 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.map("INTERCEPT_INGRESS").unwrap().try_into()?;
/// let map_fd = intercept_ingress.fd()?;
///
/// 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(map_fd)?;
///
/// # Ok::<(), aya::BpfError>(()) /// # Ok::<(), aya::BpfError>(())
/// ``` /// ```
/// ///
@ -64,9 +70,9 @@ impl SkSkb {
/// Attaches the program to the given socket map. /// Attaches the program to the given socket map.
/// ///
/// The returned value can be used to detach, see [SkSkb::detach]. /// The returned value can be used to detach, see [SkSkb::detach].
pub fn attach(&mut self, map: &dyn SocketMap) -> Result<SkSkbLinkId, ProgramError> { pub fn attach(&mut self, map: SockMapFd) -> Result<SkSkbLinkId, ProgramError> {
let prog_fd = self.data.fd_or_err()?; let prog_fd = self.data.fd_or_err()?;
let map_fd = map.fd_or_err()?; let map_fd = map.as_raw_fd();
let attach_type = match self.kind { let attach_type = match self.kind {
SkSkbKind::StreamParser => BPF_SK_SKB_STREAM_PARSER, SkSkbKind::StreamParser => BPF_SK_SKB_STREAM_PARSER,

@ -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").unwrap().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").unwrap().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();

@ -68,7 +68,7 @@ fn build_docs(working_dir: &PathBuf, abs_header_path: &Path) -> Result<(), anyho
.env( .env(
"RUSTDOCFLAGS", "RUSTDOCFLAGS",
format!( format!(
"--cfg docsrs --html-in-header {}", "--cfg docsrs --html-in-header {} -D warnings",
abs_header_path.to_str().unwrap() abs_header_path.to_str().unwrap()
), ),
) )

Loading…
Cancel
Save