From c7cb0bb552a1ae22d262b0a204e85c1c78337276 Mon Sep 17 00:00:00 2001 From: Dave Tucker Date: Wed, 26 Jul 2023 17:23:04 +0100 Subject: [PATCH] aya: Return error messages from netlink This returns error strings from netlink since they are more informative than the raw os error. For example: "Device or Resource Busy" vs. "XDP program already attached". Signed-off-by: Dave Tucker --- aya/src/sys/netlink.rs | 50 ++++++++++++++++++++++++++++++++---------- 1 file changed, 38 insertions(+), 12 deletions(-) diff --git a/aya/src/sys/netlink.rs b/aya/src/sys/netlink.rs index 44b0643bc..7aa41ee47 100644 --- a/aya/src/sys/netlink.rs +++ b/aya/src/sys/netlink.rs @@ -1,24 +1,27 @@ +use object::Endianness; use std::{collections::HashMap, ffi::CStr, io, mem, os::unix::io::RawFd, ptr, slice}; use thiserror::Error; use libc::{ close, getsockname, nlattr, nlmsgerr, nlmsghdr, recv, send, setsockopt, sockaddr_nl, socket, - AF_NETLINK, AF_UNSPEC, ETH_P_ALL, IFLA_XDP, NETLINK_EXT_ACK, NETLINK_ROUTE, NLA_ALIGNTO, - NLA_F_NESTED, NLA_TYPE_MASK, NLMSG_DONE, NLMSG_ERROR, NLM_F_ACK, NLM_F_CREATE, NLM_F_DUMP, - NLM_F_ECHO, NLM_F_EXCL, NLM_F_MULTI, NLM_F_REQUEST, RTM_DELTFILTER, RTM_GETTFILTER, - RTM_NEWQDISC, RTM_NEWTFILTER, RTM_SETLINK, SOCK_RAW, SOL_NETLINK, + AF_NETLINK, AF_PACKET, AF_UNSPEC, ETH_P_ALL, IFLA_XDP, NETLINK_CAP_ACK, NETLINK_EXT_ACK, + NETLINK_ROUTE, NLA_ALIGNTO, NLA_F_NESTED, NLA_TYPE_MASK, NLMSG_DONE, NLMSG_ERROR, NLM_F_ACK, + NLM_F_CREATE, NLM_F_DUMP, NLM_F_ECHO, NLM_F_EXCL, NLM_F_MULTI, NLM_F_REQUEST, RTM_DELTFILTER, + RTM_GETLINK, RTM_GETTFILTER, RTM_NEWLINK, RTM_NEWQDISC, RTM_NEWTFILTER, RTM_SETLINK, SOCK_RAW, + SOL_NETLINK, }; use crate::{ generated::{ - ifinfomsg, tcmsg, IFLA_XDP_EXPECTED_FD, IFLA_XDP_FD, IFLA_XDP_FLAGS, NLMSG_ALIGNTO, - TCA_BPF_FD, TCA_BPF_FLAGS, TCA_BPF_FLAG_ACT_DIRECT, TCA_BPF_NAME, TCA_KIND, TCA_OPTIONS, - TC_H_CLSACT, TC_H_INGRESS, TC_H_MAJ_MASK, TC_H_UNSPEC, XDP_FLAGS_REPLACE, + ifinfomsg, tcmsg, IFLA_XDP_EXPECTED_FD, IFLA_XDP_FD, IFLA_XDP_FLAGS, IFLA_XDP_PROG_ID, + NLMSG_ALIGNTO, TCA_BPF_FD, TCA_BPF_FLAGS, TCA_BPF_FLAG_ACT_DIRECT, TCA_BPF_NAME, TCA_KIND, + TCA_OPTIONS, TC_H_CLSACT, TC_H_INGRESS, TC_H_MAJ_MASK, TC_H_UNSPEC, XDP_FLAGS_REPLACE, }, programs::TcAttachType, util::tc_handler_make, }; +const NLMSGERR_ATTR_MSG: u16 = 0x01; const NLA_HDR_LEN: usize = align_to(mem::size_of::(), NLA_ALIGNTO as usize); // Safety: marking this as unsafe overall because of all the pointer math required to comply with @@ -62,9 +65,7 @@ pub(crate) unsafe fn netlink_set_xdp_fd( req.header.nlmsg_len += align_to(nla_len, NLA_ALIGNTO as usize) as u32; sock.send(&bytes_of(&req)[..req.header.nlmsg_len as usize])?; - sock.recv()?; - Ok(()) } @@ -270,13 +271,22 @@ impl NetlinkSocket { let enable = 1i32; // Safety: libc wrapper unsafe { + // Set NETLINK_EXT_ACK to get extended attributes setsockopt( sock, SOL_NETLINK, NETLINK_EXT_ACK, &enable as *const _ as *const _, mem::size_of::() as u32, - ) + ); + // Set NETLINK_CAP_ACK to avoid getting copies of request payload + setsockopt( + sock, + SOL_NETLINK, + NETLINK_CAP_ACK, + &enable as *const _ as *const _, + mem::size_of::() as u32, + ); }; // Safety: sockaddr_nl is POD so this is safe @@ -330,7 +340,23 @@ impl NetlinkSocket { // this is an ACK continue; } - return Err(io::Error::from_raw_os_error(-err.error)); + let attrs = parse_attrs(&message.data)?; + let err_msg = attrs.get(&NLMSGERR_ATTR_MSG).and_then(|msg| { + CStr::from_bytes_with_nul(msg.data) + .ok() + .map(|s| s.to_string_lossy().into_owned()) + }); + match err_msg { + Some(err_msg) => { + return Err(io::Error::new( + io::ErrorKind::Other, + format!("netlink error: {}", err_msg), + )); + } + None => { + return Err(io::Error::from_raw_os_error(-err.error)); + } + } } NLMSG_DONE => break 'out, _ => messages.push(message), @@ -377,7 +403,7 @@ impl NetlinkMessage { )); } ( - Vec::new(), + buf[data_offset + mem::size_of::()..msg_len].to_vec(), // Safety: nlmsgerr is POD so read is safe Some(unsafe { ptr::read_unaligned(buf[data_offset..].as_ptr() as *const nlmsgerr)