@ -12,6 +12,7 @@ use crate::{
maps ::{ check_kv_size , hash_map , IterableMap , MapData , MapError , MapIter , MapKeys } ,
programs ::ProgramFd ,
sys ::{ bpf_map_lookup_elem , SyscallError } ,
FEATURES ,
} ;
use super ::dev_map ::DevMapValue ;
@ -45,7 +46,12 @@ pub struct DevMapHash<T> {
impl < T : Borrow < MapData > > DevMapHash < T > {
pub ( crate ) fn new ( map : T ) -> Result < Self , MapError > {
let data = map . borrow ( ) ;
check_kv_size ::< u32 , bpf_devmap_val > ( data ) ? ;
if FEATURES . devmap_hash_prog_id ( ) {
check_kv_size ::< u32 , bpf_devmap_val > ( data ) ? ;
} else {
check_kv_size ::< u32 , u32 > ( data ) ? ;
}
Ok ( Self { inner : map } )
}
@ -57,18 +63,30 @@ impl<T: Borrow<MapData>> DevMapHash<T> {
/// Returns [`MapError::SyscallError`] if `bpf_map_lookup_elem` fails.
pub fn get ( & self , key : u32 , flags : u64 ) -> Result < DevMapValue , MapError > {
let fd = self . inner . borrow ( ) . fd ;
let value = bpf_map_lookup_elem ( fd , & key , flags ) . map_err ( | ( _ , io_error ) | SyscallError {
call : "bpf_map_lookup_elem" ,
io_error ,
} ) ? ;
let value : bpf_devmap_val = value . ok_or ( MapError ::KeyNotFound ) ? ;
// SAFETY: map writes use fd, map reads use id.
// https://elixir.bootlin.com/linux/v6.2/source/include/uapi/linux/bpf.h#L6136
Ok ( DevMapValue {
ifindex : value . ifindex ,
prog_id : NonZeroU32 ::new ( unsafe { value . bpf_prog . id } ) ,
} )
let value = if FEATURES . devmap_hash_prog_id ( ) {
bpf_map_lookup_elem ::< _ , bpf_devmap_val > ( fd , & key , flags ) . map ( | value | {
value . map ( | value | DevMapValue {
ifindex : value . ifindex ,
// SAFETY: map writes use fd, map reads use id.
// https://elixir.bootlin.com/linux/v6.2/source/include/uapi/linux/bpf.h#L6149
prog_id : NonZeroU32 ::new ( unsafe { value . bpf_prog . id } ) ,
} )
} )
} else {
bpf_map_lookup_elem ::< _ , u32 > ( fd , & key , flags ) . map ( | value | {
value . map ( | ifindex | DevMapValue {
ifindex ,
prog_id : None ,
} )
} )
} ;
value
. map_err ( | ( _ , io_error ) | SyscallError {
call : "bpf_map_lookup_elem" ,
io_error ,
} ) ?
. ok_or ( MapError ::KeyNotFound )
}
/// An iterator over the elements of the devmap in arbitrary order.
@ -96,7 +114,9 @@ impl<T: BorrowMut<MapData>> DevMapHash<T> {
///
/// # Errors
///
/// Returns [`MapError::SyscallError`] if `bpf_map_update_elem` fails.
/// Returns [`MapError::SyscallError`] if `bpf_map_update_elem` fails,
/// [`MapError::ProgIdNotSupported`] if the kernel does not support program ids and one is
/// provided.
pub fn insert (
& mut self ,
key : u32 ,
@ -104,18 +124,25 @@ impl<T: BorrowMut<MapData>> DevMapHash<T> {
program : Option < & ProgramFd > ,
flags : u64 ,
) -> Result < ( ) , MapError > {
let value = bpf_devmap_val {
ifindex ,
bpf_prog : bpf_devmap_val__bindgen_ty_1 {
// Default is valid as the kernel will only consider fd > 0:
// https://elixir.bootlin.com/linux/v6.4.12/source/kernel/bpf/devmap.c#L866
// https://elixir.bootlin.com/linux/v6.4.12/source/kernel/bpf/devmap.c#L918
fd : program
. map ( | prog | prog . as_fd ( ) . as_raw_fd ( ) )
. unwrap_or_default ( ) ,
} ,
} ;
hash_map ::insert ( self . inner . borrow_mut ( ) , & key , & value , flags )
if FEATURES . devmap_hash_prog_id ( ) {
let value = bpf_devmap_val {
ifindex ,
bpf_prog : bpf_devmap_val__bindgen_ty_1 {
// Default is valid as the kernel will only consider fd > 0:
// https://elixir.bootlin.com/linux/v6.4.12/source/kernel/bpf/devmap.c#L866
// https://elixir.bootlin.com/linux/v6.4.12/source/kernel/bpf/devmap.c#L918
fd : program
. map ( | prog | prog . as_fd ( ) . as_raw_fd ( ) )
. unwrap_or_default ( ) ,
} ,
} ;
hash_map ::insert ( self . inner . borrow_mut ( ) , & key , & value , flags )
} else {
if program . is_some ( ) {
return Err ( MapError ::ProgIdNotSupported ) ;
}
hash_map ::insert ( self . inner . borrow_mut ( ) , & key , & ifindex , flags )
}
}
/// Removes a value from the map.