You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
aya/src/bpf.rs

158 lines
4.6 KiB
Rust

use std::{
cell::{Ref, RefCell, RefMut},
collections::HashMap,
convert::TryFrom,
};
use thiserror::Error;
use crate::{
maps::{Map, MapError},
obj::{BtfRelocationError, Object, ParseError, RelocationError},
programs::{KProbe, Program, ProgramData, ProgramError, SocketFilter, TracePoint, UProbe, Xdp},
syscalls::bpf_map_update_elem_ptr,
};
pub(crate) const BPF_OBJ_NAME_LEN: usize = 16;
/* FIXME: these are arch dependent */
pub(crate) const PERF_EVENT_IOC_ENABLE: libc::c_ulong = 9216;
pub(crate) const PERF_EVENT_IOC_DISABLE: libc::c_ulong = 9217;
pub(crate) const PERF_EVENT_IOC_SET_BPF: libc::c_ulong = 1074013192;
pub unsafe trait Pod: Copy + 'static {}
macro_rules! unsafe_impl_pod {
($($struct_name:ident),+ $(,)?) => {
$(
unsafe impl Pod for $struct_name { }
)+
}
}
unsafe_impl_pod!(i8, u8, i16, u16, i32, u32, i64, u64);
#[repr(C)]
#[derive(Copy, Clone, Debug)]
pub(crate) struct bpf_map_def {
pub(crate) map_type: u32,
pub(crate) key_size: u32,
pub(crate) value_size: u32,
pub(crate) max_entries: u32,
pub(crate) map_flags: u32,
}
#[derive(Debug)]
pub struct Bpf {
maps: HashMap<String, RefCell<Map>>,
programs: HashMap<String, Program>,
}
impl Bpf {
pub fn load(data: &[u8]) -> Result<Bpf, BpfError> {
let mut obj = Object::parse(data)?;
obj.relocate_btf()?;
let mut maps = Vec::new();
for (_, obj) in obj.maps.drain() {
let mut map = Map { obj, fd: None };
let fd = map.create()?;
if !map.obj.data.is_empty() && map.obj.name != ".bss" {
bpf_map_update_elem_ptr(fd, &0 as *const _, map.obj.data.as_ptr(), 0)
.map_err(|(code, io_error)| MapError::UpdateElementFailed { code, io_error })?;
}
maps.push(map);
}
obj.relocate_maps(maps.as_slice())?;
let programs = obj
.programs
.drain()
.map(|(name, obj)| {
let kind = obj.kind;
let data = ProgramData {
obj,
name: name.clone(),
fd: None,
links: Vec::new(),
};
let program = match kind {
crate::obj::ProgramKind::KProbe => Program::KProbe(KProbe { data }),
crate::obj::ProgramKind::UProbe => Program::UProbe(UProbe { data }),
crate::obj::ProgramKind::TracePoint => Program::TracePoint(TracePoint { data }),
crate::obj::ProgramKind::SocketFilter => {
Program::SocketFilter(SocketFilter { data })
}
crate::obj::ProgramKind::Xdp => Program::Xdp(Xdp { data }),
};
(name, program)
})
.collect();
Ok(Bpf {
maps: maps
.drain(..)
.map(|map| (map.obj.name.clone(), RefCell::new(map)))
.collect(),
programs,
})
}
pub fn map<'a, 'slf: 'a, T: TryFrom<Ref<'a, Map>>>(
&'slf self,
name: &str,
) -> Result<Option<T>, <T as TryFrom<Ref<'a, Map>>>::Error> {
self.maps
.get(name)
.map(|cell| T::try_from(cell.borrow()))
.transpose()
}
pub fn map_mut<'a, 'slf: 'a, T: TryFrom<RefMut<'a, Map>>>(
&'slf self,
name: &str,
) -> Result<Option<T>, <T as TryFrom<RefMut<'a, Map>>>::Error> {
self.maps
.get(name)
.map(|cell| T::try_from(cell.borrow_mut()))
.transpose()
}
pub fn program<'a, 'slf: 'a, T: TryFrom<&'a Program>>(
&'slf self,
name: &str,
) -> Result<Option<T>, <T as TryFrom<&'a Program>>::Error> {
self.programs.get(name).map(|p| T::try_from(p)).transpose()
}
pub fn program_mut<'a, 'slf: 'a, T: TryFrom<&'a mut Program>>(
&'slf mut self,
name: &str,
) -> Result<Option<T>, <T as TryFrom<&'a mut Program>>::Error> {
self.programs
.get_mut(name)
.map(|p| T::try_from(p))
.transpose()
}
}
#[derive(Debug, Error)]
pub enum BpfError {
#[error("error parsing BPF object: {0}")]
ParseError(#[from] ParseError),
#[error("error relocating BPF object: {0}")]
RelocationError(#[from] RelocationError),
#[error("BTF error: {error}")]
BtfRelocationError {
#[from]
error: BtfRelocationError,
},
#[error("map error: {0}")]
MapError(#[from] MapError),
#[error("program error: {0}")]
ProgramError(#[from] ProgramError),
}