use std::ptr;
use super::kind;
pub struct MapRef {
name: &'static str,
inner: *mut libbpf_sys::bpf_map,
}
impl kind::AppItem for MapRef {
const MAP: usize = 1;
const PROG: usize = 0;
fn named(name: &'static str) -> Self {
MapRef {
name,
inner: ptr::null_mut(),
}
}
fn kind_mut(&mut self) -> kind::AppItemKindMut<'_> {
kind::AppItemKindMut::Map(self)
}
}
impl MapRef {
pub fn fd(&self) -> i32 {
unsafe { libbpf_sys::bpf_map__fd(self.inner) }
}
}
pub struct ProgRef {
name: &'static str,
prog: *mut libbpf_sys::bpf_program,
link: *mut libbpf_sys::bpf_link,
}
impl kind::AppItem for ProgRef {
const MAP: usize = 0;
const PROG: usize = 1;
fn named(name: &'static str) -> Self {
ProgRef {
name,
prog: ptr::null_mut(),
link: ptr::null_mut(),
}
}
fn kind_mut(&mut self) -> kind::AppItemKindMut<'_> {
kind::AppItemKindMut::Prog(self)
}
}
pub struct Skeleton<App>
where
App: BpfApp,
{
inner: libbpf_sys::bpf_object_skeleton,
obj: Box<*mut libbpf_sys::bpf_object>,
pub app: Box<App>,
}
pub trait BpfApp {
const MAP_CNT: usize;
const PROG_CNT: usize;
fn instance() -> Self;
fn as_mut_map(&mut self, index: usize) -> Option<&mut MapRef>;
fn as_mut_prog(&mut self, index: usize) -> Option<&mut ProgRef>;
}
impl<App> Skeleton<App>
where
App: BpfApp,
{
pub fn open(name: &'static str, code: &'static [u8]) -> Result<Self, i32> {
use std::{
mem, slice,
alloc::{Layout, alloc_zeroed},
};
let mut app = Box::new(App::instance());
let mut obj = Box::<*mut libbpf_sys::bpf_object>::new(ptr::null_mut());
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,
relaxed_core_relocs: false,
__bindgen_padding_0: [0; 6],
pin_root_path: ptr::null(),
attach_prog_fd: 0,
__bindgen_padding_1: [0; 4],
kconfig: ptr::null(),
btf_custom_path: ptr::null(),
kernel_log_buf: ptr::null_mut(),
kernel_log_size: 0,
kernel_log_level: 0,
__bindgen_padding_2: [0; 4],
};
let map_l = Layout::array::<libbpf_sys::bpf_map_skeleton>(App::MAP_CNT).unwrap();
let prog_l = Layout::array::<libbpf_sys::bpf_prog_skeleton>(App::PROG_CNT).unwrap();
let mut s = libbpf_sys::bpf_object_skeleton {
sz: mem::size_of::<libbpf_sys::bpf_object_skeleton>() as _,
name: name.as_ptr() as _,
data: code.as_ptr() as *const _ as *mut _,
data_sz: code.len() as _,
obj: obj.as_mut(),
map_cnt: App::MAP_CNT as _,
map_skel_sz: mem::size_of::<libbpf_sys::bpf_map_skeleton>() as _,
maps: unsafe { alloc_zeroed(map_l) } as *mut libbpf_sys::bpf_map_skeleton,
prog_cnt: App::PROG_CNT as _,
prog_skel_sz: mem::size_of::<libbpf_sys::bpf_prog_skeleton>() as _,
progs: unsafe { alloc_zeroed(prog_l) } as *mut libbpf_sys::bpf_prog_skeleton,
};
let maps = unsafe { slice::from_raw_parts_mut(s.maps, App::MAP_CNT) };
for (i, s_map) in maps.iter_mut().enumerate() {
let map = app.as_mut_map(i).unwrap();
s_map.name = map.name.as_ptr() as _;
s_map.map = &mut map.inner;
s_map.mmaped = ptr::null_mut();
}
let progs = unsafe { slice::from_raw_parts_mut(s.progs, App::PROG_CNT) };
for (i, s_prog) in progs.iter_mut().enumerate() {
let prog = app.as_mut_prog(i).unwrap();
s_prog.name = prog.name.as_ptr() as _;
s_prog.prog = &mut prog.prog;
s_prog.link = &mut prog.link;
}
let c = unsafe { libbpf_sys::bpf_object__open_skeleton(&mut s, &opts) };
if c == 0 {
Ok(Skeleton { inner: s, obj, app })
} else {
Err(c)
}
}
pub fn load(&mut self) -> Result<(), i32> {
let c = unsafe { libbpf_sys::bpf_object__load_skeleton(&mut self.inner) };
let _ = self.obj.as_mut();
if c == 0 {
Ok(())
} else {
Err(c)
}
}
pub fn attach(&mut self) -> Result<(), i32> {
let c = unsafe { libbpf_sys::bpf_object__attach_skeleton(&mut self.inner) };
if c == 0 {
Ok(())
} else {
Err(c)
}
}
}
impl<App> Drop for Skeleton<App>
where
App: BpfApp,
{
fn drop(&mut self) {
let s = Box::new(self.inner);
unsafe { libbpf_sys::bpf_object__destroy_skeleton(Box::leak(s)) }
}
}