use core::ffi::c_void;
use std::ffi::CStr;
use std::ffi::CString;
use std::ffi::OsStr;
use std::mem;
use std::os::unix::ffi::OsStrExt as _;
use std::path::Path;
use std::ptr;
use std::ptr::addr_of;
use std::ptr::NonNull;
use crate::map::map_fd;
use crate::set_print;
use crate::util;
use crate::util::validate_bpf_ret;
use crate::Btf;
use crate::ErrorExt as _;
use crate::Map;
use crate::MapMut;
use crate::OpenMap;
use crate::OpenMapMut;
use crate::OpenProgram;
use crate::OpenProgramMut;
use crate::PrintLevel;
use crate::Program;
use crate::ProgramMut;
use crate::Result;
#[derive(Debug)]
pub struct MapIter<'obj> {
obj: &'obj libbpf_sys::bpf_object,
last: *mut libbpf_sys::bpf_map,
}
impl<'obj> MapIter<'obj> {
pub fn new(obj: &'obj libbpf_sys::bpf_object) -> Self {
Self {
obj,
last: ptr::null_mut(),
}
}
}
impl Iterator for MapIter<'_> {
type Item = NonNull<libbpf_sys::bpf_map>;
fn next(&mut self) -> Option<Self::Item> {
self.last = unsafe { libbpf_sys::bpf_object__next_map(self.obj, self.last) };
NonNull::new(self.last)
}
}
#[derive(Debug)]
pub struct ProgIter<'obj> {
obj: &'obj libbpf_sys::bpf_object,
last: *mut libbpf_sys::bpf_program,
}
impl<'obj> ProgIter<'obj> {
pub fn new(obj: &'obj libbpf_sys::bpf_object) -> Self {
Self {
obj,
last: ptr::null_mut(),
}
}
}
impl Iterator for ProgIter<'_> {
type Item = NonNull<libbpf_sys::bpf_program>;
fn next(&mut self) -> Option<Self::Item> {
self.last = unsafe { libbpf_sys::bpf_object__next_program(self.obj, self.last) };
NonNull::new(self.last)
}
}
pub trait AsRawLibbpf {
type LibbpfType;
fn as_libbpf_object(&self) -> NonNull<Self::LibbpfType>;
}
#[derive(Debug)]
pub struct ObjectBuilder {
name: Option<CString>,
pin_root_path: Option<CString>,
opts: libbpf_sys::bpf_object_open_opts,
}
impl Default for ObjectBuilder {
fn default() -> Self {
let opts = libbpf_sys::bpf_object_open_opts {
sz: mem::size_of::<libbpf_sys::bpf_object_open_opts>() as libbpf_sys::size_t,
object_name: ptr::null(),
relaxed_maps: false,
pin_root_path: ptr::null(),
kconfig: ptr::null(),
btf_custom_path: ptr::null(),
kernel_log_buf: ptr::null_mut(),
kernel_log_size: 0,
kernel_log_level: 0,
..Default::default()
};
Self {
name: None,
pin_root_path: None,
opts,
}
}
}
impl ObjectBuilder {
pub fn name<T: AsRef<str>>(&mut self, name: T) -> Result<&mut Self> {
self.name = Some(util::str_to_cstring(name.as_ref())?);
self.opts.object_name = self.name.as_ref().map_or(ptr::null(), |p| p.as_ptr());
Ok(self)
}
pub fn pin_root_path<T: AsRef<Path>>(&mut self, path: T) -> Result<&mut Self> {
self.pin_root_path = Some(util::path_to_cstring(path)?);
self.opts.pin_root_path = self
.pin_root_path
.as_ref()
.map_or(ptr::null(), |p| p.as_ptr());
Ok(self)
}
pub fn relaxed_maps(&mut self, relaxed_maps: bool) -> &mut Self {
self.opts.relaxed_maps = relaxed_maps;
self
}
pub fn debug(&mut self, dbg: bool) -> &mut Self {
if dbg {
set_print(Some((PrintLevel::Debug, |_, s| print!("{s}"))));
} else {
set_print(None);
}
self
}
pub fn open_file<P: AsRef<Path>>(&mut self, path: P) -> Result<OpenObject> {
let path = path.as_ref();
let path_c = util::path_to_cstring(path)?;
let path_ptr = path_c.as_ptr();
let opts_ptr = self.as_libbpf_object().as_ptr();
let ptr = unsafe { libbpf_sys::bpf_object__open_file(path_ptr, opts_ptr) };
let ptr = validate_bpf_ret(ptr)
.with_context(|| format!("failed to open object from `{}`", path.display()))?;
let obj = unsafe { OpenObject::from_ptr(ptr) };
Ok(obj)
}
pub fn open_memory(&mut self, mem: &[u8]) -> Result<OpenObject> {
let opts_ptr = self.as_libbpf_object().as_ptr();
let ptr = unsafe {
libbpf_sys::bpf_object__open_mem(
mem.as_ptr() as *const c_void,
mem.len() as libbpf_sys::size_t,
opts_ptr,
)
};
let ptr = validate_bpf_ret(ptr).context("failed to open object from memory")?;
let obj = unsafe { OpenObject::from_ptr(ptr) };
Ok(obj)
}
}
impl AsRawLibbpf for ObjectBuilder {
type LibbpfType = libbpf_sys::bpf_object_open_opts;
fn as_libbpf_object(&self) -> NonNull<Self::LibbpfType> {
unsafe { NonNull::new_unchecked(addr_of!(self.opts).cast_mut()) }
}
}
#[derive(Debug)]
#[repr(transparent)]
pub struct OpenObject {
ptr: NonNull<libbpf_sys::bpf_object>,
}
impl OpenObject {
pub unsafe fn from_ptr(ptr: NonNull<libbpf_sys::bpf_object>) -> Self {
Self { ptr }
}
pub fn take_ptr(mut self) -> NonNull<libbpf_sys::bpf_object> {
let ptr = {
let Self { ptr } = &mut self;
*ptr
};
mem::forget(self);
ptr
}
pub fn name(&self) -> Option<&OsStr> {
let name_ptr = unsafe { libbpf_sys::bpf_object__name(self.ptr.as_ptr()) };
let err = unsafe { libbpf_sys::libbpf_get_error(name_ptr as *const _) };
if err != 0 {
return None
}
let name_c_str = unsafe { CStr::from_ptr(name_ptr) };
let str = OsStr::from_bytes(name_c_str.to_bytes());
Some(str)
}
pub fn maps(&self) -> impl Iterator<Item = OpenMap<'_>> {
MapIter::new(unsafe { self.ptr.as_ref() }).map(|ptr| unsafe { OpenMap::new(ptr.as_ref()) })
}
pub fn maps_mut(&mut self) -> impl Iterator<Item = OpenMapMut<'_>> {
MapIter::new(unsafe { self.ptr.as_ref() })
.map(|mut ptr| unsafe { OpenMapMut::new_mut(ptr.as_mut()) })
}
pub fn progs(&self) -> impl Iterator<Item = OpenProgram<'_>> {
ProgIter::new(unsafe { self.ptr.as_ref() })
.map(|ptr| unsafe { OpenProgram::new(ptr.as_ref()) })
}
pub fn progs_mut(&mut self) -> impl Iterator<Item = OpenProgramMut<'_>> {
ProgIter::new(unsafe { self.ptr.as_ref() })
.map(|mut ptr| unsafe { OpenProgramMut::new_mut(ptr.as_mut()) })
}
pub fn load(self) -> Result<Object> {
let ret = unsafe { libbpf_sys::bpf_object__load(self.ptr.as_ptr()) };
let () = util::parse_ret(ret)?;
let obj = unsafe { Object::from_ptr(self.take_ptr()) };
Ok(obj)
}
}
impl AsRawLibbpf for OpenObject {
type LibbpfType = libbpf_sys::bpf_object;
fn as_libbpf_object(&self) -> NonNull<Self::LibbpfType> {
self.ptr
}
}
impl Drop for OpenObject {
fn drop(&mut self) {
unsafe {
libbpf_sys::bpf_object__close(self.ptr.as_ptr());
}
}
}
#[derive(Debug)]
#[repr(transparent)]
pub struct Object {
ptr: NonNull<libbpf_sys::bpf_object>,
}
impl Object {
pub unsafe fn from_ptr(ptr: NonNull<libbpf_sys::bpf_object>) -> Self {
Self { ptr }
}
pub fn name(&self) -> Option<&OsStr> {
let name_ptr = unsafe { libbpf_sys::bpf_object__name(self.ptr.as_ptr()) };
let err = unsafe { libbpf_sys::libbpf_get_error(name_ptr as *const _) };
if err != 0 {
return None
}
let name_c_str = unsafe { CStr::from_ptr(name_ptr) };
let str = OsStr::from_bytes(name_c_str.to_bytes());
Some(str)
}
pub fn btf(&self) -> Result<Option<Btf<'_>>> {
Btf::from_bpf_object(unsafe { &*self.ptr.as_ptr() })
}
pub fn maps(&self) -> impl Iterator<Item = Map<'_>> {
MapIter::new(unsafe { self.ptr.as_ref() })
.filter(|ptr| map_fd(*ptr).is_some())
.map(|ptr| unsafe { Map::new(ptr.as_ref()) })
}
pub fn maps_mut(&mut self) -> impl Iterator<Item = MapMut<'_>> {
MapIter::new(unsafe { self.ptr.as_ref() })
.filter(|ptr| map_fd(*ptr).is_some())
.map(|mut ptr| unsafe { MapMut::new_mut(ptr.as_mut()) })
}
pub fn progs(&self) -> impl Iterator<Item = Program<'_>> {
ProgIter::new(unsafe { self.ptr.as_ref() }).map(|ptr| unsafe { Program::new(ptr.as_ref()) })
}
pub fn progs_mut(&self) -> impl Iterator<Item = ProgramMut<'_>> {
ProgIter::new(unsafe { self.ptr.as_ref() })
.map(|mut ptr| unsafe { ProgramMut::new_mut(ptr.as_mut()) })
}
}
impl AsRawLibbpf for Object {
type LibbpfType = libbpf_sys::bpf_object;
fn as_libbpf_object(&self) -> NonNull<Self::LibbpfType> {
self.ptr
}
}
impl Drop for Object {
fn drop(&mut self) {
unsafe {
libbpf_sys::bpf_object__close(self.ptr.as_ptr());
}
}
}