|  |  |  | @ -1,12 +1,12 @@ | 
		
	
		
			
				|  |  |  |  | //! Program links.
 | 
		
	
		
			
				|  |  |  |  | use std::{ | 
		
	
		
			
				|  |  |  |  |     collections::{hash_map::Entry, HashMap}, | 
		
	
		
			
				|  |  |  |  |     ffi::CString, | 
		
	
		
			
				|  |  |  |  |     io, | 
		
	
		
			
				|  |  |  |  |     os::fd::{AsFd as _, AsRawFd as _, BorrowedFd, RawFd}, | 
		
	
		
			
				|  |  |  |  |     path::{Path, PathBuf}, | 
		
	
		
			
				|  |  |  |  | }; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | use hashbrown::hash_set::{Entry, HashSet}; | 
		
	
		
			
				|  |  |  |  | use thiserror::Error; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | use crate::{ | 
		
	
	
		
			
				
					|  |  |  | @ -20,9 +20,9 @@ use crate::{ | 
		
	
		
			
				|  |  |  |  | }; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | /// A Link.
 | 
		
	
		
			
				|  |  |  |  | pub trait Link: std::fmt::Debug + 'static { | 
		
	
		
			
				|  |  |  |  | pub trait Link: std::fmt::Debug + Eq + std::hash::Hash + 'static { | 
		
	
		
			
				|  |  |  |  |     /// Unique Id
 | 
		
	
		
			
				|  |  |  |  |     type Id: std::fmt::Debug + std::hash::Hash + Eq + PartialEq; | 
		
	
		
			
				|  |  |  |  |     type Id: std::fmt::Debug + Eq + std::hash::Hash + hashbrown::Equivalent<Self>; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |     /// Returns the link id
 | 
		
	
		
			
				|  |  |  |  |     fn id(&self) -> Self::Id; | 
		
	
	
		
			
				
					|  |  |  | @ -56,48 +56,50 @@ impl From<CgroupAttachMode> for u32 { | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | #[derive(Debug)] | 
		
	
		
			
				|  |  |  |  | pub(crate) struct LinkMap<T: Link> { | 
		
	
		
			
				|  |  |  |  |     links: HashMap<T::Id, T>, | 
		
	
		
			
				|  |  |  |  | pub(crate) struct Links<T: Link> { | 
		
	
		
			
				|  |  |  |  |     links: HashSet<T>, | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | impl<T: Link> LinkMap<T> { | 
		
	
		
			
				|  |  |  |  | impl<T> Links<T> | 
		
	
		
			
				|  |  |  |  | where | 
		
	
		
			
				|  |  |  |  |     T: Eq + std::hash::Hash + Link, | 
		
	
		
			
				|  |  |  |  |     T::Id: hashbrown::Equivalent<T> + Eq + std::hash::Hash, | 
		
	
		
			
				|  |  |  |  | { | 
		
	
		
			
				|  |  |  |  |     pub(crate) fn new() -> Self { | 
		
	
		
			
				|  |  |  |  |         Self { | 
		
	
		
			
				|  |  |  |  |             links: HashMap::new(), | 
		
	
		
			
				|  |  |  |  |             links: Default::default(), | 
		
	
		
			
				|  |  |  |  |         } | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |     pub(crate) fn insert(&mut self, link: T) -> Result<T::Id, ProgramError> { | 
		
	
		
			
				|  |  |  |  |         let id = link.id(); | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |         match self.links.entry(link.id()) { | 
		
	
		
			
				|  |  |  |  |             Entry::Occupied(_) => return Err(ProgramError::AlreadyAttached), | 
		
	
		
			
				|  |  |  |  |             Entry::Vacant(e) => e.insert(link), | 
		
	
		
			
				|  |  |  |  |         }; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |         Ok(id) | 
		
	
		
			
				|  |  |  |  |         match self.links.entry(link) { | 
		
	
		
			
				|  |  |  |  |             Entry::Occupied(_entry) => Err(ProgramError::AlreadyAttached), | 
		
	
		
			
				|  |  |  |  |             Entry::Vacant(entry) => Ok(entry.insert().get().id()), | 
		
	
		
			
				|  |  |  |  |         } | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |     pub(crate) fn remove(&mut self, link_id: T::Id) -> Result<(), ProgramError> { | 
		
	
		
			
				|  |  |  |  |         self.links | 
		
	
		
			
				|  |  |  |  |             .remove(&link_id) | 
		
	
		
			
				|  |  |  |  |             .take(&link_id) | 
		
	
		
			
				|  |  |  |  |             .ok_or(ProgramError::NotAttached)? | 
		
	
		
			
				|  |  |  |  |             .detach() | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |     pub(crate) fn forget(&mut self, link_id: T::Id) -> Result<T, ProgramError> { | 
		
	
		
			
				|  |  |  |  |         self.links.take(&link_id).ok_or(ProgramError::NotAttached) | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | impl<T: Link> Links<T> { | 
		
	
		
			
				|  |  |  |  |     pub(crate) fn remove_all(&mut self) -> Result<(), ProgramError> { | 
		
	
		
			
				|  |  |  |  |         for (_, link) in self.links.drain() { | 
		
	
		
			
				|  |  |  |  |         for link in self.links.drain() { | 
		
	
		
			
				|  |  |  |  |             link.detach()?; | 
		
	
		
			
				|  |  |  |  |         } | 
		
	
		
			
				|  |  |  |  |         Ok(()) | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |     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> { | 
		
	
		
			
				|  |  |  |  | impl<T: Link> Drop for Links<T> { | 
		
	
		
			
				|  |  |  |  |     fn drop(&mut self) { | 
		
	
		
			
				|  |  |  |  |         let _ = self.remove_all(); | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
	
		
			
				
					|  |  |  | @ -206,6 +208,8 @@ impl Link for FdLink { | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | id_as_key!(FdLink, FdLinkId); | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | impl From<PinnedLink> for FdLink { | 
		
	
		
			
				|  |  |  |  |     fn from(p: PinnedLink) -> Self { | 
		
	
		
			
				|  |  |  |  |         p.inner | 
		
	
	
		
			
				
					|  |  |  | @ -321,6 +325,40 @@ impl Link for ProgAttachLink { | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | id_as_key!(ProgAttachLink, ProgAttachLinkId); | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | macro_rules! id_as_key { | 
		
	
		
			
				|  |  |  |  |     ($wrapper:ident, $wrapper_id:ident) => { | 
		
	
		
			
				|  |  |  |  |         impl PartialEq for $wrapper { | 
		
	
		
			
				|  |  |  |  |             fn eq(&self, other: &Self) -> bool { | 
		
	
		
			
				|  |  |  |  |                 use $crate::programs::links::Link as _; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |                 self.id() == other.id() | 
		
	
		
			
				|  |  |  |  |             } | 
		
	
		
			
				|  |  |  |  |         } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |         impl Eq for $wrapper {} | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |         impl std::hash::Hash for $wrapper { | 
		
	
		
			
				|  |  |  |  |             fn hash<H: std::hash::Hasher>(&self, state: &mut H) { | 
		
	
		
			
				|  |  |  |  |                 use $crate::programs::links::Link as _; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |                 self.id().hash(state) | 
		
	
		
			
				|  |  |  |  |             } | 
		
	
		
			
				|  |  |  |  |         } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |         impl hashbrown::Equivalent<$wrapper> for $wrapper_id { | 
		
	
		
			
				|  |  |  |  |             fn equivalent(&self, key: &$wrapper) -> bool { | 
		
	
		
			
				|  |  |  |  |                 use $crate::programs::links::Link as _; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |                 *self == key.id() | 
		
	
		
			
				|  |  |  |  |             } | 
		
	
		
			
				|  |  |  |  |         } | 
		
	
		
			
				|  |  |  |  |     }; | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | pub(crate) use id_as_key; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | macro_rules! define_link_wrapper { | 
		
	
		
			
				|  |  |  |  |     (#[$doc1:meta] $wrapper:ident, #[$doc2:meta] $wrapper_id:ident, $base:ident, $base_id:ident, $program:ident,) => { | 
		
	
		
			
				|  |  |  |  |         #[$doc2] | 
		
	
	
		
			
				
					|  |  |  | @ -350,7 +388,7 @@ macro_rules! define_link_wrapper { | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |         impl Drop for $wrapper { | 
		
	
		
			
				|  |  |  |  |             fn drop(&mut self) { | 
		
	
		
			
				|  |  |  |  |                 use crate::programs::links::Link; | 
		
	
		
			
				|  |  |  |  |                 use $crate::programs::links::Link as _; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |                 if let Some(base) = self.0.take() { | 
		
	
		
			
				|  |  |  |  |                     let _ = base.detach(); | 
		
	
	
		
			
				
					|  |  |  | @ -370,6 +408,8 @@ macro_rules! define_link_wrapper { | 
		
	
		
			
				|  |  |  |  |             } | 
		
	
		
			
				|  |  |  |  |         } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |         $crate::programs::links::id_as_key!($wrapper, $wrapper_id); | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |         impl From<$base> for $wrapper { | 
		
	
		
			
				|  |  |  |  |             fn from(b: $base) -> $wrapper { | 
		
	
		
			
				|  |  |  |  |                 $wrapper(Some(b)) | 
		
	
	
		
			
				
					|  |  |  | @ -540,7 +580,7 @@ mod tests { | 
		
	
		
			
				|  |  |  |  |     use assert_matches::assert_matches; | 
		
	
		
			
				|  |  |  |  |     use tempfile::tempdir; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |     use super::{FdLink, Link, LinkMap}; | 
		
	
		
			
				|  |  |  |  |     use super::{FdLink, Link, Links}; | 
		
	
		
			
				|  |  |  |  |     use crate::{ | 
		
	
		
			
				|  |  |  |  |         generated::{BPF_F_ALLOW_MULTI, BPF_F_ALLOW_OVERRIDE}, | 
		
	
		
			
				|  |  |  |  |         programs::{CgroupAttachMode, ProgramError}, | 
		
	
	
		
			
				
					|  |  |  | @ -578,9 +618,11 @@ mod tests { | 
		
	
		
			
				|  |  |  |  |         } | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |     id_as_key!(TestLink, TestLinkId); | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |     #[test] | 
		
	
		
			
				|  |  |  |  |     fn test_link_map() { | 
		
	
		
			
				|  |  |  |  |         let mut links = LinkMap::new(); | 
		
	
		
			
				|  |  |  |  |         let mut links = Links::new(); | 
		
	
		
			
				|  |  |  |  |         let l1 = TestLink::new(1, 2); | 
		
	
		
			
				|  |  |  |  |         let l1_detached = Rc::clone(&l1.detached); | 
		
	
		
			
				|  |  |  |  |         let l2 = TestLink::new(1, 3); | 
		
	
	
		
			
				
					|  |  |  | @ -603,7 +645,7 @@ mod tests { | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |     #[test] | 
		
	
		
			
				|  |  |  |  |     fn test_already_attached() { | 
		
	
		
			
				|  |  |  |  |         let mut links = LinkMap::new(); | 
		
	
		
			
				|  |  |  |  |         let mut links = Links::new(); | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |         links.insert(TestLink::new(1, 2)).unwrap(); | 
		
	
		
			
				|  |  |  |  |         assert_matches!( | 
		
	
	
		
			
				
					|  |  |  | @ -614,7 +656,7 @@ mod tests { | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |     #[test] | 
		
	
		
			
				|  |  |  |  |     fn test_not_attached() { | 
		
	
		
			
				|  |  |  |  |         let mut links = LinkMap::new(); | 
		
	
		
			
				|  |  |  |  |         let mut links = Links::new(); | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |         let l1 = TestLink::new(1, 2); | 
		
	
		
			
				|  |  |  |  |         let l1_id1 = l1.id(); | 
		
	
	
		
			
				
					|  |  |  | @ -632,7 +674,7 @@ mod tests { | 
		
	
		
			
				|  |  |  |  |         let l2_detached = Rc::clone(&l2.detached); | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |         { | 
		
	
		
			
				|  |  |  |  |             let mut links = LinkMap::new(); | 
		
	
		
			
				|  |  |  |  |             let mut links = Links::new(); | 
		
	
		
			
				|  |  |  |  |             let id1 = links.insert(l1).unwrap(); | 
		
	
		
			
				|  |  |  |  |             links.insert(l2).unwrap(); | 
		
	
		
			
				|  |  |  |  |             // manually remove one link
 | 
		
	
	
		
			
				
					|  |  |  | @ -653,7 +695,7 @@ mod tests { | 
		
	
		
			
				|  |  |  |  |         let l2_detached = Rc::clone(&l2.detached); | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |         let owned_l1 = { | 
		
	
		
			
				|  |  |  |  |             let mut links = LinkMap::new(); | 
		
	
		
			
				|  |  |  |  |             let mut links = Links::new(); | 
		
	
		
			
				|  |  |  |  |             let id1 = links.insert(l1).unwrap(); | 
		
	
		
			
				|  |  |  |  |             links.insert(l2).unwrap(); | 
		
	
		
			
				|  |  |  |  |             // manually forget one link
 | 
		
	
	
		
			
				
					|  |  |  | 
 |