diff --git a/aya/src/sys/netlink.rs b/aya/src/sys/netlink.rs index 9788fe8b..a7b7ba00 100644 --- a/aya/src/sys/netlink.rs +++ b/aya/src/sys/netlink.rs @@ -48,6 +48,20 @@ pub(crate) enum NetlinkErrorInternal { #[error(transparent)] pub struct NetlinkError(#[from] NetlinkErrorInternal); +impl NetlinkError { + pub fn raw_os_error(&self) -> Option { + let Self(inner) = self; + match inner { + NetlinkErrorInternal::Error { source, .. } => source.raw_os_error(), + NetlinkErrorInternal::IoError(err) => err.raw_os_error(), + NetlinkErrorInternal::NlAttrError(err) => match err { + NlAttrError::InvalidBufferLength { .. } + | NlAttrError::InvalidHeaderLength { .. } => None, + }, + } + } +} + // Safety: marking this as unsafe overall because of all the pointer math required to comply with // netlink alignments pub(crate) unsafe fn netlink_set_xdp_fd( diff --git a/test/integration-test/src/tests/xdp.rs b/test/integration-test/src/tests/xdp.rs index b48fc38e..08161872 100644 --- a/test/integration-test/src/tests/xdp.rs +++ b/test/integration-test/src/tests/xdp.rs @@ -1,9 +1,11 @@ use std::{net::UdpSocket, num::NonZeroU32, time::Duration}; +use assert_matches::assert_matches; use aya::{ Ebpf, maps::{Array, CpuMap, XskMap}, - programs::{Xdp, XdpFlags}, + programs::{ProgramError, Xdp, XdpError, XdpFlags, xdp::XdpLinkId}, + util::KernelVersion, }; use object::{Object as _, ObjectSection as _, ObjectSymbol as _, SymbolSection}; use xdpilone::{BufIdx, IfInfo, Socket, SocketConfig, Umem, UmemConfig}; @@ -177,7 +179,21 @@ fn cpumap_chain() { // 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 result = xdp.attach("lo", XdpFlags::default()); + // Generic devices did not support cpumap XDP programs until 5.15. + // + // See https://github.com/torvalds/linux/commit/11941f8a85362f612df61f4aaab0e41b64d2111d. + if KernelVersion::current().unwrap() < KernelVersion::new(5, 15, 0) { + assert_matches!(result, Err(ProgramError::XdpError(XdpError::NetlinkError(err))) => { + assert_eq!(err.raw_os_error(), Some(libc::EINVAL)) + }); + eprintln!( + "skipping test - cpumap attachment not supported on generic (loopback) interface" + ); + return; + } else { + let _: XdpLinkId = result.unwrap(); + }; const PAYLOAD: &str = "hello cpumap";