Example of exposing internal func as pub. But scope is chaning to feature trait instead

pull/970/head
martinsoees 10 months ago
parent 2215a62b90
commit 245070dfb7

@ -1,176 +1,182 @@
//! A collection of ebpf feature helpers that can determine kernel capabilities. // //! A collection of ebpf feature helpers that can determine kernel capabilities.
//! // //!
//! Basing kernel capabilities on kernel version is not sufficient since some // //! Basing kernel capabilities on kernel version is not sufficient since some
//! distros will backport ebpf functionality to older kernels. // //! distros will backport ebpf functionality to older kernels.
//! // //!
use std::mem::size_of; // use std::mem::size_of;
use aya_obj::{generated::bpf_map_type, maps::LegacyMap, EbpfSectionKind, Map}; // use aya_obj::{generated::bpf_map_type, maps::LegacyMap, EbpfSectionKind, Map};
use thiserror::Error; // use thiserror::Error;
use crate::maps::{MapData, MapError}; // use crate::maps::{MapData, MapError};
/// An error ocurred working with a pinned BPF object. // /// An error ocurred working with a pinned BPF object.
#[derive(Error, Debug)] // #[derive(Error, Debug)]
pub enum FeatureError { // pub enum FeatureError {
/// An error ocurred making a syscall. // /// An error ocurred making a syscall.
#[error(transparent)] // #[error(transparent)]
MapError(#[from] MapError), // MapError(#[from] MapError),
} // }
/// Result type used for the feature helpers use crate::sys::is_ringbuf_supported as ringbuf_supported;
pub type Result<T> = std::result::Result<T, FeatureError>;
pub fn is_ringbuf_supported() -> bool {
fn probe_map_create(map_type: bpf_map_type) -> Result<bool> { ringbuf_supported()
}
let def = Map::Legacy(LegacyMap {
def: aya_obj::maps::bpf_map_def { // /// Result type used for the feature helpers
map_type: map_type as u32, // pub type Result<T> = std::result::Result<T, FeatureError>;
key_size: size_of::<u32>() as u32,
value_size: size_of::<u32>() as u32, // fn probe_map_create(map_type: bpf_map_type) -> Result<bool> {
max_entries: 1,
map_flags: 0, // let def = Map::Legacy(LegacyMap {
id: 0, // def: aya_obj::maps::bpf_map_def {
pinning: aya_obj::maps::PinningType::None, // map_type: map_type as u32,
}, // key_size: size_of::<u32>() as u32,
section_index: 0, // value_size: size_of::<u32>() as u32,
section_kind: EbpfSectionKind::Undefined, // max_entries: 1,
symbol_index: None, // map_flags: 0,
data: vec![], // id: 0,
}); // pinning: aya_obj::maps::PinningType::None,
// },
let map = MapData::create(def, "", None); // section_index: 0,
// section_kind: EbpfSectionKind::Undefined,
match map { // symbol_index: None,
Ok(_) => Ok(true), // data: vec![],
Err(e) => match e { // });
MapError::CreateError { name: _, code: _, ref io_error } => match io_error.kind() {
std::io::ErrorKind::InvalidInput => { // let map = MapData::create(def, "", None);
// InvalidInput is the return kind for unsupported map
Ok(false) // match map {
} // Ok(_) => Ok(true),
_ => Err(FeatureError::MapError(e)) // Err(e) => match e {
} // MapError::CreateError { name: _, code: _, ref io_error } => match io_error.kind() {
_ => { // std::io::ErrorKind::InvalidInput => {
Err(FeatureError::MapError(e)) // // InvalidInput is the return kind for unsupported map
} // Ok(false)
} // }
} // _ => Err(FeatureError::MapError(e))
} // }
// _ => {
/// Returns `true` if `map_type` is supported. // Err(FeatureError::MapError(e))
/// // }
/// # Example // }
/// // }
/// ```no_run // }
/// use aya::features::is_map_type_supported;
/// // /// Returns `true` if `map_type` is supported.
/// if is_map_type_supported(bpf_map_type::BPF_MAP_TYPE_RINGBUF)? { // ///
/// println!("Ringbuf is supported!"); // /// # Example
/// } // ///
/// ``` // /// ```no_run
pub fn is_map_type_supported(map_type: bpf_map_type) -> Result<bool> { // /// use aya::features::is_map_type_supported;
probe_map_create(map_type) // ///
} // /// if is_map_type_supported(bpf_map_type::BPF_MAP_TYPE_RINGBUF)? {
// /// println!("Ringbuf is supported!");
/// Returns `true` if the kernel supports `Ringbuf` (`BPF_MAP_TYPE_RINGBUF`). // /// }
/// // /// ```
/// # Example // pub fn is_map_type_supported(map_type: bpf_map_type) -> Result<bool> {
/// // probe_map_create(map_type)
/// ```no_run // }
/// use aya::features::is_map_type_ringbuf_supported;
/// // /// Returns `true` if the kernel supports `Ringbuf` (`BPF_MAP_TYPE_RINGBUF`).
/// if is_map_type_ringbuf_supported()? { // ///
/// println!("Ringbuf is supported!"); // /// # Example
/// } // ///
/// ``` // /// ```no_run
pub fn is_map_type_ringbuf_supported() -> Result<bool> { // /// use aya::features::is_map_type_ringbuf_supported;
probe_map_create(bpf_map_type::BPF_MAP_TYPE_RINGBUF) // ///
} // /// if is_map_type_ringbuf_supported()? {
// /// println!("Ringbuf is supported!");
#[cfg(test)] // /// }
mod tests { // /// ```
use std::os::fd::IntoRawFd; // pub fn is_map_type_ringbuf_supported() -> Result<bool> {
// probe_map_create(bpf_map_type::BPF_MAP_TYPE_RINGBUF)
use aya_obj::generated::bpf_cmd; // }
use crate::sys::{override_syscall, Syscall}; // #[cfg(test)]
// mod tests {
use super::*; // use std::os::fd::IntoRawFd;
#[test] // use aya_obj::generated::bpf_cmd;
fn test_probe_map_create_success() {
override_syscall(|syscall| { // use crate::sys::{override_syscall, Syscall};
match syscall {
Syscall::Ebpf{cmd, attr} => { // use super::*;
assert_eq!(cmd, bpf_cmd::BPF_MAP_CREATE);
// #[test]
let u = unsafe { &mut attr.__bindgen_anon_1 }; // fn test_probe_map_create_success() {
// override_syscall(|syscall| {
assert_eq!(u.map_type, bpf_map_type::BPF_MAP_TYPE_RINGBUF as u32); // match syscall {
assert_eq!(u.key_size, size_of::<u32>() as u32); // Syscall::Ebpf{cmd, attr} => {
assert_eq!(u.value_size, size_of::<u32>() as u32); // assert_eq!(cmd, bpf_cmd::BPF_MAP_CREATE);
}
_ => { // let u = unsafe { &mut attr.__bindgen_anon_1 };
panic!();
} // assert_eq!(u.map_type, bpf_map_type::BPF_MAP_TYPE_RINGBUF as u32);
} // assert_eq!(u.key_size, size_of::<u32>() as u32);
// assert_eq!(u.value_size, size_of::<u32>() as u32);
let fd = std::fs::File::open("/dev/null").unwrap().into_raw_fd(); // }
Ok(fd as i64) // _ => {
}); // panic!();
// }
let supported = probe_map_create(bpf_map_type::BPF_MAP_TYPE_RINGBUF).unwrap(); // }
assert!(supported);
} // let fd = std::fs::File::open("/dev/null").unwrap().into_raw_fd();
// Ok(fd as i64)
#[test] // });
fn test_probe_map_create_failed() {
override_syscall(|syscall| { // let supported = probe_map_create(bpf_map_type::BPF_MAP_TYPE_RINGBUF).unwrap();
match syscall { // assert!(supported);
Syscall::Ebpf{cmd, attr} => { // }
assert_eq!(cmd, bpf_cmd::BPF_MAP_CREATE);
// #[test]
let u = unsafe { &mut attr.__bindgen_anon_1 }; // fn test_probe_map_create_failed() {
// override_syscall(|syscall| {
assert_eq!(u.map_type, bpf_map_type::BPF_MAP_TYPE_RINGBUF as u32); // match syscall {
assert_eq!(u.key_size, size_of::<u32>() as u32); // Syscall::Ebpf{cmd, attr} => {
assert_eq!(u.value_size, size_of::<u32>() as u32); // assert_eq!(cmd, bpf_cmd::BPF_MAP_CREATE);
}
_ => { // let u = unsafe { &mut attr.__bindgen_anon_1 };
panic!();
} // assert_eq!(u.map_type, bpf_map_type::BPF_MAP_TYPE_RINGBUF as u32);
} // assert_eq!(u.key_size, size_of::<u32>() as u32);
// assert_eq!(u.value_size, size_of::<u32>() as u32);
Err((-1, std::io::Error::from_raw_os_error(libc::EINVAL))) // }
}); // _ => {
// panic!();
let supported = probe_map_create(bpf_map_type::BPF_MAP_TYPE_RINGBUF).unwrap(); // }
assert!(!supported); // }
}
// Err((-1, std::io::Error::from_raw_os_error(libc::EINVAL)))
#[test] // });
fn test_probe_map_create_unknown_error() {
override_syscall(|syscall| { // let supported = probe_map_create(bpf_map_type::BPF_MAP_TYPE_RINGBUF).unwrap();
match syscall { // assert!(!supported);
Syscall::Ebpf{cmd, attr} => { // }
assert_eq!(cmd, bpf_cmd::BPF_MAP_CREATE);
// #[test]
let u = unsafe { &mut attr.__bindgen_anon_1 }; // fn test_probe_map_create_unknown_error() {
// override_syscall(|syscall| {
assert_eq!(u.map_type, bpf_map_type::BPF_MAP_TYPE_RINGBUF as u32); // match syscall {
assert_eq!(u.key_size, size_of::<u32>() as u32); // Syscall::Ebpf{cmd, attr} => {
assert_eq!(u.value_size, size_of::<u32>() as u32); // assert_eq!(cmd, bpf_cmd::BPF_MAP_CREATE);
}
_ => { // let u = unsafe { &mut attr.__bindgen_anon_1 };
panic!();
} // assert_eq!(u.map_type, bpf_map_type::BPF_MAP_TYPE_RINGBUF as u32);
} // assert_eq!(u.key_size, size_of::<u32>() as u32);
// assert_eq!(u.value_size, size_of::<u32>() as u32);
Err((-1, std::io::Error::from_raw_os_error(libc::EPERM))) // }
}); // _ => {
// panic!();
assert!(probe_map_create(bpf_map_type::BPF_MAP_TYPE_RINGBUF).is_err()); // }
} // }
}
// Err((-1, std::io::Error::from_raw_os_error(libc::EPERM)))
// });
// assert!(probe_map_create(bpf_map_type::BPF_MAP_TYPE_RINGBUF).is_err());
// }
// }

@ -990,6 +990,36 @@ pub(crate) fn is_btf_type_tag_supported() -> bool {
bpf_load_btf(btf_bytes.as_slice(), &mut [], Default::default()).is_ok() bpf_load_btf(btf_bytes.as_slice(), &mut [], Default::default()).is_ok()
} }
pub(crate) fn is_map_type_supported(map_type: bpf_map_type) -> bool {
map_create(map_type)
}
pub(crate) fn is_ringbuf_supported() -> bool {
map_create(bpf_map_type::BPF_MAP_TYPE_RINGBUF)
}
fn map_create(map_type: bpf_map_type ) -> bool {
let def = obj::Map::Legacy(LegacyMap {
def: aya_obj::maps::bpf_map_def {
map_type: map_type as u32,
key_size: std::mem::size_of::<u32>() as u32,
value_size: std::mem::size_of::<u32>() as u32,
max_entries: 1,
map_flags: 0,
id: 0,
pinning: aya_obj::maps::PinningType::None,
},
section_index: 0,
section_kind: EbpfSectionKind::Undefined,
symbol_index: None,
data: vec![],
});
let map = MapData::create(def, "", None);
map.is_ok()
}
fn bpf_prog_load(attr: &mut bpf_attr) -> SysResult<OwnedFd> { fn bpf_prog_load(attr: &mut bpf_attr) -> SysResult<OwnedFd> {
// SAFETY: BPF_PROG_LOAD returns a new file descriptor. // SAFETY: BPF_PROG_LOAD returns a new file descriptor.
unsafe { fd_sys_bpf(bpf_cmd::BPF_PROG_LOAD, attr) } unsafe { fd_sys_bpf(bpf_cmd::BPF_PROG_LOAD, attr) }
@ -1091,11 +1121,64 @@ pub(crate) fn retry_with_verifier_logs<T>(
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use std::os::fd::IntoRawFd;
use libc::{EBADF, EINVAL}; use libc::{EBADF, EINVAL};
use super::*; use super::*;
use crate::sys::override_syscall; use crate::sys::override_syscall;
#[test]
fn test_probe_map_create_success() {
override_syscall(|syscall| {
match syscall {
Syscall::Ebpf{cmd, attr} => {
assert_eq!(cmd, bpf_cmd::BPF_MAP_CREATE);
let u = unsafe { &mut attr.__bindgen_anon_1 };
assert_eq!(u.map_type, bpf_map_type::BPF_MAP_TYPE_RINGBUF as u32);
assert_eq!(u.key_size, std::mem::size_of::<u32>() as u32);
assert_eq!(u.value_size, std::mem::size_of::<u32>() as u32);
}
_ => {
panic!();
}
}
let fd = std::fs::File::open("/dev/null").unwrap().into_raw_fd();
Ok(fd as i64)
});
let supported = map_create(bpf_map_type::BPF_MAP_TYPE_RINGBUF);
assert!(supported);
}
#[test]
fn test_probe_map_create_failed() {
override_syscall(|syscall| {
match syscall {
Syscall::Ebpf{cmd, attr} => {
assert_eq!(cmd, bpf_cmd::BPF_MAP_CREATE);
let u = unsafe { &mut attr.__bindgen_anon_1 };
assert_eq!(u.map_type, bpf_map_type::BPF_MAP_TYPE_RINGBUF as u32);
assert_eq!(u.key_size, std::mem::size_of::<u32>() as u32);
assert_eq!(u.value_size, std::mem::size_of::<u32>() as u32);
}
_ => {
panic!();
}
}
Err((-1, std::io::Error::from_raw_os_error(libc::EINVAL)))
});
let supported = map_create(bpf_map_type::BPF_MAP_TYPE_RINGBUF);
assert!(!supported);
}
#[test] #[test]
fn test_perf_link_supported() { fn test_perf_link_supported() {
override_syscall(|call| match call { override_syscall(|call| match call {

Loading…
Cancel
Save