bpf: add documentation for XDP maps

reviewable/pr527/r4
Tuetuopay 2 years ago
parent fdc592e8c5
commit c716c0160a

@ -8,6 +8,28 @@ use crate::{
maps::PinningType, maps::PinningType,
}; };
/// An array of available CPUs.
///
/// XDP programs can use this map to redirect packets to a target CPU for processing.
///
/// # Minimum kernel version
///
/// The minimum kernel version required to use this feature is 4.15.
///
/// # Examples
///
/// ```rust,no_run
/// use aya_bpf::{bindings::xdp_action, macros::{map, xdp}, maps::CpuMap, programs::XdpContext};
///
/// #[map]
/// static MAP: CpuMap = CpuMap::with_max_entries(8, 0);
///
/// #[xdp]
/// fn xdp(_ctx: XdpContext) -> i32 {
/// // Redirect to CPU 7 or drop packet if no entry found.
/// MAP.redirect(7, xdp_action::XDP_DROP as u64)
/// }
/// ```
#[repr(transparent)] #[repr(transparent)]
pub struct CpuMap { pub struct CpuMap {
def: UnsafeCell<bpf_map_def>, def: UnsafeCell<bpf_map_def>,
@ -16,6 +38,20 @@ pub struct CpuMap {
unsafe impl Sync for CpuMap {} unsafe impl Sync for CpuMap {}
impl 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. To dynamically set the entry count at runtime, refer to the
/// userspace documentation.
///
/// # Examples
///
/// ```rust,no_run
/// use aya_bpf::{macros::map, maps::CpuMap};
///
/// #[map]
/// static MAP: CpuMap = CpuMap::with_max_entries(8, 0);
/// ```
pub const fn with_max_entries(max_entries: u32, flags: u32) -> CpuMap { pub const fn with_max_entries(max_entries: u32, flags: u32) -> CpuMap {
CpuMap { CpuMap {
def: UnsafeCell::new(bpf_map_def { def: UnsafeCell::new(bpf_map_def {
@ -30,6 +66,19 @@ impl CpuMap {
} }
} }
/// Creates a [`CpuMap`] with a set maximum number of elements that can be pinned to the BPF
/// File System (bpffs).
///
/// See [`CpuMap::with_max_entries`] for more information.
///
/// # Examples
///
/// ```rust,no_run
/// use aya_bpf::{macros::map, maps::CpuMap};
///
/// #[map]
/// static MAP: CpuMap = CpuMap::pinned(8, 0);
/// ```
pub const fn pinned(max_entries: u32, flags: u32) -> CpuMap { pub const fn pinned(max_entries: u32, flags: u32) -> CpuMap {
CpuMap { CpuMap {
def: UnsafeCell::new(bpf_map_def { def: UnsafeCell::new(bpf_map_def {
@ -44,6 +93,25 @@ impl CpuMap {
} }
} }
/// Redirects the current packet on the CPU at `index`.
///
/// The lower two bits of `flags` are used for the return code if the map lookup fails, which
/// can be used as the XDP program's return code if a CPU cannot be found.
///
/// # Examples
///
/// ```rust,no_run
/// use aya_bpf::{bindings::xdp_action, macros::{map, xdp}, maps::CpuMap, programs::XdpContext};
///
/// #[map]
/// static MAP: CpuMap = CpuMap::with_max_entries(8, 0);
///
/// #[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)
/// }
/// ```
#[inline(always)] #[inline(always)]
pub fn redirect(&self, index: u32, flags: u64) -> u32 { pub fn redirect(&self, index: u32, flags: u64) -> u32 {
unsafe { unsafe {

@ -9,6 +9,27 @@ use crate::{
maps::PinningType, maps::PinningType,
}; };
/// An array of network devices.
///
/// XDP programs can use this map to redirect packets to other network deviecs.
///
/// # Minimum kernel version
///
/// The minimum kernel version required to use this feature is 4.14.
///
/// # Examples
///
/// ```rust,no_run
/// use aya_bpf::{bindings::xdp_action, macros::{map, xdp}, maps::DevMap, programs::XdpContext};
///
/// #[map]
/// static MAP: DevMap = DevMap::with_max_entries(1, 0);
///
/// #[xdp]
/// fn xdp(_ctx: XdpContext) -> i32 {
/// MAP.redirect(0, xdp_action::XDP_PASS as u64)
/// }
/// ```
#[repr(transparent)] #[repr(transparent)]
pub struct DevMap { pub struct DevMap {
def: UnsafeCell<bpf_map_def>, def: UnsafeCell<bpf_map_def>,
@ -17,6 +38,16 @@ pub struct DevMap {
unsafe impl Sync for DevMap {} unsafe impl Sync for DevMap {}
impl DevMap { impl DevMap {
/// Creates a [`DevMap`] with a set maximum number of elements.
///
/// # Examples
///
/// ```rust,no_run
/// use aya_bpf::{macros::map, maps::DevMap};
///
/// #[map]
/// static MAP: DevMap = DevMap::with_max_entries(8, 0);
/// ```
pub const fn with_max_entries(max_entries: u32, flags: u32) -> DevMap { pub const fn with_max_entries(max_entries: u32, flags: u32) -> DevMap {
DevMap { DevMap {
def: UnsafeCell::new(bpf_map_def { def: UnsafeCell::new(bpf_map_def {
@ -31,6 +62,17 @@ impl DevMap {
} }
} }
/// Creates a [`DevMap`] with a set maximum number of elements that can be pinned to the BPF
/// File System (bpffs).
///
/// # Examples
///
/// ```rust,no_run
/// use aya_bpf::{macros::map, maps::DevMap};
///
/// #[map]
/// static MAP: DevMap = DevMap::pinned(8, 0);
/// ```
pub const fn pinned(max_entries: u32, flags: u32) -> DevMap { pub const fn pinned(max_entries: u32, flags: u32) -> DevMap {
DevMap { DevMap {
def: UnsafeCell::new(bpf_map_def { def: UnsafeCell::new(bpf_map_def {
@ -45,6 +87,22 @@ impl DevMap {
} }
} }
/// Retrieves the interface index at `index` in the array.
///
/// To actually redirect a packet, see [`DevMap::redirect`].
///
/// # Examples
///
/// ```rust,no_run
/// use aya_bpf::{macros::map, maps::DevMap};
///
/// #[map]
/// static MAP: DevMap = DevMap::with_max_entries(1, 0);
///
/// let ifindex = MAP.get(0);
///
/// // redirect to ifindex
/// ```
#[inline(always)] #[inline(always)]
pub fn get(&self, index: u32) -> Option<bpf_devmap_val> { pub fn get(&self, index: u32) -> Option<bpf_devmap_val> {
unsafe { unsafe {
@ -56,6 +114,24 @@ impl DevMap {
} }
} }
/// Redirects the current packet on the interface at `index`.
///
/// The lower two bits of `flags` are used for the return code if the map lookup fails, which
/// can be used as the XDP program's return code if a CPU cannot be found.
///
/// # Examples
///
/// ```rust,no_run
/// use aya_bpf::{bindings::xdp_action, macros::{map, xdp}, maps::DevMap, programs::XdpContext};
///
/// #[map]
/// static MAP: DevMap = DevMap::with_max_entries(8, 0);
///
/// #[xdp]
/// fn xdp(_ctx: XdpContext) -> i32 {
/// MAP.redirect(7, xdp_action::XDP_PASS as u64)
/// }
/// ```
#[inline(always)] #[inline(always)]
pub fn redirect(&self, index: u32, flags: u64) -> u32 { pub fn redirect(&self, index: u32, flags: u64) -> u32 {
// Return XDP_REDIRECT on success, or the value of the two lower bits of the flags // Return XDP_REDIRECT on success, or the value of the two lower bits of the flags

@ -9,6 +9,29 @@ use crate::{
maps::PinningType, maps::PinningType,
}; };
/// A map of network devices.
///
/// XDP programs can use this map to redirect packets to other network devices. It is similar to
/// [`DevMap`](super::DevMap), but is an hash map rather than an array. Keys do not need to be
/// contiguous nor start at zero, but there is a hashing cost to every lookup.
///
/// # Minimum kernel version
///
/// The minimum kernel version required to use this feature is 5.4.
///
/// # Examples
///
/// ```rust,no_run
/// use aya_bpf::{bindings::xdp_action, macros::{map, xdp}, maps::DevMapHash, programs::XdpContext};
///
/// #[map]
/// static MAP: DevMapHash = DevMapHash::with_max_entries(1, 0);
///
/// #[xdp]
/// fn xdp(_ctx: XdpContext) -> i32 {
/// MAP.redirect(42, xdp_action::XDP_PASS as u64)
/// }
/// ```
#[repr(transparent)] #[repr(transparent)]
pub struct DevMapHash { pub struct DevMapHash {
def: UnsafeCell<bpf_map_def>, def: UnsafeCell<bpf_map_def>,
@ -17,6 +40,16 @@ pub struct DevMapHash {
unsafe impl Sync for DevMapHash {} unsafe impl Sync for DevMapHash {}
impl DevMapHash { impl DevMapHash {
/// Creates a [`DevMapHash`] with a set maximum number of elements.
///
/// # Examples
///
/// ```rust,no_run
/// use aya_bpf::{macros::map, maps::DevMapHash};
///
/// #[map]
/// static MAP: DevMapHash = DevMapHash::with_max_entries(8, 0);
/// ```
pub const fn with_max_entries(max_entries: u32, flags: u32) -> DevMapHash { pub const fn with_max_entries(max_entries: u32, flags: u32) -> DevMapHash {
DevMapHash { DevMapHash {
def: UnsafeCell::new(bpf_map_def { def: UnsafeCell::new(bpf_map_def {
@ -31,6 +64,17 @@ impl DevMapHash {
} }
} }
/// Creates a [`DevMapHash`] with a set maximum number of elements that can be pinned to the BPF
/// File System (bpffs).
///
/// # Examples
///
/// ```rust,no_run
/// use aya_bpf::{macros::map, maps::DevMapHash};
///
/// #[map]
/// static MAP: DevMapHash = DevMapHash::pinned(8, 0);
/// ```
pub const fn pinned(max_entries: u32, flags: u32) -> DevMapHash { pub const fn pinned(max_entries: u32, flags: u32) -> DevMapHash {
DevMapHash { DevMapHash {
def: UnsafeCell::new(bpf_map_def { def: UnsafeCell::new(bpf_map_def {
@ -45,6 +89,22 @@ impl DevMapHash {
} }
} }
/// Retrieves the interface index with `key` in the map.
///
/// To actually redirect a packet, see [`DevMapHash::redirect`].
///
/// # Examples
///
/// ```rust,no_run
/// use aya_bpf::{macros::map, maps::DevMapHash};
///
/// #[map]
/// static MAP: DevMapHash = DevMapHash::with_max_entries(1, 0);
///
/// let ifindex = MAP.get(42);
///
/// // redirect to ifindex
/// ```
#[inline(always)] #[inline(always)]
pub fn get(&self, key: u32) -> Option<bpf_devmap_val> { pub fn get(&self, key: u32) -> Option<bpf_devmap_val> {
unsafe { unsafe {
@ -54,6 +114,24 @@ impl DevMapHash {
} }
} }
/// Redirects the current packet on the interface at `key`.
///
/// The lower two bits of `flags` are used for the return code if the map lookup fails, which
/// can be used as the XDP program's return code if a CPU cannot be found.
///
/// # Examples
///
/// ```rust,no_run
/// use aya_bpf::{bindings::xdp_action, macros::{map, xdp}, maps::DevMapHash, programs::XdpContext};
///
/// #[map]
/// static MAP: DevMapHash = DevMapHash::with_max_entries(8, 0);
///
/// #[xdp]
/// fn xdp(_ctx: XdpContext) -> i32 {
/// MAP.redirect(7, xdp_action::XDP_PASS as u64)
/// }
/// ```
#[inline(always)] #[inline(always)]
pub fn redirect(&self, key: u32, flags: u64) -> u32 { pub fn redirect(&self, key: u32, flags: u64) -> u32 {
unsafe { unsafe {

@ -9,6 +9,48 @@ use crate::{
maps::PinningType, maps::PinningType,
}; };
/// An array of AF_XDP sockets.
///
/// XDP programs can use this map to redirect packets to a target AF_XDP socket using the
/// `XDP_REDIRECT` action.
///
/// # Minimum kernel version
///
/// The minimum kernel version required to use this feature is 4.18.
///
/// # Examples
///
/// ```rust,no_run
/// use aya_bpf::{bindings::xdp_action, macros::{map, xdp}, maps::XskMap, programs::XdpContext};
///
/// #[map]
/// static SOCKS: XskMap = XskMap::with_max_entries(8, 0);
///
/// #[xdp]
/// fn xdp(ctx, XdpContext) -> i32 {
/// let queue_id = unsafe { (*ctx.ctx).rx_queue_index };
/// MAP.redirect(queue_id, xdp_action::XDP_DROP as u64)
/// }
/// ```
///
/// # Queue management
///
/// Packets received on a RX queue can only be redirected to sockets bound on the same queue. Most
/// hardware NICs have multiple RX queue to spread the load across multiple CPU cores using RSS.
///
/// Three strategies are possible:
///
/// - Reduce the RX queue count to a single one. This option is great for development, but is
/// detrimental for performance as the single CPU core recieving packets will get overwhelmed.
/// Setting the queue count for a NIC can be achieved using `ethtool -L <ifname> combined 1`.
/// - Create a socket for every RX queue. Most modern NICs will have an RX queue per CPU thread, so
/// a socket per CPU thread is best for performance. To dynamically size the map depending on the
/// recieve queue count, see the userspace documentation of `CpuMap`.
/// - Create a single socket and use a [`CpuMap`](super::CpuMap) to redirect the packet to the
/// correct CPU core. This way, the packet is sent to another CPU, and a chained XDP program can
/// the redirect to the AF_XDP socket. Using a single socket simplifies the userspace code but
/// will not perform great unless not a lot of traffic is redirected to the socket. Regular
/// traffic however will not be impacted, contrary to reducing the queue count.
#[repr(transparent)] #[repr(transparent)]
pub struct XskMap { pub struct XskMap {
def: UnsafeCell<bpf_map_def>, def: UnsafeCell<bpf_map_def>,
@ -17,6 +59,16 @@ pub struct XskMap {
unsafe impl Sync for XskMap {} unsafe impl Sync for XskMap {}
impl XskMap { impl XskMap {
/// Creates a [`XskMap`] with a set maximum number of elements.
///
/// # Examples
///
/// ```rust,no_run
/// use aya_bpf::{macros::map, maps::XskMap};
///
/// #[map]
/// static SOCKS: XskMap::with_max_entries(8, 0);
/// ```
pub const fn with_max_entries(max_entries: u32, flags: u32) -> XskMap { pub const fn with_max_entries(max_entries: u32, flags: u32) -> XskMap {
XskMap { XskMap {
def: UnsafeCell::new(bpf_map_def { def: UnsafeCell::new(bpf_map_def {
@ -31,6 +83,17 @@ impl XskMap {
} }
} }
/// Creates a [`XskMap`] with a set maximum number of elements that can be pinned to the BPF
/// filesystem (bpffs).
///
/// # Examples
///
/// ```rust,no_run
/// use aya_bpf::{macros::map, maps::XskMap};
///
/// #[map]
/// static SOCKS: XskMap::pinned(8, 0);
/// ```
pub const fn pinned(max_entries: u32, flags: u32) -> XskMap { pub const fn pinned(max_entries: u32, flags: u32) -> XskMap {
XskMap { XskMap {
def: UnsafeCell::new(bpf_map_def { def: UnsafeCell::new(bpf_map_def {
@ -45,6 +108,20 @@ impl XskMap {
} }
} }
/// Retrieves the queue to which the socket is bound at `index` in the array.
///
/// To actually redirect a packet, see [`XskMap::redirect`].
///
/// # Examples
///
/// ```rust,no_run
/// use aya_bpf::{macros::map, maps::XskMap};
///
/// #[map]
/// static SOCKS: XskMap = XskMap::with_max_entries(8, 0);
///
/// let queue_id = SOCKS.get(0);
/// ```
#[inline(always)] #[inline(always)]
pub fn get(&self, index: u32) -> Option<u32> { pub fn get(&self, index: u32) -> Option<u32> {
unsafe { unsafe {
@ -56,6 +133,28 @@ impl XskMap {
} }
} }
/// Redirects the current packet to the AF_XDP socket at `index`.
///
/// The lower two bits of `flags` are used for the return code if the map lookup fails, which
/// can be used as the XDP program's return code if a matching socket cannot be found.
///
/// However, if the socket at `index` is bound to a RX queue which is not the current RX queue,
/// the packet will be dropped.
///
/// # Examples
///
/// ```rust,no_run
/// use aya_bpf::{bindings::xdp_action, macros::{map, xdp}, maps::XskMap, programs::XdpContext};
///
/// #[map]
/// static SOCKS: XskMap = XskMap::with_max_entries(8, 0);
///
/// #[xdp]
/// fn xdp(ctx, XdpContext) -> i32 {
/// let queue_id = unsafe { (*ctx.ctx).rx_queue_index };
/// MAP.redirect(queue_id, xdp_action::XDP_DROP as u64)
/// }
/// ```
#[inline(always)] #[inline(always)]
pub fn redirect(&self, index: u32, flags: u64) -> u32 { pub fn redirect(&self, index: u32, flags: u64) -> u32 {
unsafe { unsafe {

Loading…
Cancel
Save