Skip to content

Commit a1e3e0d

Browse files
committed
aya: remove panics on indeterminate kernel version
There remains a single instance of `KernelVersion::current().unwrap()` in the program loading path; this one is likely to be noticed immediately so it is left undisturbed. Cache the current kernel version in a thread-local while I'm here. Closes aya-rs#1024. Closes aya-rs#1042.
1 parent 3edac61 commit a1e3e0d

13 files changed

+36
-22
lines changed

aya/src/maps/mod.rs

+2-6
Original file line numberDiff line numberDiff line change
@@ -579,12 +579,8 @@ impl MapData {
579579
}
580580
};
581581

582-
#[cfg(not(test))]
583-
let kernel_version = KernelVersion::current().unwrap();
584-
#[cfg(test)]
585-
let kernel_version = KernelVersion::new(0xff, 0xff, 0xff);
586-
let fd = bpf_create_map(&c_name, &obj, btf_fd, kernel_version).map_err(|io_error| {
587-
if kernel_version < KernelVersion::new(5, 11, 0) {
582+
let fd = bpf_create_map(&c_name, &obj, btf_fd).map_err(|io_error| {
583+
if !KernelVersion::at_least(5, 11, 0) {
588584
maybe_warn_rlimit();
589585
}
590586

aya/src/programs/cgroup_device.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ impl CgroupDevice {
7373
let prog_fd = prog_fd.as_fd();
7474
let cgroup_fd = cgroup.as_fd();
7575

76-
if KernelVersion::current().unwrap() >= KernelVersion::new(5, 7, 0) {
76+
if KernelVersion::at_least(5, 7, 0) {
7777
let link_fd = bpf_link_create(
7878
prog_fd,
7979
LinkTarget::Fd(cgroup_fd),

aya/src/programs/cgroup_skb.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ impl CgroupSkb {
9999
CgroupSkbAttachType::Ingress => BPF_CGROUP_INET_INGRESS,
100100
CgroupSkbAttachType::Egress => BPF_CGROUP_INET_EGRESS,
101101
};
102-
if KernelVersion::current().unwrap() >= KernelVersion::new(5, 7, 0) {
102+
if KernelVersion::at_least(5, 7, 0) {
103103
let link_fd = bpf_link_create(
104104
prog_fd,
105105
LinkTarget::Fd(cgroup_fd),

aya/src/programs/cgroup_sock.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ impl CgroupSock {
7676
let prog_fd = prog_fd.as_fd();
7777
let cgroup_fd = cgroup.as_fd();
7878
let attach_type = self.data.expected_attach_type.unwrap();
79-
if KernelVersion::current().unwrap() >= KernelVersion::new(5, 7, 0) {
79+
if KernelVersion::at_least(5, 7, 0) {
8080
let link_fd = bpf_link_create(
8181
prog_fd,
8282
LinkTarget::Fd(cgroup_fd),

aya/src/programs/cgroup_sock_addr.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ impl CgroupSockAddr {
7777
let prog_fd = prog_fd.as_fd();
7878
let cgroup_fd = cgroup.as_fd();
7979
let attach_type = self.data.expected_attach_type.unwrap();
80-
if KernelVersion::current().unwrap() >= KernelVersion::new(5, 7, 0) {
80+
if KernelVersion::at_least(5, 7, 0) {
8181
let link_fd = bpf_link_create(
8282
prog_fd,
8383
LinkTarget::Fd(cgroup_fd),

aya/src/programs/cgroup_sockopt.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ impl CgroupSockopt {
7474
let prog_fd = prog_fd.as_fd();
7575
let cgroup_fd = cgroup.as_fd();
7676
let attach_type = self.data.expected_attach_type.unwrap();
77-
if KernelVersion::current().unwrap() >= KernelVersion::new(5, 7, 0) {
77+
if KernelVersion::at_least(5, 7, 0) {
7878
let link_fd = bpf_link_create(
7979
prog_fd,
8080
LinkTarget::Fd(cgroup_fd),

aya/src/programs/cgroup_sysctl.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ impl CgroupSysctl {
7272
let prog_fd = prog_fd.as_fd();
7373
let cgroup_fd = cgroup.as_fd();
7474

75-
if KernelVersion::current().unwrap() >= KernelVersion::new(5, 7, 0) {
75+
if KernelVersion::at_least(5, 7, 0) {
7676
let link_fd = bpf_link_create(
7777
prog_fd,
7878
LinkTarget::Fd(cgroup_fd),

aya/src/programs/probe.rs

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

aya/src/programs/sock_ops.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ impl SockOps {
7171
let prog_fd = prog_fd.as_fd();
7272
let cgroup_fd = cgroup.as_fd();
7373
let attach_type = BPF_CGROUP_SOCK_OPS;
74-
if KernelVersion::current().unwrap() >= KernelVersion::new(5, 7, 0) {
74+
if KernelVersion::at_least(5, 7, 0) {
7575
let link_fd = bpf_link_create(
7676
prog_fd,
7777
LinkTarget::Fd(cgroup_fd),

aya/src/programs/tc.rs

+1-3
Original file line numberDiff line numberDiff line change
@@ -181,9 +181,7 @@ impl SchedClassifier {
181181
interface: &str,
182182
attach_type: TcAttachType,
183183
) -> Result<SchedClassifierLinkId, ProgramError> {
184-
if !matches!(attach_type, TcAttachType::Custom(_))
185-
&& KernelVersion::current().unwrap() >= KernelVersion::new(6, 6, 0)
186-
{
184+
if !matches!(attach_type, TcAttachType::Custom(_)) && KernelVersion::at_least(6, 6, 0) {
187185
self.attach_with_options(
188186
interface,
189187
attach_type,

aya/src/programs/xdp.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@ impl Xdp {
133133
let prog_fd = self.fd()?;
134134
let prog_fd = prog_fd.as_fd();
135135

136-
if KernelVersion::current().unwrap() >= KernelVersion::new(5, 9, 0) {
136+
if KernelVersion::at_least(5, 9, 0) {
137137
// Unwrap safety: the function starts with `self.fd()?` that will succeed if and only
138138
// if the program has been loaded, i.e. there is an fd. We get one by:
139139
// - Using `Xdp::from_pin` that sets `expected_attach_type`
@@ -255,7 +255,7 @@ impl Link for NlLink {
255255
}
256256

257257
fn detach(self) -> Result<(), ProgramError> {
258-
let flags = if KernelVersion::current().unwrap() >= KernelVersion::new(5, 7, 0) {
258+
let flags = if KernelVersion::at_least(5, 7, 0) {
259259
self.flags.bits() | XDP_FLAGS_REPLACE
260260
} else {
261261
self.flags.bits()

aya/src/sys/bpf.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,6 @@ pub(crate) fn bpf_create_map(
4646
name: &CStr,
4747
def: &aya_obj::Map,
4848
btf_fd: Option<BorrowedFd<'_>>,
49-
kernel_version: KernelVersion,
5049
) -> io::Result<crate::MockableFd> {
5150
let mut attr = unsafe { mem::zeroed::<bpf_attr>() };
5251

@@ -93,7 +92,7 @@ pub(crate) fn bpf_create_map(
9392
// https://github.com/torvalds/linux/commit/ad5b177bd73f5107d97c36f56395c4281fb6f089
9493
// The map name was added as a parameter in kernel 4.15+ so we skip adding it on
9594
// older kernels for compatibility
96-
if kernel_version >= KernelVersion::new(4, 15, 0) {
95+
if KernelVersion::at_least(4, 15, 0) {
9796
// u.map_name is 16 bytes max and must be NULL terminated
9897
let name_bytes = name.to_bytes_with_nul();
9998
let len = cmp::min(name_bytes.len(), u.map_name.len());

aya/src/util.rs

+22-1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ use std::{
1414

1515
use aya_obj::generated::{TC_H_MAJ_MASK, TC_H_MIN_MASK};
1616
use libc::{if_nametoindex, sysconf, uname, utsname, _SC_PAGESIZE};
17+
use log::warn;
1718

1819
use crate::Pod;
1920

@@ -48,7 +49,27 @@ impl KernelVersion {
4849

4950
/// Returns the kernel version of the currently running kernel.
5051
pub fn current() -> Result<Self, impl Error> {
51-
Self::get_kernel_version()
52+
thread_local! {
53+
// TODO(https://github.com/rust-lang/rust/issues/109737): Use
54+
// `std::cell::OnceCell` when `get_or_try_init` is stabilized.
55+
static CACHE: once_cell::unsync::OnceCell<KernelVersion> = const { once_cell::unsync::OnceCell::new() };
56+
}
57+
CACHE.with(|cell| {
58+
// TODO(https://github.com/rust-lang/rust/issues/109737): Replace `once_cell` with
59+
// `std::cell::OnceCell`.
60+
cell.get_or_try_init(Self::get_kernel_version).copied()
61+
})
62+
}
63+
64+
/// Returns true iff the current kernel version is greater than or equal to the given version.
65+
pub(crate) fn at_least(major: u8, minor: u8, patch: u16) -> bool {
66+
match Self::current() {
67+
Ok(current) => current >= Self::new(major, minor, patch),
68+
Err(error) => {
69+
warn!("failed to get current kernel version: {error}");
70+
false
71+
}
72+
}
5273
}
5374

5475
/// The equivalent of LINUX_VERSION_CODE.

0 commit comments

Comments
 (0)