aya: remove RwLocks and Ref wrappers on bpf maps.

This improves performance by removing the runtime checking of borrowing
rules. In order to retain a similar level of flexibility as the previous
implementation permitted, `take_map` and `return_map` are added as
methods to Bpf, allowing callers to move ownership of a Map.

This also removes the need for the parking_lot dependency.
pull/118/head
Thia Wyrod 3 years ago
parent 07a6016ebb
commit b90c1fe349
No known key found for this signature in database
GPG Key ID: 55D3AB7E5658CA0C

@ -17,7 +17,6 @@ object = { version = "0.27", default-features = false, features = ["std", "read_
bitflags = "1.2.1" bitflags = "1.2.1"
bytes = "1" bytes = "1"
lazy_static = "1" lazy_static = "1"
parking_lot = { version = "0.11.1", features = ["send_guard"] }
futures = { version = "0.3.12", optional = true, default-features = false, features = ["std"] } futures = { version = "0.3.12", optional = true, default-features = false, features = ["std"] }
tokio = { version = "1.2.0", features = ["macros", "rt", "rt-multi-thread", "net"], optional = true } tokio = { version = "1.2.0", features = ["macros", "rt", "rt-multi-thread", "net"], optional = true }
async-std = { version = "1.9.0", optional = true } async-std = { version = "1.9.0", optional = true }

@ -1,6 +1,6 @@
use std::{ use std::{
borrow::Cow, borrow::Cow,
collections::HashMap, collections::{hash_map::Entry, HashMap},
error::Error, error::Error,
ffi::CString, ffi::CString,
fs, io, fs, io,
@ -15,7 +15,7 @@ use crate::{
bpf_map_type::BPF_MAP_TYPE_PERF_EVENT_ARRAY, AYA_PERF_EVENT_IOC_DISABLE, 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, AYA_PERF_EVENT_IOC_ENABLE, AYA_PERF_EVENT_IOC_SET_BPF,
}, },
maps::{Map, MapError, MapLock, MapRef, MapRefMut}, maps::{Map, MapError},
obj::{ obj::{
btf::{Btf, BtfError}, btf::{Btf, BtfError},
Object, ParseError, ProgramSection, Object, ParseError, ProgramSection,
@ -319,10 +319,6 @@ impl<'a> BpfLoader<'a> {
(name, program) (name, program)
}) })
.collect(); .collect();
let maps = maps
.drain()
.map(|(name, map)| (name, MapLock::new(map)))
.collect();
Ok(Bpf { maps, programs }) Ok(Bpf { maps, programs })
} }
} }
@ -336,7 +332,7 @@ impl<'a> Default for BpfLoader<'a> {
/// The main entry point into the library, used to work with eBPF programs and maps. /// The main entry point into the library, used to work with eBPF programs and maps.
#[derive(Debug)] #[derive(Debug)]
pub struct Bpf { pub struct Bpf {
maps: HashMap<String, MapLock>, maps: HashMap<String, Map>,
programs: HashMap<String, Program>, programs: HashMap<String, Program>,
} }
@ -395,47 +391,50 @@ impl Bpf {
/// ///
/// For more details and examples on maps and their usage, see the [maps module /// For more details and examples on maps and their usage, see the [maps module
/// documentation][crate::maps]. /// documentation][crate::maps].
pub fn map(&self, name: &str) -> Option<&Map> {
self.maps.get(name)
}
/// Returns a mutable reference to the map with the given name.
/// ///
/// # Errors /// 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).
/// ///
/// Returns [`MapError::MapNotFound`] if the map does not exist. If the map is already borrowed /// For more details and examples on maps and their usage, see the [maps module
/// mutably with [map_mut](Self::map_mut) then [`MapError::BorrowError`] is returned. /// documentation][crate::maps].
pub fn map(&self, name: &str) -> Result<MapRef, MapError> { pub fn map_mut(&mut self, name: &str) -> Option<&mut Map> {
self.maps self.maps.get_mut(name)
.get(name)
.ok_or_else(|| MapError::MapNotFound {
name: name.to_owned(),
})
.and_then(|lock| {
lock.try_read().map_err(|_| MapError::BorrowError {
name: name.to_owned(),
})
})
} }
/// Returns a mutable reference to the map with the given name. /// Take ownership of the map with the given name. Useful when intending to maintain frequent
/// access to a map without repeatedly incurring the cost of converting it into a
/// [typed map](crate::maps).
/// ///
/// The returned type is mostly opaque. In order to do anything useful with it you need to /// 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). /// convert it to a [typed map](crate::maps).
/// ///
/// For more details and examples on maps and their usage, see the [maps module /// For more details and examples on maps and their usage, see the [maps module
/// documentation][crate::maps]. /// documentation][crate::maps].
pub fn take_map(&mut self, name: &str) -> Option<(String, Map)> {
self.maps.remove_entry(name)
}
/// Return ownership of the map with the given name. This is the dual of [take_map](Self::take_map).
///
/// For more details and examples on maps and their usage, see the [maps module
/// documentation][crate::maps].
/// ///
/// # Errors /// # Errors
/// ///
/// Returns [`MapError::MapNotFound`] if the map does not exist. If the map is already borrowed /// Returns [`MapError::Occupied`] if a map already exists at the given name.
/// mutably with [map_mut](Self::map_mut) then [`MapError::BorrowError`] is returned. pub fn return_map(&mut self, name: String, map: Map) -> Result<(), MapError> {
pub fn map_mut(&self, name: &str) -> Result<MapRefMut, MapError> { match self.maps.entry(name) {
self.maps Entry::Vacant(vacant) => {
.get(name) vacant.insert(map);
.ok_or_else(|| MapError::MapNotFound { Ok(())
name: name.to_owned(), }
}) Entry::Occupied(_) => Err(MapError::Occupied),
.and_then(|lock| { }
lock.try_write().map_err(|_| MapError::BorrowError {
name: name.to_owned(),
})
})
} }
/// An iterator over all the maps. /// An iterator over all the maps.
@ -447,23 +446,16 @@ impl Bpf {
/// println!( /// println!(
/// "found map `{}` of type `{:?}`", /// "found map `{}` of type `{:?}`",
/// name, /// name,
/// map?.map_type().unwrap() /// map.map_type().unwrap()
/// ); /// );
/// } /// }
/// # Ok::<(), aya::BpfError>(()) /// # Ok::<(), aya::BpfError>(())
/// ``` /// ```
pub fn maps(&self) -> impl Iterator<Item = (&str, Result<MapRef, MapError>)> { pub fn maps(&self) -> impl Iterator<Item = (&str, &Map)> {
let ret = self.maps.iter().map(|(name, lock)| { self.maps.iter().map(|(s, m)| (s.as_str(), m))
(
name.as_str(),
lock.try_read()
.map_err(|_| MapError::BorrowError { name: name.clone() }),
)
});
ret
} }
/// Returns a reference to the program with the given name. /// Returns a reference to the program with the given name if it exists.
/// ///
/// You can use this to inspect a program and its properties. To load and attach a program, use /// You can use this to inspect a program and its properties. To load and attach a program, use
/// [program_mut](Self::program_mut) instead. /// [program_mut](Self::program_mut) instead.
@ -483,7 +475,7 @@ impl Bpf {
self.programs.get(name) self.programs.get(name)
} }
/// Returns a mutable reference to the program with the given name. /// Returns a mutable reference to the program with the given name if it exists.
/// ///
/// Used to get a program before loading and attaching it. For more details on programs and /// Used to get a program before loading and attaching it. For more details on programs and
/// their usage, see the [programs module documentation](crate::programs). /// their usage, see the [programs module documentation](crate::programs).
@ -504,7 +496,7 @@ impl Bpf {
self.programs.get_mut(name) self.programs.get_mut(name)
} }
/// An iterator over all the programs. /// An iterator over all of the programs.
/// ///
/// # Examples /// # Examples
/// ```no_run /// ```no_run

@ -7,7 +7,7 @@ use std::{
use crate::{ use crate::{
generated::bpf_map_type::BPF_MAP_TYPE_ARRAY, generated::bpf_map_type::BPF_MAP_TYPE_ARRAY,
maps::{IterableMap, Map, MapError, MapRef, MapRefMut}, maps::{IterableMap, Map, MapError},
sys::{bpf_map_lookup_elem, bpf_map_update_elem}, sys::{bpf_map_lookup_elem, bpf_map_update_elem},
Pod, Pod,
}; };
@ -23,11 +23,11 @@ use crate::{
/// ///
/// # Examples /// # Examples
/// ```no_run /// ```no_run
/// # let bpf = aya::Bpf::load(&[])?; /// # let mut bpf = aya::Bpf::load(&[])?;
/// use aya::maps::Array; /// use aya::maps::Array;
/// use std::convert::TryFrom; /// use std::convert::TryFrom;
/// ///
/// let mut array = Array::try_from(bpf.map_mut("ARRAY")?)?; /// let mut array = Array::try_from(bpf.map_mut("ARRAY").unwrap())?;
/// array.set(1, 42, 0)?; /// array.set(1, 42, 0)?;
/// assert_eq!(array.get(&1, 0)?, 42); /// assert_eq!(array.get(&1, 0)?, 42);
/// # Ok::<(), aya::BpfError>(()) /// # Ok::<(), aya::BpfError>(())
@ -139,18 +139,18 @@ impl<T: Deref<Target = Map>, V: Pod> IterableMap<u32, V> for Array<T, V> {
} }
} }
impl<V: Pod> TryFrom<MapRef> for Array<MapRef, V> { impl<'a, V: Pod> TryFrom<&'a Map> for Array<&'a Map, V> {
type Error = MapError; type Error = MapError;
fn try_from(a: MapRef) -> Result<Array<MapRef, V>, MapError> { fn try_from(a: &'a Map) -> Result<Array<&'a Map, V>, MapError> {
Array::new(a) Array::new(a)
} }
} }
impl<V: Pod> TryFrom<MapRefMut> for Array<MapRefMut, V> { impl<'a, V: Pod> TryFrom<&'a mut Map> for Array<&'a mut Map, V> {
type Error = MapError; type Error = MapError;
fn try_from(a: MapRefMut) -> Result<Array<MapRefMut, V>, MapError> { fn try_from(a: &'a mut Map) -> Result<Array<&'a mut Map, V>, MapError> {
Array::new(a) Array::new(a)
} }
} }

@ -7,7 +7,7 @@ use std::{
use crate::{ use crate::{
generated::bpf_map_type::BPF_MAP_TYPE_PERCPU_ARRAY, generated::bpf_map_type::BPF_MAP_TYPE_PERCPU_ARRAY,
maps::{IterableMap, Map, MapError, MapRef, MapRefMut, PerCpuValues}, maps::{IterableMap, Map, MapError, PerCpuValues},
sys::{bpf_map_lookup_elem_per_cpu, bpf_map_update_elem_per_cpu}, sys::{bpf_map_lookup_elem_per_cpu, bpf_map_update_elem_per_cpu},
Pod, Pod,
}; };
@ -32,12 +32,12 @@ use crate::{
/// # #[error(transparent)] /// # #[error(transparent)]
/// # Bpf(#[from] aya::BpfError) /// # Bpf(#[from] aya::BpfError)
/// # } /// # }
/// # let bpf = aya::Bpf::load(&[])?; /// # let mut bpf = aya::Bpf::load(&[])?;
/// use aya::maps::{PerCpuArray, PerCpuValues}; /// use aya::maps::{PerCpuArray, PerCpuValues};
/// use aya::util::nr_cpus; /// use aya::util::nr_cpus;
/// use std::convert::TryFrom; /// use std::convert::TryFrom;
/// ///
/// let mut array = PerCpuArray::try_from(bpf.map_mut("ARRAY")?)?; /// let mut array = PerCpuArray::try_from(bpf.map_mut("ARRAY").unwrap())?;
/// ///
/// // set array[1] = 42 for all cpus /// // set array[1] = 42 for all cpus
/// let nr_cpus = nr_cpus()?; /// let nr_cpus = nr_cpus()?;
@ -158,18 +158,18 @@ impl<T: Deref<Target = Map>, V: Pod> IterableMap<u32, PerCpuValues<V>> for PerCp
} }
} }
impl<V: Pod> TryFrom<MapRef> for PerCpuArray<MapRef, V> { impl<'a, V: Pod> TryFrom<&'a Map> for PerCpuArray<&'a Map, V> {
type Error = MapError; type Error = MapError;
fn try_from(a: MapRef) -> Result<PerCpuArray<MapRef, V>, MapError> { fn try_from(a: &'a Map) -> Result<PerCpuArray<&'a Map, V>, MapError> {
PerCpuArray::new(a) PerCpuArray::new(a)
} }
} }
impl<V: Pod> TryFrom<MapRefMut> for PerCpuArray<MapRefMut, V> { impl<'a, V: Pod> TryFrom<&'a mut Map> for PerCpuArray<&'a mut Map, V> {
type Error = MapError; type Error = MapError;
fn try_from(a: MapRefMut) -> Result<PerCpuArray<MapRefMut, V>, MapError> { fn try_from(a: &'a mut Map) -> Result<PerCpuArray<&'a mut Map, V>, MapError> {
PerCpuArray::new(a) PerCpuArray::new(a)
} }
} }

@ -9,7 +9,7 @@ use std::{
use crate::{ use crate::{
generated::bpf_map_type::BPF_MAP_TYPE_PROG_ARRAY, generated::bpf_map_type::BPF_MAP_TYPE_PROG_ARRAY,
maps::{Map, MapError, MapKeys, MapRef, MapRefMut}, maps::{Map, MapError, MapKeys},
programs::ProgramFd, programs::ProgramFd,
sys::{bpf_map_delete_elem, bpf_map_update_elem}, sys::{bpf_map_delete_elem, bpf_map_update_elem},
}; };
@ -26,12 +26,13 @@ use crate::{
/// ///
/// # Examples /// # Examples
/// ```no_run /// ```no_run
/// # let bpf = aya::Bpf::load(&[])?; /// # let mut bpf = aya::Bpf::load(&[])?;
/// use aya::maps::ProgramArray; /// use aya::maps::ProgramArray;
/// use aya::programs::{CgroupSkb, ProgramFd}; /// use aya::programs::{CgroupSkb, ProgramFd};
/// use std::convert::{TryFrom, TryInto}; /// use std::convert::{TryFrom, TryInto};
/// ///
/// let mut prog_array = ProgramArray::try_from(bpf.map_mut("JUMP_TABLE")?)?; /// let (name, mut map) = bpf.take_map("JUMP_TABLE").unwrap();
/// let mut prog_array = ProgramArray::try_from(&mut map)?;
/// let prog_0: &CgroupSkb = bpf.program("example_prog_0").unwrap().try_into()?; /// let prog_0: &CgroupSkb = bpf.program("example_prog_0").unwrap().try_into()?;
/// let prog_1: &CgroupSkb = bpf.program("example_prog_1").unwrap().try_into()?; /// let prog_1: &CgroupSkb = bpf.program("example_prog_1").unwrap().try_into()?;
/// let prog_2: &CgroupSkb = bpf.program("example_prog_2").unwrap().try_into()?; /// let prog_2: &CgroupSkb = bpf.program("example_prog_2").unwrap().try_into()?;
@ -46,6 +47,8 @@ use crate::{
/// ///
/// // bpf_tail_call(ctx, JUMP_TABLE, 2) will jump to prog_2 /// // bpf_tail_call(ctx, JUMP_TABLE, 2) will jump to prog_2
/// prog_array.set(2, prog_2, flags); /// prog_array.set(2, prog_2, flags);
///
/// bpf.return_map(name, map)?;
/// # Ok::<(), aya::BpfError>(()) /// # Ok::<(), aya::BpfError>(())
/// ``` /// ```
#[doc(alias = "BPF_MAP_TYPE_PROG_ARRAY")] #[doc(alias = "BPF_MAP_TYPE_PROG_ARRAY")]
@ -130,18 +133,18 @@ impl<T: Deref<Target = Map> + DerefMut<Target = Map>> ProgramArray<T> {
} }
} }
impl TryFrom<MapRef> for ProgramArray<MapRef> { impl<'a> TryFrom<&'a Map> for ProgramArray<&'a Map> {
type Error = MapError; type Error = MapError;
fn try_from(a: MapRef) -> Result<ProgramArray<MapRef>, MapError> { fn try_from(a: &'a Map) -> Result<ProgramArray<&'a Map>, MapError> {
ProgramArray::new(a) ProgramArray::new(a)
} }
} }
impl TryFrom<MapRefMut> for ProgramArray<MapRefMut> { impl<'a> TryFrom<&'a mut Map> for ProgramArray<&'a mut Map> {
type Error = MapError; type Error = MapError;
fn try_from(a: MapRefMut) -> Result<ProgramArray<MapRefMut>, MapError> { fn try_from(a: &'a mut Map) -> Result<ProgramArray<&'a mut Map>, MapError> {
ProgramArray::new(a) ProgramArray::new(a)
} }
} }

@ -6,7 +6,7 @@ use std::{
use crate::{ use crate::{
generated::bpf_map_type::{BPF_MAP_TYPE_HASH, BPF_MAP_TYPE_LRU_HASH}, 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, Map, MapError, MapIter, MapKeys},
sys::bpf_map_lookup_elem, sys::bpf_map_lookup_elem,
Pod, Pod,
}; };
@ -20,11 +20,11 @@ use crate::{
/// # Examples /// # Examples
/// ///
/// ```no_run /// ```no_run
/// # let bpf = aya::Bpf::load(&[])?; /// # let mut bpf = aya::Bpf::load(&[])?;
/// use aya::maps::HashMap; /// use aya::maps::HashMap;
/// use std::convert::TryFrom; /// use std::convert::TryFrom;
/// ///
/// let mut redirect_ports = HashMap::try_from(bpf.map_mut("REDIRECT_PORTS")?)?; /// let mut redirect_ports = HashMap::try_from(bpf.map_mut("REDIRECT_PORTS").unwrap())?;
/// ///
/// // redirect port 80 to 8080 /// // redirect port 80 to 8080
/// redirect_ports.insert(80, 8080, 0); /// redirect_ports.insert(80, 8080, 0);
@ -108,22 +108,6 @@ impl<T: Deref<Target = Map>, K: Pod, V: Pod> IterableMap<K, V> for HashMap<T, K,
} }
} }
impl<K: Pod, V: Pod> TryFrom<MapRef> for HashMap<MapRef, K, V> {
type Error = MapError;
fn try_from(a: MapRef) -> Result<HashMap<MapRef, K, V>, MapError> {
HashMap::new(a)
}
}
impl<K: Pod, V: Pod> TryFrom<MapRefMut> for HashMap<MapRefMut, K, V> {
type Error = MapError;
fn try_from(a: MapRefMut) -> Result<HashMap<MapRefMut, K, V>, MapError> {
HashMap::new(a)
}
}
impl<'a, K: Pod, V: Pod> TryFrom<&'a Map> for HashMap<&'a Map, K, V> { impl<'a, K: Pod, V: Pod> TryFrom<&'a Map> for HashMap<&'a Map, K, V> {
type Error = MapError; type Error = MapError;

@ -7,9 +7,7 @@ use std::{
use crate::{ use crate::{
generated::bpf_map_type::{BPF_MAP_TYPE_LRU_PERCPU_HASH, BPF_MAP_TYPE_PERCPU_HASH}, generated::bpf_map_type::{BPF_MAP_TYPE_LRU_PERCPU_HASH, BPF_MAP_TYPE_PERCPU_HASH},
maps::{ maps::{hash_map, IterableMap, Map, MapError, MapIter, MapKeys, PerCpuValues},
hash_map, IterableMap, Map, MapError, MapIter, MapKeys, MapRef, MapRefMut, PerCpuValues,
},
sys::{bpf_map_lookup_elem_per_cpu, bpf_map_update_elem_per_cpu}, sys::{bpf_map_lookup_elem_per_cpu, bpf_map_update_elem_per_cpu},
Pod, Pod,
}; };
@ -27,14 +25,14 @@ use crate::{
/// # Examples /// # Examples
/// ///
/// ```no_run /// ```no_run
/// # let bpf = aya::Bpf::load(&[])?; /// # let mut bpf = aya::Bpf::load(&[])?;
/// use aya::maps::PerCpuHashMap; /// use aya::maps::PerCpuHashMap;
/// use std::convert::TryFrom; /// use std::convert::TryFrom;
/// ///
/// const CPU_IDS: u8 = 1; /// const CPU_IDS: u8 = 1;
/// const WAKEUPS: u8 = 2; /// const WAKEUPS: u8 = 2;
/// ///
/// let mut hm = PerCpuHashMap::<_, u8, u32>::try_from(bpf.map("COUNTERS")?)?; /// let mut hm = PerCpuHashMap::<_, u8, u32>::try_from(bpf.map("COUNTERS").unwrap())?;
/// let cpu_ids = unsafe { hm.get(&CPU_IDS, 0)? }; /// let cpu_ids = unsafe { hm.get(&CPU_IDS, 0)? };
/// let wakeups = unsafe { hm.get(&WAKEUPS, 0)? }; /// let wakeups = unsafe { hm.get(&WAKEUPS, 0)? };
/// for (cpu_id, wakeups) in cpu_ids.iter().zip(wakeups.iter()) { /// for (cpu_id, wakeups) in cpu_ids.iter().zip(wakeups.iter()) {
@ -113,14 +111,14 @@ impl<T: DerefMut<Target = Map>, K: Pod, V: Pod> PerCpuHashMap<T, K, V> {
/// # #[error(transparent)] /// # #[error(transparent)]
/// # Bpf(#[from] aya::BpfError) /// # Bpf(#[from] aya::BpfError)
/// # } /// # }
/// # let bpf = aya::Bpf::load(&[])?; /// # let mut bpf = aya::Bpf::load(&[])?;
/// use aya::maps::{PerCpuHashMap, PerCpuValues}; /// use aya::maps::{PerCpuHashMap, PerCpuValues};
/// use aya::util::nr_cpus; /// use aya::util::nr_cpus;
/// use std::convert::TryFrom; /// use std::convert::TryFrom;
/// ///
/// const RETRIES: u8 = 1; /// const RETRIES: u8 = 1;
/// ///
/// let mut hm = PerCpuHashMap::<_, u8, u32>::try_from(bpf.map_mut("PER_CPU_STORAGE")?)?; /// let mut hm = PerCpuHashMap::<_, u8, u32>::try_from(bpf.map_mut("PER_CPU_STORAGE").unwrap())?;
/// hm.insert( /// hm.insert(
/// RETRIES, /// RETRIES,
/// PerCpuValues::try_from(vec![3u32; nr_cpus()?])?, /// PerCpuValues::try_from(vec![3u32; nr_cpus()?])?,
@ -159,22 +157,6 @@ impl<T: Deref<Target = Map>, K: Pod, V: Pod> IterableMap<K, PerCpuValues<V>>
} }
} }
impl<K: Pod, V: Pod> TryFrom<MapRef> for PerCpuHashMap<MapRef, K, V> {
type Error = MapError;
fn try_from(a: MapRef) -> Result<PerCpuHashMap<MapRef, K, V>, MapError> {
PerCpuHashMap::new(a)
}
}
impl<K: Pod, V: Pod> TryFrom<MapRefMut> for PerCpuHashMap<MapRefMut, K, V> {
type Error = MapError;
fn try_from(a: MapRefMut) -> Result<PerCpuHashMap<MapRefMut, K, V>, MapError> {
PerCpuHashMap::new(a)
}
}
impl<'a, K: Pod, V: Pod> TryFrom<&'a Map> for PerCpuHashMap<&'a Map, K, V> { impl<'a, K: Pod, V: Pod> TryFrom<&'a Map> for PerCpuHashMap<&'a Map, K, V> {
type Error = MapError; type Error = MapError;

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

@ -11,7 +11,7 @@
//! //!
//! The eBPF API includes many map types each supporting different operations. //! The eBPF API includes many map types each supporting different operations.
//! [`Bpf::map`](crate::Bpf::map) and [`Bpf::map_mut`](crate::Bpf::map_mut) always return the //! [`Bpf::map`](crate::Bpf::map) and [`Bpf::map_mut`](crate::Bpf::map_mut) always return the
//! opaque [`MapRef`] and [`MapRefMut`] types respectively. Those two types can be converted to //! opaque &Map and &mut Map types respectively. Those two types can be converted to
//! *typed maps* using the [`TryFrom`](std::convert::TryFrom) trait. For example: //! *typed maps* using the [`TryFrom`](std::convert::TryFrom) trait. For example:
//! //!
//! ```no_run //! ```no_run
@ -20,10 +20,12 @@
//! use aya::maps::SockMap; //! use aya::maps::SockMap;
//! use aya::programs::SkMsg; //! use aya::programs::SkMsg;
//! //!
//! let intercept_egress = SockMap::try_from(bpf.map_mut("INTERCEPT_EGRESS")?)?; //! let (name, mut map) = bpf.take_map("INTERCEPT_EGRESS").unwrap();
//! let intercept_egress = SockMap::try_from(&mut map)?;
//! let prog: &mut SkMsg = bpf.program_mut("intercept_egress_packet").unwrap().try_into()?; //! let prog: &mut SkMsg = bpf.program_mut("intercept_egress_packet").unwrap().try_into()?;
//! prog.load()?; //! prog.load()?;
//! prog.attach(&intercept_egress)?; //! prog.attach(&intercept_egress)?;
//! bpf.return_map(name, map)?;
//! # Ok::<(), aya::BpfError>(()) //! # Ok::<(), aya::BpfError>(())
//! ``` //! ```
//! //!
@ -46,8 +48,6 @@ use crate::{
Pod, Pod,
}; };
mod map_lock;
pub mod array; pub mod array;
pub mod hash_map; pub mod hash_map;
pub mod perf; pub mod perf;
@ -58,7 +58,6 @@ pub mod stack_trace;
pub use array::{Array, PerCpuArray, ProgramArray}; pub use array::{Array, PerCpuArray, ProgramArray};
pub use hash_map::{HashMap, PerCpuHashMap}; pub use hash_map::{HashMap, PerCpuHashMap};
pub use map_lock::*;
pub use perf::PerfEventArray; pub use perf::PerfEventArray;
pub use queue::Queue; pub use queue::Queue;
pub use sock::{SockHash, SockMap}; pub use sock::{SockHash, SockMap};
@ -67,8 +66,8 @@ pub use stack_trace::StackTraceMap;
#[derive(Error, Debug)] #[derive(Error, Debug)]
pub enum MapError { pub enum MapError {
#[error("map `{name}` not found ")] #[error("map already exists")]
MapNotFound { name: String }, Occupied,
#[error("invalid map type {map_type}")] #[error("invalid map type {map_type}")]
InvalidMapType { map_type: u32 }, InvalidMapType { map_type: u32 },
@ -129,12 +128,6 @@ pub enum MapError {
#[source] #[source]
io_error: io::Error, io_error: io::Error,
}, },
#[error("map `{name}` is borrowed mutably")]
BorrowError { name: String },
#[error("map `{name}` is already borrowed")]
BorrowMutError { name: String },
} }
/// A generic handle to a BPF map. /// A generic handle to a BPF map.

@ -13,7 +13,7 @@ use tokio::io::unix::AsyncFd;
use crate::maps::{ use crate::maps::{
perf::{Events, PerfBufferError, PerfEventArray, PerfEventArrayBuffer}, perf::{Events, PerfBufferError, PerfEventArray, PerfEventArrayBuffer},
Map, MapError, MapRefMut, Map, MapError,
}; };
/// A `Future` based map that can be used to receive events from eBPF programs using the linux /// A `Future` based map that can be used to receive events from eBPF programs using the linux
@ -198,10 +198,10 @@ impl<T: DerefMut<Target = Map>> AsyncPerfEventArrayBuffer<T> {
} }
} }
impl TryFrom<MapRefMut> for AsyncPerfEventArray<MapRefMut> { impl<'a> TryFrom<&'a mut Map> for AsyncPerfEventArray<&'a mut Map> {
type Error = MapError; type Error = MapError;
fn try_from(a: MapRefMut) -> Result<AsyncPerfEventArray<MapRefMut>, MapError> { fn try_from(a: &'a mut Map) -> Result<AsyncPerfEventArray<&'a mut Map>, MapError> {
AsyncPerfEventArray::new(a) AsyncPerfEventArray::new(a)
} }
} }

@ -15,7 +15,7 @@ use crate::{
generated::bpf_map_type::BPF_MAP_TYPE_PERF_EVENT_ARRAY, generated::bpf_map_type::BPF_MAP_TYPE_PERF_EVENT_ARRAY,
maps::{ maps::{
perf::{Events, PerfBuffer, PerfBufferError}, perf::{Events, PerfBuffer, PerfBufferError},
Map, MapError, MapRefMut, Map, MapError,
}, },
sys::bpf_map_update_elem, sys::bpf_map_update_elem,
}; };
@ -109,13 +109,13 @@ impl<T: DerefMut<Target = Map>> AsRawFd for PerfEventArrayBuffer<T> {
/// # #[error(transparent)] /// # #[error(transparent)]
/// # PerfBuf(#[from] aya::maps::perf::PerfBufferError), /// # PerfBuf(#[from] aya::maps::perf::PerfBufferError),
/// # } /// # }
/// # let bpf = aya::Bpf::load(&[])?; /// # let mut bpf = aya::Bpf::load(&[])?;
/// use aya::maps::PerfEventArray; /// use aya::maps::PerfEventArray;
/// use aya::util::online_cpus; /// use aya::util::online_cpus;
/// use std::convert::{TryFrom, TryInto}; /// use std::convert::{TryFrom, TryInto};
/// use bytes::BytesMut; /// use bytes::BytesMut;
/// ///
/// let mut perf_array = PerfEventArray::try_from(bpf.map_mut("EVENTS")?)?; /// let mut perf_array = PerfEventArray::try_from(bpf.map_mut("EVENTS").unwrap())?;
/// ///
/// // eBPF programs are going to write to the EVENTS perf array, using the id of the CPU they're /// // eBPF programs are going to write to the EVENTS perf array, using the id of the CPU they're
/// // running on as the array index. /// // running on as the array index.
@ -205,10 +205,10 @@ impl<T: DerefMut<Target = Map>> PerfEventArray<T> {
} }
} }
impl TryFrom<MapRefMut> for PerfEventArray<MapRefMut> { impl<'a> TryFrom<&'a mut Map> for PerfEventArray<&'a mut Map> {
type Error = MapError; type Error = MapError;
fn try_from(a: MapRefMut) -> Result<PerfEventArray<MapRefMut>, MapError> { fn try_from(a: &'a mut Map) -> Result<PerfEventArray<&'a mut Map>, MapError> {
PerfEventArray::new(a) PerfEventArray::new(a)
} }
} }

@ -8,7 +8,7 @@ use std::{
use crate::{ use crate::{
generated::bpf_map_type::BPF_MAP_TYPE_QUEUE, generated::bpf_map_type::BPF_MAP_TYPE_QUEUE,
maps::{Map, MapError, MapRef, MapRefMut}, maps::{Map, MapError},
sys::{bpf_map_lookup_and_delete_elem, bpf_map_push_elem}, sys::{bpf_map_lookup_and_delete_elem, bpf_map_push_elem},
Pod, Pod,
}; };
@ -21,11 +21,11 @@ use crate::{
/// ///
/// # Examples /// # Examples
/// ```no_run /// ```no_run
/// # let bpf = aya::Bpf::load(&[])?; /// # let mut bpf = aya::Bpf::load(&[])?;
/// use aya::maps::Queue; /// use aya::maps::Queue;
/// use std::convert::TryFrom; /// use std::convert::TryFrom;
/// ///
/// let mut queue = Queue::try_from(bpf.map_mut("ARRAY")?)?; /// let mut queue = Queue::try_from(bpf.map_mut("ARRAY").unwrap())?;
/// queue.push(42, 0)?; /// queue.push(42, 0)?;
/// queue.push(43, 0)?; /// queue.push(43, 0)?;
/// assert_eq!(queue.pop(0)?, 42); /// assert_eq!(queue.pop(0)?, 42);
@ -110,18 +110,18 @@ impl<T: Deref<Target = Map> + DerefMut<Target = Map>, V: Pod> Queue<T, V> {
} }
} }
impl<V: Pod> TryFrom<MapRef> for Queue<MapRef, V> { impl<'a, V: Pod> TryFrom<&'a Map> for Queue<&'a Map, V> {
type Error = MapError; type Error = MapError;
fn try_from(a: MapRef) -> Result<Queue<MapRef, V>, MapError> { fn try_from(a: &'a Map) -> Result<Queue<&'a Map, V>, MapError> {
Queue::new(a) Queue::new(a)
} }
} }
impl<V: Pod> TryFrom<MapRefMut> for Queue<MapRefMut, V> { impl<'a, V: Pod> TryFrom<&'a mut Map> for Queue<&'a mut Map, V> {
type Error = MapError; type Error = MapError;
fn try_from(a: MapRefMut) -> Result<Queue<MapRefMut, V>, MapError> { fn try_from(a: &'a mut Map) -> Result<Queue<&'a mut Map, V>, MapError> {
Queue::new(a) Queue::new(a)
} }
} }

@ -7,9 +7,7 @@ use std::{
use crate::{ use crate::{
generated::bpf_map_type::BPF_MAP_TYPE_SOCKHASH, generated::bpf_map_type::BPF_MAP_TYPE_SOCKHASH,
maps::{ maps::{hash_map, sock::SocketMap, IterableMap, Map, MapError, MapIter, MapKeys},
hash_map, sock::SocketMap, IterableMap, Map, MapError, MapIter, MapKeys, MapRef, MapRefMut,
},
sys::bpf_map_lookup_elem, sys::bpf_map_lookup_elem,
Pod, Pod,
}; };
@ -49,13 +47,15 @@ use crate::{
/// use aya::maps::SockHash; /// use aya::maps::SockHash;
/// use aya::programs::SkMsg; /// use aya::programs::SkMsg;
/// ///
/// let mut intercept_egress = SockHash::try_from(bpf.map_mut("INTERCEPT_EGRESS")?)?; /// let (name, mut map) = bpf.take_map("INTERCEPT_EGRESS").unwrap();
/// let mut intercept_egress = SockHash::try_from(&mut map)?;
/// let prog: &mut SkMsg = bpf.program_mut("intercept_egress_packet").unwrap().try_into()?; /// let prog: &mut SkMsg = bpf.program_mut("intercept_egress_packet").unwrap().try_into()?;
/// prog.load()?; /// prog.load()?;
/// prog.attach(&intercept_egress)?; /// prog.attach(&intercept_egress)?;
/// ///
/// let mut client = TcpStream::connect("127.0.0.1:1234")?; /// let mut client = TcpStream::connect("127.0.0.1:1234")?;
/// intercept_egress.insert(1234, client.as_raw_fd(), 0)?; /// intercept_egress.insert(1234, client.as_raw_fd(), 0)?;
/// bpf.return_map(name, map)?;
/// ///
/// // the write will be intercepted /// // the write will be intercepted
/// client.write_all(b"foo")?; /// client.write_all(b"foo")?;
@ -140,18 +140,18 @@ impl<T: DerefMut<Target = Map>, K: Pod> SocketMap for SockHash<T, K> {
} }
} }
impl<K: Pod> TryFrom<MapRef> for SockHash<MapRef, K> { impl<'a, K: Pod> TryFrom<&'a Map> for SockHash<&'a Map, K> {
type Error = MapError; type Error = MapError;
fn try_from(a: MapRef) -> Result<SockHash<MapRef, K>, MapError> { fn try_from(a: &'a Map) -> Result<SockHash<&'a Map, K>, MapError> {
SockHash::new(a) SockHash::new(a)
} }
} }
impl<K: Pod> TryFrom<MapRefMut> for SockHash<MapRefMut, K> { impl<'a, K: Pod> TryFrom<&'a mut Map> for SockHash<&'a mut Map, K> {
type Error = MapError; type Error = MapError;
fn try_from(a: MapRefMut) -> Result<SockHash<MapRefMut, K>, MapError> { fn try_from(a: &'a mut Map) -> Result<SockHash<&'a mut Map, K>, MapError> {
SockHash::new(a) SockHash::new(a)
} }
} }

@ -9,7 +9,7 @@ use std::{
use crate::{ use crate::{
generated::bpf_map_type::BPF_MAP_TYPE_SOCKMAP, generated::bpf_map_type::BPF_MAP_TYPE_SOCKMAP,
maps::{sock::SocketMap, Map, MapError, MapKeys, MapRef, MapRefMut}, maps::{sock::SocketMap, Map, MapError, MapKeys},
sys::{bpf_map_delete_elem, bpf_map_update_elem}, sys::{bpf_map_delete_elem, bpf_map_update_elem},
}; };
@ -34,10 +34,12 @@ use crate::{
/// use aya::maps::SockMap; /// use aya::maps::SockMap;
/// use aya::programs::SkSkb; /// use aya::programs::SkSkb;
/// ///
/// let intercept_ingress = SockMap::try_from(bpf.map_mut("INTERCEPT_INGRESS")?)?; /// let (name, mut map) = bpf.take_map("INTERCEPT_EGRESS").unwrap();
/// let intercept_ingress = SockMap::try_from(&mut map)?;
/// let prog: &mut SkSkb = bpf.program_mut("intercept_ingress_packet").unwrap().try_into()?; /// let prog: &mut SkSkb = bpf.program_mut("intercept_ingress_packet").unwrap().try_into()?;
/// prog.load()?; /// prog.load()?;
/// prog.attach(&intercept_ingress)?; /// prog.attach(&intercept_ingress)?;
/// bpf.return_map(name, map)?;
/// # Ok::<(), aya::BpfError>(()) /// # Ok::<(), aya::BpfError>(())
/// ``` /// ```
#[doc(alias = "BPF_MAP_TYPE_SOCKMAP")] #[doc(alias = "BPF_MAP_TYPE_SOCKMAP")]
@ -120,18 +122,18 @@ impl<T: Deref<Target = Map> + DerefMut<Target = Map>> SocketMap for SockMap<T> {
} }
} }
impl TryFrom<MapRef> for SockMap<MapRef> { impl<'a> TryFrom<&'a Map> for SockMap<&'a Map> {
type Error = MapError; type Error = MapError;
fn try_from(a: MapRef) -> Result<SockMap<MapRef>, MapError> { fn try_from(a: &'a Map) -> Result<SockMap<&'a Map>, MapError> {
SockMap::new(a) SockMap::new(a)
} }
} }
impl TryFrom<MapRefMut> for SockMap<MapRefMut> { impl<'a> TryFrom<&'a mut Map> for SockMap<&'a mut Map> {
type Error = MapError; type Error = MapError;
fn try_from(a: MapRefMut) -> Result<SockMap<MapRefMut>, MapError> { fn try_from(a: &'a mut Map) -> Result<SockMap<&'a mut Map>, MapError> {
SockMap::new(a) SockMap::new(a)
} }
} }

@ -8,7 +8,7 @@ use std::{
use crate::{ use crate::{
generated::bpf_map_type::BPF_MAP_TYPE_STACK, generated::bpf_map_type::BPF_MAP_TYPE_STACK,
maps::{Map, MapError, MapRef, MapRefMut}, maps::{Map, MapError},
sys::{bpf_map_lookup_and_delete_elem, bpf_map_update_elem}, sys::{bpf_map_lookup_and_delete_elem, bpf_map_update_elem},
Pod, Pod,
}; };
@ -21,11 +21,11 @@ use crate::{
/// ///
/// # Examples /// # Examples
/// ```no_run /// ```no_run
/// # let bpf = aya::Bpf::load(&[])?; /// # let mut bpf = aya::Bpf::load(&[])?;
/// use aya::maps::Stack; /// use aya::maps::Stack;
/// use std::convert::TryFrom; /// use std::convert::TryFrom;
/// ///
/// let mut stack = Stack::try_from(bpf.map_mut("STACK")?)?; /// let mut stack = Stack::try_from(bpf.map_mut("STACK").unwrap())?;
/// stack.push(42, 0)?; /// stack.push(42, 0)?;
/// stack.push(43, 0)?; /// stack.push(43, 0)?;
/// assert_eq!(stack.pop(0)?, 43); /// assert_eq!(stack.pop(0)?, 43);
@ -110,18 +110,18 @@ impl<T: Deref<Target = Map> + DerefMut<Target = Map>, V: Pod> Stack<T, V> {
} }
} }
impl<V: Pod> TryFrom<MapRef> for Stack<MapRef, V> { impl<'a, V: Pod> TryFrom<&'a Map> for Stack<&'a Map, V> {
type Error = MapError; type Error = MapError;
fn try_from(a: MapRef) -> Result<Stack<MapRef, V>, MapError> { fn try_from(a: &'a Map) -> Result<Stack<&'a Map, V>, MapError> {
Stack::new(a) Stack::new(a)
} }
} }
impl<V: Pod> TryFrom<MapRefMut> for Stack<MapRefMut, V> { impl<'a, V: Pod> TryFrom<&'a mut Map> for Stack<&'a mut Map, V> {
type Error = MapError; type Error = MapError;
fn try_from(a: MapRefMut) -> Result<Stack<MapRefMut, V>, MapError> { fn try_from(a: &'a mut Map) -> Result<Stack<&'a mut Map, V>, MapError> {
Stack::new(a) Stack::new(a)
} }
} }

@ -7,7 +7,7 @@ use std::{
use crate::{ use crate::{
generated::bpf_map_type::BPF_MAP_TYPE_STACK_TRACE, generated::bpf_map_type::BPF_MAP_TYPE_STACK_TRACE,
maps::{IterableMap, Map, MapError, MapIter, MapKeys, MapRef, MapRefMut}, maps::{IterableMap, Map, MapError, MapIter, MapKeys},
sys::bpf_map_lookup_elem_ptr, sys::bpf_map_lookup_elem_ptr,
}; };
@ -39,7 +39,7 @@ use crate::{
/// use aya::util::kernel_symbols; /// use aya::util::kernel_symbols;
/// use std::convert::TryFrom; /// use std::convert::TryFrom;
/// ///
/// let mut stack_traces = StackTraceMap::try_from(bpf.map("STACK_TRACES")?)?; /// let mut stack_traces = StackTraceMap::try_from(bpf.map("STACK_TRACES").unwrap())?;
/// // load kernel symbols from /proc/kallsyms /// // load kernel symbols from /proc/kallsyms
/// let ksyms = kernel_symbols()?; /// let ksyms = kernel_symbols()?;
/// ///
@ -161,18 +161,18 @@ impl<T: Deref<Target = Map>> IterableMap<u32, StackTrace> for StackTraceMap<T> {
} }
} }
impl TryFrom<MapRef> for StackTraceMap<MapRef> { impl<'a> TryFrom<&'a Map> for StackTraceMap<&'a Map> {
type Error = MapError; type Error = MapError;
fn try_from(a: MapRef) -> Result<StackTraceMap<MapRef>, MapError> { fn try_from(a: &'a Map) -> Result<StackTraceMap<&'a Map>, MapError> {
StackTraceMap::new(a) StackTraceMap::new(a)
} }
} }
impl TryFrom<MapRefMut> for StackTraceMap<MapRefMut> { impl<'a> TryFrom<&'a mut Map> for StackTraceMap<&'a mut Map> {
type Error = MapError; type Error = MapError;
fn try_from(a: MapRefMut) -> Result<StackTraceMap<MapRefMut>, MapError> { fn try_from(a: &'a mut Map) -> Result<StackTraceMap<&'a mut Map>, MapError> {
StackTraceMap::new(a) StackTraceMap::new(a)
} }
} }

@ -37,7 +37,8 @@ use crate::{
/// use aya::maps::SockHash; /// use aya::maps::SockHash;
/// use aya::programs::SkMsg; /// use aya::programs::SkMsg;
/// ///
/// let mut intercept_egress = SockHash::try_from(bpf.map_mut("INTERCEPT_EGRESS")?)?; /// let (name, mut map) = bpf.take_map("INTERCEPT_EGRESS").unwrap();
/// let mut intercept_egress = SockHash::try_from(&mut map)?;
/// let prog: &mut SkMsg = bpf.program_mut("intercept_egress_packet").unwrap().try_into()?; /// let prog: &mut SkMsg = bpf.program_mut("intercept_egress_packet").unwrap().try_into()?;
/// prog.load()?; /// prog.load()?;
/// prog.attach(&intercept_egress)?; /// prog.attach(&intercept_egress)?;
@ -47,6 +48,7 @@ use crate::{
/// ///
/// // the write will be intercepted /// // the write will be intercepted
/// client.write_all(b"foo")?; /// client.write_all(b"foo")?;
/// bpf.return_map(name, map)?;
/// # Ok::<(), Error>(()) /// # Ok::<(), Error>(())
/// ``` /// ```
/// ///

@ -33,10 +33,12 @@ pub enum SkSkbKind {
/// use aya::maps::SockMap; /// use aya::maps::SockMap;
/// use aya::programs::SkSkb; /// use aya::programs::SkSkb;
/// ///
/// let intercept_ingress = SockMap::try_from(bpf.map_mut("INTERCEPT_INGRESS")?)?; /// let (name, mut map) = bpf.take_map("INTERCEPT_EGRESS").unwrap();
/// let intercept_ingress = SockMap::try_from(&mut map)?;
/// let prog: &mut SkSkb = bpf.program_mut("intercept_ingress_packet").unwrap().try_into()?; /// let prog: &mut SkSkb = bpf.program_mut("intercept_ingress_packet").unwrap().try_into()?;
/// prog.load()?; /// prog.load()?;
/// prog.attach(&intercept_ingress)?; /// prog.attach(&intercept_ingress)?;
/// bpf.return_map(name, map)?;
/// # Ok::<(), aya::BpfError>(()) /// # Ok::<(), aya::BpfError>(())
/// ``` /// ```
/// ///

Loading…
Cancel
Save