@ -2,7 +2,7 @@ use std::{
collections ::HashMap ,
collections ::HashMap ,
error ::Error ,
error ::Error ,
fs , io ,
fs , io ,
os ::raw ::c_int ,
os ::{ raw ::c_int , unix ::io ::RawFd } ,
path ::{ Path , PathBuf } ,
path ::{ Path , PathBuf } ,
} ;
} ;
@ -58,64 +58,92 @@ pub(crate) struct bpf_map_def {
pub ( crate ) map_flags : u32 ,
pub ( crate ) map_flags : u32 ,
// optional features
// optional features
pub ( crate ) id : u32 ,
pub ( crate ) id : u32 ,
pub ( crate ) pinning : u32 ,
pub ( crate ) pinning : PinningType ,
}
}
/// The main entry point into the library, used to work with eBPF programs and maps.
#[ repr(u32) ]
#[ derive(Debug) ]
#[ derive(Copy, Clone, Debug, PartialEq) ]
pub struct Bpf {
pub ( crate ) enum PinningType {
maps : HashMap < String , MapLock > ,
None = 0 ,
programs : HashMap < String , Program > ,
#[ allow(dead_code) ] // ByName is constructed from the BPF side
ByName = 1 ,
}
impl Default for PinningType {
fn default ( ) -> Self {
PinningType ::None
}
}
#[ derive(Default, Debug) ]
pub struct BpfLoader {
btf : Option < Btf > ,
map_pin_path : Option < PathBuf > ,
}
impl BpfLoader {
pub fn new ( ) -> BpfLoader {
BpfLoader {
btf : None ,
map_pin_path : None ,
}
}
// Set the target BTF
pub fn btf ( & mut self , btf : Btf ) -> & mut BpfLoader {
self . btf = Some ( btf ) ;
self
}
// Set the map pin path
pub fn map_pin_path < P : AsRef < Path > > ( & mut self , path : P ) -> & mut BpfLoader {
self . map_pin_path = Some ( path . as_ref ( ) . to_owned ( ) ) ;
self
}
}
impl Bpf {
/// Loads eBPF bytecode from a file.
/// Loads eBPF bytecode from a file.
///
///
/// Parses the given object code file and initializes the [maps](crate::maps) defined in it. If
/// Parses the given object code file and initializes the [maps](crate::maps) defined in it.
/// the kernel supports [BTF](Btf) debug info, it is automatically loaded from
/// `/sys/kernel/btf/vmlinux`.
///
///
/// # Examples
/// # Examples
///
///
/// ```no_run
/// ```no_run
/// use aya::Bpf;
/// use aya::Bpf Loader ;
///
///
/// let bpf = Bpf::load_file("file.o")?;
/// let bpf = Bpf Loader ::new(). load_file("file.o")?;
/// # Ok::<(), aya::BpfError>(())
/// # Ok::<(), aya::BpfError>(())
/// ```
/// ```
pub fn load_file < P : AsRef < Path > > ( path : P ) -> Result < Bpf , BpfError > {
pub fn load_file < P : AsRef < Path > > ( & mut self , path : P ) -> Result < Bpf , BpfError > {
let path = path . as_ref ( ) ;
let path = path . as_ref ( ) ;
Bpf ::load (
self . load ( & fs ::read ( path ) . map_err ( | error | BpfError ::FileError {
& fs ::read ( path ) . map_err ( | error | BpfError ::FileError {
path : path . to_owned ( ) ,
path : path . to_owned ( ) ,
error ,
error ,
} ) ? ,
} ) ? )
Btf ::from_sys_fs ( ) . ok ( ) . as_ref ( ) ,
)
}
}
/// Load eBPF bytecode.
/// Load eBPF bytecode.
///
///
/// Parses the object code contained in `data` and initializes the [maps](crate::maps) defined
/// Parses the object code contained in `data` and initializes the [maps](crate::maps) defined
/// in it. If `target_btf` is not `None` and `data` includes BTF debug info, [BTF](Btf) relocations
/// in it. If `BpfLoader.btf` is not `None` and `data` includes BTF debug info, [BTF](Btf) relocations
/// are applied as well. In order to allow sharing of a single [BTF](Btf) object among multiple
/// are applied as well. Any maps that require pinning will be pinned to `BpfLoader.map_pin_path`
/// eBPF programs, `target_btf` is passed by reference.
///
///
/// # Examples
/// # Examples
///
///
/// ```no_run
/// ```no_run
/// use aya::{Bpf , Btf};
/// use aya::{Bpf Loader , Btf};
/// use std::fs;
/// use std::fs;
///
///
/// let data = fs::read("file.o").unwrap();
/// let data = fs::read("file.o").unwrap();
/// // load the BTF data from /sys/kernel/btf/vmlinux
/// // load the BTF data from /sys/kernel/btf/vmlinux
/// let bpf = Bpf::load(&data, Btf::from_sys_fs().ok().as_ref());
/// let target_btf = Btf::from_sys_fs().unwrap();
/// let bpf = BpfLoader::new().btf(target_btf).load(&data);
/// # Ok::<(), aya::BpfError>(())
/// # Ok::<(), aya::BpfError>(())
/// ```
/// ```
pub fn load ( data : & [ u8 ] , target_btf : Option < & Btf > ) -> Result < Bpf , BpfError > {
pub fn load ( & mut self , data : & [ u8 ] ) -> Result < Bpf , BpfError > {
let mut obj = Object ::parse ( data ) ? ;
let mut obj = Object ::parse ( data ) ? ;
if let Some ( btf ) = target_ btf {
if let Some ( btf ) = & self . btf {
obj . relocate_btf ( btf ) ? ;
obj . relocate_btf ( btf ) ? ;
}
}
@ -130,8 +158,32 @@ impl Bpf {
} ) ?
} ) ?
. len ( ) as u32 ;
. len ( ) as u32 ;
}
}
let mut map = Map { obj , fd : None } ;
let mut map = Map {
obj ,
fd : None ,
pinned : false ,
} ;
let fd = match map . obj . def . pinning {
PinningType ::ByName = > {
let path = match & self . map_pin_path {
Some ( p ) = > p ,
None = > return Err ( BpfError ::NoPinPath ) ,
} ;
// try to open map in case it's already pinned
match map . from_pinned ( path ) {
Ok ( fd ) = > {
map . pinned = true ;
fd as RawFd
}
Err ( _ ) = > {
let fd = map . create ( ) ? ;
let fd = map . create ( ) ? ;
map . pin ( path ) ? ;
fd
}
}
}
PinningType ::None = > map . create ( ) ? ,
} ;
if ! map . obj . data . is_empty ( ) & & map . obj . name ! = ".bss" {
if ! map . obj . data . is_empty ( ) & & map . obj . name ! = ".bss" {
bpf_map_update_elem_ptr ( fd , & 0 as * const _ , map . obj . data . as_mut_ptr ( ) , 0 ) . map_err (
bpf_map_update_elem_ptr ( fd , & 0 as * const _ , map . obj . data . as_mut_ptr ( ) , 0 ) . map_err (
| ( code , io_error ) | MapError ::SyscallError {
| ( code , io_error ) | MapError ::SyscallError {
@ -208,7 +260,6 @@ impl Bpf {
( name , program )
( name , program )
} )
} )
. collect ( ) ;
. collect ( ) ;
Ok ( Bpf {
Ok ( Bpf {
maps : maps
maps : maps
. drain ( .. )
. drain ( .. )
@ -217,6 +268,64 @@ impl Bpf {
programs ,
programs ,
} )
} )
}
}
}
/// The main entry point into the library, used to work with eBPF programs and maps.
#[ derive(Debug) ]
pub struct Bpf {
maps : HashMap < String , MapLock > ,
programs : HashMap < String , Program > ,
}
impl Bpf {
/// Loads eBPF bytecode from a file.
///
/// Parses the given object code file and initializes the [maps](crate::maps) defined in it. If
/// the kernel supports [BTF](Btf) debug info, it is automatically loaded from
/// `/sys/kernel/btf/vmlinux`.
///
/// # Examples
///
/// ```no_run
/// use aya::Bpf;
///
/// let bpf = Bpf::load_file("file.o")?;
/// # Ok::<(), aya::BpfError>(())
/// ```
pub fn load_file < P : AsRef < Path > > ( path : P ) -> Result < Bpf , BpfError > {
let mut loader = BpfLoader ::new ( ) ;
let path = path . as_ref ( ) ;
if let Ok ( btf ) = Btf ::from_sys_fs ( ) {
loader . btf ( btf ) ;
} ;
loader . load_file ( path )
}
/// Load eBPF bytecode.
///
/// Parses the object code contained in `data` and initializes the [maps](crate::maps) defined
/// in it. If `target_btf` is not `None` and `data` includes BTF debug info, [BTF](Btf) relocations
/// are applied as well. In order to allow sharing of a single [BTF](Btf) object among multiple
/// eBPF programs, `target_btf` is passed by reference.
///
/// # Examples
///
/// ```no_run
/// use aya::{Bpf, Btf};
/// use std::fs;
///
/// let data = fs::read("file.o").unwrap();
/// // load the BTF data from /sys/kernel/btf/vmlinux
/// let bpf = Bpf::load(&data);
/// # Ok::<(), aya::BpfError>(())
/// ```
pub fn load ( data : & [ u8 ] ) -> Result < Bpf , BpfError > {
let mut loader = BpfLoader ::new ( ) ;
if let Ok ( btf ) = Btf ::from_sys_fs ( ) {
loader . btf ( btf ) ;
} ;
loader . load ( data )
}
/// Returns a reference to the map with the given name.
/// Returns a reference to the map with the given name.
///
///
@ -272,7 +381,7 @@ impl Bpf {
///
///
/// # Examples
/// # Examples
/// ```no_run
/// ```no_run
/// # let mut bpf = aya::Bpf::load(&[] , None )?;
/// # let mut bpf = aya::Bpf::load(&[] )?;
/// for (name, map) in bpf.maps() {
/// for (name, map) in bpf.maps() {
/// println!(
/// println!(
/// "found map `{}` of type `{:?}`",
/// "found map `{}` of type `{:?}`",
@ -308,7 +417,7 @@ impl Bpf {
/// # Examples
/// # Examples
///
///
/// ```no_run
/// ```no_run
/// # let bpf = aya::Bpf::load(&[] , None )?;
/// # let bpf = aya::Bpf::load(&[] )?;
/// let program = bpf.program("SSL_read")?;
/// let program = bpf.program("SSL_read")?;
/// println!("program SSL_read is of type {:?}", program.prog_type());
/// println!("program SSL_read is of type {:?}", program.prog_type());
/// # Ok::<(), aya::BpfError>(())
/// # Ok::<(), aya::BpfError>(())
@ -333,7 +442,7 @@ impl Bpf {
/// # Examples
/// # Examples
///
///
/// ```no_run
/// ```no_run
/// # let mut bpf = aya::Bpf::load(&[] , None )?;
/// # let mut bpf = aya::Bpf::load(&[] )?;
/// use aya::programs::UProbe;
/// use aya::programs::UProbe;
/// use std::convert::TryInto;
/// use std::convert::TryInto;
///
///
@ -354,7 +463,7 @@ impl Bpf {
///
///
/// # Examples
/// # Examples
/// ```no_run
/// ```no_run
/// # let mut bpf = aya::Bpf::load(&[] , None )?;
/// # let mut bpf = aya::Bpf::load(&[] )?;
/// for program in bpf.programs() {
/// for program in bpf.programs() {
/// println!(
/// println!(
/// "found program `{}` of type `{:?}`",
/// "found program `{}` of type `{:?}`",
@ -379,6 +488,15 @@ pub enum BpfError {
error : io ::Error ,
error : io ::Error ,
} ,
} ,
#[ error( " pinning requested but no path provided " ) ]
NoPinPath ,
#[ error( " unexpected pinning type {name} " ) ]
UnexpectedPinningType { name : u32 } ,
#[ error( " invalid path `{error}` " ) ]
InvalidPath { error : String } ,
#[ error( " error parsing BPF object " ) ]
#[ error( " error parsing BPF object " ) ]
ParseError ( #[ from ] ParseError ) ,
ParseError ( #[ from ] ParseError ) ,