aya, bpf: misc fixes following review comments

pull/527/head
Tuetuopay 1 year ago
parent 46551de3e7
commit 579e3cee22

@ -147,14 +147,7 @@ pub fn sk_msg(attrs: TokenStream, item: TokenStream) -> TokenStream {
///
/// #[xdp(frags)]
/// pub fn xdp(ctx: XdpContext) -> u32 {
/// match unsafe { try_xdp(ctx) } {
/// Ok(ret) => ret,
/// Err(ret) => ret,
/// }
/// }
///
/// unsafe fn try_xdp(_ctx: XdpContext) -> Result<u32, u32> {
/// Ok(XDP_PASS)
/// XDP_PASS
/// }
/// ```
#[proc_macro_error]

@ -28,7 +28,7 @@ impl Xdp {
Some(name) => {
return Err(Error::new_spanned(
"map",
format!("invalid value. expected 'cpumap' or 'devmap', found '{name}'"),
format!("Invalid value. Expected 'cpumap' or 'devmap', found '{name}'"),
))
}
None => None,

@ -50,7 +50,6 @@ pub struct Features {
bpf_cookie: bool,
cpumap_prog_id: bool,
devmap_prog_id: bool,
devmap_hash_prog_id: bool,
btf: Option<BtfFeatures>,
}
@ -65,7 +64,6 @@ impl Features {
bpf_cookie: bool,
cpumap_prog_id: bool,
devmap_prog_id: bool,
devmap_hash_prog_id: bool,
btf: Option<BtfFeatures>,
) -> Self {
Self {
@ -76,7 +74,6 @@ impl Features {
bpf_cookie,
cpumap_prog_id,
devmap_prog_id,
devmap_hash_prog_id,
btf,
}
}
@ -116,11 +113,6 @@ impl Features {
self.devmap_prog_id
}
/// Returns whether XDP Hash Device Maps support chained program IDs.
pub fn devmap_hash_prog_id(&self) -> bool {
self.devmap_hash_prog_id
}
/// If BTF is supported, returns which BTF features are supported.
pub fn btf(&self) -> Option<&BtfFeatures> {
self.btf.as_ref()

@ -96,7 +96,6 @@ fn detect_features() -> Features {
is_bpf_cookie_supported(),
is_prog_id_supported(BPF_MAP_TYPE_CPUMAP),
is_prog_id_supported(BPF_MAP_TYPE_DEVMAP),
is_prog_id_supported(BPF_MAP_TYPE_DEVMAP_HASH),
btf,
);
debug!("BPF Feature Detection: {:#?}", f);
@ -484,12 +483,9 @@ impl<'a> BpfLoader<'a> {
Ok(BPF_MAP_TYPE_CPUMAP) => {
obj.set_value_size(if FEATURES.cpumap_prog_id() { 8 } else { 4 })
}
Ok(BPF_MAP_TYPE_DEVMAP) => {
Ok(BPF_MAP_TYPE_DEVMAP | BPF_MAP_TYPE_DEVMAP_HASH) => {
obj.set_value_size(if FEATURES.devmap_prog_id() { 8 } else { 4 })
}
Ok(BPF_MAP_TYPE_DEVMAP_HASH) => {
obj.set_value_size(if FEATURES.devmap_hash_prog_id() { 8 } else { 4 })
}
_ => (),
}
let btf_fd = btf_fd.as_deref().map(|fd| fd.as_fd());

@ -279,7 +279,7 @@ pub enum Map {
DevMapHash(MapData),
/// A [`XskMap`] map.
XskMap(MapData),
/// An unsupported map type
/// An unsupported map type.
Unsupported(MapData),
}

@ -6,7 +6,7 @@ use std::{
os::fd::{AsFd, AsRawFd},
};
use aya_obj::generated::{bpf_cpumap_val, bpf_cpumap_val__bindgen_ty_1};
use aya_obj::generated::bpf_cpumap_val;
use crate::{
maps::{check_bounds, check_kv_size, IterableMap, MapData, MapError},
@ -15,6 +15,8 @@ use crate::{
Pod, FEATURES,
};
use super::XdpMapError;
/// An array of available CPUs.
///
/// XDP programs can use this map to redirect packets to a target
@ -29,19 +31,24 @@ use crate::{
/// # let elf_bytes = &[];
/// use aya::maps::xdp::CpuMap;
///
/// let ncpus = aya::util::nr_cpus().unwrap() as u32;
/// let mut bpf = aya::BpfLoader::new()
/// .set_max_entries("CPUS", aya::util::nr_cpus().unwrap() as u32)
/// .set_max_entries("CPUS", ncpus)
/// .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 {
/// for i in 0..ncpus {
/// cpumap.set(i, queue_size, None, flags);
/// }
///
/// # Ok::<(), aya::BpfError>(())
/// ```
///
/// # See also
///
/// Kernel documentation: <https://docs.kernel.org/next/bpf/map_cpumap.html>
#[doc(alias = "BPF_MAP_TYPE_CPUMAP")]
pub struct CpuMap<T> {
inner: T,
@ -67,7 +74,7 @@ impl<T: Borrow<MapData>> CpuMap<T> {
self.inner.borrow().obj.max_entries()
}
/// Returns the queue size and possible program for a given CPU index.
/// Returns the queue size and optional program for a given CPU index.
///
/// # Errors
///
@ -81,7 +88,7 @@ impl<T: Borrow<MapData>> CpuMap<T> {
let value = if FEATURES.cpumap_prog_id() {
bpf_map_lookup_elem::<_, bpf_cpumap_val>(fd, &cpu_index, flags).map(|value| {
value.map(|value| CpuMapValue {
qsize: value.qsize,
queue_size: value.qsize,
// SAFETY: map writes use fd, map reads use id.
// https://github.com/torvalds/linux/blob/2dde18cd1d8fac735875f2e4987f11817cc0bc2c/include/uapi/linux/bpf.h#L6241
prog_id: NonZeroU32::new(unsafe { value.bpf_prog.id }),
@ -90,7 +97,7 @@ impl<T: Borrow<MapData>> CpuMap<T> {
} else {
bpf_map_lookup_elem::<_, u32>(fd, &cpu_index, flags).map(|value| {
value.map(|qsize| CpuMapValue {
qsize,
queue_size: qsize,
prog_id: None,
})
})
@ -115,52 +122,52 @@ impl<T: BorrowMut<MapData>> CpuMap<T> {
/// When sending the packet to the CPU at the given index, the kernel will queue up to
/// `queue_size` packets before dropping them.
///
/// Another XDP program can be passed in that will be run on the target CPU, instead of the CPU
/// that receives the packets. This allows to perform minimal computations on CPUs that
/// directly handle packets from a NIC's RX queues, and perform possibly heavier ones in other,
/// less busy CPUs.
/// Starting from Linux kernel 5.9, another XDP program can be passed in that will be run on the
/// target CPU, instead of the CPU that receives the packets. This allows to perform minimal
/// computations on CPUs that directly handle packets from a NIC's RX queues, and perform
/// possibly heavier ones in other, less busy CPUs.
///
/// Note that only XDP programs with the `map = "cpumap"` argument can be passed. See the
/// kernel-space `aya_bpf::xdp` for more information.
/// The chained program must be loaded with the `BPF_XDP_CPUMAP` attach type. When using
/// `aya-ebpf`, that means XDP programs that specify the `map = "cpumap"` argument. See the
/// kernel-space `aya_ebpf::xdp` for more information.
///
/// # Errors
///
/// Returns [`MapError::OutOfBounds`] if `index` is out of bounds, [`MapError::SyscallError`]
/// if `bpf_map_update_elem` fails, [`MapError::ProgIdNotSupported`] if the kernel does not
/// support program ids and one is provided.
/// if `bpf_map_update_elem` fails, [`XdpMapError::ChainedProgramNotSupported`] if the kernel
/// does not support chained programs and one is provided.
pub fn set(
&mut self,
cpu_index: u32,
queue_size: u32,
program: Option<&ProgramFd>,
flags: u64,
) -> Result<(), MapError> {
) -> Result<(), XdpMapError> {
let data = self.inner.borrow_mut();
check_bounds(data, cpu_index)?;
let fd = data.fd().as_fd();
let res = if FEATURES.cpumap_prog_id() {
let value = bpf_cpumap_val {
qsize: queue_size,
bpf_prog: bpf_cpumap_val__bindgen_ty_1 {
let mut value = unsafe { std::mem::zeroed::<bpf_cpumap_val>() };
value.qsize = queue_size;
// Default is valid as the kernel will only consider fd > 0:
// https://github.com/torvalds/linux/blob/2dde18cd1d8fac735875f2e4987f11817cc0bc2c/kernel/bpf/cpumap.c#L466
fd: program
value.bpf_prog.fd = program
.map(|prog| prog.as_fd().as_raw_fd())
.unwrap_or_default(),
},
};
.unwrap_or_default();
bpf_map_update_elem(fd, Some(&cpu_index), &value, flags)
} else {
if program.is_some() {
return Err(MapError::ProgIdNotSupported);
return Err(XdpMapError::ChainedProgramNotSupported);
}
bpf_map_update_elem(fd, Some(&cpu_index), &queue_size, flags)
};
res.map_err(|(_, io_error)| SyscallError {
res.map_err(|(_, io_error)| {
MapError::from(SyscallError {
call: "bpf_map_update_elem",
io_error,
})
})?;
Ok(())
}
@ -179,7 +186,10 @@ impl<T: Borrow<MapData>> IterableMap<u32, CpuMapValue> for CpuMap<T> {
unsafe impl Pod for bpf_cpumap_val {}
#[derive(Clone, Copy, Debug)]
/// The value of a CPU map.
pub struct CpuMapValue {
pub qsize: u32,
/// Size of the for the CPU.
pub queue_size: u32,
/// Chained XDP program ID.
pub prog_id: Option<NonZeroU32>,
}

@ -6,7 +6,7 @@ use std::{
os::fd::{AsFd, AsRawFd},
};
use aya_obj::generated::{bpf_devmap_val, bpf_devmap_val__bindgen_ty_1};
use aya_obj::generated::bpf_devmap_val;
use crate::{
maps::{check_bounds, check_kv_size, IterableMap, MapData, MapError},
@ -15,6 +15,8 @@ use crate::{
Pod, FEATURES,
};
use super::XdpMapError;
/// An array of network devices.
///
/// XDP programs can use this map to redirect to other network
@ -30,12 +32,15 @@ use crate::{
/// use aya::maps::xdp::DevMap;
///
/// let mut devmap = DevMap::try_from(bpf.map_mut("IFACES").unwrap())?;
/// let source = 32u32;
/// let dest = 42u32;
/// devmap.set(source, dest, None, 0);
/// // Lookups at index 2 will redirect packets to interface with index 3 (e.g. eth1)
/// devmap.set(2, 3, None, 0);
///
/// # Ok::<(), aya::BpfError>(())
/// ```
///
/// # See also
///
/// Kernel documentation: <https://docs.kernel.org/next/bpf/map_devmap.html>
#[doc(alias = "BPF_MAP_TYPE_DEVMAP")]
pub struct DevMap<T> {
inner: T,
@ -61,7 +66,7 @@ impl<T: Borrow<MapData>> DevMap<T> {
self.inner.borrow().obj.max_entries()
}
/// Returns the target ifindex and possible program at a given index.
/// Returns the target interface index and optional program at a given index.
///
/// # Errors
///
@ -75,7 +80,7 @@ impl<T: Borrow<MapData>> DevMap<T> {
let value = if FEATURES.devmap_prog_id() {
bpf_map_lookup_elem::<_, bpf_devmap_val>(fd, &index, flags).map(|value| {
value.map(|value| DevMapValue {
ifindex: value.ifindex,
if_index: value.ifindex,
// SAFETY: map writes use fd, map reads use id.
// https://github.com/torvalds/linux/blob/2dde18cd1d8fac735875f2e4987f11817cc0bc2c/include/uapi/linux/bpf.h#L6228
prog_id: NonZeroU32::new(unsafe { value.bpf_prog.id }),
@ -84,7 +89,7 @@ impl<T: Borrow<MapData>> DevMap<T> {
} else {
bpf_map_lookup_elem::<_, u32>(fd, &index, flags).map(|value| {
value.map(|ifindex| DevMapValue {
ifindex,
if_index: ifindex,
prog_id: None,
})
})
@ -104,57 +109,57 @@ impl<T: Borrow<MapData>> DevMap<T> {
}
impl<T: BorrowMut<MapData>> DevMap<T> {
/// Sets the target ifindex at index, and optionally a chained program.
/// Sets the target interface index at index, and optionally a chained program.
///
/// When redirecting using `index`, packets will be transmitted by the interface with
/// `ifindex`.
/// `target_if_index`.
///
/// Another XDP program can be passed in that will be run before actual transmission. It can be
/// used to modify the packet before transmission with NIC specific data (MAC address update,
/// checksum computations, etc) or other purposes.
/// Starting from Linux kernel 5.8, another XDP program can be passed in that will be run before
/// actual transmission. It can be used to modify the packet before transmission with NIC
/// specific data (MAC address update, checksum computations, etc) or other purposes.
///
/// Note that only XDP programs with the `map = "devmap"` argument can be passed. See the
/// kernel-space `aya_bpf::xdp` for more information.
/// The chained program must be loaded with the `BPF_XDP_DEVMAP` attach type. When using
/// `aya-ebpf`, that means XDP programs that specify the `map = "devmap"` argument. See the
/// kernel-space `aya_ebpf::xdp` for more information.
///
/// # Errors
///
/// Returns [`MapError::OutOfBounds`] if `index` is out of bounds, [`MapError::SyscallError`]
/// if `bpf_map_update_elem` fails, [`MapError::ProgIdNotSupported`] if the kernel does not
/// support program ids and one is provided.
/// support chained programs and one is provided.
pub fn set(
&mut self,
index: u32,
ifindex: u32,
target_if_index: u32,
program: Option<&ProgramFd>,
flags: u64,
) -> Result<(), MapError> {
) -> Result<(), XdpMapError> {
let data = self.inner.borrow_mut();
check_bounds(data, index)?;
let fd = data.fd().as_fd();
let res = if FEATURES.devmap_prog_id() {
let value = bpf_devmap_val {
ifindex,
bpf_prog: bpf_devmap_val__bindgen_ty_1 {
let mut value = unsafe { std::mem::zeroed::<bpf_devmap_val>() };
value.ifindex = target_if_index;
// Default is valid as the kernel will only consider fd > 0:
// https://github.com/torvalds/linux/blob/2dde18cd1d8fac735875f2e4987f11817cc0bc2c/kernel/bpf/devmap.c#L866
// https://github.com/torvalds/linux/blob/2dde18cd1d8fac735875f2e4987f11817cc0bc2c/kernel/bpf/devmap.c#L918
fd: program
value.bpf_prog.fd = program
.map(|prog| prog.as_fd().as_raw_fd())
.unwrap_or_default(),
},
};
.unwrap_or_default();
bpf_map_update_elem(fd, Some(&index), &value, flags)
} else {
if program.is_some() {
return Err(MapError::ProgIdNotSupported);
return Err(XdpMapError::ChainedProgramNotSupported);
}
bpf_map_update_elem(fd, Some(&index), &ifindex, flags)
bpf_map_update_elem(fd, Some(&index), &target_if_index, flags)
};
res.map_err(|(_, io_error)| SyscallError {
res.map_err(|(_, io_error)| {
MapError::from(SyscallError {
call: "bpf_map_update_elem",
io_error,
})
})?;
Ok(())
}
@ -173,7 +178,10 @@ impl<T: Borrow<MapData>> IterableMap<u32, DevMapValue> for DevMap<T> {
unsafe impl Pod for bpf_devmap_val {}
#[derive(Clone, Copy, Debug)]
/// The value of a device map.
pub struct DevMapValue {
pub ifindex: u32,
/// Target interface index to redirect to.
pub if_index: u32,
/// Chained XDP program ID.
pub prog_id: Option<NonZeroU32>,
}

@ -6,7 +6,7 @@ use std::{
os::fd::{AsFd, AsRawFd},
};
use aya_obj::generated::{bpf_devmap_val, bpf_devmap_val__bindgen_ty_1};
use aya_obj::generated::bpf_devmap_val;
use crate::{
maps::{check_kv_size, hash_map, IterableMap, MapData, MapError, MapIter, MapKeys},
@ -15,7 +15,7 @@ use crate::{
FEATURES,
};
use super::dev_map::DevMapValue;
use super::{dev_map::DevMapValue, XdpMapError};
/// An hashmap of network devices.
///
@ -32,12 +32,15 @@ use super::dev_map::DevMapValue;
/// use aya::maps::xdp::DevMapHash;
///
/// let mut devmap = DevMapHash::try_from(bpf.map_mut("IFACES").unwrap())?;
/// let flags = 0;
/// let ifindex = 32u32;
/// devmap.insert(ifindex, ifindex, None, flags);
/// // Lookups with key 2 will redirect packets to interface with index 3 (e.g. eth1)
/// devmap.insert(2, 3, None, 0);
///
/// # Ok::<(), aya::BpfError>(())
/// ```
///
/// # See also
///
/// Kernel documentation: <https://docs.kernel.org/next/bpf/map_devmap.html>
#[doc(alias = "BPF_MAP_TYPE_DEVMAP_HASH")]
pub struct DevMapHash<T> {
inner: T,
@ -47,7 +50,7 @@ impl<T: Borrow<MapData>> DevMapHash<T> {
pub(crate) fn new(map: T) -> Result<Self, MapError> {
let data = map.borrow();
if FEATURES.devmap_hash_prog_id() {
if FEATURES.devmap_prog_id() {
check_kv_size::<u32, bpf_devmap_val>(data)?;
} else {
check_kv_size::<u32, u32>(data)?;
@ -56,7 +59,7 @@ impl<T: Borrow<MapData>> DevMapHash<T> {
Ok(Self { inner: map })
}
/// Returns the target ifindex and possible program for a given key.
/// Returns the target interface index and optional program for a given key.
///
/// # Errors
///
@ -64,10 +67,10 @@ impl<T: Borrow<MapData>> DevMapHash<T> {
pub fn get(&self, key: u32, flags: u64) -> Result<DevMapValue, MapError> {
let fd = self.inner.borrow().fd().as_fd();
let value = if FEATURES.devmap_hash_prog_id() {
let value = if FEATURES.devmap_prog_id() {
bpf_map_lookup_elem::<_, bpf_devmap_val>(fd, &key, flags).map(|value| {
value.map(|value| DevMapValue {
ifindex: value.ifindex,
if_index: value.ifindex,
// SAFETY: map writes use fd, map reads use id.
// https://github.com/torvalds/linux/blob/2dde18cd1d8fac735875f2e4987f11817cc0bc2c/include/uapi/linux/bpf.h#L6228
prog_id: NonZeroU32::new(unsafe { value.bpf_prog.id }),
@ -76,7 +79,7 @@ impl<T: Borrow<MapData>> DevMapHash<T> {
} else {
bpf_map_lookup_elem::<_, u32>(fd, &key, flags).map(|value| {
value.map(|ifindex| DevMapValue {
ifindex,
if_index: ifindex,
prog_id: None,
})
})
@ -105,44 +108,43 @@ impl<T: BorrowMut<MapData>> DevMapHash<T> {
///
/// When redirecting using `key`, packets will be transmitted by the interface with `ifindex`.
///
/// Another XDP program can be passed in that will be run before actual transmission. It can be
/// used to modify the packet before transmission with NIC specific data (MAC address update,
/// checksum computations, etc) or other purposes.
/// Starting from Linux kernel 5.8, another XDP program can be passed in that will be run before
/// actual transmission. It can be used to modify the packet before transmission with NIC
/// specific data (MAC address update, checksum computations, etc) or other purposes.
///
/// Note that only XDP programs with the `map = "devmap"` argument can be passed. See the
/// kernel-space `aya_bpf::xdp` for more information.
/// The chained program must be loaded with the `BPF_XDP_DEVMAP` attach type. When using
/// `aya-ebpf`, that means XDP programs that specify the `map = "devmap"` argument. See the
/// kernel-space `aya_ebpf::xdp` for more information.
///
/// # Errors
///
/// Returns [`MapError::SyscallError`] if `bpf_map_update_elem` fails,
/// [`MapError::ProgIdNotSupported`] if the kernel does not support program ids and one is
/// [`MapError::ProgIdNotSupported`] if the kernel does not support chained programs and one is
/// provided.
pub fn insert(
&mut self,
key: u32,
ifindex: u32,
target_if_index: u32,
program: Option<&ProgramFd>,
flags: u64,
) -> Result<(), MapError> {
if FEATURES.devmap_hash_prog_id() {
let value = bpf_devmap_val {
ifindex,
bpf_prog: bpf_devmap_val__bindgen_ty_1 {
) -> Result<(), XdpMapError> {
if FEATURES.devmap_prog_id() {
let mut value = unsafe { std::mem::zeroed::<bpf_devmap_val>() };
value.ifindex = target_if_index;
// Default is valid as the kernel will only consider fd > 0:
// https://github.com/torvalds/linux/blob/2dde18cd1d8fac735875f2e4987f11817cc0bc2c/kernel/bpf/devmap.c#L866
// https://github.com/torvalds/linux/blob/2dde18cd1d8fac735875f2e4987f11817cc0bc2c/kernel/bpf/devmap.c#L918
fd: program
value.bpf_prog.fd = program
.map(|prog| prog.as_fd().as_raw_fd())
.unwrap_or_default(),
},
};
hash_map::insert(self.inner.borrow_mut(), &key, &value, flags)
.unwrap_or_default();
hash_map::insert(self.inner.borrow_mut(), &key, &value, flags)?;
} else {
if program.is_some() {
return Err(MapError::ProgIdNotSupported);
return Err(XdpMapError::ChainedProgramNotSupported);
}
hash_map::insert(self.inner.borrow_mut(), &key, &ifindex, flags)
hash_map::insert(self.inner.borrow_mut(), &key, &target_if_index, flags)?;
}
Ok(())
}
/// Removes a value from the map.

@ -8,3 +8,18 @@ pub use cpu_map::CpuMap;
pub use dev_map::DevMap;
pub use dev_map_hash::DevMapHash;
pub use xsk_map::XskMap;
use super::MapError;
use thiserror::Error;
#[derive(Error, Debug)]
/// Errors occuring from working with XDP maps.
pub enum XdpMapError {
/// Chained programs are not supported.
#[error("chained programs are not supported by the current kernel")]
ChainedProgramNotSupported,
/// Map operation failed.
#[error(transparent)]
MapError(#[from] MapError),
}

@ -30,6 +30,10 @@ use crate::{
/// xskmap.set(0, socket_fd, 0);
/// # Ok::<(), aya::BpfError>(())
/// ```
///
/// # See also
///
/// Kernel documentation: <https://docs.kernel.org/next/bpf/map_xskmap.html>
#[doc(alias = "BPF_MAP_TYPE_XSKMAP")]
pub struct XskMap<T> {
inner: T,

@ -1,6 +1,6 @@
use core::{cell::UnsafeCell, mem};
use aya_bpf_bindings::bindings::bpf_cpumap_val;
use aya_bpf_bindings::bindings::{bpf_cpumap_val, xdp_action::XDP_REDIRECT};
use crate::{
bindings::{bpf_map_def, bpf_map_type::BPF_MAP_TYPE_CPUMAP},
@ -40,9 +40,9 @@ unsafe impl Sync for CpuMap {}
impl CpuMap {
/// Creates a [`CpuMap`] with a set maximum number of elements.
///
/// In a CPU Map, an entry represents a CPU core. Thus there should be as many entries as there
/// are CPU cores on the system. It can be set to zero here, and updated by userspace at
/// runtime. Refer to the userspace documentation for more information.
/// In a CPU map, an entry represents a CPU core. Thus there should be as many entries as there
/// are CPU cores on the system. `max_entries` can be set to zero here, and updated by userspace
/// at runtime. Refer to the userspace documentation for more information.
///
/// # Examples
///
@ -109,16 +109,18 @@ impl CpuMap {
/// #[xdp]
/// fn xdp(_ctx: XdpContext) -> u32 {
/// // Redirect to CPU 7 or drop packet if no entry found.
/// MAP.redirect(7, xdp_action::XDP_DROP as u64)
/// MAP.redirect(7, 0).unwrap_or(xdp_action::XDP_DROP)
/// }
/// ```
#[inline(always)]
pub fn redirect(&self, index: u32, flags: u64) -> u32 {
unsafe {
pub fn redirect(&self, index: u32, flags: u64) -> Result<u32, u32> {
let ret = unsafe { bpf_redirect_map(self.def.get() as *mut _, index.into(), flags) };
match ret.unsigned_abs() as u32 {
XDP_REDIRECT => Ok(XDP_REDIRECT),
// Return XDP_REDIRECT on success, or the value of the two lower bits of the flags
// argument on error. Thus I have no idea why it returns a long (i64) instead of
// something saner, hence the unsigned_abs.
bpf_redirect_map(self.def.get() as *mut _, index.into(), flags).unsigned_abs() as u32
ret => Err(ret),
}
}
}

@ -1,6 +1,6 @@
use core::{cell::UnsafeCell, mem, ptr::NonNull};
use core::{cell::UnsafeCell, mem, num::NonZeroU32, ptr::NonNull};
use aya_bpf_bindings::bindings::bpf_devmap_val;
use aya_bpf_bindings::bindings::{bpf_devmap_val, xdp_action::XDP_REDIRECT};
use aya_bpf_cty::c_void;
use crate::{
@ -99,9 +99,9 @@ impl DevMap {
/// #[map]
/// static MAP: DevMap = DevMap::with_max_entries(1, 0);
///
/// let ifindex = MAP.get(0);
/// let target_if_index = MAP.get(0).target_if_index;
///
/// // redirect to ifindex
/// // redirect to if_index
/// ```
#[inline(always)]
pub fn get(&self, index: u32) -> Option<DevMapValue> {
@ -111,10 +111,10 @@ impl DevMap {
&index as *const _ as *const c_void,
);
NonNull::new(value as *mut bpf_devmap_val).map(|p| DevMapValue {
ifindex: p.as_ref().ifindex,
if_index: p.as_ref().ifindex,
// SAFETY: map writes use fd, map reads use id.
// https://elixir.bootlin.com/linux/v6.2/source/include/uapi/linux/bpf.h#L6136
prog_id: p.as_ref().bpf_prog.id,
prog_id: NonZeroU32::new(p.as_ref().bpf_prog.id),
})
}
}
@ -133,23 +133,28 @@ impl DevMap {
/// static MAP: DevMap = DevMap::with_max_entries(8, 0);
///
/// #[xdp]
/// fn xdp(_ctx: XdpContext) -> i32 {
/// MAP.redirect(7, xdp_action::XDP_PASS as u64)
/// fn xdp(_ctx: XdpContext) -> u32 {
/// MAP.redirect(7, 0).unwrap_or(xdp_action::XDP_DROP)
/// }
/// ```
#[inline(always)]
pub fn redirect(&self, index: u32, flags: u64) -> u32 {
pub fn redirect(&self, index: u32, flags: u64) -> Result<u32, u32> {
let ret = unsafe { bpf_redirect_map(self.def.get() as *mut _, index.into(), flags) };
match ret.unsigned_abs() as u32 {
XDP_REDIRECT => Ok(XDP_REDIRECT),
// Return XDP_REDIRECT on success, or the value of the two lower bits of the flags
// argument on error. Thus I have no idea why it returns a long (i64) instead of
// something saner, hence the unsigned_abs.
unsafe {
bpf_redirect_map(self.def.get() as *mut _, index.into(), flags).unsigned_abs() as u32
ret => Err(ret),
}
}
}
#[derive(Clone, Copy)]
/// The value of a device map.
pub struct DevMapValue {
pub ifindex: u32,
pub prog_id: u32,
/// Target interface index to redirect to.
pub if_index: u32,
/// Chained XDP program ID.
pub prog_id: Option<NonZeroU32>,
}

@ -1,6 +1,6 @@
use core::{cell::UnsafeCell, mem, ptr::NonNull};
use core::{cell::UnsafeCell, mem, num::NonZeroU32, ptr::NonNull};
use aya_bpf_bindings::bindings::bpf_devmap_val;
use aya_bpf_bindings::bindings::{bpf_devmap_val, xdp_action::XDP_REDIRECT};
use aya_bpf_cty::c_void;
use crate::{
@ -103,7 +103,7 @@ impl DevMapHash {
/// #[map]
/// static MAP: DevMapHash = DevMapHash::with_max_entries(1, 0);
///
/// let ifindex = MAP.get(42);
/// let target_if_index = MAP.get(42).target_if_index;
///
/// // redirect to ifindex
/// ```
@ -113,10 +113,10 @@ impl DevMapHash {
let value =
bpf_map_lookup_elem(self.def.get() as *mut _, &key as *const _ as *const c_void);
NonNull::new(value as *mut bpf_devmap_val).map(|p| DevMapValue {
ifindex: p.as_ref().ifindex,
if_index: p.as_ref().ifindex,
// SAFETY: map writes use fd, map reads use id.
// https://elixir.bootlin.com/linux/v6.2/source/include/uapi/linux/bpf.h#L6136
prog_id: p.as_ref().bpf_prog.id,
prog_id: NonZeroU32::new(p.as_ref().bpf_prog.id),
})
}
}
@ -135,17 +135,19 @@ impl DevMapHash {
/// static MAP: DevMapHash = DevMapHash::with_max_entries(8, 0);
///
/// #[xdp]
/// fn xdp(_ctx: XdpContext) -> i32 {
/// MAP.redirect(7, xdp_action::XDP_PASS as u64)
/// fn xdp(_ctx: XdpContext) -> u32 {
/// MAP.redirect(7, 0).unwrap_or(xdp_action::XDP_DROP)
/// }
/// ```
#[inline(always)]
pub fn redirect(&self, key: u32, flags: u64) -> u32 {
unsafe {
pub fn redirect(&self, index: u32, flags: u64) -> Result<u32, u32> {
let ret = unsafe { bpf_redirect_map(self.def.get() as *mut _, index.into(), flags) };
match ret.unsigned_abs() as u32 {
XDP_REDIRECT => Ok(XDP_REDIRECT),
// Return XDP_REDIRECT on success, or the value of the two lower bits of the flags
// argument on error. Thus I have no idea why it returns a long (i64) instead of
// something saner, hence the unsigned_abs.
bpf_redirect_map(self.def.get() as *mut _, key.into(), flags).unsigned_abs() as u32
ret => Err(ret),
}
}
}

@ -1,6 +1,6 @@
use core::{cell::UnsafeCell, mem, ptr::NonNull};
use aya_bpf_bindings::bindings::bpf_xdp_sock;
use aya_bpf_bindings::bindings::{bpf_xdp_sock, xdp_action::XDP_REDIRECT};
use aya_bpf_cty::c_void;
use crate::{
@ -150,18 +150,20 @@ impl XskMap {
/// static SOCKS: XskMap = XskMap::with_max_entries(8, 0);
///
/// #[xdp]
/// fn xdp(ctx, XdpContext) -> i32 {
/// fn xdp(ctx, XdpContext) -> u32 {
/// let queue_id = unsafe { (*ctx.ctx).rx_queue_index };
/// MAP.redirect(queue_id, xdp_action::XDP_DROP as u64)
/// MAP.redirect(queue_id, 0).unwrap_or(xdp_action::XDP_DROP)
/// }
/// ```
#[inline(always)]
pub fn redirect(&self, index: u32, flags: u64) -> u32 {
unsafe {
pub fn redirect(&self, index: u32, flags: u64) -> Result<u32, u32> {
let ret = unsafe { bpf_redirect_map(self.def.get() as *mut _, index.into(), flags) };
match ret.unsigned_abs() as u32 {
XDP_REDIRECT => Ok(XDP_REDIRECT),
// Return XDP_REDIRECT on success, or the value of the two lower bits of the flags
// argument on error. Thus I have no idea why it returns a long (i64) instead of
// something saner, hence the unsigned_abs.
bpf_redirect_map(self.def.get() as *mut _, index.into(), flags).unsigned_abs() as u32
ret => Err(ret),
}
}
}

@ -26,25 +26,25 @@ static mut HITS: Array<u32> = Array::with_max_entries(2, 0);
#[xdp]
pub fn redirect_sock(_ctx: XdpContext) -> u32 {
SOCKS.redirect(0, xdp_action::XDP_ABORTED as u64)
SOCKS.redirect(0, 0).unwrap_or(xdp_action::XDP_ABORTED)
}
#[xdp]
pub fn redirect_dev(_ctx: XdpContext) -> u32 {
inc_hit(0);
DEVS.redirect(0, xdp_action::XDP_ABORTED as u64)
DEVS.redirect(0, 0).unwrap_or(xdp_action::XDP_ABORTED)
}
#[xdp]
pub fn redirect_dev_hash(_ctx: XdpContext) -> u32 {
inc_hit(0);
DEVS_HASH.redirect(10, xdp_action::XDP_ABORTED as u64)
DEVS_HASH.redirect(10, 0).unwrap_or(xdp_action::XDP_ABORTED)
}
#[xdp]
pub fn redirect_cpu(_ctx: XdpContext) -> u32 {
inc_hit(0);
CPUS.redirect(0, xdp_action::XDP_ABORTED as u64)
CPUS.redirect(0, 0).unwrap_or(xdp_action::XDP_ABORTED)
}
#[xdp(map = "cpumap")]

@ -567,7 +567,7 @@ pub mod aya_bpf::maps::xdp
#[repr(transparent)] pub struct aya_bpf::maps::xdp::CpuMap
impl aya_bpf::maps::CpuMap
pub const fn aya_bpf::maps::CpuMap::pinned(max_entries: u32, flags: u32) -> aya_bpf::maps::CpuMap
pub fn aya_bpf::maps::CpuMap::redirect(&self, index: u32, flags: u64) -> u32
pub fn aya_bpf::maps::CpuMap::redirect(&self, index: u32, flags: u64) -> core::result::Result<u32, u32>
pub const fn aya_bpf::maps::CpuMap::with_max_entries(max_entries: u32, flags: u32) -> aya_bpf::maps::CpuMap
impl core::marker::Sync for aya_bpf::maps::CpuMap
impl core::marker::Send for aya_bpf::maps::CpuMap
@ -594,7 +594,7 @@ pub fn aya_bpf::maps::CpuMap::from(t: T) -> T
impl aya_bpf::maps::DevMap
pub fn aya_bpf::maps::DevMap::get(&self, index: u32) -> core::option::Option<DevMapValue>
pub const fn aya_bpf::maps::DevMap::pinned(max_entries: u32, flags: u32) -> aya_bpf::maps::DevMap
pub fn aya_bpf::maps::DevMap::redirect(&self, index: u32, flags: u64) -> u32
pub fn aya_bpf::maps::DevMap::redirect(&self, index: u32, flags: u64) -> core::result::Result<u32, u32>
pub const fn aya_bpf::maps::DevMap::with_max_entries(max_entries: u32, flags: u32) -> aya_bpf::maps::DevMap
impl core::marker::Sync for aya_bpf::maps::DevMap
impl core::marker::Send for aya_bpf::maps::DevMap
@ -621,7 +621,7 @@ pub fn aya_bpf::maps::DevMap::from(t: T) -> T
impl aya_bpf::maps::DevMapHash
pub fn aya_bpf::maps::DevMapHash::get(&self, key: u32) -> core::option::Option<DevMapValue>
pub const fn aya_bpf::maps::DevMapHash::pinned(max_entries: u32, flags: u32) -> aya_bpf::maps::DevMapHash
pub fn aya_bpf::maps::DevMapHash::redirect(&self, key: u32, flags: u64) -> u32
pub fn aya_bpf::maps::DevMapHash::redirect(&self, index: u32, flags: u64) -> core::result::Result<u32, u32>
pub const fn aya_bpf::maps::DevMapHash::with_max_entries(max_entries: u32, flags: u32) -> aya_bpf::maps::DevMapHash
impl core::marker::Sync for aya_bpf::maps::DevMapHash
impl core::marker::Send for aya_bpf::maps::DevMapHash
@ -648,7 +648,7 @@ pub fn aya_bpf::maps::DevMapHash::from(t: T) -> T
impl aya_bpf::maps::XskMap
pub fn aya_bpf::maps::XskMap::get(&self, index: u32) -> core::option::Option<u32>
pub const fn aya_bpf::maps::XskMap::pinned(max_entries: u32, flags: u32) -> aya_bpf::maps::XskMap
pub fn aya_bpf::maps::XskMap::redirect(&self, index: u32, flags: u64) -> u32
pub fn aya_bpf::maps::XskMap::redirect(&self, index: u32, flags: u64) -> core::result::Result<u32, u32>
pub const fn aya_bpf::maps::XskMap::with_max_entries(max_entries: u32, flags: u32) -> aya_bpf::maps::XskMap
impl core::marker::Sync for aya_bpf::maps::XskMap
impl core::marker::Send for aya_bpf::maps::XskMap
@ -729,7 +729,7 @@ pub fn aya_bpf::maps::bloom_filter::BloomFilter<T>::from(t: T) -> T
#[repr(transparent)] pub struct aya_bpf::maps::CpuMap
impl aya_bpf::maps::CpuMap
pub const fn aya_bpf::maps::CpuMap::pinned(max_entries: u32, flags: u32) -> aya_bpf::maps::CpuMap
pub fn aya_bpf::maps::CpuMap::redirect(&self, index: u32, flags: u64) -> u32
pub fn aya_bpf::maps::CpuMap::redirect(&self, index: u32, flags: u64) -> core::result::Result<u32, u32>
pub const fn aya_bpf::maps::CpuMap::with_max_entries(max_entries: u32, flags: u32) -> aya_bpf::maps::CpuMap
impl core::marker::Sync for aya_bpf::maps::CpuMap
impl core::marker::Send for aya_bpf::maps::CpuMap
@ -756,7 +756,7 @@ pub fn aya_bpf::maps::CpuMap::from(t: T) -> T
impl aya_bpf::maps::DevMap
pub fn aya_bpf::maps::DevMap::get(&self, index: u32) -> core::option::Option<DevMapValue>
pub const fn aya_bpf::maps::DevMap::pinned(max_entries: u32, flags: u32) -> aya_bpf::maps::DevMap
pub fn aya_bpf::maps::DevMap::redirect(&self, index: u32, flags: u64) -> u32
pub fn aya_bpf::maps::DevMap::redirect(&self, index: u32, flags: u64) -> core::result::Result<u32, u32>
pub const fn aya_bpf::maps::DevMap::with_max_entries(max_entries: u32, flags: u32) -> aya_bpf::maps::DevMap
impl core::marker::Sync for aya_bpf::maps::DevMap
impl core::marker::Send for aya_bpf::maps::DevMap
@ -783,7 +783,7 @@ pub fn aya_bpf::maps::DevMap::from(t: T) -> T
impl aya_bpf::maps::DevMapHash
pub fn aya_bpf::maps::DevMapHash::get(&self, key: u32) -> core::option::Option<DevMapValue>
pub const fn aya_bpf::maps::DevMapHash::pinned(max_entries: u32, flags: u32) -> aya_bpf::maps::DevMapHash
pub fn aya_bpf::maps::DevMapHash::redirect(&self, key: u32, flags: u64) -> u32
pub fn aya_bpf::maps::DevMapHash::redirect(&self, index: u32, flags: u64) -> core::result::Result<u32, u32>
pub const fn aya_bpf::maps::DevMapHash::with_max_entries(max_entries: u32, flags: u32) -> aya_bpf::maps::DevMapHash
impl core::marker::Sync for aya_bpf::maps::DevMapHash
impl core::marker::Send for aya_bpf::maps::DevMapHash
@ -1206,7 +1206,7 @@ pub fn aya_bpf::maps::stack_trace::StackTrace::from(t: T) -> T
impl aya_bpf::maps::XskMap
pub fn aya_bpf::maps::XskMap::get(&self, index: u32) -> core::option::Option<u32>
pub const fn aya_bpf::maps::XskMap::pinned(max_entries: u32, flags: u32) -> aya_bpf::maps::XskMap
pub fn aya_bpf::maps::XskMap::redirect(&self, index: u32, flags: u64) -> u32
pub fn aya_bpf::maps::XskMap::redirect(&self, index: u32, flags: u64) -> core::result::Result<u32, u32>
pub const fn aya_bpf::maps::XskMap::with_max_entries(max_entries: u32, flags: u32) -> aya_bpf::maps::XskMap
impl core::marker::Sync for aya_bpf::maps::XskMap
impl core::marker::Send for aya_bpf::maps::XskMap

Loading…
Cancel
Save