@ -54,7 +54,10 @@ use std::{
marker ::PhantomData ,
marker ::PhantomData ,
mem ,
mem ,
ops ::Deref ,
ops ::Deref ,
os ::fd ::{ AsFd , BorrowedFd , OwnedFd } ,
os ::{
fd ::{ AsFd , BorrowedFd , OwnedFd } ,
unix ::ffi ::OsStrExt as _ ,
} ,
path ::Path ,
path ::Path ,
ptr ,
ptr ,
} ;
} ;
@ -66,7 +69,7 @@ use thiserror::Error;
use crate ::{
use crate ::{
generated ::bpf_map_info ,
generated ::bpf_map_info ,
obj ::{ self , parse_map_info, EbpfSectionKind} ,
obj ::{ self , EbpfSectionKind} ,
pin ::PinError ,
pin ::PinError ,
sys ::{
sys ::{
bpf_create_map , bpf_get_object , bpf_map_freeze , bpf_map_get_fd_by_id ,
bpf_create_map , bpf_get_object , bpf_map_freeze , bpf_map_get_fd_by_id ,
@ -74,7 +77,7 @@ use crate::{
iter_map_ids , SyscallError ,
iter_map_ids , SyscallError ,
} ,
} ,
util ::{ bytes_of_bpf_name , nr_cpus , KernelVersion } ,
util ::{ bytes_of_bpf_name , nr_cpus , KernelVersion } ,
P inningType, P od,
P od,
} ;
} ;
pub mod array ;
pub mod array ;
@ -304,27 +307,27 @@ impl Map {
/// Returns the low level map type.
/// Returns the low level map type.
fn map_type ( & self ) -> u32 {
fn map_type ( & self ) -> u32 {
match self {
match self {
Self ::Array ( map ) = > map . obj . map_type ( ) ,
Self ::Array ( map ) = > map . def . map_type ( ) ,
Self ::BloomFilter ( map ) = > map . obj . map_type ( ) ,
Self ::BloomFilter ( map ) = > map . def . map_type ( ) ,
Self ::CpuMap ( map ) = > map . obj . map_type ( ) ,
Self ::CpuMap ( map ) = > map . def . map_type ( ) ,
Self ::DevMap ( map ) = > map . obj . map_type ( ) ,
Self ::DevMap ( map ) = > map . def . map_type ( ) ,
Self ::DevMapHash ( map ) = > map . obj . map_type ( ) ,
Self ::DevMapHash ( map ) = > map . def . map_type ( ) ,
Self ::HashMap ( map ) = > map . obj . map_type ( ) ,
Self ::HashMap ( map ) = > map . def . map_type ( ) ,
Self ::LpmTrie ( map ) = > map . obj . map_type ( ) ,
Self ::LpmTrie ( map ) = > map . def . map_type ( ) ,
Self ::LruHashMap ( map ) = > map . obj . map_type ( ) ,
Self ::LruHashMap ( map ) = > map . def . map_type ( ) ,
Self ::PerCpuArray ( map ) = > map . obj . map_type ( ) ,
Self ::PerCpuArray ( map ) = > map . def . map_type ( ) ,
Self ::PerCpuHashMap ( map ) = > map . obj . map_type ( ) ,
Self ::PerCpuHashMap ( map ) = > map . def . map_type ( ) ,
Self ::PerCpuLruHashMap ( map ) = > map . obj . map_type ( ) ,
Self ::PerCpuLruHashMap ( map ) = > map . def . map_type ( ) ,
Self ::PerfEventArray ( map ) = > map . obj . map_type ( ) ,
Self ::PerfEventArray ( map ) = > map . def . map_type ( ) ,
Self ::ProgramArray ( map ) = > map . obj . map_type ( ) ,
Self ::ProgramArray ( map ) = > map . def . map_type ( ) ,
Self ::Queue ( map ) = > map . obj . map_type ( ) ,
Self ::Queue ( map ) = > map . def . map_type ( ) ,
Self ::RingBuf ( map ) = > map . obj . map_type ( ) ,
Self ::RingBuf ( map ) = > map . def . map_type ( ) ,
Self ::SockHash ( map ) = > map . obj . map_type ( ) ,
Self ::SockHash ( map ) = > map . def . map_type ( ) ,
Self ::SockMap ( map ) = > map . obj . map_type ( ) ,
Self ::SockMap ( map ) = > map . def . map_type ( ) ,
Self ::Stack ( map ) = > map . obj . map_type ( ) ,
Self ::Stack ( map ) = > map . def . map_type ( ) ,
Self ::StackTraceMap ( map ) = > map . obj . map_type ( ) ,
Self ::StackTraceMap ( map ) = > map . def . map_type ( ) ,
Self ::Unsupported ( map ) = > map . obj . map_type ( ) ,
Self ::Unsupported ( map ) = > map . def . map_type ( ) ,
Self ::XskMap ( map ) = > map . obj . map_type ( ) ,
Self ::XskMap ( map ) = > map . def . map_type ( ) ,
}
}
}
}
@ -493,7 +496,7 @@ impl_try_from_map!((K, V) {
} ) ;
} ) ;
pub ( crate ) fn check_bounds ( map : & MapData , index : u32 ) -> Result < ( ) , MapError > {
pub ( crate ) fn check_bounds ( map : & MapData , index : u32 ) -> Result < ( ) , MapError > {
let max_entries = map . obj . max_entries ( ) ;
let max_entries = map . def . max_entries ( ) ;
if index > = max_entries {
if index > = max_entries {
Err ( MapError ::OutOfBounds { index , max_entries } )
Err ( MapError ::OutOfBounds { index , max_entries } )
} else {
} else {
@ -503,12 +506,12 @@ pub(crate) fn check_bounds(map: &MapData, index: u32) -> Result<(), MapError> {
pub ( crate ) fn check_kv_size < K , V > ( map : & MapData ) -> Result < ( ) , MapError > {
pub ( crate ) fn check_kv_size < K , V > ( map : & MapData ) -> Result < ( ) , MapError > {
let size = mem ::size_of ::< K > ( ) ;
let size = mem ::size_of ::< K > ( ) ;
let expected = map . obj . key_size ( ) as usize ;
let expected = map . def . key_size ( ) as usize ;
if size ! = expected {
if size ! = expected {
return Err ( MapError ::InvalidKeySize { size , expected } ) ;
return Err ( MapError ::InvalidKeySize { size , expected } ) ;
}
}
let size = mem ::size_of ::< V > ( ) ;
let size = mem ::size_of ::< V > ( ) ;
let expected = map . obj . value_size ( ) as usize ;
let expected = map . def . value_size ( ) as usize ;
if size ! = expected {
if size ! = expected {
return Err ( MapError ::InvalidValueSize { size , expected } ) ;
return Err ( MapError ::InvalidValueSize { size , expected } ) ;
} ;
} ;
@ -517,25 +520,22 @@ pub(crate) fn check_kv_size<K, V>(map: &MapData) -> Result<(), MapError> {
pub ( crate ) fn check_v_size < V > ( map : & MapData ) -> Result < ( ) , MapError > {
pub ( crate ) fn check_v_size < V > ( map : & MapData ) -> Result < ( ) , MapError > {
let size = mem ::size_of ::< V > ( ) ;
let size = mem ::size_of ::< V > ( ) ;
let expected = map . obj . value_size ( ) as usize ;
let expected = map . def . value_size ( ) as usize ;
if size ! = expected {
if size ! = expected {
return Err ( MapError ::InvalidValueSize { size , expected } ) ;
return Err ( MapError ::InvalidValueSize { size , expected } ) ;
} ;
} ;
Ok ( ( ) )
Ok ( ( ) )
}
}
/// A generic handle to a BPF map.
///
/// You should never need to use this unless you're implementing a new map type.
#[ derive(Debug) ]
#[ derive(Debug) ]
pub struct MapData {
pub ( crate ) struct ElfMapData {
obj : obj ::Map ,
pub ( crate ) obj : obj ::Map ,
fd : MapFd ,
pub ( crate ) fd : MapFd ,
}
}
impl MapData {
impl Elf MapData {
/// Creates a new map with the provided `name`
/// Creates a new map with the provided `name`
pub fn create (
pub ( crate ) fn create (
obj : obj ::Map ,
obj : obj ::Map ,
name : & str ,
name : & str ,
btf_fd : Option < BorrowedFd < ' _ > > ,
btf_fd : Option < BorrowedFd < ' _ > > ,
@ -591,7 +591,7 @@ impl MapData {
}
}
Err ( _ ) = > {
Err ( _ ) = > {
let map = Self ::create ( obj , name , btf_fd ) ? ;
let map = Self ::create ( obj , name , btf_fd ) ? ;
map. pin ( & path ) . map_err ( | error | MapError ::PinError {
pin_map( & map . fd , & path ) . map_err ( | error | MapError ::PinError {
name : Some ( name . into ( ) ) ,
name : Some ( name . into ( ) ) ,
error ,
error ,
} ) ? ;
} ) ? ;
@ -620,7 +620,18 @@ impl MapData {
}
}
Ok ( ( ) )
Ok ( ( ) )
}
}
}
/// A generic handle to a BPF map.
///
/// You should never need to use this unless you're implementing a new map type.
#[ derive(Debug) ]
pub struct MapData {
pub ( crate ) def : obj ::MapDef ,
pub ( crate ) fd : MapFd ,
}
impl MapData {
/// Loads a map from a pinned path in bpffs.
/// Loads a map from a pinned path in bpffs.
pub fn from_pin < P : AsRef < Path > > ( path : P ) -> Result < Self , MapError > {
pub fn from_pin < P : AsRef < Path > > ( path : P ) -> Result < Self , MapError > {
use std ::os ::unix ::ffi ::OsStrExt as _ ;
use std ::os ::unix ::ffi ::OsStrExt as _ ;
@ -657,7 +668,7 @@ impl MapData {
pub fn from_fd ( fd : OwnedFd ) -> Result < Self , MapError > {
pub fn from_fd ( fd : OwnedFd ) -> Result < Self , MapError > {
let MapInfo ( info ) = MapInfo ::new_from_fd ( fd . as_fd ( ) ) ? ;
let MapInfo ( info ) = MapInfo ::new_from_fd ( fd . as_fd ( ) ) ? ;
Ok ( Self {
Ok ( Self {
obj: parse_map_info ( info , PinningType ::None ) ,
def: info . into ( ) ,
fd : MapFd ( fd ) ,
fd : MapFd ( fd ) ,
} )
} )
}
}
@ -687,40 +698,47 @@ impl MapData {
/// # Ok::<(), Box<dyn std::error::Error>>(())
/// # Ok::<(), Box<dyn std::error::Error>>(())
/// ```
/// ```
pub fn pin < P : AsRef < Path > > ( & self , path : P ) -> Result < ( ) , PinError > {
pub fn pin < P : AsRef < Path > > ( & self , path : P ) -> Result < ( ) , PinError > {
use std ::os ::unix ::ffi ::OsStrExt as _ ;
let Self { fd , def : _ } = self ;
pin_map ( fd , path )
let Self { fd , obj : _ } = self ;
let path = path . as_ref ( ) ;
let path_string = CString ::new ( path . as_os_str ( ) . as_bytes ( ) ) . map_err ( | error | {
PinError ::InvalidPinPath {
path : path . to_path_buf ( ) ,
error ,
}
} ) ? ;
bpf_pin_object ( fd . as_fd ( ) , & path_string ) . map_err ( | ( _ , io_error ) | SyscallError {
call : "BPF_OBJ_PIN" ,
io_error ,
} ) ? ;
Ok ( ( ) )
}
}
/// Returns the file descriptor of the map.
/// Returns the file descriptor of the map.
pub fn fd ( & self ) -> & MapFd {
pub fn fd ( & self ) -> & MapFd {
let Self { obj : _ , fd } = self ;
let Self { def : _ , fd } = self ;
fd
fd
}
}
pub ( crate ) fn obj ( & self ) -> & obj ::Map {
let Self { obj , fd : _ } = self ;
obj
}
/// Returns the kernel's information about the loaded map.
/// Returns the kernel's information about the loaded map.
pub fn info ( & self ) -> Result < MapInfo , MapError > {
pub fn info ( & self ) -> Result < MapInfo , MapError > {
MapInfo ::new_from_fd ( self . fd . as_fd ( ) )
MapInfo ::new_from_fd ( self . fd . as_fd ( ) )
}
}
}
}
impl From < ElfMapData > for MapData {
fn from ( elf_map : ElfMapData ) -> Self {
let ElfMapData { fd , obj } = elf_map ;
let def = match obj {
aya_obj ::Map ::Legacy ( m ) = > m . def ,
aya_obj ::Map ::Btf ( m ) = > m . def ,
} ;
Self { def , fd }
}
}
fn pin_map ( fd : & MapFd , path : impl AsRef < Path > ) -> Result < ( ) , PinError > {
let path = path . as_ref ( ) ;
let path_string =
CString ::new ( path . as_os_str ( ) . as_bytes ( ) ) . map_err ( | error | PinError ::InvalidPinPath {
path : path . to_path_buf ( ) ,
error ,
} ) ? ;
bpf_pin_object ( fd . as_fd ( ) , & path_string ) . map_err ( | ( _ , io_error ) | SyscallError {
call : "BPF_OBJ_PIN" ,
io_error ,
} ) ? ;
Ok ( ( ) )
}
/// An iterable map
/// An iterable map
pub trait IterableMap < K : Pod , V > {
pub trait IterableMap < K : Pod , V > {
/// Get a generic map handle
/// Get a generic map handle
@ -1078,7 +1096,7 @@ mod tests {
assert_matches ! (
assert_matches ! (
MapData ::from_id ( 1234 ) ,
MapData ::from_id ( 1234 ) ,
Ok ( MapData {
Ok ( MapData {
obj : _ ,
def : _ ,
fd ,
fd ,
} ) = > assert_eq! ( fd . as_fd ( ) . as_raw_fd ( ) , 42 )
} ) = > assert_eq! ( fd . as_fd ( ) . as_raw_fd ( ) , 42 )
) ;
) ;
@ -1095,8 +1113,8 @@ mod tests {
} ) ;
} ) ;
assert_matches ! (
assert_matches ! (
MapData::create ( new_obj_map ( ) , "foo" , None ) ,
Elf MapData::create ( new_obj_map ( ) , "foo" , None ) ,
Ok ( MapData {
Ok ( Elf MapData {
obj : _ ,
obj : _ ,
fd ,
fd ,
} ) = > assert_eq! ( fd . as_fd ( ) . as_raw_fd ( ) , 42 )
} ) = > assert_eq! ( fd . as_fd ( ) . as_raw_fd ( ) , 42 )
@ -1135,8 +1153,9 @@ mod tests {
_ = > Err ( ( - 1 , io ::Error ::from_raw_os_error ( EFAULT ) ) ) ,
_ = > Err ( ( - 1 , io ::Error ::from_raw_os_error ( EFAULT ) ) ) ,
} ) ;
} ) ;
let map_data = MapData ::create ( new_obj_map ( ) , TEST_NAME , None ) . unwrap ( ) ;
let map_data = ElfMapData ::create ( new_obj_map ( ) , TEST_NAME , None ) . unwrap ( ) ;
assert_eq! ( TEST_NAME , map_data . info ( ) . unwrap ( ) . name_as_str ( ) . unwrap ( ) ) ;
let info = MapInfo ::new_from_fd ( map_data . fd . as_fd ( ) ) . unwrap ( ) ;
assert_eq! ( TEST_NAME , info . name_as_str ( ) . unwrap ( ) ) ;
}
}
#[ test ]
#[ test ]
@ -1199,7 +1218,7 @@ mod tests {
override_syscall ( | _ | Err ( ( - 42 , io ::Error ::from_raw_os_error ( EFAULT ) ) ) ) ;
override_syscall ( | _ | Err ( ( - 42 , io ::Error ::from_raw_os_error ( EFAULT ) ) ) ) ;
assert_matches ! (
assert_matches ! (
MapData::create ( new_obj_map ( ) , "foo" , None ) ,
Elf MapData::create ( new_obj_map ( ) , "foo" , None ) ,
Err ( MapError ::CreateError { name , code , io_error } ) = > {
Err ( MapError ::CreateError { name , code , io_error } ) = > {
assert_eq! ( name , "foo" ) ;
assert_eq! ( name , "foo" ) ;
assert_eq! ( code , - 42 ) ;
assert_eq! ( code , - 42 ) ;