diff --git a/aya/src/maps/bloom_filter.rs b/aya/src/maps/bloom_filter.rs index deb2c053..c74a5b2a 100644 --- a/aya/src/maps/bloom_filter.rs +++ b/aya/src/maps/bloom_filter.rs @@ -88,7 +88,7 @@ mod tests { sys::{override_syscall, SysResult, Syscall}, }; use libc::{EFAULT, ENOENT}; - use std::{env, fs::File, io, os::fd::OwnedFd}; + use std::{env, fs::File, io, os::fd::OwnedFd, sync::Arc}; fn new_obj_map() -> obj::Map { obj::Map::Legacy(LegacyMap { @@ -275,10 +275,12 @@ mod tests { )); } - fn create_fd() -> OwnedFd { + fn create_fd() -> Arc { let dir = env::temp_dir(); - File::create(dir.join("f1")) - .expect("unable to create file in tmpdir") - .into() + Arc::new( + File::create(dir.join("f1")) + .expect("unable to create file in tmpdir") + .into(), + ) } } diff --git a/aya/src/maps/hash_map/hash_map.rs b/aya/src/maps/hash_map/hash_map.rs index d70ec1bb..7eb5be0b 100644 --- a/aya/src/maps/hash_map/hash_map.rs +++ b/aya/src/maps/hash_map/hash_map.rs @@ -105,7 +105,7 @@ impl, K: Pod, V: Pod> IterableMap for HashMap #[cfg(test)] mod tests { - use std::{env, fs::File, io, os::fd::OwnedFd}; + use std::{env, fs::File, io, os::fd::OwnedFd, sync::Arc}; use libc::{EFAULT, ENOENT}; @@ -696,10 +696,12 @@ mod tests { assert!(matches!(iter.next(), None)); } - fn create_fd() -> OwnedFd { + fn create_fd() -> Arc { let dir = env::temp_dir(); - File::create(dir.join("f1")) - .expect("unable to create file in tmpdir") - .into() + Arc::new( + File::create(dir.join("f1")) + .expect("unable to create file in tmpdir") + .into(), + ) } } diff --git a/aya/src/maps/lpm_trie.rs b/aya/src/maps/lpm_trie.rs index e5c5cf53..af934f70 100644 --- a/aya/src/maps/lpm_trie.rs +++ b/aya/src/maps/lpm_trie.rs @@ -207,7 +207,7 @@ mod tests { sys::{override_syscall, SysResult, Syscall}, }; use libc::{EFAULT, ENOENT}; - use std::{env, fs::File, io, mem, net::Ipv4Addr, os::fd::OwnedFd}; + use std::{env, fs::File, io, mem, net::Ipv4Addr, os::fd::OwnedFd, sync::Arc}; fn new_obj_map() -> obj::Map { obj::Map::Legacy(LegacyMap { @@ -456,10 +456,12 @@ mod tests { assert!(matches!(trie.get(&key, 0), Err(MapError::KeyNotFound))); } - fn create_fd() -> OwnedFd { + fn create_fd() -> Arc { let dir = env::temp_dir(); - File::create(dir.join("f1")) - .expect("unable to create file in tmpdir") - .into() + Arc::new( + File::create(dir.join("f1")) + .expect("unable to create file in tmpdir") + .into(), + ) } } diff --git a/aya/src/maps/mod.rs b/aya/src/maps/mod.rs index 3c7a0796..c74e03a8 100644 --- a/aya/src/maps/mod.rs +++ b/aya/src/maps/mod.rs @@ -46,6 +46,7 @@ use std::{ os::fd::{AsFd, AsRawFd, BorrowedFd, OwnedFd, RawFd}, path::Path, ptr, + sync::Arc, }; use libc::{getrlimit, rlimit, RLIMIT_MEMLOCK, RLIM_INFINITY}; @@ -186,15 +187,15 @@ pub enum MapError { } /// A map file descriptor. -pub struct MapFd<'f>(BorrowedFd<'f>); +pub struct MapFd(Arc); -impl AsRawFd for MapFd<'_> { +impl AsRawFd for MapFd { fn as_raw_fd(&self) -> RawFd { self.0.as_raw_fd() } } -impl AsFd for MapFd<'_> { +impl AsFd for MapFd { fn as_fd(&self) -> BorrowedFd<'_> { self.0.as_fd() } @@ -478,10 +479,10 @@ pub(crate) fn check_v_size(map: &MapData) -> Result<(), MapError> { /// A generic handle to a BPF map. /// /// You should never need to use this unless you're implementing a new map type. -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct MapData { pub(crate) obj: obj::Map, - pub(crate) fd: Option, + pub(crate) fd: Option>, pub(crate) btf_fd: Option, /// Indicates if this map has been pinned to bpffs pub pinned: bool, @@ -509,7 +510,7 @@ impl MapData { } })?; - self.fd = Some(fd); + self.fd = Some(Arc::new(fd)); Ok(()) } @@ -528,7 +529,7 @@ impl MapData { call: "BPF_OBJ_GET".to_string(), io_error, })?; - self.fd = Some(fd); + self.fd = Some(Arc::new(fd)); Ok(()) } @@ -558,7 +559,7 @@ impl MapData { Ok(MapData { obj: parse_map_info(info, PinningType::ByName), - fd: Some(fd), + fd: Some(Arc::new(fd)), btf_fd: None, pinned: true, }) @@ -578,7 +579,7 @@ impl MapData { Ok(MapData { obj: parse_map_info(info, PinningType::None), - fd: Some(fd), + fd: Some(Arc::new(fd)), btf_fd: None, pinned: false, }) @@ -615,32 +616,9 @@ impl MapData { /// Returns the file descriptor of the map. /// /// Can be converted to [`RawFd`] using [`AsRawFd`]. - pub fn fd(&self) -> Option> { - self.fd.as_ref().map(|fd| MapFd(fd.as_fd())) - } -} - -impl MapData { - /// Attempts to duplicate MapData - /// - /// Fails if if the inner file descriptor could not be cloned - // TODO (AM): should we return MapError? New variant? Maybe make MapError non_exhaustive? - pub fn try_clone(&self) -> io::Result { - let fd = self.fd.as_ref().map(|f| f.try_clone()).transpose()?; - - Ok(MapData { - fd, - obj: self.obj.clone(), - btf_fd: self.btf_fd, - pinned: self.pinned, - }) - } -} - -// TODO (AM): DELETE? -impl Clone for MapData { - fn clone(&self) -> MapData { - self.try_clone().unwrap() + pub fn fd(&self) -> Option { + let fd = self.fd.clone()?; + Some(MapFd(fd)) } } diff --git a/aya/src/maps/sock/mod.rs b/aya/src/maps/sock/mod.rs index e05359c1..4dcb0926 100644 --- a/aya/src/maps/sock/mod.rs +++ b/aya/src/maps/sock/mod.rs @@ -5,22 +5,25 @@ mod sock_map; pub use sock_hash::SockHash; pub use sock_map::SockMap; -use std::os::{ - fd::{AsFd, BorrowedFd}, - unix::io::{AsRawFd, RawFd}, +use std::{ + os::{ + fd::{AsFd, BorrowedFd, OwnedFd}, + unix::io::{AsRawFd, RawFd}, + }, + sync::Arc, }; /// A socket map file descriptor. -#[derive(Copy, Clone)] -pub struct SockMapFd<'f>(BorrowedFd<'f>); +#[derive(Clone)] +pub struct SockMapFd(Arc); -impl AsRawFd for SockMapFd<'_> { +impl AsRawFd for SockMapFd { fn as_raw_fd(&self) -> RawFd { self.0.as_raw_fd() } } -impl AsFd for SockMapFd<'_> { +impl AsFd for SockMapFd { fn as_fd(&self) -> BorrowedFd<'_> { self.0.as_fd() } diff --git a/aya/src/maps/sock/sock_hash.rs b/aya/src/maps/sock/sock_hash.rs index ec383ce1..80adf3b9 100644 --- a/aya/src/maps/sock/sock_hash.rs +++ b/aya/src/maps/sock/sock_hash.rs @@ -49,10 +49,9 @@ use crate::{ /// let mut intercept_egress = SockHash::<_, u32>::try_from(bpf.map("INTERCEPT_EGRESS").unwrap())?; /// let map_fd = intercept_egress.fd()?; /// -/// // TODO (AM) : figure out lifetimes -/// // let prog: &mut SkMsg = bpf.program_mut("intercept_egress_packet").unwrap().try_into()?; -/// // prog.load()?; -/// // prog.attach(map_fd)?; +/// let prog: &mut SkMsg = bpf.program_mut("intercept_egress_packet").unwrap().try_into()?; +/// prog.load()?; +/// prog.attach(map_fd)?; /// /// let mut client = TcpStream::connect("127.0.0.1:1234")?; /// let mut intercept_egress = SockHash::try_from(bpf.map_mut("INTERCEPT_EGRESS").unwrap())?; @@ -109,8 +108,10 @@ impl, K: Pod> SockHash { /// /// The returned file descriptor can be used to attach programs that work with /// socket maps, like [`SkMsg`](crate::programs::SkMsg) and [`SkSkb`](crate::programs::SkSkb). - pub fn fd(&self) -> Result, MapError> { - Ok(SockMapFd(self.inner.borrow().fd_or_err()?)) + pub fn fd(&self) -> Result { + Ok(SockMapFd( + self.inner.borrow().fd.clone().ok_or(MapError::NotCreated)?, + )) } } diff --git a/aya/src/maps/sock/sock_map.rs b/aya/src/maps/sock/sock_map.rs index a82a9a5e..0917db37 100644 --- a/aya/src/maps/sock/sock_map.rs +++ b/aya/src/maps/sock/sock_map.rs @@ -33,10 +33,9 @@ use crate::{ /// let intercept_ingress = SockMap::try_from(bpf.map("INTERCEPT_INGRESS").unwrap())?; /// let map_fd = intercept_ingress.fd()?; /// -/// // TODO (AM): figure out lifetimes -/// // let prog: &mut SkSkb = bpf.program_mut("intercept_ingress_packet").unwrap().try_into()?; -/// // prog.load()?; -/// // prog.attach(map_fd)?; +/// let prog: &mut SkSkb = bpf.program_mut("intercept_ingress_packet").unwrap().try_into()?; +/// prog.load()?; +/// prog.attach(map_fd)?; /// /// # Ok::<(), aya::BpfError>(()) /// ``` @@ -65,8 +64,10 @@ impl> SockMap { /// /// The returned file descriptor can be used to attach programs that work with /// socket maps, like [`SkMsg`](crate::programs::SkMsg) and [`SkSkb`](crate::programs::SkSkb). - pub fn fd(&self) -> Result, MapError> { - Ok(SockMapFd(self.inner.borrow().fd_or_err()?)) + pub fn fd(&self) -> Result { + Ok(SockMapFd( + self.inner.borrow().fd.clone().ok_or(MapError::NotCreated)?, + )) } } diff --git a/aya/src/programs/extension.rs b/aya/src/programs/extension.rs index ad28767e..bfed52f9 100644 --- a/aya/src/programs/extension.rs +++ b/aya/src/programs/extension.rs @@ -42,11 +42,9 @@ pub enum ExtensionError { /// prog.attach("eth0", XdpFlags::default())?; /// /// let prog_fd = prog.fd().unwrap(); -/// // TODO (AM): can't borrow here becauase prog_fd is holding a reference already -/// // need to confirm what the API wants to be -/// // let ext: &mut Extension = bpf.program_mut("extension").unwrap().try_into()?; -/// // ext.load(prog_fd, "function_to_replace")?; -/// // ext.attach()?; +/// let ext: &mut Extension = bpf.program_mut("extension").unwrap().try_into()?; +/// ext.load(prog_fd, "function_to_replace")?; +/// ext.attach()?; /// Ok::<(), aya::BpfError>(()) /// ``` #[derive(Debug)] diff --git a/aya/src/programs/mod.rs b/aya/src/programs/mod.rs index c0b60311..16e91759 100644 --- a/aya/src/programs/mod.rs +++ b/aya/src/programs/mod.rs @@ -73,6 +73,7 @@ use std::{ unix::io::{AsRawFd, RawFd}, }, path::{Path, PathBuf}, + sync::Arc, }; use thiserror::Error; @@ -217,16 +218,16 @@ pub enum ProgramError { } /// A [`Program`] file descriptor. -#[derive(Copy, Clone)] -pub struct ProgramFd<'f>(BorrowedFd<'f>); +#[derive(Clone)] +pub struct ProgramFd(Arc); -impl AsRawFd for ProgramFd<'_> { +impl AsRawFd for ProgramFd { fn as_raw_fd(&self) -> RawFd { self.0.as_raw_fd() } } -impl AsFd for ProgramFd<'_> { +impl AsFd for ProgramFd { fn as_fd(&self) -> BorrowedFd<'_> { self.0.as_fd() } @@ -415,7 +416,7 @@ impl Program { pub(crate) struct ProgramData { pub(crate) name: Option, pub(crate) obj: Option<(obj::Program, obj::Function)>, - pub(crate) fd: Option, + pub(crate) fd: Option>, pub(crate) links: LinkMap, pub(crate) expected_attach_type: Option, pub(crate) attach_btf_obj_fd: Option, @@ -476,7 +477,7 @@ impl ProgramData { Ok(ProgramData { name, obj: None, - fd: Some(fd), + fd: Some(Arc::new(fd)), links: LinkMap::new(), expected_attach_type: None, attach_btf_obj_fd, @@ -630,7 +631,7 @@ fn load_program( match ret { Ok(prog_fd) => { - *fd = Some(prog_fd); + *fd = Some(Arc::new(prog_fd)); Ok(()) } Err((_, io_error)) => { @@ -739,8 +740,9 @@ macro_rules! impl_fd { $( impl $struct_name { /// Returns the file descriptor of this Program. - pub fn fd(&self) -> Option> { - self.data.fd.as_ref().map(|fd| ProgramFd(fd.as_fd())) + pub fn fd(&self) -> Option { + let fd = self.data.fd.clone()?; + Some(ProgramFd(fd)) } } )+ diff --git a/aya/src/programs/sk_msg.rs b/aya/src/programs/sk_msg.rs index 88e61cf2..f6b9c75d 100644 --- a/aya/src/programs/sk_msg.rs +++ b/aya/src/programs/sk_msg.rs @@ -46,10 +46,9 @@ use crate::{ /// let intercept_egress: SockHash<_, u32> = bpf.map("INTERCEPT_EGRESS").unwrap().try_into()?; /// let map_fd = intercept_egress.fd()?; /// -/// // TODO (AM): Figure out lifetimes -/// // let prog: &mut SkMsg = bpf.program_mut("intercept_egress_packet").unwrap().try_into()?; -/// // prog.load()?; -/// // prog.attach(map_fd)?; +/// let prog: &mut SkMsg = bpf.program_mut("intercept_egress_packet").unwrap().try_into()?; +/// prog.load()?; +/// prog.attach(map_fd)?; /// /// let mut client = TcpStream::connect("127.0.0.1:1234")?; /// let mut intercept_egress: SockHash<_, u32> = bpf.map_mut("INTERCEPT_EGRESS").unwrap().try_into()?; @@ -79,7 +78,7 @@ impl SkMsg { /// Attaches the program to the given sockmap. /// /// The returned value can be used to detach, see [SkMsg::detach]. - pub fn attach(&mut self, map: SockMapFd<'_>) -> Result { + pub fn attach(&mut self, map: SockMapFd) -> Result { let prog_fd = self.data.fd_or_err()?; let map_fd = map.as_fd(); diff --git a/aya/src/programs/sk_skb.rs b/aya/src/programs/sk_skb.rs index 65d0f5cb..6cd3a3e3 100644 --- a/aya/src/programs/sk_skb.rs +++ b/aya/src/programs/sk_skb.rs @@ -47,10 +47,9 @@ pub enum SkSkbKind { /// let intercept_ingress: SockMap<_> = bpf.map("INTERCEPT_INGRESS").unwrap().try_into()?; /// let map_fd = intercept_ingress.fd()?; /// -/// // TODO (AM): figure out lifetimes -/// // let prog: &mut SkSkb = bpf.program_mut("intercept_ingress_packet").unwrap().try_into()?; -/// // prog.load()?; -/// // prog.attach(map_fd)?; +/// let prog: &mut SkSkb = bpf.program_mut("intercept_ingress_packet").unwrap().try_into()?; +/// prog.load()?; +/// prog.attach(map_fd)?; /// /// # Ok::<(), aya::BpfError>(()) /// ``` @@ -74,7 +73,7 @@ impl SkSkb { /// Attaches the program to the given socket map. /// /// The returned value can be used to detach, see [SkSkb::detach]. - pub fn attach(&mut self, map: SockMapFd<'_>) -> Result { + pub fn attach(&mut self, map: SockMapFd) -> Result { let prog_fd = self.data.fd_or_err()?; let map_fd = map.as_fd();