@ -4,25 +4,30 @@
//! used to setup and share data with eBPF programs. When you call
//! used to setup and share data with eBPF programs. When you call
//! [`Bpf::load_file`](crate::Bpf::load_file) or
//! [`Bpf::load_file`](crate::Bpf::load_file) or
//! [`Bpf::load`](crate::Bpf::load), all the maps defined in the eBPF code get
//! [`Bpf::load`](crate::Bpf::load), all the maps defined in the eBPF code get
//! initialized and can then be accessed using [`Bpf::map`](crate::Bpf::map) and
//! initialized and can then be accessed using [`Bpf::map`](crate::Bpf::map) ,
//! [`Bpf::map_mut`](crate::Bpf::map_mut) .
//! [`Bpf::map_mut`](crate::Bpf::map_mut) , or [`Bpf::take_map`](crate::Bpf::take_map) .
//!
//!
//! # Typed maps
//! # Typed maps
//!
//!
//! The eBPF API includes many map types each supporting different operations.
//! The eBPF API includes many map types each supporting different operations.
//! [`Bpf::map`](crate::Bpf::map) and [`Bpf::map_mut`](crate::Bpf::map_mut) always return the
//! [`Bpf::map`](crate::Bpf::map), [`Bpf::map_mut`](crate::Bpf::map_mut), and
//! opaque [`MapRef`] and [`MapRefMut`] types respectively. Those two types can be converted to
//! [`Bpf::take_map`](crate::Bpf::take_map) always return the
//! *typed maps* using the [`TryFrom`](std::convert::TryFrom) trait. For example:
//! opaque [`&Map`](crate::maps::Map), [`&mut Map`](crate::maps::Map), and [`Map`](crate::maps::Map)
//! types respectively. Those three types can be converted to *typed maps* using
//! the [`TryFrom`](std::convert::TryFrom) or [`TryInto`](std::convert::TryInto)
//! trait. For example:
//!
//!
//! ```no_run
//! ```no_run
//! # let mut bpf = aya::Bpf::load(&[])?;
//! # let mut bpf = aya::Bpf::load(&[])?;
//! use aya::maps::SockMap;
//! use aya::maps::SockMap;
//! use aya::programs::SkMsg;
//! use aya::programs::SkMsg;
//!
//!
//! let intercept_egress = SockMap::try_from(bpf.map_mut("INTERCEPT_EGRESS")?)?;
//! let intercept_egress = SockMap::try_from(bpf.map_mut("INTERCEPT_EGRESS").unwrap())?;
//! let map_fd = intercept_egress.fd()?;
//! let prog: &mut SkMsg = bpf.program_mut("intercept_egress_packet").unwrap().try_into()?;
//! let prog: &mut SkMsg = bpf.program_mut("intercept_egress_packet").unwrap().try_into()?;
//! prog.load()?;
//! prog.load()?;
//! prog.attach(&intercept_egress)?;
//! prog.attach(map_fd)?;
//!
//! # Ok::<(), aya::BpfError>(())
//! # Ok::<(), aya::BpfError>(())
//! ```
//! ```
//!
//!
@ -32,6 +37,7 @@
//! versa. Because of that, all map values must be plain old data and therefore
//! versa. Because of that, all map values must be plain old data and therefore
//! implement the [Pod] trait.
//! implement the [Pod] trait.
use std ::{
use std ::{
convert ::{ AsMut , AsRef } ,
ffi ::CString ,
ffi ::CString ,
fmt , io ,
fmt , io ,
marker ::PhantomData ,
marker ::PhantomData ,
@ -58,8 +64,6 @@ use crate::{
PinningType , Pod ,
PinningType , Pod ,
} ;
} ;
mod map_lock ;
pub mod array ;
pub mod array ;
pub mod bloom_filter ;
pub mod bloom_filter ;
pub mod hash_map ;
pub mod hash_map ;
@ -71,8 +75,12 @@ pub mod stack;
pub mod stack_trace ;
pub mod stack_trace ;
pub use array ::{ Array , PerCpuArray , ProgramArray } ;
pub use array ::{ Array , PerCpuArray , ProgramArray } ;
pub use bloom_filter ::BloomFilter ;
pub use hash_map ::{ HashMap , PerCpuHashMap } ;
pub use hash_map ::{ HashMap , PerCpuHashMap } ;
pub use map_lock ::* ;
pub use lpm_trie ::LpmTrie ;
#[ cfg(feature = " async " ) ]
#[ cfg_attr(docsrs, doc(cfg(feature = " async " ))) ]
pub use perf ::AsyncPerfEventArray ;
pub use perf ::PerfEventArray ;
pub use perf ::PerfEventArray ;
pub use queue ::Queue ;
pub use queue ::Queue ;
pub use sock ::{ SockHash , SockMap } ;
pub use sock ::{ SockHash , SockMap } ;
@ -82,13 +90,6 @@ pub use stack_trace::StackTraceMap;
#[ derive(Error, Debug) ]
#[ derive(Error, Debug) ]
/// Errors occuring from working with Maps
/// Errors occuring from working with Maps
pub enum MapError {
pub enum MapError {
/// Unable to find the map
#[ error( " map `{name}` not found " ) ]
MapNotFound {
/// Map name
name : String ,
} ,
/// Invalid map type encontered
/// Invalid map type encontered
#[ error( " invalid map type {map_type} " ) ]
#[ error( " invalid map type {map_type} " ) ]
InvalidMapType {
InvalidMapType {
@ -174,20 +175,6 @@ pub enum MapError {
io_error : io ::Error ,
io_error : io ::Error ,
} ,
} ,
/// Map is borrowed mutably
#[ error( " map `{name}` is borrowed mutably " ) ]
BorrowError {
/// Map name
name : String ,
} ,
/// Map is already borrowed
#[ error( " map `{name}` is already borrowed " ) ]
BorrowMutError {
/// Map name
name : String ,
} ,
/// Could not pin map by name
/// Could not pin map by name
#[ error( " map `{name:?}` requested pinning by name. pinning failed " ) ]
#[ error( " map `{name:?}` requested pinning by name. pinning failed " ) ]
PinError {
PinError {
@ -243,11 +230,234 @@ fn maybe_warn_rlimit() {
}
}
}
}
/// eBPF map types.
#[ derive(Debug) ]
pub enum Map {
/// A [`Array`] map
Array ( MapData ) ,
/// A [`PerCpuArray`] map
PerCpuArray ( MapData ) ,
/// A [`ProgramArray`] map
ProgramArray ( MapData ) ,
/// A [`HashMap`] map
HashMap ( MapData ) ,
/// A [`PerCpuHashMap`] map
PerCpuHashMap ( MapData ) ,
/// A [`PerfEventArray`] map
PerfEventArray ( MapData ) ,
/// A [`SockMap`] map
SockMap ( MapData ) ,
/// A [`SockHash`] map
SockHash ( MapData ) ,
/// A [`BloomFilter`] map
BloomFilter ( MapData ) ,
/// A [`LpmTrie`] map
LpmTrie ( MapData ) ,
/// A [`Stack`] map
Stack ( MapData ) ,
/// A [`StackTraceMap`] map
StackTraceMap ( MapData ) ,
/// A [`Queue`] map
Queue ( MapData ) ,
}
impl Map {
/// Returns the low level map type.
fn map_type ( & self ) -> u32 {
match self {
Map ::Array ( map ) = > map . obj . map_type ( ) ,
Map ::PerCpuArray ( map ) = > map . obj . map_type ( ) ,
Map ::ProgramArray ( map ) = > map . obj . map_type ( ) ,
Map ::HashMap ( map ) = > map . obj . map_type ( ) ,
Map ::PerCpuHashMap ( map ) = > map . obj . map_type ( ) ,
Map ::PerfEventArray ( map ) = > map . obj . map_type ( ) ,
Map ::SockHash ( map ) = > map . obj . map_type ( ) ,
Map ::SockMap ( map ) = > map . obj . map_type ( ) ,
Map ::BloomFilter ( map ) = > map . obj . map_type ( ) ,
Map ::LpmTrie ( map ) = > map . obj . map_type ( ) ,
Map ::Stack ( map ) = > map . obj . map_type ( ) ,
Map ::StackTraceMap ( map ) = > map . obj . map_type ( ) ,
Map ::Queue ( map ) = > map . obj . map_type ( ) ,
}
}
}
macro_rules! impl_try_from_map {
( $( $tx :ident from Map ::$ty :ident ) , + $(, ) ? ) = > {
$(
impl < ' a > TryFrom < & ' a Map > for $tx < & ' a MapData > {
type Error = MapError ;
fn try_from ( map : & ' a Map ) -> Result < $tx < & ' a MapData > , MapError > {
match map {
Map ::$ty ( m ) = > {
$tx ::new ( m )
} ,
_ = > Err ( MapError ::InvalidMapType { map_type : map . map_type ( ) } ) ,
}
}
}
impl < ' a , > TryFrom < & ' a mut Map > for $tx < & ' a mut MapData > {
type Error = MapError ;
fn try_from ( map : & ' a mut Map ) -> Result < $tx < & ' a mut MapData > , MapError > {
match map {
Map ::$ty ( m ) = > {
$tx ::new ( m )
} ,
_ = > Err ( MapError ::InvalidMapType { map_type : map . map_type ( ) } ) ,
}
}
}
impl TryFrom < Map > for $tx < MapData > {
type Error = MapError ;
fn try_from ( map : Map ) -> Result < $tx < MapData > , MapError > {
match map {
Map ::$ty ( m ) = > {
$tx ::new ( m )
} ,
_ = > Err ( MapError ::InvalidMapType { map_type : map . map_type ( ) } ) ,
}
}
}
) +
}
}
impl_try_from_map ! (
ProgramArray from Map ::ProgramArray ,
SockMap from Map ::SockMap ,
PerfEventArray from Map ::PerfEventArray ,
StackTraceMap from Map ::StackTraceMap ,
) ;
#[ cfg(feature = " async " ) ]
#[ cfg_attr(docsrs, doc(cfg(feature = " async " ))) ]
impl_try_from_map ! (
AsyncPerfEventArray from Map ::PerfEventArray ,
) ;
macro_rules! impl_try_from_map_generic_key_or_value {
( $( $ty :ident ) , + $(, ) ? ) = > {
$(
impl < ' a , V :Pod > TryFrom < & ' a Map > for $ty < & ' a MapData , V > {
type Error = MapError ;
fn try_from ( map : & ' a Map ) -> Result < $ty < & ' a MapData , V > , MapError > {
match map {
Map ::$ty ( m ) = > {
$ty ::new ( m )
} ,
_ = > Err ( MapError ::InvalidMapType { map_type : map . map_type ( ) } ) ,
}
}
}
impl < ' a , V : Pod > TryFrom < & ' a mut Map > for $ty < & ' a mut MapData , V > {
type Error = MapError ;
fn try_from ( map : & ' a mut Map ) -> Result < $ty < & ' a mut MapData , V > , MapError > {
match map {
Map ::$ty ( m ) = > {
$ty ::new ( m )
} ,
_ = > Err ( MapError ::InvalidMapType { map_type : map . map_type ( ) } ) ,
}
}
}
impl < V : Pod > TryFrom < Map > for $ty < MapData , V > {
type Error = MapError ;
fn try_from ( map : Map ) -> Result < $ty < MapData , V > , MapError > {
match map {
Map ::$ty ( m ) = > {
$ty ::new ( m )
} ,
_ = > Err ( MapError ::InvalidMapType { map_type : map . map_type ( ) } ) ,
}
}
}
) +
}
}
impl_try_from_map_generic_key_or_value ! ( Array , PerCpuArray , SockHash , BloomFilter , Queue , Stack , ) ;
macro_rules! impl_try_from_map_generic_key_and_value {
( $( $ty :ident ) , + $(, ) ? ) = > {
$(
impl < ' a , V : Pod , K : Pod > TryFrom < & ' a Map > for $ty < & ' a MapData , V , K > {
type Error = MapError ;
fn try_from ( map : & ' a Map ) -> Result < $ty < & ' a MapData , V , K > , MapError > {
match map {
Map ::$ty ( m ) = > {
$ty ::new ( m )
} ,
_ = > Err ( MapError ::InvalidMapType { map_type : map . map_type ( ) } ) ,
}
}
}
impl < ' a , V : Pod , K : Pod > TryFrom < & ' a mut Map > for $ty < & ' a mut MapData , V , K > {
type Error = MapError ;
fn try_from ( map : & ' a mut Map ) -> Result < $ty < & ' a mut MapData , V , K > , MapError > {
match map {
Map ::$ty ( m ) = > {
$ty ::new ( m )
} ,
_ = > Err ( MapError ::InvalidMapType { map_type : map . map_type ( ) } ) ,
}
}
}
) +
}
}
impl_try_from_map_generic_key_and_value ! ( HashMap , PerCpuHashMap , LpmTrie ) ;
pub ( crate ) fn check_bounds ( map : & MapData , index : u32 ) -> Result < ( ) , MapError > {
let max_entries = map . obj . max_entries ( ) ;
if index > = max_entries {
Err ( MapError ::OutOfBounds { index , max_entries } )
} else {
Ok ( ( ) )
}
}
pub ( crate ) fn check_kv_size < K , V > ( map : & MapData ) -> Result < ( ) , MapError > {
let size = mem ::size_of ::< K > ( ) ;
let expected = map . obj . key_size ( ) as usize ;
if size ! = expected {
return Err ( MapError ::InvalidKeySize { size , expected } ) ;
}
let size = mem ::size_of ::< V > ( ) ;
let expected = map . obj . value_size ( ) as usize ;
if size ! = expected {
return Err ( MapError ::InvalidValueSize { size , expected } ) ;
} ;
Ok ( ( ) )
}
pub ( crate ) fn check_v_size < V > ( map : & MapData ) -> Result < ( ) , MapError > {
let size = mem ::size_of ::< V > ( ) ;
let expected = map . obj . value_size ( ) as usize ;
if size ! = expected {
return Err ( MapError ::InvalidValueSize { size , expected } ) ;
} ;
Ok ( ( ) )
}
/// A generic handle to a BPF map.
/// A generic handle to a BPF map.
///
///
/// You should never need to use this unless you're implementing a new map type.
/// You should never need to use this unless you're implementing a new map type.
#[ derive(Debug) ]
#[ derive(Debug) ]
pub struct Map {
pub struct Map Data {
pub ( crate ) obj : obj ::Map ,
pub ( crate ) obj : obj ::Map ,
pub ( crate ) fd : Option < RawFd > ,
pub ( crate ) fd : Option < RawFd > ,
pub ( crate ) btf_fd : Option < RawFd > ,
pub ( crate ) btf_fd : Option < RawFd > ,
@ -255,7 +465,19 @@ pub struct Map {
pub pinned : bool ,
pub pinned : bool ,
}
}
impl Map {
impl AsRef < MapData > for MapData {
fn as_ref ( & self ) -> & MapData {
self
}
}
impl AsMut < MapData > for MapData {
fn as_mut ( & mut self ) -> & mut MapData {
self
}
}
impl MapData {
/// Creates a new map with the provided `name`
/// Creates a new map with the provided `name`
pub fn create ( & mut self , name : & str ) -> Result < RawFd , MapError > {
pub fn create ( & mut self , name : & str ) -> Result < RawFd , MapError > {
if self . fd . is_some ( ) {
if self . fd . is_some ( ) {
@ -303,7 +525,7 @@ impl Map {
}
}
/// 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 < Map , MapError > {
pub fn from_pin < P : AsRef < Path > > ( path : P ) -> Result < Map Data , MapError > {
let path_string =
let path_string =
CString ::new ( path . as_ref ( ) . to_string_lossy ( ) . into_owned ( ) ) . map_err ( | e | {
CString ::new ( path . as_ref ( ) . to_string_lossy ( ) . into_owned ( ) ) . map_err ( | e | {
MapError ::PinError {
MapError ::PinError {
@ -324,7 +546,7 @@ impl Map {
io_error ,
io_error ,
} ) ? ;
} ) ? ;
Ok ( Map {
Ok ( Map Data {
obj : parse_map_info ( info , PinningType ::ByName ) ,
obj : parse_map_info ( info , PinningType ::ByName ) ,
fd : Some ( fd ) ,
fd : Some ( fd ) ,
btf_fd : None ,
btf_fd : None ,
@ -334,16 +556,16 @@ impl Map {
/// Loads a map from a [`RawFd`].
/// Loads a map from a [`RawFd`].
///
///
/// If loading from a BPF Filesystem (bpffs) you should use [`Map::from_pin`] .
/// If loading from a BPF Filesystem (bpffs) you should use [`Map::from_pin`] (crate::maps::MapData::from_pin) .
/// This API is intended for cases where you have received a valid BPF FD from some other means.
/// This API is intended for cases where you have received a valid BPF FD from some other means.
/// For example, you received an FD over Unix Domain Socket.
/// For example, you received an FD over Unix Domain Socket.
pub fn from_fd ( fd : RawFd ) -> Result < Map , MapError > {
pub fn from_fd ( fd : RawFd ) -> Result < Map Data , MapError > {
let info = bpf_map_get_info_by_fd ( fd ) . map_err ( | io_error | MapError ::SyscallError {
let info = bpf_map_get_info_by_fd ( fd ) . map_err ( | io_error | MapError ::SyscallError {
call : "BPF_OBJ_GET" . to_owned ( ) ,
call : "BPF_OBJ_GET" . to_owned ( ) ,
io_error ,
io_error ,
} ) ? ;
} ) ? ;
Ok ( Map {
Ok ( Map Data {
obj : parse_map_info ( info , PinningType ::None ) ,
obj : parse_map_info ( info , PinningType ::None ) ,
fd : Some ( fd ) ,
fd : Some ( fd ) ,
btf_fd : None ,
btf_fd : None ,
@ -351,11 +573,6 @@ impl Map {
} )
} )
}
}
/// Returns the [`bpf_map_type`] of this map
pub fn map_type ( & self ) -> Result < bpf_map_type , MapError > {
bpf_map_type ::try_from ( self . obj . map_type ( ) )
}
pub ( crate ) fn fd_or_err ( & self ) -> Result < RawFd , MapError > {
pub ( crate ) fn fd_or_err ( & self ) -> Result < RawFd , MapError > {
self . fd . ok_or ( MapError ::NotCreated )
self . fd . ok_or ( MapError ::NotCreated )
}
}
@ -389,7 +606,7 @@ impl Map {
}
}
}
}
impl Drop for Map {
impl Drop for Map Data {
fn drop ( & mut self ) {
fn drop ( & mut self ) {
// TODO: Replace this with an OwnedFd once that is stabilized.
// TODO: Replace this with an OwnedFd once that is stabilized.
if let Some ( fd ) = self . fd . take ( ) {
if let Some ( fd ) = self . fd . take ( ) {
@ -398,10 +615,26 @@ impl Drop for Map {
}
}
}
}
impl Clone for MapData {
fn clone ( & self ) -> MapData {
MapData {
obj : self . obj . clone ( ) ,
fd : {
if let Some ( fd ) = self . fd {
unsafe { Some ( libc ::dup ( fd ) ) } ;
}
None
} ,
btf_fd : self . btf_fd ,
pinned : self . pinned ,
}
}
}
/// 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
fn map ( & self ) -> & Map ;
fn map ( & self ) -> & Map Data ;
/// Get the value for the provided `key`
/// Get the value for the provided `key`
fn get ( & self , key : & K ) -> Result < V , MapError > ;
fn get ( & self , key : & K ) -> Result < V , MapError > ;
@ -409,13 +642,13 @@ pub trait IterableMap<K: Pod, V> {
/// Iterator returned by `map.keys()`.
/// Iterator returned by `map.keys()`.
pub struct MapKeys < ' coll , K : Pod > {
pub struct MapKeys < ' coll , K : Pod > {
map : & ' coll Map ,
map : & ' coll Map Data ,
err : bool ,
err : bool ,
key : Option < K > ,
key : Option < K > ,
}
}
impl < ' coll , K : Pod > MapKeys < ' coll , K > {
impl < ' coll , K : Pod > MapKeys < ' coll , K > {
fn new ( map : & ' coll Map ) -> MapKeys < ' coll , K > {
fn new ( map : & ' coll Map Data ) -> MapKeys < ' coll , K > {
MapKeys {
MapKeys {
map ,
map ,
err : false ,
err : false ,
@ -538,6 +771,7 @@ impl TryFrom<u32> for bpf_map_type {
} )
} )
}
}
}
}
pub ( crate ) struct PerCpuKernelMem {
pub ( crate ) struct PerCpuKernelMem {
bytes : Vec < u8 > ,
bytes : Vec < u8 > ,
}
}
@ -643,6 +877,7 @@ mod tests {
use crate ::{
use crate ::{
bpf_map_def ,
bpf_map_def ,
generated ::{ bpf_cmd , bpf_map_type ::BPF_MAP_TYPE_HASH } ,
generated ::{ bpf_cmd , bpf_map_type ::BPF_MAP_TYPE_HASH } ,
maps ::MapData ,
obj ::MapKind ,
obj ::MapKind ,
sys ::{ override_syscall , Syscall } ,
sys ::{ override_syscall , Syscall } ,
} ;
} ;
@ -665,8 +900,8 @@ mod tests {
} )
} )
}
}
fn new_map ( ) -> Map {
fn new_map ( ) -> Map Data {
Map {
Map Data {
obj : new_obj_map ( ) ,
obj : new_obj_map ( ) ,
fd : None ,
fd : None ,
pinned : false ,
pinned : false ,