|
|
|
@ -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<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>,
|
|
|
|
@ -43,6 +77,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> {
|
|
|
|
@ -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);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|