Merge pull request #343 from dave-tucker/pinning-redux

Small Pinning API improvements
pull/355/head
Dave Tucker 2 years ago committed by GitHub
commit 8e6c9ad0d2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -400,7 +400,10 @@ impl<'a> BpfLoader<'a> {
}
Err(_) => {
let fd = map.create(&name)?;
map.pin(&name, path)?;
map.pin(&name, path).map_err(|error| MapError::PinError {
name: name.to_string(),
error,
})?;
fd
}
}
@ -774,12 +777,19 @@ impl Bpf {
/// # Examples
/// ```no_run
/// # use std::path::Path;
/// # #[derive(thiserror::Error, Debug)]
/// # enum Error {
/// # #[error(transparent)]
/// # Bpf(#[from] aya::BpfError),
/// # #[error(transparent)]
/// # Pin(#[from] aya::pin::PinError)
/// # }
/// # let mut bpf = aya::Bpf::load(&[])?;
/// # let pin_path = Path::new("/tmp/pin_path");
/// for (_, program) in bpf.programs_mut() {
/// program.pin(pin_path)?;
/// }
/// # Ok::<(), aya::BpfError>(())
/// # Ok::<(), Error>(())
/// ```
pub fn programs_mut(&mut self) -> impl Iterator<Item = (&str, &mut Program)> {
self.programs.iter_mut().map(|(s, p)| (s.as_str(), p))

@ -48,6 +48,7 @@ mod bpf;
mod generated;
pub mod maps;
mod obj;
pub mod pin;
pub mod programs;
mod sys;
pub mod util;

@ -51,6 +51,7 @@ use thiserror::Error;
use crate::{
generated::bpf_map_type,
obj,
pin::PinError,
sys::{bpf_create_map, bpf_get_object, bpf_map_get_next_key, bpf_pin_object, kernel_version},
util::nr_cpus,
Pod,
@ -119,13 +120,6 @@ pub enum MapError {
name: String,
},
/// The map has already been pinned
#[error("the map `{name}` has already been pinned")]
AlreadyPinned {
/// Map name
name: String,
},
/// Failed to create map
#[error("failed to create map `{name}` with code {code}")]
CreateError {
@ -138,18 +132,6 @@ pub enum MapError {
io_error: io::Error,
},
/// Failed to pin map
#[error("failed to pin map `{name}` with code {code}")]
PinError {
/// Map Name
name: String,
/// Error code
code: libc::c_long,
#[source]
/// Original io::Error
io_error: io::Error,
},
/// Invalid key size
#[error("invalid key size {size}, expected {expected}")]
InvalidKeySize {
@ -214,6 +196,16 @@ pub enum MapError {
/// Map name
name: String,
},
/// Could not pin map by name
#[error("map `{name}` requested pinning by name. pinning failed")]
PinError {
/// The map name
name: String,
/// The reason for the failure
#[source]
error: PinError,
},
}
/// A map file descriptor.
@ -316,11 +308,12 @@ impl Map {
})
}
};
let fd = bpf_get_object(&path_string).map_err(|(code, io_error)| MapError::PinError {
name: name.into(),
code,
io_error,
})? as RawFd;
let fd =
bpf_get_object(&path_string).map_err(|(code, io_error)| MapError::SyscallError {
call: "BPF_OBJ_GET".to_string(),
code,
io_error,
})? as RawFd;
self.fd = Some(fd);
@ -336,20 +329,21 @@ impl Map {
self.fd.ok_or(MapError::NotCreated)
}
pub(crate) fn pin<P: AsRef<Path>>(&mut self, name: &str, path: P) -> Result<(), MapError> {
pub(crate) fn pin<P: AsRef<Path>>(&mut self, name: &str, path: P) -> Result<(), PinError> {
if self.pinned {
return Err(MapError::AlreadyPinned { name: name.into() });
return Err(PinError::AlreadyPinned { name: name.into() });
}
let map_path = path.as_ref().join(name);
let fd = self.fd_or_err()?;
let fd = self.fd.ok_or(PinError::NoFd {
name: name.to_string(),
})?;
let path_string = CString::new(map_path.to_string_lossy().into_owned()).map_err(|e| {
MapError::InvalidPinPath {
PinError::InvalidPinPath {
error: e.to_string(),
}
})?;
bpf_pin_object(fd, &path_string).map_err(|(code, io_error)| MapError::SyscallError {
call: "BPF_OBJ_PIN".to_string(),
code,
bpf_pin_object(fd, &path_string).map_err(|(_, io_error)| PinError::SyscallError {
name: "BPF_OBJ_GET".to_string(),
io_error,
})?;
self.pinned = true;

@ -0,0 +1,35 @@
//! Pinning BPF objects to the BPF filesystem.
use std::io;
use thiserror::Error;
/// An error ocurred working with a pinned BPF object.
#[derive(Error, Debug)]
pub enum PinError {
/// The object has already been pinned.
#[error("the BPF object `{name}` has already been pinned")]
AlreadyPinned {
/// Object name.
name: String,
},
/// The object FD is not known by Aya.
#[error("the BPF object `{name}`'s FD is not known")]
NoFd {
/// Object name.
name: String,
},
/// The path for the BPF object is not valid.
#[error("invalid pin path `{error}`")]
InvalidPinPath {
/// The error message.
error: String,
},
/// An error ocurred making a syscall.
#[error("{name} failed")]
SyscallError {
/// The syscall name.
name: String,
/// The [`io::Error`] returned by the syscall.
#[source]
io_error: io::Error,
},
}

@ -4,11 +4,18 @@ use libc::{close, dup};
use std::{
borrow::Borrow,
collections::{hash_map::Entry, HashMap},
ffi::CString,
ops::Deref,
os::unix::prelude::RawFd,
path::Path,
};
use crate::{generated::bpf_attach_type, programs::ProgramError, sys::bpf_prog_detach};
use crate::{
generated::bpf_attach_type,
pin::PinError,
programs::ProgramError,
sys::{bpf_pin_object, bpf_prog_detach},
};
/// A Link.
pub trait Link: std::fmt::Debug + 'static {
@ -111,6 +118,26 @@ impl FdLink {
pub(crate) fn new(fd: RawFd) -> FdLink {
FdLink { fd }
}
/// Pins the FdLink to a BPF filesystem.
///
/// When a BPF object is pinned to a BPF filesystem it will remain attached after
/// Aya has detached the link.
/// To remove the attachment, the file on the BPF filesystem must be removed.
/// Any directories in the the path provided should have been created by the caller.
pub fn pin<P: AsRef<Path>>(&self, path: P) -> Result<(), PinError> {
let path_string =
CString::new(path.as_ref().to_string_lossy().into_owned()).map_err(|e| {
PinError::InvalidPinPath {
error: e.to_string(),
}
})?;
bpf_pin_object(self.fd, &path_string).map_err(|(_, io_error)| PinError::SyscallError {
name: "BPF_OBJ_PIN".to_string(),
io_error,
})?;
Ok(())
}
}
impl Link for FdLink {

@ -106,6 +106,7 @@ use crate::{
generated::{bpf_attach_type, bpf_prog_info, bpf_prog_type},
maps::MapError,
obj::{self, btf::BtfError, Function, KernelVersion},
pin::PinError,
sys::{
bpf_get_object, bpf_load_program, bpf_obj_get_info_by_fd, bpf_pin_object,
bpf_prog_get_fd_by_id, bpf_prog_query, retry_with_verifier_logs, BpfLoadProgramAttrs,
@ -163,13 +164,6 @@ pub enum ProgramError {
#[error("unexpected program type")]
UnexpectedProgramType,
/// Invalid pin path
#[error("invalid pin path `{error}`")]
InvalidPinPath {
/// the error message
error: String,
},
/// A map error occurred while loading or attaching a program.
#[error(transparent)]
MapError(#[from] MapError),
@ -307,31 +301,31 @@ impl Program {
}
/// Pin the program to the provided path
pub fn pin<P: AsRef<Path>>(&mut self, path: P) -> Result<(), ProgramError> {
pub fn pin<P: AsRef<Path>>(&mut self, path: P) -> Result<(), PinError> {
match self {
Program::KProbe(p) => p.data.pin(path),
Program::UProbe(p) => p.data.pin(path),
Program::TracePoint(p) => p.data.pin(path),
Program::SocketFilter(p) => p.data.pin(path),
Program::Xdp(p) => p.data.pin(path),
Program::SkMsg(p) => p.data.pin(path),
Program::SkSkb(p) => p.data.pin(path),
Program::SockOps(p) => p.data.pin(path),
Program::SchedClassifier(p) => p.data.pin(path),
Program::CgroupSkb(p) => p.data.pin(path),
Program::CgroupSysctl(p) => p.data.pin(path),
Program::CgroupSockopt(p) => p.data.pin(path),
Program::LircMode2(p) => p.data.pin(path),
Program::PerfEvent(p) => p.data.pin(path),
Program::RawTracePoint(p) => p.data.pin(path),
Program::Lsm(p) => p.data.pin(path),
Program::BtfTracePoint(p) => p.data.pin(path),
Program::FEntry(p) => p.data.pin(path),
Program::FExit(p) => p.data.pin(path),
Program::Extension(p) => p.data.pin(path),
Program::CgroupSockAddr(p) => p.data.pin(path),
Program::SkLookup(p) => p.data.pin(path),
Program::CgroupSock(p) => p.data.pin(path),
Program::KProbe(p) => p.pin(path),
Program::UProbe(p) => p.pin(path),
Program::TracePoint(p) => p.pin(path),
Program::SocketFilter(p) => p.pin(path),
Program::Xdp(p) => p.pin(path),
Program::SkMsg(p) => p.pin(path),
Program::SkSkb(p) => p.pin(path),
Program::SockOps(p) => p.pin(path),
Program::SchedClassifier(p) => p.pin(path),
Program::CgroupSkb(p) => p.pin(path),
Program::CgroupSysctl(p) => p.pin(path),
Program::CgroupSockopt(p) => p.pin(path),
Program::LircMode2(p) => p.pin(path),
Program::PerfEvent(p) => p.pin(path),
Program::RawTracePoint(p) => p.pin(path),
Program::Lsm(p) => p.pin(path),
Program::BtfTracePoint(p) => p.pin(path),
Program::FEntry(p) => p.pin(path),
Program::FExit(p) => p.pin(path),
Program::Extension(p) => p.pin(path),
Program::CgroupSockAddr(p) => p.pin(path),
Program::SkLookup(p) => p.pin(path),
Program::CgroupSock(p) => p.pin(path),
}
}
@ -441,23 +435,6 @@ impl<T: Link> ProgramData<T> {
self.fd.ok_or(ProgramError::NotLoaded)
}
pub fn pin<P: AsRef<Path>>(&mut self, path: P) -> Result<(), ProgramError> {
let fd = self.fd_or_err()?;
let path_string =
CString::new(path.as_ref().to_string_lossy().into_owned()).map_err(|e| {
MapError::InvalidPinPath {
error: e.to_string(),
}
})?;
bpf_pin_object(fd, &path_string).map_err(|(_code, io_error)| {
ProgramError::SyscallError {
call: "BPF_OBJ_PIN".to_string(),
io_error,
}
})?;
Ok(())
}
pub(crate) fn take_link(&mut self, link_id: T::Id) -> Result<T, ProgramError> {
self.links.forget(link_id)
}
@ -472,6 +449,29 @@ fn unload_program<T: Link>(data: &mut ProgramData<T>) -> Result<(), ProgramError
Ok(())
}
fn pin_program<T: Link, P: AsRef<Path>>(
data: &mut ProgramData<T>,
path: P,
) -> Result<(), PinError> {
let fd = data.fd.ok_or(PinError::NoFd {
name: data
.name
.as_ref()
.unwrap_or(&"<unknown program>".to_string())
.to_string(),
})?;
let path_string = CString::new(path.as_ref().to_string_lossy().into_owned()).map_err(|e| {
PinError::InvalidPinPath {
error: e.to_string(),
}
})?;
bpf_pin_object(fd, &path_string).map_err(|(_, io_error)| PinError::SyscallError {
name: "BPF_OBJ_PIN".to_string(),
io_error,
})?;
Ok(())
}
fn load_program<T: Link>(
prog_type: bpf_prog_type,
data: &mut ProgramData<T>,
@ -673,6 +673,50 @@ impl_fd!(
CgroupSock,
);
macro_rules! impl_program_pin{
($($struct_name:ident),+ $(,)?) => {
$(
impl $struct_name {
/// Pins the program to a BPF filesystem.
///
/// When a BPF object is pinned to a BPF filesystem it will remain loaded after
/// Aya has unloaded the program.
/// To remove the program, the file on the BPF filesystem must be removed.
/// Any directories in the the path provided should have been created by the caller.
pub fn pin<P: AsRef<Path>>(&mut self, path: P) -> Result<(), PinError> {
pin_program(&mut self.data, path)
}
}
)+
}
}
impl_program_pin!(
KProbe,
UProbe,
TracePoint,
SocketFilter,
Xdp,
SkMsg,
SkSkb,
SchedClassifier,
CgroupSkb,
CgroupSysctl,
CgroupSockopt,
LircMode2,
PerfEvent,
Lsm,
RawTracePoint,
BtfTracePoint,
FEntry,
FExit,
Extension,
CgroupSockAddr,
SkLookup,
SockOps,
CgroupSock,
);
macro_rules! impl_try_from_program {
($($ty:ident),+ $(,)?) => {
$(
@ -770,17 +814,10 @@ impl ProgramInfo {
/// Loads a program from a pinned path in bpffs.
pub fn from_pinned<P: AsRef<Path>>(path: P) -> Result<ProgramInfo, ProgramError> {
let path_string = match CString::new(path.as_ref().to_str().unwrap()) {
Ok(s) => s,
Err(e) => {
return Err(ProgramError::InvalidPinPath {
error: e.to_string(),
})
}
};
let path_string = CString::new(path.as_ref().to_str().unwrap()).unwrap();
let fd =
bpf_get_object(&path_string).map_err(|(_, io_error)| ProgramError::SyscallError {
call: "bpf_obj_get".to_owned(),
call: "BPF_OBJ_GET".to_owned(),
io_error,
})? as RawFd;
@ -788,7 +825,6 @@ impl ProgramInfo {
call: "bpf_obj_get_info_by_fd".to_owned(),
io_error,
})?;
unsafe {
libc::close(fd);
}

Loading…
Cancel
Save