bpf: add explicit BTF argument to the load API

Add a `target_btf: Option<Btf>` 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.
pull/1/head
Alessandro Decina 4 years ago
parent 01e9f81043
commit 2cec04c578

@ -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 thiserror::Error;
use crate::{ use crate::{
maps::{Map, MapError, MapLock, MapRef, MapRefMut}, 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}, programs::{KProbe, Program, ProgramData, ProgramError, SocketFilter, TracePoint, UProbe, Xdp},
sys::bpf_map_update_elem_ptr, sys::bpf_map_update_elem_ptr,
}; };
@ -46,10 +55,23 @@ pub struct Bpf {
} }
impl Bpf { impl Bpf {
pub fn load(data: &[u8]) -> Result<Bpf, BpfError> { pub fn load_file<P: AsRef<Path>>(path: P) -> Result<Bpf, BpfError> {
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<Btf>) -> Result<Bpf, BpfError> {
let mut obj = Object::parse(data)?; let mut obj = Object::parse(data)?;
obj.relocate_btf()?; if let Some(btf) = target_btf {
obj.relocate_btf(btf)?;
}
let mut maps = Vec::new(); let mut maps = Vec::new();
for (_, obj) in obj.maps.drain() { for (_, obj) in obj.maps.drain() {
@ -152,13 +174,17 @@ impl Bpf {
#[derive(Debug, Error)] #[derive(Debug, Error)]
pub enum BpfError { pub enum BpfError {
#[error("IO error: {0}")] #[error("error loading {path}")]
IO(#[from] io::Error), FileError {
path: PathBuf,
#[source]
error: io::Error,
},
#[error("error parsing BPF object: {0}")] #[error("error parsing BPF object: {0}")]
ParseError(#[from] ParseError), ParseError(#[from] ParseError),
#[error("BTF error: {0}")] #[error("BTF error")]
BtfError(#[from] BtfError), BtfError(#[from] BtfError),
#[error("error relocating BPF program `{program_name}`: {error}")] #[error("error relocating BPF program `{program_name}`: {error}")]

@ -14,3 +14,5 @@ mod sys;
pub mod util; pub mod util;
pub use bpf::*; pub use bpf::*;
pub use obj::btf::{Btf, BtfError};
pub use object::Endianness;

@ -2,7 +2,9 @@ use std::{
borrow::Cow, borrow::Cow,
convert::TryInto, convert::TryInto,
ffi::{c_void, CStr}, ffi::{c_void, CStr},
mem, ptr, fs, io, mem,
path::{Path, PathBuf},
ptr,
}; };
use object::Endianness; use object::Endianness;
@ -17,8 +19,15 @@ use crate::{
pub(crate) const MAX_RESOLVE_DEPTH: u8 = 32; pub(crate) const MAX_RESOLVE_DEPTH: u8 = 32;
pub(crate) const MAX_SPEC_LEN: usize = 64; pub(crate) const MAX_SPEC_LEN: usize = 64;
#[derive(Error, Debug, Clone, Eq, PartialEq)] #[derive(Error, Debug)]
pub enum BtfError { pub enum BtfError {
#[error("error parsing {path}")]
FileError {
path: PathBuf,
#[source]
error: io::Error,
},
#[error("error parsing BTF header")] #[error("error parsing BTF header")]
InvalidHeader, InvalidHeader,
@ -70,6 +79,21 @@ pub struct Btf {
} }
impl Btf { impl Btf {
pub fn from_sys_fs() -> Result<Btf, BtfError> {
Btf::parse_file("/sys/kernel/btf/vmlinux", Endianness::default())
}
pub fn parse_file<P: AsRef<Path>>(path: P, endianness: Endianness) -> Result<Btf, BtfError> {
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<Btf, BtfError> { pub(crate) fn parse(data: &[u8], endianness: Endianness) -> Result<Btf, BtfError> {
if data.len() < mem::size_of::<btf_header>() { if data.len() < mem::size_of::<btf_header>() {
return Err(BtfError::InvalidHeader); return Err(BtfError::InvalidHeader);

@ -1,10 +1,9 @@
use std::{ use std::{
collections::HashMap, collections::HashMap,
convert::{TryFrom, TryInto}, convert::{TryFrom, TryInto},
fs, io, mem, ptr, io, mem, ptr,
}; };
use object::{Endian, Endianness, NativeEndian};
use thiserror::Error; use thiserror::Error;
use crate::{ use crate::{
@ -152,22 +151,12 @@ impl Relocation {
} }
impl Object { 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) { let (local_btf, btf_ext) = match (&self.btf, &self.btf_ext) {
(Some(btf), Some(btf_ext)) => (btf, btf_ext), (Some(btf), Some(btf_ext)) => (btf, btf_ext),
_ => return Ok(()), _ => 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::<u32, Vec<Candidate>>::new(); let mut candidates_cache = HashMap::<u32, Vec<Candidate>>::new();
for (sec_name_off, relos) in btf_ext.relocations() { for (sec_name_off, relos) in btf_ext.relocations() {
let section_name = local_btf.string_at(*sec_name_off)?; let section_name = local_btf.string_at(*sec_name_off)?;

Loading…
Cancel
Save