Skip to content

Commit

Permalink
aya: Implement forget_link
Browse files Browse the repository at this point in the history
Fixes #51

Signed-off-by: Dave Tucker <dave@dtucker.co.uk>
  • Loading branch information
dave-tucker committed May 10, 2022
1 parent e71e07f commit 03cf302
Show file tree
Hide file tree
Showing 21 changed files with 334 additions and 46 deletions.
15 changes: 14 additions & 1 deletion aya/src/programs/cgroup_skb.rs
Expand Up @@ -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},
};
Expand Down Expand Up @@ -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<OwnedLink<CgroupSkbLink>, ProgramError> {
Ok(OwnedLink::new(self.data.forget_link(link_id)?))
}

/// Detaches the program.
///
/// See [CgroupSkb::attach].
Expand Down Expand Up @@ -155,6 +167,7 @@ impl Link for CgroupSkbLinkInner {
}

define_link_wrapper!(
/// An owned link, obtained using [CgroupSkb::forget_link]
CgroupSkbLink,
/// The type returned by [CgroupSkb::attach]. Can be passed to [CgroupSkb::detach].
CgroupSkbLinkId,
Expand Down
16 changes: 15 additions & 1 deletion aya/src/programs/extension.rs
Expand Up @@ -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,
};
Expand Down Expand Up @@ -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<OwnedLink<ExtensionLink>, ProgramError> {
Ok(OwnedLink::new(self.data.forget_link(link_id)?))
}
}

define_link_wrapper!(
/// An owned link, obtained using [Extension::forget_link]
ExtensionLink,
/// The type returned by [Extension::attach]. Can be passed to [Extension::detach].
ExtensionLinkId,
Expand Down
14 changes: 13 additions & 1 deletion aya/src/programs/fentry.rs
Expand Up @@ -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,
},
};

Expand Down Expand Up @@ -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<OwnedLink<FEntryLink>, ProgramError> {
Ok(OwnedLink::new(self.data.forget_link(link_id)?))
}
}

define_link_wrapper!(
/// An owned link, obtained using [FEntry::forget_link]
FEntryLink,
/// The type returned by [FEntry::attach]. Can be passed to [FEntry::detach].
FEntryLinkId,
Expand Down
14 changes: 13 additions & 1 deletion aya/src/programs/fexit.rs
Expand Up @@ -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,
},
};

Expand Down Expand Up @@ -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<OwnedLink<FExitLink>, ProgramError> {
Ok(OwnedLink::new(self.data.forget_link(link_id)?))
}
}

define_link_wrapper!(
/// An owned link, obtained using [FExit::forget_link]
FExitLink,
/// The type returned by [FExit::attach]. Can be passed to [FExit::detach].
FExitLinkId,
Expand Down
14 changes: 13 additions & 1 deletion aya/src/programs/kprobe.rs
Expand Up @@ -8,7 +8,7 @@ use crate::{
define_link_wrapper, load_program,
perf_attach::{PerfLink, PerfLinkId},
probe::{attach, ProbeKind},
ProgramData, ProgramError,
OwnedLink, ProgramData, ProgramError,
},
};

Expand Down Expand Up @@ -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<OwnedLink<KProbeLink>, ProgramError> {
Ok(OwnedLink::new(self.data.forget_link(link_id)?))
}
}

define_link_wrapper!(
/// An owned link, obtained using [KProbe::forget_link]
KProbeLink,
/// The type returned by [KProbe::attach]. Can be passed to [KProbe::detach].
KProbeLinkId,
Expand Down
78 changes: 73 additions & 5 deletions aya/src/programs/links.rs
@@ -1,19 +1,54 @@
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 UUID
fn id(&self) -> Self::Id;

/// Detaches the Link
fn detach(self) -> Result<(), ProgramError>;
}

/// OwnedLink is a wrapper that is used to return a Link to the caller
/// and ensures the link will be cleaned up when out of scope.
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>,
Expand Down Expand Up @@ -43,6 +78,10 @@ impl<T: Link> LinkMap<T> {
.ok_or(ProgramError::NotAttached)?
.detach()
}

pub(crate) fn forget(&mut self, link_id: T::Id) -> Result<T, ProgramError> {
self.links.remove(&link_id).ok_or(ProgramError::NotAttached)
}
}

impl<T: Link> Drop for LinkMap<T> {
Expand All @@ -58,7 +97,7 @@ pub(crate) struct FdLinkId(pub(crate) RawFd);

#[derive(Debug)]
pub(crate) struct FdLink {
fd: RawFd,
pub(crate) fd: RawFd,
}

impl FdLink {
Expand Down Expand Up @@ -119,13 +158,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;
Expand Down Expand Up @@ -257,4 +297,32 @@ mod tests {
assert!(*l1_detached.borrow() == 1);
assert!(*l2_detached.borrow() == 1);
}

#[test]
fn test_forget() {
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);
}
}
15 changes: 14 additions & 1 deletion aya/src/programs/lirc_mode2.rs
Expand Up @@ -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},
};

Expand Down Expand Up @@ -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<OwnedLink<LircLink>, ProgramError> {
Ok(OwnedLink::new(self.data.forget_link(link_id)?))
}

/// Queries the lirc device for attached programs.
pub fn query<T: AsRawFd>(target_fd: T) -> Result<Vec<LircLink>, ProgramError> {
let prog_ids = query(target_fd.as_raw_fd(), BPF_LIRC_MODE2, 0, &mut None)?;
Expand Down Expand Up @@ -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,
Expand All @@ -121,6 +133,7 @@ impl LircLink {
}
}

/// Get ProgramInfo from this link
pub fn info(&self) -> Result<ProgramInfo, ProgramError> {
match bpf_obj_get_info_by_fd(self.prog_fd) {
Ok(info) => Ok(ProgramInfo(info)),
Expand Down
11 changes: 10 additions & 1 deletion aya/src/programs/lsm.rs
Expand Up @@ -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,
},
};

Expand Down Expand Up @@ -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<OwnedLink<LsmLink>, ProgramError> {
Ok(OwnedLink::new(self.data.forget_link(link_id)?))
}
}

define_link_wrapper!(
/// An owned link, obtained using [Lsm::forget_link]
LsmLink,
/// The type returned by [Lsm::attach]. Can be passed to [Lsm::detach].
LsmLinkId,
Expand Down

0 comments on commit 03cf302

Please sign in to comment.