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>;
fn probe_map_create(map_type: bpf_map_type) -> Result<bool> {
let def = Map::Legacy(LegacyMap {
def: aya_obj::maps::bpf_map_def {
map_type: map_type as u32,
key_size: size_of::<u32>() as u32,
value_size: 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);
match map {
Ok(_) => Ok(true),
Err(e) => match e {
MapError::CreateError { name: _, code: _, ref io_error } => match io_error.kind() {
std::io::ErrorKind::InvalidInput => {
// InvalidInput is the return kind for unsupported map
Ok(false)
}
_ => Err(FeatureError::MapError(e))
}
_ => {
Err(FeatureError::MapError(e))
}
}
}
}
/// Returns `true` if `map_type` is supported. pub fn is_ringbuf_supported() -> bool {
/// ringbuf_supported()
/// # Example
///
/// ```no_run
/// use aya::features::is_map_type_supported;
///
/// if is_map_type_supported(bpf_map_type::BPF_MAP_TYPE_RINGBUF)? {
/// println!("Ringbuf is supported!");
/// }
/// ```
pub fn is_map_type_supported(map_type: bpf_map_type) -> Result<bool> {
probe_map_create(map_type)
} }
/// Returns `true` if the kernel supports `Ringbuf` (`BPF_MAP_TYPE_RINGBUF`). // /// Result type used for the feature helpers
/// // pub type Result<T> = std::result::Result<T, FeatureError>;
/// # Example
/// // fn probe_map_create(map_type: bpf_map_type) -> Result<bool> {
/// ```no_run
/// use aya::features::is_map_type_ringbuf_supported; // let def = Map::Legacy(LegacyMap {
/// // def: aya_obj::maps::bpf_map_def {
/// if is_map_type_ringbuf_supported()? { // map_type: map_type as u32,
/// println!("Ringbuf is supported!"); // key_size: size_of::<u32>() as u32,
/// } // value_size: size_of::<u32>() as u32,
/// ``` // max_entries: 1,
pub fn is_map_type_ringbuf_supported() -> Result<bool> { // map_flags: 0,
probe_map_create(bpf_map_type::BPF_MAP_TYPE_RINGBUF) // id: 0,
} // pinning: aya_obj::maps::PinningType::None,
// },
#[cfg(test)] // section_index: 0,
mod tests { // section_kind: EbpfSectionKind::Undefined,
use std::os::fd::IntoRawFd; // symbol_index: None,
// data: vec![],
use aya_obj::generated::bpf_cmd; // });
use crate::sys::{override_syscall, Syscall}; // let map = MapData::create(def, "", None);
use super::*; // match map {
// Ok(_) => Ok(true),
#[test] // Err(e) => match e {
fn test_probe_map_create_success() { // MapError::CreateError { name: _, code: _, ref io_error } => match io_error.kind() {
override_syscall(|syscall| { // std::io::ErrorKind::InvalidInput => {
match syscall { // // InvalidInput is the return kind for unsupported map
Syscall::Ebpf{cmd, attr} => { // Ok(false)
assert_eq!(cmd, bpf_cmd::BPF_MAP_CREATE); // }
// _ => Err(FeatureError::MapError(e))
let u = unsafe { &mut attr.__bindgen_anon_1 }; // }
// _ => {
assert_eq!(u.map_type, bpf_map_type::BPF_MAP_TYPE_RINGBUF as u32); // Err(FeatureError::MapError(e))
assert_eq!(u.key_size, size_of::<u32>() as u32); // }
assert_eq!(u.value_size, size_of::<u32>() as u32); // }
} // }
_ => { // }
panic!();
} // /// Returns `true` if `map_type` is supported.
} // ///
// /// # Example
let fd = std::fs::File::open("/dev/null").unwrap().into_raw_fd(); // ///
Ok(fd as i64) // /// ```no_run
}); // /// use aya::features::is_map_type_supported;
// ///
let supported = probe_map_create(bpf_map_type::BPF_MAP_TYPE_RINGBUF).unwrap(); // /// if is_map_type_supported(bpf_map_type::BPF_MAP_TYPE_RINGBUF)? {
assert!(supported); // /// println!("Ringbuf is supported!");
} // /// }
// /// ```
#[test] // pub fn is_map_type_supported(map_type: bpf_map_type) -> Result<bool> {
fn test_probe_map_create_failed() { // probe_map_create(map_type)
override_syscall(|syscall| { // }
match syscall {
Syscall::Ebpf{cmd, attr} => { // /// Returns `true` if the kernel supports `Ringbuf` (`BPF_MAP_TYPE_RINGBUF`).
assert_eq!(cmd, bpf_cmd::BPF_MAP_CREATE); // ///
// /// # Example
let u = unsafe { &mut attr.__bindgen_anon_1 }; // ///
// /// ```no_run
assert_eq!(u.map_type, bpf_map_type::BPF_MAP_TYPE_RINGBUF as u32); // /// use aya::features::is_map_type_ringbuf_supported;
assert_eq!(u.key_size, size_of::<u32>() as u32); // ///
assert_eq!(u.value_size, size_of::<u32>() as u32); // /// if is_map_type_ringbuf_supported()? {
} // /// println!("Ringbuf is supported!");
_ => { // /// }
panic!(); // /// ```
} // pub fn is_map_type_ringbuf_supported() -> Result<bool> {
} // probe_map_create(bpf_map_type::BPF_MAP_TYPE_RINGBUF)
// }
Err((-1, std::io::Error::from_raw_os_error(libc::EINVAL)))
}); // #[cfg(test)]
// mod tests {
let supported = probe_map_create(bpf_map_type::BPF_MAP_TYPE_RINGBUF).unwrap(); // use std::os::fd::IntoRawFd;
assert!(!supported);
} // use aya_obj::generated::bpf_cmd;
#[test] // use crate::sys::{override_syscall, Syscall};
fn test_probe_map_create_unknown_error() {
override_syscall(|syscall| { // use super::*;
match syscall {
Syscall::Ebpf{cmd, attr} => { // #[test]
assert_eq!(cmd, bpf_cmd::BPF_MAP_CREATE); // fn test_probe_map_create_success() {
// override_syscall(|syscall| {
let u = unsafe { &mut attr.__bindgen_anon_1 }; // match syscall {
// Syscall::Ebpf{cmd, attr} => {
assert_eq!(u.map_type, bpf_map_type::BPF_MAP_TYPE_RINGBUF as u32); // assert_eq!(cmd, bpf_cmd::BPF_MAP_CREATE);
assert_eq!(u.key_size, size_of::<u32>() as u32);
assert_eq!(u.value_size, size_of::<u32>() as u32); // let u = unsafe { &mut attr.__bindgen_anon_1 };
}
_ => { // assert_eq!(u.map_type, bpf_map_type::BPF_MAP_TYPE_RINGBUF as u32);
panic!(); // 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());
} // let fd = std::fs::File::open("/dev/null").unwrap().into_raw_fd();
} // Ok(fd as i64)
// });
// let supported = probe_map_create(bpf_map_type::BPF_MAP_TYPE_RINGBUF).unwrap();
// 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, size_of::<u32>() as u32);
// assert_eq!(u.value_size, size_of::<u32>() as u32);
// }
// _ => {
// panic!();
// }
// }
// Err((-1, std::io::Error::from_raw_os_error(libc::EINVAL)))
// });
// let supported = probe_map_create(bpf_map_type::BPF_MAP_TYPE_RINGBUF).unwrap();
// assert!(!supported);
// }
// #[test]
// fn test_probe_map_create_unknown_error() {
// 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, size_of::<u32>() as u32);
// assert_eq!(u.value_size, size_of::<u32>() as u32);
// }
// _ => {
// panic!();
// }
// }
// 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