aya: Fix Link Pinning

1. Removes OwnedLink
2. Allows Links to be converted into FdLink
3. Introduces a PinnedLink type to handle wrap FdLink when pinned and
   support un-pinning

Signed-off-by: Dave Tucker <dave@dtucker.co.uk>
pull/366/head
Dave Tucker 2 years ago
parent 207c689f56
commit 4c1d645aa6

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

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

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

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

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

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

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

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

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

@ -1,13 +1,13 @@
//! Program links.
use libc::{close, dup};
use thiserror::Error;
use std::{
borrow::Borrow,
collections::{hash_map::Entry, HashMap},
ffi::CString,
ops::Deref,
io,
os::unix::prelude::RawFd,
path::Path,
path::{Path, PathBuf},
};
use crate::{
@ -25,37 +25,10 @@ pub trait Link: std::fmt::Debug + 'static {
/// Returns the link id
fn id(&self) -> Self::Id;
/// Detaches the Link
/// Detaches the LinkOwnedLink is gone... but this doesn't work :(
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)]
pub(crate) struct LinkMap<T: Link> {
links: HashMap<T::Id, T>,
@ -106,37 +79,63 @@ impl<T: Link> Drop for LinkMap<T> {
/// The identifier of an `FdLink`.
#[derive(Debug, Hash, Eq, PartialEq)]
pub struct FdLinkId(pub(crate) RawFd);
pub struct FdLinkId(pub(crate) Option<RawFd>);
/// A file descriptor link.
#[derive(Debug)]
pub struct FdLink {
pub(crate) fd: RawFd,
pub(crate) fd: Option<RawFd>,
}
impl 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
/// 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> {
/// When a link is pinned it will remain attached even after the link instance is dropped,
/// and will only be detached once the pinned file is removed. To unpin, see [PinnedFd::unpin].
///
/// The parent directories in the provided path must already exist before calling this method,
/// 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 =
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 {
bpf_pin_object(fd, &path_string).map_err(|(_, io_error)| PinError::SyscallError {
name: "BPF_OBJ_PIN".to_string(),
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> {
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(())
}
}
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`.
#[derive(Debug, Hash, Eq, PartialEq)]
pub struct ProgAttachLinkId(RawFd, RawFd, bpf_attach_type);
@ -220,18 +255,32 @@ macro_rules! define_link_wrapper {
$wrapper(b)
}
}
impl From<$wrapper> for $base {
fn from(w: $wrapper) -> $base {
w.into()
}
}
};
}
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)]
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)]
struct TestLinkId(u8, u8);
@ -363,28 +412,23 @@ mod tests {
}
#[test]
fn test_owned_drop() {
let l1 = TestLink::new(1, 2);
let l1_detached = Rc::clone(&l1.detached);
let l2 = TestLink::new(1, 3);
let l2_detached = Rc::clone(&l2.detached);
{
let mut links = LinkMap::new();
let id1 = links.insert(l1).unwrap();
links.insert(l2).unwrap();
// manually forget one link and wrap in OwnedLink
let _ = OwnedLink {
inner: Some(links.forget(id1).unwrap()),
};
// OwnedLink was dropped in the statement above
assert!(*l1_detached.borrow() == 1);
assert!(*l2_detached.borrow() == 0);
};
assert!(*l1_detached.borrow() == 1);
assert!(*l2_detached.borrow() == 1);
#[cfg_attr(miri, ignore)]
fn test_pin() {
let dir = env::temp_dir();
let f1 = File::create(dir.join("f1")).expect("unable to create file in tmpdir");
let fd_link = FdLink::new(f1.as_raw_fd());
// leak the fd, it will get closed when our pinned link is dropped
mem::forget(f1);
// override syscall to allow for pin to happen in our tmpdir
override_syscall(|_| Ok(0));
// create the file that would have happened as a side-effect of a real pin operation
File::create(dir.join("f1-pin")).expect("unable to create file in tmpdir");
assert!(dir.join("f1-pin").exists());
let pinned_link = fd_link.pin(dir.join("f1-pin")).expect("pin failed");
pinned_link.unpin().expect("unpin failed");
assert!(!dir.join("f1-pin").exists());
}
}

@ -3,7 +3,7 @@ use std::os::unix::prelude::{AsRawFd, RawFd};
use crate::{
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},
};
@ -86,8 +86,8 @@ impl LircMode2 {
///
/// The link will be detached on `Drop` and the caller is now responsible
/// for managing its lifetime.
pub fn take_link(&mut self, link_id: LircLinkId) -> Result<OwnedLink<LircLink>, ProgramError> {
Ok(OwnedLink::new(self.data.take_link(link_id)?))
pub fn take_link(&mut self, link_id: LircLinkId) -> Result<LircLink, ProgramError> {
self.data.take_link(link_id)
}
/// Queries the lirc device for attached programs.

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

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

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

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

@ -2,7 +2,7 @@ use std::os::unix::prelude::{AsRawFd, RawFd};
use crate::{
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,
};
@ -78,11 +78,8 @@ impl SkLookup {
///
/// The link will be detached on `Drop` and the caller is now responsible
/// for managing its lifetime.
pub fn take_link(
&mut self,
link_id: SkLookupLinkId,
) -> Result<OwnedLink<SkLookupLink>, ProgramError> {
Ok(OwnedLink::new(self.data.take_link(link_id)?))
pub fn take_link(&mut self, link_id: SkLookupLinkId) -> Result<SkLookupLink, ProgramError> {
self.data.take_link(link_id)
}
/// 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},
maps::sock::SocketMap,
programs::{
define_link_wrapper, load_program, OwnedLink, ProgAttachLink, ProgAttachLinkId,
ProgramData, ProgramError,
define_link_wrapper, load_program, ProgAttachLink, ProgAttachLinkId, ProgramData,
ProgramError,
},
sys::bpf_prog_attach,
};
@ -100,11 +100,8 @@ impl SkMsg {
///
/// The link will be detached on `Drop` and the caller is now responsible
/// for managing its lifetime.
pub fn take_link(
&mut self,
link_id: SkMsgLinkId,
) -> Result<OwnedLink<SkMsgLink>, ProgramError> {
Ok(OwnedLink::new(self.data.take_link(link_id)?))
pub fn take_link(&mut self, link_id: SkMsgLinkId) -> Result<SkMsgLink, ProgramError> {
self.data.take_link(link_id)
}
}

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

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

@ -8,7 +8,7 @@ use thiserror::Error;
use crate::{
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.
@ -110,8 +110,8 @@ impl SocketFilter {
pub fn take_link(
&mut self,
link_id: SocketFilterLinkId,
) -> Result<OwnedLink<SocketFilterLink>, ProgramError> {
Ok(OwnedLink::new(self.data.take_link(link_id)?))
) -> Result<SocketFilterLink, ProgramError> {
self.data.take_link(link_id)
}
}

@ -10,7 +10,7 @@ use crate::{
generated::{
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::{
netlink_find_filter_with_name, netlink_qdisc_add_clsact, netlink_qdisc_attach,
netlink_qdisc_detach,
@ -155,8 +155,8 @@ impl SchedClassifier {
pub fn take_link(
&mut self,
link_id: SchedClassifierLinkId,
) -> Result<OwnedLink<SchedClassifierLink>, ProgramError> {
Ok(OwnedLink::new(self.data.take_link(link_id)?))
) -> Result<SchedClassifierLink, ProgramError> {
self.data.take_link(link_id)
}
}

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

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

@ -19,7 +19,7 @@ use crate::{
define_link_wrapper, load_program,
perf_attach::{PerfLink, PerfLinkId},
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
/// for managing its lifetime.
pub fn take_link(
&mut self,
link_id: UProbeLinkId,
) -> Result<OwnedLink<UProbeLink>, ProgramError> {
Ok(OwnedLink::new(self.data.take_link(link_id)?))
pub fn take_link(&mut self, link_id: UProbeLinkId) -> Result<UProbeLink, ProgramError> {
self.data.take_link(link_id)
}
}

@ -1,7 +1,7 @@
//! eXpress Data Path (XDP) programs.
use bitflags;
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 crate::{
@ -12,7 +12,7 @@ use crate::{
XDP_FLAGS_UPDATE_IF_NOEXIST,
},
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},
};
@ -138,18 +138,18 @@ impl Xdp {
///
/// The link will be detached on `Drop` and the caller is now responsible
/// for managing its lifetime.
pub fn take_link(&mut self, link_id: XdpLinkId) -> Result<OwnedLink<XdpLink>, ProgramError> {
Ok(OwnedLink::new(self.data.take_link(link_id)?))
pub fn take_link(&mut self, link_id: XdpLinkId) -> Result<XdpLink, ProgramError> {
self.data.take_link(link_id)
}
/// Atomically replaces the program referenced by the provided link.
///
/// 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()?;
match &link.0 {
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)| {
ProgramError::SyscallError {
call: "bpf_link_update".to_string(),
@ -239,6 +239,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!(
/// The link used by [Xdp] programs.
XdpLink,

@ -7,7 +7,7 @@ use std::{
use aya::{
include_bytes_aligned,
maps::{Array, MapRefMut},
programs::{TracePoint, Xdp, XdpFlags},
programs::{links::FdLink, TracePoint, Xdp, XdpFlags},
Bpf,
};
@ -103,3 +103,33 @@ fn unload() -> anyhow::Result<()> {
assert_loaded(false);
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