diff --git a/aya-bpf-macros/src/lib.rs b/aya-bpf-macros/src/lib.rs index 5696b82d..f29b725f 100644 --- a/aya-bpf-macros/src/lib.rs +++ b/aya-bpf-macros/src/lib.rs @@ -128,6 +128,28 @@ pub fn sk_msg(attrs: TokenStream, item: TokenStream) -> TokenStream { } } +/// Marks a function as an eBPF XDP program that can be attached to a network interface. +/// +/// On some NIC drivers, XDP probes are compatible with jumbo frames through the use of +/// multi-buffer packets. Programs can opt-in this support by passing the `frags` argument. +/// +/// XDP programs can also be chained through the use of CPU maps and dev maps, but must opt-in +/// with the `map = "cpumap"` or `map = "devmap"` arguments. +/// +/// # Minimum kernel version +/// +/// The minimum kernel version required to use this feature is 4.8. +/// +/// # Examples +/// +/// ```no_run +/// use aya_bpf::{bindings::xdp_action::XDP_PASS, macros::xdp, programs::XdpContext}; +/// +/// #[xdp(frags)] +/// pub fn xdp(ctx: XdpContext) -> u32 { +/// XDP_PASS +/// } +/// ``` #[proc_macro_error] #[proc_macro_attribute] pub fn xdp(attrs: TokenStream, item: TokenStream) -> TokenStream { diff --git a/aya-bpf-macros/src/xdp.rs b/aya-bpf-macros/src/xdp.rs index 9a5ff36a..61f8c014 100644 --- a/aya-bpf-macros/src/xdp.rs +++ b/aya-bpf-macros/src/xdp.rs @@ -1,31 +1,52 @@ -use std::borrow::Cow; - use proc_macro2::TokenStream; use quote::quote; -use syn::{ItemFn, Result}; +use syn::{Error, ItemFn, Result}; -use crate::args::{err_on_unknown_args, pop_bool_arg, Args}; +use crate::args::{err_on_unknown_args, pop_bool_arg, pop_string_arg, Args}; pub(crate) struct Xdp { item: ItemFn, frags: bool, + map: Option, +} + +#[derive(Clone, Copy)] +pub(crate) enum XdpMap { + CpuMap, + DevMap, } impl Xdp { pub(crate) fn parse(attrs: TokenStream, item: TokenStream) -> Result { let item = syn::parse2(item)?; let mut args: Args = syn::parse2(attrs)?; + let frags = pop_bool_arg(&mut args, "frags"); + let map = match pop_string_arg(&mut args, "map").as_deref() { + Some("cpumap") => Some(XdpMap::CpuMap), + Some("devmap") => Some(XdpMap::DevMap), + Some(name) => { + return Err(Error::new_spanned( + "map", + format!("Invalid value. Expected 'cpumap' or 'devmap', found '{name}'"), + )) + } + None => None, + }; + err_on_unknown_args(&args)?; - Ok(Xdp { item, frags }) + Ok(Xdp { item, frags, map }) } pub(crate) fn expand(&self) -> Result { - let section_name: Cow<'_, _> = if self.frags { - "xdp.frags".into() - } else { - "xdp".into() + let mut section_name = vec![if self.frags { "xdp.frags" } else { "xdp" }]; + match self.map { + Some(XdpMap::CpuMap) => section_name.push("cpumap"), + Some(XdpMap::DevMap) => section_name.push("devmap"), + None => (), }; + let section_name = section_name.join("/"); + let fn_vis = &self.item.vis; let fn_name = self.item.sig.ident.clone(); let item = &self.item; @@ -97,4 +118,122 @@ mod tests { }; assert_eq!(expected.to_string(), expanded.to_string()); } + + #[test] + fn test_xdp_cpumap() { + let prog = Xdp::parse( + parse_quote! { map = "cpumap" }, + parse_quote! { + fn prog(ctx: &mut ::aya_bpf::programs::XdpContext) -> i32 { + 0 + } + }, + ) + .unwrap(); + let expanded = prog.expand().unwrap(); + let expected = quote! { + #[no_mangle] + #[link_section = "xdp/cpumap"] + fn prog(ctx: *mut ::aya_bpf::bindings::xdp_md) -> u32 { + return prog(::aya_bpf::programs::XdpContext::new(ctx)); + + fn prog(ctx: &mut ::aya_bpf::programs::XdpContext) -> i32 { + 0 + } + } + }; + assert_eq!(expected.to_string(), expanded.to_string()); + } + + #[test] + fn test_xdp_devmap() { + let prog = Xdp::parse( + parse_quote! { map = "devmap" }, + parse_quote! { + fn prog(ctx: &mut ::aya_bpf::programs::XdpContext) -> i32 { + 0 + } + }, + ) + .unwrap(); + let expanded = prog.expand().unwrap(); + let expected = quote! { + #[no_mangle] + #[link_section = "xdp/devmap"] + fn prog(ctx: *mut ::aya_bpf::bindings::xdp_md) -> u32 { + return prog(::aya_bpf::programs::XdpContext::new(ctx)); + + fn prog(ctx: &mut ::aya_bpf::programs::XdpContext) -> i32 { + 0 + } + } + }; + assert_eq!(expected.to_string(), expanded.to_string()); + } + + #[test] + #[should_panic(expected = "Invalid value. Expected 'cpumap' or 'devmap', found 'badmap'")] + fn test_xdp_bad_map() { + Xdp::parse( + parse_quote! { map = "badmap" }, + parse_quote! { + fn prog(ctx: &mut ::aya_bpf::programs::XdpContext) -> i32 { + 0 + } + }, + ) + .unwrap(); + } + + #[test] + fn test_xdp_frags_cpumap() { + let prog = Xdp::parse( + parse_quote! { frags, map = "cpumap" }, + parse_quote! { + fn prog(ctx: &mut ::aya_bpf::programs::XdpContext) -> i32 { + 0 + } + }, + ) + .unwrap(); + let expanded = prog.expand().unwrap(); + let expected = quote! { + #[no_mangle] + #[link_section = "xdp.frags/cpumap"] + fn prog(ctx: *mut ::aya_bpf::bindings::xdp_md) -> u32 { + return prog(::aya_bpf::programs::XdpContext::new(ctx)); + + fn prog(ctx: &mut ::aya_bpf::programs::XdpContext) -> i32 { + 0 + } + } + }; + assert_eq!(expected.to_string(), expanded.to_string()); + } + + #[test] + fn test_xdp_frags_devmap() { + let prog = Xdp::parse( + parse_quote! { frags, map = "devmap" }, + parse_quote! { + fn prog(ctx: &mut ::aya_bpf::programs::XdpContext) -> i32 { + 0 + } + }, + ) + .unwrap(); + let expanded = prog.expand().unwrap(); + let expected = quote! { + #[no_mangle] + #[link_section = "xdp.frags/devmap"] + fn prog(ctx: *mut ::aya_bpf::bindings::xdp_md) -> u32 { + return prog(::aya_bpf::programs::XdpContext::new(ctx)); + + fn prog(ctx: &mut ::aya_bpf::programs::XdpContext) -> i32 { + 0 + } + } + }; + assert_eq!(expected.to_string(), expanded.to_string()); + } } diff --git a/aya-obj/src/maps.rs b/aya-obj/src/maps.rs index dbffed0c..aede3cfe 100644 --- a/aya-obj/src/maps.rs +++ b/aya-obj/src/maps.rs @@ -176,6 +176,14 @@ impl Map { } } + /// Set the value size in bytes + pub fn set_value_size(&mut self, size: u32) { + match self { + Map::Legacy(m) => m.def.value_size = size, + Map::Btf(m) => m.def.value_size = size, + } + } + /// Returns the max entry number pub fn max_entries(&self) -> u32 { match self { diff --git a/aya-obj/src/obj.rs b/aya-obj/src/obj.rs index deadeeaf..38221f96 100644 --- a/aya-obj/src/obj.rs +++ b/aya-obj/src/obj.rs @@ -19,6 +19,7 @@ use crate::{ btf::BtfFeatures, generated::{BPF_CALL, BPF_JMP, BPF_K}, maps::{BtfMap, LegacyMap, Map, MINIMUM_MAP_SIZE}, + programs::XdpAttachType, relocation::*, util::HashMap, }; @@ -47,17 +48,22 @@ pub struct Features { bpf_perf_link: bool, bpf_global_data: bool, bpf_cookie: bool, + cpumap_prog_id: bool, + devmap_prog_id: bool, btf: Option, } impl Features { #[doc(hidden)] + #[allow(clippy::too_many_arguments)] pub fn new( bpf_name: bool, bpf_probe_read_kernel: bool, bpf_perf_link: bool, bpf_global_data: bool, bpf_cookie: bool, + cpumap_prog_id: bool, + devmap_prog_id: bool, btf: Option, ) -> Self { Self { @@ -66,6 +72,8 @@ impl Features { bpf_perf_link, bpf_global_data, bpf_cookie, + cpumap_prog_id, + devmap_prog_id, btf, } } @@ -95,6 +103,16 @@ impl Features { self.bpf_cookie } + /// Returns whether XDP CPU Maps support chained program IDs. + pub fn cpumap_prog_id(&self) -> bool { + self.cpumap_prog_id + } + + /// Returns whether XDP Device Maps support chained program IDs. + pub fn devmap_prog_id(&self) -> bool { + self.devmap_prog_id + } + /// If BTF is supported, returns which BTF features are supported. pub fn btf(&self) -> Option<&BtfFeatures> { self.btf.as_ref() @@ -204,8 +222,6 @@ pub struct Function { /// - `struct_ops+` /// - `fmod_ret+`, `fmod_ret.s+` /// - `iter+`, `iter.s+` -/// - `xdp.frags/cpumap`, `xdp/cpumap` -/// - `xdp.frags/devmap`, `xdp/devmap` #[derive(Debug, Clone)] #[allow(missing_docs)] pub enum ProgramSection { @@ -221,6 +237,7 @@ pub enum ProgramSection { SocketFilter, Xdp { frags: bool, + attach_type: XdpAttachType, }, SkMsg, SkSkbStreamParser, @@ -283,8 +300,19 @@ impl FromStr for ProgramSection { "uprobe.s" => UProbe { sleepable: true }, "uretprobe" => URetProbe { sleepable: false }, "uretprobe.s" => URetProbe { sleepable: true }, - "xdp" => Xdp { frags: false }, - "xdp.frags" => Xdp { frags: true }, + "xdp" | "xdp.frags" => Xdp { + frags: kind == "xdp.frags", + attach_type: match pieces.next() { + None => XdpAttachType::Interface, + Some("cpumap") => XdpAttachType::CpuMap, + Some("devmap") => XdpAttachType::DevMap, + Some(_) => { + return Err(ParseError::InvalidProgramSection { + section: section.to_owned(), + }) + } + }, + }, "tp_btf" => BtfTracePoint, "tracepoint" | "tp" => TracePoint, "socket" => SocketFilter, @@ -2012,7 +2040,7 @@ mod tests { assert_matches!( obj.parse_section(fake_section( BpfSectionKind::Program, - "xdp/foo", + "xdp", bytes_of(&fake_ins()), None )), @@ -2035,7 +2063,7 @@ mod tests { assert_matches!( obj.parse_section(fake_section( BpfSectionKind::Program, - "xdp.frags/foo", + "xdp.frags", bytes_of(&fake_ins()), None )), diff --git a/aya-obj/src/programs/mod.rs b/aya-obj/src/programs/mod.rs index 4f76211a..6b66b005 100644 --- a/aya-obj/src/programs/mod.rs +++ b/aya-obj/src/programs/mod.rs @@ -3,7 +3,9 @@ pub mod cgroup_sock; pub mod cgroup_sock_addr; pub mod cgroup_sockopt; +pub mod xdp; pub use cgroup_sock::CgroupSockAttachType; pub use cgroup_sock_addr::CgroupSockAddrAttachType; pub use cgroup_sockopt::CgroupSockoptAttachType; +pub use xdp::XdpAttachType; diff --git a/aya-obj/src/programs/xdp.rs b/aya-obj/src/programs/xdp.rs new file mode 100644 index 00000000..17fab6ab --- /dev/null +++ b/aya-obj/src/programs/xdp.rs @@ -0,0 +1,24 @@ +//! XDP programs. + +use crate::generated::bpf_attach_type; + +/// Defines where to attach an `XDP` program. +#[derive(Copy, Clone, Debug)] +pub enum XdpAttachType { + /// Attach to a network interface. + Interface, + /// Attach to a cpumap. Requires kernel 5.9 or later. + CpuMap, + /// Attach to a devmap. Requires kernel 5.8 or later. + DevMap, +} + +impl From for bpf_attach_type { + fn from(value: XdpAttachType) -> Self { + match value { + XdpAttachType::Interface => bpf_attach_type::BPF_XDP, + XdpAttachType::CpuMap => bpf_attach_type::BPF_XDP_CPUMAP, + XdpAttachType::DevMap => bpf_attach_type::BPF_XDP_DEVMAP, + } + } +} diff --git a/aya/Cargo.toml b/aya/Cargo.toml index 59025b2d..9cdae143 100644 --- a/aya/Cargo.toml +++ b/aya/Cargo.toml @@ -12,6 +12,7 @@ edition = "2021" rust-version = "1.66" [dependencies] +assert_matches = { workspace = true } async-io = { workspace = true, optional = true } aya-obj = { workspace = true, features = ["std"] } bitflags = { workspace = true } @@ -28,7 +29,6 @@ thiserror = { workspace = true } tokio = { workspace = true, features = ["rt"], optional = true } [dev-dependencies] -assert_matches = { workspace = true } tempfile = { workspace = true } [features] diff --git a/aya/src/bpf.rs b/aya/src/bpf.rs index a5fb9273..2272bc52 100644 --- a/aya/src/bpf.rs +++ b/aya/src/bpf.rs @@ -40,7 +40,8 @@ use crate::{ is_btf_datasec_supported, is_btf_decl_tag_supported, is_btf_enum64_supported, is_btf_float_supported, is_btf_func_global_supported, is_btf_func_supported, is_btf_supported, is_btf_type_tag_supported, is_perf_link_supported, - is_probe_read_kernel_supported, is_prog_name_supported, retry_with_verifier_logs, + is_probe_read_kernel_supported, is_prog_id_supported, is_prog_name_supported, + retry_with_verifier_logs, }, util::{bytes_of, bytes_of_slice, possible_cpus, POSSIBLE_CPUS}, }; @@ -93,6 +94,8 @@ fn detect_features() -> Features { is_perf_link_supported(), is_bpf_global_data_supported(), is_bpf_cookie_supported(), + is_prog_id_supported(BPF_MAP_TYPE_CPUMAP), + is_prog_id_supported(BPF_MAP_TYPE_DEVMAP), btf, ); debug!("BPF Feature Detection: {:#?}", f); @@ -412,7 +415,10 @@ impl<'a> BpfLoader<'a> { | ProgramSection::URetProbe { sleepable: _ } | ProgramSection::TracePoint | ProgramSection::SocketFilter - | ProgramSection::Xdp { frags: _ } + | ProgramSection::Xdp { + frags: _, + attach_type: _, + } | ProgramSection::SkMsg | ProgramSection::SkSkbStreamParser | ProgramSection::SkSkbStreamVerdict @@ -473,6 +479,15 @@ impl<'a> BpfLoader<'a> { } } } + match obj.map_type().try_into() { + Ok(BPF_MAP_TYPE_CPUMAP) => { + obj.set_value_size(if FEATURES.cpumap_prog_id() { 8 } else { 4 }) + } + Ok(BPF_MAP_TYPE_DEVMAP | BPF_MAP_TYPE_DEVMAP_HASH) => { + obj.set_value_size(if FEATURES.devmap_prog_id() { 8 } else { 4 }) + } + _ => (), + } let btf_fd = btf_fd.as_deref().map(|fd| fd.as_fd()); let mut map = match obj.pinning() { PinningType::None => MapData::create(obj, &name, btf_fd)?, @@ -556,13 +571,18 @@ impl<'a> BpfLoader<'a> { ProgramSection::SocketFilter => Program::SocketFilter(SocketFilter { data: ProgramData::new(prog_name, obj, btf_fd, *verifier_log_level), }), - ProgramSection::Xdp { frags, .. } => { + ProgramSection::Xdp { + frags, attach_type, .. + } => { let mut data = ProgramData::new(prog_name, obj, btf_fd, *verifier_log_level); if *frags { data.flags = BPF_F_XDP_HAS_FRAGS; } - Program::Xdp(Xdp { data }) + Program::Xdp(Xdp { + data, + attach_type: *attach_type, + }) } ProgramSection::SkMsg => Program::SkMsg(SkMsg { data: ProgramData::new(prog_name, obj, btf_fd, *verifier_log_level), @@ -707,6 +727,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) diff --git a/aya/src/maps/mod.rs b/aya/src/maps/mod.rs index 191c5883..1a590791 100644 --- a/aya/src/maps/mod.rs +++ b/aya/src/maps/mod.rs @@ -83,6 +83,7 @@ pub mod queue; pub mod sock; pub mod stack; pub mod stack_trace; +pub mod xdp; pub use array::{Array, PerCpuArray, ProgramArray}; pub use bloom_filter::BloomFilter; @@ -96,6 +97,7 @@ pub use queue::Queue; pub use sock::{SockHash, SockMap}; pub use stack::Stack; pub use stack_trace::StackTraceMap; +pub use xdp::{CpuMap, DevMap, DevMapHash, XskMap}; #[derive(Error, Debug)] /// Errors occuring from working with Maps @@ -179,6 +181,10 @@ pub enum MapError { error: PinError, }, + /// Program IDs are not supported + #[error("program ids are not supported by the current kernel")] + ProgIdNotSupported, + /// Unsupported Map type #[error("Unsupported map type found {map_type}")] Unsupported { @@ -235,37 +241,45 @@ fn maybe_warn_rlimit() { /// eBPF map types. #[derive(Debug)] pub enum Map { - /// A [`Array`] map + /// An [`Array`] map. Array(MapData), - /// A [`PerCpuArray`] map + /// A [`PerCpuArray`] map. PerCpuArray(MapData), - /// A [`ProgramArray`] map + /// A [`ProgramArray`] map. ProgramArray(MapData), - /// A [`HashMap`] map + /// A [`HashMap`] map. HashMap(MapData), - /// A [`PerCpuHashMap`] map + /// A [`PerCpuHashMap`] map. PerCpuHashMap(MapData), /// A [`HashMap`] map that uses a LRU eviction policy. LruHashMap(MapData), /// A [`PerCpuHashMap`] map that uses a LRU eviction policy. PerCpuLruHashMap(MapData), - /// A [`PerfEventArray`] map + /// A [`PerfEventArray`] map. PerfEventArray(MapData), - /// A [`SockMap`] map + /// A [`SockMap`] map. SockMap(MapData), - /// A [`SockHash`] map + /// A [`SockHash`] map. SockHash(MapData), - /// A [`BloomFilter`] map + /// A [`BloomFilter`] map. BloomFilter(MapData), - /// A [`LpmTrie`] map + /// A [`LpmTrie`] map. LpmTrie(MapData), - /// A [`Stack`] map + /// A [`Stack`] map. Stack(MapData), - /// A [`StackTraceMap`] map + /// A [`StackTraceMap`] map. StackTraceMap(MapData), - /// A [`Queue`] map + /// A [`Queue`] map. Queue(MapData), - /// An unsupported map type + /// 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), } @@ -288,6 +302,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(), } } @@ -347,6 +365,10 @@ impl_try_from_map!(() { SockMap, PerfEventArray, StackTraceMap, + CpuMap, + DevMap, + DevMapHash, + XskMap, }); #[cfg(any(feature = "async_tokio", feature = "async_std"))] diff --git a/aya/src/maps/xdp/cpu_map.rs b/aya/src/maps/xdp/cpu_map.rs new file mode 100644 index 00000000..d9cc7d19 --- /dev/null +++ b/aya/src/maps/xdp/cpu_map.rs @@ -0,0 +1,195 @@ +//! An array of available CPUs. + +use std::{ + borrow::{Borrow, BorrowMut}, + num::NonZeroU32, + os::fd::{AsFd, AsRawFd}, +}; + +use aya_obj::generated::bpf_cpumap_val; + +use crate::{ + maps::{check_bounds, check_kv_size, IterableMap, MapData, MapError}, + programs::ProgramFd, + sys::{bpf_map_lookup_elem, bpf_map_update_elem, SyscallError}, + Pod, FEATURES, +}; + +use super::XdpMapError; + +/// 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 +/// ```no_run +/// # 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", 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 0..ncpus { +/// cpumap.set(i, queue_size, None, flags); +/// } +/// +/// # Ok::<(), aya::BpfError>(()) +/// ``` +/// +/// # See also +/// +/// Kernel documentation: +#[doc(alias = "BPF_MAP_TYPE_CPUMAP")] +pub struct CpuMap { + inner: T, +} + +impl> CpuMap { + pub(crate) fn new(map: T) -> Result { + let data = map.borrow(); + + if FEATURES.cpumap_prog_id() { + check_kv_size::(data)?; + } else { + check_kv_size::(data)?; + } + + 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.borrow().obj.max_entries() + } + + /// Returns the queue size and optional program for a given CPU index. + /// + /// # Errors + /// + /// Returns [`MapError::OutOfBounds`] if `cpu_index` is out of bounds, + /// [`MapError::SyscallError`] if `bpf_map_lookup_elem` fails. + pub fn get(&self, cpu_index: u32, flags: u64) -> Result { + let data = self.inner.borrow(); + check_bounds(data, cpu_index)?; + let fd = data.fd().as_fd(); + + let value = if FEATURES.cpumap_prog_id() { + bpf_map_lookup_elem::<_, bpf_cpumap_val>(fd, &cpu_index, flags).map(|value| { + value.map(|value| CpuMapValue { + 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 }), + }) + }) + } else { + bpf_map_lookup_elem::<_, u32>(fd, &cpu_index, flags).map(|value| { + value.map(|qsize| CpuMapValue { + queue_size: qsize, + prog_id: None, + }) + }) + }; + value + .map_err(|(_, io_error)| SyscallError { + call: "bpf_map_lookup_elem", + io_error, + })? + .ok_or(MapError::KeyNotFound) + } + + /// An iterator over the elements of the map. + pub fn iter(&self) -> impl Iterator> + '_ { + (0..self.len()).map(move |i| self.get(i, 0)) + } +} + +impl> CpuMap { + /// Sets the queue size at the given CPU index, and optionally a chained program. + /// + /// When sending the packet to the CPU at the given index, the kernel will queue up to + /// `queue_size` packets before dropping them. + /// + /// 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. + /// + /// 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, [`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<(), 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 mut value = unsafe { std::mem::zeroed::() }; + 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 + value.bpf_prog.fd = program + .map(|prog| prog.as_fd().as_raw_fd()) + .unwrap_or_default(); + bpf_map_update_elem(fd, Some(&cpu_index), &value, flags) + } else { + if program.is_some() { + return Err(XdpMapError::ChainedProgramNotSupported); + } + bpf_map_update_elem(fd, Some(&cpu_index), &queue_size, flags) + }; + + res.map_err(|(_, io_error)| { + MapError::from(SyscallError { + call: "bpf_map_update_elem", + io_error, + }) + })?; + Ok(()) + } +} + +impl> IterableMap for CpuMap { + fn map(&self) -> &MapData { + self.inner.borrow() + } + + fn get(&self, key: &u32) -> Result { + self.get(*key, 0) + } +} + +unsafe impl Pod for bpf_cpumap_val {} + +#[derive(Clone, Copy, Debug)] +/// The value of a CPU map. +pub struct CpuMapValue { + /// Size of the for the CPU. + pub queue_size: u32, + /// Chained XDP program ID. + pub prog_id: Option, +} diff --git a/aya/src/maps/xdp/dev_map.rs b/aya/src/maps/xdp/dev_map.rs new file mode 100644 index 00000000..3c4240f5 --- /dev/null +++ b/aya/src/maps/xdp/dev_map.rs @@ -0,0 +1,187 @@ +//! An array of network devices. + +use std::{ + borrow::{Borrow, BorrowMut}, + num::NonZeroU32, + os::fd::{AsFd, AsRawFd}, +}; + +use aya_obj::generated::bpf_devmap_val; + +use crate::{ + maps::{check_bounds, check_kv_size, IterableMap, MapData, MapError}, + programs::ProgramFd, + sys::{bpf_map_lookup_elem, bpf_map_update_elem, SyscallError}, + Pod, FEATURES, +}; + +use super::XdpMapError; + +/// An array of network devices. +/// +/// XDP programs can use this map to redirect to other network +/// devices. +/// +/// # Minimum kernel version +/// +/// The minimum kernel version required to use this feature is 4.14. +/// +/// # Examples +/// ```no_run +/// # let mut bpf = aya::Bpf::load(&[])?; +/// use aya::maps::xdp::DevMap; +/// +/// let mut devmap = DevMap::try_from(bpf.map_mut("IFACES").unwrap())?; +/// // 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: +#[doc(alias = "BPF_MAP_TYPE_DEVMAP")] +pub struct DevMap { + inner: T, +} + +impl> DevMap { + pub(crate) fn new(map: T) -> Result { + let data = map.borrow(); + + if FEATURES.devmap_prog_id() { + check_kv_size::(data)?; + } else { + check_kv_size::(data)?; + } + + 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.borrow().obj.max_entries() + } + + /// Returns the target interface index and optional program at a 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 { + let data = self.inner.borrow(); + check_bounds(data, index)?; + let fd = data.fd().as_fd(); + + let value = if FEATURES.devmap_prog_id() { + bpf_map_lookup_elem::<_, bpf_devmap_val>(fd, &index, flags).map(|value| { + value.map(|value| DevMapValue { + 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 }), + }) + }) + } else { + bpf_map_lookup_elem::<_, u32>(fd, &index, flags).map(|value| { + value.map(|ifindex| DevMapValue { + if_index: ifindex, + prog_id: None, + }) + }) + }; + value + .map_err(|(_, io_error)| SyscallError { + call: "bpf_map_lookup_elem", + io_error, + })? + .ok_or(MapError::KeyNotFound) + } + + /// An iterator over the elements of the array. + pub fn iter(&self) -> impl Iterator> + '_ { + (0..self.len()).map(move |i| self.get(i, 0)) + } +} + +impl> DevMap { + /// Sets the target interface index at index, and optionally a chained program. + /// + /// When redirecting using `index`, packets will be transmitted by the interface with + /// `target_if_index`. + /// + /// 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. + /// + /// 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 chained programs and one is provided. + pub fn set( + &mut self, + index: u32, + target_if_index: u32, + program: Option<&ProgramFd>, + flags: u64, + ) -> 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 mut value = unsafe { std::mem::zeroed::() }; + 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 + value.bpf_prog.fd = program + .map(|prog| prog.as_fd().as_raw_fd()) + .unwrap_or_default(); + bpf_map_update_elem(fd, Some(&index), &value, flags) + } else { + if program.is_some() { + return Err(XdpMapError::ChainedProgramNotSupported); + } + bpf_map_update_elem(fd, Some(&index), &target_if_index, flags) + }; + + res.map_err(|(_, io_error)| { + MapError::from(SyscallError { + call: "bpf_map_update_elem", + io_error, + }) + })?; + Ok(()) + } +} + +impl> IterableMap for DevMap { + fn map(&self) -> &MapData { + self.inner.borrow() + } + + fn get(&self, key: &u32) -> Result { + self.get(*key, 0) + } +} + +unsafe impl Pod for bpf_devmap_val {} + +#[derive(Clone, Copy, Debug)] +/// The value of a device map. +pub struct DevMapValue { + /// Target interface index to redirect to. + pub if_index: u32, + /// Chained XDP program ID. + pub prog_id: Option, +} diff --git a/aya/src/maps/xdp/dev_map_hash.rs b/aya/src/maps/xdp/dev_map_hash.rs new file mode 100644 index 00000000..469c8420 --- /dev/null +++ b/aya/src/maps/xdp/dev_map_hash.rs @@ -0,0 +1,168 @@ +//! An hashmap of network devices. + +use std::{ + borrow::{Borrow, BorrowMut}, + num::NonZeroU32, + os::fd::{AsFd, AsRawFd}, +}; + +use aya_obj::generated::bpf_devmap_val; + +use crate::{ + maps::{check_kv_size, hash_map, IterableMap, MapData, MapError, MapIter, MapKeys}, + programs::ProgramFd, + sys::{bpf_map_lookup_elem, SyscallError}, + FEATURES, +}; + +use super::{dev_map::DevMapValue, XdpMapError}; + +/// An hashmap of network devices. +/// +/// XDP programs can use this map to redirect to other network +/// devices. +/// +/// # Minimum kernel version +/// +/// The minimum kernel version required to use this feature is 5.4. +/// +/// # Examples +/// ```no_run +/// # let mut bpf = aya::Bpf::load(&[])?; +/// use aya::maps::xdp::DevMapHash; +/// +/// let mut devmap = DevMapHash::try_from(bpf.map_mut("IFACES").unwrap())?; +/// // 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: +#[doc(alias = "BPF_MAP_TYPE_DEVMAP_HASH")] +pub struct DevMapHash { + inner: T, +} + +impl> DevMapHash { + pub(crate) fn new(map: T) -> Result { + let data = map.borrow(); + + if FEATURES.devmap_prog_id() { + check_kv_size::(data)?; + } else { + check_kv_size::(data)?; + } + + Ok(Self { inner: map }) + } + + /// Returns the target interface index and optional program for a given key. + /// + /// # Errors + /// + /// Returns [`MapError::SyscallError`] if `bpf_map_lookup_elem` fails. + pub fn get(&self, key: u32, flags: u64) -> Result { + let fd = self.inner.borrow().fd().as_fd(); + + let value = if FEATURES.devmap_prog_id() { + bpf_map_lookup_elem::<_, bpf_devmap_val>(fd, &key, flags).map(|value| { + value.map(|value| DevMapValue { + 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 }), + }) + }) + } else { + bpf_map_lookup_elem::<_, u32>(fd, &key, flags).map(|value| { + value.map(|ifindex| DevMapValue { + if_index: ifindex, + prog_id: None, + }) + }) + }; + value + .map_err(|(_, io_error)| SyscallError { + call: "bpf_map_lookup_elem", + io_error, + })? + .ok_or(MapError::KeyNotFound) + } + + /// An iterator over the elements of the devmap in arbitrary order. + pub fn iter(&self) -> MapIter<'_, u32, DevMapValue, Self> { + MapIter::new(self) + } + + /// An iterator visiting all keys in arbitrary order. + pub fn keys(&self) -> MapKeys<'_, u32> { + MapKeys::new(self.inner.borrow()) + } +} + +impl> DevMapHash { + /// Inserts an ifindex and optionally a chained program in the map. + /// + /// When redirecting using `key`, packets will be transmitted by the interface with `ifindex`. + /// + /// 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. + /// + /// 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 chained programs and one is + /// provided. + pub fn insert( + &mut self, + key: u32, + target_if_index: u32, + program: Option<&ProgramFd>, + flags: u64, + ) -> Result<(), XdpMapError> { + if FEATURES.devmap_prog_id() { + let mut value = unsafe { std::mem::zeroed::() }; + 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 + 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)?; + } else { + if program.is_some() { + return Err(XdpMapError::ChainedProgramNotSupported); + } + hash_map::insert(self.inner.borrow_mut(), &key, &target_if_index, flags)?; + } + Ok(()) + } + + /// Removes a value from the map. + /// + /// # Errors + /// + /// Returns [`MapError::SyscallError`] if `bpf_map_delete_elem` fails. + pub fn remove(&mut self, key: u32) -> Result<(), MapError> { + hash_map::remove(self.inner.borrow_mut(), &key) + } +} + +impl> IterableMap for DevMapHash { + fn map(&self) -> &MapData { + self.inner.borrow() + } + + fn get(&self, key: &u32) -> Result { + self.get(*key, 0) + } +} diff --git a/aya/src/maps/xdp/mod.rs b/aya/src/maps/xdp/mod.rs new file mode 100644 index 00000000..0faa41bb --- /dev/null +++ b/aya/src/maps/xdp/mod.rs @@ -0,0 +1,25 @@ +//! XDP maps. +mod cpu_map; +mod dev_map; +mod dev_map_hash; +mod xsk_map; + +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), +} diff --git a/aya/src/maps/xdp/xsk_map.rs b/aya/src/maps/xdp/xsk_map.rs new file mode 100644 index 00000000..5382ae4c --- /dev/null +++ b/aya/src/maps/xdp/xsk_map.rs @@ -0,0 +1,81 @@ +//! An array of AF_XDP sockets. + +use std::{ + borrow::{Borrow, BorrowMut}, + os::fd::{AsFd, AsRawFd, RawFd}, +}; + +use crate::{ + maps::{check_bounds, check_kv_size, MapData, MapError}, + sys::{bpf_map_update_elem, SyscallError}, +}; + +/// 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 +/// ```no_run +/// # let mut bpf = aya::Bpf::load(&[])?; +/// # let socket_fd = 1; +/// use aya::maps::XskMap; +/// +/// let mut xskmap = XskMap::try_from(bpf.map_mut("SOCKETS").unwrap())?; +/// // socket_fd is the RawFd of an AF_XDP socket +/// xskmap.set(0, socket_fd, 0); +/// # Ok::<(), aya::BpfError>(()) +/// ``` +/// +/// # See also +/// +/// Kernel documentation: +#[doc(alias = "BPF_MAP_TYPE_XSKMAP")] +pub struct XskMap { + inner: T, +} + +impl> XskMap { + pub(crate) fn new(map: T) -> Result { + let data = map.borrow(); + check_kv_size::(data)?; + + 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.borrow().obj.max_entries() + } +} + +impl> XskMap { + /// Sets the `AF_XDP` socket at a given index. + /// + /// When redirecting a packet, the `AF_XDP` socket at `index` will recieve the packet. Note + /// that it will do so only if the socket is bound to the same queue the packet was recieved + /// on. + /// + /// # 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, socket_fd: impl AsRawFd, flags: u64) -> Result<(), MapError> { + let data = self.inner.borrow_mut(); + check_bounds(data, index)?; + let fd = data.fd().as_fd(); + bpf_map_update_elem(fd, Some(&index), &socket_fd.as_raw_fd(), flags).map_err( + |(_, io_error)| SyscallError { + call: "bpf_map_update_elem", + io_error, + }, + )?; + Ok(()) + } +} diff --git a/aya/src/programs/mod.rs b/aya/src/programs/mod.rs index 0952a348..bb9622fe 100644 --- a/aya/src/programs/mod.rs +++ b/aya/src/programs/mod.rs @@ -879,7 +879,6 @@ macro_rules! impl_from_pin { impl_from_pin!( TracePoint, SocketFilter, - Xdp, SkMsg, CgroupSysctl, LircMode2, diff --git a/aya/src/programs/xdp.rs b/aya/src/programs/xdp.rs index 89574328..481d95d9 100644 --- a/aya/src/programs/xdp.rs +++ b/aya/src/programs/xdp.rs @@ -12,18 +12,21 @@ use std::{ hash::Hash, io, os::fd::{AsFd as _, AsRawFd as _, BorrowedFd, RawFd}, + path::Path, }; use thiserror::Error; use crate::{ generated::{ - bpf_attach_type, bpf_link_type, bpf_prog_type, XDP_FLAGS_DRV_MODE, XDP_FLAGS_HW_MODE, - XDP_FLAGS_REPLACE, XDP_FLAGS_SKB_MODE, XDP_FLAGS_UPDATE_IF_NOEXIST, + bpf_link_type, bpf_prog_type, XDP_FLAGS_DRV_MODE, XDP_FLAGS_HW_MODE, XDP_FLAGS_REPLACE, + XDP_FLAGS_SKB_MODE, XDP_FLAGS_UPDATE_IF_NOEXIST, }, + obj::programs::XdpAttachType, programs::{ define_link_wrapper, load_program, FdLink, Link, LinkError, ProgramData, ProgramError, }, sys::{bpf_link_create, bpf_link_get_info_by_fd, bpf_link_update, netlink_set_xdp_fd}, + VerifierLogLevel, }; /// The type returned when attaching an [`Xdp`] program fails on kernels `< 5.9`. @@ -80,12 +83,13 @@ bitflags::bitflags! { #[doc(alias = "BPF_PROG_TYPE_XDP")] pub struct Xdp { pub(crate) data: ProgramData, + pub(crate) attach_type: XdpAttachType, } impl Xdp { /// Loads the program inside the kernel. pub fn load(&mut self) -> Result<(), ProgramError> { - self.data.expected_attach_type = Some(bpf_attach_type::BPF_XDP); + self.data.expected_attach_type = Some(self.attach_type.into()); load_program(bpf_prog_type::BPF_PROG_TYPE_XDP, &mut self.data) } @@ -133,10 +137,18 @@ impl Xdp { let prog_fd = prog_fd.as_fd(); if KernelVersion::current().unwrap() >= KernelVersion::new(5, 9, 0) { + // Unwrap safety: the function starts with `self.fd()?` that will succeed if and only + // if the program has been loaded, i.e. there is an fd. We get one by: + // - Using `Xdp::from_pin` that sets `expected_attach_type` + // - Calling `Xdp::attach` that sets `expected_attach_type`, as geting an `Xdp` + // instance trhough `Xdp:try_from(Program)` does not set any fd. + // So, in all cases where we have an fd, we have an expected_attach_type. Thus, if we + // reach this point, expected_attach_type is guaranteed to be Some(_). + let attach_type = self.data.expected_attach_type.unwrap(); let link_fd = bpf_link_create( prog_fd, LinkTarget::IfIndex(if_index), - bpf_attach_type::BPF_XDP, + attach_type, None, flags.bits(), ) @@ -163,6 +175,21 @@ impl Xdp { } } + /// Creates a program from a pinned entry on a bpffs. + /// + /// Existing links will not be populated. To work with existing links you should use [`crate::programs::links::PinnedLink`]. + /// + /// On drop, any managed links are detached and the program is unloaded. This will not result in + /// the program being unloaded from the kernel if it is still pinned. + pub fn from_pin>( + path: P, + attach_type: XdpAttachType, + ) -> Result { + let mut data = ProgramData::from_pinned_path(path, VerifierLogLevel::default())?; + data.expected_attach_type = Some(attach_type.into()); + Ok(Self { data, attach_type }) + } + /// Detaches the program. /// /// See [Xdp::attach]. diff --git a/aya/src/sys/bpf.rs b/aya/src/sys/bpf.rs index d3cca3ee..cf41b74a 100644 --- a/aya/src/sys/bpf.rs +++ b/aya/src/sys/bpf.rs @@ -8,6 +8,7 @@ use std::{ }; use crate::util::KernelVersion; +use assert_matches::assert_matches; use libc::{c_char, c_long, ENOENT, ENOSPC}; use obj::{ btf::{BtfEnum64, Enum64}, @@ -793,6 +794,28 @@ pub(crate) fn is_bpf_cookie_supported() -> bool { bpf_prog_load(&mut attr).is_ok() } +/// Tests whether CpuMap, DevMap and DevMapHash support program ids +pub(crate) fn is_prog_id_supported(map_type: bpf_map_type) -> bool { + assert_matches!( + map_type, + bpf_map_type::BPF_MAP_TYPE_CPUMAP + | bpf_map_type::BPF_MAP_TYPE_DEVMAP + | bpf_map_type::BPF_MAP_TYPE_DEVMAP_HASH + ); + + let mut attr = unsafe { mem::zeroed::() }; + let u = unsafe { &mut attr.__bindgen_anon_1 }; + + u.map_type = map_type as u32; + u.key_size = 4; + u.value_size = 8; // 4 for CPU ID, 8 for CPU ID + prog ID + u.max_entries = 1; + u.map_flags = 0; + + // SAFETY: BPF_MAP_CREATE returns a new file descriptor. + unsafe { fd_sys_bpf(bpf_cmd::BPF_MAP_CREATE, &mut attr) }.is_ok() +} + pub(crate) fn is_btf_supported() -> bool { let mut btf = Btf::new(); let name_offset = btf.add_string("int"); @@ -1072,4 +1095,28 @@ mod tests { let supported = is_perf_link_supported(); assert!(!supported); } + + #[test] + fn test_prog_id_supported() { + override_syscall(|_call| Ok(42)); + + // Ensure that the three map types we can check are accepted + let supported = is_prog_id_supported(bpf_map_type::BPF_MAP_TYPE_CPUMAP); + assert!(supported); + let supported = is_prog_id_supported(bpf_map_type::BPF_MAP_TYPE_DEVMAP); + assert!(supported); + let supported = is_prog_id_supported(bpf_map_type::BPF_MAP_TYPE_DEVMAP_HASH); + assert!(supported); + + override_syscall(|_call| Err((-1, io::Error::from_raw_os_error(EINVAL)))); + let supported = is_prog_id_supported(bpf_map_type::BPF_MAP_TYPE_CPUMAP); + assert!(!supported); + } + + #[test] + #[should_panic = "assertion failed: `BPF_MAP_TYPE_HASH` does not match `bpf_map_type::BPF_MAP_TYPE_CPUMAP | bpf_map_type::BPF_MAP_TYPE_DEVMAP | +bpf_map_type::BPF_MAP_TYPE_DEVMAP_HASH`"] + fn test_prog_id_supported_reject_types() { + is_prog_id_supported(bpf_map_type::BPF_MAP_TYPE_HASH); + } } diff --git a/bpf/aya-bpf/src/maps/mod.rs b/bpf/aya-bpf/src/maps/mod.rs index 8fa375dd..b46bf084 100644 --- a/bpf/aya-bpf/src/maps/mod.rs +++ b/bpf/aya-bpf/src/maps/mod.rs @@ -17,6 +17,7 @@ pub mod sock_hash; pub mod sock_map; pub mod stack; pub mod stack_trace; +pub mod xdp; pub use array::Array; pub use bloom_filter::BloomFilter; @@ -30,3 +31,4 @@ pub use sock_hash::SockHash; pub use sock_map::SockMap; pub use stack::Stack; pub use stack_trace::StackTrace; +pub use xdp::{CpuMap, DevMap, DevMapHash, XskMap}; diff --git a/bpf/aya-bpf/src/maps/xdp/cpu_map.rs b/bpf/aya-bpf/src/maps/xdp/cpu_map.rs new file mode 100644 index 00000000..133be94b --- /dev/null +++ b/bpf/aya-bpf/src/maps/xdp/cpu_map.rs @@ -0,0 +1,120 @@ +use core::{cell::UnsafeCell, mem}; + +use aya_bpf_bindings::bindings::bpf_cpumap_val; + +use crate::{ + bindings::{bpf_map_def, bpf_map_type::BPF_MAP_TYPE_CPUMAP}, + maps::PinningType, +}; + +use super::try_redirect_map; + +/// 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)] +pub struct CpuMap { + def: UnsafeCell, +} + +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. `max_entries` can be set to zero here, and updated by userspace + /// at runtime. Refer to the userspace documentation for more information. + /// + /// # 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 { + CpuMap { + def: UnsafeCell::new(bpf_map_def { + type_: BPF_MAP_TYPE_CPUMAP, + key_size: mem::size_of::() as u32, + value_size: mem::size_of::() as u32, + max_entries, + map_flags: flags, + id: 0, + pinning: PinningType::None as u32, + }), + } + } + + /// 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 { + CpuMap { + def: UnsafeCell::new(bpf_map_def { + type_: BPF_MAP_TYPE_CPUMAP, + key_size: mem::size_of::() as u32, + value_size: mem::size_of::() as u32, + max_entries, + map_flags: flags, + id: 0, + pinning: PinningType::ByName as u32, + }), + } + } + + /// 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, 0).unwrap_or(xdp_action::XDP_DROP) + /// } + /// ``` + #[inline(always)] + pub fn redirect(&self, index: u32, flags: u64) -> Result { + try_redirect_map(&self.def, index, flags) + } +} diff --git a/bpf/aya-bpf/src/maps/xdp/dev_map.rs b/bpf/aya-bpf/src/maps/xdp/dev_map.rs new file mode 100644 index 00000000..cfa44cb3 --- /dev/null +++ b/bpf/aya-bpf/src/maps/xdp/dev_map.rs @@ -0,0 +1,155 @@ +use core::{cell::UnsafeCell, mem, num::NonZeroU32, ptr::NonNull}; + +use aya_bpf_bindings::bindings::bpf_devmap_val; +use aya_bpf_cty::c_void; + +use crate::{ + bindings::{bpf_map_def, bpf_map_type::BPF_MAP_TYPE_DEVMAP}, + helpers::bpf_map_lookup_elem, + maps::PinningType, +}; + +use super::try_redirect_map; + +/// 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)] +pub struct DevMap { + def: UnsafeCell, +} + +unsafe impl Sync for 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 { + DevMap { + def: UnsafeCell::new(bpf_map_def { + type_: BPF_MAP_TYPE_DEVMAP, + key_size: mem::size_of::() as u32, + value_size: mem::size_of::() as u32, + max_entries, + map_flags: flags, + id: 0, + pinning: PinningType::None as u32, + }), + } + } + + /// 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 { + DevMap { + def: UnsafeCell::new(bpf_map_def { + type_: BPF_MAP_TYPE_DEVMAP, + key_size: mem::size_of::() as u32, + value_size: mem::size_of::() as u32, + max_entries, + map_flags: flags, + id: 0, + pinning: PinningType::ByName as u32, + }), + } + } + + /// 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 target_if_index = MAP.get(0).target_if_index; + /// + /// // redirect to if_index + /// ``` + #[inline(always)] + pub fn get(&self, index: u32) -> Option { + unsafe { + let value = bpf_map_lookup_elem( + self.def.get() as *mut _, + &index as *const _ as *const c_void, + ); + NonNull::new(value as *mut bpf_devmap_val).map(|p| DevMapValue { + 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: NonZeroU32::new(p.as_ref().bpf_prog.id), + }) + } + } + + /// 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) -> u32 { + /// MAP.redirect(7, 0).unwrap_or(xdp_action::XDP_DROP) + /// } + /// ``` + #[inline(always)] + pub fn redirect(&self, index: u32, flags: u64) -> Result { + try_redirect_map(&self.def, index, flags) + } +} + +#[derive(Clone, Copy)] +/// The value of a device map. +pub struct DevMapValue { + /// Target interface index to redirect to. + pub if_index: u32, + /// Chained XDP program ID. + pub prog_id: Option, +} diff --git a/bpf/aya-bpf/src/maps/xdp/dev_map_hash.rs b/bpf/aya-bpf/src/maps/xdp/dev_map_hash.rs new file mode 100644 index 00000000..cbec50bb --- /dev/null +++ b/bpf/aya-bpf/src/maps/xdp/dev_map_hash.rs @@ -0,0 +1,146 @@ +use core::{cell::UnsafeCell, mem, num::NonZeroU32, ptr::NonNull}; + +use aya_bpf_bindings::bindings::bpf_devmap_val; +use aya_bpf_cty::c_void; + +use crate::{ + bindings::{bpf_map_def, bpf_map_type::BPF_MAP_TYPE_DEVMAP_HASH}, + helpers::bpf_map_lookup_elem, + maps::PinningType, +}; + +use super::{dev_map::DevMapValue, try_redirect_map}; + +/// 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)] +pub struct DevMapHash { + def: UnsafeCell, +} + +unsafe impl Sync for 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 { + DevMapHash { + def: UnsafeCell::new(bpf_map_def { + type_: BPF_MAP_TYPE_DEVMAP_HASH, + key_size: mem::size_of::() as u32, + value_size: mem::size_of::() as u32, + max_entries, + map_flags: flags, + id: 0, + pinning: PinningType::None as u32, + }), + } + } + + /// 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 { + DevMapHash { + def: UnsafeCell::new(bpf_map_def { + type_: BPF_MAP_TYPE_DEVMAP_HASH, + key_size: mem::size_of::() as u32, + value_size: mem::size_of::() as u32, + max_entries, + map_flags: flags, + id: 0, + pinning: PinningType::ByName as u32, + }), + } + } + + /// 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 target_if_index = MAP.get(42).target_if_index; + /// + /// // redirect to ifindex + /// ``` + #[inline(always)] + pub fn get(&self, key: u32) -> Option { + unsafe { + 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 { + 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: NonZeroU32::new(p.as_ref().bpf_prog.id), + }) + } + } + + /// 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) -> u32 { + /// MAP.redirect(7, 0).unwrap_or(xdp_action::XDP_DROP) + /// } + /// ``` + #[inline(always)] + pub fn redirect(&self, key: u32, flags: u64) -> Result { + try_redirect_map(&self.def, key, flags) + } +} diff --git a/bpf/aya-bpf/src/maps/xdp/mod.rs b/bpf/aya-bpf/src/maps/xdp/mod.rs new file mode 100644 index 00000000..5c8df0e5 --- /dev/null +++ b/bpf/aya-bpf/src/maps/xdp/mod.rs @@ -0,0 +1,33 @@ +mod cpu_map; +mod dev_map; +mod dev_map_hash; +mod xsk_map; + +use core::cell::UnsafeCell; + +use aya_bpf_bindings::{ + bindings::{bpf_map_def, xdp_action::XDP_REDIRECT}, + helpers::bpf_redirect_map, +}; +pub use cpu_map::CpuMap; +pub use dev_map::DevMap; +pub use dev_map_hash::DevMapHash; +pub use xsk_map::XskMap; + +/// Wrapper aroung the `bpf_redirect_map` function. +/// +/// # Return value +/// +/// - `Ok(XDP_REDIRECT)` on success. +/// - `Err(_)` of the lowest two bits of `flags` on failure. +#[inline(always)] +fn try_redirect_map(def: &UnsafeCell, key: u32, flags: u64) -> Result { + // 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. + let ret = unsafe { bpf_redirect_map(def.get() as *mut _, key.into(), flags) }; + match ret.unsigned_abs() as u32 { + XDP_REDIRECT => Ok(XDP_REDIRECT), + ret => Err(ret), + } +} diff --git a/bpf/aya-bpf/src/maps/xdp/xsk_map.rs b/bpf/aya-bpf/src/maps/xdp/xsk_map.rs new file mode 100644 index 00000000..455dfc84 --- /dev/null +++ b/bpf/aya-bpf/src/maps/xdp/xsk_map.rs @@ -0,0 +1,164 @@ +use core::{cell::UnsafeCell, mem, ptr::NonNull}; + +use aya_bpf_bindings::bindings::bpf_xdp_sock; +use aya_bpf_cty::c_void; + +use crate::{ + bindings::{bpf_map_def, bpf_map_type::BPF_MAP_TYPE_XSKMAP}, + helpers::bpf_map_lookup_elem, + maps::PinningType, +}; + +use super::try_redirect_map; + +/// 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 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)] +pub struct XskMap { + def: UnsafeCell, +} + +unsafe impl Sync for 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 { + XskMap { + def: UnsafeCell::new(bpf_map_def { + type_: BPF_MAP_TYPE_XSKMAP, + key_size: mem::size_of::() as u32, + value_size: mem::size_of::() as u32, + max_entries, + map_flags: flags, + id: 0, + pinning: PinningType::None as u32, + }), + } + } + + /// 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 { + XskMap { + def: UnsafeCell::new(bpf_map_def { + type_: BPF_MAP_TYPE_XSKMAP, + key_size: mem::size_of::() as u32, + value_size: mem::size_of::() as u32, + max_entries, + map_flags: flags, + id: 0, + pinning: PinningType::ByName as u32, + }), + } + } + + /// 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)] + pub fn get(&self, index: u32) -> Option { + unsafe { + let value = bpf_map_lookup_elem( + self.def.get() as *mut _, + &index as *const _ as *const c_void, + ); + NonNull::new(value as *mut bpf_xdp_sock).map(|p| p.as_ref().queue_id) + } + } + + /// 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) -> u32 { + /// let queue_id = unsafe { (*ctx.ctx).rx_queue_index }; + /// MAP.redirect(queue_id, 0).unwrap_or(xdp_action::XDP_DROP) + /// } + /// ``` + #[inline(always)] + pub fn redirect(&self, index: u32, flags: u64) -> Result { + try_redirect_map(&self.def, index, flags) + } +} diff --git a/test/integration-ebpf/Cargo.toml b/test/integration-ebpf/Cargo.toml index 12b04546..e72e0a87 100644 --- a/test/integration-ebpf/Cargo.toml +++ b/test/integration-ebpf/Cargo.toml @@ -43,3 +43,11 @@ path = "src/bpf_probe_read.rs" [[bin]] name = "two_progs" path = "src/two_progs.rs" + +[[bin]] +name = "redirect" +path = "src/redirect.rs" + +[[bin]] +name = "xdp_sec" +path = "src/xdp_sec.rs" diff --git a/test/integration-ebpf/src/redirect.rs b/test/integration-ebpf/src/redirect.rs new file mode 100644 index 00000000..41812cd0 --- /dev/null +++ b/test/integration-ebpf/src/redirect.rs @@ -0,0 +1,73 @@ +#![no_std] +#![no_main] + +use aya_bpf::{ + bindings::xdp_action, + macros::{map, xdp}, + maps::{Array, CpuMap, DevMap, DevMapHash, XskMap}, + programs::XdpContext, +}; + +#[map] +static SOCKS: XskMap = XskMap::with_max_entries(1, 0); +#[map] +static DEVS: DevMap = DevMap::with_max_entries(1, 0); +#[map] +static DEVS_HASH: DevMapHash = DevMapHash::with_max_entries(1, 0); +#[map] +static CPUS: CpuMap = CpuMap::with_max_entries(1, 0); + +/// Hits of a probe, used to test program chaining through CpuMap/DevMap. +/// The first slot counts how many times the "raw" xdp program got executed, while the second slot +/// counts how many times the map programs got executed. +/// This allows the test harness to assert that a specific step got executed. +#[map] +static mut HITS: Array = Array::with_max_entries(2, 0); + +#[xdp] +pub fn redirect_sock(_ctx: XdpContext) -> u32 { + SOCKS.redirect(0, 0).unwrap_or(xdp_action::XDP_ABORTED) +} + +#[xdp] +pub fn redirect_dev(_ctx: XdpContext) -> u32 { + inc_hit(0); + 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, 0).unwrap_or(xdp_action::XDP_ABORTED) +} + +#[xdp] +pub fn redirect_cpu(_ctx: XdpContext) -> u32 { + inc_hit(0); + CPUS.redirect(0, 0).unwrap_or(xdp_action::XDP_ABORTED) +} + +#[xdp(map = "cpumap")] +pub fn redirect_cpu_chain(_ctx: XdpContext) -> u32 { + inc_hit(1); + xdp_action::XDP_PASS +} + +#[xdp(map = "devmap")] +pub fn redirect_dev_chain(_ctx: XdpContext) -> u32 { + inc_hit(1); + xdp_action::XDP_PASS +} + +#[inline(always)] +fn inc_hit(index: u32) { + if let Some(hit) = unsafe { HITS.get_ptr_mut(index) } { + unsafe { *hit += 1 }; + } +} + +#[cfg(not(test))] +#[panic_handler] +fn panic(_info: &core::panic::PanicInfo) -> ! { + loop {} +} diff --git a/test/integration-ebpf/src/xdp_sec.rs b/test/integration-ebpf/src/xdp_sec.rs new file mode 100644 index 00000000..5e64f56a --- /dev/null +++ b/test/integration-ebpf/src/xdp_sec.rs @@ -0,0 +1,26 @@ +#![no_std] +#![no_main] + +use aya_bpf::{bindings::xdp_action::XDP_PASS, macros::xdp, programs::XdpContext}; + +macro_rules! probe { + ($name:ident, ($($arg:ident $(= $value:literal)?),*) ) => { + #[xdp($($arg $(= $value)?),*)] + pub fn $name(_ctx: XdpContext) -> u32 { + XDP_PASS + } + }; +} + +probe!(xdp_plain, ()); +probe!(xdp_frags, (frags)); +probe!(xdp_cpumap, (map = "cpumap")); +probe!(xdp_devmap, (map = "devmap")); +probe!(xdp_frags_cpumap, (frags, map = "cpumap")); +probe!(xdp_frags_devmap, (frags, map = "devmap")); + +#[cfg(not(test))] +#[panic_handler] +fn panic(_info: &core::panic::PanicInfo) -> ! { + loop {} +} diff --git a/test/integration-test/src/lib.rs b/test/integration-test/src/lib.rs index 08911a4e..79be5fd3 100644 --- a/test/integration-test/src/lib.rs +++ b/test/integration-test/src/lib.rs @@ -19,6 +19,8 @@ pub const RELOCATIONS: &[u8] = include_bytes_aligned!(concat!(env!("OUT_DIR"), " pub const TWO_PROGS: &[u8] = include_bytes_aligned!(concat!(env!("OUT_DIR"), "/two_progs")); pub const BPF_PROBE_READ: &[u8] = include_bytes_aligned!(concat!(env!("OUT_DIR"), "/bpf_probe_read")); +pub const REDIRECT: &[u8] = include_bytes_aligned!(concat!(env!("OUT_DIR"), "/redirect")); +pub const XDP_SEC: &[u8] = include_bytes_aligned!(concat!(env!("OUT_DIR"), "/xdp_sec")); #[cfg(test)] mod tests; diff --git a/test/integration-test/src/tests.rs b/test/integration-test/src/tests.rs index dd8565b0..3a995180 100644 --- a/test/integration-test/src/tests.rs +++ b/test/integration-test/src/tests.rs @@ -6,3 +6,4 @@ mod log; mod rbpf; mod relocations; mod smoke; +mod xdp; diff --git a/test/integration-test/src/tests/load.rs b/test/integration-test/src/tests/load.rs index 761a9e89..795f396d 100644 --- a/test/integration-test/src/tests/load.rs +++ b/test/integration-test/src/tests/load.rs @@ -13,6 +13,7 @@ use aya::{ util::KernelVersion, Bpf, }; +use aya_obj::programs::XdpAttachType; const MAX_RETRIES: usize = 100; const RETRY_DURATION: Duration = Duration::from_millis(10); @@ -309,7 +310,7 @@ fn pin_lifecycle() { // 2. Load program from bpffs but don't attach it { - let _ = Xdp::from_pin("/sys/fs/bpf/aya-xdp-test-prog").unwrap(); + let _ = Xdp::from_pin("/sys/fs/bpf/aya-xdp-test-prog", XdpAttachType::Interface).unwrap(); } // should still be loaded since prog was pinned @@ -317,7 +318,8 @@ fn pin_lifecycle() { // 3. Load program from bpffs and attach { - let mut prog = Xdp::from_pin("/sys/fs/bpf/aya-xdp-test-prog").unwrap(); + let mut prog = + Xdp::from_pin("/sys/fs/bpf/aya-xdp-test-prog", XdpAttachType::Interface).unwrap(); let link_id = prog.attach("lo", XdpFlags::default()).unwrap(); let link = prog.take_link(link_id).unwrap(); let fd_link: FdLink = link.try_into().unwrap(); diff --git a/test/integration-test/src/tests/rbpf.rs b/test/integration-test/src/tests/rbpf.rs index 9caab94c..3d2c0c97 100644 --- a/test/integration-test/src/tests/rbpf.rs +++ b/test/integration-test/src/tests/rbpf.rs @@ -2,7 +2,7 @@ use core::{mem::size_of, ptr::null_mut, slice::from_raw_parts}; use std::collections::HashMap; use assert_matches::assert_matches; -use aya_obj::{generated::bpf_insn, Object, ProgramSection}; +use aya_obj::{generated::bpf_insn, programs::XdpAttachType, Object, ProgramSection}; #[test] fn run_with_rbpf() { @@ -11,7 +11,10 @@ fn run_with_rbpf() { assert_eq!(object.programs.len(), 1); assert_matches!( object.programs["pass"].section, - ProgramSection::Xdp { frags: true } + ProgramSection::Xdp { + frags: true, + attach_type: XdpAttachType::Interface + } ); let instructions = &object diff --git a/test/integration-test/src/tests/xdp.rs b/test/integration-test/src/tests/xdp.rs new file mode 100644 index 00000000..88423fe9 --- /dev/null +++ b/test/integration-test/src/tests/xdp.rs @@ -0,0 +1,98 @@ +use std::{net::UdpSocket, time::Duration}; + +use aya::{ + maps::{Array, CpuMap}, + programs::{Xdp, XdpFlags}, + Bpf, +}; +use object::{Object, ObjectSection, ObjectSymbol, SymbolSection}; + +use crate::utils::NetNsGuard; + +#[test] +fn prog_sections() { + let obj_file = object::File::parse(crate::XDP_SEC).unwrap(); + + ensure_symbol(&obj_file, "xdp", "xdp_plain"); + ensure_symbol(&obj_file, "xdp.frags", "xdp_frags"); + ensure_symbol(&obj_file, "xdp/cpumap", "xdp_cpumap"); + ensure_symbol(&obj_file, "xdp/devmap", "xdp_devmap"); + ensure_symbol(&obj_file, "xdp.frags/cpumap", "xdp_frags_cpumap"); + ensure_symbol(&obj_file, "xdp.frags/devmap", "xdp_frags_devmap"); +} + +#[track_caller] +fn ensure_symbol(obj_file: &object::File, sec_name: &str, sym_name: &str) { + let sec = obj_file.section_by_name(sec_name).unwrap_or_else(|| { + let secs = obj_file + .sections() + .flat_map(|sec| sec.name().ok().map(|name| name.to_owned())) + .collect::>(); + panic!("section {sec_name} not found. available sections: {secs:?}"); + }); + let sec = SymbolSection::Section(sec.index()); + + let syms = obj_file + .symbols() + .filter(|sym| sym.section() == sec) + .filter_map(|sym| sym.name().ok()) + .collect::>(); + assert!( + syms.contains(&sym_name), + "symbol not found. available symbols in section: {syms:?}" + ); +} + +#[test] +fn map_load() { + let bpf = Bpf::load(crate::XDP_SEC).unwrap(); + + bpf.program("xdp_plain").unwrap(); + bpf.program("xdp_frags").unwrap(); + bpf.program("xdp_cpumap").unwrap(); + bpf.program("xdp_devmap").unwrap(); + bpf.program("xdp_frags_cpumap").unwrap(); + bpf.program("xdp_frags_devmap").unwrap(); +} + +#[test] +fn cpumap_chain() { + let _netns = NetNsGuard::new(); + + let mut bpf = Bpf::load(crate::REDIRECT).unwrap(); + + // Load our cpumap and our canary map + let mut cpus: CpuMap<_> = bpf.take_map("CPUS").unwrap().try_into().unwrap(); + let hits: Array<_, u32> = bpf.take_map("HITS").unwrap().try_into().unwrap(); + + let xdp_chain_fd = { + // Load the chained program to run on the target CPU + let xdp: &mut Xdp = bpf + .program_mut("redirect_cpu_chain") + .unwrap() + .try_into() + .unwrap(); + xdp.load().unwrap(); + xdp.fd().unwrap() + }; + cpus.set(0, 2048, Some(xdp_chain_fd), 0).unwrap(); + + // Load the main program + let xdp: &mut Xdp = bpf.program_mut("redirect_cpu").unwrap().try_into().unwrap(); + xdp.load().unwrap(); + xdp.attach("lo", XdpFlags::default()).unwrap(); + + let sock = UdpSocket::bind("127.0.0.1:1777").unwrap(); + sock.set_read_timeout(Some(Duration::from_millis(1))) + .unwrap(); + sock.send_to(b"hello cpumap", "127.0.0.1:1777").unwrap(); + + // Read back the packet to ensure it wenth through the entire network stack, including our two + // probes. + let mut buf = vec![0u8; 1000]; + let n = sock.recv(&mut buf).unwrap(); + + assert_eq!(&buf[..n], b"hello cpumap"); + assert_eq!(hits.get(&0, 0).unwrap(), 1); + assert_eq!(hits.get(&1, 0).unwrap(), 1); +} diff --git a/xtask/public-api/aya-bpf.txt b/xtask/public-api/aya-bpf.txt index 4d4aa0f7..e221d2cc 100644 --- a/xtask/public-api/aya-bpf.txt +++ b/xtask/public-api/aya-bpf.txt @@ -563,6 +563,114 @@ impl core::borrow::BorrowMut for aya_bpf::maps::stack_trace::StackTrace wh pub fn aya_bpf::maps::stack_trace::StackTrace::borrow_mut(&mut self) -> &mut T impl core::convert::From for aya_bpf::maps::stack_trace::StackTrace pub fn aya_bpf::maps::stack_trace::StackTrace::from(t: T) -> T +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) -> core::result::Result +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 +impl core::marker::Unpin for aya_bpf::maps::CpuMap +impl !core::panic::unwind_safe::RefUnwindSafe for aya_bpf::maps::CpuMap +impl core::panic::unwind_safe::UnwindSafe for aya_bpf::maps::CpuMap +impl core::convert::Into for aya_bpf::maps::CpuMap where U: core::convert::From +pub fn aya_bpf::maps::CpuMap::into(self) -> U +impl core::convert::TryFrom for aya_bpf::maps::CpuMap where U: core::convert::Into +pub type aya_bpf::maps::CpuMap::Error = core::convert::Infallible +pub fn aya_bpf::maps::CpuMap::try_from(value: U) -> core::result::Result>::Error> +impl core::convert::TryInto for aya_bpf::maps::CpuMap where U: core::convert::TryFrom +pub type aya_bpf::maps::CpuMap::Error = >::Error +pub fn aya_bpf::maps::CpuMap::try_into(self) -> core::result::Result>::Error> +impl core::any::Any for aya_bpf::maps::CpuMap where T: 'static + core::marker::Sized +pub fn aya_bpf::maps::CpuMap::type_id(&self) -> core::any::TypeId +impl core::borrow::Borrow for aya_bpf::maps::CpuMap where T: core::marker::Sized +pub fn aya_bpf::maps::CpuMap::borrow(&self) -> &T +impl core::borrow::BorrowMut for aya_bpf::maps::CpuMap where T: core::marker::Sized +pub fn aya_bpf::maps::CpuMap::borrow_mut(&mut self) -> &mut T +impl core::convert::From for aya_bpf::maps::CpuMap +pub fn aya_bpf::maps::CpuMap::from(t: T) -> T +#[repr(transparent)] pub struct aya_bpf::maps::xdp::DevMap +impl aya_bpf::maps::DevMap +pub fn aya_bpf::maps::DevMap::get(&self, index: u32) -> core::option::Option +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) -> core::result::Result +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 +impl core::marker::Unpin for aya_bpf::maps::DevMap +impl !core::panic::unwind_safe::RefUnwindSafe for aya_bpf::maps::DevMap +impl core::panic::unwind_safe::UnwindSafe for aya_bpf::maps::DevMap +impl core::convert::Into for aya_bpf::maps::DevMap where U: core::convert::From +pub fn aya_bpf::maps::DevMap::into(self) -> U +impl core::convert::TryFrom for aya_bpf::maps::DevMap where U: core::convert::Into +pub type aya_bpf::maps::DevMap::Error = core::convert::Infallible +pub fn aya_bpf::maps::DevMap::try_from(value: U) -> core::result::Result>::Error> +impl core::convert::TryInto for aya_bpf::maps::DevMap where U: core::convert::TryFrom +pub type aya_bpf::maps::DevMap::Error = >::Error +pub fn aya_bpf::maps::DevMap::try_into(self) -> core::result::Result>::Error> +impl core::any::Any for aya_bpf::maps::DevMap where T: 'static + core::marker::Sized +pub fn aya_bpf::maps::DevMap::type_id(&self) -> core::any::TypeId +impl core::borrow::Borrow for aya_bpf::maps::DevMap where T: core::marker::Sized +pub fn aya_bpf::maps::DevMap::borrow(&self) -> &T +impl core::borrow::BorrowMut for aya_bpf::maps::DevMap where T: core::marker::Sized +pub fn aya_bpf::maps::DevMap::borrow_mut(&mut self) -> &mut T +impl core::convert::From for aya_bpf::maps::DevMap +pub fn aya_bpf::maps::DevMap::from(t: T) -> T +#[repr(transparent)] pub struct aya_bpf::maps::xdp::DevMapHash +impl aya_bpf::maps::DevMapHash +pub fn aya_bpf::maps::DevMapHash::get(&self, key: u32) -> core::option::Option +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) -> core::result::Result +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 +impl core::marker::Unpin for aya_bpf::maps::DevMapHash +impl !core::panic::unwind_safe::RefUnwindSafe for aya_bpf::maps::DevMapHash +impl core::panic::unwind_safe::UnwindSafe for aya_bpf::maps::DevMapHash +impl core::convert::Into for aya_bpf::maps::DevMapHash where U: core::convert::From +pub fn aya_bpf::maps::DevMapHash::into(self) -> U +impl core::convert::TryFrom for aya_bpf::maps::DevMapHash where U: core::convert::Into +pub type aya_bpf::maps::DevMapHash::Error = core::convert::Infallible +pub fn aya_bpf::maps::DevMapHash::try_from(value: U) -> core::result::Result>::Error> +impl core::convert::TryInto for aya_bpf::maps::DevMapHash where U: core::convert::TryFrom +pub type aya_bpf::maps::DevMapHash::Error = >::Error +pub fn aya_bpf::maps::DevMapHash::try_into(self) -> core::result::Result>::Error> +impl core::any::Any for aya_bpf::maps::DevMapHash where T: 'static + core::marker::Sized +pub fn aya_bpf::maps::DevMapHash::type_id(&self) -> core::any::TypeId +impl core::borrow::Borrow for aya_bpf::maps::DevMapHash where T: core::marker::Sized +pub fn aya_bpf::maps::DevMapHash::borrow(&self) -> &T +impl core::borrow::BorrowMut for aya_bpf::maps::DevMapHash where T: core::marker::Sized +pub fn aya_bpf::maps::DevMapHash::borrow_mut(&mut self) -> &mut T +impl core::convert::From for aya_bpf::maps::DevMapHash +pub fn aya_bpf::maps::DevMapHash::from(t: T) -> T +#[repr(transparent)] pub struct aya_bpf::maps::xdp::XskMap +impl aya_bpf::maps::XskMap +pub fn aya_bpf::maps::XskMap::get(&self, index: u32) -> core::option::Option +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) -> core::result::Result +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 +impl core::marker::Unpin for aya_bpf::maps::XskMap +impl !core::panic::unwind_safe::RefUnwindSafe for aya_bpf::maps::XskMap +impl core::panic::unwind_safe::UnwindSafe for aya_bpf::maps::XskMap +impl core::convert::Into for aya_bpf::maps::XskMap where U: core::convert::From +pub fn aya_bpf::maps::XskMap::into(self) -> U +impl core::convert::TryFrom for aya_bpf::maps::XskMap where U: core::convert::Into +pub type aya_bpf::maps::XskMap::Error = core::convert::Infallible +pub fn aya_bpf::maps::XskMap::try_from(value: U) -> core::result::Result>::Error> +impl core::convert::TryInto for aya_bpf::maps::XskMap where U: core::convert::TryFrom +pub type aya_bpf::maps::XskMap::Error = >::Error +pub fn aya_bpf::maps::XskMap::try_into(self) -> core::result::Result>::Error> +impl core::any::Any for aya_bpf::maps::XskMap where T: 'static + core::marker::Sized +pub fn aya_bpf::maps::XskMap::type_id(&self) -> core::any::TypeId +impl core::borrow::Borrow for aya_bpf::maps::XskMap where T: core::marker::Sized +pub fn aya_bpf::maps::XskMap::borrow(&self) -> &T +impl core::borrow::BorrowMut for aya_bpf::maps::XskMap where T: core::marker::Sized +pub fn aya_bpf::maps::XskMap::borrow_mut(&mut self) -> &mut T +impl core::convert::From for aya_bpf::maps::XskMap +pub fn aya_bpf::maps::XskMap::from(t: T) -> T #[repr(transparent)] pub struct aya_bpf::maps::Array impl aya_bpf::maps::array::Array pub fn aya_bpf::maps::array::Array::get(&self, index: u32) -> core::option::Option<&T> @@ -618,6 +726,86 @@ impl core::borrow::BorrowMut for aya_bpf::maps::bloom_filter::BloomFilter< pub fn aya_bpf::maps::bloom_filter::BloomFilter::borrow_mut(&mut self) -> &mut T impl core::convert::From for aya_bpf::maps::bloom_filter::BloomFilter pub fn aya_bpf::maps::bloom_filter::BloomFilter::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) -> core::result::Result +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 +impl core::marker::Unpin for aya_bpf::maps::CpuMap +impl !core::panic::unwind_safe::RefUnwindSafe for aya_bpf::maps::CpuMap +impl core::panic::unwind_safe::UnwindSafe for aya_bpf::maps::CpuMap +impl core::convert::Into for aya_bpf::maps::CpuMap where U: core::convert::From +pub fn aya_bpf::maps::CpuMap::into(self) -> U +impl core::convert::TryFrom for aya_bpf::maps::CpuMap where U: core::convert::Into +pub type aya_bpf::maps::CpuMap::Error = core::convert::Infallible +pub fn aya_bpf::maps::CpuMap::try_from(value: U) -> core::result::Result>::Error> +impl core::convert::TryInto for aya_bpf::maps::CpuMap where U: core::convert::TryFrom +pub type aya_bpf::maps::CpuMap::Error = >::Error +pub fn aya_bpf::maps::CpuMap::try_into(self) -> core::result::Result>::Error> +impl core::any::Any for aya_bpf::maps::CpuMap where T: 'static + core::marker::Sized +pub fn aya_bpf::maps::CpuMap::type_id(&self) -> core::any::TypeId +impl core::borrow::Borrow for aya_bpf::maps::CpuMap where T: core::marker::Sized +pub fn aya_bpf::maps::CpuMap::borrow(&self) -> &T +impl core::borrow::BorrowMut for aya_bpf::maps::CpuMap where T: core::marker::Sized +pub fn aya_bpf::maps::CpuMap::borrow_mut(&mut self) -> &mut T +impl core::convert::From for aya_bpf::maps::CpuMap +pub fn aya_bpf::maps::CpuMap::from(t: T) -> T +#[repr(transparent)] pub struct aya_bpf::maps::DevMap +impl aya_bpf::maps::DevMap +pub fn aya_bpf::maps::DevMap::get(&self, index: u32) -> core::option::Option +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) -> core::result::Result +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 +impl core::marker::Unpin for aya_bpf::maps::DevMap +impl !core::panic::unwind_safe::RefUnwindSafe for aya_bpf::maps::DevMap +impl core::panic::unwind_safe::UnwindSafe for aya_bpf::maps::DevMap +impl core::convert::Into for aya_bpf::maps::DevMap where U: core::convert::From +pub fn aya_bpf::maps::DevMap::into(self) -> U +impl core::convert::TryFrom for aya_bpf::maps::DevMap where U: core::convert::Into +pub type aya_bpf::maps::DevMap::Error = core::convert::Infallible +pub fn aya_bpf::maps::DevMap::try_from(value: U) -> core::result::Result>::Error> +impl core::convert::TryInto for aya_bpf::maps::DevMap where U: core::convert::TryFrom +pub type aya_bpf::maps::DevMap::Error = >::Error +pub fn aya_bpf::maps::DevMap::try_into(self) -> core::result::Result>::Error> +impl core::any::Any for aya_bpf::maps::DevMap where T: 'static + core::marker::Sized +pub fn aya_bpf::maps::DevMap::type_id(&self) -> core::any::TypeId +impl core::borrow::Borrow for aya_bpf::maps::DevMap where T: core::marker::Sized +pub fn aya_bpf::maps::DevMap::borrow(&self) -> &T +impl core::borrow::BorrowMut for aya_bpf::maps::DevMap where T: core::marker::Sized +pub fn aya_bpf::maps::DevMap::borrow_mut(&mut self) -> &mut T +impl core::convert::From for aya_bpf::maps::DevMap +pub fn aya_bpf::maps::DevMap::from(t: T) -> T +#[repr(transparent)] pub struct aya_bpf::maps::DevMapHash +impl aya_bpf::maps::DevMapHash +pub fn aya_bpf::maps::DevMapHash::get(&self, key: u32) -> core::option::Option +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) -> core::result::Result +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 +impl core::marker::Unpin for aya_bpf::maps::DevMapHash +impl !core::panic::unwind_safe::RefUnwindSafe for aya_bpf::maps::DevMapHash +impl core::panic::unwind_safe::UnwindSafe for aya_bpf::maps::DevMapHash +impl core::convert::Into for aya_bpf::maps::DevMapHash where U: core::convert::From +pub fn aya_bpf::maps::DevMapHash::into(self) -> U +impl core::convert::TryFrom for aya_bpf::maps::DevMapHash where U: core::convert::Into +pub type aya_bpf::maps::DevMapHash::Error = core::convert::Infallible +pub fn aya_bpf::maps::DevMapHash::try_from(value: U) -> core::result::Result>::Error> +impl core::convert::TryInto for aya_bpf::maps::DevMapHash where U: core::convert::TryFrom +pub type aya_bpf::maps::DevMapHash::Error = >::Error +pub fn aya_bpf::maps::DevMapHash::try_into(self) -> core::result::Result>::Error> +impl core::any::Any for aya_bpf::maps::DevMapHash where T: 'static + core::marker::Sized +pub fn aya_bpf::maps::DevMapHash::type_id(&self) -> core::any::TypeId +impl core::borrow::Borrow for aya_bpf::maps::DevMapHash where T: core::marker::Sized +pub fn aya_bpf::maps::DevMapHash::borrow(&self) -> &T +impl core::borrow::BorrowMut for aya_bpf::maps::DevMapHash where T: core::marker::Sized +pub fn aya_bpf::maps::DevMapHash::borrow_mut(&mut self) -> &mut T +impl core::convert::From for aya_bpf::maps::DevMapHash +pub fn aya_bpf::maps::DevMapHash::from(t: T) -> T #[repr(transparent)] pub struct aya_bpf::maps::HashMap impl aya_bpf::maps::hash_map::HashMap pub unsafe fn aya_bpf::maps::hash_map::HashMap::get(&self, key: &K) -> core::option::Option<&V> @@ -1014,6 +1202,33 @@ impl core::borrow::BorrowMut for aya_bpf::maps::stack_trace::StackTrace wh pub fn aya_bpf::maps::stack_trace::StackTrace::borrow_mut(&mut self) -> &mut T impl core::convert::From for aya_bpf::maps::stack_trace::StackTrace pub fn aya_bpf::maps::stack_trace::StackTrace::from(t: T) -> T +#[repr(transparent)] pub struct aya_bpf::maps::XskMap +impl aya_bpf::maps::XskMap +pub fn aya_bpf::maps::XskMap::get(&self, index: u32) -> core::option::Option +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) -> core::result::Result +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 +impl core::marker::Unpin for aya_bpf::maps::XskMap +impl !core::panic::unwind_safe::RefUnwindSafe for aya_bpf::maps::XskMap +impl core::panic::unwind_safe::UnwindSafe for aya_bpf::maps::XskMap +impl core::convert::Into for aya_bpf::maps::XskMap where U: core::convert::From +pub fn aya_bpf::maps::XskMap::into(self) -> U +impl core::convert::TryFrom for aya_bpf::maps::XskMap where U: core::convert::Into +pub type aya_bpf::maps::XskMap::Error = core::convert::Infallible +pub fn aya_bpf::maps::XskMap::try_from(value: U) -> core::result::Result>::Error> +impl core::convert::TryInto for aya_bpf::maps::XskMap where U: core::convert::TryFrom +pub type aya_bpf::maps::XskMap::Error = >::Error +pub fn aya_bpf::maps::XskMap::try_into(self) -> core::result::Result>::Error> +impl core::any::Any for aya_bpf::maps::XskMap where T: 'static + core::marker::Sized +pub fn aya_bpf::maps::XskMap::type_id(&self) -> core::any::TypeId +impl core::borrow::Borrow for aya_bpf::maps::XskMap where T: core::marker::Sized +pub fn aya_bpf::maps::XskMap::borrow(&self) -> &T +impl core::borrow::BorrowMut for aya_bpf::maps::XskMap where T: core::marker::Sized +pub fn aya_bpf::maps::XskMap::borrow_mut(&mut self) -> &mut T +impl core::convert::From for aya_bpf::maps::XskMap +pub fn aya_bpf::maps::XskMap::from(t: T) -> T pub mod aya_bpf::programs pub mod aya_bpf::programs::device pub struct aya_bpf::programs::device::DeviceContext diff --git a/xtask/public-api/aya-obj.txt b/xtask/public-api/aya-obj.txt index c6dea1ba..5c361372 100644 --- a/xtask/public-api/aya-obj.txt +++ b/xtask/public-api/aya-obj.txt @@ -1342,6 +1342,8 @@ impl core::convert::From aya_obj::generated::bpf_attach_type impl core::convert::From for aya_obj::generated::bpf_attach_type pub fn aya_obj::generated::bpf_attach_type::from(s: aya_obj::programs::cgroup_sockopt::CgroupSockoptAttachType) -> aya_obj::generated::bpf_attach_type +impl core::convert::From for aya_obj::generated::bpf_attach_type +pub fn aya_obj::generated::bpf_attach_type::from(value: aya_obj::programs::xdp::XdpAttachType) -> Self impl core::clone::Clone for aya_obj::generated::bpf_attach_type pub fn aya_obj::generated::bpf_attach_type::clone(&self) -> aya_obj::generated::bpf_attach_type impl core::cmp::Eq for aya_obj::generated::bpf_attach_type @@ -5411,6 +5413,7 @@ pub fn aya_obj::maps::Map::pinning(&self) -> aya_obj::maps::PinningType pub fn aya_obj::maps::Map::section_index(&self) -> usize pub fn aya_obj::maps::Map::section_kind(&self) -> aya_obj::BpfSectionKind pub fn aya_obj::maps::Map::set_max_entries(&mut self, v: u32) +pub fn aya_obj::maps::Map::set_value_size(&mut self, size: u32) pub fn aya_obj::maps::Map::symbol_index(&self) -> core::option::Option pub fn aya_obj::maps::Map::value_size(&self) -> u32 impl core::clone::Clone for aya_obj::maps::Map @@ -5848,6 +5851,7 @@ pub aya_obj::obj::ProgramSection::UProbe::sleepable: bool pub aya_obj::obj::ProgramSection::URetProbe pub aya_obj::obj::ProgramSection::URetProbe::sleepable: bool pub aya_obj::obj::ProgramSection::Xdp +pub aya_obj::obj::ProgramSection::Xdp::attach_type: aya_obj::programs::xdp::XdpAttachType pub aya_obj::obj::ProgramSection::Xdp::frags: bool impl core::str::traits::FromStr for aya_obj::ProgramSection pub type aya_obj::ProgramSection::Err = aya_obj::ParseError @@ -5889,6 +5893,8 @@ pub fn aya_obj::Features::bpf_name(&self) -> bool pub fn aya_obj::Features::bpf_perf_link(&self) -> bool pub fn aya_obj::Features::bpf_probe_read_kernel(&self) -> bool pub fn aya_obj::Features::btf(&self) -> core::option::Option<&aya_obj::btf::BtfFeatures> +pub fn aya_obj::Features::cpumap_prog_id(&self) -> bool +pub fn aya_obj::Features::devmap_prog_id(&self) -> bool impl core::default::Default for aya_obj::Features pub fn aya_obj::Features::default() -> aya_obj::Features impl core::fmt::Debug for aya_obj::Features @@ -6164,6 +6170,43 @@ impl core::borrow::BorrowMut for aya_obj::programs::cgroup_sockopt::Cgroup pub fn aya_obj::programs::cgroup_sockopt::CgroupSockoptAttachType::borrow_mut(&mut self) -> &mut T impl core::convert::From for aya_obj::programs::cgroup_sockopt::CgroupSockoptAttachType pub fn aya_obj::programs::cgroup_sockopt::CgroupSockoptAttachType::from(t: T) -> T +pub mod aya_obj::programs::xdp +pub enum aya_obj::programs::xdp::XdpAttachType +pub aya_obj::programs::xdp::XdpAttachType::CpuMap +pub aya_obj::programs::xdp::XdpAttachType::DevMap +pub aya_obj::programs::xdp::XdpAttachType::Interface +impl core::convert::From for aya_obj::generated::bpf_attach_type +pub fn aya_obj::generated::bpf_attach_type::from(value: aya_obj::programs::xdp::XdpAttachType) -> Self +impl core::clone::Clone for aya_obj::programs::xdp::XdpAttachType +pub fn aya_obj::programs::xdp::XdpAttachType::clone(&self) -> aya_obj::programs::xdp::XdpAttachType +impl core::fmt::Debug for aya_obj::programs::xdp::XdpAttachType +pub fn aya_obj::programs::xdp::XdpAttachType::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +impl core::marker::Copy for aya_obj::programs::xdp::XdpAttachType +impl core::marker::Send for aya_obj::programs::xdp::XdpAttachType +impl core::marker::Sync for aya_obj::programs::xdp::XdpAttachType +impl core::marker::Unpin for aya_obj::programs::xdp::XdpAttachType +impl core::panic::unwind_safe::RefUnwindSafe for aya_obj::programs::xdp::XdpAttachType +impl core::panic::unwind_safe::UnwindSafe for aya_obj::programs::xdp::XdpAttachType +impl core::convert::Into for aya_obj::programs::xdp::XdpAttachType where U: core::convert::From +pub fn aya_obj::programs::xdp::XdpAttachType::into(self) -> U +impl core::convert::TryFrom for aya_obj::programs::xdp::XdpAttachType where U: core::convert::Into +pub type aya_obj::programs::xdp::XdpAttachType::Error = core::convert::Infallible +pub fn aya_obj::programs::xdp::XdpAttachType::try_from(value: U) -> core::result::Result>::Error> +impl core::convert::TryInto for aya_obj::programs::xdp::XdpAttachType where U: core::convert::TryFrom +pub type aya_obj::programs::xdp::XdpAttachType::Error = >::Error +pub fn aya_obj::programs::xdp::XdpAttachType::try_into(self) -> core::result::Result>::Error> +impl alloc::borrow::ToOwned for aya_obj::programs::xdp::XdpAttachType where T: core::clone::Clone +pub type aya_obj::programs::xdp::XdpAttachType::Owned = T +pub fn aya_obj::programs::xdp::XdpAttachType::clone_into(&self, target: &mut T) +pub fn aya_obj::programs::xdp::XdpAttachType::to_owned(&self) -> T +impl core::any::Any for aya_obj::programs::xdp::XdpAttachType where T: 'static + core::marker::Sized +pub fn aya_obj::programs::xdp::XdpAttachType::type_id(&self) -> core::any::TypeId +impl core::borrow::Borrow for aya_obj::programs::xdp::XdpAttachType where T: core::marker::Sized +pub fn aya_obj::programs::xdp::XdpAttachType::borrow(&self) -> &T +impl core::borrow::BorrowMut for aya_obj::programs::xdp::XdpAttachType where T: core::marker::Sized +pub fn aya_obj::programs::xdp::XdpAttachType::borrow_mut(&mut self) -> &mut T +impl core::convert::From for aya_obj::programs::xdp::XdpAttachType +pub fn aya_obj::programs::xdp::XdpAttachType::from(t: T) -> T pub enum aya_obj::programs::CgroupSockAddrAttachType pub aya_obj::programs::CgroupSockAddrAttachType::Bind4 pub aya_obj::programs::CgroupSockAddrAttachType::Bind6 @@ -6283,6 +6326,42 @@ impl core::borrow::BorrowMut for aya_obj::programs::cgroup_sockopt::Cgroup pub fn aya_obj::programs::cgroup_sockopt::CgroupSockoptAttachType::borrow_mut(&mut self) -> &mut T impl core::convert::From for aya_obj::programs::cgroup_sockopt::CgroupSockoptAttachType pub fn aya_obj::programs::cgroup_sockopt::CgroupSockoptAttachType::from(t: T) -> T +pub enum aya_obj::programs::XdpAttachType +pub aya_obj::programs::XdpAttachType::CpuMap +pub aya_obj::programs::XdpAttachType::DevMap +pub aya_obj::programs::XdpAttachType::Interface +impl core::convert::From for aya_obj::generated::bpf_attach_type +pub fn aya_obj::generated::bpf_attach_type::from(value: aya_obj::programs::xdp::XdpAttachType) -> Self +impl core::clone::Clone for aya_obj::programs::xdp::XdpAttachType +pub fn aya_obj::programs::xdp::XdpAttachType::clone(&self) -> aya_obj::programs::xdp::XdpAttachType +impl core::fmt::Debug for aya_obj::programs::xdp::XdpAttachType +pub fn aya_obj::programs::xdp::XdpAttachType::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +impl core::marker::Copy for aya_obj::programs::xdp::XdpAttachType +impl core::marker::Send for aya_obj::programs::xdp::XdpAttachType +impl core::marker::Sync for aya_obj::programs::xdp::XdpAttachType +impl core::marker::Unpin for aya_obj::programs::xdp::XdpAttachType +impl core::panic::unwind_safe::RefUnwindSafe for aya_obj::programs::xdp::XdpAttachType +impl core::panic::unwind_safe::UnwindSafe for aya_obj::programs::xdp::XdpAttachType +impl core::convert::Into for aya_obj::programs::xdp::XdpAttachType where U: core::convert::From +pub fn aya_obj::programs::xdp::XdpAttachType::into(self) -> U +impl core::convert::TryFrom for aya_obj::programs::xdp::XdpAttachType where U: core::convert::Into +pub type aya_obj::programs::xdp::XdpAttachType::Error = core::convert::Infallible +pub fn aya_obj::programs::xdp::XdpAttachType::try_from(value: U) -> core::result::Result>::Error> +impl core::convert::TryInto for aya_obj::programs::xdp::XdpAttachType where U: core::convert::TryFrom +pub type aya_obj::programs::xdp::XdpAttachType::Error = >::Error +pub fn aya_obj::programs::xdp::XdpAttachType::try_into(self) -> core::result::Result>::Error> +impl alloc::borrow::ToOwned for aya_obj::programs::xdp::XdpAttachType where T: core::clone::Clone +pub type aya_obj::programs::xdp::XdpAttachType::Owned = T +pub fn aya_obj::programs::xdp::XdpAttachType::clone_into(&self, target: &mut T) +pub fn aya_obj::programs::xdp::XdpAttachType::to_owned(&self) -> T +impl core::any::Any for aya_obj::programs::xdp::XdpAttachType where T: 'static + core::marker::Sized +pub fn aya_obj::programs::xdp::XdpAttachType::type_id(&self) -> core::any::TypeId +impl core::borrow::Borrow for aya_obj::programs::xdp::XdpAttachType where T: core::marker::Sized +pub fn aya_obj::programs::xdp::XdpAttachType::borrow(&self) -> &T +impl core::borrow::BorrowMut for aya_obj::programs::xdp::XdpAttachType where T: core::marker::Sized +pub fn aya_obj::programs::xdp::XdpAttachType::borrow_mut(&mut self) -> &mut T +impl core::convert::From for aya_obj::programs::xdp::XdpAttachType +pub fn aya_obj::programs::xdp::XdpAttachType::from(t: T) -> T pub mod aya_obj::relocation pub enum aya_obj::relocation::RelocationError pub aya_obj::relocation::RelocationError::InvalidRelocationOffset @@ -6420,6 +6499,7 @@ pub fn aya_obj::maps::Map::pinning(&self) -> aya_obj::maps::PinningType pub fn aya_obj::maps::Map::section_index(&self) -> usize pub fn aya_obj::maps::Map::section_kind(&self) -> aya_obj::BpfSectionKind pub fn aya_obj::maps::Map::set_max_entries(&mut self, v: u32) +pub fn aya_obj::maps::Map::set_value_size(&mut self, size: u32) pub fn aya_obj::maps::Map::symbol_index(&self) -> core::option::Option pub fn aya_obj::maps::Map::value_size(&self) -> u32 impl core::clone::Clone for aya_obj::maps::Map @@ -6560,6 +6640,7 @@ pub aya_obj::ProgramSection::UProbe::sleepable: bool pub aya_obj::ProgramSection::URetProbe pub aya_obj::ProgramSection::URetProbe::sleepable: bool pub aya_obj::ProgramSection::Xdp +pub aya_obj::ProgramSection::Xdp::attach_type: aya_obj::programs::xdp::XdpAttachType pub aya_obj::ProgramSection::Xdp::frags: bool impl core::str::traits::FromStr for aya_obj::ProgramSection pub type aya_obj::ProgramSection::Err = aya_obj::ParseError @@ -6601,6 +6682,8 @@ pub fn aya_obj::Features::bpf_name(&self) -> bool pub fn aya_obj::Features::bpf_perf_link(&self) -> bool pub fn aya_obj::Features::bpf_probe_read_kernel(&self) -> bool pub fn aya_obj::Features::btf(&self) -> core::option::Option<&aya_obj::btf::BtfFeatures> +pub fn aya_obj::Features::cpumap_prog_id(&self) -> bool +pub fn aya_obj::Features::devmap_prog_id(&self) -> bool impl core::default::Default for aya_obj::Features pub fn aya_obj::Features::default() -> aya_obj::Features impl core::fmt::Debug for aya_obj::Features diff --git a/xtask/public-api/aya.txt b/xtask/public-api/aya.txt index 8c1b0b9c..86221498 100644 --- a/xtask/public-api/aya.txt +++ b/xtask/public-api/aya.txt @@ -795,9 +795,194 @@ impl core::borrow::BorrowMut for aya::maps::stack_trace::StackTraceMap pub fn aya::maps::stack_trace::StackTraceMap::borrow_mut(&mut self) -> &mut T impl core::convert::From for aya::maps::stack_trace::StackTraceMap pub fn aya::maps::stack_trace::StackTraceMap::from(t: T) -> T +pub mod aya::maps::xdp +pub enum aya::maps::xdp::XdpMapError +pub aya::maps::xdp::XdpMapError::ChainedProgramNotSupported +pub aya::maps::xdp::XdpMapError::MapError(aya::maps::MapError) +impl core::convert::From for aya::maps::xdp::XdpMapError +pub fn aya::maps::xdp::XdpMapError::from(source: aya::maps::MapError) -> Self +impl core::error::Error for aya::maps::xdp::XdpMapError +pub fn aya::maps::xdp::XdpMapError::source(&self) -> core::option::Option<&(dyn core::error::Error + 'static)> +impl core::fmt::Display for aya::maps::xdp::XdpMapError +pub fn aya::maps::xdp::XdpMapError::fmt(&self, __formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +impl core::fmt::Debug for aya::maps::xdp::XdpMapError +pub fn aya::maps::xdp::XdpMapError::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +impl core::marker::Send for aya::maps::xdp::XdpMapError +impl core::marker::Sync for aya::maps::xdp::XdpMapError +impl core::marker::Unpin for aya::maps::xdp::XdpMapError +impl !core::panic::unwind_safe::RefUnwindSafe for aya::maps::xdp::XdpMapError +impl !core::panic::unwind_safe::UnwindSafe for aya::maps::xdp::XdpMapError +impl core::convert::Into for aya::maps::xdp::XdpMapError where U: core::convert::From +pub fn aya::maps::xdp::XdpMapError::into(self) -> U +impl core::convert::TryFrom for aya::maps::xdp::XdpMapError where U: core::convert::Into +pub type aya::maps::xdp::XdpMapError::Error = core::convert::Infallible +pub fn aya::maps::xdp::XdpMapError::try_from(value: U) -> core::result::Result>::Error> +impl core::convert::TryInto for aya::maps::xdp::XdpMapError where U: core::convert::TryFrom +pub type aya::maps::xdp::XdpMapError::Error = >::Error +pub fn aya::maps::xdp::XdpMapError::try_into(self) -> core::result::Result>::Error> +impl alloc::string::ToString for aya::maps::xdp::XdpMapError where T: core::fmt::Display + core::marker::Sized +pub fn aya::maps::xdp::XdpMapError::to_string(&self) -> alloc::string::String +impl core::any::Any for aya::maps::xdp::XdpMapError where T: 'static + core::marker::Sized +pub fn aya::maps::xdp::XdpMapError::type_id(&self) -> core::any::TypeId +impl core::borrow::Borrow for aya::maps::xdp::XdpMapError where T: core::marker::Sized +pub fn aya::maps::xdp::XdpMapError::borrow(&self) -> &T +impl core::borrow::BorrowMut for aya::maps::xdp::XdpMapError where T: core::marker::Sized +pub fn aya::maps::xdp::XdpMapError::borrow_mut(&mut self) -> &mut T +impl core::convert::From for aya::maps::xdp::XdpMapError +pub fn aya::maps::xdp::XdpMapError::from(t: T) -> T +pub struct aya::maps::xdp::CpuMap +impl> aya::maps::CpuMap +pub fn aya::maps::CpuMap::get(&self, cpu_index: u32, flags: u64) -> core::result::Result +pub fn aya::maps::CpuMap::iter(&self) -> impl core::iter::traits::iterator::Iterator> + '_ +pub fn aya::maps::CpuMap::len(&self) -> u32 +impl> aya::maps::CpuMap +pub fn aya::maps::CpuMap::set(&mut self, cpu_index: u32, queue_size: u32, program: core::option::Option<&aya::programs::ProgramFd>, flags: u64) -> core::result::Result<(), aya::maps::xdp::XdpMapError> +impl core::convert::TryFrom for aya::maps::CpuMap +pub type aya::maps::CpuMap::Error = aya::maps::MapError +pub fn aya::maps::CpuMap::try_from(map: aya::maps::Map) -> core::result::Result +impl<'a> core::convert::TryFrom<&'a aya::maps::Map> for aya::maps::CpuMap<&'a aya::maps::MapData> +pub type aya::maps::CpuMap<&'a aya::maps::MapData>::Error = aya::maps::MapError +pub fn aya::maps::CpuMap<&'a aya::maps::MapData>::try_from(map: &'a aya::maps::Map) -> core::result::Result +impl<'a> core::convert::TryFrom<&'a mut aya::maps::Map> for aya::maps::CpuMap<&'a mut aya::maps::MapData> +pub type aya::maps::CpuMap<&'a mut aya::maps::MapData>::Error = aya::maps::MapError +pub fn aya::maps::CpuMap<&'a mut aya::maps::MapData>::try_from(map: &'a mut aya::maps::Map) -> core::result::Result +impl core::marker::Send for aya::maps::CpuMap where T: core::marker::Send +impl core::marker::Sync for aya::maps::CpuMap where T: core::marker::Sync +impl core::marker::Unpin for aya::maps::CpuMap where T: core::marker::Unpin +impl core::panic::unwind_safe::RefUnwindSafe for aya::maps::CpuMap where T: core::panic::unwind_safe::RefUnwindSafe +impl core::panic::unwind_safe::UnwindSafe for aya::maps::CpuMap where T: core::panic::unwind_safe::UnwindSafe +impl core::convert::Into for aya::maps::CpuMap where U: core::convert::From +pub fn aya::maps::CpuMap::into(self) -> U +impl core::convert::TryFrom for aya::maps::CpuMap where U: core::convert::Into +pub type aya::maps::CpuMap::Error = core::convert::Infallible +pub fn aya::maps::CpuMap::try_from(value: U) -> core::result::Result>::Error> +impl core::convert::TryInto for aya::maps::CpuMap where U: core::convert::TryFrom +pub type aya::maps::CpuMap::Error = >::Error +pub fn aya::maps::CpuMap::try_into(self) -> core::result::Result>::Error> +impl core::any::Any for aya::maps::CpuMap where T: 'static + core::marker::Sized +pub fn aya::maps::CpuMap::type_id(&self) -> core::any::TypeId +impl core::borrow::Borrow for aya::maps::CpuMap where T: core::marker::Sized +pub fn aya::maps::CpuMap::borrow(&self) -> &T +impl core::borrow::BorrowMut for aya::maps::CpuMap where T: core::marker::Sized +pub fn aya::maps::CpuMap::borrow_mut(&mut self) -> &mut T +impl core::convert::From for aya::maps::CpuMap +pub fn aya::maps::CpuMap::from(t: T) -> T +pub struct aya::maps::xdp::DevMap +impl> aya::maps::DevMap +pub fn aya::maps::DevMap::get(&self, index: u32, flags: u64) -> core::result::Result +pub fn aya::maps::DevMap::iter(&self) -> impl core::iter::traits::iterator::Iterator> + '_ +pub fn aya::maps::DevMap::len(&self) -> u32 +impl> aya::maps::DevMap +pub fn aya::maps::DevMap::set(&mut self, index: u32, target_if_index: u32, program: core::option::Option<&aya::programs::ProgramFd>, flags: u64) -> core::result::Result<(), aya::maps::xdp::XdpMapError> +impl core::convert::TryFrom for aya::maps::DevMap +pub type aya::maps::DevMap::Error = aya::maps::MapError +pub fn aya::maps::DevMap::try_from(map: aya::maps::Map) -> core::result::Result +impl<'a> core::convert::TryFrom<&'a aya::maps::Map> for aya::maps::DevMap<&'a aya::maps::MapData> +pub type aya::maps::DevMap<&'a aya::maps::MapData>::Error = aya::maps::MapError +pub fn aya::maps::DevMap<&'a aya::maps::MapData>::try_from(map: &'a aya::maps::Map) -> core::result::Result +impl<'a> core::convert::TryFrom<&'a mut aya::maps::Map> for aya::maps::DevMap<&'a mut aya::maps::MapData> +pub type aya::maps::DevMap<&'a mut aya::maps::MapData>::Error = aya::maps::MapError +pub fn aya::maps::DevMap<&'a mut aya::maps::MapData>::try_from(map: &'a mut aya::maps::Map) -> core::result::Result +impl core::marker::Send for aya::maps::DevMap where T: core::marker::Send +impl core::marker::Sync for aya::maps::DevMap where T: core::marker::Sync +impl core::marker::Unpin for aya::maps::DevMap where T: core::marker::Unpin +impl core::panic::unwind_safe::RefUnwindSafe for aya::maps::DevMap where T: core::panic::unwind_safe::RefUnwindSafe +impl core::panic::unwind_safe::UnwindSafe for aya::maps::DevMap where T: core::panic::unwind_safe::UnwindSafe +impl core::convert::Into for aya::maps::DevMap where U: core::convert::From +pub fn aya::maps::DevMap::into(self) -> U +impl core::convert::TryFrom for aya::maps::DevMap where U: core::convert::Into +pub type aya::maps::DevMap::Error = core::convert::Infallible +pub fn aya::maps::DevMap::try_from(value: U) -> core::result::Result>::Error> +impl core::convert::TryInto for aya::maps::DevMap where U: core::convert::TryFrom +pub type aya::maps::DevMap::Error = >::Error +pub fn aya::maps::DevMap::try_into(self) -> core::result::Result>::Error> +impl core::any::Any for aya::maps::DevMap where T: 'static + core::marker::Sized +pub fn aya::maps::DevMap::type_id(&self) -> core::any::TypeId +impl core::borrow::Borrow for aya::maps::DevMap where T: core::marker::Sized +pub fn aya::maps::DevMap::borrow(&self) -> &T +impl core::borrow::BorrowMut for aya::maps::DevMap where T: core::marker::Sized +pub fn aya::maps::DevMap::borrow_mut(&mut self) -> &mut T +impl core::convert::From for aya::maps::DevMap +pub fn aya::maps::DevMap::from(t: T) -> T +pub struct aya::maps::xdp::DevMapHash +impl> aya::maps::DevMapHash +pub fn aya::maps::DevMapHash::get(&self, key: u32, flags: u64) -> core::result::Result +pub fn aya::maps::DevMapHash::iter(&self) -> aya::maps::MapIter<'_, u32, DevMapValue, Self> +pub fn aya::maps::DevMapHash::keys(&self) -> aya::maps::MapKeys<'_, u32> +impl> aya::maps::DevMapHash +pub fn aya::maps::DevMapHash::insert(&mut self, key: u32, target_if_index: u32, program: core::option::Option<&aya::programs::ProgramFd>, flags: u64) -> core::result::Result<(), aya::maps::xdp::XdpMapError> +pub fn aya::maps::DevMapHash::remove(&mut self, key: u32) -> core::result::Result<(), aya::maps::MapError> +impl core::convert::TryFrom for aya::maps::DevMapHash +pub type aya::maps::DevMapHash::Error = aya::maps::MapError +pub fn aya::maps::DevMapHash::try_from(map: aya::maps::Map) -> core::result::Result +impl<'a> core::convert::TryFrom<&'a aya::maps::Map> for aya::maps::DevMapHash<&'a aya::maps::MapData> +pub type aya::maps::DevMapHash<&'a aya::maps::MapData>::Error = aya::maps::MapError +pub fn aya::maps::DevMapHash<&'a aya::maps::MapData>::try_from(map: &'a aya::maps::Map) -> core::result::Result +impl<'a> core::convert::TryFrom<&'a mut aya::maps::Map> for aya::maps::DevMapHash<&'a mut aya::maps::MapData> +pub type aya::maps::DevMapHash<&'a mut aya::maps::MapData>::Error = aya::maps::MapError +pub fn aya::maps::DevMapHash<&'a mut aya::maps::MapData>::try_from(map: &'a mut aya::maps::Map) -> core::result::Result +impl core::marker::Send for aya::maps::DevMapHash where T: core::marker::Send +impl core::marker::Sync for aya::maps::DevMapHash where T: core::marker::Sync +impl core::marker::Unpin for aya::maps::DevMapHash where T: core::marker::Unpin +impl core::panic::unwind_safe::RefUnwindSafe for aya::maps::DevMapHash where T: core::panic::unwind_safe::RefUnwindSafe +impl core::panic::unwind_safe::UnwindSafe for aya::maps::DevMapHash where T: core::panic::unwind_safe::UnwindSafe +impl core::convert::Into for aya::maps::DevMapHash where U: core::convert::From +pub fn aya::maps::DevMapHash::into(self) -> U +impl core::convert::TryFrom for aya::maps::DevMapHash where U: core::convert::Into +pub type aya::maps::DevMapHash::Error = core::convert::Infallible +pub fn aya::maps::DevMapHash::try_from(value: U) -> core::result::Result>::Error> +impl core::convert::TryInto for aya::maps::DevMapHash where U: core::convert::TryFrom +pub type aya::maps::DevMapHash::Error = >::Error +pub fn aya::maps::DevMapHash::try_into(self) -> core::result::Result>::Error> +impl core::any::Any for aya::maps::DevMapHash where T: 'static + core::marker::Sized +pub fn aya::maps::DevMapHash::type_id(&self) -> core::any::TypeId +impl core::borrow::Borrow for aya::maps::DevMapHash where T: core::marker::Sized +pub fn aya::maps::DevMapHash::borrow(&self) -> &T +impl core::borrow::BorrowMut for aya::maps::DevMapHash where T: core::marker::Sized +pub fn aya::maps::DevMapHash::borrow_mut(&mut self) -> &mut T +impl core::convert::From for aya::maps::DevMapHash +pub fn aya::maps::DevMapHash::from(t: T) -> T +pub struct aya::maps::xdp::XskMap +impl> aya::maps::XskMap +pub fn aya::maps::XskMap::len(&self) -> u32 +impl> aya::maps::XskMap +pub fn aya::maps::XskMap::set(&mut self, index: u32, socket_fd: impl std::os::fd::raw::AsRawFd, flags: u64) -> core::result::Result<(), aya::maps::MapError> +impl core::convert::TryFrom for aya::maps::XskMap +pub type aya::maps::XskMap::Error = aya::maps::MapError +pub fn aya::maps::XskMap::try_from(map: aya::maps::Map) -> core::result::Result +impl<'a> core::convert::TryFrom<&'a aya::maps::Map> for aya::maps::XskMap<&'a aya::maps::MapData> +pub type aya::maps::XskMap<&'a aya::maps::MapData>::Error = aya::maps::MapError +pub fn aya::maps::XskMap<&'a aya::maps::MapData>::try_from(map: &'a aya::maps::Map) -> core::result::Result +impl<'a> core::convert::TryFrom<&'a mut aya::maps::Map> for aya::maps::XskMap<&'a mut aya::maps::MapData> +pub type aya::maps::XskMap<&'a mut aya::maps::MapData>::Error = aya::maps::MapError +pub fn aya::maps::XskMap<&'a mut aya::maps::MapData>::try_from(map: &'a mut aya::maps::Map) -> core::result::Result +impl core::marker::Send for aya::maps::XskMap where T: core::marker::Send +impl core::marker::Sync for aya::maps::XskMap where T: core::marker::Sync +impl core::marker::Unpin for aya::maps::XskMap where T: core::marker::Unpin +impl core::panic::unwind_safe::RefUnwindSafe for aya::maps::XskMap where T: core::panic::unwind_safe::RefUnwindSafe +impl core::panic::unwind_safe::UnwindSafe for aya::maps::XskMap where T: core::panic::unwind_safe::UnwindSafe +impl core::convert::Into for aya::maps::XskMap where U: core::convert::From +pub fn aya::maps::XskMap::into(self) -> U +impl core::convert::TryFrom for aya::maps::XskMap where U: core::convert::Into +pub type aya::maps::XskMap::Error = core::convert::Infallible +pub fn aya::maps::XskMap::try_from(value: U) -> core::result::Result>::Error> +impl core::convert::TryInto for aya::maps::XskMap where U: core::convert::TryFrom +pub type aya::maps::XskMap::Error = >::Error +pub fn aya::maps::XskMap::try_into(self) -> core::result::Result>::Error> +impl core::any::Any for aya::maps::XskMap where T: 'static + core::marker::Sized +pub fn aya::maps::XskMap::type_id(&self) -> core::any::TypeId +impl core::borrow::Borrow for aya::maps::XskMap where T: core::marker::Sized +pub fn aya::maps::XskMap::borrow(&self) -> &T +impl core::borrow::BorrowMut for aya::maps::XskMap where T: core::marker::Sized +pub fn aya::maps::XskMap::borrow_mut(&mut self) -> &mut T +impl core::convert::From for aya::maps::XskMap +pub fn aya::maps::XskMap::from(t: T) -> T pub enum aya::maps::Map pub aya::maps::Map::Array(aya::maps::MapData) pub aya::maps::Map::BloomFilter(aya::maps::MapData) +pub aya::maps::Map::CpuMap(aya::maps::MapData) +pub aya::maps::Map::DevMap(aya::maps::MapData) +pub aya::maps::Map::DevMapHash(aya::maps::MapData) pub aya::maps::Map::HashMap(aya::maps::MapData) pub aya::maps::Map::LpmTrie(aya::maps::MapData) pub aya::maps::Map::LruHashMap(aya::maps::MapData) @@ -812,12 +997,25 @@ pub aya::maps::Map::SockMap(aya::maps::MapData) pub aya::maps::Map::Stack(aya::maps::MapData) pub aya::maps::Map::StackTraceMap(aya::maps::MapData) pub aya::maps::Map::Unsupported(aya::maps::MapData) +pub aya::maps::Map::XskMap(aya::maps::MapData) +impl core::convert::TryFrom for aya::maps::CpuMap +pub type aya::maps::CpuMap::Error = aya::maps::MapError +pub fn aya::maps::CpuMap::try_from(map: aya::maps::Map) -> core::result::Result +impl core::convert::TryFrom for aya::maps::DevMap +pub type aya::maps::DevMap::Error = aya::maps::MapError +pub fn aya::maps::DevMap::try_from(map: aya::maps::Map) -> core::result::Result +impl core::convert::TryFrom for aya::maps::DevMapHash +pub type aya::maps::DevMapHash::Error = aya::maps::MapError +pub fn aya::maps::DevMapHash::try_from(map: aya::maps::Map) -> core::result::Result impl core::convert::TryFrom for aya::maps::ProgramArray pub type aya::maps::ProgramArray::Error = aya::maps::MapError pub fn aya::maps::ProgramArray::try_from(map: aya::maps::Map) -> core::result::Result impl core::convert::TryFrom for aya::maps::SockMap pub type aya::maps::SockMap::Error = aya::maps::MapError pub fn aya::maps::SockMap::try_from(map: aya::maps::Map) -> core::result::Result +impl core::convert::TryFrom for aya::maps::XskMap +pub type aya::maps::XskMap::Error = aya::maps::MapError +pub fn aya::maps::XskMap::try_from(map: aya::maps::Map) -> core::result::Result impl core::convert::TryFrom for aya::maps::perf::AsyncPerfEventArray pub type aya::maps::perf::AsyncPerfEventArray::Error = aya::maps::MapError pub fn aya::maps::perf::AsyncPerfEventArray::try_from(map: aya::maps::Map) -> core::result::Result @@ -881,12 +1079,24 @@ pub fn aya::maps::queue::Queue<&'a mut aya::maps::MapData, V>::try_from(map: &'a impl<'a, V: aya::Pod> core::convert::TryFrom<&'a mut aya::maps::Map> for aya::maps::stack::Stack<&'a mut aya::maps::MapData, V> pub type aya::maps::stack::Stack<&'a mut aya::maps::MapData, V>::Error = aya::maps::MapError pub fn aya::maps::stack::Stack<&'a mut aya::maps::MapData, V>::try_from(map: &'a mut aya::maps::Map) -> core::result::Result +impl<'a> core::convert::TryFrom<&'a aya::maps::Map> for aya::maps::CpuMap<&'a aya::maps::MapData> +pub type aya::maps::CpuMap<&'a aya::maps::MapData>::Error = aya::maps::MapError +pub fn aya::maps::CpuMap<&'a aya::maps::MapData>::try_from(map: &'a aya::maps::Map) -> core::result::Result +impl<'a> core::convert::TryFrom<&'a aya::maps::Map> for aya::maps::DevMap<&'a aya::maps::MapData> +pub type aya::maps::DevMap<&'a aya::maps::MapData>::Error = aya::maps::MapError +pub fn aya::maps::DevMap<&'a aya::maps::MapData>::try_from(map: &'a aya::maps::Map) -> core::result::Result +impl<'a> core::convert::TryFrom<&'a aya::maps::Map> for aya::maps::DevMapHash<&'a aya::maps::MapData> +pub type aya::maps::DevMapHash<&'a aya::maps::MapData>::Error = aya::maps::MapError +pub fn aya::maps::DevMapHash<&'a aya::maps::MapData>::try_from(map: &'a aya::maps::Map) -> core::result::Result impl<'a> core::convert::TryFrom<&'a aya::maps::Map> for aya::maps::ProgramArray<&'a aya::maps::MapData> pub type aya::maps::ProgramArray<&'a aya::maps::MapData>::Error = aya::maps::MapError pub fn aya::maps::ProgramArray<&'a aya::maps::MapData>::try_from(map: &'a aya::maps::Map) -> core::result::Result impl<'a> core::convert::TryFrom<&'a aya::maps::Map> for aya::maps::SockMap<&'a aya::maps::MapData> pub type aya::maps::SockMap<&'a aya::maps::MapData>::Error = aya::maps::MapError pub fn aya::maps::SockMap<&'a aya::maps::MapData>::try_from(map: &'a aya::maps::Map) -> core::result::Result +impl<'a> core::convert::TryFrom<&'a aya::maps::Map> for aya::maps::XskMap<&'a aya::maps::MapData> +pub type aya::maps::XskMap<&'a aya::maps::MapData>::Error = aya::maps::MapError +pub fn aya::maps::XskMap<&'a aya::maps::MapData>::try_from(map: &'a aya::maps::Map) -> core::result::Result impl<'a> core::convert::TryFrom<&'a aya::maps::Map> for aya::maps::perf::AsyncPerfEventArray<&'a aya::maps::MapData> pub type aya::maps::perf::AsyncPerfEventArray<&'a aya::maps::MapData>::Error = aya::maps::MapError pub fn aya::maps::perf::AsyncPerfEventArray<&'a aya::maps::MapData>::try_from(map: &'a aya::maps::Map) -> core::result::Result @@ -896,12 +1106,24 @@ pub fn aya::maps::perf::PerfEventArray<&'a aya::maps::MapData>::try_from(map: &' impl<'a> core::convert::TryFrom<&'a aya::maps::Map> for aya::maps::stack_trace::StackTraceMap<&'a aya::maps::MapData> pub type aya::maps::stack_trace::StackTraceMap<&'a aya::maps::MapData>::Error = aya::maps::MapError pub fn aya::maps::stack_trace::StackTraceMap<&'a aya::maps::MapData>::try_from(map: &'a aya::maps::Map) -> core::result::Result +impl<'a> core::convert::TryFrom<&'a mut aya::maps::Map> for aya::maps::CpuMap<&'a mut aya::maps::MapData> +pub type aya::maps::CpuMap<&'a mut aya::maps::MapData>::Error = aya::maps::MapError +pub fn aya::maps::CpuMap<&'a mut aya::maps::MapData>::try_from(map: &'a mut aya::maps::Map) -> core::result::Result +impl<'a> core::convert::TryFrom<&'a mut aya::maps::Map> for aya::maps::DevMap<&'a mut aya::maps::MapData> +pub type aya::maps::DevMap<&'a mut aya::maps::MapData>::Error = aya::maps::MapError +pub fn aya::maps::DevMap<&'a mut aya::maps::MapData>::try_from(map: &'a mut aya::maps::Map) -> core::result::Result +impl<'a> core::convert::TryFrom<&'a mut aya::maps::Map> for aya::maps::DevMapHash<&'a mut aya::maps::MapData> +pub type aya::maps::DevMapHash<&'a mut aya::maps::MapData>::Error = aya::maps::MapError +pub fn aya::maps::DevMapHash<&'a mut aya::maps::MapData>::try_from(map: &'a mut aya::maps::Map) -> core::result::Result impl<'a> core::convert::TryFrom<&'a mut aya::maps::Map> for aya::maps::ProgramArray<&'a mut aya::maps::MapData> pub type aya::maps::ProgramArray<&'a mut aya::maps::MapData>::Error = aya::maps::MapError pub fn aya::maps::ProgramArray<&'a mut aya::maps::MapData>::try_from(map: &'a mut aya::maps::Map) -> core::result::Result impl<'a> core::convert::TryFrom<&'a mut aya::maps::Map> for aya::maps::SockMap<&'a mut aya::maps::MapData> pub type aya::maps::SockMap<&'a mut aya::maps::MapData>::Error = aya::maps::MapError pub fn aya::maps::SockMap<&'a mut aya::maps::MapData>::try_from(map: &'a mut aya::maps::Map) -> core::result::Result +impl<'a> core::convert::TryFrom<&'a mut aya::maps::Map> for aya::maps::XskMap<&'a mut aya::maps::MapData> +pub type aya::maps::XskMap<&'a mut aya::maps::MapData>::Error = aya::maps::MapError +pub fn aya::maps::XskMap<&'a mut aya::maps::MapData>::try_from(map: &'a mut aya::maps::Map) -> core::result::Result impl<'a> core::convert::TryFrom<&'a mut aya::maps::Map> for aya::maps::perf::AsyncPerfEventArray<&'a mut aya::maps::MapData> pub type aya::maps::perf::AsyncPerfEventArray<&'a mut aya::maps::MapData>::Error = aya::maps::MapError pub fn aya::maps::perf::AsyncPerfEventArray<&'a mut aya::maps::MapData>::try_from(map: &'a mut aya::maps::Map) -> core::result::Result @@ -984,12 +1206,15 @@ pub aya::maps::MapError::OutOfBounds::max_entries: u32 pub aya::maps::MapError::PinError pub aya::maps::MapError::PinError::error: aya::pin::PinError pub aya::maps::MapError::PinError::name: core::option::Option +pub aya::maps::MapError::ProgIdNotSupported pub aya::maps::MapError::ProgramNotLoaded pub aya::maps::MapError::SyscallError(crate::sys::SyscallError) pub aya::maps::MapError::Unsupported pub aya::maps::MapError::Unsupported::map_type: u32 impl core::convert::From for aya::BpfError pub fn aya::BpfError::from(source: aya::maps::MapError) -> Self +impl core::convert::From for aya::maps::xdp::XdpMapError +pub fn aya::maps::xdp::XdpMapError::from(source: aya::maps::MapError) -> Self impl core::convert::From for aya::programs::ProgramError pub fn aya::programs::ProgramError::from(source: aya::maps::MapError) -> Self impl core::error::Error for aya::maps::MapError @@ -1131,6 +1356,118 @@ impl core::borrow::BorrowMut for aya::maps::bloom_filter::BloomFilter::borrow_mut(&mut self) -> &mut T impl core::convert::From for aya::maps::bloom_filter::BloomFilter pub fn aya::maps::bloom_filter::BloomFilter::from(t: T) -> T +pub struct aya::maps::CpuMap +impl> aya::maps::CpuMap +pub fn aya::maps::CpuMap::get(&self, cpu_index: u32, flags: u64) -> core::result::Result +pub fn aya::maps::CpuMap::iter(&self) -> impl core::iter::traits::iterator::Iterator> + '_ +pub fn aya::maps::CpuMap::len(&self) -> u32 +impl> aya::maps::CpuMap +pub fn aya::maps::CpuMap::set(&mut self, cpu_index: u32, queue_size: u32, program: core::option::Option<&aya::programs::ProgramFd>, flags: u64) -> core::result::Result<(), aya::maps::xdp::XdpMapError> +impl core::convert::TryFrom for aya::maps::CpuMap +pub type aya::maps::CpuMap::Error = aya::maps::MapError +pub fn aya::maps::CpuMap::try_from(map: aya::maps::Map) -> core::result::Result +impl<'a> core::convert::TryFrom<&'a aya::maps::Map> for aya::maps::CpuMap<&'a aya::maps::MapData> +pub type aya::maps::CpuMap<&'a aya::maps::MapData>::Error = aya::maps::MapError +pub fn aya::maps::CpuMap<&'a aya::maps::MapData>::try_from(map: &'a aya::maps::Map) -> core::result::Result +impl<'a> core::convert::TryFrom<&'a mut aya::maps::Map> for aya::maps::CpuMap<&'a mut aya::maps::MapData> +pub type aya::maps::CpuMap<&'a mut aya::maps::MapData>::Error = aya::maps::MapError +pub fn aya::maps::CpuMap<&'a mut aya::maps::MapData>::try_from(map: &'a mut aya::maps::Map) -> core::result::Result +impl core::marker::Send for aya::maps::CpuMap where T: core::marker::Send +impl core::marker::Sync for aya::maps::CpuMap where T: core::marker::Sync +impl core::marker::Unpin for aya::maps::CpuMap where T: core::marker::Unpin +impl core::panic::unwind_safe::RefUnwindSafe for aya::maps::CpuMap where T: core::panic::unwind_safe::RefUnwindSafe +impl core::panic::unwind_safe::UnwindSafe for aya::maps::CpuMap where T: core::panic::unwind_safe::UnwindSafe +impl core::convert::Into for aya::maps::CpuMap where U: core::convert::From +pub fn aya::maps::CpuMap::into(self) -> U +impl core::convert::TryFrom for aya::maps::CpuMap where U: core::convert::Into +pub type aya::maps::CpuMap::Error = core::convert::Infallible +pub fn aya::maps::CpuMap::try_from(value: U) -> core::result::Result>::Error> +impl core::convert::TryInto for aya::maps::CpuMap where U: core::convert::TryFrom +pub type aya::maps::CpuMap::Error = >::Error +pub fn aya::maps::CpuMap::try_into(self) -> core::result::Result>::Error> +impl core::any::Any for aya::maps::CpuMap where T: 'static + core::marker::Sized +pub fn aya::maps::CpuMap::type_id(&self) -> core::any::TypeId +impl core::borrow::Borrow for aya::maps::CpuMap where T: core::marker::Sized +pub fn aya::maps::CpuMap::borrow(&self) -> &T +impl core::borrow::BorrowMut for aya::maps::CpuMap where T: core::marker::Sized +pub fn aya::maps::CpuMap::borrow_mut(&mut self) -> &mut T +impl core::convert::From for aya::maps::CpuMap +pub fn aya::maps::CpuMap::from(t: T) -> T +pub struct aya::maps::DevMap +impl> aya::maps::DevMap +pub fn aya::maps::DevMap::get(&self, index: u32, flags: u64) -> core::result::Result +pub fn aya::maps::DevMap::iter(&self) -> impl core::iter::traits::iterator::Iterator> + '_ +pub fn aya::maps::DevMap::len(&self) -> u32 +impl> aya::maps::DevMap +pub fn aya::maps::DevMap::set(&mut self, index: u32, target_if_index: u32, program: core::option::Option<&aya::programs::ProgramFd>, flags: u64) -> core::result::Result<(), aya::maps::xdp::XdpMapError> +impl core::convert::TryFrom for aya::maps::DevMap +pub type aya::maps::DevMap::Error = aya::maps::MapError +pub fn aya::maps::DevMap::try_from(map: aya::maps::Map) -> core::result::Result +impl<'a> core::convert::TryFrom<&'a aya::maps::Map> for aya::maps::DevMap<&'a aya::maps::MapData> +pub type aya::maps::DevMap<&'a aya::maps::MapData>::Error = aya::maps::MapError +pub fn aya::maps::DevMap<&'a aya::maps::MapData>::try_from(map: &'a aya::maps::Map) -> core::result::Result +impl<'a> core::convert::TryFrom<&'a mut aya::maps::Map> for aya::maps::DevMap<&'a mut aya::maps::MapData> +pub type aya::maps::DevMap<&'a mut aya::maps::MapData>::Error = aya::maps::MapError +pub fn aya::maps::DevMap<&'a mut aya::maps::MapData>::try_from(map: &'a mut aya::maps::Map) -> core::result::Result +impl core::marker::Send for aya::maps::DevMap where T: core::marker::Send +impl core::marker::Sync for aya::maps::DevMap where T: core::marker::Sync +impl core::marker::Unpin for aya::maps::DevMap where T: core::marker::Unpin +impl core::panic::unwind_safe::RefUnwindSafe for aya::maps::DevMap where T: core::panic::unwind_safe::RefUnwindSafe +impl core::panic::unwind_safe::UnwindSafe for aya::maps::DevMap where T: core::panic::unwind_safe::UnwindSafe +impl core::convert::Into for aya::maps::DevMap where U: core::convert::From +pub fn aya::maps::DevMap::into(self) -> U +impl core::convert::TryFrom for aya::maps::DevMap where U: core::convert::Into +pub type aya::maps::DevMap::Error = core::convert::Infallible +pub fn aya::maps::DevMap::try_from(value: U) -> core::result::Result>::Error> +impl core::convert::TryInto for aya::maps::DevMap where U: core::convert::TryFrom +pub type aya::maps::DevMap::Error = >::Error +pub fn aya::maps::DevMap::try_into(self) -> core::result::Result>::Error> +impl core::any::Any for aya::maps::DevMap where T: 'static + core::marker::Sized +pub fn aya::maps::DevMap::type_id(&self) -> core::any::TypeId +impl core::borrow::Borrow for aya::maps::DevMap where T: core::marker::Sized +pub fn aya::maps::DevMap::borrow(&self) -> &T +impl core::borrow::BorrowMut for aya::maps::DevMap where T: core::marker::Sized +pub fn aya::maps::DevMap::borrow_mut(&mut self) -> &mut T +impl core::convert::From for aya::maps::DevMap +pub fn aya::maps::DevMap::from(t: T) -> T +pub struct aya::maps::DevMapHash +impl> aya::maps::DevMapHash +pub fn aya::maps::DevMapHash::get(&self, key: u32, flags: u64) -> core::result::Result +pub fn aya::maps::DevMapHash::iter(&self) -> aya::maps::MapIter<'_, u32, DevMapValue, Self> +pub fn aya::maps::DevMapHash::keys(&self) -> aya::maps::MapKeys<'_, u32> +impl> aya::maps::DevMapHash +pub fn aya::maps::DevMapHash::insert(&mut self, key: u32, target_if_index: u32, program: core::option::Option<&aya::programs::ProgramFd>, flags: u64) -> core::result::Result<(), aya::maps::xdp::XdpMapError> +pub fn aya::maps::DevMapHash::remove(&mut self, key: u32) -> core::result::Result<(), aya::maps::MapError> +impl core::convert::TryFrom for aya::maps::DevMapHash +pub type aya::maps::DevMapHash::Error = aya::maps::MapError +pub fn aya::maps::DevMapHash::try_from(map: aya::maps::Map) -> core::result::Result +impl<'a> core::convert::TryFrom<&'a aya::maps::Map> for aya::maps::DevMapHash<&'a aya::maps::MapData> +pub type aya::maps::DevMapHash<&'a aya::maps::MapData>::Error = aya::maps::MapError +pub fn aya::maps::DevMapHash<&'a aya::maps::MapData>::try_from(map: &'a aya::maps::Map) -> core::result::Result +impl<'a> core::convert::TryFrom<&'a mut aya::maps::Map> for aya::maps::DevMapHash<&'a mut aya::maps::MapData> +pub type aya::maps::DevMapHash<&'a mut aya::maps::MapData>::Error = aya::maps::MapError +pub fn aya::maps::DevMapHash<&'a mut aya::maps::MapData>::try_from(map: &'a mut aya::maps::Map) -> core::result::Result +impl core::marker::Send for aya::maps::DevMapHash where T: core::marker::Send +impl core::marker::Sync for aya::maps::DevMapHash where T: core::marker::Sync +impl core::marker::Unpin for aya::maps::DevMapHash where T: core::marker::Unpin +impl core::panic::unwind_safe::RefUnwindSafe for aya::maps::DevMapHash where T: core::panic::unwind_safe::RefUnwindSafe +impl core::panic::unwind_safe::UnwindSafe for aya::maps::DevMapHash where T: core::panic::unwind_safe::UnwindSafe +impl core::convert::Into for aya::maps::DevMapHash where U: core::convert::From +pub fn aya::maps::DevMapHash::into(self) -> U +impl core::convert::TryFrom for aya::maps::DevMapHash where U: core::convert::Into +pub type aya::maps::DevMapHash::Error = core::convert::Infallible +pub fn aya::maps::DevMapHash::try_from(value: U) -> core::result::Result>::Error> +impl core::convert::TryInto for aya::maps::DevMapHash where U: core::convert::TryFrom +pub type aya::maps::DevMapHash::Error = >::Error +pub fn aya::maps::DevMapHash::try_into(self) -> core::result::Result>::Error> +impl core::any::Any for aya::maps::DevMapHash where T: 'static + core::marker::Sized +pub fn aya::maps::DevMapHash::type_id(&self) -> core::any::TypeId +impl core::borrow::Borrow for aya::maps::DevMapHash where T: core::marker::Sized +pub fn aya::maps::DevMapHash::borrow(&self) -> &T +impl core::borrow::BorrowMut for aya::maps::DevMapHash where T: core::marker::Sized +pub fn aya::maps::DevMapHash::borrow_mut(&mut self) -> &mut T +impl core::convert::From for aya::maps::DevMapHash +pub fn aya::maps::DevMapHash::from(t: T) -> T pub struct aya::maps::HashMap impl, K: aya::Pod, V: aya::Pod> aya::maps::hash_map::HashMap pub fn aya::maps::hash_map::HashMap::get(&self, key: &K, flags: u64) -> core::result::Result @@ -1712,6 +2049,41 @@ impl core::borrow::BorrowMut for aya::maps::stack_trace::StackTraceMap pub fn aya::maps::stack_trace::StackTraceMap::borrow_mut(&mut self) -> &mut T impl core::convert::From for aya::maps::stack_trace::StackTraceMap pub fn aya::maps::stack_trace::StackTraceMap::from(t: T) -> T +pub struct aya::maps::XskMap +impl> aya::maps::XskMap +pub fn aya::maps::XskMap::len(&self) -> u32 +impl> aya::maps::XskMap +pub fn aya::maps::XskMap::set(&mut self, index: u32, socket_fd: impl std::os::fd::raw::AsRawFd, flags: u64) -> core::result::Result<(), aya::maps::MapError> +impl core::convert::TryFrom for aya::maps::XskMap +pub type aya::maps::XskMap::Error = aya::maps::MapError +pub fn aya::maps::XskMap::try_from(map: aya::maps::Map) -> core::result::Result +impl<'a> core::convert::TryFrom<&'a aya::maps::Map> for aya::maps::XskMap<&'a aya::maps::MapData> +pub type aya::maps::XskMap<&'a aya::maps::MapData>::Error = aya::maps::MapError +pub fn aya::maps::XskMap<&'a aya::maps::MapData>::try_from(map: &'a aya::maps::Map) -> core::result::Result +impl<'a> core::convert::TryFrom<&'a mut aya::maps::Map> for aya::maps::XskMap<&'a mut aya::maps::MapData> +pub type aya::maps::XskMap<&'a mut aya::maps::MapData>::Error = aya::maps::MapError +pub fn aya::maps::XskMap<&'a mut aya::maps::MapData>::try_from(map: &'a mut aya::maps::Map) -> core::result::Result +impl core::marker::Send for aya::maps::XskMap where T: core::marker::Send +impl core::marker::Sync for aya::maps::XskMap where T: core::marker::Sync +impl core::marker::Unpin for aya::maps::XskMap where T: core::marker::Unpin +impl core::panic::unwind_safe::RefUnwindSafe for aya::maps::XskMap where T: core::panic::unwind_safe::RefUnwindSafe +impl core::panic::unwind_safe::UnwindSafe for aya::maps::XskMap where T: core::panic::unwind_safe::UnwindSafe +impl core::convert::Into for aya::maps::XskMap where U: core::convert::From +pub fn aya::maps::XskMap::into(self) -> U +impl core::convert::TryFrom for aya::maps::XskMap where U: core::convert::Into +pub type aya::maps::XskMap::Error = core::convert::Infallible +pub fn aya::maps::XskMap::try_from(value: U) -> core::result::Result>::Error> +impl core::convert::TryInto for aya::maps::XskMap where U: core::convert::TryFrom +pub type aya::maps::XskMap::Error = >::Error +pub fn aya::maps::XskMap::try_into(self) -> core::result::Result>::Error> +impl core::any::Any for aya::maps::XskMap where T: 'static + core::marker::Sized +pub fn aya::maps::XskMap::type_id(&self) -> core::any::TypeId +impl core::borrow::Borrow for aya::maps::XskMap where T: core::marker::Sized +pub fn aya::maps::XskMap::borrow(&self) -> &T +impl core::borrow::BorrowMut for aya::maps::XskMap where T: core::marker::Sized +pub fn aya::maps::XskMap::borrow_mut(&mut self) -> &mut T +impl core::convert::From for aya::maps::XskMap +pub fn aya::maps::XskMap::from(t: T) -> T pub trait aya::maps::IterableMap pub fn aya::maps::IterableMap::get(&self, key: &K) -> core::result::Result pub fn aya::maps::IterableMap::map(&self) -> &aya::maps::MapData @@ -4514,13 +4886,12 @@ pub fn aya::programs::xdp::Xdp::attach(&mut self, interface: &str, flags: aya::p pub fn aya::programs::xdp::Xdp::attach_to_if_index(&mut self, if_index: u32, flags: aya::programs::xdp::XdpFlags) -> core::result::Result pub fn aya::programs::xdp::Xdp::attach_to_link(&mut self, link: aya::programs::xdp::XdpLink) -> core::result::Result pub fn aya::programs::xdp::Xdp::detach(&mut self, link_id: aya::programs::xdp::XdpLinkId) -> core::result::Result<(), aya::programs::ProgramError> +pub fn aya::programs::xdp::Xdp::from_pin>(path: P, attach_type: aya_obj::programs::xdp::XdpAttachType) -> core::result::Result pub fn aya::programs::xdp::Xdp::load(&mut self) -> core::result::Result<(), aya::programs::ProgramError> pub fn aya::programs::xdp::Xdp::take_link(&mut self, link_id: aya::programs::xdp::XdpLinkId) -> core::result::Result impl aya::programs::xdp::Xdp pub fn aya::programs::xdp::Xdp::fd(&self) -> core::result::Result<&aya::programs::ProgramFd, aya::programs::ProgramError> impl aya::programs::xdp::Xdp -pub fn aya::programs::xdp::Xdp::from_pin>(path: P) -> core::result::Result -impl aya::programs::xdp::Xdp pub fn aya::programs::xdp::Xdp::info(&self) -> core::result::Result impl aya::programs::xdp::Xdp pub fn aya::programs::xdp::Xdp::pin>(&mut self, path: P) -> core::result::Result<(), aya::pin::PinError> @@ -6681,13 +7052,12 @@ pub fn aya::programs::xdp::Xdp::attach(&mut self, interface: &str, flags: aya::p pub fn aya::programs::xdp::Xdp::attach_to_if_index(&mut self, if_index: u32, flags: aya::programs::xdp::XdpFlags) -> core::result::Result pub fn aya::programs::xdp::Xdp::attach_to_link(&mut self, link: aya::programs::xdp::XdpLink) -> core::result::Result pub fn aya::programs::xdp::Xdp::detach(&mut self, link_id: aya::programs::xdp::XdpLinkId) -> core::result::Result<(), aya::programs::ProgramError> +pub fn aya::programs::xdp::Xdp::from_pin>(path: P, attach_type: aya_obj::programs::xdp::XdpAttachType) -> core::result::Result pub fn aya::programs::xdp::Xdp::load(&mut self) -> core::result::Result<(), aya::programs::ProgramError> pub fn aya::programs::xdp::Xdp::take_link(&mut self, link_id: aya::programs::xdp::XdpLinkId) -> core::result::Result impl aya::programs::xdp::Xdp pub fn aya::programs::xdp::Xdp::fd(&self) -> core::result::Result<&aya::programs::ProgramFd, aya::programs::ProgramError> impl aya::programs::xdp::Xdp -pub fn aya::programs::xdp::Xdp::from_pin>(path: P) -> core::result::Result -impl aya::programs::xdp::Xdp pub fn aya::programs::xdp::Xdp::info(&self) -> core::result::Result impl aya::programs::xdp::Xdp pub fn aya::programs::xdp::Xdp::pin>(&mut self, path: P) -> core::result::Result<(), aya::pin::PinError> @@ -7234,6 +7604,8 @@ pub fn aya::VerifierLogLevel::borrow_mut(&mut self) -> &mut T impl core::convert::From for aya::VerifierLogLevel pub fn aya::VerifierLogLevel::from(t: T) -> T pub unsafe trait aya::Pod: core::marker::Copy + 'static +impl aya::Pod for aya_obj::generated::linux_bindings_x86_64::bpf_cpumap_val +impl aya::Pod for aya_obj::generated::linux_bindings_x86_64::bpf_devmap_val impl aya::Pod for i128 impl aya::Pod for i16 impl aya::Pod for i32