diff --git a/aya/src/programs/cgroup_skb.rs b/aya/src/programs/cgroup_skb.rs index b7d31899..ab928a4d 100644 --- a/aya/src/programs/cgroup_skb.rs +++ b/aya/src/programs/cgroup_skb.rs @@ -9,7 +9,8 @@ use crate::{ bpf_prog_type::BPF_PROG_TYPE_CGROUP_SKB, }, programs::{ - define_link_wrapper, load_program, FdLink, Link, ProgAttachLink, ProgramData, ProgramError, + define_link_wrapper, load_program, FdLink, Link, OwnedLink, ProgAttachLink, ProgramData, + ProgramError, }, sys::{bpf_link_create, bpf_prog_attach, kernel_version}, }; @@ -116,6 +117,17 @@ impl CgroupSkb { } } + /// Takes ownership of the link referenced by the provided link_id. + /// + /// The link will be detached on `Drop` and the caller is now responsible + /// for managing its lifetime. + pub fn forget_link( + &mut self, + link_id: CgroupSkbLinkId, + ) -> Result, ProgramError> { + Ok(OwnedLink::new(self.data.forget_link(link_id)?)) + } + /// Detaches the program. /// /// See [CgroupSkb::attach]. @@ -155,6 +167,7 @@ impl Link for CgroupSkbLinkInner { } define_link_wrapper!( + /// The link used by [CgroupSkb] programs. CgroupSkbLink, /// The type returned by [CgroupSkb::attach]. Can be passed to [CgroupSkb::detach]. CgroupSkbLinkId, diff --git a/aya/src/programs/extension.rs b/aya/src/programs/extension.rs index a47ff9df..c16e612a 100644 --- a/aya/src/programs/extension.rs +++ b/aya/src/programs/extension.rs @@ -6,7 +6,9 @@ use object::Endianness; 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, ProgramData, ProgramError}, + programs::{ + define_link_wrapper, load_program, FdLink, FdLinkId, OwnedLink, ProgramData, ProgramError, + }, sys::{self, bpf_link_create}, Btf, }; @@ -146,9 +148,21 @@ impl Extension { pub fn detach(&mut self, link_id: ExtensionLinkId) -> Result<(), ProgramError> { self.data.links.remove(link_id) } + + /// Takes ownership of the link referenced by the provided link_id. + /// + /// The link will be detached on `Drop` and the caller is now responsible + /// for managing its lifetime. + pub fn forget_link( + &mut self, + link_id: ExtensionLinkId, + ) -> Result, ProgramError> { + Ok(OwnedLink::new(self.data.forget_link(link_id)?)) + } } define_link_wrapper!( + /// The link used by [Extension] programs. ExtensionLink, /// The type returned by [Extension::attach]. Can be passed to [Extension::detach]. ExtensionLinkId, diff --git a/aya/src/programs/fentry.rs b/aya/src/programs/fentry.rs index 8e6ade51..cc51e15a 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, - ProgramData, ProgramError, + OwnedLink, ProgramData, ProgramError, }, }; @@ -75,9 +75,21 @@ impl FEntry { pub fn detach(&mut self, link_id: FEntryLinkId) -> Result<(), ProgramError> { self.data.links.remove(link_id) } + + /// Takes ownership of the link referenced by the provided link_id. + /// + /// The link will be detached on `Drop` and the caller is now responsible + /// for managing its lifetime. + pub fn forget_link( + &mut self, + link_id: FEntryLinkId, + ) -> Result, ProgramError> { + Ok(OwnedLink::new(self.data.forget_link(link_id)?)) + } } define_link_wrapper!( + /// The link used by [FEntry] programs. FEntryLink, /// The type returned by [FEntry::attach]. Can be passed to [FEntry::detach]. FEntryLinkId, diff --git a/aya/src/programs/fexit.rs b/aya/src/programs/fexit.rs index a04e68aa..302276cf 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, - ProgramData, ProgramError, + OwnedLink, ProgramData, ProgramError, }, }; @@ -75,9 +75,21 @@ impl FExit { pub fn detach(&mut self, link_id: FExitLinkId) -> Result<(), ProgramError> { self.data.links.remove(link_id) } + + /// Takes ownership of the link referenced by the provided link_id. + /// + /// The link will be detached on `Drop` and the caller is now responsible + /// for managing its lifetime. + pub fn forget_link( + &mut self, + link_id: FExitLinkId, + ) -> Result, ProgramError> { + Ok(OwnedLink::new(self.data.forget_link(link_id)?)) + } } define_link_wrapper!( + /// The link used by [FExit] programs. FExitLink, /// The type returned by [FExit::attach]. Can be passed to [FExit::detach]. FExitLinkId, diff --git a/aya/src/programs/kprobe.rs b/aya/src/programs/kprobe.rs index c55752cc..a5bf0475 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}, - ProgramData, ProgramError, + OwnedLink, ProgramData, ProgramError, }, }; @@ -76,9 +76,21 @@ impl KProbe { pub fn detach(&mut self, link_id: KProbeLinkId) -> Result<(), ProgramError> { self.data.links.remove(link_id) } + + /// Takes ownership of the link referenced by the provided link_id. + /// + /// The link will be detached on `Drop` and the caller is now responsible + /// for managing its lifetime. + pub fn forget_link( + &mut self, + link_id: KProbeLinkId, + ) -> Result, ProgramError> { + Ok(OwnedLink::new(self.data.forget_link(link_id)?)) + } } define_link_wrapper!( + /// The link used by [KProbe] programs. KProbeLink, /// The type returned by [KProbe::attach]. Can be passed to [KProbe::detach]. KProbeLinkId, diff --git a/aya/src/programs/links.rs b/aya/src/programs/links.rs index 9a8567aa..9ee06e80 100644 --- a/aya/src/programs/links.rs +++ b/aya/src/programs/links.rs @@ -1,19 +1,53 @@ use libc::{close, dup}; + use std::{ + borrow::Borrow, collections::{hash_map::Entry, HashMap}, + ops::Deref, os::unix::prelude::RawFd, }; use crate::{generated::bpf_attach_type, programs::ProgramError, sys::bpf_prog_detach}; -pub(crate) trait Link: std::fmt::Debug + 'static { +/// A Link +pub trait Link: std::fmt::Debug + 'static { + /// Unique Id type Id: std::fmt::Debug + std::hash::Hash + Eq + PartialEq; + /// Returns the link id fn id(&self) -> Self::Id; + /// Detaches the Link 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, @@ -43,6 +77,10 @@ impl LinkMap { .ok_or(ProgramError::NotAttached)? .detach() } + + pub(crate) fn forget(&mut self, link_id: T::Id) -> Result { + self.links.remove(&link_id).ok_or(ProgramError::NotAttached) + } } impl Drop for LinkMap { @@ -58,7 +96,7 @@ pub(crate) struct FdLinkId(pub(crate) RawFd); #[derive(Debug)] pub(crate) struct FdLink { - fd: RawFd, + pub(crate) fd: RawFd, } impl FdLink { @@ -119,13 +157,14 @@ impl Link for ProgAttachLink { } macro_rules! define_link_wrapper { - ($wrapper:ident, #[$doc:meta] $wrapper_id:ident, $base:ident, $base_id:ident) => { - #[$doc] + (#[$doc1:meta] $wrapper:ident, #[$doc2:meta] $wrapper_id:ident, $base:ident, $base_id:ident) => { + #[$doc2] #[derive(Debug, Hash, Eq, PartialEq)] pub struct $wrapper_id($base_id); + #[$doc1] #[derive(Debug)] - pub(crate) struct $wrapper($base); + pub struct $wrapper($base); impl crate::programs::Link for $wrapper { type Id = $wrapper_id; @@ -153,7 +192,7 @@ pub(crate) use define_link_wrapper; mod tests { use std::{cell::RefCell, rc::Rc}; - use crate::programs::ProgramError; + use crate::programs::{OwnedLink, ProgramError}; use super::{Link, LinkMap}; @@ -257,4 +296,58 @@ mod tests { assert!(*l1_detached.borrow() == 1); assert!(*l2_detached.borrow() == 1); } + + #[test] + fn test_owned_detach() { + 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 owned_l1 = { + let mut links = LinkMap::new(); + let id1 = links.insert(l1).unwrap(); + links.insert(l2).unwrap(); + // manually forget one link + let owned_l1 = links.forget(id1); + assert!(*l1_detached.borrow() == 0); + assert!(*l2_detached.borrow() == 0); + owned_l1.unwrap() + }; + + // l2 is detached on `Drop`, but l1 is still alive + assert!(*l1_detached.borrow() == 0); + assert!(*l2_detached.borrow() == 1); + + // manually detach l1 + assert!(owned_l1.detach().is_ok()); + assert!(*l1_detached.borrow() == 1); + assert!(*l2_detached.borrow() == 1); + } + + #[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); + } } diff --git a/aya/src/programs/lirc_mode2.rs b/aya/src/programs/lirc_mode2.rs index fb4ec985..297a28d4 100644 --- a/aya/src/programs/lirc_mode2.rs +++ b/aya/src/programs/lirc_mode2.rs @@ -2,7 +2,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, ProgramData, ProgramError, ProgramInfo}, + programs::{load_program, query, Link, OwnedLink, ProgramData, ProgramError, ProgramInfo}, sys::{bpf_obj_get_info_by_fd, bpf_prog_attach, bpf_prog_detach, bpf_prog_get_fd_by_id}, }; @@ -81,6 +81,17 @@ impl LircMode2 { self.data.links.remove(link_id) } + /// Takes ownership of the link referenced by the provided link_id. + /// + /// The link will be detached on `Drop` and the caller is now responsible + /// for managing its lifetime. + pub fn forget_link( + &mut self, + link_id: LircLinkId, + ) -> Result, ProgramError> { + Ok(OwnedLink::new(self.data.forget_link(link_id)?)) + } + /// Queries the lirc device for attached programs. pub fn query(target_fd: T) -> Result, ProgramError> { let prog_ids = query(target_fd.as_raw_fd(), BPF_LIRC_MODE2, 0, &mut None)?; @@ -108,6 +119,7 @@ impl LircMode2 { pub struct LircLinkId(RawFd, RawFd); #[derive(Debug)] +/// An LircMode2 Link pub struct LircLink { prog_fd: RawFd, target_fd: RawFd, @@ -121,6 +133,7 @@ impl LircLink { } } + /// Get ProgramInfo from this link pub fn info(&self) -> Result { match bpf_obj_get_info_by_fd(self.prog_fd) { Ok(info) => Ok(ProgramInfo(info)), diff --git a/aya/src/programs/lsm.rs b/aya/src/programs/lsm.rs index 7c3ade5a..87109df9 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, - ProgramData, ProgramError, + OwnedLink, ProgramData, ProgramError, }, }; @@ -80,9 +80,18 @@ impl Lsm { pub fn detach(&mut self, link_id: LsmLinkId) -> Result<(), ProgramError> { self.data.links.remove(link_id) } + + /// Takes ownership of the link referenced by the provided link_id. + /// + /// The link will be detached on `Drop` and the caller is now responsible + /// for managing its lifetime. + pub fn forget_link(&mut self, link_id: LsmLinkId) -> Result, ProgramError> { + Ok(OwnedLink::new(self.data.forget_link(link_id)?)) + } } define_link_wrapper!( + /// The link used by [Lsm] programs. LsmLink, /// The type returned by [Lsm::attach]. Can be passed to [Lsm::detach]. LsmLinkId, diff --git a/aya/src/programs/mod.rs b/aya/src/programs/mod.rs index 2d889ba5..559c6e4f 100644 --- a/aya/src/programs/mod.rs +++ b/aya/src/programs/mod.rs @@ -69,26 +69,27 @@ use std::{ }; use thiserror::Error; -pub use cgroup_skb::{CgroupSkb, CgroupSkbAttachType, CgroupSkbLinkId}; -pub use extension::{Extension, ExtensionError, ExtensionLinkId}; -pub use fentry::{FEntry, FEntryLinkId}; -pub use fexit::{FExit, FExitLinkId}; -pub use kprobe::{KProbe, KProbeError, KProbeLinkId}; +pub use cgroup_skb::{CgroupSkb, CgroupSkbAttachType}; +pub use extension::{Extension, ExtensionError}; +pub use fentry::FEntry; +pub use fexit::FExit; +pub use kprobe::{KProbe, KProbeError}; use links::*; -pub use lirc_mode2::{LircLinkId, LircMode2}; -pub use lsm::{Lsm, LsmLinkId}; +pub use links::{Link, OwnedLink}; +pub use lirc_mode2::LircMode2; +pub use lsm::Lsm; use perf_attach::*; pub use perf_event::{PerfEvent, PerfEventScope, PerfTypeId, SamplePolicy}; pub use probe::ProbeKind; -pub use raw_trace_point::{RawTracePoint, RawTracePointLinkId}; -pub use sk_msg::{SkMsg, SkMsgLinkId}; -pub use sk_skb::{SkSkb, SkSkbKind, SkSkbLinkId}; -pub use sock_ops::{SockOps, SockOpsLinkId}; -pub use socket_filter::{SocketFilter, SocketFilterError, SocketFilterLinkId}; -pub use tc::{SchedClassifier, SchedClassifierLinkId, TcAttachType, TcError}; -pub use tp_btf::{BtfTracePoint, BtfTracePointLinkId}; -pub use trace_point::{TracePoint, TracePointError, TracePointLinkId}; -pub use uprobe::{UProbe, UProbeError, UProbeLinkId}; +pub use raw_trace_point::RawTracePoint; +pub use sk_msg::SkMsg; +pub use sk_skb::{SkSkb, SkSkbKind}; +pub use sock_ops::SockOps; +pub use socket_filter::{SocketFilter, SocketFilterError}; +pub use tc::{SchedClassifier, TcAttachType, TcError}; +pub use tp_btf::BtfTracePoint; +pub use trace_point::{TracePoint, TracePointError}; +pub use uprobe::{UProbe, UProbeError}; pub use xdp::{Xdp, XdpError, XdpFlags}; use crate::{ @@ -355,6 +356,10 @@ impl ProgramData { })?; Ok(()) } + + pub(crate) fn forget_link(&mut self, link_id: T::Id) -> Result { + self.links.forget(link_id) + } } fn load_program( diff --git a/aya/src/programs/perf_attach.rs b/aya/src/programs/perf_attach.rs index bf67bfa6..a0c4a598 100644 --- a/aya/src/programs/perf_attach.rs +++ b/aya/src/programs/perf_attach.rs @@ -11,7 +11,7 @@ use crate::{ pub struct PerfLinkId(RawFd); #[derive(Debug)] -pub(crate) struct PerfLink { +pub struct PerfLink { perf_fd: RawFd, probe_kind: Option, event_alias: Option, diff --git a/aya/src/programs/perf_event.rs b/aya/src/programs/perf_event.rs index 35cb5421..44c15c3e 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}, - ProgramData, ProgramError, + OwnedLink, ProgramData, ProgramError, }, sys::perf_event_open, }; @@ -177,4 +177,15 @@ impl PerfEvent { pub fn detach(&mut self, link_id: PerfLinkId) -> Result<(), ProgramError> { self.data.links.remove(link_id) } + + /// Takes ownership of the link referenced by the provided link_id. + /// + /// The link will be detached on `Drop` and the caller is now responsible + /// for managing its lifetime. + pub fn forget_link( + &mut self, + link_id: PerfLinkId, + ) -> Result, ProgramError> { + Ok(OwnedLink::new(self.data.forget_link(link_id)?)) + } } diff --git a/aya/src/programs/raw_trace_point.rs b/aya/src/programs/raw_trace_point.rs index 01ac78df..fd4656fa 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, - ProgramData, ProgramError, + OwnedLink, ProgramData, ProgramError, }, }; @@ -59,9 +59,21 @@ impl RawTracePoint { pub fn detach(&mut self, link_id: RawTracePointLinkId) -> Result<(), ProgramError> { self.data.links.remove(link_id) } + + /// Takes ownership of the link referenced by the provided link_id. + /// + /// The link will be detached on `Drop` and the caller is now responsible + /// for managing its lifetime. + pub fn forget_link( + &mut self, + link_id: RawTracePointLinkId, + ) -> Result, ProgramError> { + Ok(OwnedLink::new(self.data.forget_link(link_id)?)) + } } define_link_wrapper!( + /// The link used by [RawTracePoint] programs. RawTracePointLink, /// The type returned by [RawTracePoint::attach]. Can be passed to [RawTracePoint::detach]. RawTracePointLinkId, diff --git a/aya/src/programs/sk_msg.rs b/aya/src/programs/sk_msg.rs index 1050d466..1d0f8a10 100644 --- a/aya/src/programs/sk_msg.rs +++ b/aya/src/programs/sk_msg.rs @@ -2,8 +2,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, ProgAttachLink, ProgAttachLinkId, ProgramData, - ProgramError, + define_link_wrapper, load_program, OwnedLink, ProgAttachLink, ProgAttachLinkId, + ProgramData, ProgramError, }, sys::bpf_prog_attach, }; @@ -94,9 +94,21 @@ impl SkMsg { pub fn detach(&mut self, link_id: SkMsgLinkId) -> Result<(), ProgramError> { self.data.links.remove(link_id) } + + /// Takes ownership of the link referenced by the provided link_id. + /// + /// The link will be detached on `Drop` and the caller is now responsible + /// for managing its lifetime. + pub fn forget_link( + &mut self, + link_id: SkMsgLinkId, + ) -> Result, ProgramError> { + Ok(OwnedLink::new(self.data.forget_link(link_id)?)) + } } define_link_wrapper!( + /// The link used by [SkMsg] programs. SkMsgLink, /// The type returned by [SkMsg::attach]. Can be passed to [SkMsg::detach]. SkMsgLinkId, diff --git a/aya/src/programs/sk_skb.rs b/aya/src/programs/sk_skb.rs index baf5f2a9..4f7e7215 100644 --- a/aya/src/programs/sk_skb.rs +++ b/aya/src/programs/sk_skb.rs @@ -5,8 +5,8 @@ use crate::{ }, maps::sock::SocketMap, programs::{ - define_link_wrapper, load_program, ProgAttachLink, ProgAttachLinkId, ProgramData, - ProgramError, + define_link_wrapper, load_program, OwnedLink, ProgAttachLink, ProgAttachLinkId, + ProgramData, ProgramError, }, sys::bpf_prog_attach, }; @@ -89,9 +89,21 @@ impl SkSkb { pub fn detach(&mut self, link_id: SkSkbLinkId) -> Result<(), ProgramError> { self.data.links.remove(link_id) } + + /// Takes ownership of the link referenced by the provided link_id. + /// + /// The link will be detached on `Drop` and the caller is now responsible + /// for managing its lifetime. + pub fn forget_link( + &mut self, + link_id: SkSkbLinkId, + ) -> Result, ProgramError> { + Ok(OwnedLink::new(self.data.forget_link(link_id)?)) + } } define_link_wrapper!( + /// The link used by [SkSkb] programs. SkSkbLink, /// The type returned by [SkSkb::attach]. Can be passed to [SkSkb::detach]. SkSkbLinkId, diff --git a/aya/src/programs/sock_ops.rs b/aya/src/programs/sock_ops.rs index 232f93d3..64d1e845 100644 --- a/aya/src/programs/sock_ops.rs +++ b/aya/src/programs/sock_ops.rs @@ -3,8 +3,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, ProgAttachLink, ProgAttachLinkId, ProgramData, - ProgramError, + define_link_wrapper, load_program, OwnedLink, ProgAttachLink, ProgAttachLinkId, + ProgramData, ProgramError, }, sys::bpf_prog_attach, }; @@ -81,9 +81,21 @@ impl SockOps { pub fn detach(&mut self, link_id: SockOpsLinkId) -> Result<(), ProgramError> { self.data.links.remove(link_id) } + + /// Takes ownership of the link referenced by the provided link_id. + /// + /// The link will be detached on `Drop` and the caller is now responsible + /// for managing its lifetime. + pub fn forget_link( + &mut self, + link_id: SockOpsLinkId, + ) -> Result, ProgramError> { + Ok(OwnedLink::new(self.data.forget_link(link_id)?)) + } } define_link_wrapper!( + /// The link used by [SockOps] programs. SockOpsLink, /// The type returned by [SockOps::attach]. Can be passed to [SockOps::detach]. SockOpsLinkId, diff --git a/aya/src/programs/socket_filter.rs b/aya/src/programs/socket_filter.rs index 82cd0c48..1b65e6cd 100644 --- a/aya/src/programs/socket_filter.rs +++ b/aya/src/programs/socket_filter.rs @@ -7,7 +7,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, ProgramData, ProgramError}, + programs::{load_program, Link, OwnedLink, ProgramData, ProgramError}, }; /// The type returned when attaching a [`SocketFilter`] fails. @@ -101,14 +101,26 @@ impl SocketFilter { pub fn detach(&mut self, link_id: SocketFilterLinkId) -> Result<(), ProgramError> { self.data.links.remove(link_id) } + + /// Takes ownership of the link referenced by the provided link_id. + /// + /// The link will be detached on `Drop` and the caller is now responsible + /// for managing its lifetime. + pub fn forget_link( + &mut self, + link_id: SocketFilterLinkId, + ) -> Result, ProgramError> { + Ok(OwnedLink::new(self.data.forget_link(link_id)?)) + } } /// The type returned by [SocketFilter::attach]. Can be passed to [SocketFilter::detach]. #[derive(Debug, Hash, Eq, PartialEq)] pub struct SocketFilterLinkId(RawFd, RawFd); +/// A SocketFilter Link #[derive(Debug)] -pub(crate) struct SocketFilterLink { +pub struct SocketFilterLink { socket: RawFd, prog_fd: RawFd, } diff --git a/aya/src/programs/tc.rs b/aya/src/programs/tc.rs index a5e743bf..941ed18e 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, ProgramData, ProgramError}, + programs::{define_link_wrapper, load_program, Link, OwnedLink, ProgramData, ProgramError}, sys::{ netlink_find_filter_with_name, netlink_qdisc_add_clsact, netlink_qdisc_attach, netlink_qdisc_detach, @@ -141,6 +141,17 @@ impl SchedClassifier { pub fn detach(&mut self, link_id: SchedClassifierLinkId) -> Result<(), ProgramError> { self.data.links.remove(link_id) } + + /// Takes ownership of the link referenced by the provided link_id. + /// + /// The link will be detached on `Drop` and the caller is now responsible + /// for managing its lifetime. + pub fn forget_link( + &mut self, + link_id: SchedClassifierLinkId, + ) -> Result, ProgramError> { + Ok(OwnedLink::new(self.data.forget_link(link_id)?)) + } } #[derive(Debug, Hash, Eq, PartialEq)] @@ -168,6 +179,7 @@ impl Link for TcLink { } define_link_wrapper!( + /// The link used by [SchedClassifier] programs. SchedClassifierLink, /// The type returned by [SchedClassifier::attach]. Can be passed to [SchedClassifier::detach]. SchedClassifierLinkId, diff --git a/aya/src/programs/tp_btf.rs b/aya/src/programs/tp_btf.rs index adc641aa..d68785f3 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, - ProgramData, ProgramError, + OwnedLink, ProgramData, ProgramError, }, }; @@ -78,9 +78,21 @@ impl BtfTracePoint { pub fn detach(&mut self, link_id: BtfTracePointLinkId) -> Result<(), ProgramError> { self.data.links.remove(link_id) } + + /// Takes ownership of the link referenced by the provided link_id. + /// + /// The link will be detached on `Drop` and the caller is now responsible + /// for managing its lifetime. + pub fn forget_link( + &mut self, + link_id: BtfTracePointLinkId, + ) -> Result, ProgramError> { + Ok(OwnedLink::new(self.data.forget_link(link_id)?)) + } } define_link_wrapper!( + /// The link used by [BtfTracePoint] programs. BtfTracePointLink, /// The type returned by [BtfTracePoint::attach]. Can be passed to [BtfTracePoint::detach]. BtfTracePointLinkId, diff --git a/aya/src/programs/trace_point.rs b/aya/src/programs/trace_point.rs index fe9a3824..8882f538 100644 --- a/aya/src/programs/trace_point.rs +++ b/aya/src/programs/trace_point.rs @@ -6,7 +6,7 @@ use crate::{ programs::{ define_link_wrapper, load_program, perf_attach::{perf_attach, PerfLink, PerfLinkId}, - ProgramData, ProgramError, + OwnedLink, ProgramData, ProgramError, }, sys::perf_event_open_trace_point, }; @@ -94,9 +94,21 @@ impl TracePoint { pub fn detach(&mut self, link_id: TracePointLinkId) -> Result<(), ProgramError> { self.data.links.remove(link_id) } + + /// Takes ownership of the link referenced by the provided link_id. + /// + /// The link will be detached on `Drop` and the caller is now responsible + /// for managing its lifetime. + pub fn forget_link( + &mut self, + link_id: TracePointLinkId, + ) -> Result, ProgramError> { + Ok(OwnedLink::new(self.data.forget_link(link_id)?)) + } } define_link_wrapper!( + /// The link used by [TracePoint] programs. TracePointLink, /// The type returned by [TracePoint::attach]. Can be passed to [TracePoint::detach]. TracePointLinkId, diff --git a/aya/src/programs/uprobe.rs b/aya/src/programs/uprobe.rs index 9acff545..fa1f7a9a 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}, - ProgramData, ProgramError, + OwnedLink, ProgramData, ProgramError, }, }; @@ -128,9 +128,21 @@ impl UProbe { pub fn detach(&mut self, link_id: UProbeLinkId) -> Result<(), ProgramError> { self.data.links.remove(link_id) } + + /// Takes ownership of the link referenced by the provided link_id. + /// + /// The link will be detached on `Drop` and the caller is now responsible + /// for managing its lifetime. + pub fn forget_link( + &mut self, + link_id: UProbeLinkId, + ) -> Result, ProgramError> { + Ok(OwnedLink::new(self.data.forget_link(link_id)?)) + } } define_link_wrapper!( + /// The link used by [UProbe] programs. UProbeLink, /// The type returned by [UProbe::attach]. Can be passed to [UProbe::detach]. UProbeLinkId, diff --git a/aya/src/programs/xdp.rs b/aya/src/programs/xdp.rs index abc6dbaf..09809640 100644 --- a/aya/src/programs/xdp.rs +++ b/aya/src/programs/xdp.rs @@ -10,7 +10,9 @@ use crate::{ XDP_FLAGS_DRV_MODE, XDP_FLAGS_HW_MODE, XDP_FLAGS_REPLACE, XDP_FLAGS_SKB_MODE, XDP_FLAGS_UPDATE_IF_NOEXIST, }, - programs::{define_link_wrapper, load_program, FdLink, Link, ProgramData, ProgramError}, + programs::{ + define_link_wrapper, load_program, FdLink, Link, OwnedLink, ProgramData, ProgramError, + }, sys::{bpf_link_create, kernel_version, netlink_set_xdp_fd}, }; @@ -130,6 +132,14 @@ impl Xdp { pub fn detach(&mut self, link_id: XdpLinkId) -> Result<(), ProgramError> { self.data.links.remove(link_id) } + + /// Takes ownership of the link referenced by the provided link_id. + /// + /// The link will be detached on `Drop` and the caller is now responsible + /// for managing its lifetime. + pub fn forget_link(&mut self, link_id: XdpLinkId) -> Result, ProgramError> { + Ok(OwnedLink::new(self.data.forget_link(link_id)?)) + } } #[derive(Debug)] @@ -159,13 +169,13 @@ impl Link for NlLink { } #[derive(Debug, Hash, Eq, PartialEq)] -enum XdpLinkIdInner { +pub(crate) enum XdpLinkIdInner { FdLinkId(::Id), NlLinkId(::Id), } #[derive(Debug)] -enum XdpLinkInner { +pub(crate) enum XdpLinkInner { FdLink(FdLink), NlLink(NlLink), } @@ -189,6 +199,7 @@ impl Link for XdpLinkInner { } define_link_wrapper!( + /// The link used by [Xdp] programs. XdpLink, /// The type returned by [Xdp::attach]. Can be passed to [Xdp::detach]. XdpLinkId,