diff --git a/aya/src/programs/cgroup_skb.rs b/aya/src/programs/cgroup_skb.rs index e068df2b..17d69063 100644 --- a/aya/src/programs/cgroup_skb.rs +++ b/aya/src/programs/cgroup_skb.rs @@ -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}, }; @@ -127,11 +126,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, ProgramError> { - Ok(OwnedLink::new(self.data.take_link(link_id)?)) + pub fn take_link(&mut self, link_id: CgroupSkbLinkId) -> Result { + self.data.take_link(link_id) } /// Detaches the program. diff --git a/aya/src/programs/cgroup_sock.rs b/aya/src/programs/cgroup_sock.rs index 5da64b97..17bc68ee 100644 --- a/aya/src/programs/cgroup_sock.rs +++ b/aya/src/programs/cgroup_sock.rs @@ -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}, }; @@ -105,11 +104,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, ProgramError> { - Ok(OwnedLink::new(self.data.take_link(link_id)?)) + pub fn take_link(&mut self, link_id: CgroupSockLinkId) -> Result { + self.data.take_link(link_id) } /// Detaches the program. diff --git a/aya/src/programs/cgroup_sock_addr.rs b/aya/src/programs/cgroup_sock_addr.rs index 332872fe..aa8b71fd 100644 --- a/aya/src/programs/cgroup_sock_addr.rs +++ b/aya/src/programs/cgroup_sock_addr.rs @@ -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}, }; @@ -109,8 +108,8 @@ impl CgroupSockAddr { pub fn take_link( &mut self, link_id: CgroupSockAddrLinkId, - ) -> Result, ProgramError> { - Ok(OwnedLink::new(self.data.take_link(link_id)?)) + ) -> Result { + self.data.take_link(link_id) } /// Detaches the program. diff --git a/aya/src/programs/cgroup_sockopt.rs b/aya/src/programs/cgroup_sockopt.rs index 5c1d2101..14df5fc6 100644 --- a/aya/src/programs/cgroup_sockopt.rs +++ b/aya/src/programs/cgroup_sockopt.rs @@ -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}, }; @@ -105,8 +105,8 @@ impl CgroupSockopt { pub fn take_link( &mut self, link_id: CgroupSockoptLinkId, - ) -> Result, ProgramError> { - Ok(OwnedLink::new(self.data.take_link(link_id)?)) + ) -> Result { + self.data.take_link(link_id) } /// Detaches the program. diff --git a/aya/src/programs/cgroup_sysctl.rs b/aya/src/programs/cgroup_sysctl.rs index 3caf58f3..f4a3f352 100644 --- a/aya/src/programs/cgroup_sysctl.rs +++ b/aya/src/programs/cgroup_sysctl.rs @@ -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}, }; @@ -101,8 +100,8 @@ impl CgroupSysctl { pub fn take_link( &mut self, link_id: CgroupSysctlLinkId, - ) -> Result, ProgramError> { - Ok(OwnedLink::new(self.data.take_link(link_id)?)) + ) -> Result { + self.data.take_link(link_id) } /// Detaches the program. diff --git a/aya/src/programs/extension.rs b/aya/src/programs/extension.rs index a3477eb9..1f9d4aaf 100644 --- a/aya/src/programs/extension.rs +++ b/aya/src/programs/extension.rs @@ -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, @@ -139,11 +138,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, ProgramError> { - Ok(OwnedLink::new(self.data.take_link(link_id)?)) + pub fn take_link(&mut self, link_id: ExtensionLinkId) -> Result { + self.data.take_link(link_id) } } diff --git a/aya/src/programs/fentry.rs b/aya/src/programs/fentry.rs index 7344e3c0..8f59061a 100644 --- a/aya/src/programs/fentry.rs +++ b/aya/src/programs/fentry.rs @@ -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, }, }; @@ -79,11 +79,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, ProgramError> { - Ok(OwnedLink::new(self.data.take_link(link_id)?)) + pub fn take_link(&mut self, link_id: FEntryLinkId) -> Result { + self.data.take_link(link_id) } } diff --git a/aya/src/programs/fexit.rs b/aya/src/programs/fexit.rs index 5cc165ac..ba2e1f1b 100644 --- a/aya/src/programs/fexit.rs +++ b/aya/src/programs/fexit.rs @@ -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, }, }; @@ -79,11 +79,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, ProgramError> { - Ok(OwnedLink::new(self.data.take_link(link_id)?)) + pub fn take_link(&mut self, link_id: FExitLinkId) -> Result { + self.data.take_link(link_id) } } diff --git a/aya/src/programs/kprobe.rs b/aya/src/programs/kprobe.rs index ebcc0af7..81bb783f 100644 --- a/aya/src/programs/kprobe.rs +++ b/aya/src/programs/kprobe.rs @@ -8,7 +8,7 @@ use crate::{ define_link_wrapper, load_program, perf_attach::{PerfLink, PerfLinkId}, 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 /// for managing its lifetime. - pub fn take_link( - &mut self, - link_id: KProbeLinkId, - ) -> Result, ProgramError> { - Ok(OwnedLink::new(self.data.take_link(link_id)?)) + pub fn take_link(&mut self, link_id: KProbeLinkId) -> Result { + self.data.take_link(link_id) } } diff --git a/aya/src/programs/links.rs b/aya/src/programs/links.rs index c16edefc..1f7a68f0 100644 --- a/aya/src/programs/links.rs +++ b/aya/src/programs/links.rs @@ -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 { - inner: Option, -} - -impl OwnedLink { - pub(crate) fn new(inner: T) -> Self { - Self { inner: Some(inner) } - } -} - -impl Deref for OwnedLink { - type Target = T; - - fn deref(&self) -> &Self::Target { - self.inner.borrow().as_ref().unwrap() - } -} - -impl Drop for OwnedLink { - fn drop(&mut self) { - if let Some(link) = self.inner.take() { - link.detach().unwrap(); - } - } -} - #[derive(Debug)] pub(crate) struct LinkMap { links: HashMap, @@ -106,37 +79,63 @@ impl Drop for LinkMap { /// The identifier of an `FdLink`. #[derive(Debug, Hash, Eq, PartialEq)] -pub struct FdLinkId(pub(crate) RawFd); +pub struct FdLinkId(pub(crate) Option); /// A file descriptor link. #[derive(Debug)] pub struct FdLink { - pub(crate) fd: RawFd, + pub(crate) fd: Option, } 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>(&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>(mut self, path: P) -> Result { + 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 { + 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()); } } diff --git a/aya/src/programs/lirc_mode2.rs b/aya/src/programs/lirc_mode2.rs index b7320cc2..d3ff2087 100644 --- a/aya/src/programs/lirc_mode2.rs +++ b/aya/src/programs/lirc_mode2.rs @@ -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}, }; @@ -85,8 +85,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, ProgramError> { - Ok(OwnedLink::new(self.data.take_link(link_id)?)) + pub fn take_link(&mut self, link_id: LircLinkId) -> Result { + self.data.take_link(link_id) } /// Queries the lirc device for attached programs. diff --git a/aya/src/programs/lsm.rs b/aya/src/programs/lsm.rs index cdc9afa2..92122b55 100644 --- a/aya/src/programs/lsm.rs +++ b/aya/src/programs/lsm.rs @@ -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, }, }; @@ -84,8 +84,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, ProgramError> { - Ok(OwnedLink::new(self.data.take_link(link_id)?)) + pub fn take_link(&mut self, link_id: LsmLinkId) -> Result { + self.data.take_link(link_id) } } diff --git a/aya/src/programs/mod.rs b/aya/src/programs/mod.rs index bf139a44..dc72f15f 100644 --- a/aya/src/programs/mod.rs +++ b/aya/src/programs/mod.rs @@ -81,8 +81,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::*; diff --git a/aya/src/programs/perf_event.rs b/aya/src/programs/perf_event.rs index c9cffcb0..0b8e7ae7 100644 --- a/aya/src/programs/perf_event.rs +++ b/aya/src/programs/perf_event.rs @@ -14,7 +14,7 @@ use crate::{ programs::{ load_program, perf_attach, perf_attach::{PerfLink, PerfLinkId}, - OwnedLink, ProgramData, ProgramError, + ProgramData, ProgramError, }, sys::perf_event_open, }; @@ -181,7 +181,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, ProgramError> { - Ok(OwnedLink::new(self.data.take_link(link_id)?)) + pub fn take_link(&mut self, link_id: PerfLinkId) -> Result { + self.data.take_link(link_id) } } diff --git a/aya/src/programs/raw_trace_point.rs b/aya/src/programs/raw_trace_point.rs index 7150fd4a..af451e59 100644 --- a/aya/src/programs/raw_trace_point.rs +++ b/aya/src/programs/raw_trace_point.rs @@ -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, }, }; @@ -66,8 +66,8 @@ impl RawTracePoint { pub fn take_link( &mut self, link_id: RawTracePointLinkId, - ) -> Result, ProgramError> { - Ok(OwnedLink::new(self.data.take_link(link_id)?)) + ) -> Result { + self.data.take_link(link_id) } } diff --git a/aya/src/programs/sk_lookup.rs b/aya/src/programs/sk_lookup.rs index fdda9557..a64e062a 100644 --- a/aya/src/programs/sk_lookup.rs +++ b/aya/src/programs/sk_lookup.rs @@ -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, }; @@ -77,11 +77,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, ProgramError> { - Ok(OwnedLink::new(self.data.take_link(link_id)?)) + pub fn take_link(&mut self, link_id: SkLookupLinkId) -> Result { + self.data.take_link(link_id) } /// Detaches the program. diff --git a/aya/src/programs/sk_msg.rs b/aya/src/programs/sk_msg.rs index 619e3420..e801f9ff 100644 --- a/aya/src/programs/sk_msg.rs +++ b/aya/src/programs/sk_msg.rs @@ -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, }; @@ -99,11 +99,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, ProgramError> { - Ok(OwnedLink::new(self.data.take_link(link_id)?)) + pub fn take_link(&mut self, link_id: SkMsgLinkId) -> Result { + self.data.take_link(link_id) } } diff --git a/aya/src/programs/sk_skb.rs b/aya/src/programs/sk_skb.rs index 02fbf77f..f8766e4b 100644 --- a/aya/src/programs/sk_skb.rs +++ b/aya/src/programs/sk_skb.rs @@ -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, }; @@ -94,11 +94,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, ProgramError> { - Ok(OwnedLink::new(self.data.take_link(link_id)?)) + pub fn take_link(&mut self, link_id: SkSkbLinkId) -> Result { + self.data.take_link(link_id) } } diff --git a/aya/src/programs/sock_ops.rs b/aya/src/programs/sock_ops.rs index dd600383..c46540e4 100644 --- a/aya/src/programs/sock_ops.rs +++ b/aya/src/programs/sock_ops.rs @@ -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, }; @@ -86,11 +86,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, ProgramError> { - Ok(OwnedLink::new(self.data.take_link(link_id)?)) + pub fn take_link(&mut self, link_id: SockOpsLinkId) -> Result { + self.data.take_link(link_id) } } diff --git a/aya/src/programs/socket_filter.rs b/aya/src/programs/socket_filter.rs index 3eb1febf..8534574d 100644 --- a/aya/src/programs/socket_filter.rs +++ b/aya/src/programs/socket_filter.rs @@ -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. @@ -109,8 +109,8 @@ impl SocketFilter { pub fn take_link( &mut self, link_id: SocketFilterLinkId, - ) -> Result, ProgramError> { - Ok(OwnedLink::new(self.data.take_link(link_id)?)) + ) -> Result { + self.data.take_link(link_id) } } diff --git a/aya/src/programs/tc.rs b/aya/src/programs/tc.rs index f95ae01c..00a82f06 100644 --- a/aya/src/programs/tc.rs +++ b/aya/src/programs/tc.rs @@ -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, @@ -154,8 +154,8 @@ impl SchedClassifier { pub fn take_link( &mut self, link_id: SchedClassifierLinkId, - ) -> Result, ProgramError> { - Ok(OwnedLink::new(self.data.take_link(link_id)?)) + ) -> Result { + self.data.take_link(link_id) } } diff --git a/aya/src/programs/tp_btf.rs b/aya/src/programs/tp_btf.rs index eaad3617..f206e72b 100644 --- a/aya/src/programs/tp_btf.rs +++ b/aya/src/programs/tp_btf.rs @@ -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 BtfTracePoint { pub fn take_link( &mut self, link_id: BtfTracePointLinkId, - ) -> Result, ProgramError> { - Ok(OwnedLink::new(self.data.take_link(link_id)?)) + ) -> Result { + self.data.take_link(link_id) } } diff --git a/aya/src/programs/trace_point.rs b/aya/src/programs/trace_point.rs index 79b9cd9f..f75e00f7 100644 --- a/aya/src/programs/trace_point.rs +++ b/aya/src/programs/trace_point.rs @@ -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, }; @@ -99,11 +99,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, ProgramError> { - Ok(OwnedLink::new(self.data.take_link(link_id)?)) + pub fn take_link(&mut self, link_id: TracePointLinkId) -> Result { + self.data.take_link(link_id) } } diff --git a/aya/src/programs/uprobe.rs b/aya/src/programs/uprobe.rs index 91cd25a8..3d90e562 100644 --- a/aya/src/programs/uprobe.rs +++ b/aya/src/programs/uprobe.rs @@ -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, ProgramError> { - Ok(OwnedLink::new(self.data.take_link(link_id)?)) + pub fn take_link(&mut self, link_id: UProbeLinkId) -> Result { + self.data.take_link(link_id) } } diff --git a/aya/src/programs/xdp.rs b/aya/src/programs/xdp.rs index a1fe3b76..875a9f04 100644 --- a/aya/src/programs/xdp.rs +++ b/aya/src/programs/xdp.rs @@ -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}, }; @@ -137,18 +137,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, ProgramError> { - Ok(OwnedLink::new(self.data.take_link(link_id)?)) + pub fn take_link(&mut self, link_id: XdpLinkId) -> Result { + 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) -> Result { + pub fn attach_to_link(&mut self, link: XdpLink) -> Result { 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(), @@ -238,6 +238,18 @@ impl Link for XdpLinkInner { } } +impl TryFrom for FdLink { + type Error = LinkError; + + fn try_from(value: XdpLink) -> Result { + if let XdpLinkInner::FdLink(fd) = value.0 { + Ok(fd) + } else { + Err(LinkError::InvalidLink) + } + } +} + define_link_wrapper!( /// The link used by [Xdp] programs. XdpLink, diff --git a/test/integration-test/src/tests/load.rs b/test/integration-test/src/tests/load.rs index 4ae61780..8ee257be 100644 --- a/test/integration-test/src/tests/load.rs +++ b/test/integration-test/src/tests/load.rs @@ -3,7 +3,7 @@ use std::{process::Command, thread, time}; use aya::{ include_bytes_aligned, maps::{Array, MapRefMut}, - programs::{TracePoint, Xdp, XdpFlags}, + programs::{links::FdLink, TracePoint, Xdp, XdpFlags}, Bpf, }; @@ -99,3 +99,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(()) +}