use core::{ cell::UnsafeCell, ffi::{c_long, c_void}, marker::PhantomData, mem, ptr::NonNull, }; use aya_ebpf_bindings::bindings::BPF_F_NO_PREALLOC; use crate::{ bindings::{bpf_map_def, bpf_map_type::BPF_MAP_TYPE_LPM_TRIE}, helpers::{bpf_map_delete_elem, bpf_map_lookup_elem, bpf_map_update_elem}, maps::PinningType, }; #[repr(transparent)] pub struct LpmTrie { def: UnsafeCell, _k: PhantomData, _v: PhantomData, } unsafe impl Sync for LpmTrie {} #[repr(C, packed)] pub struct Key { /// Represents the number of bits matched against. pub prefix_len: u32, /// Represents arbitrary data stored in the LpmTrie. pub data: K, } impl Key { pub fn new(prefix_len: u32, data: K) -> Self { Self { prefix_len, data } } } impl LpmTrie { pub const fn with_max_entries(max_entries: u32, flags: u32) -> LpmTrie { let flags = flags | BPF_F_NO_PREALLOC; LpmTrie { def: UnsafeCell::new(build_def::( BPF_MAP_TYPE_LPM_TRIE, max_entries, flags, PinningType::None, )), _k: PhantomData, _v: PhantomData, } } pub const fn pinned(max_entries: u32, flags: u32) -> LpmTrie { let flags = flags | BPF_F_NO_PREALLOC; LpmTrie { def: UnsafeCell::new(build_def::( BPF_MAP_TYPE_LPM_TRIE, max_entries, flags, PinningType::ByName, )), _k: PhantomData, _v: PhantomData, } } #[inline] pub fn get(&self, key: &Key) -> Option<&V> { unsafe { let value = bpf_map_lookup_elem(self.def.get() as *mut _, key as *const _ as *const c_void); // FIXME: alignment NonNull::new(value as *mut V).map(|p| p.as_ref()) } } #[inline] pub fn insert(&self, key: &Key, value: &V, flags: u64) -> Result<(), c_long> { let ret = unsafe { bpf_map_update_elem( self.def.get() as *mut _, key as *const _ as *const _, value as *const _ as *const _, flags, ) }; (ret == 0).then_some(()).ok_or(ret) } #[inline] pub fn remove(&self, key: &Key) -> Result<(), c_long> { let ret = unsafe { bpf_map_delete_elem(self.def.get() as *mut _, key as *const _ as *const c_void) }; (ret == 0).then_some(()).ok_or(ret) } } const fn build_def(ty: u32, max_entries: u32, flags: u32, pin: PinningType) -> bpf_map_def { bpf_map_def { type_: ty, key_size: mem::size_of::>() as u32, value_size: mem::size_of::() as u32, max_entries, map_flags: flags, id: 0, pinning: pin as u32, } }