From 1aefa2e5e6d22a600cc7339d289d64ab06f842e3 Mon Sep 17 00:00:00 2001 From: Andrew Stoycos Date: Wed, 28 Sep 2022 17:51:56 -0400 Subject: [PATCH 1/9] 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 b56c16e6..bbff0f61 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 db1ad3be..e473802f 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 ac5c6587..8b60b8a5 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 5b762e27..c33f91cf 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 6cbfb37b..5589e306 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 aa5372cc..c51cfbb7 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 03902ae6..5e49749a 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 6e36081c..8a120201 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 60d0ec8a..92333700 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 a539965d..329a51fc 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 989ee51f..4cbc6ec7 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 18f87acf..00000000 --- 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 9d8a13d1..82bfa0c0 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 1c14fc6a..651d503a 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 2a74a437..0517cb7d 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 f8fb56b0..10dbd96e 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 e6350f78..617fbe8d 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 542f6102..c93a3c5b 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 601c1194..dcff4832 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 0b7113f1..51d89fe4 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 4be758ff..1564084a 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 e801f9ff..1792cb96 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 f8766e4b..228b2994 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 1dbffd79..72129f27 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(); From 898a14d42559c7567f45e43fccdaa741a3ac9f27 Mon Sep 17 00:00:00 2001 From: Andrew Stoycos Date: Mon, 3 Oct 2022 10:12:51 -0400 Subject: [PATCH 2/9] Use SockMapFd Create a new type called `SockMapFd` which is solely used when a program needs to attach to a socket map. In the future this same tatic could be used for other use cases so we may make this more generic. Signed-off-by: Andrew Stoycos --- aya/src/maps/mod.rs | 6 ++++-- aya/src/maps/sock/mod.rs | 18 +++++++++------- aya/src/maps/sock/sock_hash.rs | 22 +++++++++++-------- aya/src/maps/sock/sock_map.rs | 39 ++++++++++++++++++---------------- aya/src/programs/sk_msg.rs | 17 ++++++++++----- aya/src/programs/sk_skb.rs | 16 +++++++++----- 6 files changed, 71 insertions(+), 47 deletions(-) diff --git a/aya/src/maps/mod.rs b/aya/src/maps/mod.rs index 82bfa0c0..9e69e3af 100644 --- a/aya/src/maps/mod.rs +++ b/aya/src/maps/mod.rs @@ -22,10 +22,12 @@ //! use aya::maps::SockMap; //! use aya::programs::SkMsg; //! -//! let intercept_egress: SockMap<_> = bpf.take_map("INTERCEPT_EGRESS")?.try_into()?; +//! let mut intercept_egress: SockMap<_> = bpf.map_mut("INTERCEPT_EGRESS")?.try_into()?; +//! let map_fd = intercept_egress.fd()?; //! let prog: &mut SkMsg = bpf.program_mut("intercept_egress_packet").unwrap().try_into()?; //! prog.load()?; -//! prog.attach(&intercept_egress)?; +//! prog.attach(map_fd)?; +//! //! # Ok::<(), aya::BpfError>(()) //! ``` //! diff --git a/aya/src/maps/sock/mod.rs b/aya/src/maps/sock/mod.rs index ebc37b25..59979896 100644 --- a/aya/src/maps/sock/mod.rs +++ b/aya/src/maps/sock/mod.rs @@ -2,15 +2,17 @@ mod sock_hash; mod sock_map; -use std::os::unix::io::RawFd; - -use crate::maps::MapError; - pub use sock_hash::SockHash; pub use sock_map::SockMap; -/// Shared behaviour between [`SockHash`] and [`SockMap`] -pub trait SocketMap { - /// Returns a [`Result`] containg the map fd or an error if there is none - fn fd_or_err(&self) -> Result; +use std::os::unix::io::{AsRawFd, RawFd}; + +/// A [`SocketMap`] file descriptor. +#[derive(Copy, Clone)] +pub struct SockMapFd(RawFd); + +impl AsRawFd for SockMapFd { + fn as_raw_fd(&self) -> RawFd { + self.0 + } } diff --git a/aya/src/maps/sock/sock_hash.rs b/aya/src/maps/sock/sock_hash.rs index 617fbe8d..c7ceb752 100644 --- a/aya/src/maps/sock/sock_hash.rs +++ b/aya/src/maps/sock/sock_hash.rs @@ -5,7 +5,7 @@ use std::{ }; use crate::{ - maps::{hash_map, sock::SocketMap, IterableMap, MapData, MapError, MapIter, MapKeys}, + maps::{hash_map, sock::SockMapFd, IterableMap, MapData, MapError, MapIter, MapKeys}, sys::bpf_map_lookup_elem, Pod, }; @@ -44,12 +44,16 @@ use crate::{ /// use aya::maps::SockHash; /// use aya::programs::SkMsg; /// -/// let mut intercept_egress: SockHash<_, u32> = bpf.take_map("INTERCEPT_EGRESS")?.try_into()?; +/// let intercept_egress: SockHash<_, u32> = bpf.map("INTERCEPT_EGRESS")?.try_into()?; +/// let map_fd = intercept_egress.fd()?; +/// /// let prog: &mut SkMsg = bpf.program_mut("intercept_egress_packet").unwrap().try_into()?; /// prog.load()?; -/// prog.attach(&intercept_egress)?; +/// prog.attach(map_fd)?; /// /// let mut client = TcpStream::connect("127.0.0.1:1234")?; +/// let mut intercept_egress: SockHash<_, u32> = bpf.map_mut("INTERCEPT_EGRESS")?.try_into()?; +/// /// intercept_egress.insert(1234, client.as_raw_fd(), 0)?; /// /// // the write will be intercepted @@ -97,6 +101,12 @@ impl, K: Pod> SockHash { pub fn keys(&self) -> MapKeys<'_, K> { MapKeys::new(self.inner.as_ref()) } + + /// Returns the map's file descriptor, used for instances where programs + /// are attached to maps. + pub fn fd(&self) -> Result { + Ok(SockMapFd(self.inner.as_ref().fd_or_err()?)) + } } impl, K: Pod> SockHash { @@ -120,9 +130,3 @@ impl, K: Pod> IterableMap for SockHash { SockHash::get(self, key, 0) } } - -impl, K: Pod> SocketMap for SockHash { - fn fd_or_err(&self) -> Result { - 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 c93a3c5b..b13291a9 100644 --- a/aya/src/maps/sock/sock_map.rs +++ b/aya/src/maps/sock/sock_map.rs @@ -7,7 +7,7 @@ use std::{ }; use crate::{ - maps::{sock::SocketMap, MapData, MapError, MapKeys}, + maps::{sock::SockMapFd, MapData, MapError, MapKeys}, sys::{bpf_map_delete_elem, bpf_map_update_elem}, }; @@ -31,14 +31,17 @@ use crate::{ /// use aya::maps::SockMap; /// use aya::programs::SkSkb; /// -/// let intercept_ingress: SockMap<_> = bpf.take_map("INTERCEPT_INGRESS")?.try_into()?; +/// let intercept_ingress: SockMap<_> = bpf.map("INTERCEPT_INGRESS")?.try_into()?; +/// let map_fd = intercept_ingress.fd()?; +/// /// let prog: &mut SkSkb = bpf.program_mut("intercept_ingress_packet").unwrap().try_into()?; /// prog.load()?; -/// prog.attach(&intercept_ingress)?; +/// prog.attach(map_fd)?; +/// /// # Ok::<(), aya::BpfError>(()) /// ``` #[doc(alias = "BPF_MAP_TYPE_SOCKMAP")] -pub struct SockMap> { +pub struct SockMap { pub(crate) inner: T, } @@ -67,20 +70,17 @@ impl> SockMap { MapKeys::new(self.inner.as_ref()) } - fn check_bounds(&self, index: u32) -> Result<(), MapError> { - 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(()) - } + /// Returns the map's file descriptor, used for instances where programs + /// are attached to maps. + pub fn fd(&self) -> Result { + Ok(SockMapFd(self.inner.as_ref().fd_or_err()?)) } } -impl + AsMut> SockMap { +impl> SockMap { /// Stores a socket into the map. pub fn set(&mut self, index: u32, socket: &I, flags: u64) -> Result<(), MapError> { - let fd = self.inner.as_ref().fd_or_err()?; + let fd = self.inner.as_mut().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 { @@ -93,7 +93,7 @@ impl + AsMut> SockMap { /// Removes the socket stored at `index` from the map. pub fn clear_index(&mut self, index: &u32) -> Result<(), MapError> { - let fd = self.inner.as_ref().fd_or_err()?; + let fd = self.inner.as_mut().fd_or_err()?; self.check_bounds(*index)?; bpf_map_delete_elem(fd, index) .map(|_| ()) @@ -102,10 +102,13 @@ impl + AsMut> SockMap { io_error, }) } -} -impl + AsMut> SocketMap for SockMap { - fn fd_or_err(&self) -> Result { - self.inner.as_ref().fd_or_err() + fn check_bounds(&mut self, index: u32) -> Result<(), MapError> { + let max_entries = self.inner.as_mut().obj.max_entries(); + if index >= self.inner.as_mut().obj.max_entries() { + Err(MapError::OutOfBounds { index, max_entries }) + } else { + Ok(()) + } } } diff --git a/aya/src/programs/sk_msg.rs b/aya/src/programs/sk_msg.rs index 1792cb96..867f3448 100644 --- a/aya/src/programs/sk_msg.rs +++ b/aya/src/programs/sk_msg.rs @@ -1,7 +1,10 @@ //! Skmsg programs. + +use std::os::unix::io::AsRawFd; + use crate::{ generated::{bpf_attach_type::BPF_SK_MSG_VERDICT, bpf_prog_type::BPF_PROG_TYPE_SK_MSG}, - maps::sock::SocketMap, + maps::sock::SockMapFd, programs::{ define_link_wrapper, load_program, ProgAttachLink, ProgAttachLinkId, ProgramData, ProgramError, @@ -40,12 +43,16 @@ use crate::{ /// use aya::maps::SockHash; /// use aya::programs::SkMsg; /// -/// let mut intercept_egress: SockHash<_, u32> = bpf.take_map("INTERCEPT_EGRESS")?.try_into()?; +/// let intercept_egress: SockHash<_, u32> = bpf.map("INTERCEPT_EGRESS")?.try_into()?; +/// let map_fd = intercept_egress.fd()?; +/// /// let prog: &mut SkMsg = bpf.program_mut("intercept_egress_packet").unwrap().try_into()?; /// prog.load()?; -/// prog.attach(&intercept_egress)?; +/// prog.attach(map_fd)?; /// /// let mut client = TcpStream::connect("127.0.0.1:1234")?; +/// let mut intercept_egress: SockHash<_, u32> = bpf.map_mut("INTERCEPT_EGRESS")?.try_into()?; +/// /// intercept_egress.insert(1234, client.as_raw_fd(), 0)?; /// /// // the write will be intercepted @@ -71,9 +78,9 @@ impl SkMsg { /// Attaches the program to the given sockmap. /// /// The returned value can be used to detach, see [SkMsg::detach]. - pub fn attach(&mut self, map: &dyn SocketMap) -> Result { + pub fn attach(&mut self, map: SockMapFd) -> Result { 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)| { ProgramError::SyscallError { diff --git a/aya/src/programs/sk_skb.rs b/aya/src/programs/sk_skb.rs index 228b2994..a90a2d82 100644 --- a/aya/src/programs/sk_skb.rs +++ b/aya/src/programs/sk_skb.rs @@ -1,10 +1,13 @@ //! Skskb programs. + +use std::os::unix::io::AsRawFd; + use crate::{ generated::{ bpf_attach_type::{BPF_SK_SKB_STREAM_PARSER, BPF_SK_SKB_STREAM_VERDICT}, bpf_prog_type::BPF_PROG_TYPE_SK_SKB, }, - maps::sock::SocketMap, + maps::sock::SockMapFd, programs::{ define_link_wrapper, load_program, ProgAttachLink, ProgAttachLinkId, ProgramData, ProgramError, @@ -38,10 +41,13 @@ pub enum SkSkbKind { /// use aya::maps::SockMap; /// use aya::programs::SkSkb; /// -/// let intercept_ingress: SockMap<_> = bpf.take_map("INTERCEPT_INGRESS")?.try_into()?; +/// let intercept_ingress: SockMap<_> = bpf.map("INTERCEPT_INGRESS")?.try_into()?; +/// let map_fd = intercept_ingress.fd()?; +/// /// let prog: &mut SkSkb = bpf.program_mut("intercept_ingress_packet").unwrap().try_into()?; /// prog.load()?; -/// prog.attach(&intercept_ingress)?; +/// prog.attach(map_fd)?; +/// /// # Ok::<(), aya::BpfError>(()) /// ``` /// @@ -64,9 +70,9 @@ impl SkSkb { /// Attaches the program to the given socket map. /// /// The returned value can be used to detach, see [SkSkb::detach]. - pub fn attach(&mut self, map: &dyn SocketMap) -> Result { + pub fn attach(&mut self, map: SockMapFd) -> Result { 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 { SkSkbKind::StreamParser => BPF_SK_SKB_STREAM_PARSER, From 893f9f44a22d4c78d86107cdac1204c4da65938a Mon Sep 17 00:00:00 2001 From: Andrew Stoycos Date: Mon, 3 Oct 2022 12:28:51 -0400 Subject: [PATCH 3/9] Implement Copy for MapData Implement Copy for MapData so that when `take_map` is used we create a 1 to 1 mapping of MapData to internal FileDescriptor. This will ensure that when MapData is used in multiple tasks that we don't drop the FD before all tasks are done using it. Signed-off-by: Andrew Stoycos --- aya/src/maps/mod.rs | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/aya/src/maps/mod.rs b/aya/src/maps/mod.rs index 9e69e3af..4abcf3af 100644 --- a/aya/src/maps/mod.rs +++ b/aya/src/maps/mod.rs @@ -413,7 +413,7 @@ 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, Clone)] +#[derive(Debug)] pub struct MapData { pub(crate) obj: obj::Map, pub(crate) fd: Option, @@ -577,6 +577,22 @@ impl Drop for MapData { } } +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 pub trait IterableMap { /// Get a generic map handle From 8009361694a7f8967a31734d109f79a6b26516dc Mon Sep 17 00:00:00 2001 From: Andrew Stoycos Date: Tue, 4 Oct 2022 14:09:34 -0400 Subject: [PATCH 4/9] Fixups Respond to review comments, specifically: - Remove Map::map_type() - Update some comments - remove `docs` from feature macros - generalize check_bounds, check_kv_size, and check_v_size functions to remove duplicate code Signed-off-by: Andrew Stoycos --- aya/src/bpf.rs | 16 ++++++--- aya/src/maps/array/array.rs | 18 +++------- aya/src/maps/array/mod.rs | 11 ------- aya/src/maps/array/per_cpu_array.rs | 18 +++------- aya/src/maps/array/program_array.rs | 18 +++------- aya/src/maps/bloom_filter.rs | 10 ++---- aya/src/maps/hash_map/hash_map.rs | 4 +-- aya/src/maps/hash_map/mod.rs | 16 --------- aya/src/maps/hash_map/per_cpu_hash_map.rs | 14 +++----- aya/src/maps/lpm_trie.rs | 13 ++------ aya/src/maps/mod.rs | 40 +++++++++++++++++++---- aya/src/maps/queue.rs | 14 ++------ aya/src/maps/sock/sock_hash.rs | 6 ++-- aya/src/maps/sock/sock_map.rs | 33 +++++-------------- aya/src/maps/stack.rs | 14 ++------ 15 files changed, 83 insertions(+), 162 deletions(-) diff --git a/aya/src/bpf.rs b/aya/src/bpf.rs index e473802f..6b54fa51 100644 --- a/aya/src/bpf.rs +++ b/aya/src/bpf.rs @@ -13,7 +13,7 @@ use thiserror::Error; use crate::{ generated::{ - bpf_map_type::*, AYA_PERF_EVENT_IOC_DISABLE, AYA_PERF_EVENT_IOC_ENABLE, + bpf_map_type, bpf_map_type::*, AYA_PERF_EVENT_IOC_DISABLE, AYA_PERF_EVENT_IOC_ENABLE, AYA_PERF_EVENT_IOC_SET_BPF, }, maps::{Map, MapData, MapError}, @@ -650,14 +650,16 @@ impl<'a> BpfLoader<'a> { 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_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 => Ok(Map::PerfEventArray(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)), @@ -770,9 +772,13 @@ impl Bpf { }) } - /// Returns a map with the given name. + /// Takes ownership of a map with the given name. /// - /// WARNING: This transfers ownership of the map to the user. + /// This API is intended for cases where the map must be moved into spawned + /// task. For example, when using an [`AsyncPerfEventArray`]. For map interactions + /// without taking ownership, see `map` or `map_mut`. An owned map will be + /// closed on `Drop`, therefore the the caller is now responsible for managing + /// its lifetime. /// /// 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). diff --git a/aya/src/maps/array/array.rs b/aya/src/maps/array/array.rs index 8b60b8a5..d661be18 100644 --- a/aya/src/maps/array/array.rs +++ b/aya/src/maps/array/array.rs @@ -1,11 +1,10 @@ use std::{ convert::{AsMut, AsRef}, marker::PhantomData, - mem, }; use crate::{ - maps::{array, IterableMap, MapData, MapError}, + maps::{check_bounds, check_kv_size, IterableMap, MapData, MapError}, sys::{bpf_map_lookup_elem, bpf_map_update_elem}, Pod, }; @@ -38,17 +37,8 @@ pub struct Array { impl, V: Pod> Array { pub(crate) fn new(map: T) -> Result, MapError> { let data = map.as_ref(); - let expected = mem::size_of::(); - let size = data.obj.key_size() as usize; - if size != expected { - return Err(MapError::InvalidKeySize { size, expected }); - } + check_kv_size::(data)?; - let expected = mem::size_of::(); - let size = data.obj.value_size() as usize; - if size != expected { - return Err(MapError::InvalidValueSize { size, expected }); - } let _fd = data.fd_or_err()?; Ok(Array { @@ -72,7 +62,7 @@ impl, V: Pod> Array { /// if `bpf_map_lookup_elem` fails. pub fn get(&self, index: &u32, flags: u64) -> Result { let data = self.inner.as_ref(); - array::check_bounds(data, *index)?; + check_bounds(data, *index)?; let fd = data.fd_or_err()?; let value = bpf_map_lookup_elem(fd, index, flags).map_err(|(_, io_error)| { @@ -100,7 +90,7 @@ impl, V: Pod> Array { /// if `bpf_map_update_elem` fails. pub fn set(&mut self, index: u32, value: V, flags: u64) -> Result<(), MapError> { let data = self.inner.as_mut(); - array::check_bounds(data, index)?; + 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 { diff --git a/aya/src/maps/array/mod.rs b/aya/src/maps/array/mod.rs index c33f91cf..728e4851 100644 --- a/aya/src/maps/array/mod.rs +++ b/aya/src/maps/array/mod.rs @@ -7,14 +7,3 @@ mod program_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 5589e306..d9a4f73c 100644 --- a/aya/src/maps/array/per_cpu_array.rs +++ b/aya/src/maps/array/per_cpu_array.rs @@ -1,11 +1,10 @@ use std::{ convert::{AsMut, AsRef}, marker::PhantomData, - mem, }; use crate::{ - maps::{array, IterableMap, MapData, MapError, PerCpuValues}, + maps::{check_bounds, check_kv_size, IterableMap, MapData, MapError, PerCpuValues}, sys::{bpf_map_lookup_elem_per_cpu, bpf_map_update_elem_per_cpu}, Pod, }; @@ -57,17 +56,8 @@ pub struct PerCpuArray { impl, V: Pod> PerCpuArray { pub(crate) fn new(map: T) -> Result, MapError> { let data = map.as_ref(); - let expected = mem::size_of::(); - let size = data.obj.key_size() as usize; - if size != expected { - return Err(MapError::InvalidKeySize { size, expected }); - } + check_kv_size::(data)?; - let expected = mem::size_of::(); - let size = data.obj.value_size() as usize; - if size != expected { - return Err(MapError::InvalidValueSize { size, expected }); - } let _fd = data.fd_or_err()?; Ok(PerCpuArray { @@ -91,7 +81,7 @@ impl, V: Pod> PerCpuArray { /// if `bpf_map_lookup_elem` fails. pub fn get(&self, index: &u32, flags: u64) -> Result, MapError> { let data = self.inner.as_ref(); - array::check_bounds(data, *index)?; + 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)| { @@ -119,7 +109,7 @@ impl, V: Pod> PerCpuArray { /// if `bpf_map_update_elem` fails. pub fn set(&mut self, index: u32, values: PerCpuValues, flags: u64) -> Result<(), MapError> { let data = self.inner.as_mut(); - array::check_bounds(data, 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)| { diff --git a/aya/src/maps/array/program_array.rs b/aya/src/maps/array/program_array.rs index c51cfbb7..5245d001 100644 --- a/aya/src/maps/array/program_array.rs +++ b/aya/src/maps/array/program_array.rs @@ -2,12 +2,11 @@ use std::{ convert::{AsMut, AsRef}, - mem, os::unix::prelude::{AsRawFd, RawFd}, }; use crate::{ - maps::{array, MapData, MapError, MapKeys}, + maps::{check_bounds, check_kv_size, MapData, MapError, MapKeys}, programs::ProgramFd, sys::{bpf_map_delete_elem, bpf_map_update_elem}, }; @@ -55,17 +54,8 @@ pub struct ProgramArray { impl> ProgramArray { pub(crate) fn new(map: T) -> Result, MapError> { let data = map.as_ref(); - let expected = mem::size_of::(); - let size = data.obj.key_size() as usize; - if size != expected { - return Err(MapError::InvalidKeySize { size, expected }); - } + check_kv_size::(data)?; - let expected = mem::size_of::(); - let size = data.obj.value_size() as usize; - if size != expected { - return Err(MapError::InvalidValueSize { size, expected }); - } let _fd = data.fd_or_err()?; Ok(ProgramArray { inner: map }) @@ -85,7 +75,7 @@ impl> ProgramArray { /// flow will jump to `program`. pub fn set(&mut self, index: u32, program: ProgramFd, flags: u64) -> Result<(), MapError> { let data = self.inner.as_mut(); - array::check_bounds(data, index)?; + check_bounds(data, index)?; let fd = data.fd_or_err()?; let prog_fd = program.as_raw_fd(); @@ -104,7 +94,7 @@ impl> ProgramArray { /// error. pub fn clear_index(&mut self, index: &u32) -> Result<(), MapError> { let data = self.inner.as_mut(); - array::check_bounds(data, *index)?; + check_bounds(data, *index)?; let fd = self.inner.as_mut().fd_or_err()?; bpf_map_delete_elem(fd, index) diff --git a/aya/src/maps/bloom_filter.rs b/aya/src/maps/bloom_filter.rs index 5e49749a..7a540367 100644 --- a/aya/src/maps/bloom_filter.rs +++ b/aya/src/maps/bloom_filter.rs @@ -1,10 +1,8 @@ //! A Bloom Filter. use std::{convert::AsRef, marker::PhantomData}; -use core::mem; - use crate::{ - maps::{MapData, MapError}, + maps::{check_v_size, MapData, MapError}, sys::{bpf_map_lookup_elem_ptr, bpf_map_push_elem}, Pod, }; @@ -40,11 +38,7 @@ pub struct BloomFilter { impl, V: Pod> BloomFilter { pub(crate) fn new(map: T) -> Result, MapError> { let data = map.as_ref(); - let size = mem::size_of::(); - let expected = data.obj.value_size() as usize; - if size != expected { - return Err(MapError::InvalidValueSize { size, expected }); - }; + check_v_size::(data)?; let _ = data.fd_or_err()?; diff --git a/aya/src/maps/hash_map/hash_map.rs b/aya/src/maps/hash_map/hash_map.rs index 8a120201..474337bd 100644 --- a/aya/src/maps/hash_map/hash_map.rs +++ b/aya/src/maps/hash_map/hash_map.rs @@ -4,7 +4,7 @@ use std::{ }; use crate::{ - maps::{hash_map, IterableMap, MapData, MapError, MapIter, MapKeys}, + maps::{check_kv_size, hash_map, IterableMap, MapData, MapError, MapIter, MapKeys}, sys::bpf_map_lookup_elem, Pod, }; @@ -41,7 +41,7 @@ pub struct HashMap { impl, K: Pod, V: Pod> HashMap { pub(crate) fn new(map: T) -> Result, MapError> { let data = map.as_ref(); - hash_map::check_kv_size::(data)?; + check_kv_size::(data)?; let _ = data.fd_or_err()?; Ok(HashMap { diff --git a/aya/src/maps/hash_map/mod.rs b/aya/src/maps/hash_map/mod.rs index 92333700..5be375c9 100644 --- a/aya/src/maps/hash_map/mod.rs +++ b/aya/src/maps/hash_map/mod.rs @@ -1,6 +1,4 @@ //! Hash map types. -use std::mem; - use crate::{ maps::MapError, sys::{bpf_map_delete_elem, bpf_map_update_elem}, @@ -15,20 +13,6 @@ pub use per_cpu_hash_map::*; 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 { - return Err(MapError::InvalidKeySize { size, expected }); - } - let size = mem::size_of::(); - let expected = map.obj.value_size() as usize; - if size != expected { - return Err(MapError::InvalidValueSize { size, expected }); - }; - Ok(()) -} - pub(crate) fn insert( map: &mut MapData, key: K, 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 329a51fc..946ab63a 100644 --- a/aya/src/maps/hash_map/per_cpu_hash_map.rs +++ b/aya/src/maps/hash_map/per_cpu_hash_map.rs @@ -5,8 +5,9 @@ use std::{ }; use crate::{ - generated::bpf_map_type::{BPF_MAP_TYPE_LRU_PERCPU_HASH, BPF_MAP_TYPE_PERCPU_HASH}, - maps::{hash_map, IterableMap, MapData, MapError, MapIter, MapKeys, PerCpuValues}, + maps::{ + check_kv_size, hash_map, IterableMap, MapData, MapError, MapIter, MapKeys, PerCpuValues, + }, sys::{bpf_map_lookup_elem_per_cpu, bpf_map_update_elem_per_cpu}, Pod, }; @@ -49,15 +50,8 @@ pub struct PerCpuHashMap { impl, K: Pod, V: Pod> PerCpuHashMap { pub(crate) fn new(map: T) -> Result, MapError> { let data = map.as_ref(); - let map_type = data.obj.map_type(); + check_kv_size::(data)?; - // validate the map definition - 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::(data)?; let _ = data.fd_or_err()?; Ok(PerCpuHashMap { diff --git a/aya/src/maps/lpm_trie.rs b/aya/src/maps/lpm_trie.rs index 4cbc6ec7..ae479529 100644 --- a/aya/src/maps/lpm_trie.rs +++ b/aya/src/maps/lpm_trie.rs @@ -6,7 +6,7 @@ use std::{ }; use crate::{ - maps::{IterableMap, MapData, MapError}, + maps::{check_kv_size, IterableMap, MapData, MapError}, sys::{bpf_map_delete_elem, bpf_map_lookup_elem, bpf_map_update_elem}, Pod, }; @@ -102,16 +102,7 @@ unsafe impl Pod for Key {} impl, K: Pod, V: Pod> LpmTrie { pub(crate) fn new(map: T) -> Result, MapError> { let data = map.as_ref(); - let size = mem::size_of::>(); - let expected = data.obj.key_size() as usize; - if size != expected { - return Err(MapError::InvalidKeySize { size, expected }); - } - let size = mem::size_of::(); - let expected = data.obj.value_size() as usize; - if size != expected { - return Err(MapError::InvalidValueSize { size, expected }); - }; + check_kv_size::, V>(data)?; let _ = data.fd_or_err()?; diff --git a/aya/src/maps/mod.rs b/aya/src/maps/mod.rs index 4abcf3af..29bf0658 100644 --- a/aya/src/maps/mod.rs +++ b/aya/src/maps/mod.rs @@ -78,7 +78,8 @@ pub use array::{Array, PerCpuArray, ProgramArray}; pub use bloom_filter::BloomFilter; pub use hash_map::{HashMap, PerCpuHashMap}; pub use lpm_trie::LpmTrie; -#[cfg(any(feature = "async", doc))] +#[cfg(feature = "async")] +#[cfg_attr(docsrs, doc(cfg(feature = "async")))] pub use perf::AsyncPerfEventArray; pub use perf::PerfEventArray; pub use queue::Queue; @@ -410,6 +411,38 @@ macro_rules! impl_try_from_map_generic_key_and_value { 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(map: &MapData) -> Result<(), MapError> { + let size = mem::size_of::(); + let expected = map.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; + if size != expected { + return Err(MapError::InvalidValueSize { size, expected }); + }; + Ok(()) +} + +pub(crate) fn check_v_size(map: &MapData) -> Result<(), MapError> { + let size = mem::size_of::(); + 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. /// /// You should never need to use this unless you're implementing a new map type. @@ -530,11 +563,6 @@ impl MapData { }) } - /// Returns the [`bpf_map_type`] of this map - pub fn map_type(&self) -> Result { - bpf_map_type::try_from(self.obj.map_type()) - } - pub(crate) fn fd_or_err(&self) -> Result { self.fd.ok_or(MapError::NotCreated) } diff --git a/aya/src/maps/queue.rs b/aya/src/maps/queue.rs index 10dbd96e..8484f2df 100644 --- a/aya/src/maps/queue.rs +++ b/aya/src/maps/queue.rs @@ -2,11 +2,10 @@ use std::{ convert::{AsMut, AsRef}, marker::PhantomData, - mem, }; use crate::{ - maps::{MapData, MapError}, + maps::{check_kv_size, MapData, MapError}, sys::{bpf_map_lookup_and_delete_elem, bpf_map_push_elem}, Pod, }; @@ -37,17 +36,8 @@ pub struct Queue { impl, V: Pod> Queue { pub(crate) fn new(map: T) -> Result, MapError> { let data = map.as_ref(); - let expected = 0; - let size = data.obj.key_size() as usize; - if size != expected { - return Err(MapError::InvalidKeySize { size, expected }); - } + check_kv_size::<(), V>(data)?; - let expected = mem::size_of::(); - let size = data.obj.value_size() as usize; - if size != expected { - return Err(MapError::InvalidValueSize { size, expected }); - } let _fd = data.fd_or_err()?; Ok(Queue { diff --git a/aya/src/maps/sock/sock_hash.rs b/aya/src/maps/sock/sock_hash.rs index c7ceb752..58ba8944 100644 --- a/aya/src/maps/sock/sock_hash.rs +++ b/aya/src/maps/sock/sock_hash.rs @@ -5,7 +5,9 @@ use std::{ }; use crate::{ - maps::{hash_map, sock::SockMapFd, IterableMap, MapData, MapError, MapIter, MapKeys}, + maps::{ + check_kv_size, hash_map, sock::SockMapFd, IterableMap, MapData, MapError, MapIter, MapKeys, + }, sys::bpf_map_lookup_elem, Pod, }; @@ -69,7 +71,7 @@ pub struct SockHash { impl, K: Pod> SockHash { pub(crate) fn new(map: T) -> Result, MapError> { let data = map.as_ref(); - hash_map::check_kv_size::(data)?; + check_kv_size::(data)?; let _ = data.fd_or_err()?; Ok(SockHash { diff --git a/aya/src/maps/sock/sock_map.rs b/aya/src/maps/sock/sock_map.rs index b13291a9..e4b7131e 100644 --- a/aya/src/maps/sock/sock_map.rs +++ b/aya/src/maps/sock/sock_map.rs @@ -2,12 +2,11 @@ use std::{ convert::{AsMut, AsRef}, - mem, os::unix::{io::AsRawFd, prelude::RawFd}, }; use crate::{ - maps::{sock::SockMapFd, MapData, MapError, MapKeys}, + maps::{check_bounds, check_kv_size, sock::SockMapFd, MapData, MapError, MapKeys}, sys::{bpf_map_delete_elem, bpf_map_update_elem}, }; @@ -48,17 +47,8 @@ pub struct SockMap { impl> SockMap { pub(crate) fn new(map: T) -> Result, MapError> { let data = map.as_ref(); - let expected = mem::size_of::(); - let size = data.obj.key_size() as usize; - if size != expected { - return Err(MapError::InvalidKeySize { size, expected }); - } + check_kv_size::(data)?; - let expected = mem::size_of::(); - let size = data.obj.value_size() as usize; - if size != expected { - return Err(MapError::InvalidValueSize { size, expected }); - } let _fd = data.fd_or_err()?; Ok(SockMap { inner: map }) @@ -80,8 +70,9 @@ impl> SockMap { impl> SockMap { /// Stores a socket into the map. pub fn set(&mut self, index: u32, socket: &I, flags: u64) -> Result<(), MapError> { - let fd = self.inner.as_mut().fd_or_err()?; - self.check_bounds(index)?; + let data = self.inner.as_mut(); + let fd = data.fd_or_err()?; + check_bounds(data, index)?; bpf_map_update_elem(fd, Some(&index), &socket.as_raw_fd(), flags).map_err( |(_, io_error)| MapError::SyscallError { call: "bpf_map_update_elem".to_owned(), @@ -93,8 +84,9 @@ impl> SockMap { /// Removes the socket stored at `index` from the map. pub fn clear_index(&mut self, index: &u32) -> Result<(), MapError> { - let fd = self.inner.as_mut().fd_or_err()?; - self.check_bounds(*index)?; + let data = self.inner.as_mut(); + let fd = data.fd_or_err()?; + check_bounds(data, *index)?; bpf_map_delete_elem(fd, index) .map(|_| ()) .map_err(|(_, io_error)| MapError::SyscallError { @@ -102,13 +94,4 @@ impl> SockMap { io_error, }) } - - fn check_bounds(&mut self, index: u32) -> Result<(), MapError> { - let max_entries = self.inner.as_mut().obj.max_entries(); - if index >= self.inner.as_mut().obj.max_entries() { - Err(MapError::OutOfBounds { index, max_entries }) - } else { - Ok(()) - } - } } diff --git a/aya/src/maps/stack.rs b/aya/src/maps/stack.rs index dcff4832..135c18d3 100644 --- a/aya/src/maps/stack.rs +++ b/aya/src/maps/stack.rs @@ -2,11 +2,10 @@ use std::{ convert::{AsMut, AsRef}, marker::PhantomData, - mem, }; use crate::{ - maps::{MapData, MapError}, + maps::{check_kv_size, MapData, MapError}, sys::{bpf_map_lookup_and_delete_elem, bpf_map_update_elem}, Pod, }; @@ -37,17 +36,8 @@ pub struct Stack { impl, V: Pod> Stack { pub(crate) fn new(map: T) -> Result, MapError> { let data = map.as_ref(); - let expected = 0; - let size = data.obj.key_size() as usize; - if size != expected { - return Err(MapError::InvalidKeySize { size, expected }); - } + check_kv_size::<(), V>(data)?; - let expected = mem::size_of::(); - let size = data.obj.value_size() as usize; - if size != expected { - return Err(MapError::InvalidValueSize { size, expected }); - } let _fd = data.fd_or_err()?; Ok(Stack { From 939d16cce5dcfeaebc5d571d21127105fc886186 Mon Sep 17 00:00:00 2001 From: Andrew Stoycos Date: Mon, 17 Oct 2022 17:19:20 -0400 Subject: [PATCH 5/9] Fixups 2 Respond to more review comments: Revert to try_from in doctests so we don't need to explicitly specify type parameters. Fixup some documentation Remove explit types in `try_from` methods Signed-off-by: Andrew Stoycos --- aya/src/maps/array/array.rs | 2 +- aya/src/maps/array/per_cpu_array.rs | 2 +- aya/src/maps/array/program_array.rs | 2 +- aya/src/maps/bloom_filter.rs | 2 +- aya/src/maps/hash_map/hash_map.rs | 2 +- aya/src/maps/hash_map/per_cpu_hash_map.rs | 6 +++--- aya/src/maps/lpm_trie.rs | 2 +- aya/src/maps/mod.rs | 18 +++++++++--------- aya/src/maps/perf/async_perf_event_array.rs | 2 +- aya/src/maps/perf/perf_event_array.rs | 2 +- aya/src/maps/queue.rs | 2 +- aya/src/maps/sock/sock_hash.rs | 10 ++++++---- aya/src/maps/sock/sock_map.rs | 8 +++++--- aya/src/maps/stack.rs | 2 +- 14 files changed, 33 insertions(+), 29 deletions(-) diff --git a/aya/src/maps/array/array.rs b/aya/src/maps/array/array.rs index d661be18..0074e2c4 100644 --- a/aya/src/maps/array/array.rs +++ b/aya/src/maps/array/array.rs @@ -23,7 +23,7 @@ use crate::{ /// # let mut bpf = aya::Bpf::load(&[])?; /// use aya::maps::Array; /// -/// let mut array: Array<_, u32> = bpf.map_mut("ARRAY")?.try_into()?; +/// let mut array = Array::try_from(bpf.map_mut("ARRAY")?)?; /// array.set(1, 42, 0)?; /// assert_eq!(array.get(&1, 0)?, 42); /// # Ok::<(), aya::BpfError>(()) diff --git a/aya/src/maps/array/per_cpu_array.rs b/aya/src/maps/array/per_cpu_array.rs index d9a4f73c..2692eac2 100644 --- a/aya/src/maps/array/per_cpu_array.rs +++ b/aya/src/maps/array/per_cpu_array.rs @@ -33,7 +33,7 @@ use crate::{ /// use aya::maps::{PerCpuArray, PerCpuValues}; /// use aya::util::nr_cpus; /// -/// let mut array: PerCpuArray<_,u32> = bpf.map_mut("ARRAY")?.try_into()?; +/// let mut array = PerCpuArray::try_from(bpf.map_mut("ARRAY")?)?; /// /// // set array[1] = 42 for all cpus /// let nr_cpus = nr_cpus()?; diff --git a/aya/src/maps/array/program_array.rs b/aya/src/maps/array/program_array.rs index 5245d001..b4cbbbf7 100644 --- a/aya/src/maps/array/program_array.rs +++ b/aya/src/maps/array/program_array.rs @@ -27,7 +27,7 @@ use crate::{ /// use aya::maps::ProgramArray; /// use aya::programs::CgroupSkb; /// -/// let mut prog_array: ProgramArray<_> = bpf.take_map("JUMP_TABLE")?.try_into()?; +/// let mut prog_array = ProgramArray::try_from(bpf.take_map("JUMP_TABLE")?)?; /// 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()?; diff --git a/aya/src/maps/bloom_filter.rs b/aya/src/maps/bloom_filter.rs index 7a540367..b97f8720 100644 --- a/aya/src/maps/bloom_filter.rs +++ b/aya/src/maps/bloom_filter.rs @@ -19,7 +19,7 @@ use crate::{ /// # let mut bpf = aya::Bpf::load(&[])?; /// use aya::maps::bloom_filter::BloomFilter; /// -/// let mut bloom_filter: BloomFilter<_,u32> = bpf.map_mut("BLOOM_FILTER")?.try_into()?; +/// let mut bloom_filter = BloomFilter::try_from(bpf.map_mut("BLOOM_FILTER")?)?; /// /// bloom_filter.insert(1, 0)?; /// diff --git a/aya/src/maps/hash_map/hash_map.rs b/aya/src/maps/hash_map/hash_map.rs index 474337bd..42e5f596 100644 --- a/aya/src/maps/hash_map/hash_map.rs +++ b/aya/src/maps/hash_map/hash_map.rs @@ -21,7 +21,7 @@ use crate::{ /// # let mut bpf = aya::Bpf::load(&[])?; /// use aya::maps::HashMap; /// -/// let mut redirect_ports: HashMap<_, u32, u32> = bpf.map_mut("REDIRECT_PORTS")?.try_into()?; +/// let mut redirect_ports = HashMap::try_from(bpf.map_mut("REDIRECT_PORTS")?)?; /// /// // redirect port 80 to 8080 /// redirect_ports.insert(80, 8080, 0); 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 946ab63a..b94bf8ba 100644 --- a/aya/src/maps/hash_map/per_cpu_hash_map.rs +++ b/aya/src/maps/hash_map/per_cpu_hash_map.rs @@ -25,13 +25,13 @@ use crate::{ /// # Examples /// /// ```no_run -/// # let bpf = aya::Bpf::load(&[])?; +/// # let mut bpf = aya::Bpf::load(&[])?; /// use aya::maps::PerCpuHashMap; /// /// const CPU_IDS: u8 = 1; /// 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")?)?; /// let cpu_ids = unsafe { hm.get(&CPU_IDS, 0)? }; /// let wakeups = unsafe { hm.get(&WAKEUPS, 0)? }; /// for (cpu_id, wakeups) in cpu_ids.iter().zip(wakeups.iter()) { @@ -107,7 +107,7 @@ impl, K: Pod, V: Pod> PerCpuHashMap { /// /// const RETRIES: u8 = 1; /// - /// let mut hm: PerCpuHashMap::<_, u8, u32> = bpf.map_mut("PER_CPU_STORAGE")?.try_into()?; + /// let mut hm = PerCpuHashMap::<_, u8, u32>::try_from(bpf.map_mut("PER_CPU_STORAGE")?)?; /// hm.insert( /// RETRIES, /// PerCpuValues::try_from(vec![3u32; nr_cpus()?])?, diff --git a/aya/src/maps/lpm_trie.rs b/aya/src/maps/lpm_trie.rs index ae479529..047b36b1 100644 --- a/aya/src/maps/lpm_trie.rs +++ b/aya/src/maps/lpm_trie.rs @@ -24,7 +24,7 @@ use crate::{ /// use aya::maps::lpm_trie::{LpmTrie, Key}; /// use std::net::Ipv4Addr; /// -/// let mut trie: LpmTrie<_,u32,u32> = bpf.map_mut("LPM_TRIE")?.try_into()?; +/// let mut trie = LpmTrie::try_from(bpf.map_mut("LPM_TRIE")?)?; /// 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. diff --git a/aya/src/maps/mod.rs b/aya/src/maps/mod.rs index 29bf0658..94484cc9 100644 --- a/aya/src/maps/mod.rs +++ b/aya/src/maps/mod.rs @@ -22,7 +22,7 @@ //! use aya::maps::SockMap; //! use aya::programs::SkMsg; //! -//! let mut intercept_egress: SockMap<_> = bpf.map_mut("INTERCEPT_EGRESS")?.try_into()?; +//! let intercept_egress = SockMap::try_from(bpf.map_mut("INTERCEPT_EGRESS")?)?; //! let map_fd = intercept_egress.fd()?; //! let prog: &mut SkMsg = bpf.program_mut("intercept_egress_packet").unwrap().try_into()?; //! prog.load()?; @@ -281,7 +281,7 @@ macro_rules! impl_try_from_map { fn try_from(map: &'a Map) -> Result<$tx<&'a MapData>, MapError> { match map { Map::$ty(m) => { - $tx::<&'a MapData>::new(m) + $tx::new(m) }, _ => Err(MapError::UnexpectedMapType), } @@ -294,7 +294,7 @@ macro_rules! impl_try_from_map { fn try_from(map: &'a mut Map) -> Result<$tx<&'a mut MapData>, MapError> { match map { Map::$ty(m) => { - $tx::<&'a mut MapData>::new(m) + $tx::new(m) }, _ => Err(MapError::UnexpectedMapType), } @@ -307,7 +307,7 @@ macro_rules! impl_try_from_map { fn try_from(map: Map) -> Result<$tx, MapError> { match map { Map::$ty(m) => { - $tx::::new(m) + $tx::new(m) }, _ => Err(MapError::UnexpectedMapType), } @@ -339,7 +339,7 @@ macro_rules! impl_try_from_map_generic_key_or_value { fn try_from(map: &'a Map) -> Result<$ty<&'a MapData , V>, MapError> { match map { Map::$ty(m) => { - $ty::<&'a MapData,V>::new(m) + $ty::new(m) }, _ => Err(MapError::UnexpectedMapType), } @@ -352,7 +352,7 @@ macro_rules! impl_try_from_map_generic_key_or_value { 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) + $ty::new(m) }, _ => Err(MapError::UnexpectedMapType), } @@ -365,7 +365,7 @@ macro_rules! impl_try_from_map_generic_key_or_value { fn try_from(map: Map) -> Result<$ty, MapError> { match map { Map::$ty(m) => { - $ty::::new(m) + $ty::new(m) }, _ => Err(MapError::UnexpectedMapType), } @@ -386,7 +386,7 @@ macro_rules! impl_try_from_map_generic_key_and_value { 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) + $ty::new(m) }, _ => Err(MapError::UnexpectedMapType), } @@ -399,7 +399,7 @@ macro_rules! impl_try_from_map_generic_key_and_value { 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) + $ty::new(m) }, _ => Err(MapError::UnexpectedMapType), } diff --git a/aya/src/maps/perf/async_perf_event_array.rs b/aya/src/maps/perf/async_perf_event_array.rs index 651d503a..1ca14be5 100644 --- a/aya/src/maps/perf/async_perf_event_array.rs +++ b/aya/src/maps/perf/async_perf_event_array.rs @@ -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<_> =bpf.take_map("PERF_ARRAY")?.try_into()?; +/// let mut perf_array = AsyncPerfEventArray::try_from(bpf.take_map("PERF_ARRAY")?)?; /// /// for cpu_id in online_cpus()? { /// // open a separate perf buffer for each cpu diff --git a/aya/src/maps/perf/perf_event_array.rs b/aya/src/maps/perf/perf_event_array.rs index 0517cb7d..7b25addd 100644 --- a/aya/src/maps/perf/perf_event_array.rs +++ b/aya/src/maps/perf/perf_event_array.rs @@ -110,7 +110,7 @@ impl + AsRef> AsRawFd for PerfEventArrayBuffer { /// use aya::util::online_cpus; /// use bytes::BytesMut; /// -/// let mut perf_array: PerfEventArray<_> = bpf.map_mut("EVENTS")?.try_into()?; +/// let mut perf_array = PerfEventArray::try_from(bpf.map_mut("EVENTS")?)?; /// /// // 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. diff --git a/aya/src/maps/queue.rs b/aya/src/maps/queue.rs index 8484f2df..fe882430 100644 --- a/aya/src/maps/queue.rs +++ b/aya/src/maps/queue.rs @@ -21,7 +21,7 @@ use crate::{ /// # let mut bpf = aya::Bpf::load(&[])?; /// use aya::maps::Queue; /// -/// let mut queue: Queue<_, u32> = bpf.map_mut("ARRAY")?.try_into()?; +/// let mut queue = Queue::try_from(bpf.map_mut("ARRAY")?)?; /// queue.push(42, 0)?; /// queue.push(43, 0)?; /// assert_eq!(queue.pop(0)?, 42); diff --git a/aya/src/maps/sock/sock_hash.rs b/aya/src/maps/sock/sock_hash.rs index 58ba8944..302d9df4 100644 --- a/aya/src/maps/sock/sock_hash.rs +++ b/aya/src/maps/sock/sock_hash.rs @@ -46,7 +46,7 @@ use crate::{ /// use aya::maps::SockHash; /// use aya::programs::SkMsg; /// -/// let intercept_egress: SockHash<_, u32> = bpf.map("INTERCEPT_EGRESS")?.try_into()?; +/// let mut intercept_egress = SockHash::<_, u32>::try_from(bpf.map("INTERCEPT_EGRESS")?)?; /// let map_fd = intercept_egress.fd()?; /// /// let prog: &mut SkMsg = bpf.program_mut("intercept_egress_packet").unwrap().try_into()?; @@ -54,7 +54,7 @@ use crate::{ /// prog.attach(map_fd)?; /// /// let mut client = TcpStream::connect("127.0.0.1:1234")?; -/// let mut intercept_egress: SockHash<_, u32> = bpf.map_mut("INTERCEPT_EGRESS")?.try_into()?; +/// let mut intercept_egress = SockHash::try_from(bpf.map_mut("INTERCEPT_EGRESS")?)?; /// /// intercept_egress.insert(1234, client.as_raw_fd(), 0)?; /// @@ -104,8 +104,10 @@ impl, K: Pod> SockHash { MapKeys::new(self.inner.as_ref()) } - /// Returns the map's file descriptor, used for instances where programs - /// are attached to maps. + /// Returns the map's file descriptor. + /// + /// The returned file descriptor can be used to attach programs that work with + /// socket maps, like [`SkMsg`] and [`SkSkb`]. pub fn fd(&self) -> Result { Ok(SockMapFd(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 e4b7131e..2c7efa7a 100644 --- a/aya/src/maps/sock/sock_map.rs +++ b/aya/src/maps/sock/sock_map.rs @@ -30,7 +30,7 @@ use crate::{ /// use aya::maps::SockMap; /// use aya::programs::SkSkb; /// -/// let intercept_ingress: SockMap<_> = bpf.map("INTERCEPT_INGRESS")?.try_into()?; +/// let intercept_ingress = SockMap::try_from(bpf.map("INTERCEPT_INGRESS")?)?; /// let map_fd = intercept_ingress.fd()?; /// /// let prog: &mut SkSkb = bpf.program_mut("intercept_ingress_packet").unwrap().try_into()?; @@ -60,8 +60,10 @@ impl> SockMap { MapKeys::new(self.inner.as_ref()) } - /// Returns the map's file descriptor, used for instances where programs - /// are attached to maps. + /// Returns the map's file descriptor. + /// + /// The returned file descriptor can be used to attach programs that work with + /// socket maps, like [`SkMsg`] and [`SkSkb`]. pub fn fd(&self) -> Result { Ok(SockMapFd(self.inner.as_ref().fd_or_err()?)) } diff --git a/aya/src/maps/stack.rs b/aya/src/maps/stack.rs index 135c18d3..7089d9e7 100644 --- a/aya/src/maps/stack.rs +++ b/aya/src/maps/stack.rs @@ -21,7 +21,7 @@ use crate::{ /// # let mut bpf = aya::Bpf::load(&[])?; /// use aya::maps::Stack; /// -/// let mut stack: Stack<_, u32> = bpf.map_mut("STACK")?.try_into()?; +/// let mut stack = Stack::try_from(bpf.map_mut("STACK")?)?; /// stack.push(42, 0)?; /// stack.push(43, 0)?; /// assert_eq!(stack.pop(0)?, 43); From 440097d7bc671c78fa33d13f890c3aa456530306 Mon Sep 17 00:00:00 2001 From: Andrew Stoycos Date: Tue, 18 Oct 2022 10:20:19 -0400 Subject: [PATCH 6/9] Fixups 3 Remove MapError::UnexpectedMapType Add Macro for converting from aya::Map to u32 (map type) for use in `MapError::InvalidMapType { map_type: x }` Signed-off-by: Andrew Stoycos --- aya/src/maps/bloom_filter.rs | 2 +- aya/src/maps/hash_map/hash_map.rs | 2 +- aya/src/maps/lpm_trie.rs | 2 +- aya/src/maps/mod.rs | 49 +++++++++++++++++++++++-------- 4 files changed, 40 insertions(+), 15 deletions(-) diff --git a/aya/src/maps/bloom_filter.rs b/aya/src/maps/bloom_filter.rs index b97f8720..b19b9d5d 100644 --- a/aya/src/maps/bloom_filter.rs +++ b/aya/src/maps/bloom_filter.rs @@ -150,7 +150,7 @@ mod tests { assert!(matches!( BloomFilter::<_, u32>::try_from(&map), - Err(MapError::UnexpectedMapType) + Err(MapError::InvalidMapType { .. }) )); } diff --git a/aya/src/maps/hash_map/hash_map.rs b/aya/src/maps/hash_map/hash_map.rs index 42e5f596..53057c62 100644 --- a/aya/src/maps/hash_map/hash_map.rs +++ b/aya/src/maps/hash_map/hash_map.rs @@ -183,7 +183,7 @@ mod tests { let map = Map::Array(map_data); assert!(matches!( HashMap::<_, u8, u32>::try_from(&map), - Err(MapError::UnexpectedMapType) + Err(MapError::InvalidMapType { .. }) )); } diff --git a/aya/src/maps/lpm_trie.rs b/aya/src/maps/lpm_trie.rs index 047b36b1..5fb92d79 100644 --- a/aya/src/maps/lpm_trie.rs +++ b/aya/src/maps/lpm_trie.rs @@ -260,7 +260,7 @@ mod tests { assert!(matches!( LpmTrie::<_, u32, u32>::try_from(&map), - Err(MapError::UnexpectedMapType) + Err(MapError::InvalidMapType { .. }) )); } diff --git a/aya/src/maps/mod.rs b/aya/src/maps/mod.rs index 94484cc9..c5632808 100644 --- a/aya/src/maps/mod.rs +++ b/aya/src/maps/mod.rs @@ -191,10 +191,6 @@ pub enum MapError { #[source] error: PinError, }, - - /// The map is not of the expected type. - #[error("unexpected map type")] - UnexpectedMapType, } /// A map file descriptor. @@ -283,7 +279,7 @@ macro_rules! impl_try_from_map { Map::$ty(m) => { $tx::new(m) }, - _ => Err(MapError::UnexpectedMapType), + _ => Err(MapError::InvalidMapType{ map_type: map.into()}), } } } @@ -296,7 +292,7 @@ macro_rules! impl_try_from_map { Map::$ty(m) => { $tx::new(m) }, - _ => Err(MapError::UnexpectedMapType), + _ => Err(MapError::InvalidMapType{ map_type: map.into()}), } } } @@ -309,7 +305,7 @@ macro_rules! impl_try_from_map { Map::$ty(m) => { $tx::new(m) }, - _ => Err(MapError::UnexpectedMapType), + _ => Err(MapError::InvalidMapType{ map_type: map.into()}), } } } @@ -341,7 +337,7 @@ macro_rules! impl_try_from_map_generic_key_or_value { Map::$ty(m) => { $ty::new(m) }, - _ => Err(MapError::UnexpectedMapType), + _ => Err(MapError::InvalidMapType{ map_type: map.into()}), } } } @@ -354,7 +350,7 @@ macro_rules! impl_try_from_map_generic_key_or_value { Map::$ty(m) => { $ty::new(m) }, - _ => Err(MapError::UnexpectedMapType), + _ => Err(MapError::InvalidMapType{ map_type: map.into()}), } } } @@ -367,7 +363,7 @@ macro_rules! impl_try_from_map_generic_key_or_value { Map::$ty(m) => { $ty::new(m) }, - _ => Err(MapError::UnexpectedMapType), + _ => Err(MapError::InvalidMapType{ map_type: map.into()}), } } } @@ -388,7 +384,7 @@ macro_rules! impl_try_from_map_generic_key_and_value { Map::$ty(m) => { $ty::new(m) }, - _ => Err(MapError::UnexpectedMapType), + _ => Err(MapError::InvalidMapType{ map_type: map.into()}), } } } @@ -401,7 +397,7 @@ macro_rules! impl_try_from_map_generic_key_and_value { Map::$ty(m) => { $ty::new(m) }, - _ => Err(MapError::UnexpectedMapType), + _ => Err(MapError::InvalidMapType{ map_type: map.into()}), } } } @@ -761,6 +757,35 @@ impl TryFrom for bpf_map_type { }) } } + +macro_rules! impl_try_from_map_generic_key_or_value { + ($($typ:ty),+ $(,)?) => { + $( + impl From<$typ> for u32 { + fn from(map_type: $typ) -> u32 { + match map_type { + 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(), + } + } + } + )+ + } +} + +impl_try_from_map_generic_key_or_value!(&Map, &mut Map, Map); + pub(crate) struct PerCpuKernelMem { bytes: Vec, } From 4ddf2600b4084d224d66810f8372f42354dc40e0 Mon Sep 17 00:00:00 2001 From: Andrew Stoycos Date: Wed, 19 Oct 2022 09:50:33 -0400 Subject: [PATCH 7/9] Fixups4 Remove From method and replace with internal helper function. Signed-off-by: Andrew Stoycos --- aya/src/maps/mod.rs | 65 ++++++++++++++++++++------------------------- 1 file changed, 29 insertions(+), 36 deletions(-) diff --git a/aya/src/maps/mod.rs b/aya/src/maps/mod.rs index c5632808..f3841502 100644 --- a/aya/src/maps/mod.rs +++ b/aya/src/maps/mod.rs @@ -268,6 +268,27 @@ pub enum 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),+ $(,)?) => { $( @@ -279,7 +300,7 @@ macro_rules! impl_try_from_map { Map::$ty(m) => { $tx::new(m) }, - _ => Err(MapError::InvalidMapType{ map_type: map.into()}), + _ => Err(MapError::InvalidMapType{ map_type: map.map_type()}), } } } @@ -292,7 +313,7 @@ macro_rules! impl_try_from_map { Map::$ty(m) => { $tx::new(m) }, - _ => Err(MapError::InvalidMapType{ map_type: map.into()}), + _ => Err(MapError::InvalidMapType{ map_type: map.map_type()}), } } } @@ -305,7 +326,7 @@ macro_rules! impl_try_from_map { Map::$ty(m) => { $tx::new(m) }, - _ => Err(MapError::InvalidMapType{ map_type: map.into()}), + _ => Err(MapError::InvalidMapType{ map_type: map.map_type()}), } } } @@ -337,7 +358,7 @@ macro_rules! impl_try_from_map_generic_key_or_value { Map::$ty(m) => { $ty::new(m) }, - _ => Err(MapError::InvalidMapType{ map_type: map.into()}), + _ => Err(MapError::InvalidMapType{ map_type: map.map_type()}), } } } @@ -350,7 +371,7 @@ macro_rules! impl_try_from_map_generic_key_or_value { Map::$ty(m) => { $ty::new(m) }, - _ => Err(MapError::InvalidMapType{ map_type: map.into()}), + _ => Err(MapError::InvalidMapType{ map_type: map.map_type()}), } } } @@ -363,7 +384,7 @@ macro_rules! impl_try_from_map_generic_key_or_value { Map::$ty(m) => { $ty::new(m) }, - _ => Err(MapError::InvalidMapType{ map_type: map.into()}), + _ => Err(MapError::InvalidMapType{ map_type: map.map_type()}), } } } @@ -384,7 +405,7 @@ macro_rules! impl_try_from_map_generic_key_and_value { Map::$ty(m) => { $ty::new(m) }, - _ => Err(MapError::InvalidMapType{ map_type: map.into()}), + _ => Err(MapError::InvalidMapType{ map_type: map.map_type()}), } } } @@ -397,7 +418,7 @@ macro_rules! impl_try_from_map_generic_key_and_value { Map::$ty(m) => { $ty::new(m) }, - _ => Err(MapError::InvalidMapType{ map_type: map.into()}), + _ => Err(MapError::InvalidMapType{ map_type: map.map_type()}), } } } @@ -758,34 +779,6 @@ impl TryFrom for bpf_map_type { } } -macro_rules! impl_try_from_map_generic_key_or_value { - ($($typ:ty),+ $(,)?) => { - $( - impl From<$typ> for u32 { - fn from(map_type: $typ) -> u32 { - match map_type { - 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(), - } - } - } - )+ - } -} - -impl_try_from_map_generic_key_or_value!(&Map, &mut Map, Map); - pub(crate) struct PerCpuKernelMem { bytes: Vec, } From f3262e87bd6ff895537df47fcf5d17c598e564cc Mon Sep 17 00:00:00 2001 From: Andrew Stoycos Date: Thu, 20 Oct 2022 09:12:57 -0400 Subject: [PATCH 8/9] Make map APIs return an option switch map() and map_mut() from returning a `Result` to an `Option` since it's just getting a value from a Hashmap, and to stay in line with the Programs API. Remove `MapError::MapNotFound` Signed-off-by: Andrew Stoycos --- aya-log/src/lib.rs | 2 +- aya/src/bpf.rs | 36 +++++---------------- aya/src/maps/array/array.rs | 2 +- aya/src/maps/array/per_cpu_array.rs | 2 +- aya/src/maps/array/program_array.rs | 2 +- aya/src/maps/bloom_filter.rs | 2 +- aya/src/maps/hash_map/hash_map.rs | 2 +- aya/src/maps/hash_map/per_cpu_hash_map.rs | 4 +-- aya/src/maps/lpm_trie.rs | 2 +- aya/src/maps/mod.rs | 9 +----- aya/src/maps/perf/async_perf_event_array.rs | 2 +- aya/src/maps/perf/perf_event_array.rs | 2 +- aya/src/maps/queue.rs | 2 +- aya/src/maps/sock/sock_hash.rs | 4 +-- aya/src/maps/sock/sock_map.rs | 2 +- aya/src/maps/stack.rs | 2 +- aya/src/maps/stack_trace.rs | 2 +- aya/src/programs/sk_msg.rs | 4 +-- aya/src/programs/sk_skb.rs | 2 +- test/integration-test/src/tests/load.rs | 4 +-- 20 files changed, 31 insertions(+), 58 deletions(-) diff --git a/aya-log/src/lib.rs b/aya-log/src/lib.rs index bbff0f61..a2dd686b 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.take_map("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)? { let mut buf = logs.open(cpu_id, None)?; diff --git a/aya/src/bpf.rs b/aya/src/bpf.rs index 6b54fa51..bd8dd1a3 100644 --- a/aya/src/bpf.rs +++ b/aya/src/bpf.rs @@ -743,14 +743,8 @@ impl Bpf { /// /// 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 map(&self, name: &str) -> Result<&Map, MapError> { - self.maps.get(name).ok_or_else(|| MapError::MapNotFound { - name: name.to_owned(), - }) + pub fn map(&self, name: &str) -> Option<&Map> { + self.maps.get(name) } /// Returns a mutable reference to the map with the given name. @@ -760,16 +754,8 @@ impl Bpf { /// /// 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 map_mut(&mut self, name: &str) -> Result<&mut Map, MapError> { - self.maps - .get_mut(name) - .ok_or_else(|| MapError::MapNotFound { - name: name.to_owned(), - }) + 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. @@ -785,14 +771,8 @@ impl Bpf { /// /// 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(), - }) + pub fn take_map(&mut self, name: &str) -> Option { + self.maps.remove(name) } /// An iterator over all the maps. @@ -808,8 +788,8 @@ impl Bpf { /// } /// # Ok::<(), aya::BpfError>(()) /// ``` - pub fn maps(&self) -> impl Iterator)> { - self.maps.iter().map(|(name, map)| (name.as_str(), Ok(map))) + pub fn maps(&self) -> impl Iterator { + self.maps.iter().map(|(name, map)| (name.as_str(), 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 0074e2c4..1402d57d 100644 --- a/aya/src/maps/array/array.rs +++ b/aya/src/maps/array/array.rs @@ -23,7 +23,7 @@ use crate::{ /// # let mut bpf = aya::Bpf::load(&[])?; /// 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)?; /// assert_eq!(array.get(&1, 0)?, 42); /// # Ok::<(), aya::BpfError>(()) diff --git a/aya/src/maps/array/per_cpu_array.rs b/aya/src/maps/array/per_cpu_array.rs index 2692eac2..a3b5eab9 100644 --- a/aya/src/maps/array/per_cpu_array.rs +++ b/aya/src/maps/array/per_cpu_array.rs @@ -33,7 +33,7 @@ use crate::{ /// use aya::maps::{PerCpuArray, PerCpuValues}; /// 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 /// let nr_cpus = nr_cpus()?; diff --git a/aya/src/maps/array/program_array.rs b/aya/src/maps/array/program_array.rs index b4cbbbf7..27566e28 100644 --- a/aya/src/maps/array/program_array.rs +++ b/aya/src/maps/array/program_array.rs @@ -27,7 +27,7 @@ use crate::{ /// use aya::maps::ProgramArray; /// use aya::programs::CgroupSkb; /// -/// let mut prog_array = ProgramArray::try_from(bpf.take_map("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_fd = prog_0.fd().unwrap(); /// let prog_1: &CgroupSkb = bpf.program("example_prog_1").unwrap().try_into()?; diff --git a/aya/src/maps/bloom_filter.rs b/aya/src/maps/bloom_filter.rs index b19b9d5d..5e94e247 100644 --- a/aya/src/maps/bloom_filter.rs +++ b/aya/src/maps/bloom_filter.rs @@ -19,7 +19,7 @@ use crate::{ /// # 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::try_from(bpf.map_mut("BLOOM_FILTER").unwrap())?; /// /// bloom_filter.insert(1, 0)?; /// diff --git a/aya/src/maps/hash_map/hash_map.rs b/aya/src/maps/hash_map/hash_map.rs index 53057c62..4c480ca2 100644 --- a/aya/src/maps/hash_map/hash_map.rs +++ b/aya/src/maps/hash_map/hash_map.rs @@ -21,7 +21,7 @@ use crate::{ /// # 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::try_from(bpf.map_mut("REDIRECT_PORTS").unwrap())?; /// /// // redirect port 80 to 8080 /// redirect_ports.insert(80, 8080, 0); 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 b94bf8ba..0f38f6c6 100644 --- a/aya/src/maps/hash_map/per_cpu_hash_map.rs +++ b/aya/src/maps/hash_map/per_cpu_hash_map.rs @@ -31,7 +31,7 @@ use crate::{ /// const CPU_IDS: u8 = 1; /// const WAKEUPS: u8 = 2; /// -/// 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())?; /// let cpu_ids = unsafe { hm.get(&CPU_IDS, 0)? }; /// let wakeups = unsafe { hm.get(&WAKEUPS, 0)? }; /// for (cpu_id, wakeups) in cpu_ids.iter().zip(wakeups.iter()) { @@ -107,7 +107,7 @@ impl, K: Pod, V: Pod> PerCpuHashMap { /// /// 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( /// RETRIES, /// PerCpuValues::try_from(vec![3u32; nr_cpus()?])?, diff --git a/aya/src/maps/lpm_trie.rs b/aya/src/maps/lpm_trie.rs index 5fb92d79..ea6d8ffc 100644 --- a/aya/src/maps/lpm_trie.rs +++ b/aya/src/maps/lpm_trie.rs @@ -24,7 +24,7 @@ use crate::{ /// 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::try_from(bpf.map_mut("LPM_TRIE").unwrap())?; /// 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. diff --git a/aya/src/maps/mod.rs b/aya/src/maps/mod.rs index f3841502..8930128d 100644 --- a/aya/src/maps/mod.rs +++ b/aya/src/maps/mod.rs @@ -22,7 +22,7 @@ //! use aya::maps::SockMap; //! 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()?; //! prog.load()?; @@ -90,13 +90,6 @@ pub use stack_trace::StackTraceMap; #[derive(Error, Debug)] /// Errors occuring from working with Maps pub enum MapError { - /// Unable to find the map - #[error("map `{name}` not found ")] - MapNotFound { - /// Map name - name: String, - }, - /// Invalid map type encontered #[error("invalid map type {map_type}")] InvalidMapType { diff --git a/aya/src/maps/perf/async_perf_event_array.rs b/aya/src/maps/perf/async_perf_event_array.rs index 1ca14be5..39ffcfa1 100644 --- a/aya/src/maps/perf/async_perf_event_array.rs +++ b/aya/src/maps/perf/async_perf_event_array.rs @@ -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.take_map("PERF_ARRAY")?)?; +/// let mut perf_array = AsyncPerfEventArray::try_from(bpf.take_map("PERF_ARRAY").unwrap())?; /// /// for cpu_id in online_cpus()? { /// // open a separate perf buffer for each cpu diff --git a/aya/src/maps/perf/perf_event_array.rs b/aya/src/maps/perf/perf_event_array.rs index 7b25addd..8dafd7f1 100644 --- a/aya/src/maps/perf/perf_event_array.rs +++ b/aya/src/maps/perf/perf_event_array.rs @@ -110,7 +110,7 @@ impl + AsRef> AsRawFd for PerfEventArrayBuffer { /// use aya::util::online_cpus; /// 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 /// // running on as the array index. diff --git a/aya/src/maps/queue.rs b/aya/src/maps/queue.rs index fe882430..e7233773 100644 --- a/aya/src/maps/queue.rs +++ b/aya/src/maps/queue.rs @@ -21,7 +21,7 @@ use crate::{ /// # let mut bpf = aya::Bpf::load(&[])?; /// 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(43, 0)?; /// assert_eq!(queue.pop(0)?, 42); diff --git a/aya/src/maps/sock/sock_hash.rs b/aya/src/maps/sock/sock_hash.rs index 302d9df4..679c2be3 100644 --- a/aya/src/maps/sock/sock_hash.rs +++ b/aya/src/maps/sock/sock_hash.rs @@ -46,7 +46,7 @@ use crate::{ /// use aya::maps::SockHash; /// use aya::programs::SkMsg; /// -/// let mut intercept_egress = SockHash::<_, u32>::try_from(bpf.map("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()?; @@ -54,7 +54,7 @@ use crate::{ /// prog.attach(map_fd)?; /// /// let mut client = TcpStream::connect("127.0.0.1:1234")?; -/// let mut intercept_egress = SockHash::try_from(bpf.map_mut("INTERCEPT_EGRESS")?)?; +/// let mut intercept_egress = SockHash::try_from(bpf.map_mut("INTERCEPT_EGRESS").unwrap())?; /// /// intercept_egress.insert(1234, client.as_raw_fd(), 0)?; /// diff --git a/aya/src/maps/sock/sock_map.rs b/aya/src/maps/sock/sock_map.rs index 2c7efa7a..7c284d22 100644 --- a/aya/src/maps/sock/sock_map.rs +++ b/aya/src/maps/sock/sock_map.rs @@ -30,7 +30,7 @@ use crate::{ /// use aya::maps::SockMap; /// use aya::programs::SkSkb; /// -/// let intercept_ingress = SockMap::try_from(bpf.map("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()?; diff --git a/aya/src/maps/stack.rs b/aya/src/maps/stack.rs index 7089d9e7..1350ef30 100644 --- a/aya/src/maps/stack.rs +++ b/aya/src/maps/stack.rs @@ -21,7 +21,7 @@ use crate::{ /// # let mut bpf = aya::Bpf::load(&[])?; /// 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(43, 0)?; /// assert_eq!(stack.pop(0)?, 43); diff --git a/aya/src/maps/stack_trace.rs b/aya/src/maps/stack_trace.rs index 51d89fe4..135387e4 100644 --- a/aya/src/maps/stack_trace.rs +++ b/aya/src/maps/stack_trace.rs @@ -35,7 +35,7 @@ use crate::{ /// use aya::maps::StackTraceMap; /// 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 /// let ksyms = kernel_symbols()?; /// diff --git a/aya/src/programs/sk_msg.rs b/aya/src/programs/sk_msg.rs index 867f3448..2cf4d51a 100644 --- a/aya/src/programs/sk_msg.rs +++ b/aya/src/programs/sk_msg.rs @@ -43,7 +43,7 @@ use crate::{ /// use aya::maps::SockHash; /// use aya::programs::SkMsg; /// -/// let intercept_egress: SockHash<_, u32> = bpf.map("INTERCEPT_EGRESS")?.try_into()?; +/// 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()?; @@ -51,7 +51,7 @@ use crate::{ /// prog.attach(map_fd)?; /// /// let mut client = TcpStream::connect("127.0.0.1:1234")?; -/// let mut intercept_egress: SockHash<_, u32> = bpf.map_mut("INTERCEPT_EGRESS")?.try_into()?; +/// let mut intercept_egress: SockHash<_, u32> = bpf.map_mut("INTERCEPT_EGRESS").unwrap().try_into()?; /// /// intercept_egress.insert(1234, client.as_raw_fd(), 0)?; /// diff --git a/aya/src/programs/sk_skb.rs b/aya/src/programs/sk_skb.rs index a90a2d82..79e741fd 100644 --- a/aya/src/programs/sk_skb.rs +++ b/aya/src/programs/sk_skb.rs @@ -41,7 +41,7 @@ pub enum SkSkbKind { /// use aya::maps::SockMap; /// use aya::programs::SkSkb; /// -/// let intercept_ingress: SockMap<_> = bpf.map("INTERCEPT_INGRESS")?.try_into()?; +/// 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()?; diff --git a/test/integration-test/src/tests/load.rs b/test/integration-test/src/tests/load.rs index 72129f27..de01e6c2 100644 --- a/test/integration-test/src/tests/load.rs +++ b/test/integration-test/src/tests/load.rs @@ -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<_, u64> = bpf.take_map("map_1")?.try_into()?; - let map_2: Array<_, u64> = bpf.take_map("map_2")?.try_into()?; + let map_1: Array<_, u64> = bpf.take_map("map_1").unwrap().try_into()?; + 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(); prog.load().unwrap(); From 82edd681c398f73de026a695837dd37643ed124a Mon Sep 17 00:00:00 2001 From: Andrew Stoycos Date: Thu, 20 Oct 2022 14:46:40 -0400 Subject: [PATCH 9/9] Fix doc links, update rustdoc args Fix some broken rust doc links. Make sure rustdoc build fail on warnings so we catch these broken links in CI. Signed-off-by: Andrew Stoycos --- aya/Cargo.toml | 2 +- aya/src/bpf.rs | 9 ++++----- aya/src/maps/mod.rs | 18 +++++++++--------- aya/src/maps/perf/mod.rs | 2 +- aya/src/maps/sock/mod.rs | 2 +- aya/src/maps/sock/sock_hash.rs | 2 +- aya/src/maps/sock/sock_map.rs | 2 +- xtask/src/docs/mod.rs | 2 +- 8 files changed, 19 insertions(+), 20 deletions(-) diff --git a/aya/Cargo.toml b/aya/Cargo.toml index 8c43a401..c5b2f01d 100644 --- a/aya/Cargo.toml +++ b/aya/Cargo.toml @@ -34,4 +34,4 @@ async_std = ["async-io", "async"] [package.metadata.docs.rs] all-features = true -rustdoc-args = ["--cfg", "docsrs"] +rustdoc-args = ["--cfg", "docsrs","-D", "warnings"] diff --git a/aya/src/bpf.rs b/aya/src/bpf.rs index bd8dd1a3..f5307f83 100644 --- a/aya/src/bpf.rs +++ b/aya/src/bpf.rs @@ -760,11 +760,10 @@ impl Bpf { /// Takes ownership of a map with the given name. /// - /// This API is intended for cases where the map must be moved into spawned - /// task. For example, when using an [`AsyncPerfEventArray`]. For map interactions - /// without taking ownership, see `map` or `map_mut`. An owned map will be - /// closed on `Drop`, therefore the the caller is now responsible for managing - /// its lifetime. + /// 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. /// /// 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). diff --git a/aya/src/maps/mod.rs b/aya/src/maps/mod.rs index 8930128d..e0b980be 100644 --- a/aya/src/maps/mod.rs +++ b/aya/src/maps/mod.rs @@ -5,16 +5,16 @@ //! [`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), -//! [`Bpf::map_mut`](crate::Bpf::map_mut), [`Bpf::take_map`](crate::Bpf::map) -//! or [`Bpf::map_mut`](crate::Bpf::take_map). +//! [`Bpf::map_mut`](crate::Bpf::map_mut), or [`Bpf::take_map`](crate::Bpf::take_map). //! //! # Typed maps //! //! The eBPF API includes many map types each supporting different operations. //! [`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) +//! [`Bpf::take_map`](crate::Bpf::take_map) always return the +//! 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 @@ -233,7 +233,7 @@ fn maybe_warn_rlimit() { /// eBPF map types. #[derive(Debug)] pub enum Map { - /// A ['Array`] map + /// A [`Array`] map Array(MapData), /// A [`PerCpuArray`] map PerCpuArray(MapData), @@ -241,7 +241,7 @@ pub enum Map { ProgramArray(MapData), /// A [`HashMap`] map HashMap(MapData), - /// A ['PerCpuHashMap'] map + /// A [`PerCpuHashMap`] map PerCpuHashMap(MapData), /// A [`PerfEventArray`] map PerfEventArray(MapData), @@ -255,7 +255,7 @@ pub enum Map { LpmTrie(MapData), /// A [`Stack`] map Stack(MapData), - /// A [`StackTrace`] map + /// A [`StackTraceMap`] map StackTraceMap(MapData), /// A [`Queue`] map Queue(MapData), @@ -556,7 +556,7 @@ impl MapData { /// 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. /// For example, you received an FD over Unix Domain Socket. pub fn from_fd(fd: RawFd) -> Result { diff --git a/aya/src/maps/perf/mod.rs b/aya/src/maps/perf/mod.rs index 1f9bae7d..db3c3005 100644 --- a/aya/src/maps/perf/mod.rs +++ b/aya/src/maps/perf/mod.rs @@ -1,6 +1,6 @@ //! 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_attr(docsrs, doc(cfg(feature = "async")))] mod async_perf_event_array; diff --git a/aya/src/maps/sock/mod.rs b/aya/src/maps/sock/mod.rs index 59979896..ffbf7aa3 100644 --- a/aya/src/maps/sock/mod.rs +++ b/aya/src/maps/sock/mod.rs @@ -7,7 +7,7 @@ pub use sock_map::SockMap; use std::os::unix::io::{AsRawFd, RawFd}; -/// A [`SocketMap`] file descriptor. +/// A socket map file descriptor. #[derive(Copy, Clone)] pub struct SockMapFd(RawFd); diff --git a/aya/src/maps/sock/sock_hash.rs b/aya/src/maps/sock/sock_hash.rs index 679c2be3..4271f5e6 100644 --- a/aya/src/maps/sock/sock_hash.rs +++ b/aya/src/maps/sock/sock_hash.rs @@ -107,7 +107,7 @@ impl, K: Pod> SockHash { /// Returns the map's file descriptor. /// /// The returned file descriptor can be used to attach programs that work with - /// socket maps, like [`SkMsg`] and [`SkSkb`]. + /// socket maps, like [`SkMsg`](crate::programs::SkMsg) and [`SkSkb`](crate::programs::SkSkb). pub fn fd(&self) -> Result { Ok(SockMapFd(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 7c284d22..28c5b404 100644 --- a/aya/src/maps/sock/sock_map.rs +++ b/aya/src/maps/sock/sock_map.rs @@ -63,7 +63,7 @@ impl> SockMap { /// Returns the map's file descriptor. /// /// The returned file descriptor can be used to attach programs that work with - /// socket maps, like [`SkMsg`] and [`SkSkb`]. + /// socket maps, like [`SkMsg`](crate::programs::SkMsg) and [`SkSkb`](crate::programs::SkSkb). pub fn fd(&self) -> Result { Ok(SockMapFd(self.inner.as_ref().fd_or_err()?)) } diff --git a/xtask/src/docs/mod.rs b/xtask/src/docs/mod.rs index 669852c6..b6779cba 100644 --- a/xtask/src/docs/mod.rs +++ b/xtask/src/docs/mod.rs @@ -68,7 +68,7 @@ fn build_docs(working_dir: &PathBuf, abs_header_path: &Path) -> Result<(), anyho .env( "RUSTDOCFLAGS", format!( - "--cfg docsrs --html-in-header {}", + "--cfg docsrs --html-in-header {} -D warnings", abs_header_path.to_str().unwrap() ), )