From 1aefa2e5e6d22a600cc7339d289d64ab06f842e3 Mon Sep 17 00:00:00 2001 From: Andrew Stoycos Date: Wed, 28 Sep 2022 17:51:56 -0400 Subject: [PATCH] Core refactor of Map API Build completing tests passing Refactor the Map API to better align with the aya programs API. Specifically remove all internal locking mechanisms and custom Deref/DerefMut implementations. They are replaced with a Map enum and AsRef/AsMut implementations. All Try_From implementations have been moved to standardized enums, with a slightly special one for PerfEventArray's. Also cleanup/fix all associated tests and documentation. Signed-off-by: Andrew Stoycos --- aya-log/src/lib.rs | 2 +- aya/src/bpf.rs | 110 +++++---- aya/src/maps/array/array.rs | 71 ++---- aya/src/maps/array/mod.rs | 13 +- aya/src/maps/array/per_cpu_array.rs | 72 ++---- aya/src/maps/array/program_array.rs | 64 ++--- aya/src/maps/bloom_filter.rs | 86 ++----- aya/src/maps/hash_map/hash_map.rs | 158 ++++++------- aya/src/maps/hash_map/mod.rs | 15 +- aya/src/maps/hash_map/per_cpu_hash_map.rs | 71 ++---- aya/src/maps/lpm_trie.rs | 119 ++++------ aya/src/maps/map_lock.rs | 81 ------- aya/src/maps/mod.rs | 250 +++++++++++++++++--- aya/src/maps/perf/async_perf_event_array.rs | 30 +-- aya/src/maps/perf/perf_event_array.rs | 47 ++-- aya/src/maps/queue.rs | 50 ++-- aya/src/maps/sock/sock_hash.rs | 60 ++--- aya/src/maps/sock/sock_map.rs | 56 ++--- aya/src/maps/stack.rs | 50 ++-- aya/src/maps/stack_trace.rs | 48 ++-- aya/src/obj/relocation.rs | 17 +- aya/src/programs/sk_msg.rs | 2 +- aya/src/programs/sk_skb.rs | 2 +- test/integration-test/src/tests/load.rs | 6 +- 24 files changed, 650 insertions(+), 830 deletions(-) delete mode 100644 aya/src/maps/map_lock.rs diff --git a/aya-log/src/lib.rs b/aya-log/src/lib.rs index b56c16e6d..bbff0f617 100644 --- a/aya-log/src/lib.rs +++ b/aya-log/src/lib.rs @@ -90,7 +90,7 @@ impl BpfLogger { logger: T, ) -> Result { let logger = Arc::new(logger); - let mut logs: AsyncPerfEventArray<_> = bpf.map_mut("AYA_LOGS")?.try_into()?; + let mut logs: AsyncPerfEventArray<_> = bpf.take_map("AYA_LOGS")?.try_into()?; for cpu_id in online_cpus().map_err(Error::InvalidOnlineCpu)? { let mut buf = logs.open(cpu_id, None)?; diff --git a/aya/src/bpf.rs b/aya/src/bpf.rs index db1ad3be7..e473802f3 100644 --- a/aya/src/bpf.rs +++ b/aya/src/bpf.rs @@ -13,10 +13,10 @@ use thiserror::Error; use crate::{ generated::{ - bpf_map_type::BPF_MAP_TYPE_PERF_EVENT_ARRAY, AYA_PERF_EVENT_IOC_DISABLE, - AYA_PERF_EVENT_IOC_ENABLE, AYA_PERF_EVENT_IOC_SET_BPF, + bpf_map_type::*, AYA_PERF_EVENT_IOC_DISABLE, AYA_PERF_EVENT_IOC_ENABLE, + AYA_PERF_EVENT_IOC_SET_BPF, }, - maps::{Map, MapError, MapLock, MapRef, MapRefMut}, + maps::{Map, MapData, MapError}, obj::{ btf::{Btf, BtfError}, MapKind, Object, ParseError, ProgramSection, @@ -451,7 +451,7 @@ impl<'a> BpfLoader<'a> { } } } - let mut map = Map { + let mut map = MapData { obj, fd: None, pinned: false, @@ -638,14 +638,41 @@ impl<'a> BpfLoader<'a> { (name, program) }) .collect(); - let maps = maps - .drain() - .map(|(name, map)| (name, MapLock::new(map))) - .collect(); - Ok(Bpf { maps, programs }) + let maps: Result, BpfError> = maps.drain().map(parse_map).collect(); + + Ok(Bpf { + maps: maps?, + programs, + }) } } +fn parse_map(data: (String, MapData)) -> Result<(String, Map), BpfError> { + let name = data.0; + let map = data.1; + let map_type = map.map_type().map_err(BpfError::MapError)?; + let map = match map_type { + BPF_MAP_TYPE_ARRAY => Ok(Map::Array(map)), + BPF_MAP_TYPE_PERCPU_ARRAY => Ok(Map::PerCpuArray(map)), + BPF_MAP_TYPE_PROG_ARRAY => Ok(Map::ProgramArray(map)), + BPF_MAP_TYPE_HASH => Ok(Map::HashMap(map)), + BPF_MAP_TYPE_PERCPU_HASH => Ok(Map::PerCpuHashMap(map)), + BPF_MAP_TYPE_PERF_EVENT_ARRAY => Ok(Map::PerfEventArray(map)), + BPF_MAP_TYPE_SOCKHASH => Ok(Map::SockHash(map)), + BPF_MAP_TYPE_SOCKMAP => Ok(Map::SockMap(map)), + BPF_MAP_TYPE_BLOOM_FILTER => Ok(Map::BloomFilter(map)), + BPF_MAP_TYPE_LPM_TRIE => Ok(Map::LpmTrie(map)), + BPF_MAP_TYPE_STACK => Ok(Map::Stack(map)), + BPF_MAP_TYPE_STACK_TRACE => Ok(Map::StackTraceMap(map)), + BPF_MAP_TYPE_QUEUE => Ok(Map::Queue(map)), + m => Err(BpfError::MapError(MapError::InvalidMapType { + map_type: m as u32, + })), + }?; + + Ok((name, map)) +} + impl<'a> Default for BpfLoader<'a> { fn default() -> Self { BpfLoader::new() @@ -655,7 +682,7 @@ impl<'a> Default for BpfLoader<'a> { /// The main entry point into the library, used to work with eBPF programs and maps. #[derive(Debug)] pub struct Bpf { - maps: HashMap, + maps: HashMap, programs: HashMap, } @@ -717,19 +744,11 @@ impl Bpf { /// /// # Errors /// - /// 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 { - 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 [`MapError::MapNotFound`] if the map does not exist. + pub fn map(&self, name: &str) -> Result<&Map, MapError> { + self.maps.get(name).ok_or_else(|| MapError::MapNotFound { + name: name.to_owned(), + }) } /// Returns a mutable reference to the map with the given name. @@ -742,19 +761,32 @@ impl Bpf { /// /// # Errors /// - /// 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_mut(&self, name: &str) -> Result { + /// Returns [`MapError::MapNotFound`] if the map does not exist. + pub fn map_mut(&mut self, name: &str) -> Result<&mut Map, MapError> { self.maps - .get(name) + .get_mut(name) .ok_or_else(|| MapError::MapNotFound { name: name.to_owned(), }) - .and_then(|lock| { - lock.try_write().map_err(|_| MapError::BorrowError { - name: name.to_owned(), - }) - }) + } + + /// Returns a map with the given name. + /// + /// WARNING: This transfers ownership of the map to the user. + /// + /// The returned type is mostly opaque. In order to do anything useful with it you need to + /// convert it to a [typed map](crate::maps). + /// + /// For more details and examples on maps and their usage, see the [maps module + /// documentation][crate::maps]. + /// + /// # Errors + /// + /// Returns [`MapError::MapNotFound`] if the map does not exist. + pub fn take_map(&mut self, name: &str) -> Result { + self.maps.remove(name).ok_or_else(|| MapError::MapNotFound { + name: name.to_owned(), + }) } /// An iterator over all the maps. @@ -764,22 +796,14 @@ impl Bpf { /// # let mut bpf = aya::Bpf::load(&[])?; /// for (name, map) in bpf.maps() { /// println!( - /// "found map `{}` of type `{:?}`", + /// "found map `{}`", /// name, - /// map?.map_type().unwrap() /// ); /// } /// # Ok::<(), aya::BpfError>(()) /// ``` - pub fn maps(&self) -> impl Iterator)> { - let ret = self.maps.iter().map(|(name, lock)| { - ( - name.as_str(), - lock.try_read() - .map_err(|_| MapError::BorrowError { name: name.clone() }), - ) - }); - ret + pub fn maps(&self) -> impl Iterator)> { + self.maps.iter().map(|(name, map)| (name.as_str(), Ok(map))) } /// Returns a reference to the program with the given name. diff --git a/aya/src/maps/array/array.rs b/aya/src/maps/array/array.rs index ac5c65871..8b60b8a52 100644 --- a/aya/src/maps/array/array.rs +++ b/aya/src/maps/array/array.rs @@ -1,12 +1,11 @@ use std::{ + convert::{AsMut, AsRef}, marker::PhantomData, mem, - ops::{Deref, DerefMut}, }; use crate::{ - generated::bpf_map_type::BPF_MAP_TYPE_ARRAY, - maps::{IterableMap, Map, MapError, MapRef, MapRefMut}, + maps::{array, IterableMap, MapData, MapError}, sys::{bpf_map_lookup_elem, bpf_map_update_elem}, Pod, }; @@ -22,38 +21,35 @@ use crate::{ /// /// # Examples /// ```no_run -/// # let bpf = aya::Bpf::load(&[])?; +/// # let mut bpf = aya::Bpf::load(&[])?; /// use aya::maps::Array; /// -/// let mut array = Array::try_from(bpf.map_mut("ARRAY")?)?; +/// let mut array: Array<_, u32> = bpf.map_mut("ARRAY")?.try_into()?; /// array.set(1, 42, 0)?; /// assert_eq!(array.get(&1, 0)?, 42); /// # Ok::<(), aya::BpfError>(()) /// ``` #[doc(alias = "BPF_MAP_TYPE_ARRAY")] -pub struct Array, V: Pod> { +pub struct Array { inner: T, _v: PhantomData, } -impl, V: Pod> Array { - fn new(map: T) -> Result, MapError> { - let map_type = map.obj.map_type(); - if map_type != BPF_MAP_TYPE_ARRAY as u32 { - return Err(MapError::InvalidMapType { map_type }); - } +impl, V: Pod> Array { + pub(crate) fn new(map: T) -> Result, MapError> { + let data = map.as_ref(); let expected = mem::size_of::(); - let size = map.obj.key_size() as usize; + let size = data.obj.key_size() as usize; if size != expected { return Err(MapError::InvalidKeySize { size, expected }); } let expected = mem::size_of::(); - let size = map.obj.value_size() as usize; + let size = data.obj.value_size() as usize; if size != expected { return Err(MapError::InvalidValueSize { size, expected }); } - let _fd = map.fd_or_err()?; + let _fd = data.fd_or_err()?; Ok(Array { inner: map, @@ -65,7 +61,7 @@ impl, V: Pod> Array { /// /// This corresponds to the value of `bpf_map_def::max_entries` on the eBPF side. 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. @@ -75,8 +71,9 @@ impl, V: Pod> Array { /// Returns [`MapError::OutOfBounds`] if `index` is out of bounds, [`MapError::SyscallError`] /// if `bpf_map_lookup_elem` fails. pub fn get(&self, index: &u32, flags: u64) -> Result { - self.check_bounds(*index)?; - let fd = self.inner.fd_or_err()?; + let data = self.inner.as_ref(); + array::check_bounds(data, *index)?; + let fd = data.fd_or_err()?; let value = bpf_map_lookup_elem(fd, index, flags).map_err(|(_, io_error)| { MapError::SyscallError { @@ -92,18 +89,9 @@ impl, V: Pod> Array { pub fn iter(&self) -> impl Iterator> + '_ { (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 + DerefMut, V: Pod> Array { +impl, V: Pod> Array { /// Sets the value of the element at the given index. /// /// # Errors @@ -111,8 +99,9 @@ impl + DerefMut, V: Pod> Array { /// Returns [`MapError::OutOfBounds`] if `index` is out of bounds, [`MapError::SyscallError`] /// if `bpf_map_update_elem` fails. pub fn set(&mut self, index: u32, value: V, flags: u64) -> Result<(), MapError> { - let fd = self.inner.fd_or_err()?; - self.check_bounds(index)?; + let data = self.inner.as_mut(); + array::check_bounds(data, index)?; + let fd = data.fd_or_err()?; bpf_map_update_elem(fd, Some(&index), &value, flags).map_err(|(_, io_error)| { MapError::SyscallError { call: "bpf_map_update_elem".to_owned(), @@ -123,28 +112,12 @@ impl + DerefMut, V: Pod> Array { } } -impl, V: Pod> IterableMap for Array { - fn map(&self) -> &Map { - &self.inner +impl, V: Pod> IterableMap for Array { + fn map(&self) -> &MapData { + self.inner.as_ref() } fn get(&self, index: &u32) -> Result { self.get(index, 0) } } - -impl TryFrom for Array { - type Error = MapError; - - fn try_from(a: MapRef) -> Result, MapError> { - Array::new(a) - } -} - -impl TryFrom for Array { - type Error = MapError; - - fn try_from(a: MapRefMut) -> Result, MapError> { - Array::new(a) - } -} diff --git a/aya/src/maps/array/mod.rs b/aya/src/maps/array/mod.rs index 5b762e274..c33f91cfa 100644 --- a/aya/src/maps/array/mod.rs +++ b/aya/src/maps/array/mod.rs @@ -4,6 +4,17 @@ mod array; mod per_cpu_array; mod program_array; -pub use array::Array; +pub use array::*; pub use per_cpu_array::PerCpuArray; pub use program_array::ProgramArray; + +use crate::maps::{MapData, MapError}; + +pub(crate) fn check_bounds(map: &MapData, index: u32) -> Result<(), MapError> { + let max_entries = map.obj.max_entries(); + if index >= map.obj.max_entries() { + Err(MapError::OutOfBounds { index, max_entries }) + } else { + Ok(()) + } +} diff --git a/aya/src/maps/array/per_cpu_array.rs b/aya/src/maps/array/per_cpu_array.rs index 6cbfb37b3..5589e3063 100644 --- a/aya/src/maps/array/per_cpu_array.rs +++ b/aya/src/maps/array/per_cpu_array.rs @@ -1,12 +1,11 @@ use std::{ + convert::{AsMut, AsRef}, marker::PhantomData, mem, - ops::{Deref, DerefMut}, }; use crate::{ - generated::bpf_map_type::BPF_MAP_TYPE_PERCPU_ARRAY, - maps::{IterableMap, Map, MapError, MapRef, MapRefMut, PerCpuValues}, + maps::{array, IterableMap, MapData, MapError, PerCpuValues}, sys::{bpf_map_lookup_elem_per_cpu, bpf_map_update_elem_per_cpu}, Pod, }; @@ -31,11 +30,11 @@ use crate::{ /// # #[error(transparent)] /// # Bpf(#[from] aya::BpfError) /// # } -/// # let bpf = aya::Bpf::load(&[])?; +/// # let mut bpf = aya::Bpf::load(&[])?; /// use aya::maps::{PerCpuArray, PerCpuValues}; /// use aya::util::nr_cpus; /// -/// let mut array = PerCpuArray::try_from(bpf.map_mut("ARRAY")?)?; +/// let mut array: PerCpuArray<_,u32> = bpf.map_mut("ARRAY")?.try_into()?; /// /// // set array[1] = 42 for all cpus /// let nr_cpus = nr_cpus()?; @@ -50,29 +49,26 @@ use crate::{ /// # Ok::<(), Error>(()) /// ``` #[doc(alias = "BPF_MAP_TYPE_PERCPU_ARRAY")] -pub struct PerCpuArray, V: Pod> { +pub struct PerCpuArray { inner: T, _v: PhantomData, } -impl, V: Pod> PerCpuArray { - fn new(map: T) -> Result, MapError> { - let map_type = map.obj.map_type(); - if map_type != BPF_MAP_TYPE_PERCPU_ARRAY as u32 { - return Err(MapError::InvalidMapType { map_type }); - } +impl, V: Pod> PerCpuArray { + pub(crate) fn new(map: T) -> Result, MapError> { + let data = map.as_ref(); let expected = mem::size_of::(); - let size = map.obj.key_size() as usize; + let size = data.obj.key_size() as usize; if size != expected { return Err(MapError::InvalidKeySize { size, expected }); } let expected = mem::size_of::(); - let size = map.obj.value_size() as usize; + let size = data.obj.value_size() as usize; if size != expected { return Err(MapError::InvalidValueSize { size, expected }); } - let _fd = map.fd_or_err()?; + let _fd = data.fd_or_err()?; Ok(PerCpuArray { inner: map, @@ -84,7 +80,7 @@ impl, V: Pod> PerCpuArray { /// /// This corresponds to the value of `bpf_map_def::max_entries` on the eBPF side. 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. @@ -94,8 +90,9 @@ impl, V: Pod> PerCpuArray { /// Returns [`MapError::OutOfBounds`] if `index` is out of bounds, [`MapError::SyscallError`] /// if `bpf_map_lookup_elem` fails. pub fn get(&self, index: &u32, flags: u64) -> Result, MapError> { - self.check_bounds(*index)?; - let fd = self.inner.fd_or_err()?; + let data = self.inner.as_ref(); + array::check_bounds(data, *index)?; + let fd = data.fd_or_err()?; let value = bpf_map_lookup_elem_per_cpu(fd, index, flags).map_err(|(_, io_error)| { MapError::SyscallError { @@ -111,18 +108,9 @@ impl, V: Pod> PerCpuArray { pub fn iter(&self) -> impl Iterator, MapError>> + '_ { (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 + DerefMut, V: Pod> PerCpuArray { +impl, V: Pod> PerCpuArray { /// Sets the values - one for each CPU - at the given index. /// /// # Errors @@ -130,8 +118,10 @@ impl + DerefMut, V: Pod> PerCpuArray /// Returns [`MapError::OutOfBounds`] if `index` is out of bounds, [`MapError::SyscallError`] /// if `bpf_map_update_elem` fails. pub fn set(&mut self, index: u32, values: PerCpuValues, flags: u64) -> Result<(), MapError> { - let fd = self.inner.fd_or_err()?; - self.check_bounds(index)?; + let data = self.inner.as_mut(); + array::check_bounds(data, index)?; + let fd = data.fd_or_err()?; + bpf_map_update_elem_per_cpu(fd, &index, &values, flags).map_err(|(_, io_error)| { MapError::SyscallError { call: "bpf_map_update_elem".to_owned(), @@ -142,28 +132,12 @@ impl + DerefMut, V: Pod> PerCpuArray } } -impl, V: Pod> IterableMap> for PerCpuArray { - fn map(&self) -> &Map { - &self.inner +impl, V: Pod> IterableMap> for PerCpuArray { + fn map(&self) -> &MapData { + self.inner.as_ref() } fn get(&self, index: &u32) -> Result, MapError> { self.get(index, 0) } } - -impl TryFrom for PerCpuArray { - type Error = MapError; - - fn try_from(a: MapRef) -> Result, MapError> { - PerCpuArray::new(a) - } -} - -impl TryFrom for PerCpuArray { - type Error = MapError; - - fn try_from(a: MapRefMut) -> Result, MapError> { - PerCpuArray::new(a) - } -} diff --git a/aya/src/maps/array/program_array.rs b/aya/src/maps/array/program_array.rs index aa5372cce..c51cfbb79 100644 --- a/aya/src/maps/array/program_array.rs +++ b/aya/src/maps/array/program_array.rs @@ -1,14 +1,13 @@ //! An array of eBPF program file descriptors used as a jump table. use std::{ + convert::{AsMut, AsRef}, mem, - ops::{Deref, DerefMut}, os::unix::prelude::{AsRawFd, RawFd}, }; use crate::{ - generated::bpf_map_type::BPF_MAP_TYPE_PROG_ARRAY, - maps::{Map, MapError, MapKeys, MapRef, MapRefMut}, + maps::{array, MapData, MapError, MapKeys}, programs::ProgramFd, sys::{bpf_map_delete_elem, bpf_map_update_elem}, }; @@ -29,7 +28,7 @@ use crate::{ /// use aya::maps::ProgramArray; /// use aya::programs::CgroupSkb; /// -/// let mut prog_array = ProgramArray::try_from(bpf.map_mut("JUMP_TABLE")?)?; +/// let mut prog_array: ProgramArray<_> = bpf.take_map("JUMP_TABLE")?.try_into()?; /// let prog_0: &CgroupSkb = bpf.program("example_prog_0").unwrap().try_into()?; /// let prog_0_fd = prog_0.fd().unwrap(); /// let prog_1: &CgroupSkb = bpf.program("example_prog_1").unwrap().try_into()?; @@ -49,28 +48,25 @@ use crate::{ /// # Ok::<(), aya::BpfError>(()) /// ``` #[doc(alias = "BPF_MAP_TYPE_PROG_ARRAY")] -pub struct ProgramArray> { +pub struct ProgramArray { inner: T, } -impl> ProgramArray { - fn new(map: T) -> Result, MapError> { - let map_type = map.obj.map_type(); - if map_type != BPF_MAP_TYPE_PROG_ARRAY as u32 { - return Err(MapError::InvalidMapType { map_type }); - } +impl> ProgramArray { + pub(crate) fn new(map: T) -> Result, MapError> { + let data = map.as_ref(); let expected = mem::size_of::(); - let size = map.obj.key_size() as usize; + let size = data.obj.key_size() as usize; if size != expected { return Err(MapError::InvalidKeySize { size, expected }); } let expected = mem::size_of::(); - let size = map.obj.value_size() as usize; + let size = data.obj.value_size() as usize; if size != expected { return Err(MapError::InvalidValueSize { size, expected }); } - let _fd = map.fd_or_err()?; + let _fd = data.fd_or_err()?; Ok(ProgramArray { inner: map }) } @@ -78,27 +74,19 @@ impl> ProgramArray { /// An iterator over the indices of the array that point to a program. The iterator item type /// is `Result`. pub fn indices(&self) -> MapKeys<'_, u32> { - MapKeys::new(&self.inner) - } - - 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(()) - } + MapKeys::new(self.inner.as_ref()) } } -impl + DerefMut> ProgramArray { +impl> ProgramArray { /// 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 /// flow will jump to `program`. pub fn set(&mut self, index: u32, program: ProgramFd, flags: u64) -> Result<(), MapError> { - let fd = self.inner.fd_or_err()?; - self.check_bounds(index)?; + let data = self.inner.as_mut(); + array::check_bounds(data, index)?; + let fd = data.fd_or_err()?; let prog_fd = program.as_raw_fd(); bpf_map_update_elem(fd, Some(&index), &prog_fd, flags).map_err(|(_, io_error)| { @@ -115,8 +103,10 @@ impl + DerefMut> ProgramArray { /// Calling `bpf_tail_call(ctx, prog_array, index)` on an index that has been cleared returns an /// error. pub fn clear_index(&mut self, index: &u32) -> Result<(), MapError> { - let fd = self.inner.fd_or_err()?; - self.check_bounds(*index)?; + let data = self.inner.as_mut(); + array::check_bounds(data, *index)?; + let fd = self.inner.as_mut().fd_or_err()?; + bpf_map_delete_elem(fd, index) .map(|_| ()) .map_err(|(_, io_error)| MapError::SyscallError { @@ -125,19 +115,3 @@ impl + DerefMut> ProgramArray { }) } } - -impl TryFrom for ProgramArray { - type Error = MapError; - - fn try_from(a: MapRef) -> Result, MapError> { - ProgramArray::new(a) - } -} - -impl TryFrom for ProgramArray { - type Error = MapError; - - fn try_from(a: MapRefMut) -> Result, MapError> { - ProgramArray::new(a) - } -} diff --git a/aya/src/maps/bloom_filter.rs b/aya/src/maps/bloom_filter.rs index 03902ae65..5e49749ad 100644 --- a/aya/src/maps/bloom_filter.rs +++ b/aya/src/maps/bloom_filter.rs @@ -1,11 +1,10 @@ //! A Bloom Filter. -use std::{marker::PhantomData, ops::Deref}; +use std::{convert::AsRef, marker::PhantomData}; use core::mem; use crate::{ - generated::bpf_map_type::BPF_MAP_TYPE_BLOOM_FILTER, - maps::{Map, MapError, MapRef, MapRefMut}, + maps::{MapData, MapError}, sys::{bpf_map_lookup_elem_ptr, bpf_map_push_elem}, Pod, }; @@ -19,10 +18,10 @@ use crate::{ /// # Examples /// /// ```no_run -/// # let bpf = aya::Bpf::load(&[])?; +/// # let mut bpf = aya::Bpf::load(&[])?; /// use aya::maps::bloom_filter::BloomFilter; /// -/// let mut bloom_filter = BloomFilter::try_from(bpf.map_mut("BLOOM_FILTER")?)?; +/// let mut bloom_filter: BloomFilter<_,u32> = bpf.map_mut("BLOOM_FILTER")?.try_into()?; /// /// bloom_filter.insert(1, 0)?; /// @@ -33,27 +32,21 @@ use crate::{ /// ``` #[doc(alias = "BPF_MAP_TYPE_BLOOM_FILTER")] -pub struct BloomFilter, V: Pod> { +pub struct BloomFilter { inner: T, _v: PhantomData, } -impl, V: Pod> BloomFilter { +impl, V: Pod> BloomFilter { pub(crate) fn new(map: T) -> Result, MapError> { - let map_type = map.obj.map_type(); - - // validate the map definition - if map_type != BPF_MAP_TYPE_BLOOM_FILTER as u32 { - return Err(MapError::InvalidMapType { map_type }); - } - + let data = map.as_ref(); let size = mem::size_of::(); - let expected = map.obj.value_size() as usize; + let expected = data.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 { inner: map, @@ -63,7 +56,7 @@ impl, V: Pod> BloomFilter { /// Query the existence of the element. 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::(fd, None, &mut value, flags) .map_err(|(_, io_error)| MapError::SyscallError { @@ -76,7 +69,7 @@ impl, V: Pod> BloomFilter { /// Inserts a value into the map. 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 { call: "bpf_map_push_elem".to_owned(), io_error, @@ -85,38 +78,6 @@ impl, V: Pod> BloomFilter { } } -impl TryFrom for BloomFilter { - type Error = MapError; - - fn try_from(a: MapRef) -> Result, MapError> { - BloomFilter::new(a) - } -} - -impl TryFrom for BloomFilter { - type Error = MapError; - - fn try_from(a: MapRefMut) -> Result, 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, 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, MapError> { - BloomFilter::new(a) - } -} - #[cfg(test)] mod tests { use super::*; @@ -126,6 +87,7 @@ mod tests { bpf_cmd, bpf_map_type::{BPF_MAP_TYPE_BLOOM_FILTER, BPF_MAP_TYPE_PERF_EVENT_ARRAY}, }, + maps::{Map, MapData}, obj, sys::{override_syscall, SysResult, Syscall}, }; @@ -154,7 +116,7 @@ mod tests { #[test] fn test_wrong_value_size() { - let map = Map { + let map = MapData { obj: new_obj_map(), fd: None, pinned: false, @@ -171,7 +133,7 @@ mod tests { #[test] fn test_try_from_wrong_map() { - let map = Map { + let map_data = MapData { obj: obj::Map::Legacy(obj::LegacyMap { def: bpf_map_def { map_type: BPF_MAP_TYPE_PERF_EVENT_ARRAY as u32, @@ -190,15 +152,17 @@ mod tests { btf_fd: None, }; + let map = Map::PerfEventArray(map_data); + assert!(matches!( BloomFilter::<_, u32>::try_from(&map), - Err(MapError::InvalidMapType { .. }) + Err(MapError::UnexpectedMapType) )); } #[test] fn test_new_not_created() { - let mut map = Map { + let mut map = MapData { obj: new_obj_map(), fd: None, pinned: false, @@ -213,7 +177,7 @@ mod tests { #[test] fn test_new_ok() { - let mut map = Map { + let mut map = MapData { obj: new_obj_map(), fd: Some(42), pinned: false, @@ -225,12 +189,14 @@ mod tests { #[test] fn test_try_from_ok() { - let map = Map { + let map_data = MapData { obj: new_obj_map(), fd: Some(42), pinned: false, btf_fd: None, }; + + let map = Map::BloomFilter(map_data); assert!(BloomFilter::<_, u32>::try_from(&map).is_ok()) } @@ -238,7 +204,7 @@ mod tests { fn test_insert_syscall_error() { override_syscall(|_| sys_error(EFAULT)); - let mut map = Map { + let mut map = MapData { obj: new_obj_map(), fd: Some(42), pinned: false, @@ -262,7 +228,7 @@ mod tests { _ => sys_error(EFAULT), }); - let mut map = Map { + let mut map = MapData { obj: new_obj_map(), fd: Some(42), pinned: false, @@ -276,7 +242,7 @@ mod tests { #[test] fn test_contains_syscall_error() { override_syscall(|_| sys_error(EFAULT)); - let map = Map { + let map = MapData { obj: new_obj_map(), fd: Some(42), pinned: false, @@ -299,7 +265,7 @@ mod tests { } => sys_error(ENOENT), _ => sys_error(EFAULT), }); - let map = Map { + let map = MapData { obj: new_obj_map(), fd: Some(42), pinned: false, diff --git a/aya/src/maps/hash_map/hash_map.rs b/aya/src/maps/hash_map/hash_map.rs index 6e36081c6..8a1202016 100644 --- a/aya/src/maps/hash_map/hash_map.rs +++ b/aya/src/maps/hash_map/hash_map.rs @@ -1,11 +1,10 @@ use std::{ + convert::{AsMut, AsRef}, marker::PhantomData, - ops::{Deref, DerefMut}, }; use crate::{ - generated::bpf_map_type::{BPF_MAP_TYPE_HASH, BPF_MAP_TYPE_LRU_HASH}, - maps::{hash_map, IterableMap, Map, MapError, MapIter, MapKeys, MapRef, MapRefMut}, + maps::{hash_map, IterableMap, MapData, MapError, MapIter, MapKeys}, sys::bpf_map_lookup_elem, Pod, }; @@ -19,10 +18,10 @@ use crate::{ /// # Examples /// /// ```no_run -/// # let bpf = aya::Bpf::load(&[])?; +/// # let mut bpf = aya::Bpf::load(&[])?; /// use aya::maps::HashMap; /// -/// let mut redirect_ports = HashMap::try_from(bpf.map_mut("REDIRECT_PORTS")?)?; +/// let mut redirect_ports: HashMap<_, u32, u32> = bpf.map_mut("REDIRECT_PORTS")?.try_into()?; /// /// // redirect port 80 to 8080 /// redirect_ports.insert(80, 8080, 0); @@ -32,22 +31,18 @@ use crate::{ /// ``` #[doc(alias = "BPF_MAP_TYPE_HASH")] #[doc(alias = "BPF_MAP_TYPE_LRU_HASH")] -pub struct HashMap, K, V> { +#[derive(Debug)] +pub struct HashMap { inner: T, _k: PhantomData, _v: PhantomData, } -impl, K: Pod, V: Pod> HashMap { +impl, K: Pod, V: Pod> HashMap { pub(crate) fn new(map: T) -> Result, MapError> { - let map_type = map.obj.map_type(); - - // validate the map definition - 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::(&map)?; - let _ = map.fd_or_err()?; + let data = map.as_ref(); + hash_map::check_kv_size::(data)?; + let _ = data.fd_or_err()?; Ok(HashMap { inner: map, @@ -58,7 +53,7 @@ impl, K: Pod, V: Pod> HashMap { /// Returns a copy of the value associated with the key. pub fn get(&self, key: &K, flags: u64) -> Result { - 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)| { MapError::SyscallError { call: "bpf_map_lookup_elem".to_owned(), @@ -77,25 +72,25 @@ impl, K: Pod, V: Pod> HashMap { /// An iterator visiting all keys in arbitrary order. The iterator element /// type is `Result`. pub fn keys(&self) -> MapKeys<'_, K> { - MapKeys::new(&self.inner) + MapKeys::new(self.inner.as_ref()) } } -impl, K: Pod, V: Pod> HashMap { +impl, K: Pod, V: Pod> HashMap { /// Inserts a key-value pair into the map. 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. 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, K: Pod, V: Pod> IterableMap for HashMap { - fn map(&self) -> &Map { - &self.inner +impl, K: Pod, V: Pod> IterableMap for HashMap { + fn map(&self) -> &MapData { + self.inner.as_ref() } fn get(&self, key: &K) -> Result { @@ -103,38 +98,6 @@ impl, K: Pod, V: Pod> IterableMap for HashMap TryFrom for HashMap { - type Error = MapError; - - fn try_from(a: MapRef) -> Result, MapError> { - HashMap::new(a) - } -} - -impl TryFrom for HashMap { - type Error = MapError; - - fn try_from(a: MapRefMut) -> Result, 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, 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, MapError> { - HashMap::new(a) - } -} - #[cfg(test)] mod tests { use std::io; @@ -145,8 +108,9 @@ mod tests { bpf_map_def, generated::{ 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, sys::{override_syscall, SysResult, Syscall}, }; @@ -175,7 +139,7 @@ mod tests { #[test] fn test_wrong_key_size() { - let map = Map { + let map = MapData { obj: new_obj_map(), fd: None, pinned: false, @@ -192,7 +156,7 @@ mod tests { #[test] fn test_wrong_value_size() { - let map = Map { + let map = MapData { obj: new_obj_map(), fd: None, pinned: false, @@ -209,34 +173,42 @@ mod tests { #[test] fn test_try_from_wrong_map() { - let map = Map { - obj: obj::Map::Legacy(obj::LegacyMap { - 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, - }), + let map_data = MapData { + obj: new_obj_map(), + fd: None, + pinned: false, + btf_fd: None, + }; + + let map = Map::Array(map_data); + assert!(matches!( + HashMap::<_, u8, u32>::try_from(&map), + Err(MapError::UnexpectedMapType) + )); + } + + #[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, u32>::try_from(&map), - Err(MapError::InvalidMapType { .. }) + HashMap::<_, u32, u16>::try_from(&map), + Err(MapError::InvalidValueSize { + size: 2, + expected: 4 + }) )); } #[test] fn test_new_not_created() { - let mut map = Map { + let mut map = MapData { obj: new_obj_map(), fd: None, pinned: false, @@ -251,7 +223,7 @@ mod tests { #[test] fn test_new_ok() { - let mut map = Map { + let mut map = MapData { obj: new_obj_map(), fd: Some(42), pinned: false, @@ -263,18 +235,20 @@ mod tests { #[test] fn test_try_from_ok() { - let map = Map { + let map_data = MapData { obj: new_obj_map(), fd: Some(42), pinned: false, btf_fd: None, }; + + let map = Map::HashMap(map_data); assert!(HashMap::<_, u32, u32>::try_from(&map).is_ok()) } #[test] fn test_try_from_ok_lru() { - let map = Map { + let map_data = MapData { obj: obj::Map::Legacy(obj::LegacyMap { def: bpf_map_def { map_type: BPF_MAP_TYPE_LRU_HASH as u32, @@ -293,6 +267,8 @@ mod tests { btf_fd: None, }; + let map = Map::HashMap(map_data); + assert!(HashMap::<_, u32, u32>::try_from(&map).is_ok()) } @@ -300,7 +276,7 @@ mod tests { fn test_insert_syscall_error() { override_syscall(|_| sys_error(EFAULT)); - let mut map = Map { + let mut map = MapData { obj: new_obj_map(), fd: Some(42), pinned: false, @@ -324,7 +300,7 @@ mod tests { _ => sys_error(EFAULT), }); - let mut map = Map { + let mut map = MapData { obj: new_obj_map(), fd: Some(42), pinned: false, @@ -339,7 +315,7 @@ mod tests { fn test_remove_syscall_error() { override_syscall(|_| sys_error(EFAULT)); - let mut map = Map { + let mut map = MapData { obj: new_obj_map(), fd: Some(42), pinned: false, @@ -363,7 +339,7 @@ mod tests { _ => sys_error(EFAULT), }); - let mut map = Map { + let mut map = MapData { obj: new_obj_map(), fd: Some(42), pinned: false, @@ -377,7 +353,7 @@ mod tests { #[test] fn test_get_syscall_error() { override_syscall(|_| sys_error(EFAULT)); - let map = Map { + let map = MapData { obj: new_obj_map(), fd: Some(42), pinned: false, @@ -400,7 +376,7 @@ mod tests { } => sys_error(ENOENT), _ => sys_error(EFAULT), }); - let map = Map { + let map = MapData { obj: new_obj_map(), fd: Some(42), pinned: false, @@ -437,7 +413,7 @@ mod tests { } => sys_error(ENOENT), _ => sys_error(EFAULT), }); - let map = Map { + let map = MapData { obj: new_obj_map(), fd: Some(42), pinned: false, @@ -486,7 +462,7 @@ mod tests { _ => sys_error(EFAULT), }); - let map = Map { + let map = MapData { obj: new_obj_map(), fd: Some(42), pinned: false, @@ -519,7 +495,7 @@ mod tests { } _ => sys_error(EFAULT), }); - let map = Map { + let map = MapData { obj: new_obj_map(), fd: Some(42), pinned: false, @@ -554,7 +530,7 @@ mod tests { } => lookup_elem(attr), _ => sys_error(EFAULT), }); - let map = Map { + let map = MapData { obj: new_obj_map(), fd: Some(42), pinned: false, @@ -592,7 +568,7 @@ mod tests { } _ => sys_error(EFAULT), }); - let map = Map { + let map = MapData { obj: new_obj_map(), fd: Some(42), pinned: false, @@ -631,7 +607,7 @@ mod tests { } => lookup_elem(attr), _ => sys_error(EFAULT), }); - let map = Map { + let map = MapData { obj: new_obj_map(), fd: Some(42), pinned: false, @@ -676,7 +652,7 @@ mod tests { } _ => sys_error(EFAULT), }); - let map = Map { + let map = MapData { obj: new_obj_map(), fd: Some(42), pinned: false, diff --git a/aya/src/maps/hash_map/mod.rs b/aya/src/maps/hash_map/mod.rs index 60d0ec8a7..923337001 100644 --- a/aya/src/maps/hash_map/mod.rs +++ b/aya/src/maps/hash_map/mod.rs @@ -2,7 +2,7 @@ use std::mem; use crate::{ - maps::{Map, MapError}, + maps::MapError, sys::{bpf_map_delete_elem, bpf_map_update_elem}, }; @@ -13,7 +13,9 @@ mod per_cpu_hash_map; pub use hash_map::*; pub use per_cpu_hash_map::*; -pub(crate) fn check_kv_size(map: &Map) -> Result<(), MapError> { +use super::MapData; + +pub(crate) fn check_kv_size(map: &MapData) -> Result<(), MapError> { let size = mem::size_of::(); let expected = map.obj.key_size() as usize; if size != expected { @@ -27,7 +29,12 @@ pub(crate) fn check_kv_size(map: &Map) -> Result<(), MapError> { Ok(()) } -pub(crate) fn insert(map: &mut Map, key: K, value: V, flags: u64) -> Result<(), MapError> { +pub(crate) fn insert( + map: &mut MapData, + key: K, + value: V, + flags: u64, +) -> Result<(), MapError> { let fd = map.fd_or_err()?; bpf_map_update_elem(fd, Some(&key), &value, flags).map_err(|(_, io_error)| { MapError::SyscallError { @@ -39,7 +46,7 @@ pub(crate) fn insert(map: &mut Map, key: K, value: V, flags: u64) -> Resul Ok(()) } -pub(crate) fn remove(map: &mut Map, key: &K) -> Result<(), MapError> { +pub(crate) fn remove(map: &mut MapData, key: &K) -> Result<(), MapError> { let fd = map.fd_or_err()?; bpf_map_delete_elem(fd, key) .map(|_| ()) diff --git a/aya/src/maps/hash_map/per_cpu_hash_map.rs b/aya/src/maps/hash_map/per_cpu_hash_map.rs index a539965d2..329a51fc6 100644 --- a/aya/src/maps/hash_map/per_cpu_hash_map.rs +++ b/aya/src/maps/hash_map/per_cpu_hash_map.rs @@ -1,14 +1,12 @@ //! Per-CPU hash map. use std::{ + convert::{AsMut, AsRef}, marker::PhantomData, - ops::{Deref, DerefMut}, }; use crate::{ generated::bpf_map_type::{BPF_MAP_TYPE_LRU_PERCPU_HASH, BPF_MAP_TYPE_PERCPU_HASH}, - maps::{ - hash_map, IterableMap, Map, MapError, MapIter, MapKeys, MapRef, MapRefMut, PerCpuValues, - }, + maps::{hash_map, IterableMap, MapData, MapError, MapIter, MapKeys, PerCpuValues}, sys::{bpf_map_lookup_elem_per_cpu, bpf_map_update_elem_per_cpu}, Pod, }; @@ -42,15 +40,16 @@ use crate::{ /// ``` #[doc(alias = "BPF_MAP_TYPE_LRU_PERCPU_HASH")] #[doc(alias = "BPF_MAP_TYPE_PERCPU_HASH")] -pub struct PerCpuHashMap, K: Pod, V: Pod> { +pub struct PerCpuHashMap { inner: T, _k: PhantomData, _v: PhantomData, } -impl, K: Pod, V: Pod> PerCpuHashMap { +impl, K: Pod, V: Pod> PerCpuHashMap { pub(crate) fn new(map: T) -> Result, MapError> { - let map_type = map.obj.map_type(); + let data = map.as_ref(); + let map_type = data.obj.map_type(); // validate the map definition if map_type != BPF_MAP_TYPE_PERCPU_HASH as u32 @@ -58,8 +57,8 @@ impl, K: Pod, V: Pod> PerCpuHashMap { { return Err(MapError::InvalidMapType { map_type }); } - hash_map::check_kv_size::(&map)?; - let _ = map.fd_or_err()?; + hash_map::check_kv_size::(data)?; + let _ = data.fd_or_err()?; Ok(PerCpuHashMap { inner: map, @@ -70,7 +69,7 @@ impl, K: Pod, V: Pod> PerCpuHashMap { /// Returns a slice of values - one for each CPU - associated with the key. pub fn get(&self, key: &K, flags: u64) -> Result, 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)| { MapError::SyscallError { call: "bpf_map_lookup_elem".to_owned(), @@ -89,11 +88,11 @@ impl, K: Pod, V: Pod> PerCpuHashMap { /// An iterator visiting all keys in arbitrary order. The iterator element /// type is `Result`. pub fn keys(&self) -> MapKeys<'_, K> { - MapKeys::new(&self.inner) + MapKeys::new(self.inner.as_ref()) } } -impl, K: Pod, V: Pod> PerCpuHashMap { +impl, K: Pod, V: Pod> PerCpuHashMap { /// Inserts a slice of values - one for each CPU - for the given key. /// /// # Examples @@ -108,13 +107,13 @@ impl, K: Pod, V: Pod> PerCpuHashMap { /// # #[error(transparent)] /// # Bpf(#[from] aya::BpfError) /// # } - /// # let bpf = aya::Bpf::load(&[])?; + /// # let mut bpf = aya::Bpf::load(&[])?; /// use aya::maps::{PerCpuHashMap, PerCpuValues}; /// use aya::util::nr_cpus; /// /// const RETRIES: u8 = 1; /// - /// let mut hm = PerCpuHashMap::<_, u8, u32>::try_from(bpf.map_mut("PER_CPU_STORAGE")?)?; + /// let mut hm: PerCpuHashMap::<_, u8, u32> = bpf.map_mut("PER_CPU_STORAGE")?.try_into()?; /// hm.insert( /// RETRIES, /// PerCpuValues::try_from(vec![3u32; nr_cpus()?])?, @@ -123,7 +122,7 @@ impl, K: Pod, V: Pod> PerCpuHashMap { /// # Ok::<(), Error>(()) /// ``` pub fn insert(&mut self, key: K, values: PerCpuValues, 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)| { MapError::SyscallError { call: "bpf_map_update_elem".to_owned(), @@ -136,50 +135,16 @@ impl, K: Pod, V: Pod> PerCpuHashMap { /// Removes a key from the map. 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, K: Pod, V: Pod> IterableMap> - for PerCpuHashMap -{ - fn map(&self) -> &Map { - &self.inner +impl, K: Pod, V: Pod> IterableMap> for PerCpuHashMap { + fn map(&self) -> &MapData { + self.inner.as_ref() } fn get(&self, key: &K) -> Result, MapError> { PerCpuHashMap::get(self, key, 0) } } - -impl TryFrom for PerCpuHashMap { - type Error = MapError; - - fn try_from(a: MapRef) -> Result, MapError> { - PerCpuHashMap::new(a) - } -} - -impl TryFrom for PerCpuHashMap { - type Error = MapError; - - fn try_from(a: MapRefMut) -> Result, 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, 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, MapError> { - PerCpuHashMap::new(a) - } -} diff --git a/aya/src/maps/lpm_trie.rs b/aya/src/maps/lpm_trie.rs index 989ee51f6..4cbc6ec7b 100644 --- a/aya/src/maps/lpm_trie.rs +++ b/aya/src/maps/lpm_trie.rs @@ -1,9 +1,12 @@ //! A LPM Trie. -use std::{marker::PhantomData, mem, ops::Deref}; +use std::{ + convert::{AsMut, AsRef}, + marker::PhantomData, + mem, +}; use crate::{ - generated::bpf_map_type::BPF_MAP_TYPE_LPM_TRIE, - maps::{IterableMap, Map, MapError, MapRef, MapRefMut}, + maps::{IterableMap, MapData, MapError}, sys::{bpf_map_delete_elem, bpf_map_lookup_elem, bpf_map_update_elem}, Pod, }; @@ -17,11 +20,11 @@ use crate::{ /// # Examples /// /// ```no_run -/// # let bpf = aya::Bpf::load(&[])?; +/// # let mut bpf = aya::Bpf::load(&[])?; /// use aya::maps::lpm_trie::{LpmTrie, Key}; /// use std::net::Ipv4Addr; /// -/// let mut trie = LpmTrie::try_from(bpf.map_mut("LPM_TRIE")?)?; +/// let mut trie: LpmTrie<_,u32,u32> = bpf.map_mut("LPM_TRIE")?.try_into()?; /// let ipaddr = Ipv4Addr::new(8, 8, 8, 8); /// // 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. @@ -43,7 +46,7 @@ use crate::{ /// ``` #[doc(alias = "BPF_MAP_TYPE_LPM_TRIE")] -pub struct LpmTrie, K, V> { +pub struct LpmTrie { inner: T, _k: PhantomData, _v: PhantomData, @@ -96,26 +99,21 @@ impl Clone for Key { // A Pod impl is required as Key struct is a key for a map. unsafe impl Pod for Key {} -impl, K: Pod, V: Pod> LpmTrie { +impl, K: Pod, V: Pod> LpmTrie { pub(crate) fn new(map: T) -> Result, MapError> { - let map_type = map.obj.map_type(); - - // validate the map definition - if map_type != BPF_MAP_TYPE_LPM_TRIE as u32 { - return Err(MapError::InvalidMapType { map_type }); - } + let data = map.as_ref(); let size = mem::size_of::>(); - let expected = map.obj.key_size() as usize; + let expected = data.obj.key_size() as usize; if size != expected { return Err(MapError::InvalidKeySize { size, expected }); } let size = mem::size_of::(); - let expected = map.obj.value_size() as usize; + let expected = data.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 { inner: map, @@ -126,7 +124,7 @@ impl, K: Pod, V: Pod> LpmTrie { /// Returns a copy of the value associated with the longest prefix matching key in the LpmTrie. pub fn get(&self, key: &Key, flags: u64) -> Result { - 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)| { MapError::SyscallError { call: "bpf_map_lookup_elem".to_owned(), @@ -135,10 +133,12 @@ impl, K: Pod, V: Pod> LpmTrie { })?; value.ok_or(MapError::KeyNotFound) } +} +impl, K: Pod, V: Pod> LpmTrie { /// Inserts a key value pair into the map. - pub fn insert(&self, key: &Key, value: V, flags: u64) -> Result<(), MapError> { - let fd = self.inner.deref().fd_or_err()?; + pub fn insert(&mut self, key: &Key, value: V, flags: u64) -> Result<(), MapError> { + let fd = self.inner.as_mut().fd_or_err()?; bpf_map_update_elem(fd, Some(key), &value, flags).map_err(|(_, io_error)| { MapError::SyscallError { call: "bpf_map_update_elem".to_owned(), @@ -152,8 +152,8 @@ impl, K: Pod, V: Pod> LpmTrie { /// Removes an element from the map. /// /// Both the prefix and data must match exactly - this method does not do a longest prefix match. - pub fn remove(&self, key: &Key) -> Result<(), MapError> { - let fd = self.inner.deref().fd_or_err()?; + pub fn remove(&mut self, key: &Key) -> Result<(), MapError> { + let fd = self.inner.as_mut().fd_or_err()?; bpf_map_delete_elem(fd, key) .map(|_| ()) .map_err(|(_, io_error)| MapError::SyscallError { @@ -163,9 +163,9 @@ impl, K: Pod, V: Pod> LpmTrie { } } -impl, K: Pod, V: Pod> IterableMap for LpmTrie { - fn map(&self) -> &Map { - &self.inner +impl, K: Pod, V: Pod> IterableMap for LpmTrie { + fn map(&self) -> &MapData { + self.inner.as_ref() } fn get(&self, key: &K) -> Result { @@ -174,38 +174,6 @@ impl, K: Pod, V: Pod> IterableMap for LpmTrie TryFrom for LpmTrie { - type Error = MapError; - - fn try_from(a: MapRef) -> Result, MapError> { - LpmTrie::new(a) - } -} - -impl TryFrom for LpmTrie { - type Error = MapError; - - fn try_from(a: MapRefMut) -> Result, 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, 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, MapError> { - LpmTrie::new(a) - } -} - #[cfg(test)] mod tests { use super::*; @@ -215,6 +183,7 @@ mod tests { bpf_cmd, bpf_map_type::{BPF_MAP_TYPE_LPM_TRIE, BPF_MAP_TYPE_PERF_EVENT_ARRAY}, }, + maps::{Map, MapData}, obj, sys::{override_syscall, SysResult, Syscall}, }; @@ -243,7 +212,7 @@ mod tests { #[test] fn test_wrong_key_size() { - let map = Map { + let map = MapData { obj: new_obj_map(), fd: None, pinned: false, @@ -260,7 +229,7 @@ mod tests { #[test] fn test_wrong_value_size() { - let map = Map { + let map = MapData { obj: new_obj_map(), fd: None, pinned: false, @@ -277,7 +246,7 @@ mod tests { #[test] fn test_try_from_wrong_map() { - let map = Map { + let map_data = MapData { obj: obj::Map::Legacy(obj::LegacyMap { def: bpf_map_def { map_type: BPF_MAP_TYPE_PERF_EVENT_ARRAY as u32, @@ -296,15 +265,17 @@ mod tests { pinned: false, }; + let map = Map::PerfEventArray(map_data); + assert!(matches!( LpmTrie::<_, u32, u32>::try_from(&map), - Err(MapError::InvalidMapType { .. }) + Err(MapError::UnexpectedMapType) )); } #[test] fn test_new_not_created() { - let mut map = Map { + let mut map = MapData { obj: new_obj_map(), fd: None, pinned: false, @@ -319,7 +290,7 @@ mod tests { #[test] fn test_new_ok() { - let mut map = Map { + let mut map = MapData { obj: new_obj_map(), fd: Some(42), pinned: false, @@ -331,12 +302,14 @@ mod tests { #[test] fn test_try_from_ok() { - let map = Map { + let map_data = MapData { obj: new_obj_map(), fd: Some(42), pinned: false, btf_fd: None, }; + + let map = Map::LpmTrie(map_data); assert!(LpmTrie::<_, u32, u32>::try_from(&map).is_ok()) } @@ -344,13 +317,13 @@ mod tests { fn test_insert_syscall_error() { override_syscall(|_| sys_error(EFAULT)); - let mut map = Map { + let mut map = MapData { obj: new_obj_map(), fd: Some(42), pinned: false, 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 key = Key::new(16, u32::from(ipaddr).to_be()); assert!(matches!( @@ -369,14 +342,14 @@ mod tests { _ => sys_error(EFAULT), }); - let mut map = Map { + let mut map = MapData { obj: new_obj_map(), fd: Some(42), pinned: false, 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 key = Key::new(16, u32::from(ipaddr).to_be()); assert!(trie.insert(&key, 1, 0).is_ok()); @@ -386,13 +359,13 @@ mod tests { fn test_remove_syscall_error() { override_syscall(|_| sys_error(EFAULT)); - let mut map = Map { + let mut map = MapData { obj: new_obj_map(), fd: Some(42), pinned: false, 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 key = Key::new(16, u32::from(ipaddr).to_be()); assert!(matches!( @@ -411,13 +384,13 @@ mod tests { _ => sys_error(EFAULT), }); - let mut map = Map { + let mut map = MapData { obj: new_obj_map(), fd: Some(42), pinned: false, 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 key = Key::new(16, u32::from(ipaddr).to_be()); assert!(trie.remove(&key).is_ok()); @@ -426,7 +399,7 @@ mod tests { #[test] fn test_get_syscall_error() { override_syscall(|_| sys_error(EFAULT)); - let map = Map { + let map = MapData { obj: new_obj_map(), fd: Some(42), pinned: false, @@ -451,7 +424,7 @@ mod tests { } => sys_error(ENOENT), _ => sys_error(EFAULT), }); - let map = Map { + let map = MapData { obj: new_obj_map(), fd: Some(42), pinned: false, diff --git a/aya/src/maps/map_lock.rs b/aya/src/maps/map_lock.rs deleted file mode 100644 index 18f87acfa..000000000 --- a/aya/src/maps/map_lock.rs +++ /dev/null @@ -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>, -} - -impl MapLock { - pub(crate) fn new(map: Map) -> MapLock { - MapLock { - inner: Arc::new(RwLock::new(map)), - } - } - - pub(crate) fn try_read(&self) -> Result { - let lock: Option> = - 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 { - let lock: Option> = - 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>, - guard: RwLockReadGuard<'static, Map>, -} - -/// A mutable borrowed reference to a BPF map. -pub struct MapRefMut { - _lock: Arc>, - 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 - } -} diff --git a/aya/src/maps/mod.rs b/aya/src/maps/mod.rs index 9d8a13d19..82bfa0c01 100644 --- a/aya/src/maps/mod.rs +++ b/aya/src/maps/mod.rs @@ -4,22 +4,25 @@ //! used to setup and share data with eBPF programs. When you call //! [`Bpf::load_file`](crate::Bpf::load_file) or //! [`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 -//! [`Bpf::map_mut`](crate::Bpf::map_mut). +//! initialized and can then be accessed using [`Bpf::map`](crate::Bpf::map), +//! [`Bpf::map_mut`](crate::Bpf::map_mut), [`Bpf::take_map`](crate::Bpf::map) +//! or [`Bpf::map_mut`](crate::Bpf::take_map). //! //! # Typed maps //! //! 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 -//! opaque [`MapRef`] and [`MapRefMut`] types respectively. Those two types can be converted to -//! *typed maps* using the [`TryFrom`](std::convert::TryFrom) trait. For example: +//! [`Bpf::map`](crate::Bpf::map), [`Bpf::map_mut`](crate::Bpf::map_mut), and +//! [`Bpf::map_mut`](crate::Bpf::take_map) always return the +//! opaque [`&Map`], [`&mut Map`], and [`Map`] types respectively. Those three types can be converted to +//! *typed maps* using the [`TryFrom`](std::convert::TryFrom) or [`TryInto`](std::convert::TryInto) +//! trait. For example: //! //! ```no_run //! # let mut bpf = aya::Bpf::load(&[])?; //! use aya::maps::SockMap; //! use aya::programs::SkMsg; //! -//! let intercept_egress = SockMap::try_from(bpf.map_mut("INTERCEPT_EGRESS")?)?; +//! let intercept_egress: SockMap<_> = bpf.take_map("INTERCEPT_EGRESS")?.try_into()?; //! let prog: &mut SkMsg = bpf.program_mut("intercept_egress_packet").unwrap().try_into()?; //! prog.load()?; //! prog.attach(&intercept_egress)?; @@ -32,6 +35,7 @@ //! versa. Because of that, all map values must be plain old data and therefore //! implement the [Pod] trait. use std::{ + convert::{AsMut, AsRef}, ffi::CString, fmt, io, marker::PhantomData, @@ -58,8 +62,6 @@ use crate::{ PinningType, Pod, }; -mod map_lock; - pub mod array; pub mod bloom_filter; pub mod hash_map; @@ -71,8 +73,11 @@ pub mod stack; pub mod stack_trace; pub use array::{Array, PerCpuArray, ProgramArray}; +pub use bloom_filter::BloomFilter; pub use hash_map::{HashMap, PerCpuHashMap}; -pub use map_lock::*; +pub use lpm_trie::LpmTrie; +#[cfg(any(feature = "async", doc))] +pub use perf::AsyncPerfEventArray; pub use perf::PerfEventArray; pub use queue::Queue; pub use sock::{SockHash, SockMap}; @@ -174,20 +179,6 @@ pub enum MapError { 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 #[error("map `{name:?}` requested pinning by name. pinning failed")] PinError { @@ -197,6 +188,10 @@ pub enum MapError { #[source] error: PinError, }, + + /// The map is not of the expected type. + #[error("unexpected map type")] + UnexpectedMapType, } /// A map file descriptor. @@ -243,11 +238,181 @@ fn maybe_warn_rlimit() { } } +/// eBPF map types. +#[derive(Debug)] +pub enum Map { + /// A ['Array`] map + Array(MapData), + /// A [`PerCpuArray`] map + PerCpuArray(MapData), + /// A [`ProgramArray`] map + ProgramArray(MapData), + /// A [`HashMap`] map + HashMap(MapData), + /// A ['PerCpuHashMap'] map + PerCpuHashMap(MapData), + /// A [`PerfEventArray`] map + PerfEventArray(MapData), + /// A [`SockMap`] map + SockMap(MapData), + /// A [`SockHash`] map + SockHash(MapData), + /// A [`BloomFilter`] map + BloomFilter(MapData), + /// A [`LpmTrie`] map + LpmTrie(MapData), + /// A [`Stack`] map + Stack(MapData), + /// A [`StackTrace`] map + StackTraceMap(MapData), + /// A [`Queue`] map + Queue(MapData), +} + +macro_rules! impl_try_from_map { + ($($tx:ident from Map::$ty:ident),+ $(,)?) => { + $( + impl<'a> TryFrom<&'a Map> for $tx<&'a MapData> { + type Error = MapError; + + fn try_from(map: &'a Map) -> Result<$tx<&'a MapData>, MapError> { + match map { + Map::$ty(m) => { + $tx::<&'a MapData>::new(m) + }, + _ => Err(MapError::UnexpectedMapType), + } + } + } + + impl<'a,> TryFrom<&'a mut Map> for $tx<&'a mut MapData> { + type Error = MapError; + + fn try_from(map: &'a mut Map) -> Result<$tx<&'a mut MapData>, MapError> { + match map { + Map::$ty(m) => { + $tx::<&'a mut MapData>::new(m) + }, + _ => Err(MapError::UnexpectedMapType), + } + } + } + + impl TryFrom for $tx { + type Error = MapError; + + fn try_from(map: Map) -> Result<$tx, MapError> { + match map { + Map::$ty(m) => { + $tx::::new(m) + }, + _ => Err(MapError::UnexpectedMapType), + } + } + } + )+ + } +} + +impl_try_from_map!( + ProgramArray from Map::ProgramArray, + SockMap from Map::SockMap, + PerfEventArray from Map::PerfEventArray, + StackTraceMap from Map::StackTraceMap, +); + +#[cfg(feature = "async")] +#[cfg_attr(docsrs, doc(cfg(feature = "async")))] +impl_try_from_map!( + AsyncPerfEventArray from Map::PerfEventArray, +); + +macro_rules! impl_try_from_map_generic_key_or_value { + ($($ty:ident),+ $(,)?) => { + $( + impl<'a, V:Pod> TryFrom<&'a Map> for $ty<&'a MapData, V> { + type Error = MapError; + + fn try_from(map: &'a Map) -> Result<$ty<&'a MapData , V>, MapError> { + match map { + Map::$ty(m) => { + $ty::<&'a MapData,V>::new(m) + }, + _ => Err(MapError::UnexpectedMapType), + } + } + } + + impl<'a,V: Pod> TryFrom<&'a mut Map> for $ty<&'a mut MapData, V> { + type Error = MapError; + + fn try_from(map: &'a mut Map) -> Result<$ty<&'a mut MapData, V>, MapError> { + match map { + Map::$ty(m) => { + $ty::<&'a mut MapData,V>::new(m) + }, + _ => Err(MapError::UnexpectedMapType), + } + } + } + + impl TryFrom for $ty { + type Error = MapError; + + fn try_from(map: Map) -> Result<$ty, MapError> { + match map { + Map::$ty(m) => { + $ty::::new(m) + }, + _ => Err(MapError::UnexpectedMapType), + } + } + } + )+ + } +} + +impl_try_from_map_generic_key_or_value!(Array, PerCpuArray, SockHash, BloomFilter, Queue, Stack,); + +macro_rules! impl_try_from_map_generic_key_and_value { + ($($ty:ident),+ $(,)?) => { + $( + impl<'a, V: Pod, K: Pod> TryFrom<&'a Map> for $ty<&'a MapData, V, K> { + type Error = MapError; + + fn try_from(map: &'a Map) -> Result<$ty<&'a MapData,V,K>, MapError> { + match map { + Map::$ty(m) => { + $ty::<&'a MapData,V,K>::new(m) + }, + _ => Err(MapError::UnexpectedMapType), + } + } + } + + impl<'a,V: Pod,K: Pod> TryFrom<&'a mut Map> for $ty<&'a mut MapData, V, K> { + type Error = MapError; + + fn try_from(map: &'a mut Map) -> Result<$ty<&'a mut MapData, V, K>, MapError> { + match map { + Map::$ty(m) => { + $ty::<&'a mut MapData,V,K>::new(m) + }, + _ => Err(MapError::UnexpectedMapType), + } + } + } + )+ + } +} + +impl_try_from_map_generic_key_and_value!(HashMap, PerCpuHashMap, LpmTrie); + /// A generic handle to a BPF map. /// /// You should never need to use this unless you're implementing a new map type. -#[derive(Debug)] -pub struct Map { +#[derive(Debug, Clone)] +pub struct MapData { pub(crate) obj: obj::Map, pub(crate) fd: Option, pub(crate) btf_fd: Option, @@ -255,7 +420,19 @@ pub struct Map { pub pinned: bool, } -impl Map { +impl AsRef for MapData { + fn as_ref(&self) -> &MapData { + self + } +} + +impl AsMut for MapData { + fn as_mut(&mut self) -> &mut MapData { + self + } +} + +impl MapData { /// Creates a new map with the provided `name` pub fn create(&mut self, name: &str) -> Result { if self.fd.is_some() { @@ -303,7 +480,7 @@ impl Map { } /// Loads a map from a pinned path in bpffs. - pub fn from_pin>(path: P) -> Result { + pub fn from_pin>(path: P) -> Result { let path_string = CString::new(path.as_ref().to_string_lossy().into_owned()).map_err(|e| { MapError::PinError { @@ -324,7 +501,7 @@ impl Map { io_error, })?; - Ok(Map { + Ok(MapData { obj: parse_map_info(info, PinningType::ByName), fd: Some(fd), btf_fd: None, @@ -337,13 +514,13 @@ impl Map { /// If loading from a BPF Filesystem (bpffs) you should use [`Map::from_pin`]. /// This API is intended for cases where you have received a valid BPF FD from some other means. /// For example, you received an FD over Unix Domain Socket. - pub fn from_fd(fd: RawFd) -> Result { + pub fn from_fd(fd: RawFd) -> Result { let info = bpf_map_get_info_by_fd(fd).map_err(|io_error| MapError::SyscallError { call: "BPF_OBJ_GET".to_owned(), io_error, })?; - Ok(Map { + Ok(MapData { obj: parse_map_info(info, PinningType::None), fd: Some(fd), btf_fd: None, @@ -389,7 +566,7 @@ impl Map { } } -impl Drop for Map { +impl Drop for MapData { fn drop(&mut self) { // TODO: Replace this with an OwnedFd once that is stabilized. if let Some(fd) = self.fd.take() { @@ -401,7 +578,7 @@ impl Drop for Map { /// An iterable map pub trait IterableMap { /// Get a generic map handle - fn map(&self) -> ⤅ + fn map(&self) -> &MapData; /// Get the value for the provided `key` fn get(&self, key: &K) -> Result; @@ -409,13 +586,13 @@ pub trait IterableMap { /// Iterator returned by `map.keys()`. pub struct MapKeys<'coll, K: Pod> { - map: &'coll Map, + map: &'coll MapData, err: bool, key: Option, } impl<'coll, K: Pod> MapKeys<'coll, K> { - fn new(map: &'coll Map) -> MapKeys<'coll, K> { + fn new(map: &'coll MapData) -> MapKeys<'coll, K> { MapKeys { map, err: false, @@ -643,6 +820,7 @@ mod tests { use crate::{ bpf_map_def, generated::{bpf_cmd, bpf_map_type::BPF_MAP_TYPE_HASH}, + maps::MapData, obj::MapKind, sys::{override_syscall, Syscall}, }; @@ -665,8 +843,8 @@ mod tests { }) } - fn new_map() -> Map { - Map { + fn new_map() -> MapData { + MapData { obj: new_obj_map(), fd: None, pinned: false, diff --git a/aya/src/maps/perf/async_perf_event_array.rs b/aya/src/maps/perf/async_perf_event_array.rs index 1c14fc6a2..651d503a8 100644 --- a/aya/src/maps/perf/async_perf_event_array.rs +++ b/aya/src/maps/perf/async_perf_event_array.rs @@ -1,6 +1,6 @@ use bytes::BytesMut; use std::{ - ops::DerefMut, + convert::AsMut, os::unix::prelude::{AsRawFd, RawFd}, }; @@ -12,7 +12,7 @@ use tokio::io::unix::AsyncFd; use crate::maps::{ 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 @@ -45,7 +45,7 @@ use crate::maps::{ /// # } /// # #[cfg(feature = "async_tokio")] /// # 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::util::online_cpus; /// use futures::future; @@ -53,7 +53,7 @@ use crate::maps::{ /// use tokio::task; // or async_std::task /// /// // try to convert the PERF_ARRAY map to an AsyncPerfEventArray -/// let mut perf_array = AsyncPerfEventArray::try_from(bpf.map_mut("PERF_ARRAY")?)?; +/// let mut perf_array: AsyncPerfEventArray<_> =bpf.take_map("PERF_ARRAY")?.try_into()?; /// /// for cpu_id in online_cpus()? { /// // open a separate perf buffer for each cpu @@ -85,11 +85,11 @@ use crate::maps::{ /// # } /// ``` #[doc(alias = "BPF_MAP_TYPE_PERF_EVENT_ARRAY")] -pub struct AsyncPerfEventArray> { +pub struct AsyncPerfEventArray { perf_map: PerfEventArray, } -impl> AsyncPerfEventArray { +impl + AsRef> AsyncPerfEventArray { /// Opens the perf buffer at the given index. /// /// The returned buffer will receive all the events eBPF programs send at the given index. @@ -112,8 +112,8 @@ impl> AsyncPerfEventArray { } } -impl> AsyncPerfEventArray { - fn new(map: T) -> Result, MapError> { +impl> AsyncPerfEventArray { + pub(crate) fn new(map: T) -> Result, MapError> { Ok(AsyncPerfEventArray { perf_map: PerfEventArray::new(map)?, }) @@ -127,7 +127,7 @@ impl> AsyncPerfEventArray { /// /// See the [`AsyncPerfEventArray` documentation](AsyncPerfEventArray) for an overview of how to /// use perf buffers. -pub struct AsyncPerfEventArrayBuffer> { +pub struct AsyncPerfEventArrayBuffer { buf: PerfEventArrayBuffer, #[cfg(feature = "async_tokio")] @@ -138,7 +138,7 @@ pub struct AsyncPerfEventArrayBuffer> { } #[cfg(any(feature = "async_tokio"))] -impl> AsyncPerfEventArrayBuffer { +impl + AsRef> AsyncPerfEventArrayBuffer { /// Reads events from the buffer. /// /// This method reads events into the provided slice of buffers, filling @@ -168,7 +168,7 @@ impl> AsyncPerfEventArrayBuffer { } #[cfg(all(not(feature = "async_tokio"), feature = "async_std"))] -impl> AsyncPerfEventArrayBuffer { +impl + AsRef> AsyncPerfEventArrayBuffer { /// Reads events from the buffer. /// /// This method reads events into the provided slice of buffers, filling @@ -195,11 +195,3 @@ impl> AsyncPerfEventArrayBuffer { } } } - -impl TryFrom for AsyncPerfEventArray { - type Error = MapError; - - fn try_from(a: MapRefMut) -> Result, MapError> { - AsyncPerfEventArray::new(a) - } -} diff --git a/aya/src/maps/perf/perf_event_array.rs b/aya/src/maps/perf/perf_event_array.rs index 2a74a4372..0517cb7d0 100644 --- a/aya/src/maps/perf/perf_event_array.rs +++ b/aya/src/maps/perf/perf_event_array.rs @@ -2,7 +2,8 @@ //! //! [`perf`]: https://perf.wiki.kernel.org/index.php/Main_Page. use std::{ - ops::DerefMut, + convert::AsMut, + ops::Deref, os::unix::io::{AsRawFd, RawFd}, sync::Arc, }; @@ -10,10 +11,9 @@ use std::{ use bytes::BytesMut; use crate::{ - generated::bpf_map_type::BPF_MAP_TYPE_PERF_EVENT_ARRAY, maps::{ perf::{Events, PerfBuffer, PerfBufferError}, - Map, MapError, MapRefMut, + MapData, MapError, }, sys::bpf_map_update_elem, util::page_size, @@ -26,12 +26,12 @@ use crate::{ /// /// See the [`PerfEventArray` documentation](PerfEventArray) for an overview of how to use /// perf buffers. -pub struct PerfEventArrayBuffer> { +pub struct PerfEventArrayBuffer { _map: Arc, buf: PerfBuffer, } -impl> PerfEventArrayBuffer { +impl + AsRef> PerfEventArrayBuffer { /// Returns true if the buffer contains events that haven't been read. pub fn readable(&self) -> bool { self.buf.readable() @@ -55,7 +55,7 @@ impl> PerfEventArrayBuffer { } } -impl> AsRawFd for PerfEventArrayBuffer { +impl + AsRef> AsRawFd for PerfEventArrayBuffer { fn as_raw_fd(&self) -> RawFd { self.buf.as_raw_fd() } @@ -83,15 +83,15 @@ impl> AsRawFd for PerfEventArrayBuffer { /// /// ```no_run /// # use aya::maps::perf::PerfEventArrayBuffer; -/// # use aya::maps::Map; -/// # use std::ops::DerefMut; +/// # use aya::maps::MapData; +/// # use std::convert::AsMut; /// # struct Poll { _t: std::marker::PhantomData }; -/// # impl> Poll { +/// # impl> Poll { /// # fn poll_readable(&self) -> &mut [PerfEventArrayBuffer] { /// # &mut [] /// # } /// # } -/// # fn poll_buffers>(bufs: Vec>) -> Poll { +/// # fn poll_buffers>(bufs: Vec>) -> Poll { /// # Poll { _t: std::marker::PhantomData } /// # } /// # #[derive(thiserror::Error, Debug)] @@ -105,12 +105,12 @@ impl> AsRawFd for PerfEventArrayBuffer { /// # #[error(transparent)] /// # PerfBuf(#[from] aya::maps::perf::PerfBufferError), /// # } -/// # let bpf = aya::Bpf::load(&[])?; +/// # let mut bpf = aya::Bpf::load(&[])?; /// use aya::maps::PerfEventArray; /// use aya::util::online_cpus; /// use bytes::BytesMut; /// -/// let mut perf_array = PerfEventArray::try_from(bpf.map_mut("EVENTS")?)?; +/// let mut perf_array: PerfEventArray<_> = bpf.map_mut("EVENTS")?.try_into()?; /// /// // eBPF programs are going to write to the EVENTS perf array, using the id of the CPU they're /// // running on as the array index. @@ -155,25 +155,23 @@ impl> AsRawFd for PerfEventArrayBuffer { /// [tokio]: https://docs.rs/tokio /// [async-std]: https://docs.rs/async-std #[doc(alias = "BPF_MAP_TYPE_PERF_EVENT_ARRAY")] -pub struct PerfEventArray> { +pub struct PerfEventArray { map: Arc, page_size: usize, } -impl> PerfEventArray { +impl> PerfEventArray { pub(crate) fn new(map: T) -> Result, MapError> { - let map_type = map.obj.map_type(); - if map_type != BPF_MAP_TYPE_PERF_EVENT_ARRAY as u32 { - return Err(MapError::InvalidMapType { map_type }); - } - let _fd = map.fd_or_err()?; + let _fd = map.as_ref().fd_or_err()?; Ok(PerfEventArray { map: Arc::new(map), page_size: page_size(), }) } +} +impl + AsRef> PerfEventArray { /// Opens the perf buffer at the given index. /// /// The returned buffer will receive all the events eBPF programs send at the given index. @@ -185,7 +183,8 @@ impl> PerfEventArray { // FIXME: keep track of open buffers // 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))?; bpf_map_update_elem(map_fd, Some(&index), &buf.as_raw_fd(), 0) .map_err(|(_, io_error)| io_error)?; @@ -196,11 +195,3 @@ impl> PerfEventArray { }) } } - -impl TryFrom for PerfEventArray { - type Error = MapError; - - fn try_from(a: MapRefMut) -> Result, MapError> { - PerfEventArray::new(a) - } -} diff --git a/aya/src/maps/queue.rs b/aya/src/maps/queue.rs index f8fb56b03..10dbd96ef 100644 --- a/aya/src/maps/queue.rs +++ b/aya/src/maps/queue.rs @@ -1,13 +1,12 @@ //! A FIFO queue. use std::{ + convert::{AsMut, AsRef}, marker::PhantomData, mem, - ops::{Deref, DerefMut}, }; use crate::{ - generated::bpf_map_type::BPF_MAP_TYPE_QUEUE, - maps::{Map, MapError, MapRef, MapRefMut}, + maps::{MapData, MapError}, sys::{bpf_map_lookup_and_delete_elem, bpf_map_push_elem}, Pod, }; @@ -20,39 +19,36 @@ use crate::{ /// /// # Examples /// ```no_run -/// # let bpf = aya::Bpf::load(&[])?; +/// # let mut bpf = aya::Bpf::load(&[])?; /// use aya::maps::Queue; /// -/// let mut queue = Queue::try_from(bpf.map_mut("ARRAY")?)?; +/// let mut queue: Queue<_, u32> = bpf.map_mut("ARRAY")?.try_into()?; /// queue.push(42, 0)?; /// queue.push(43, 0)?; /// assert_eq!(queue.pop(0)?, 42); /// # Ok::<(), aya::BpfError>(()) /// ``` #[doc(alias = "BPF_MAP_TYPE_QUEUE")] -pub struct Queue, V: Pod> { +pub struct Queue { inner: T, _v: PhantomData, } -impl, V: Pod> Queue { - fn new(map: T) -> Result, MapError> { - let map_type = map.obj.map_type(); - if map_type != BPF_MAP_TYPE_QUEUE as u32 { - return Err(MapError::InvalidMapType { map_type }); - } +impl, V: Pod> Queue { + pub(crate) fn new(map: T) -> Result, MapError> { + let data = map.as_ref(); let expected = 0; - let size = map.obj.key_size() as usize; + let size = data.obj.key_size() as usize; if size != expected { return Err(MapError::InvalidKeySize { size, expected }); } let expected = mem::size_of::(); - let size = map.obj.value_size() as usize; + let size = data.obj.value_size() as usize; if size != expected { return Err(MapError::InvalidValueSize { size, expected }); } - let _fd = map.fd_or_err()?; + let _fd = data.fd_or_err()?; Ok(Queue { inner: map, @@ -64,11 +60,11 @@ impl, V: Pod> Queue { /// /// This corresponds to the value of `bpf_map_def::max_entries` on the eBPF side. pub fn capacity(&self) -> u32 { - self.inner.obj.max_entries() + self.inner.as_ref().obj.max_entries() } } -impl + DerefMut, V: Pod> Queue { +impl, V: Pod> Queue { /// Removes the first element and returns it. /// /// # Errors @@ -76,7 +72,7 @@ impl + DerefMut, V: Pod> Queue { /// Returns [`MapError::ElementNotFound`] if the queue is empty, [`MapError::SyscallError`] /// if `bpf_map_lookup_and_delete_elem` fails. pub fn pop(&mut self, flags: u64) -> Result { - let fd = self.inner.fd_or_err()?; + let fd = self.inner.as_mut().fd_or_err()?; let value = bpf_map_lookup_and_delete_elem::(fd, None, flags).map_err( |(_, io_error)| MapError::SyscallError { @@ -93,7 +89,7 @@ impl + DerefMut, V: Pod> Queue { /// /// [`MapError::SyscallError`] if `bpf_map_update_elem` fails. 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 { call: "bpf_map_push_elem".to_owned(), io_error, @@ -101,19 +97,3 @@ impl + DerefMut, V: Pod> Queue { Ok(()) } } - -impl TryFrom for Queue { - type Error = MapError; - - fn try_from(a: MapRef) -> Result, MapError> { - Queue::new(a) - } -} - -impl TryFrom for Queue { - type Error = MapError; - - fn try_from(a: MapRefMut) -> Result, MapError> { - Queue::new(a) - } -} diff --git a/aya/src/maps/sock/sock_hash.rs b/aya/src/maps/sock/sock_hash.rs index e6350f78d..617fbe8de 100644 --- a/aya/src/maps/sock/sock_hash.rs +++ b/aya/src/maps/sock/sock_hash.rs @@ -1,14 +1,11 @@ use std::{ + convert::{AsMut, AsRef}, marker::PhantomData, - ops::{Deref, DerefMut}, os::unix::io::{AsRawFd, RawFd}, }; use crate::{ - generated::bpf_map_type::BPF_MAP_TYPE_SOCKHASH, - maps::{ - hash_map, sock::SocketMap, IterableMap, Map, MapError, MapIter, MapKeys, MapRef, MapRefMut, - }, + maps::{hash_map, sock::SocketMap, IterableMap, MapData, MapError, MapIter, MapKeys}, sys::bpf_map_lookup_elem, Pod, }; @@ -47,7 +44,7 @@ use crate::{ /// use aya::maps::SockHash; /// use aya::programs::SkMsg; /// -/// let mut intercept_egress = SockHash::try_from(bpf.map_mut("INTERCEPT_EGRESS")?)?; +/// let mut intercept_egress: SockHash<_, u32> = bpf.take_map("INTERCEPT_EGRESS")?.try_into()?; /// let prog: &mut SkMsg = bpf.program_mut("intercept_egress_packet").unwrap().try_into()?; /// prog.load()?; /// prog.attach(&intercept_egress)?; @@ -60,21 +57,16 @@ use crate::{ /// # Ok::<(), Error>(()) /// ``` #[doc(alias = "BPF_MAP_TYPE_SOCKHASH")] -pub struct SockHash, K> { +pub struct SockHash { inner: T, _k: PhantomData, } -impl, K: Pod> SockHash { +impl, K: Pod> SockHash { pub(crate) fn new(map: T) -> Result, MapError> { - let map_type = map.obj.map_type(); - - // validate the map definition - if map_type != BPF_MAP_TYPE_SOCKHASH as u32 { - return Err(MapError::InvalidMapType { map_type }); - } - hash_map::check_kv_size::(&map)?; - let _ = map.fd_or_err()?; + let data = map.as_ref(); + hash_map::check_kv_size::(data)?; + let _ = data.fd_or_err()?; Ok(SockHash { inner: map, @@ -84,7 +76,7 @@ impl, K: Pod> SockHash { /// Returns the fd of the socket stored at the given key. pub fn get(&self, key: &K, flags: u64) -> Result { - 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)| { MapError::SyscallError { call: "bpf_map_lookup_elem".to_owned(), @@ -103,25 +95,25 @@ impl, K: Pod> SockHash { /// An iterator visiting all keys in arbitrary order. The iterator element /// type is `Result`. pub fn keys(&self) -> MapKeys<'_, K> { - MapKeys::new(&self.inner) + MapKeys::new(self.inner.as_ref()) } } -impl, K: Pod> SockHash { +impl, K: Pod> SockHash { /// Inserts a socket under the given key. pub fn insert(&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. 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, K: Pod> IterableMap for SockHash { - fn map(&self) -> &Map { - &self.inner +impl, K: Pod> IterableMap for SockHash { + fn map(&self) -> &MapData { + self.inner.as_ref() } fn get(&self, key: &K) -> Result { @@ -129,24 +121,8 @@ impl, K: Pod> IterableMap for SockHash { } } -impl, K: Pod> SocketMap for SockHash { +impl, K: Pod> SocketMap for SockHash { fn fd_or_err(&self) -> Result { - self.inner.fd_or_err() - } -} - -impl TryFrom for SockHash { - type Error = MapError; - - fn try_from(a: MapRef) -> Result, MapError> { - SockHash::new(a) - } -} - -impl TryFrom for SockHash { - type Error = MapError; - - fn try_from(a: MapRefMut) -> Result, MapError> { - SockHash::new(a) + self.inner.as_ref().fd_or_err() } } diff --git a/aya/src/maps/sock/sock_map.rs b/aya/src/maps/sock/sock_map.rs index 542f6102b..c93a3c5bd 100644 --- a/aya/src/maps/sock/sock_map.rs +++ b/aya/src/maps/sock/sock_map.rs @@ -1,14 +1,13 @@ //! An array of eBPF program file descriptors used as a jump table. use std::{ + convert::{AsMut, AsRef}, mem, - ops::{Deref, DerefMut}, os::unix::{io::AsRawFd, prelude::RawFd}, }; use crate::{ - generated::bpf_map_type::BPF_MAP_TYPE_SOCKMAP, - maps::{sock::SocketMap, Map, MapError, MapKeys, MapRef, MapRefMut}, + maps::{sock::SocketMap, MapData, MapError, MapKeys}, sys::{bpf_map_delete_elem, bpf_map_update_elem}, }; @@ -32,35 +31,32 @@ use crate::{ /// use aya::maps::SockMap; /// use aya::programs::SkSkb; /// -/// let intercept_ingress = SockMap::try_from(bpf.map_mut("INTERCEPT_INGRESS")?)?; +/// let intercept_ingress: SockMap<_> = bpf.take_map("INTERCEPT_INGRESS")?.try_into()?; /// let prog: &mut SkSkb = bpf.program_mut("intercept_ingress_packet").unwrap().try_into()?; /// prog.load()?; /// prog.attach(&intercept_ingress)?; /// # Ok::<(), aya::BpfError>(()) /// ``` #[doc(alias = "BPF_MAP_TYPE_SOCKMAP")] -pub struct SockMap> { +pub struct SockMap> { pub(crate) inner: T, } -impl> SockMap { - fn new(map: T) -> Result, MapError> { - let map_type = map.obj.map_type(); - if map_type != BPF_MAP_TYPE_SOCKMAP as u32 { - return Err(MapError::InvalidMapType { map_type }); - } +impl> SockMap { + pub(crate) fn new(map: T) -> Result, MapError> { + let data = map.as_ref(); let expected = mem::size_of::(); - let size = map.obj.key_size() as usize; + let size = data.obj.key_size() as usize; if size != expected { return Err(MapError::InvalidKeySize { size, expected }); } let expected = mem::size_of::(); - let size = map.obj.value_size() as usize; + let size = data.obj.value_size() as usize; if size != expected { return Err(MapError::InvalidValueSize { size, expected }); } - let _fd = map.fd_or_err()?; + let _fd = data.fd_or_err()?; Ok(SockMap { inner: map }) } @@ -68,12 +64,12 @@ impl> SockMap { /// An iterator over the indices of the array that point to a program. The iterator item type /// is `Result`. 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() { + let max_entries = self.inner.as_ref().obj.max_entries(); + if index >= self.inner.as_ref().obj.max_entries() { Err(MapError::OutOfBounds { index, max_entries }) } else { Ok(()) @@ -81,10 +77,10 @@ impl> SockMap { } } -impl + DerefMut> SockMap { +impl + AsMut> SockMap { /// Stores a socket into the map. pub fn set(&mut self, index: u32, socket: &I, flags: u64) -> Result<(), MapError> { - let fd = self.inner.fd_or_err()?; + let fd = self.inner.as_ref().fd_or_err()?; self.check_bounds(index)?; bpf_map_update_elem(fd, Some(&index), &socket.as_raw_fd(), flags).map_err( |(_, io_error)| MapError::SyscallError { @@ -97,7 +93,7 @@ impl + DerefMut> SockMap { /// Removes the socket stored at `index` from the map. pub fn clear_index(&mut self, index: &u32) -> Result<(), MapError> { - let fd = self.inner.fd_or_err()?; + let fd = self.inner.as_ref().fd_or_err()?; self.check_bounds(*index)?; bpf_map_delete_elem(fd, index) .map(|_| ()) @@ -108,24 +104,8 @@ impl + DerefMut> SockMap { } } -impl + DerefMut> SocketMap for SockMap { +impl + AsMut> SocketMap for SockMap { fn fd_or_err(&self) -> Result { - self.inner.fd_or_err() - } -} - -impl TryFrom for SockMap { - type Error = MapError; - - fn try_from(a: MapRef) -> Result, MapError> { - SockMap::new(a) - } -} - -impl TryFrom for SockMap { - type Error = MapError; - - fn try_from(a: MapRefMut) -> Result, MapError> { - SockMap::new(a) + self.inner.as_ref().fd_or_err() } } diff --git a/aya/src/maps/stack.rs b/aya/src/maps/stack.rs index 601c11946..dcff48320 100644 --- a/aya/src/maps/stack.rs +++ b/aya/src/maps/stack.rs @@ -1,13 +1,12 @@ //! A LIFO stack. use std::{ + convert::{AsMut, AsRef}, marker::PhantomData, mem, - ops::{Deref, DerefMut}, }; use crate::{ - generated::bpf_map_type::BPF_MAP_TYPE_STACK, - maps::{Map, MapError, MapRef, MapRefMut}, + maps::{MapData, MapError}, sys::{bpf_map_lookup_and_delete_elem, bpf_map_update_elem}, Pod, }; @@ -20,39 +19,36 @@ use crate::{ /// /// # Examples /// ```no_run -/// # let bpf = aya::Bpf::load(&[])?; +/// # let mut bpf = aya::Bpf::load(&[])?; /// use aya::maps::Stack; /// -/// let mut stack = Stack::try_from(bpf.map_mut("STACK")?)?; +/// let mut stack: Stack<_, u32> = bpf.map_mut("STACK")?.try_into()?; /// stack.push(42, 0)?; /// stack.push(43, 0)?; /// assert_eq!(stack.pop(0)?, 43); /// # Ok::<(), aya::BpfError>(()) /// ``` #[doc(alias = "BPF_MAP_TYPE_STACK")] -pub struct Stack, V: Pod> { +pub struct Stack { inner: T, _v: PhantomData, } -impl, V: Pod> Stack { - fn new(map: T) -> Result, MapError> { - let map_type = map.obj.map_type(); - if map_type != BPF_MAP_TYPE_STACK as u32 { - return Err(MapError::InvalidMapType { map_type }); - } +impl, V: Pod> Stack { + pub(crate) fn new(map: T) -> Result, MapError> { + let data = map.as_ref(); let expected = 0; - let size = map.obj.key_size() as usize; + let size = data.obj.key_size() as usize; if size != expected { return Err(MapError::InvalidKeySize { size, expected }); } let expected = mem::size_of::(); - let size = map.obj.value_size() as usize; + let size = data.obj.value_size() as usize; if size != expected { return Err(MapError::InvalidValueSize { size, expected }); } - let _fd = map.fd_or_err()?; + let _fd = data.fd_or_err()?; Ok(Stack { inner: map, @@ -64,11 +60,11 @@ impl, V: Pod> Stack { /// /// This corresponds to the value of `bpf_map_def::max_entries` on the eBPF side. pub fn capacity(&self) -> u32 { - self.inner.obj.max_entries() + self.inner.as_ref().obj.max_entries() } } -impl + DerefMut, V: Pod> Stack { +impl, V: Pod> Stack { /// Removes the last element and returns it. /// /// # Errors @@ -76,7 +72,7 @@ impl + DerefMut, V: Pod> Stack { /// Returns [`MapError::ElementNotFound`] if the stack is empty, [`MapError::SyscallError`] /// if `bpf_map_lookup_and_delete_elem` fails. pub fn pop(&mut self, flags: u64) -> Result { - let fd = self.inner.fd_or_err()?; + let fd = self.inner.as_mut().fd_or_err()?; let value = bpf_map_lookup_and_delete_elem::(fd, None, flags).map_err( |(_, io_error)| MapError::SyscallError { @@ -93,7 +89,7 @@ impl + DerefMut, V: Pod> Stack { /// /// [`MapError::SyscallError`] if `bpf_map_update_elem` fails. 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)| { MapError::SyscallError { call: "bpf_map_update_elem".to_owned(), @@ -103,19 +99,3 @@ impl + DerefMut, V: Pod> Stack { Ok(()) } } - -impl TryFrom for Stack { - type Error = MapError; - - fn try_from(a: MapRef) -> Result, MapError> { - Stack::new(a) - } -} - -impl TryFrom for Stack { - type Error = MapError; - - fn try_from(a: MapRefMut) -> Result, MapError> { - Stack::new(a) - } -} diff --git a/aya/src/maps/stack_trace.rs b/aya/src/maps/stack_trace.rs index 0b7113f11..51d89fe46 100644 --- a/aya/src/maps/stack_trace.rs +++ b/aya/src/maps/stack_trace.rs @@ -1,11 +1,10 @@ //! A hash map of kernel or user space stack traces. //! //! 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::{ - generated::bpf_map_type::BPF_MAP_TYPE_STACK_TRACE, - maps::{IterableMap, Map, MapError, MapIter, MapKeys, MapRef, MapRefMut}, + maps::{IterableMap, MapData, MapError, MapIter, MapKeys}, sys::bpf_map_lookup_elem_ptr, }; @@ -68,14 +67,11 @@ pub struct StackTraceMap { max_stack_depth: usize, } -impl> StackTraceMap { - fn new(map: T) -> Result, MapError> { - let map_type = map.obj.map_type(); - if map_type != BPF_MAP_TYPE_STACK_TRACE as u32 { - return Err(MapError::InvalidMapType { map_type }); - } +impl> StackTraceMap { + pub(crate) fn new(map: T) -> Result, MapError> { + let data = map.as_ref(); let expected = mem::size_of::(); - let size = map.obj.key_size() as usize; + let size = data.obj.key_size() as usize; if size != expected { return Err(MapError::InvalidKeySize { size, expected }); } @@ -87,11 +83,11 @@ impl> StackTraceMap { 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::() { return Err(MapError::InvalidValueSize { size, expected }); } - let _fd = map.fd_or_err()?; + let _fd = data.fd_or_err()?; Ok(StackTraceMap { inner: map, @@ -106,7 +102,7 @@ impl> StackTraceMap { /// Returns [`MapError::KeyNotFound`] if there is no stack trace with the /// given `stack_id`, or [`MapError::SyscallError`] if `bpf_map_lookup_elem` fails. pub fn get(&self, stack_id: &u32, flags: u64) -> Result { - 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]; bpf_map_lookup_elem_ptr(fd, Some(stack_id), frames.as_mut_ptr(), flags) @@ -140,13 +136,13 @@ impl> StackTraceMap { /// An iterator visiting all the stack_ids in arbitrary order. The iterator element /// type is `Result`. pub fn stack_ids(&self) -> MapKeys<'_, u32> { - MapKeys::new(&self.inner) + MapKeys::new(self.inner.as_ref()) } } -impl> IterableMap for StackTraceMap { - fn map(&self) -> &Map { - &self.inner +impl> IterableMap for StackTraceMap { + fn map(&self) -> &MapData { + self.inner.as_ref() } fn get(&self, index: &u32) -> Result { @@ -154,23 +150,7 @@ impl> IterableMap for StackTraceMap { } } -impl TryFrom for StackTraceMap { - type Error = MapError; - - fn try_from(a: MapRef) -> Result, MapError> { - StackTraceMap::new(a) - } -} - -impl TryFrom for StackTraceMap { - type Error = MapError; - - fn try_from(a: MapRefMut) -> Result, MapError> { - StackTraceMap::new(a) - } -} - -impl<'a, T: Deref> IntoIterator for &'a StackTraceMap { +impl<'a, T: AsRef> IntoIterator for &'a StackTraceMap { type Item = Result<(u32, StackTrace), MapError>; type IntoIter = MapIter<'a, u32, StackTrace, StackTraceMap>; diff --git a/aya/src/obj/relocation.rs b/aya/src/obj/relocation.rs index 4be758ff3..1564084a7 100644 --- a/aya/src/obj/relocation.rs +++ b/aya/src/obj/relocation.rs @@ -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_PSEUDO_MAP_VALUE, }, - maps::Map, + maps::MapData, obj::{Function, Object, Program}, BpfError, }; @@ -62,7 +62,7 @@ pub(crate) struct Symbol { } impl Object { - pub fn relocate_maps(&mut self, maps: &HashMap) -> Result<(), BpfError> { + pub fn relocate_maps(&mut self, maps: &HashMap) -> Result<(), BpfError> { let maps_by_section = maps .iter() .map(|(name, map)| (map.obj.section_index(), (name.as_str(), map))) @@ -122,8 +122,8 @@ impl Object { fn relocate_maps<'a, I: Iterator>( fun: &mut Function, relocations: I, - maps_by_section: &HashMap, - maps_by_symbol: &HashMap, + maps_by_section: &HashMap, + maps_by_symbol: &HashMap, symbol_table: &HashMap, text_section_index: Option, ) -> Result<(), RelocationError> { @@ -438,6 +438,7 @@ fn insn_is_call(ins: &bpf_insn) -> bool { mod test { use crate::{ bpf_map_def, + maps::MapData, obj::{self, BtfMap, LegacyMap, MapKind}, BtfMapDef, }; @@ -460,8 +461,8 @@ mod test { unsafe { std::ptr::read_unaligned(bytes.as_ptr() as *const _) } } - fn fake_legacy_map(fd: i32, symbol_index: usize) -> Map { - Map { + fn fake_legacy_map(fd: i32, symbol_index: usize) -> MapData { + MapData { obj: obj::Map::Legacy(LegacyMap { def: bpf_map_def { ..Default::default() @@ -477,8 +478,8 @@ mod test { } } - fn fake_btf_map(fd: i32, symbol_index: usize) -> Map { - Map { + fn fake_btf_map(fd: i32, symbol_index: usize) -> MapData { + MapData { obj: obj::Map::Btf(BtfMap { def: BtfMapDef { ..Default::default() diff --git a/aya/src/programs/sk_msg.rs b/aya/src/programs/sk_msg.rs index e801f9ff5..1792cb96e 100644 --- a/aya/src/programs/sk_msg.rs +++ b/aya/src/programs/sk_msg.rs @@ -40,7 +40,7 @@ use crate::{ /// use aya::maps::SockHash; /// use aya::programs::SkMsg; /// -/// let mut intercept_egress = SockHash::try_from(bpf.map_mut("INTERCEPT_EGRESS")?)?; +/// let mut intercept_egress: SockHash<_, u32> = bpf.take_map("INTERCEPT_EGRESS")?.try_into()?; /// let prog: &mut SkMsg = bpf.program_mut("intercept_egress_packet").unwrap().try_into()?; /// prog.load()?; /// prog.attach(&intercept_egress)?; diff --git a/aya/src/programs/sk_skb.rs b/aya/src/programs/sk_skb.rs index f8766e4be..228b29946 100644 --- a/aya/src/programs/sk_skb.rs +++ b/aya/src/programs/sk_skb.rs @@ -38,7 +38,7 @@ pub enum SkSkbKind { /// use aya::maps::SockMap; /// use aya::programs::SkSkb; /// -/// let intercept_ingress = SockMap::try_from(bpf.map_mut("INTERCEPT_INGRESS")?)?; +/// let intercept_ingress: SockMap<_> = bpf.take_map("INTERCEPT_INGRESS")?.try_into()?; /// let prog: &mut SkSkb = bpf.program_mut("intercept_ingress_packet").unwrap().try_into()?; /// prog.load()?; /// prog.attach(&intercept_ingress)?; diff --git a/test/integration-test/src/tests/load.rs b/test/integration-test/src/tests/load.rs index 1dbffd795..72129f276 100644 --- a/test/integration-test/src/tests/load.rs +++ b/test/integration-test/src/tests/load.rs @@ -2,7 +2,7 @@ use std::{process::Command, thread, time}; use aya::{ include_bytes_aligned, - maps::{Array, MapRefMut}, + maps::Array, programs::{ links::{FdLink, PinnedLink}, 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"); let mut bpf = Bpf::load(bytes)?; - let map_1: Array = Array::try_from(bpf.map_mut("map_1")?)?; - let map_2: Array = Array::try_from(bpf.map_mut("map_2")?)?; + let map_1: Array<_, u64> = bpf.take_map("map_1")?.try_into()?; + let map_2: Array<_, u64> = bpf.take_map("map_2")?.try_into()?; let prog: &mut TracePoint = bpf.program_mut("tracepoint").unwrap().try_into().unwrap(); prog.load().unwrap();