xdp: replace kernel version check with fallback

reviewable/pr1251/r56
Tamir Duberstein 1 week ago
parent 0ec60c4f23
commit 4c974d33a3
No known key found for this signature in database

@ -14,7 +14,6 @@ use aya_obj::{
}, },
programs::XdpAttachType, programs::XdpAttachType,
}; };
use libc::if_nametoindex;
use thiserror::Error; use thiserror::Error;
use crate::{ use crate::{
@ -102,14 +101,12 @@ impl Xdp {
/// If the given `interface` does not exist /// If the given `interface` does not exist
/// [`ProgramError::UnknownInterface`] is returned. /// [`ProgramError::UnknownInterface`] is returned.
/// ///
/// When attaching fails, [`ProgramError::SyscallError`] is returned for /// When `bpf_link_create` is unavailable or rejects the request, the call
/// kernels `>= 5.9.0`, and instead /// transparently falls back to the legacy netlink-based attach path.
/// [`XdpError::NetlinkError`] is returned for older
/// kernels.
pub fn attach(&mut self, interface: &str, flags: XdpFlags) -> Result<XdpLinkId, ProgramError> { pub fn attach(&mut self, interface: &str, flags: XdpFlags) -> Result<XdpLinkId, ProgramError> {
// TODO: avoid this unwrap by adding a new error variant. // TODO: avoid this unwrap by adding a new error variant.
let c_interface = CString::new(interface).unwrap(); let c_interface = CString::new(interface).unwrap();
let if_index = unsafe { if_nametoindex(c_interface.as_ptr()) }; let if_index = unsafe { libc::if_nametoindex(c_interface.as_ptr()) };
if if_index == 0 { if if_index == 0 {
return Err(ProgramError::UnknownInterface { return Err(ProgramError::UnknownInterface {
name: interface.to_string(), name: interface.to_string(),
@ -124,10 +121,8 @@ impl Xdp {
/// ///
/// # Errors /// # Errors
/// ///
/// When attaching fails, [`ProgramError::SyscallError`] is returned for /// When `bpf_link_create` is unavailable or rejects the request, the call
/// kernels `>= 5.9.0`, and instead /// transparently falls back to the legacy netlink-based attach path.
/// [`XdpError::NetlinkError`] is returned for older
/// kernels.
pub fn attach_to_if_index( pub fn attach_to_if_index(
&mut self, &mut self,
if_index: u32, if_index: u32,
@ -136,43 +131,45 @@ impl Xdp {
let prog_fd = self.fd()?; let prog_fd = self.fd()?;
let prog_fd = prog_fd.as_fd(); let prog_fd = prog_fd.as_fd();
if KernelVersion::at_least(5, 9, 0) { // Unwrap safety: the function starts with `self.fd()?` that will succeed if and only
// 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:
// 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`
// - Using `Xdp::from_pin` that sets `expected_attach_type` // - Calling `Xdp::attach` that sets `expected_attach_type`, as geting an `Xdp`
// - Calling `Xdp::attach` that sets `expected_attach_type`, as geting an `Xdp` // instance through `Xdp:try_from(Program)` does not set any fd.
// instance through `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
// 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(_).
// reach this point, expected_attach_type is guaranteed to be Some(_). let attach_type = self.data.expected_attach_type.unwrap();
let attach_type = self.data.expected_attach_type.unwrap(); let link = match bpf_link_create(
let link_fd = bpf_link_create( prog_fd,
prog_fd, LinkTarget::IfIndex(if_index),
LinkTarget::IfIndex(if_index), attach_type,
attach_type, flags.bits(),
flags.bits(), None,
None, ) {
) Ok(link_fd) => XdpLinkInner::Fd(FdLink::new(link_fd)),
.map_err(|io_error| SyscallError { Err(io_error) => {
call: "bpf_link_create", if io_error.raw_os_error() != Some(libc::EINVAL) {
io_error, return Err(ProgramError::SyscallError(SyscallError {
})?; call: "bpf_link_create",
self.data io_error,
.links }));
.insert(XdpLink::new(XdpLinkInner::Fd(FdLink::new(link_fd)))) }
} else {
let if_index = if_index as i32; // Fall back to netlink-based attachment.
unsafe { netlink_set_xdp_fd(if_index, Some(prog_fd), None, flags.bits()) }
.map_err(XdpError::NetlinkError)?; let if_index = if_index as i32;
unsafe { netlink_set_xdp_fd(if_index, Some(prog_fd), None, flags.bits()) }
let prog_fd = prog_fd.as_raw_fd(); .map_err(XdpError::NetlinkError)?;
self.data
.links let prog_fd = prog_fd.as_raw_fd();
.insert(XdpLink::new(XdpLinkInner::NlLink(NlLink { XdpLinkInner::NlLink(NlLink {
if_index, if_index,
prog_fd, prog_fd,
flags, flags,
}))) })
} }
};
self.data.links.insert(XdpLink::new(link))
} }
/// Creates a program from a pinned entry on a bpffs. /// Creates a program from a pinned entry on a bpffs.

Loading…
Cancel
Save