use core::convert::TryInto;
use core::default::Default;
use core::marker::PhantomData;
use core::mem;
use cty::*;
use crate::bindings::*;
use crate::helpers::*;
#[repr(transparent)]
pub struct HashMap<K, V> {
def: bpf_map_def,
_k: PhantomData<K>,
_v: PhantomData<V>,
}
impl<K, V> HashMap<K, V> {
pub const fn with_max_entries(max_entries: u32) -> Self {
Self {
def: bpf_map_def {
type_: bpf_map_type_BPF_MAP_TYPE_HASH,
key_size: mem::size_of::<K>() as u32,
value_size: mem::size_of::<V>() as u32,
max_entries,
map_flags: 0,
},
_k: PhantomData,
_v: PhantomData,
}
}
#[inline]
pub fn get(&mut self, key: &K) -> Option<&V> {
unsafe {
let value = bpf_map_lookup_elem(
&mut self.def as *mut _ as *mut c_void,
key as *const _ as *const c_void,
);
if value.is_null() {
None
} else {
Some(&*(value as *const V))
}
}
}
#[inline]
pub fn get_mut(&mut self, key: &K) -> Option<&mut V> {
unsafe {
let value = bpf_map_lookup_elem(
&mut self.def as *mut _ as *mut c_void,
key as *const _ as *const c_void,
);
if value.is_null() {
None
} else {
Some(&mut *(value as *mut V))
}
}
}
#[inline]
pub fn set(&mut self, key: &K, value: &V) {
unsafe {
bpf_map_update_elem(
&mut self.def as *mut _ as *mut c_void,
key as *const _ as *const c_void,
value as *const _ as *const c_void,
BPF_ANY.into(),
);
}
}
#[inline]
pub fn delete(&mut self, key: &K) {
unsafe {
bpf_map_delete_elem(
&mut self.def as *mut _ as *mut c_void,
key as *const _ as *const c_void,
);
}
}
}
#[derive(Debug, Copy, Clone)]
pub struct PerfMapFlags {
index: Option<u32>,
pub(crate) xdp_size: u32,
}
impl Default for PerfMapFlags {
#[inline]
fn default() -> Self {
PerfMapFlags {
index: None,
xdp_size: 0,
}
}
}
impl PerfMapFlags {
#[inline]
pub fn new() -> Self {
Default::default()
}
#[inline]
pub fn with_xdp_size(size: u32) -> Self {
*PerfMapFlags::new().xdp_size(size)
}
#[inline]
pub fn index(&mut self, index: u32) -> &mut PerfMapFlags {
self.index = Some(index);
self
}
#[inline]
pub fn xdp_size(&mut self, size: u32) -> &mut PerfMapFlags {
self.xdp_size = size;
self
}
}
impl From<PerfMapFlags> for u64 {
#[inline]
fn from(flags: PerfMapFlags) -> u64 {
(flags.xdp_size as u64) << 32
| (flags.index.unwrap_or_else(|| BPF_F_CURRENT_CPU.try_into().unwrap()) as u64)
}
}
#[repr(transparent)]
pub struct PerfMap<T> {
def: bpf_map_def,
_event: PhantomData<T>,
}
impl<T> PerfMap<T> {
pub const fn with_max_entries(max_entries: u32) -> Self {
Self {
def: bpf_map_def {
type_: bpf_map_type_BPF_MAP_TYPE_PERF_EVENT_ARRAY,
key_size: mem::size_of::<u32>() as u32,
value_size: mem::size_of::<u32>() as u32,
max_entries,
map_flags: 0,
},
_event: PhantomData,
}
}
#[inline]
pub fn insert<C>(&mut self, ctx: *mut C, data: &T) {
self.insert_with_flags(ctx, data, PerfMapFlags::default())
}
#[inline]
pub fn insert_with_flags<C>(&mut self, ctx: *mut C, data: &T, flags: PerfMapFlags) {
bpf_perf_event_output(
ctx as *mut _ as *mut c_void,
&mut self.def as *mut _ as *mut c_void,
flags.into(),
data as *const _ as *const c_void,
mem::size_of::<T>() as u64,
);
}
}
const BPF_MAX_STACK_DEPTH: usize = 127;
#[repr(transparent)]
pub struct StackTrace {
def: bpf_map_def
}
#[repr(C)]
struct BpfStackFrames {
ip: [u64; BPF_MAX_STACK_DEPTH]
}
impl StackTrace {
pub const fn with_max_entries(cap: u32) -> Self {
StackTrace {
def: bpf_map_def {
type_: bpf_map_type_BPF_MAP_TYPE_STACK_TRACE,
key_size: mem::size_of::<u32>() as u32,
value_size: mem::size_of::<BpfStackFrames>() as u32,
max_entries: cap,
map_flags: 0
}
}
}
pub unsafe fn stack_id(&mut self, ctx: *mut pt_regs, flag: u64) -> Result<c_int, c_int> {
let ret = bpf_get_stackid(ctx as _, &mut self.def as *mut _ as _, flag);
if ret >= 0 {
Ok(ret)
} else {
Err(ret)
}
}
}
#[repr(transparent)]
pub struct ProgramArray {
def: bpf_map_def,
}
impl ProgramArray {
pub const fn with_max_entries(max_entries: u32) -> Self {
Self {
def: bpf_map_def {
type_: bpf_map_type_BPF_MAP_TYPE_PROG_ARRAY,
key_size: mem::size_of::<u32>() as u32,
value_size: mem::size_of::<u32>() as u32,
max_entries,
map_flags: 0,
},
}
}
pub unsafe fn tail_call<C>(&mut self, ctx: *mut C, index: u32) -> Result<(), i32> {
let ret = bpf_tail_call(ctx as *mut _, &mut self.def as *mut _ as *mut c_void, index);
if ret < 0 {
return Err(ret);
}
Ok(())
}
}