aya: remove panics on indeterminate kernel version

Cache the current kernel version in a thread-local while I'm here.

Closes https://github.com/aya-rs/aya/issues/1024.
Closes https://github.com/aya-rs/aya/pull/1042.
reviewable/pr1199/r1
Tamir Duberstein 2 weeks ago
parent 9eefb48a0a
commit 27d69c35f0

@ -579,12 +579,8 @@ impl MapData {
}
};
#[cfg(not(test))]
let kernel_version = KernelVersion::current().unwrap();
#[cfg(test)]
let kernel_version = KernelVersion::new(0xff, 0xff, 0xff);
let fd = bpf_create_map(&c_name, &obj, btf_fd, kernel_version).map_err(|io_error| {
if kernel_version < KernelVersion::new(5, 11, 0) {
let fd = bpf_create_map(&c_name, &obj, btf_fd).map_err(|io_error| {
if !KernelVersion::at_least(5, 11, 0) {
maybe_warn_rlimit();
}

@ -73,7 +73,7 @@ impl CgroupDevice {
let prog_fd = prog_fd.as_fd();
let cgroup_fd = cgroup.as_fd();
if KernelVersion::current().unwrap() >= KernelVersion::new(5, 7, 0) {
if KernelVersion::at_least(5, 7, 0) {
let link_fd = bpf_link_create(
prog_fd,
LinkTarget::Fd(cgroup_fd),

@ -99,7 +99,7 @@ impl CgroupSkb {
CgroupSkbAttachType::Ingress => BPF_CGROUP_INET_INGRESS,
CgroupSkbAttachType::Egress => BPF_CGROUP_INET_EGRESS,
};
if KernelVersion::current().unwrap() >= KernelVersion::new(5, 7, 0) {
if KernelVersion::at_least(5, 7, 0) {
let link_fd = bpf_link_create(
prog_fd,
LinkTarget::Fd(cgroup_fd),

@ -76,7 +76,7 @@ impl CgroupSock {
let prog_fd = prog_fd.as_fd();
let cgroup_fd = cgroup.as_fd();
let attach_type = self.data.expected_attach_type.unwrap();
if KernelVersion::current().unwrap() >= KernelVersion::new(5, 7, 0) {
if KernelVersion::at_least(5, 7, 0) {
let link_fd = bpf_link_create(
prog_fd,
LinkTarget::Fd(cgroup_fd),

@ -77,7 +77,7 @@ impl CgroupSockAddr {
let prog_fd = prog_fd.as_fd();
let cgroup_fd = cgroup.as_fd();
let attach_type = self.data.expected_attach_type.unwrap();
if KernelVersion::current().unwrap() >= KernelVersion::new(5, 7, 0) {
if KernelVersion::at_least(5, 7, 0) {
let link_fd = bpf_link_create(
prog_fd,
LinkTarget::Fd(cgroup_fd),

@ -74,7 +74,7 @@ impl CgroupSockopt {
let prog_fd = prog_fd.as_fd();
let cgroup_fd = cgroup.as_fd();
let attach_type = self.data.expected_attach_type.unwrap();
if KernelVersion::current().unwrap() >= KernelVersion::new(5, 7, 0) {
if KernelVersion::at_least(5, 7, 0) {
let link_fd = bpf_link_create(
prog_fd,
LinkTarget::Fd(cgroup_fd),

@ -72,7 +72,7 @@ impl CgroupSysctl {
let prog_fd = prog_fd.as_fd();
let cgroup_fd = cgroup.as_fd();
if KernelVersion::current().unwrap() >= KernelVersion::new(5, 7, 0) {
if KernelVersion::at_least(5, 7, 0) {
let link_fd = bpf_link_create(
prog_fd,
LinkTarget::Fd(cgroup_fd),

@ -659,8 +659,11 @@ fn load_program<T: Link>(
},
) = obj;
let target_kernel_version =
kernel_version.unwrap_or_else(|| KernelVersion::current().unwrap().code());
let target_kernel_version = kernel_version.unwrap_or_else(|| {
KernelVersion::current()
.map(KernelVersion::code)
.unwrap_or(0)
});
let prog_name = if let Some(name) = name.as_deref() {
let prog_name = CString::new(name).map_err(|err @ std::ffi::NulError { .. }| {

@ -118,7 +118,7 @@ pub(crate) fn attach<T: Link + From<PerfLinkInner>>(
// Use debugfs to create probe
let prog_fd = program_data.fd()?;
let prog_fd = prog_fd.as_fd();
let link = if KernelVersion::current().unwrap() < KernelVersion::new(4, 17, 0) {
let link = if !KernelVersion::at_least(4, 17, 0) {
if cookie.is_some() {
return Err(ProgramError::AttachCookieNotSupported);
}

@ -71,7 +71,7 @@ impl SockOps {
let prog_fd = prog_fd.as_fd();
let cgroup_fd = cgroup.as_fd();
let attach_type = BPF_CGROUP_SOCK_OPS;
if KernelVersion::current().unwrap() >= KernelVersion::new(5, 7, 0) {
if KernelVersion::at_least(5, 7, 0) {
let link_fd = bpf_link_create(
prog_fd,
LinkTarget::Fd(cgroup_fd),

@ -181,9 +181,7 @@ impl SchedClassifier {
interface: &str,
attach_type: TcAttachType,
) -> Result<SchedClassifierLinkId, ProgramError> {
if !matches!(attach_type, TcAttachType::Custom(_))
&& KernelVersion::current().unwrap() >= KernelVersion::new(6, 6, 0)
{
if !matches!(attach_type, TcAttachType::Custom(_)) && KernelVersion::at_least(6, 6, 0) {
self.attach_with_options(
interface,
attach_type,

@ -133,7 +133,7 @@ impl Xdp {
let prog_fd = self.fd()?;
let prog_fd = prog_fd.as_fd();
if KernelVersion::current().unwrap() >= KernelVersion::new(5, 9, 0) {
if KernelVersion::at_least(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`
@ -255,7 +255,7 @@ impl Link for NlLink {
}
fn detach(self) -> Result<(), ProgramError> {
let flags = if KernelVersion::current().unwrap() >= KernelVersion::new(5, 7, 0) {
let flags = if KernelVersion::at_least(5, 7, 0) {
self.flags.bits() | XDP_FLAGS_REPLACE
} else {
self.flags.bits()

@ -46,7 +46,6 @@ pub(crate) fn bpf_create_map(
name: &CStr,
def: &aya_obj::Map,
btf_fd: Option<BorrowedFd<'_>>,
kernel_version: KernelVersion,
) -> io::Result<crate::MockableFd> {
let mut attr = unsafe { mem::zeroed::<bpf_attr>() };
@ -93,7 +92,7 @@ pub(crate) fn bpf_create_map(
// https://github.com/torvalds/linux/commit/ad5b177bd73f5107d97c36f56395c4281fb6f089
// The map name was added as a parameter in kernel 4.15+ so we skip adding it on
// older kernels for compatibility
if kernel_version >= KernelVersion::new(4, 15, 0) {
if KernelVersion::at_least(4, 15, 0) {
// u.map_name is 16 bytes max and must be NULL terminated
let name_bytes = name.to_bytes_with_nul();
let len = cmp::min(name_bytes.len(), u.map_name.len());

@ -14,6 +14,7 @@ use std::{
use aya_obj::generated::{TC_H_MAJ_MASK, TC_H_MIN_MASK};
use libc::{if_nametoindex, sysconf, uname, utsname, _SC_PAGESIZE};
use log::warn;
use crate::Pod;
@ -48,8 +49,36 @@ impl KernelVersion {
/// Returns the kernel version of the currently running kernel.
pub fn current() -> Result<Self, impl Error> {
thread_local! {
// TODO(https://github.com/rust-lang/rust/issues/109737): Use
// `std::cell::OnceCell` when `get_or_try_init` is stabilized.
static CACHE: once_cell::unsync::OnceCell<KernelVersion> = const { once_cell::unsync::OnceCell::new() };
}
CACHE.with(|cell| {
// TODO(https://github.com/rust-lang/rust/issues/109737): Replace `once_cell` with
// `std::cell::OnceCell`.
cell.get_or_try_init(|| {
// error: unsupported operation: `open` not available when isolation is enabled
if cfg!(miri) {
Ok(Self::new(0xff, 0xff, 0xff))
} else {
Self::get_kernel_version()
}
})
.copied()
})
}
/// Returns true iff the current kernel version is greater than or equal to the given version.
pub(crate) fn at_least(major: u8, minor: u8, patch: u16) -> bool {
match Self::current() {
Ok(current) => current >= Self::new(major, minor, patch),
Err(error) => {
warn!("failed to get current kernel version: {error}");
false
}
}
}
/// The equivalent of LINUX_VERSION_CODE.
pub fn code(self) -> u32 {

Loading…
Cancel
Save