Use procfs crate for kernel version parsing

This allows the logic to be shared between aya and the integration tests
without exposing additional public API surface.
pull/641/head
Tamir Duberstein 1 year ago
parent 7f25956aea
commit b611038d5b
No known key found for this signature in database

@ -109,7 +109,7 @@ pub struct Object {
/// Program license
pub license: CString,
/// Kernel version
pub kernel_version: KernelVersion,
pub kernel_version: Option<u32>,
/// Program BTF
pub btf: Option<Btf>,
/// Program BTF.ext
@ -135,7 +135,7 @@ pub struct Program {
/// The license
pub license: CString,
/// The kernel version
pub kernel_version: KernelVersion,
pub kernel_version: Option<u32>,
/// The section containing the program
pub section: ProgramSection,
/// The section index of the program
@ -579,7 +579,7 @@ impl Object {
let kernel_version = if let Some(section) = obj.section_by_name("version") {
parse_version(Section::try_from(&section)?.data, endianness)?
} else {
KernelVersion::Any
None
};
let mut bpf_obj = Object::new(endianness, license, kernel_version);
@ -631,7 +631,7 @@ impl Object {
Ok(bpf_obj)
}
fn new(endianness: Endianness, license: CString, kernel_version: KernelVersion) -> Object {
fn new(endianness: Endianness, license: CString, kernel_version: Option<u32>) -> Object {
Object {
endianness,
license,
@ -1256,7 +1256,7 @@ fn parse_license(data: &[u8]) -> Result<CString, ParseError> {
.to_owned())
}
fn parse_version(data: &[u8], endianness: object::Endianness) -> Result<KernelVersion, ParseError> {
fn parse_version(data: &[u8], endianness: object::Endianness) -> Result<Option<u32>, ParseError> {
let data = match data.len() {
4 => data.try_into().unwrap(),
_ => {
@ -1271,9 +1271,10 @@ fn parse_version(data: &[u8], endianness: object::Endianness) -> Result<KernelVe
object::Endianness::Little => u32::from_le_bytes(data),
};
Ok(match v {
KERNEL_VERSION_ANY => KernelVersion::Any,
v => KernelVersion::Version(v),
Ok(if v == KERNEL_VERSION_ANY {
None
} else {
Some(v)
})
}
@ -1301,24 +1302,6 @@ fn get_map_field(btf: &Btf, type_id: u32) -> Result<u32, BtfError> {
Ok(arr.len)
}
/// The parsed kernel version
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum KernelVersion {
/// Specified version
Version(u32),
/// Any version
Any,
}
impl From<KernelVersion> for u32 {
fn from(version: KernelVersion) -> u32 {
match version {
KernelVersion::Any => KERNEL_VERSION_ANY,
KernelVersion::Version(v) => v,
}
}
}
// Parsed '.bss' '.data' and '.rodata' sections. These sections are arrays of
// bytes and are relocated based on their section index.
fn parse_data_map_section(section: &Section) -> Result<Map, ParseError> {
@ -1592,23 +1575,20 @@ mod tests {
Err(ParseError::InvalidKernelVersion { .. })
));
assert_eq!(
parse_version(&0xFFFF_FFFEu32.to_le_bytes(), Endianness::Little)
.expect("failed to parse magic version"),
KernelVersion::Any
);
assert!(matches!(
parse_version(&0xFFFF_FFFEu32.to_le_bytes(), Endianness::Little),
Ok(None)
));
assert_eq!(
parse_version(&0xFFFF_FFFEu32.to_be_bytes(), Endianness::Big)
.expect("failed to parse magic version"),
KernelVersion::Any
);
assert!(matches!(
parse_version(&0xFFFF_FFFEu32.to_be_bytes(), Endianness::Big),
Ok(None)
));
assert_eq!(
parse_version(&1234u32.to_le_bytes(), Endianness::Little)
.expect("failed to parse magic version"),
KernelVersion::Version(1234)
);
assert!(matches!(
parse_version(&1234u32.to_le_bytes(), Endianness::Little),
Ok(Some(1234))
));
}
#[test]
@ -1699,11 +1679,7 @@ mod tests {
}
fn fake_obj() -> Object {
Object::new(
Endianness::Little,
CString::new("GPL").unwrap(),
KernelVersion::Any,
)
Object::new(Endianness::Little, CString::new("GPL").unwrap(), None)
}
#[test]
@ -1753,7 +1729,7 @@ mod tests {
obj.parse_program(&fake_section(BpfSectionKind::Program,"kprobe/foo", bytes_of(&fake_ins()))),
Ok((Program {
license,
kernel_version: KernelVersion::Any,
kernel_version: None,
section: ProgramSection::KProbe { .. },
.. }, Function {
name,

@ -11,21 +11,31 @@ documentation = "https://docs.rs/aya"
edition = "2021"
[dependencies]
libc = { version = "0.2.105" }
async-io = { version = "1.3", optional = true }
aya-obj = { path = "../aya-obj", version = "0.1.0", features = ["std"] }
thiserror = "1"
object = { version = "0.31", default-features = false, features = ["std", "read_core", "elf"] }
bitflags = "2.2.1"
bytes = "1"
lazy_static = "1"
parking_lot = { version = "0.12.0", features = ["send_guard"] }
tokio = { version = "1.24.0", features = ["macros", "rt", "rt-multi-thread", "net"], optional = true }
async-io = { version = "1.3", optional = true }
libc = { version = "0.2.105" }
log = "0.4"
object = { version = "0.31", default-features = false, features = [
"std",
"read_core",
"elf",
] }
parking_lot = { version = "0.12.0", features = ["send_guard"] }
thiserror = "1"
tokio = { version = "1.24.0", features = [
"macros",
"rt",
"rt-multi-thread",
"net",
], optional = true }
procfs = { version = "0.15.1", default-features = false }
[dev-dependencies]
matches = "0.1.8"
futures = { version = "0.3.12", default-features = false, features = ["std"] }
matches = "0.1.8"
[features]
default = []
@ -35,4 +45,4 @@ async_std = ["async-io", "async"]
[package.metadata.docs.rs]
all-features = true
rustdoc-args = ["--cfg", "docsrs","-D", "warnings"]
rustdoc-args = ["--cfg", "docsrs", "-D", "warnings"]

@ -49,6 +49,7 @@ use std::{
use libc::{getrlimit, rlimit, RLIMIT_MEMLOCK, RLIM_INFINITY};
use log::warn;
use procfs::KernelVersion;
use thiserror::Error;
use crate::{
@ -56,7 +57,7 @@ use crate::{
pin::PinError,
sys::{
bpf_create_map, bpf_get_object, bpf_map_get_info_by_fd, bpf_map_get_next_key,
bpf_pin_object, kernel_version,
bpf_pin_object,
},
util::nr_cpus,
PinningType, Pod,
@ -489,18 +490,23 @@ impl MapData {
let c_name = CString::new(name).map_err(|_| MapError::InvalidName { name: name.into() })?;
let fd = bpf_create_map(&c_name, &self.obj, self.btf_fd).map_err(|(code, io_error)| {
let k_ver = kernel_version().unwrap();
if k_ver < (5, 11, 0) {
maybe_warn_rlimit();
}
#[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, &self.obj, self.btf_fd, kernel_version).map_err(
|(code, io_error)| {
if kernel_version < KernelVersion::new(5, 11, 0) {
maybe_warn_rlimit();
}
MapError::CreateError {
name: name.into(),
code,
io_error,
}
})? as RawFd;
MapError::CreateError {
name: name.into(),
code,
io_error,
}
},
)? as RawFd;
self.fd = Some(fd);

@ -1,4 +1,6 @@
//! Cgroup device programs.
use procfs::KernelVersion;
use std::os::fd::{AsRawFd, RawFd};
use crate::{
@ -6,7 +8,7 @@ use crate::{
programs::{
define_link_wrapper, load_program, FdLink, Link, ProgAttachLink, ProgramData, ProgramError,
},
sys::{bpf_link_create, bpf_prog_attach, kernel_version},
sys::{bpf_link_create, bpf_prog_attach},
};
/// A program used to watch or prevent device interaction from a cgroup.
@ -62,8 +64,7 @@ impl CgroupDevice {
let prog_fd = self.data.fd_or_err()?;
let cgroup_fd = cgroup.as_raw_fd();
let k_ver = kernel_version().unwrap();
if k_ver >= (5, 7, 0) {
if KernelVersion::current().unwrap() >= KernelVersion::new(5, 7, 0) {
let link_fd = bpf_link_create(prog_fd, cgroup_fd, BPF_CGROUP_DEVICE, None, 0).map_err(
|(_, io_error)| ProgramError::SyscallError {
call: "bpf_link_create",

@ -1,4 +1,6 @@
//! Cgroup skb programs.
use procfs::KernelVersion;
use std::{
hash::Hash,
os::fd::{AsRawFd, RawFd},
@ -13,7 +15,7 @@ use crate::{
programs::{
define_link_wrapper, load_program, FdLink, Link, ProgAttachLink, ProgramData, ProgramError,
},
sys::{bpf_link_create, bpf_prog_attach, kernel_version},
sys::{bpf_link_create, bpf_prog_attach},
};
/// A program used to inspect or filter network activity for a given cgroup.
@ -96,8 +98,7 @@ impl CgroupSkb {
CgroupSkbAttachType::Ingress => BPF_CGROUP_INET_INGRESS,
CgroupSkbAttachType::Egress => BPF_CGROUP_INET_EGRESS,
};
let k_ver = kernel_version().unwrap();
if k_ver >= (5, 7, 0) {
if KernelVersion::current().unwrap() >= KernelVersion::new(5, 7, 0) {
let link_fd = bpf_link_create(prog_fd, cgroup_fd, attach_type, None, 0).map_err(
|(_, io_error)| ProgramError::SyscallError {
call: "bpf_link_create",

@ -1,6 +1,8 @@
//! Cgroup socket programs.
pub use aya_obj::programs::CgroupSockAttachType;
use procfs::KernelVersion;
use std::{
hash::Hash,
os::fd::{AsRawFd, RawFd},
@ -12,7 +14,7 @@ use crate::{
programs::{
define_link_wrapper, load_program, FdLink, Link, ProgAttachLink, ProgramData, ProgramError,
},
sys::{bpf_link_create, bpf_prog_attach, kernel_version},
sys::{bpf_link_create, bpf_prog_attach},
};
/// A program that is called on socket creation, bind and release.
@ -71,8 +73,7 @@ impl CgroupSock {
let prog_fd = self.data.fd_or_err()?;
let cgroup_fd = cgroup.as_raw_fd();
let attach_type = self.data.expected_attach_type.unwrap();
let k_ver = kernel_version().unwrap();
if k_ver >= (5, 7, 0) {
if KernelVersion::current().unwrap() >= KernelVersion::new(5, 7, 0) {
let link_fd = bpf_link_create(prog_fd, cgroup_fd, attach_type, None, 0).map_err(
|(_, io_error)| ProgramError::SyscallError {
call: "bpf_link_create",

@ -1,6 +1,8 @@
//! Cgroup socket address programs.
pub use aya_obj::programs::CgroupSockAddrAttachType;
use procfs::KernelVersion;
use std::{
hash::Hash,
os::fd::{AsRawFd, RawFd},
@ -12,7 +14,7 @@ use crate::{
programs::{
define_link_wrapper, load_program, FdLink, Link, ProgAttachLink, ProgramData, ProgramError,
},
sys::{bpf_link_create, bpf_prog_attach, kernel_version},
sys::{bpf_link_create, bpf_prog_attach},
};
/// A program that can be used to inspect or modify socket addresses (`struct sockaddr`).
@ -72,8 +74,7 @@ impl CgroupSockAddr {
let prog_fd = self.data.fd_or_err()?;
let cgroup_fd = cgroup.as_raw_fd();
let attach_type = self.data.expected_attach_type.unwrap();
let k_ver = kernel_version().unwrap();
if k_ver >= (5, 7, 0) {
if KernelVersion::current().unwrap() >= KernelVersion::new(5, 7, 0) {
let link_fd = bpf_link_create(prog_fd, cgroup_fd, attach_type, None, 0).map_err(
|(_, io_error)| ProgramError::SyscallError {
call: "bpf_link_create",

@ -1,6 +1,8 @@
//! Cgroup socket option programs.
pub use aya_obj::programs::CgroupSockoptAttachType;
use procfs::KernelVersion;
use std::{
hash::Hash,
os::fd::{AsRawFd, RawFd},
@ -12,7 +14,7 @@ use crate::{
programs::{
define_link_wrapper, load_program, FdLink, Link, ProgAttachLink, ProgramData, ProgramError,
},
sys::{bpf_link_create, bpf_prog_attach, kernel_version},
sys::{bpf_link_create, bpf_prog_attach},
};
/// A program that can be used to get or set options on sockets.
@ -69,8 +71,7 @@ impl CgroupSockopt {
let prog_fd = self.data.fd_or_err()?;
let cgroup_fd = cgroup.as_raw_fd();
let attach_type = self.data.expected_attach_type.unwrap();
let k_ver = kernel_version().unwrap();
if k_ver >= (5, 7, 0) {
if KernelVersion::current().unwrap() >= KernelVersion::new(5, 7, 0) {
let link_fd = bpf_link_create(prog_fd, cgroup_fd, attach_type, None, 0).map_err(
|(_, io_error)| ProgramError::SyscallError {
call: "bpf_link_create",

@ -1,4 +1,6 @@
//! Cgroup sysctl programs.
use procfs::KernelVersion;
use std::{
hash::Hash,
os::fd::{AsRawFd, RawFd},
@ -9,7 +11,7 @@ use crate::{
programs::{
define_link_wrapper, load_program, FdLink, Link, ProgAttachLink, ProgramData, ProgramError,
},
sys::{bpf_link_create, bpf_prog_attach, kernel_version},
sys::{bpf_link_create, bpf_prog_attach},
};
/// A program used to watch for sysctl changes.
@ -64,8 +66,7 @@ impl CgroupSysctl {
let prog_fd = self.data.fd_or_err()?;
let cgroup_fd = cgroup.as_raw_fd();
let k_ver = kernel_version().unwrap();
if k_ver >= (5, 7, 0) {
if KernelVersion::current().unwrap() >= KernelVersion::new(5, 7, 0) {
let link_fd = bpf_link_create(prog_fd, cgroup_fd, BPF_CGROUP_SYSCTL, None, 0).map_err(
|(_, io_error)| ProgramError::SyscallError {
call: "bpf_link_create",

@ -65,6 +65,7 @@ mod utils;
pub mod xdp;
use libc::ENOSPC;
use procfs::KernelVersion;
use std::{
ffi::CString,
io,
@ -105,7 +106,7 @@ pub use xdp::{Xdp, XdpError, XdpFlags};
use crate::{
generated::{bpf_attach_type, bpf_prog_info, bpf_prog_type},
maps::MapError,
obj::{self, btf::BtfError, Function, KernelVersion},
obj::{self, btf::BtfError, Function},
pin::PinError,
sys::{
bpf_btf_get_fd_by_id, bpf_get_object, bpf_load_program, bpf_pin_object,
@ -573,13 +574,14 @@ fn load_program<T: Link>(
},
) = obj;
let target_kernel_version = match *kernel_version {
KernelVersion::Any => {
let (major, minor, patch) = crate::sys::kernel_version().unwrap();
(major << 16) + (minor << 8) + patch
}
_ => (*kernel_version).into(),
};
let target_kernel_version = kernel_version.unwrap_or_else(|| {
let KernelVersion {
major,
minor,
patch,
} = KernelVersion::current().unwrap();
(u32::from(major) << 16) + (u32::from(minor) << 8) + u32::from(patch)
});
let mut logger = VerifierLog::new();

@ -1,4 +1,5 @@
use libc::pid_t;
use procfs::KernelVersion;
use std::{
fs::{self, OpenOptions},
io::{self, Write},
@ -13,7 +14,7 @@ use crate::{
trace_point::read_sys_fs_trace_point_id, uprobe::UProbeError, utils::find_tracefs_path,
Link, ProgramData, ProgramError,
},
sys::{kernel_version, perf_event_open_probe, perf_event_open_trace_point},
sys::{perf_event_open_probe, perf_event_open_trace_point},
};
static PROBE_NAME_INDEX: AtomicUsize = AtomicUsize::new(0);
@ -49,8 +50,7 @@ pub(crate) fn attach<T: Link + From<PerfLinkInner>>(
) -> Result<T::Id, ProgramError> {
// https://github.com/torvalds/linux/commit/e12f03d7031a977356e3d7b75a68c2185ff8d155
// Use debugfs to create probe
let k_ver = kernel_version().unwrap();
if k_ver < (4, 17, 0) {
if KernelVersion::current().unwrap() >= KernelVersion::new(4, 17, 0) {
let (fd, event_alias) = create_as_trace_point(kind, fn_name, offset, pid)?;
let link = T::from(perf_attach_debugfs(
program_data.fd_or_err()?,

@ -1,6 +1,8 @@
//! eXpress Data Path (XDP) programs.
use bitflags;
use libc::if_nametoindex;
use procfs::KernelVersion;
use std::{convert::TryFrom, ffi::CString, hash::Hash, io, mem, os::unix::io::RawFd};
use thiserror::Error;
@ -15,10 +17,7 @@ use crate::{
programs::{
define_link_wrapper, load_program, FdLink, Link, LinkError, ProgramData, ProgramError,
},
sys::{
bpf_link_create, bpf_link_get_info_by_fd, bpf_link_update, kernel_version,
netlink_set_xdp_fd,
},
sys::{bpf_link_create, bpf_link_get_info_by_fd, bpf_link_update, netlink_set_xdp_fd},
};
/// The type returned when attaching an [`Xdp`] program fails on kernels `< 5.9`.
@ -126,8 +125,7 @@ impl Xdp {
let prog_fd = self.data.fd_or_err()?;
let if_index = if_index as RawFd;
let k_ver = kernel_version().unwrap();
if k_ver >= (5, 9, 0) {
if KernelVersion::current().unwrap() >= KernelVersion::new(5, 9, 0) {
let link_fd = bpf_link_create(prog_fd, if_index, BPF_XDP, None, flags.bits()).map_err(
|(_, io_error)| ProgramError::SyscallError {
call: "bpf_link_create",
@ -224,8 +222,7 @@ impl Link for NlLink {
}
fn detach(self) -> Result<(), ProgramError> {
let k_ver = kernel_version().unwrap();
let flags = if k_ver >= (5, 7, 0) {
let flags = if KernelVersion::current().unwrap() >= KernelVersion::new(5, 7, 0) {
self.flags.bits() | XDP_FLAGS_REPLACE
} else {
self.flags.bits()

@ -12,6 +12,7 @@ use obj::{
maps::{bpf_map_def, LegacyMap},
BpfSectionKind,
};
use procfs::KernelVersion;
use crate::{
generated::{
@ -27,12 +28,17 @@ use crate::{
},
copy_instructions,
},
sys::{kernel_version, syscall, SysResult, Syscall},
sys::{syscall, SysResult, Syscall},
util::VerifierLog,
Btf, Pod, BPF_OBJ_NAME_LEN,
};
pub(crate) fn bpf_create_map(name: &CStr, def: &obj::Map, btf_fd: Option<RawFd>) -> SysResult {
pub(crate) fn bpf_create_map(
name: &CStr,
def: &obj::Map,
btf_fd: Option<RawFd>,
kernel_version: KernelVersion,
) -> SysResult {
let mut attr = unsafe { mem::zeroed::<bpf_attr>() };
let u = unsafe { &mut attr.__bindgen_anon_1 };
@ -78,8 +84,7 @@ pub(crate) fn bpf_create_map(name: &CStr, def: &obj::Map, btf_fd: Option<RawFd>)
// 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
let k_ver = kernel_version().unwrap();
if k_ver >= (4, 15, 0) {
if kernel_version >= KernelVersion::new(4, 15, 0) {
// u.map_name is 16 bytes max and must be NULL terminated
let name_len = cmp::min(name.to_bytes().len(), BPF_OBJ_NAME_LEN - 1);
u.map_name[..name_len]

@ -5,15 +5,9 @@ mod perf_event;
#[cfg(test)]
mod fake;
use std::io;
#[cfg(not(test))]
use std::{ffi::CString, mem};
#[cfg(not(test))]
use std::{fs::File, io::Read};
use std::{io, mem};
#[cfg(not(test))]
use libc::utsname;
use libc::{c_int, c_long, pid_t};
use libc::{c_int, c_long, pid_t, SYS_bpf, SYS_perf_event_open};
pub(crate) use bpf::*;
#[cfg(test)]
@ -25,7 +19,6 @@ use crate::generated::{bpf_attr, bpf_cmd, perf_event_attr};
pub(crate) type SysResult = Result<c_long, (c_long, io::Error)>;
#[cfg_attr(test, allow(dead_code))]
pub(crate) enum Syscall<'a> {
Bpf {
cmd: bpf_cmd,
@ -46,126 +39,28 @@ pub(crate) enum Syscall<'a> {
}
fn syscall(call: Syscall) -> SysResult {
#[cfg(not(test))]
return unsafe { syscall_impl(call) };
#[cfg(test)]
return TEST_SYSCALL.with(|test_impl| unsafe { test_impl.borrow()(call) });
}
#[cfg(not(test))]
unsafe fn syscall_impl(call: Syscall) -> SysResult {
use libc::{SYS_bpf, SYS_perf_event_open};
use Syscall::*;
let ret = match call {
Bpf { cmd, attr } => libc::syscall(SYS_bpf, cmd, attr, mem::size_of::<bpf_attr>()),
PerfEventOpen {
attr,
pid,
cpu,
group,
flags,
} => libc::syscall(SYS_perf_event_open, &attr, pid, cpu, group, flags),
PerfEventIoctl { fd, request, arg } => {
libc::ioctl(fd, request.try_into().unwrap(), arg) as libc::c_long
}
};
if ret < 0 {
return Err((ret, io::Error::last_os_error()));
}
Ok(ret)
}
#[cfg(test)]
pub(crate) fn kernel_version() -> Result<(u32, u32, u32), ()> {
Ok((0xff, 0xff, 0xff))
}
#[cfg(not(test))]
fn ubuntu_kernel_version() -> Result<(u32, u32, u32), ()> {
if let Ok(mut file) = File::open("/proc/version_signature") {
let mut buf = String::new();
let mut major = 0u32;
let mut minor = 0u32;
let mut patch = 0u32;
let format = CString::new("%*s %*s %u.%u.%u\n").unwrap();
file.read_to_string(&mut buf).map_err(|_| ())?;
unsafe {
if libc::sscanf(
buf.as_ptr() as *const _,
format.as_ptr(),
&mut major as *mut u32,
&mut minor as *mut _,
&mut patch as *mut _,
) == 3
{
return Ok((major, minor, patch));
#[cfg_attr(test, allow(unreachable_code))]
match unsafe {
match call {
Syscall::Bpf { cmd, attr } => {
libc::syscall(SYS_bpf, cmd, attr, mem::size_of::<bpf_attr>())
}
}
}
Err(())
}
#[cfg(not(test))]
pub(crate) fn kernel_version() -> Result<(u32, u32, u32), ()> {
if let Ok(version) = ubuntu_kernel_version() {
return Ok(version);
}
unsafe {
let mut v = mem::zeroed::<utsname>();
if libc::uname(&mut v as *mut _) != 0 {
return Err(());
}
let mut major = 0u32;
let mut minor = 0u32;
let mut patch = 0u32;
let debian_marker = CString::new("Debian").unwrap();
let p = libc::strstr(v.version.as_ptr(), debian_marker.as_ptr());
if !p.is_null() {
let debian_format = CString::new("Debian %u.%u.%u").map_err(|_| ())?;
if libc::sscanf(
p,
debian_format.as_ptr(),
&mut major as *mut u32,
&mut minor as *mut _,
&mut patch as *mut _,
) == 3
{
// On Debian 10, kernels after 4.19.229 expect 4.19.255 due to broken Makefile patches.
let patch_level_limit = if major == 4 && minor == 19 { 230 } else { 255 };
if patch >= patch_level_limit {
patch = 255;
}
return Ok((major, minor, patch));
Syscall::PerfEventOpen {
attr,
pid,
cpu,
group,
flags,
} => libc::syscall(SYS_perf_event_open, &attr, pid, cpu, group, flags),
Syscall::PerfEventIoctl { fd, request, arg } => {
libc::ioctl(fd, request.try_into().unwrap(), arg) as libc::c_long
}
}
let format = CString::new("%u.%u.%u").unwrap();
if libc::sscanf(
v.release.as_ptr(),
format.as_ptr(),
&mut major as *mut u32,
&mut minor as *mut _,
&mut patch as *mut _,
) != 3
{
return Err(());
}
Ok((major, minor, patch))
} {
ret @ 0.. => Ok(ret),
ret => Err((ret, io::Error::last_os_error())),
}
}

@ -12,7 +12,7 @@ aya-obj = { path = "../../aya-obj" }
libc = { version = "0.2.105" }
log = "0.4"
object = { version = "0.31", default-features = false, features = ["std", "read_core", "elf"] }
procfs = "0.15.1"
rbpf = "0.2.0"
regex = "1"
tempfile = "3.3.0"
tokio = { version = "1.24", features = ["rt", "rt-multi-thread", "sync", "time"] }

@ -1,23 +0,0 @@
use anyhow::bail;
use libc::{uname, utsname};
use regex::Regex;
use std::{cell::OnceCell, ffi::CStr, mem};
pub fn kernel_version() -> anyhow::Result<(u8, u8, u8)> {
static mut RE: OnceCell<Regex> = OnceCell::new();
let re =
unsafe { &mut RE }.get_or_init(|| Regex::new(r"^([0-9]+)\.([0-9]+)\.([0-9]+)").unwrap());
let mut data: utsname = unsafe { mem::zeroed() };
let ret = unsafe { uname(&mut data) };
assert!(ret >= 0, "libc::uname failed.");
let release_cstr = unsafe { CStr::from_ptr(data.release.as_ptr()) };
let release = release_cstr.to_string_lossy();
if let Some(caps) = re.captures(&release) {
let major = caps.get(1).unwrap().as_str().parse().unwrap();
let minor = caps.get(2).unwrap().as_str().parse().unwrap();
let patch = caps.get(3).unwrap().as_str().parse().unwrap();
Ok((major, minor, patch))
} else {
bail!("no kernel version found");
}
}

@ -1,3 +1,4 @@
use procfs::KernelVersion;
use std::{convert::TryInto as _, thread, time};
use aya::{
@ -10,9 +11,6 @@ use aya::{
Bpf,
};
mod common;
use common::kernel_version;
const MAX_RETRIES: u32 = 100;
const RETRY_DURATION_MS: u64 = 10;
@ -133,7 +131,7 @@ fn unload_kprobe() {
#[test]
fn pin_link() {
if kernel_version().unwrap() < (5, 9, 0) {
if KernelVersion::current().unwrap() < KernelVersion::new(5, 9, 0) {
eprintln!("skipping test, XDP uses netlink");
return;
}
@ -168,7 +166,7 @@ fn pin_link() {
#[test]
fn pin_lifecycle() {
if kernel_version().unwrap() < (5, 9, 0) {
if KernelVersion::current().unwrap() < KernelVersion::new(5, 9, 0) {
eprintln!("skipping test, XDP uses netlink");
return;
}

@ -1,12 +1,11 @@
use procfs::KernelVersion;
use aya::{
include_bytes_aligned,
programs::{Extension, Xdp, XdpFlags},
Bpf, BpfLoader,
};
mod common;
use common::kernel_version;
#[test]
fn xdp() {
let bytes = include_bytes_aligned!("../../../target/bpfel-unknown-none/release/pass");
@ -18,15 +17,10 @@ fn xdp() {
#[test]
fn extension() {
let (major, minor, _) = kernel_version().unwrap();
if major < 5 || (minor == 5 && minor < 9) {
eprintln!(
"skipping as {}.{} does not meet version requirement of 5.9",
major, minor
);
if KernelVersion::current().unwrap() < KernelVersion::new(5, 9, 0) {
eprintln!("skipping test, XDP uses netlink");
return;
}
// TODO: Check kernel version == 5.9 or later
let main_bytes =
include_bytes_aligned!("../../../target/bpfel-unknown-none/release/main.bpf.o");
let mut bpf = Bpf::load(main_bytes).unwrap();

Loading…
Cancel
Save