From 2cec04c5781bc7b03c601dbb0cb1c23f3df22385 Mon Sep 17 00:00:00 2001 From: Alessandro Decina Date: Sun, 14 Feb 2021 07:48:31 +0000 Subject: [PATCH] bpf: add explicit BTF argument to the load API Add a `target_btf: Option` argument to Bpf::load. None can be passed to indicate to skip BTF relocation, for example for kernels that don't support it. Some(btf) can be used to pass BTF parsed with Btf::from_sys_fs() or Btf::parse/parse_file. Finally, add a simpler Bpf::load_file(path) that uses from_sys_fs() internally to simplify the common case. --- aya/src/bpf.rs | 40 +++++++++++++++++++++++++++++------ aya/src/lib.rs | 2 ++ aya/src/obj/btf/btf.rs | 28 ++++++++++++++++++++++-- aya/src/obj/btf/relocation.rs | 15 ++----------- 4 files changed, 63 insertions(+), 22 deletions(-) diff --git a/aya/src/bpf.rs b/aya/src/bpf.rs index bd70f219..8dafe51d 100644 --- a/aya/src/bpf.rs +++ b/aya/src/bpf.rs @@ -1,10 +1,19 @@ -use std::{collections::HashMap, convert::TryFrom, error::Error, io}; +use std::{ + collections::HashMap, + convert::TryFrom, + error::Error, + fs, io, + path::{Path, PathBuf}, +}; use thiserror::Error; use crate::{ maps::{Map, MapError, MapLock, MapRef, MapRefMut}, - obj::{btf::BtfError, Object, ParseError}, + obj::{ + btf::{Btf, BtfError}, + Object, ParseError, + }, programs::{KProbe, Program, ProgramData, ProgramError, SocketFilter, TracePoint, UProbe, Xdp}, sys::bpf_map_update_elem_ptr, }; @@ -46,10 +55,23 @@ pub struct Bpf { } impl Bpf { - pub fn load(data: &[u8]) -> Result { + pub fn load_file>(path: P) -> Result { + let path = path.as_ref(); + Bpf::load( + &fs::read(path).map_err(|error| BpfError::FileError { + path: path.to_owned(), + error, + })?, + Some(Btf::from_sys_fs()?), + ) + } + + pub fn load(data: &[u8], target_btf: Option) -> Result { let mut obj = Object::parse(data)?; - obj.relocate_btf()?; + if let Some(btf) = target_btf { + obj.relocate_btf(btf)?; + } let mut maps = Vec::new(); for (_, obj) in obj.maps.drain() { @@ -152,13 +174,17 @@ impl Bpf { #[derive(Debug, Error)] pub enum BpfError { - #[error("IO error: {0}")] - IO(#[from] io::Error), + #[error("error loading {path}")] + FileError { + path: PathBuf, + #[source] + error: io::Error, + }, #[error("error parsing BPF object: {0}")] ParseError(#[from] ParseError), - #[error("BTF error: {0}")] + #[error("BTF error")] BtfError(#[from] BtfError), #[error("error relocating BPF program `{program_name}`: {error}")] diff --git a/aya/src/lib.rs b/aya/src/lib.rs index fe7dc5d4..11914960 100644 --- a/aya/src/lib.rs +++ b/aya/src/lib.rs @@ -14,3 +14,5 @@ mod sys; pub mod util; pub use bpf::*; +pub use obj::btf::{Btf, BtfError}; +pub use object::Endianness; diff --git a/aya/src/obj/btf/btf.rs b/aya/src/obj/btf/btf.rs index 838e05a8..96323911 100644 --- a/aya/src/obj/btf/btf.rs +++ b/aya/src/obj/btf/btf.rs @@ -2,7 +2,9 @@ use std::{ borrow::Cow, convert::TryInto, ffi::{c_void, CStr}, - mem, ptr, + fs, io, mem, + path::{Path, PathBuf}, + ptr, }; use object::Endianness; @@ -17,8 +19,15 @@ use crate::{ pub(crate) const MAX_RESOLVE_DEPTH: u8 = 32; pub(crate) const MAX_SPEC_LEN: usize = 64; -#[derive(Error, Debug, Clone, Eq, PartialEq)] +#[derive(Error, Debug)] pub enum BtfError { + #[error("error parsing {path}")] + FileError { + path: PathBuf, + #[source] + error: io::Error, + }, + #[error("error parsing BTF header")] InvalidHeader, @@ -70,6 +79,21 @@ pub struct Btf { } impl Btf { + pub fn from_sys_fs() -> Result { + Btf::parse_file("/sys/kernel/btf/vmlinux", Endianness::default()) + } + + pub fn parse_file>(path: P, endianness: Endianness) -> Result { + let path = path.as_ref(); + Btf::parse( + &fs::read(path).map_err(|error| BtfError::FileError { + path: path.to_owned(), + error, + })?, + endianness, + ) + } + pub(crate) fn parse(data: &[u8], endianness: Endianness) -> Result { if data.len() < mem::size_of::() { return Err(BtfError::InvalidHeader); diff --git a/aya/src/obj/btf/relocation.rs b/aya/src/obj/btf/relocation.rs index 5f0f227f..4a93511c 100644 --- a/aya/src/obj/btf/relocation.rs +++ b/aya/src/obj/btf/relocation.rs @@ -1,10 +1,9 @@ use std::{ collections::HashMap, convert::{TryFrom, TryInto}, - fs, io, mem, ptr, + io, mem, ptr, }; -use object::{Endian, Endianness, NativeEndian}; use thiserror::Error; use crate::{ @@ -152,22 +151,12 @@ impl Relocation { } impl Object { - pub fn relocate_btf(&mut self) -> Result<(), BpfError> { + pub fn relocate_btf(&mut self, target_btf: Btf) -> Result<(), BpfError> { let (local_btf, btf_ext) = match (&self.btf, &self.btf_ext) { (Some(btf), Some(btf_ext)) => (btf, btf_ext), _ => return Ok(()), }; - let target_btf = fs::read("/sys/kernel/btf/vmlinux")?; - let target_btf = Btf::parse(&target_btf, { - let e = NativeEndian; - if e.is_little_endian() { - Endianness::Little - } else { - Endianness::Big - } - })?; - let mut candidates_cache = HashMap::>::new(); for (sec_name_off, relos) in btf_ext.relocations() { let section_name = local_btf.string_at(*sec_name_off)?;