Skip to content

Commit

Permalink
aya: Update XDP maps implementations
Browse files Browse the repository at this point in the history
Map impls changed since this was first written.

Fixes: 2b726c8 ("aya: Implement XDP Map Types")
  • Loading branch information
Tuetuopay committed Sep 22, 2023
1 parent e90d521 commit ede3e91
Show file tree
Hide file tree
Showing 6 changed files with 197 additions and 262 deletions.
4 changes: 4 additions & 0 deletions aya/src/bpf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -707,6 +707,10 @@ fn parse_map(data: (String, MapData)) -> Result<(String, Map), BpfError> {
BPF_MAP_TYPE_STACK => Map::Stack(map),
BPF_MAP_TYPE_STACK_TRACE => Map::StackTraceMap(map),
BPF_MAP_TYPE_QUEUE => Map::Queue(map),
BPF_MAP_TYPE_CPUMAP => Map::CpuMap(map),
BPF_MAP_TYPE_DEVMAP => Map::DevMap(map),
BPF_MAP_TYPE_DEVMAP_HASH => Map::DevMapHash(map),
BPF_MAP_TYPE_XSKMAP => Map::XskMap(map),
m => {
warn!("The map {name} is of type {:#?} which is currently unsupported in Aya, use `allow_unsupported_maps()` to load it anyways", m);
Map::Unsupported(map)
Expand Down
18 changes: 17 additions & 1 deletion aya/src/maps/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ pub use queue::Queue;
pub use sock::{SockHash, SockMap};
pub use stack::Stack;
pub use stack_trace::StackTraceMap;
pub use xdp::XskMap;
pub use xdp::{CpuMap, DevMap, DevMapHash, XskMap};

#[derive(Error, Debug)]
/// Errors occuring from working with Maps
Expand Down Expand Up @@ -267,6 +267,14 @@ pub enum Map {
StackTraceMap(MapData),
/// A [`Queue`] map
Queue(MapData),
/// A [`CpuMap`] map
CpuMap(MapData),
/// A [`DevMap`] map
DevMap(MapData),
/// A [`DevMapHash`] map
DevMapHash(MapData),
/// A [`XskMap`] map
XskMap(MapData),
/// An unsupported map type
Unsupported(MapData),
}
Expand All @@ -290,6 +298,10 @@ impl Map {
Self::Stack(map) => map.obj.map_type(),
Self::StackTraceMap(map) => map.obj.map_type(),
Self::Queue(map) => map.obj.map_type(),
Self::CpuMap(map) => map.obj.map_type(),
Self::DevMap(map) => map.obj.map_type(),
Self::DevMapHash(map) => map.obj.map_type(),
Self::XskMap(map) => map.obj.map_type(),
Self::Unsupported(map) => map.obj.map_type(),
}
}
Expand Down Expand Up @@ -349,6 +361,10 @@ impl_try_from_map!(() {
SockMap,
PerfEventArray,
StackTraceMap,
CpuMap,
DevMap,
DevMapHash,
XskMap,
});

#[cfg(any(feature = "async_tokio", feature = "async_std"))]
Expand Down
111 changes: 51 additions & 60 deletions aya/src/maps/xdp/cpu_map.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,10 @@
//! An array of available CPUs.

use std::{
convert::TryFrom,
mem,
ops::{Deref, DerefMut},
};
use std::borrow::{Borrow, BorrowMut};

use crate::{
generated::bpf_map_type::BPF_MAP_TYPE_CPUMAP,
maps::{Map, MapError, MapRef, MapRefMut},
sys::bpf_map_update_elem,
maps::{check_bounds, check_kv_size, IterableMap, MapData, MapError},
sys::{bpf_map_lookup_elem, bpf_map_update_elem, SyscallError},
};

/// An array of available CPUs.
Expand All @@ -19,15 +14,18 @@ use crate::{
///
/// # Minimum kernel version
///
/// The minimum kernel version required to use this feature is 4.2.
/// The minimum kernel version required to use this feature is 4.15.
///
/// # Examples
/// ```no_run
/// # let bpf = aya::Bpf::load(&[])?;
/// # let elf_bytes = &[];
/// use aya::maps::xdp::CpuMap;
/// use std::convert::{TryFrom, TryInto};
///
/// let mut cpumap = CpuMap::try_from(bpf.map_mut("CPUS")?)?;
/// let mut bpf = aya::BpfLoader::new()
/// .set_max_entries("CPUS", aya::util::nr_cpus().unwrap() as u32)
/// .load(elf_bytes)
/// .unwrap();
/// let mut cpumap = CpuMap::try_from(bpf.map_mut("CPUS").unwrap())?;
/// let flags = 0;
/// let queue_size = 2048;
/// for i in 0u32..8u32 {
Expand All @@ -37,84 +35,77 @@ use crate::{
/// # Ok::<(), aya::BpfError>(())
/// ```
#[doc(alias = "BPF_MAP_TYPE_CPUMAP")]
pub struct CpuMap<T: Deref<Target = Map>> {
pub struct CpuMap<T> {
inner: T,
}

impl<T: Deref<Target = Map>> CpuMap<T> {
fn new(map: T) -> Result<CpuMap<T>, MapError> {
let map_type = map.obj.def.map_type;
if map_type != BPF_MAP_TYPE_CPUMAP as u32 {
return Err(MapError::InvalidMapType {
map_type: map_type as u32,
});
}
let expected = mem::size_of::<u32>();
let size = map.obj.def.key_size as usize;
if size != expected {
return Err(MapError::InvalidKeySize { size, expected });
}

let expected = mem::size_of::<u32>();
let size = map.obj.def.value_size as usize;
if size != expected {
return Err(MapError::InvalidValueSize { size, expected });
}
let _fd = map.fd_or_err()?;
impl<T: Borrow<MapData>> CpuMap<T> {
pub(crate) fn new(map: T) -> Result<Self, MapError> {
let data = map.borrow();
check_kv_size::<u32, u32>(data)?;

Ok(CpuMap { inner: map })
Ok(Self { inner: map })
}

/// Returns the number of elements in the array.
///
/// This corresponds to the value of `bpf_map_def::max_entries` on the eBPF side.
pub fn len(&self) -> u32 {
self.inner.obj.def.max_entries
self.inner.borrow().obj.max_entries()
}

fn check_bounds(&self, index: u32) -> Result<(), MapError> {
let max_entries = self.inner.obj.def.max_entries;
if index >= self.inner.obj.def.max_entries {
Err(MapError::OutOfBounds { index, max_entries })
} else {
Ok(())
}
/// Returns the value stored at the given index.
///
/// # Errors
///
/// 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<u32, MapError> {
let data = self.inner.borrow();
check_bounds(data, index)?;
let fd = data.fd().as_fd();

let value =
bpf_map_lookup_elem(fd, &index, flags).map_err(|(_, io_error)| SyscallError {
call: "bpf_map_lookup_elem",
io_error,
})?;
value.ok_or(MapError::KeyNotFound)
}

/// An iterator over the elements of the map.
pub fn iter(&self) -> impl Iterator<Item = Result<u32, MapError>> + '_ {
(0..self.len()).map(move |i| self.get(i, 0))
}
}

impl<T: Deref<Target = Map> + DerefMut<Target = Map>> CpuMap<T> {
impl<T: BorrowMut<MapData>> CpuMap<T> {
/// Sets the value of the element at the given index.
///
/// # Errors
///
/// 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: u32, flags: u64) -> Result<(), MapError> {
let fd = self.inner.fd_or_err()?;
self.check_bounds(index)?;
bpf_map_update_elem(fd, &index, &value, flags).map_err(|(code, io_error)| {
MapError::SyscallError {
call: "bpf_map_update_elem".to_owned(),
code,
let data = self.inner.borrow_mut();
check_bounds(data, index)?;
let fd = data.fd().as_fd();
bpf_map_update_elem(fd, Some(&index), &value, flags).map_err(|(_, io_error)| {
SyscallError {
call: "bpf_map_update_elem",
io_error,
}
})?;
Ok(())
}
}

impl TryFrom<MapRef> for CpuMap<MapRef> {
type Error = MapError;

fn try_from(a: MapRef) -> Result<CpuMap<MapRef>, MapError> {
CpuMap::new(a)
impl<T: Borrow<MapData>> IterableMap<u32, u32> for CpuMap<T> {
fn map(&self) -> &MapData {
self.inner.borrow()
}
}

impl TryFrom<MapRefMut> for CpuMap<MapRefMut> {
type Error = MapError;

fn try_from(a: MapRefMut) -> Result<CpuMap<MapRefMut>, MapError> {
CpuMap::new(a)
fn get(&self, key: &u32) -> Result<u32, MapError> {
self.get(*key, 0)
}
}
112 changes: 50 additions & 62 deletions aya/src/maps/xdp/dev_map.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,10 @@
//! An array of network devices.

use std::{
convert::TryFrom,
mem,
ops::{Deref, DerefMut},
};
use std::borrow::{Borrow, BorrowMut};

use crate::{
generated::bpf_map_type::BPF_MAP_TYPE_DEVMAP,
maps::{Map, MapError, MapRef, MapRefMut},
sys::bpf_map_update_elem,
maps::{check_bounds, check_kv_size, IterableMap, MapData, MapError},
sys::{bpf_map_lookup_elem, bpf_map_update_elem, SyscallError},
};

/// An array of network devices.
Expand All @@ -19,99 +14,92 @@ use crate::{
///
/// # Minimum kernel version
///
/// The minimum kernel version required to use this feature is 4.2.
/// The minimum kernel version required to use this feature is 4.14.
///
/// # Examples
/// ```no_run
/// # let bpf = aya::Bpf::load(&[])?;
/// # let mut bpf = aya::Bpf::load(&[])?;
/// use aya::maps::xdp::DevMap;
/// use std::convert::{TryFrom, TryInto};
///
/// let mut devmap = DevMap::try_from(bpf.map_mut("IFACES")?)?;
/// let ifindex = 32u32;
/// devmap.set(ifindex, ifindex, 0);
/// let mut devmap = DevMap::try_from(bpf.map_mut("IFACES").unwrap())?;
/// let source = 32u32;
/// let dest = 42u32;
/// devmap.set(source, dest, 0);
///
/// # Ok::<(), aya::BpfError>(())
/// ```
#[doc(alias = "BPF_MAP_TYPE_DEVMAP")]
pub struct DevMap<T: Deref<Target = Map>> {
pub struct DevMap<T> {
inner: T,
}

impl<T: Deref<Target = Map>> DevMap<T> {
fn new(map: T) -> Result<DevMap<T>, MapError> {
let map_type = map.obj.def.map_type;
if map_type != BPF_MAP_TYPE_DEVMAP as u32 {
return Err(MapError::InvalidMapType {
map_type: map_type as u32,
});
}
let expected = mem::size_of::<u32>();
let size = map.obj.def.key_size as usize;
if size != expected {
return Err(MapError::InvalidKeySize { size, expected });
}

let expected = mem::size_of::<u32>();
let size = map.obj.def.value_size as usize;
if size != expected {
return Err(MapError::InvalidValueSize { size, expected });
}
let _fd = map.fd_or_err()?;
impl<T: Borrow<MapData>> DevMap<T> {
pub(crate) fn new(map: T) -> Result<Self, MapError> {
let data = map.borrow();
check_kv_size::<u32, u32>(data)?;

Ok(DevMap { inner: map })
Ok(Self { inner: map })
}

/// Returns the number of elements in the array.
///
/// This corresponds to the value of `bpf_map_def::max_entries` on the eBPF side.
pub fn len(&self) -> u32 {
self.inner.obj.def.max_entries
self.inner.borrow().obj.max_entries()
}

fn check_bounds(&self, index: u32) -> Result<(), MapError> {
let max_entries = self.inner.obj.def.max_entries;
if index >= self.inner.obj.def.max_entries {
Err(MapError::OutOfBounds { index, max_entries })
} else {
Ok(())
}
/// Returns the value stored at the given index.
///
/// # Errors
///
/// 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<u32, MapError> {
let data = self.inner.borrow();
check_bounds(data, index)?;
let fd = data.fd().as_fd();

let value =
bpf_map_lookup_elem(fd, &index, flags).map_err(|(_, io_error)| SyscallError {
call: "bpf_map_lookup_elem",
io_error,
})?;
value.ok_or(MapError::KeyNotFound)
}

/// An iterator over the elements of the array.
pub fn iter(&self) -> impl Iterator<Item = Result<u32, MapError>> + '_ {
(0..self.len()).map(move |i| self.get(i, 0))
}
}

impl<T: Deref<Target = Map> + DerefMut<Target = Map>> DevMap<T> {
impl<T: BorrowMut<MapData>> DevMap<T> {
/// Sets the value of the element at the given index.
///
/// # Errors
///
/// 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: u32, flags: u64) -> Result<(), MapError> {
let fd = self.inner.fd_or_err()?;
self.check_bounds(index)?;
bpf_map_update_elem(fd, &index, &value, flags).map_err(|(code, io_error)| {
MapError::SyscallError {
call: "bpf_map_update_elem".to_owned(),
code,
let data = self.inner.borrow_mut();
check_bounds(data, index)?;
let fd = data.fd().as_fd();
bpf_map_update_elem(fd, Some(&index), &value, flags).map_err(|(_, io_error)| {
SyscallError {
call: "bpf_map_update_elem",
io_error,
}
})?;
Ok(())
}
}

impl TryFrom<MapRef> for DevMap<MapRef> {
type Error = MapError;

fn try_from(a: MapRef) -> Result<DevMap<MapRef>, MapError> {
DevMap::new(a)
impl<T: Borrow<MapData>> IterableMap<u32, u32> for DevMap<T> {
fn map(&self) -> &MapData {
self.inner.borrow()
}
}

impl TryFrom<MapRefMut> for DevMap<MapRefMut> {
type Error = MapError;

fn try_from(a: MapRefMut) -> Result<DevMap<MapRefMut>, MapError> {
DevMap::new(a)
fn get(&self, key: &u32) -> Result<u32, MapError> {
self.get(*key, 0)
}
}
Loading

0 comments on commit ede3e91

Please sign in to comment.