Merge pull request #366 from dave-tucker/pin-redux-2

aya: Fix Link Pinning
pull/374/head
Dave Tucker 2 years ago committed by GitHub
commit 4826bf7f74
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -10,8 +10,7 @@ use crate::{
bpf_prog_type::BPF_PROG_TYPE_CGROUP_SKB, bpf_prog_type::BPF_PROG_TYPE_CGROUP_SKB,
}, },
programs::{ programs::{
define_link_wrapper, load_program, FdLink, Link, OwnedLink, ProgAttachLink, ProgramData, define_link_wrapper, load_program, FdLink, Link, ProgAttachLink, ProgramData, ProgramError,
ProgramError,
}, },
sys::{bpf_link_create, bpf_prog_attach, kernel_version}, sys::{bpf_link_create, bpf_prog_attach, kernel_version},
}; };
@ -127,11 +126,8 @@ impl CgroupSkb {
/// ///
/// The link will be detached on `Drop` and the caller is now responsible /// The link will be detached on `Drop` and the caller is now responsible
/// for managing its lifetime. /// for managing its lifetime.
pub fn take_link( pub fn take_link(&mut self, link_id: CgroupSkbLinkId) -> Result<CgroupSkbLink, ProgramError> {
&mut self, self.data.take_link(link_id)
link_id: CgroupSkbLinkId,
) -> Result<OwnedLink<CgroupSkbLink>, ProgramError> {
Ok(OwnedLink::new(self.data.take_link(link_id)?))
} }
/// Detaches the program. /// Detaches the program.

@ -10,8 +10,7 @@ use std::{
use crate::{ use crate::{
generated::bpf_prog_type::BPF_PROG_TYPE_CGROUP_SOCK, generated::bpf_prog_type::BPF_PROG_TYPE_CGROUP_SOCK,
programs::{ programs::{
define_link_wrapper, load_program, FdLink, Link, OwnedLink, ProgAttachLink, ProgramData, define_link_wrapper, load_program, FdLink, Link, ProgAttachLink, ProgramData, ProgramError,
ProgramError,
}, },
sys::{bpf_link_create, bpf_prog_attach, kernel_version}, sys::{bpf_link_create, bpf_prog_attach, kernel_version},
}; };
@ -105,11 +104,8 @@ impl CgroupSock {
/// ///
/// The link will be detached on `Drop` and the caller is now responsible /// The link will be detached on `Drop` and the caller is now responsible
/// for managing its lifetime. /// for managing its lifetime.
pub fn take_link( pub fn take_link(&mut self, link_id: CgroupSockLinkId) -> Result<CgroupSockLink, ProgramError> {
&mut self, self.data.take_link(link_id)
link_id: CgroupSockLinkId,
) -> Result<OwnedLink<CgroupSockLink>, ProgramError> {
Ok(OwnedLink::new(self.data.take_link(link_id)?))
} }
/// Detaches the program. /// Detaches the program.

@ -10,8 +10,7 @@ use std::{
use crate::{ use crate::{
generated::bpf_prog_type::BPF_PROG_TYPE_CGROUP_SOCK_ADDR, generated::bpf_prog_type::BPF_PROG_TYPE_CGROUP_SOCK_ADDR,
programs::{ programs::{
define_link_wrapper, load_program, FdLink, Link, OwnedLink, ProgAttachLink, ProgramData, define_link_wrapper, load_program, FdLink, Link, ProgAttachLink, ProgramData, ProgramError,
ProgramError,
}, },
sys::{bpf_link_create, bpf_prog_attach, kernel_version}, sys::{bpf_link_create, bpf_prog_attach, kernel_version},
}; };
@ -109,8 +108,8 @@ impl CgroupSockAddr {
pub fn take_link( pub fn take_link(
&mut self, &mut self,
link_id: CgroupSockAddrLinkId, link_id: CgroupSockAddrLinkId,
) -> Result<OwnedLink<CgroupSockAddrLink>, ProgramError> { ) -> Result<CgroupSockAddrLink, ProgramError> {
Ok(OwnedLink::new(self.data.take_link(link_id)?)) self.data.take_link(link_id)
} }
/// Detaches the program. /// Detaches the program.

@ -9,8 +9,8 @@ use std::{
use crate::{ use crate::{
generated::bpf_prog_type::BPF_PROG_TYPE_CGROUP_SOCKOPT, generated::bpf_prog_type::BPF_PROG_TYPE_CGROUP_SOCKOPT,
programs::{ programs::{
bpf_attach_type, define_link_wrapper, load_program, FdLink, Link, OwnedLink, bpf_attach_type, define_link_wrapper, load_program, FdLink, Link, ProgAttachLink,
ProgAttachLink, ProgramData, ProgramError, ProgramData, ProgramError,
}, },
sys::{bpf_link_create, bpf_prog_attach, kernel_version}, sys::{bpf_link_create, bpf_prog_attach, kernel_version},
}; };
@ -105,8 +105,8 @@ impl CgroupSockopt {
pub fn take_link( pub fn take_link(
&mut self, &mut self,
link_id: CgroupSockoptLinkId, link_id: CgroupSockoptLinkId,
) -> Result<OwnedLink<CgroupSockoptLink>, ProgramError> { ) -> Result<CgroupSockoptLink, ProgramError> {
Ok(OwnedLink::new(self.data.take_link(link_id)?)) self.data.take_link(link_id)
} }
/// Detaches the program. /// Detaches the program.

@ -7,8 +7,7 @@ use std::{
use crate::{ use crate::{
generated::{bpf_attach_type::BPF_CGROUP_SYSCTL, bpf_prog_type::BPF_PROG_TYPE_CGROUP_SYSCTL}, generated::{bpf_attach_type::BPF_CGROUP_SYSCTL, bpf_prog_type::BPF_PROG_TYPE_CGROUP_SYSCTL},
programs::{ programs::{
define_link_wrapper, load_program, FdLink, Link, OwnedLink, ProgAttachLink, ProgramData, define_link_wrapper, load_program, FdLink, Link, ProgAttachLink, ProgramData, ProgramError,
ProgramError,
}, },
sys::{bpf_link_create, bpf_prog_attach, kernel_version}, sys::{bpf_link_create, bpf_prog_attach, kernel_version},
}; };
@ -101,8 +100,8 @@ impl CgroupSysctl {
pub fn take_link( pub fn take_link(
&mut self, &mut self,
link_id: CgroupSysctlLinkId, link_id: CgroupSysctlLinkId,
) -> Result<OwnedLink<CgroupSysctlLink>, ProgramError> { ) -> Result<CgroupSysctlLink, ProgramError> {
Ok(OwnedLink::new(self.data.take_link(link_id)?)) self.data.take_link(link_id)
} }
/// Detaches the program. /// Detaches the program.

@ -8,8 +8,7 @@ use crate::{
generated::{bpf_attach_type::BPF_CGROUP_INET_INGRESS, bpf_prog_type::BPF_PROG_TYPE_EXT}, generated::{bpf_attach_type::BPF_CGROUP_INET_INGRESS, bpf_prog_type::BPF_PROG_TYPE_EXT},
obj::btf::BtfKind, obj::btf::BtfKind,
programs::{ programs::{
define_link_wrapper, load_program, FdLink, FdLinkId, OwnedLink, ProgramData, ProgramError, define_link_wrapper, load_program, FdLink, FdLinkId, ProgramData, ProgramError, ProgramFd,
ProgramFd,
}, },
sys::{self, bpf_link_create}, sys::{self, bpf_link_create},
Btf, Btf,
@ -139,11 +138,8 @@ impl Extension {
/// ///
/// The link will be detached on `Drop` and the caller is now responsible /// The link will be detached on `Drop` and the caller is now responsible
/// for managing its lifetime. /// for managing its lifetime.
pub fn take_link( pub fn take_link(&mut self, link_id: ExtensionLinkId) -> Result<ExtensionLink, ProgramError> {
&mut self, self.data.take_link(link_id)
link_id: ExtensionLinkId,
) -> Result<OwnedLink<ExtensionLink>, ProgramError> {
Ok(OwnedLink::new(self.data.take_link(link_id)?))
} }
} }

@ -5,7 +5,7 @@ use crate::{
obj::btf::{Btf, BtfKind}, obj::btf::{Btf, BtfKind},
programs::{ programs::{
define_link_wrapper, load_program, utils::attach_raw_tracepoint, FdLink, FdLinkId, define_link_wrapper, load_program, utils::attach_raw_tracepoint, FdLink, FdLinkId,
OwnedLink, ProgramData, ProgramError, ProgramData, ProgramError,
}, },
}; };
@ -79,11 +79,8 @@ impl FEntry {
/// ///
/// The link will be detached on `Drop` and the caller is now responsible /// The link will be detached on `Drop` and the caller is now responsible
/// for managing its lifetime. /// for managing its lifetime.
pub fn take_link( pub fn take_link(&mut self, link_id: FEntryLinkId) -> Result<FEntryLink, ProgramError> {
&mut self, self.data.take_link(link_id)
link_id: FEntryLinkId,
) -> Result<OwnedLink<FEntryLink>, ProgramError> {
Ok(OwnedLink::new(self.data.take_link(link_id)?))
} }
} }

@ -5,7 +5,7 @@ use crate::{
obj::btf::{Btf, BtfKind}, obj::btf::{Btf, BtfKind},
programs::{ programs::{
define_link_wrapper, load_program, utils::attach_raw_tracepoint, FdLink, FdLinkId, define_link_wrapper, load_program, utils::attach_raw_tracepoint, FdLink, FdLinkId,
OwnedLink, ProgramData, ProgramError, ProgramData, ProgramError,
}, },
}; };
@ -79,11 +79,8 @@ impl FExit {
/// ///
/// The link will be detached on `Drop` and the caller is now responsible /// The link will be detached on `Drop` and the caller is now responsible
/// for managing its lifetime. /// for managing its lifetime.
pub fn take_link( pub fn take_link(&mut self, link_id: FExitLinkId) -> Result<FExitLink, ProgramError> {
&mut self, self.data.take_link(link_id)
link_id: FExitLinkId,
) -> Result<OwnedLink<FExitLink>, ProgramError> {
Ok(OwnedLink::new(self.data.take_link(link_id)?))
} }
} }

@ -8,7 +8,7 @@ use crate::{
define_link_wrapper, load_program, define_link_wrapper, load_program,
perf_attach::{PerfLink, PerfLinkId}, perf_attach::{PerfLink, PerfLinkId},
probe::{attach, ProbeKind}, probe::{attach, ProbeKind},
OwnedLink, ProgramData, ProgramError, ProgramData, ProgramError,
}, },
}; };
@ -80,11 +80,8 @@ impl KProbe {
/// ///
/// The link will be detached on `Drop` and the caller is now responsible /// The link will be detached on `Drop` and the caller is now responsible
/// for managing its lifetime. /// for managing its lifetime.
pub fn take_link( pub fn take_link(&mut self, link_id: KProbeLinkId) -> Result<KProbeLink, ProgramError> {
&mut self, self.data.take_link(link_id)
link_id: KProbeLinkId,
) -> Result<OwnedLink<KProbeLink>, ProgramError> {
Ok(OwnedLink::new(self.data.take_link(link_id)?))
} }
} }

@ -1,13 +1,13 @@
//! Program links. //! Program links.
use libc::{close, dup}; use libc::{close, dup};
use thiserror::Error;
use std::{ use std::{
borrow::Borrow,
collections::{hash_map::Entry, HashMap}, collections::{hash_map::Entry, HashMap},
ffi::CString, ffi::CString,
ops::Deref, io,
os::unix::prelude::RawFd, os::unix::prelude::RawFd,
path::Path, path::{Path, PathBuf},
}; };
use crate::{ use crate::{
@ -25,37 +25,10 @@ pub trait Link: std::fmt::Debug + 'static {
/// Returns the link id /// Returns the link id
fn id(&self) -> Self::Id; fn id(&self) -> Self::Id;
/// Detaches the Link /// Detaches the LinkOwnedLink is gone... but this doesn't work :(
fn detach(self) -> Result<(), ProgramError>; fn detach(self) -> Result<(), ProgramError>;
} }
/// An owned link that automatically detaches the inner link when dropped.
pub struct OwnedLink<T: Link> {
inner: Option<T>,
}
impl<T: Link> OwnedLink<T> {
pub(crate) fn new(inner: T) -> Self {
Self { inner: Some(inner) }
}
}
impl<T: Link> Deref for OwnedLink<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
self.inner.borrow().as_ref().unwrap()
}
}
impl<T: Link> Drop for OwnedLink<T> {
fn drop(&mut self) {
if let Some(link) = self.inner.take() {
link.detach().unwrap();
}
}
}
#[derive(Debug)] #[derive(Debug)]
pub(crate) struct LinkMap<T: Link> { pub(crate) struct LinkMap<T: Link> {
links: HashMap<T::Id, T>, links: HashMap<T::Id, T>,
@ -106,37 +79,63 @@ impl<T: Link> Drop for LinkMap<T> {
/// The identifier of an `FdLink`. /// The identifier of an `FdLink`.
#[derive(Debug, Hash, Eq, PartialEq)] #[derive(Debug, Hash, Eq, PartialEq)]
pub struct FdLinkId(pub(crate) RawFd); pub struct FdLinkId(pub(crate) Option<RawFd>);
/// A file descriptor link. /// A file descriptor link.
#[derive(Debug)] #[derive(Debug)]
pub struct FdLink { pub struct FdLink {
pub(crate) fd: RawFd, pub(crate) fd: Option<RawFd>,
} }
impl FdLink { impl FdLink {
pub(crate) fn new(fd: RawFd) -> FdLink { pub(crate) fn new(fd: RawFd) -> FdLink {
FdLink { fd } FdLink { fd: Some(fd) }
} }
/// Pins the FdLink to a BPF filesystem. /// Pins the link to a BPF file system.
/// ///
/// When a BPF object is pinned to a BPF filesystem it will remain attached after /// When a link is pinned it will remain attached even after the link instance is dropped,
/// Aya has detached the link. /// and will only be detached once the pinned file is removed. To unpin, see [PinnedFd::unpin].
/// 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. /// The parent directories in the provided path must already exist before calling this method,
pub fn pin<P: AsRef<Path>>(&self, path: P) -> Result<(), PinError> { /// and must be on a BPF file system (bpffs).
///
/// # Example
/// ```no_run
/// # use aya::programs::{links::FdLink, Extension};
/// # use std::convert::TryInto;
/// # #[derive(thiserror::Error, Debug)]
/// # enum Error {
/// # #[error(transparent)]
/// # Bpf(#[from] aya::BpfError),
/// # #[error(transparent)]
/// # Pin(#[from] aya::pin::PinError),
/// # #[error(transparent)]
/// # Program(#[from] aya::programs::ProgramError)
/// # }
/// # let mut bpf = aya::Bpf::load(&[])?;
/// # let prog: &mut Extension = bpf.program_mut("example").unwrap().try_into()?;
/// let link_id = prog.attach()?;
/// let owned_link = prog.take_link(link_id)?;
/// let fd_link: FdLink = owned_link.into();
/// let pinned_link = fd_link.pin("/sys/fs/bpf/example")?;
/// # Ok::<(), Error>(())
/// ```
pub fn pin<P: AsRef<Path>>(mut self, path: P) -> Result<PinnedLink, PinError> {
let fd = self.fd.take().ok_or_else(|| PinError::NoFd {
name: "link".to_string(),
})?;
let path_string = let path_string =
CString::new(path.as_ref().to_string_lossy().into_owned()).map_err(|e| { CString::new(path.as_ref().to_string_lossy().into_owned()).map_err(|e| {
PinError::InvalidPinPath { PinError::InvalidPinPath {
error: e.to_string(), error: e.to_string(),
} }
})?; })?;
bpf_pin_object(self.fd, &path_string).map_err(|(_, io_error)| PinError::SyscallError { bpf_pin_object(fd, &path_string).map_err(|(_, io_error)| PinError::SyscallError {
name: "BPF_OBJ_PIN".to_string(), name: "BPF_OBJ_PIN".to_string(),
io_error, io_error,
})?; })?;
Ok(()) Ok(PinnedLink::new(PathBuf::from(path.as_ref()), fd))
} }
} }
@ -148,11 +147,47 @@ impl Link for FdLink {
} }
fn detach(self) -> Result<(), ProgramError> { fn detach(self) -> Result<(), ProgramError> {
unsafe { close(self.fd) }; // detach is a noop since it consumes self. once self is consumed,
// drop will be triggered and the link will be detached.
Ok(()) Ok(())
} }
} }
impl Drop for FdLink {
fn drop(&mut self) {
if let Some(fd) = self.fd.take() {
// Safety: libc
unsafe { close(fd) };
}
}
}
/// A pinned file descriptor link.
///
/// This link has been pinned to the BPF filesystem. On drop, the file descriptor that backs
/// this link will be closed. Whether or not the program remains attached is dependent
/// on the presence of the file in BPFFS.
#[derive(Debug)]
pub struct PinnedLink {
inner: FdLink,
path: PathBuf,
}
impl PinnedLink {
fn new(path: PathBuf, fd: RawFd) -> Self {
PinnedLink {
inner: FdLink::new(fd),
path,
}
}
/// Removes the pinned link from the filesystem and returns an [`FdLink`].
pub fn unpin(self) -> Result<FdLink, io::Error> {
std::fs::remove_file(self.path)?;
Ok(self.inner)
}
}
/// The identifier of a `ProgAttachLink`. /// The identifier of a `ProgAttachLink`.
#[derive(Debug, Hash, Eq, PartialEq)] #[derive(Debug, Hash, Eq, PartialEq)]
pub struct ProgAttachLinkId(RawFd, RawFd, bpf_attach_type); pub struct ProgAttachLinkId(RawFd, RawFd, bpf_attach_type);
@ -220,18 +255,32 @@ macro_rules! define_link_wrapper {
$wrapper(b) $wrapper(b)
} }
} }
impl From<$wrapper> for $base {
fn from(w: $wrapper) -> $base {
w.into()
}
}
}; };
} }
pub(crate) use define_link_wrapper; pub(crate) use define_link_wrapper;
#[derive(Error, Debug)]
/// Errors from operations on links.
pub enum LinkError {
/// Invalid link.
#[error("Invalid link")]
InvalidLink,
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use std::{cell::RefCell, rc::Rc}; use std::{cell::RefCell, env, fs::File, mem, os::unix::io::AsRawFd, rc::Rc};
use crate::programs::{OwnedLink, ProgramError}; use crate::{programs::ProgramError, sys::override_syscall};
use super::{Link, LinkMap}; use super::{FdLink, Link, LinkMap};
#[derive(Debug, Hash, Eq, PartialEq)] #[derive(Debug, Hash, Eq, PartialEq)]
struct TestLinkId(u8, u8); struct TestLinkId(u8, u8);
@ -363,28 +412,23 @@ mod tests {
} }
#[test] #[test]
fn test_owned_drop() { #[cfg_attr(miri, ignore)]
let l1 = TestLink::new(1, 2); fn test_pin() {
let l1_detached = Rc::clone(&l1.detached); let dir = env::temp_dir();
let l2 = TestLink::new(1, 3); let f1 = File::create(dir.join("f1")).expect("unable to create file in tmpdir");
let l2_detached = Rc::clone(&l2.detached); let fd_link = FdLink::new(f1.as_raw_fd());
{ // leak the fd, it will get closed when our pinned link is dropped
let mut links = LinkMap::new(); mem::forget(f1);
let id1 = links.insert(l1).unwrap();
links.insert(l2).unwrap(); // override syscall to allow for pin to happen in our tmpdir
override_syscall(|_| Ok(0));
// manually forget one link and wrap in OwnedLink // create the file that would have happened as a side-effect of a real pin operation
let _ = OwnedLink { File::create(dir.join("f1-pin")).expect("unable to create file in tmpdir");
inner: Some(links.forget(id1).unwrap()), assert!(dir.join("f1-pin").exists());
};
let pinned_link = fd_link.pin(dir.join("f1-pin")).expect("pin failed");
// OwnedLink was dropped in the statement above pinned_link.unpin().expect("unpin failed");
assert!(*l1_detached.borrow() == 1); assert!(!dir.join("f1-pin").exists());
assert!(*l2_detached.borrow() == 0);
};
assert!(*l1_detached.borrow() == 1);
assert!(*l2_detached.borrow() == 1);
} }
} }

@ -3,7 +3,7 @@ use std::os::unix::prelude::{AsRawFd, RawFd};
use crate::{ use crate::{
generated::{bpf_attach_type::BPF_LIRC_MODE2, bpf_prog_type::BPF_PROG_TYPE_LIRC_MODE2}, generated::{bpf_attach_type::BPF_LIRC_MODE2, bpf_prog_type::BPF_PROG_TYPE_LIRC_MODE2},
programs::{load_program, query, Link, OwnedLink, ProgramData, ProgramError, ProgramInfo}, programs::{load_program, query, Link, ProgramData, ProgramError, ProgramInfo},
sys::{bpf_obj_get_info_by_fd, bpf_prog_attach, bpf_prog_detach, bpf_prog_get_fd_by_id}, sys::{bpf_obj_get_info_by_fd, bpf_prog_attach, bpf_prog_detach, bpf_prog_get_fd_by_id},
}; };
@ -85,8 +85,8 @@ impl LircMode2 {
/// ///
/// The link will be detached on `Drop` and the caller is now responsible /// The link will be detached on `Drop` and the caller is now responsible
/// for managing its lifetime. /// for managing its lifetime.
pub fn take_link(&mut self, link_id: LircLinkId) -> Result<OwnedLink<LircLink>, ProgramError> { pub fn take_link(&mut self, link_id: LircLinkId) -> Result<LircLink, ProgramError> {
Ok(OwnedLink::new(self.data.take_link(link_id)?)) self.data.take_link(link_id)
} }
/// Queries the lirc device for attached programs. /// Queries the lirc device for attached programs.

@ -4,7 +4,7 @@ use crate::{
obj::btf::{Btf, BtfKind}, obj::btf::{Btf, BtfKind},
programs::{ programs::{
define_link_wrapper, load_program, utils::attach_raw_tracepoint, FdLink, FdLinkId, define_link_wrapper, load_program, utils::attach_raw_tracepoint, FdLink, FdLinkId,
OwnedLink, ProgramData, ProgramError, ProgramData, ProgramError,
}, },
}; };
@ -84,8 +84,8 @@ impl Lsm {
/// ///
/// The link will be detached on `Drop` and the caller is now responsible /// The link will be detached on `Drop` and the caller is now responsible
/// for managing its lifetime. /// for managing its lifetime.
pub fn take_link(&mut self, link_id: LsmLinkId) -> Result<OwnedLink<LsmLink>, ProgramError> { pub fn take_link(&mut self, link_id: LsmLinkId) -> Result<LsmLink, ProgramError> {
Ok(OwnedLink::new(self.data.take_link(link_id)?)) self.data.take_link(link_id)
} }
} }

@ -81,8 +81,8 @@ pub use extension::{Extension, ExtensionError};
pub use fentry::FEntry; pub use fentry::FEntry;
pub use fexit::FExit; pub use fexit::FExit;
pub use kprobe::{KProbe, KProbeError}; pub use kprobe::{KProbe, KProbeError};
pub use links::Link;
use links::*; use links::*;
pub use links::{Link, OwnedLink};
pub use lirc_mode2::LircMode2; pub use lirc_mode2::LircMode2;
pub use lsm::Lsm; pub use lsm::Lsm;
use perf_attach::*; use perf_attach::*;

@ -14,7 +14,7 @@ use crate::{
programs::{ programs::{
load_program, perf_attach, load_program, perf_attach,
perf_attach::{PerfLink, PerfLinkId}, perf_attach::{PerfLink, PerfLinkId},
OwnedLink, ProgramData, ProgramError, ProgramData, ProgramError,
}, },
sys::perf_event_open, sys::perf_event_open,
}; };
@ -181,7 +181,7 @@ impl PerfEvent {
/// ///
/// The link will be detached on `Drop` and the caller is now responsible /// The link will be detached on `Drop` and the caller is now responsible
/// for managing its lifetime. /// for managing its lifetime.
pub fn take_link(&mut self, link_id: PerfLinkId) -> Result<OwnedLink<PerfLink>, ProgramError> { pub fn take_link(&mut self, link_id: PerfLinkId) -> Result<PerfLink, ProgramError> {
Ok(OwnedLink::new(self.data.take_link(link_id)?)) self.data.take_link(link_id)
} }
} }

@ -5,7 +5,7 @@ use crate::{
generated::bpf_prog_type::BPF_PROG_TYPE_RAW_TRACEPOINT, generated::bpf_prog_type::BPF_PROG_TYPE_RAW_TRACEPOINT,
programs::{ programs::{
define_link_wrapper, load_program, utils::attach_raw_tracepoint, FdLink, FdLinkId, define_link_wrapper, load_program, utils::attach_raw_tracepoint, FdLink, FdLinkId,
OwnedLink, ProgramData, ProgramError, ProgramData, ProgramError,
}, },
}; };
@ -66,8 +66,8 @@ impl RawTracePoint {
pub fn take_link( pub fn take_link(
&mut self, &mut self,
link_id: RawTracePointLinkId, link_id: RawTracePointLinkId,
) -> Result<OwnedLink<RawTracePointLink>, ProgramError> { ) -> Result<RawTracePointLink, ProgramError> {
Ok(OwnedLink::new(self.data.take_link(link_id)?)) self.data.take_link(link_id)
} }
} }

@ -2,7 +2,7 @@ use std::os::unix::prelude::{AsRawFd, RawFd};
use crate::{ use crate::{
generated::{bpf_attach_type::BPF_SK_LOOKUP, bpf_prog_type::BPF_PROG_TYPE_SK_LOOKUP}, generated::{bpf_attach_type::BPF_SK_LOOKUP, bpf_prog_type::BPF_PROG_TYPE_SK_LOOKUP},
programs::{define_link_wrapper, load_program, FdLinkId, OwnedLink, ProgramData, ProgramError}, programs::{define_link_wrapper, load_program, FdLinkId, ProgramData, ProgramError},
sys::bpf_link_create, sys::bpf_link_create,
}; };
@ -77,11 +77,8 @@ impl SkLookup {
/// ///
/// The link will be detached on `Drop` and the caller is now responsible /// The link will be detached on `Drop` and the caller is now responsible
/// for managing its lifetime. /// for managing its lifetime.
pub fn take_link( pub fn take_link(&mut self, link_id: SkLookupLinkId) -> Result<SkLookupLink, ProgramError> {
&mut self, self.data.take_link(link_id)
link_id: SkLookupLinkId,
) -> Result<OwnedLink<SkLookupLink>, ProgramError> {
Ok(OwnedLink::new(self.data.take_link(link_id)?))
} }
/// Detaches the program. /// Detaches the program.

@ -3,8 +3,8 @@ use crate::{
generated::{bpf_attach_type::BPF_SK_MSG_VERDICT, bpf_prog_type::BPF_PROG_TYPE_SK_MSG}, generated::{bpf_attach_type::BPF_SK_MSG_VERDICT, bpf_prog_type::BPF_PROG_TYPE_SK_MSG},
maps::sock::SocketMap, maps::sock::SocketMap,
programs::{ programs::{
define_link_wrapper, load_program, OwnedLink, ProgAttachLink, ProgAttachLinkId, define_link_wrapper, load_program, ProgAttachLink, ProgAttachLinkId, ProgramData,
ProgramData, ProgramError, ProgramError,
}, },
sys::bpf_prog_attach, sys::bpf_prog_attach,
}; };
@ -99,11 +99,8 @@ impl SkMsg {
/// ///
/// The link will be detached on `Drop` and the caller is now responsible /// The link will be detached on `Drop` and the caller is now responsible
/// for managing its lifetime. /// for managing its lifetime.
pub fn take_link( pub fn take_link(&mut self, link_id: SkMsgLinkId) -> Result<SkMsgLink, ProgramError> {
&mut self, self.data.take_link(link_id)
link_id: SkMsgLinkId,
) -> Result<OwnedLink<SkMsgLink>, ProgramError> {
Ok(OwnedLink::new(self.data.take_link(link_id)?))
} }
} }

@ -6,8 +6,8 @@ use crate::{
}, },
maps::sock::SocketMap, maps::sock::SocketMap,
programs::{ programs::{
define_link_wrapper, load_program, OwnedLink, ProgAttachLink, ProgAttachLinkId, define_link_wrapper, load_program, ProgAttachLink, ProgAttachLinkId, ProgramData,
ProgramData, ProgramError, ProgramError,
}, },
sys::bpf_prog_attach, sys::bpf_prog_attach,
}; };
@ -94,11 +94,8 @@ impl SkSkb {
/// ///
/// The link will be detached on `Drop` and the caller is now responsible /// The link will be detached on `Drop` and the caller is now responsible
/// for managing its lifetime. /// for managing its lifetime.
pub fn take_link( pub fn take_link(&mut self, link_id: SkSkbLinkId) -> Result<SkSkbLink, ProgramError> {
&mut self, self.data.take_link(link_id)
link_id: SkSkbLinkId,
) -> Result<OwnedLink<SkSkbLink>, ProgramError> {
Ok(OwnedLink::new(self.data.take_link(link_id)?))
} }
} }

@ -4,8 +4,8 @@ use std::os::unix::io::AsRawFd;
use crate::{ use crate::{
generated::{bpf_attach_type::BPF_CGROUP_SOCK_OPS, bpf_prog_type::BPF_PROG_TYPE_SOCK_OPS}, generated::{bpf_attach_type::BPF_CGROUP_SOCK_OPS, bpf_prog_type::BPF_PROG_TYPE_SOCK_OPS},
programs::{ programs::{
define_link_wrapper, load_program, OwnedLink, ProgAttachLink, ProgAttachLinkId, define_link_wrapper, load_program, ProgAttachLink, ProgAttachLinkId, ProgramData,
ProgramData, ProgramError, ProgramError,
}, },
sys::bpf_prog_attach, sys::bpf_prog_attach,
}; };
@ -86,11 +86,8 @@ impl SockOps {
/// ///
/// The link will be detached on `Drop` and the caller is now responsible /// The link will be detached on `Drop` and the caller is now responsible
/// for managing its lifetime. /// for managing its lifetime.
pub fn take_link( pub fn take_link(&mut self, link_id: SockOpsLinkId) -> Result<SockOpsLink, ProgramError> {
&mut self, self.data.take_link(link_id)
link_id: SockOpsLinkId,
) -> Result<OwnedLink<SockOpsLink>, ProgramError> {
Ok(OwnedLink::new(self.data.take_link(link_id)?))
} }
} }

@ -8,7 +8,7 @@ use thiserror::Error;
use crate::{ use crate::{
generated::{bpf_prog_type::BPF_PROG_TYPE_SOCKET_FILTER, SO_ATTACH_BPF, SO_DETACH_BPF}, generated::{bpf_prog_type::BPF_PROG_TYPE_SOCKET_FILTER, SO_ATTACH_BPF, SO_DETACH_BPF},
programs::{load_program, Link, OwnedLink, ProgramData, ProgramError}, programs::{load_program, Link, ProgramData, ProgramError},
}; };
/// The type returned when attaching a [`SocketFilter`] fails. /// The type returned when attaching a [`SocketFilter`] fails.
@ -109,8 +109,8 @@ impl SocketFilter {
pub fn take_link( pub fn take_link(
&mut self, &mut self,
link_id: SocketFilterLinkId, link_id: SocketFilterLinkId,
) -> Result<OwnedLink<SocketFilterLink>, ProgramError> { ) -> Result<SocketFilterLink, ProgramError> {
Ok(OwnedLink::new(self.data.take_link(link_id)?)) self.data.take_link(link_id)
} }
} }

@ -10,7 +10,7 @@ use crate::{
generated::{ generated::{
bpf_prog_type::BPF_PROG_TYPE_SCHED_CLS, TC_H_CLSACT, TC_H_MIN_EGRESS, TC_H_MIN_INGRESS, bpf_prog_type::BPF_PROG_TYPE_SCHED_CLS, TC_H_CLSACT, TC_H_MIN_EGRESS, TC_H_MIN_INGRESS,
}, },
programs::{define_link_wrapper, load_program, Link, OwnedLink, ProgramData, ProgramError}, programs::{define_link_wrapper, load_program, Link, ProgramData, ProgramError},
sys::{ sys::{
netlink_find_filter_with_name, netlink_qdisc_add_clsact, netlink_qdisc_attach, netlink_find_filter_with_name, netlink_qdisc_add_clsact, netlink_qdisc_attach,
netlink_qdisc_detach, netlink_qdisc_detach,
@ -154,8 +154,8 @@ impl SchedClassifier {
pub fn take_link( pub fn take_link(
&mut self, &mut self,
link_id: SchedClassifierLinkId, link_id: SchedClassifierLinkId,
) -> Result<OwnedLink<SchedClassifierLink>, ProgramError> { ) -> Result<SchedClassifierLink, ProgramError> {
Ok(OwnedLink::new(self.data.take_link(link_id)?)) self.data.take_link(link_id)
} }
} }

@ -4,7 +4,7 @@ use crate::{
obj::btf::{Btf, BtfKind}, obj::btf::{Btf, BtfKind},
programs::{ programs::{
define_link_wrapper, load_program, utils::attach_raw_tracepoint, FdLink, FdLinkId, define_link_wrapper, load_program, utils::attach_raw_tracepoint, FdLink, FdLinkId,
OwnedLink, ProgramData, ProgramError, ProgramData, ProgramError,
}, },
}; };
@ -85,8 +85,8 @@ impl BtfTracePoint {
pub fn take_link( pub fn take_link(
&mut self, &mut self,
link_id: BtfTracePointLinkId, link_id: BtfTracePointLinkId,
) -> Result<OwnedLink<BtfTracePointLink>, ProgramError> { ) -> Result<BtfTracePointLink, ProgramError> {
Ok(OwnedLink::new(self.data.take_link(link_id)?)) self.data.take_link(link_id)
} }
} }

@ -7,7 +7,7 @@ use crate::{
programs::{ programs::{
define_link_wrapper, load_program, define_link_wrapper, load_program,
perf_attach::{perf_attach, PerfLink, PerfLinkId}, perf_attach::{perf_attach, PerfLink, PerfLinkId},
OwnedLink, ProgramData, ProgramError, ProgramData, ProgramError,
}, },
sys::perf_event_open_trace_point, sys::perf_event_open_trace_point,
}; };
@ -99,11 +99,8 @@ impl TracePoint {
/// ///
/// The link will be detached on `Drop` and the caller is now responsible /// The link will be detached on `Drop` and the caller is now responsible
/// for managing its lifetime. /// for managing its lifetime.
pub fn take_link( pub fn take_link(&mut self, link_id: TracePointLinkId) -> Result<TracePointLink, ProgramError> {
&mut self, self.data.take_link(link_id)
link_id: TracePointLinkId,
) -> Result<OwnedLink<TracePointLink>, ProgramError> {
Ok(OwnedLink::new(self.data.take_link(link_id)?))
} }
} }

@ -19,7 +19,7 @@ use crate::{
define_link_wrapper, load_program, define_link_wrapper, load_program,
perf_attach::{PerfLink, PerfLinkId}, perf_attach::{PerfLink, PerfLinkId},
probe::{attach, ProbeKind}, probe::{attach, ProbeKind},
OwnedLink, ProgramData, ProgramError, ProgramData, ProgramError,
}, },
}; };
@ -133,11 +133,8 @@ impl UProbe {
/// ///
/// The link will be detached on `Drop` and the caller is now responsible /// The link will be detached on `Drop` and the caller is now responsible
/// for managing its lifetime. /// for managing its lifetime.
pub fn take_link( pub fn take_link(&mut self, link_id: UProbeLinkId) -> Result<UProbeLink, ProgramError> {
&mut self, self.data.take_link(link_id)
link_id: UProbeLinkId,
) -> Result<OwnedLink<UProbeLink>, ProgramError> {
Ok(OwnedLink::new(self.data.take_link(link_id)?))
} }
} }

@ -1,7 +1,7 @@
//! eXpress Data Path (XDP) programs. //! eXpress Data Path (XDP) programs.
use bitflags; use bitflags;
use libc::if_nametoindex; use libc::if_nametoindex;
use std::{ffi::CString, hash::Hash, io, mem, os::unix::io::RawFd}; use std::{convert::TryFrom, ffi::CString, hash::Hash, io, mem, os::unix::io::RawFd};
use thiserror::Error; use thiserror::Error;
use crate::{ use crate::{
@ -12,7 +12,7 @@ use crate::{
XDP_FLAGS_UPDATE_IF_NOEXIST, XDP_FLAGS_UPDATE_IF_NOEXIST,
}, },
programs::{ programs::{
define_link_wrapper, load_program, FdLink, Link, OwnedLink, ProgramData, ProgramError, define_link_wrapper, load_program, FdLink, Link, LinkError, ProgramData, ProgramError,
}, },
sys::{bpf_link_create, bpf_link_update, kernel_version, netlink_set_xdp_fd}, sys::{bpf_link_create, bpf_link_update, kernel_version, netlink_set_xdp_fd},
}; };
@ -137,18 +137,18 @@ impl Xdp {
/// ///
/// The link will be detached on `Drop` and the caller is now responsible /// The link will be detached on `Drop` and the caller is now responsible
/// for managing its lifetime. /// for managing its lifetime.
pub fn take_link(&mut self, link_id: XdpLinkId) -> Result<OwnedLink<XdpLink>, ProgramError> { pub fn take_link(&mut self, link_id: XdpLinkId) -> Result<XdpLink, ProgramError> {
Ok(OwnedLink::new(self.data.take_link(link_id)?)) self.data.take_link(link_id)
} }
/// Atomically replaces the program referenced by the provided link. /// Atomically replaces the program referenced by the provided link.
/// ///
/// Ownership of the link will transfer to this program. /// Ownership of the link will transfer to this program.
pub fn attach_to_link(&mut self, link: OwnedLink<XdpLink>) -> Result<XdpLinkId, ProgramError> { pub fn attach_to_link(&mut self, link: XdpLink) -> Result<XdpLinkId, ProgramError> {
let prog_fd = self.data.fd_or_err()?; let prog_fd = self.data.fd_or_err()?;
match &link.0 { match &link.0 {
XdpLinkInner::FdLink(fd_link) => { XdpLinkInner::FdLink(fd_link) => {
let link_fd = fd_link.fd; let link_fd = fd_link.fd.unwrap();
bpf_link_update(link_fd, prog_fd, None, 0).map_err(|(_, io_error)| { bpf_link_update(link_fd, prog_fd, None, 0).map_err(|(_, io_error)| {
ProgramError::SyscallError { ProgramError::SyscallError {
call: "bpf_link_update".to_string(), call: "bpf_link_update".to_string(),
@ -238,6 +238,18 @@ impl Link for XdpLinkInner {
} }
} }
impl TryFrom<XdpLink> for FdLink {
type Error = LinkError;
fn try_from(value: XdpLink) -> Result<Self, Self::Error> {
if let XdpLinkInner::FdLink(fd) = value.0 {
Ok(fd)
} else {
Err(LinkError::InvalidLink)
}
}
}
define_link_wrapper!( define_link_wrapper!(
/// The link used by [Xdp] programs. /// The link used by [Xdp] programs.
XdpLink, XdpLink,

@ -3,7 +3,7 @@ use std::{process::Command, thread, time};
use aya::{ use aya::{
include_bytes_aligned, include_bytes_aligned,
maps::{Array, MapRefMut}, maps::{Array, MapRefMut},
programs::{TracePoint, Xdp, XdpFlags}, programs::{links::FdLink, TracePoint, Xdp, XdpFlags},
Bpf, Bpf,
}; };
@ -99,3 +99,33 @@ fn unload() -> anyhow::Result<()> {
assert_loaded(false); assert_loaded(false);
Ok(()) Ok(())
} }
#[integration_test]
fn pin_link() -> anyhow::Result<()> {
let bytes = include_bytes_aligned!("../../../../target/bpfel-unknown-none/debug/test");
let mut bpf = Bpf::load(bytes)?;
let prog: &mut Xdp = bpf.program_mut("test_unload").unwrap().try_into().unwrap();
prog.load().unwrap();
let link_id = prog.attach("lo", XdpFlags::default()).unwrap();
let link = prog.take_link(link_id)?;
assert_loaded(true);
let fd_link: FdLink = link.try_into()?;
let pinned = fd_link.pin("/sys/fs/bpf/aya-xdp-test-lo")?;
// because of the pin, the program is still attached
prog.unload()?;
assert_loaded(true);
// delete the pin, but the program is still attached
let new_link = pinned.unpin()?;
println!("third assert");
assert_loaded(true);
// finally when new_link is dropped we're detached
drop(new_link);
println!("final assert");
assert_loaded(false);
Ok(())
}

Loading…
Cancel
Save