浏览代码

Merge pull request #662 from nrxus/use-owned-fd-for-btf

Use `OwnedFd` for BTF's file descriptor
Tamir Duberstein 1 年之前
父节点
当前提交
13e83b24ee

+ 1 - 0
aya/Cargo.toml

@@ -9,6 +9,7 @@ repository = "https://github.com/aya-rs/aya"
 readme = "README.md"
 documentation = "https://docs.rs/aya"
 edition = "2021"
+rust-version = "1.66"
 
 [dependencies]
 async-io = { workspace = true, optional = true }

+ 13 - 11
aya/src/bpf.rs

@@ -3,8 +3,12 @@ use std::{
     collections::{HashMap, HashSet},
     ffi::CString,
     fs, io,
-    os::{raw::c_int, unix::io::RawFd},
+    os::{
+        fd::{OwnedFd, RawFd},
+        raw::c_int,
+    },
     path::{Path, PathBuf},
+    sync::Arc,
 };
 
 use aya_obj::{
@@ -390,7 +394,7 @@ impl<'a> BpfLoader<'a> {
         let btf_fd = if let Some(features) = &FEATURES.btf() {
             if let Some(btf) = obj.fixup_and_sanitize_btf(features)? {
                 match load_btf(btf.to_bytes(), *verifier_log_level) {
-                    Ok(btf_fd) => Some(btf_fd),
+                    Ok(btf_fd) => Some(Arc::new(btf_fd)),
                     // Only report an error here if the BTF is truely needed, otherwise proceed without.
                     Err(err) => {
                         for program in obj.programs.values() {
@@ -473,7 +477,7 @@ impl<'a> BpfLoader<'a> {
                 obj,
                 fd: None,
                 pinned: false,
-                btf_fd,
+                btf_fd: btf_fd.as_ref().map(Arc::clone),
             };
             let fd = match map.obj.pinning() {
                 PinningType::ByName => {
@@ -543,6 +547,7 @@ impl<'a> BpfLoader<'a> {
                 let section = prog_obj.section.clone();
                 let obj = (prog_obj, function_obj);
 
+                let btf_fd = btf_fd.as_ref().map(Arc::clone);
                 let program = if extensions.contains(name.as_str()) {
                     Program::Extension(Extension {
                         data: ProgramData::new(prog_name, obj, btf_fd, *verifier_log_level),
@@ -993,17 +998,14 @@ pub enum BpfError {
     ProgramError(#[from] ProgramError),
 }
 
-fn load_btf(raw_btf: Vec<u8>, verifier_log_level: VerifierLogLevel) -> Result<RawFd, BtfError> {
+fn load_btf(raw_btf: Vec<u8>, verifier_log_level: VerifierLogLevel) -> Result<OwnedFd, BtfError> {
     let (ret, verifier_log) = retry_with_verifier_logs(10, |logger| {
         bpf_load_btf(raw_btf.as_slice(), logger, verifier_log_level)
     });
-    match ret {
-        Ok(fd) => Ok(fd as RawFd),
-        Err((_, io_error)) => Err(BtfError::LoadError {
-            io_error,
-            verifier_log,
-        }),
-    }
+    ret.map_err(|(_, io_error)| BtfError::LoadError {
+        io_error,
+        verifier_log,
+    })
 }
 
 /// Global data that can be exported to eBPF programs before they are loaded.

+ 2 - 2
aya/src/maps/bloom_filter.rs

@@ -90,7 +90,7 @@ mod tests {
     };
     use assert_matches::assert_matches;
     use libc::{EFAULT, ENOENT};
-    use std::io;
+    use std::{ffi::c_long, io};
 
     fn new_obj_map() -> obj::Map {
         obj::Map::Legacy(LegacyMap {
@@ -108,7 +108,7 @@ mod tests {
         })
     }
 
-    fn sys_error(value: i32) -> SysResult {
+    fn sys_error(value: i32) -> SysResult<c_long> {
         Err((-1, io::Error::from_raw_os_error(value)))
     }
 

+ 4 - 4
aya/src/maps/hash_map/hash_map.rs

@@ -105,7 +105,7 @@ impl<T: Borrow<MapData>, K: Pod, V: Pod> IterableMap<K, V> for HashMap<T, K, V>
 
 #[cfg(test)]
 mod tests {
-    use std::io;
+    use std::{ffi::c_long, io};
 
     use assert_matches::assert_matches;
     use libc::{EFAULT, ENOENT};
@@ -139,7 +139,7 @@ mod tests {
         })
     }
 
-    fn sys_error(value: i32) -> SysResult {
+    fn sys_error(value: i32) -> SysResult<c_long> {
         Err((-1, io::Error::from_raw_os_error(value)))
     }
 
@@ -451,7 +451,7 @@ mod tests {
         assert_matches!(keys, Ok(ks) if ks.is_empty())
     }
 
-    fn get_next_key(attr: &bpf_attr) -> SysResult {
+    fn get_next_key(attr: &bpf_attr) -> SysResult<c_long> {
         match bpf_key(attr) {
             None => set_next_key(attr, 10),
             Some(10) => set_next_key(attr, 20),
@@ -463,7 +463,7 @@ mod tests {
         Ok(1)
     }
 
-    fn lookup_elem(attr: &bpf_attr) -> SysResult {
+    fn lookup_elem(attr: &bpf_attr) -> SysResult<c_long> {
         match bpf_key(attr) {
             Some(10) => set_ret(attr, 100),
             Some(20) => set_ret(attr, 200),

+ 2 - 2
aya/src/maps/lpm_trie.rs

@@ -209,7 +209,7 @@ mod tests {
     };
     use assert_matches::assert_matches;
     use libc::{EFAULT, ENOENT};
-    use std::{io, mem, net::Ipv4Addr};
+    use std::{ffi::c_long, io, mem, net::Ipv4Addr};
 
     fn new_obj_map() -> obj::Map {
         obj::Map::Legacy(LegacyMap {
@@ -227,7 +227,7 @@ mod tests {
         })
     }
 
-    fn sys_error(value: i32) -> SysResult {
+    fn sys_error(value: i32) -> SysResult<c_long> {
         Err((-1, io::Error::from_raw_os_error(value)))
     }
 

+ 20 - 15
aya/src/maps/mod.rs

@@ -42,9 +42,10 @@ use std::{
     marker::PhantomData,
     mem,
     ops::Deref,
-    os::fd::{AsRawFd, RawFd},
+    os::fd::{AsFd, AsRawFd, OwnedFd, RawFd},
     path::Path,
     ptr,
+    sync::Arc,
 };
 
 use crate::util::KernelVersion;
@@ -486,7 +487,7 @@ pub(crate) fn check_v_size<V>(map: &MapData) -> Result<(), MapError> {
 pub struct MapData {
     pub(crate) obj: obj::Map,
     pub(crate) fd: Option<RawFd>,
-    pub(crate) btf_fd: Option<RawFd>,
+    pub(crate) btf_fd: Option<Arc<OwnedFd>>,
     /// Indicates if this map has been pinned to bpffs
     pub pinned: bool,
 }
@@ -504,19 +505,23 @@ impl MapData {
         let kernel_version = KernelVersion::current().unwrap();
         #[cfg(test)]
         let kernel_version = KernelVersion::new(0xff, 0xff, 0xff);
-        let fd = bpf_create_map(&c_name, &self.obj, self.btf_fd, kernel_version).map_err(
-            |(code, io_error)| {
-                if kernel_version < KernelVersion::new(5, 11, 0) {
-                    maybe_warn_rlimit();
-                }
+        let fd = bpf_create_map(
+            &c_name,
+            &self.obj,
+            self.btf_fd.as_ref().map(|f| f.as_fd()),
+            kernel_version,
+        )
+        .map_err(|(code, io_error)| {
+            if kernel_version < KernelVersion::new(5, 11, 0) {
+                maybe_warn_rlimit();
+            }
 
-                MapError::CreateError {
-                    name: name.into(),
-                    code,
-                    io_error,
-                }
-            },
-        )? as RawFd;
+            MapError::CreateError {
+                name: name.into(),
+                code,
+                io_error,
+            }
+        })? as RawFd;
 
         self.fd = Some(fd);
 
@@ -639,7 +644,7 @@ impl Clone for MapData {
         MapData {
             obj: self.obj.clone(),
             fd: self.fd.map(|fd| unsafe { libc::dup(fd) }),
-            btf_fd: self.btf_fd,
+            btf_fd: self.btf_fd.as_ref().map(Arc::clone),
             pinned: self.pinned,
         }
     }

+ 1 - 1
aya/src/maps/perf/perf_buffer.rs

@@ -1,7 +1,7 @@
 use std::{
     ffi::c_void,
     io, mem,
-    os::unix::io::{AsRawFd, RawFd},
+    os::fd::{AsRawFd, RawFd},
     ptr, slice,
     sync::atomic::{self, AtomicPtr, Ordering},
 };

+ 3 - 3
aya/src/maps/perf/perf_event_array.rs

@@ -4,7 +4,7 @@
 use std::{
     borrow::{Borrow, BorrowMut},
     ops::Deref,
-    os::unix::io::{AsRawFd, RawFd},
+    os::fd::{AsRawFd, RawFd},
     sync::Arc,
 };
 
@@ -64,7 +64,7 @@ impl<T: BorrowMut<MapData> + Borrow<MapData>> AsRawFd for PerfEventArrayBuffer<T
 /// A map that can be used to receive events from eBPF programs using the linux [`perf`] API.
 ///
 /// Each element of a [`PerfEventArray`] is a separate [`PerfEventArrayBuffer`] which can be used
-/// to receive events sent by eBPF programs that use `bpf_perf_event_output()`.    
+/// to receive events sent by eBPF programs that use `bpf_perf_event_output()`.
 ///
 /// To receive events you need to:
 /// * call [`PerfEventArray::open`]
@@ -138,7 +138,7 @@ impl<T: BorrowMut<MapData> + Borrow<MapData>> AsRawFd for PerfEventArrayBuffer<T
 ///
 /// In the example above the implementation of `poll_buffers()` and `poll.poll_readable()` is not
 /// given. [`PerfEventArrayBuffer`] implements the [`AsRawFd`] trait, so you can implement polling
-/// using any crate that can poll file descriptors, like [epoll], [mio] etc.  
+/// using any crate that can poll file descriptors, like [epoll], [mio] etc.
 ///
 /// Perf buffers are internally implemented as ring buffers. If your eBPF programs produce large
 /// amounts of data, in order not to lose events you might want to process each

+ 1 - 1
aya/src/maps/sock/mod.rs

@@ -5,7 +5,7 @@ mod sock_map;
 pub use sock_hash::SockHash;
 pub use sock_map::SockMap;
 
-use std::os::unix::io::{AsRawFd, RawFd};
+use std::os::fd::{AsRawFd, RawFd};
 
 /// A socket map file descriptor.
 #[derive(Copy, Clone)]

+ 2 - 2
aya/src/maps/sock/sock_hash.rs

@@ -1,7 +1,7 @@
 use std::{
     borrow::{Borrow, BorrowMut},
     marker::PhantomData,
-    os::unix::io::{AsRawFd, RawFd},
+    os::fd::{AsRawFd, RawFd},
 };
 
 use crate::{
@@ -42,7 +42,7 @@ use crate::{
 /// # let mut bpf = aya::Bpf::load(&[])?;
 /// use std::io::Write;
 /// use std::net::TcpStream;
-/// use std::os::unix::io::AsRawFd;
+/// use std::os::fd::AsRawFd;
 /// use aya::maps::SockHash;
 /// use aya::programs::SkMsg;
 ///

+ 1 - 1
aya/src/programs/links.rs

@@ -354,7 +354,7 @@ pub enum LinkError {
 #[cfg(test)]
 mod tests {
     use assert_matches::assert_matches;
-    use std::{cell::RefCell, fs::File, mem, os::unix::io::AsRawFd, rc::Rc};
+    use std::{cell::RefCell, fs::File, mem, os::fd::AsRawFd, rc::Rc};
     use tempfile::tempdir;
 
     use crate::{programs::ProgramError, sys::override_syscall};

+ 5 - 4
aya/src/programs/mod.rs

@@ -69,8 +69,9 @@ use libc::ENOSPC;
 use std::{
     ffi::CString,
     io,
-    os::fd::{AsRawFd, IntoRawFd as _, RawFd},
+    os::fd::{AsFd, AsRawFd, IntoRawFd as _, OwnedFd, RawFd},
     path::{Path, PathBuf},
+    sync::Arc,
 };
 use thiserror::Error;
 
@@ -413,7 +414,7 @@ pub(crate) struct ProgramData<T: Link> {
     pub(crate) attach_btf_obj_fd: Option<u32>,
     pub(crate) attach_btf_id: Option<u32>,
     pub(crate) attach_prog_fd: Option<RawFd>,
-    pub(crate) btf_fd: Option<RawFd>,
+    pub(crate) btf_fd: Option<Arc<OwnedFd>>,
     pub(crate) verifier_log_level: VerifierLogLevel,
     pub(crate) path: Option<PathBuf>,
     pub(crate) flags: u32,
@@ -423,7 +424,7 @@ impl<T: Link> ProgramData<T> {
     pub(crate) fn new(
         name: Option<String>,
         obj: (obj::Program, obj::Function),
-        btf_fd: Option<RawFd>,
+        btf_fd: Option<Arc<OwnedFd>>,
         verifier_log_level: VerifierLogLevel,
     ) -> ProgramData<T> {
         ProgramData {
@@ -613,7 +614,7 @@ fn load_program<T: Link>(
         license,
         kernel_version: target_kernel_version,
         expected_attach_type: *expected_attach_type,
-        prog_btf_fd: *btf_fd,
+        prog_btf_fd: btf_fd.as_ref().map(|f| f.as_fd()),
         attach_btf_obj_fd: *attach_btf_obj_fd,
         attach_btf_id: *attach_btf_id,
         attach_prog_fd: *attach_prog_fd,

+ 1 - 1
aya/src/programs/perf_attach.rs

@@ -1,6 +1,6 @@
 //! Perf attach links.
 use libc::close;
-use std::os::unix::io::RawFd;
+use std::os::fd::RawFd;
 
 use crate::{
     generated::bpf_attach_type::BPF_PERF_EVENT,

+ 2 - 2
aya/src/programs/sk_msg.rs

@@ -1,6 +1,6 @@
 //! Skmsg programs.
 
-use std::os::unix::io::AsRawFd;
+use std::os::fd::AsRawFd;
 
 use crate::{
     generated::{bpf_attach_type::BPF_SK_MSG_VERDICT, bpf_prog_type::BPF_PROG_TYPE_SK_MSG},
@@ -39,7 +39,7 @@ use crate::{
 /// # let mut bpf = aya::Bpf::load(&[])?;
 /// use std::io::Write;
 /// use std::net::TcpStream;
-/// use std::os::unix::io::AsRawFd;
+/// use std::os::fd::AsRawFd;
 /// use aya::maps::SockHash;
 /// use aya::programs::SkMsg;
 ///

+ 1 - 1
aya/src/programs/sk_skb.rs

@@ -1,6 +1,6 @@
 //! Skskb programs.
 
-use std::{os::unix::io::AsRawFd, path::Path};
+use std::{os::fd::AsRawFd, path::Path};
 
 use crate::{
     generated::{

+ 1 - 1
aya/src/programs/sock_ops.rs

@@ -1,5 +1,5 @@
 //! Socket option programs.
-use std::os::unix::io::AsRawFd;
+use std::os::fd::AsRawFd;
 
 use crate::{
     generated::{bpf_attach_type::BPF_CGROUP_SOCK_OPS, bpf_prog_type::BPF_PROG_TYPE_SOCK_OPS},

+ 1 - 1
aya/src/programs/socket_filter.rs

@@ -48,7 +48,7 @@ pub enum SocketFilterError {
 /// # }
 /// # let mut bpf = aya::Bpf::load(&[])?;
 /// use std::net::TcpStream;
-/// use std::os::unix::io::AsRawFd;
+/// use std::os::fd::AsRawFd;
 /// use aya::programs::SocketFilter;
 ///
 /// let mut client = TcpStream::connect("127.0.0.1:1234")?;

+ 1 - 1
aya/src/programs/utils.rs

@@ -1,5 +1,5 @@
 //! Common functions shared between multiple eBPF program types.
-use std::{ffi::CStr, io, os::unix::io::RawFd, path::Path};
+use std::{ffi::CStr, io, os::fd::RawFd, path::Path};
 
 use crate::{
     programs::{FdLink, Link, ProgramData, ProgramError},

+ 1 - 1
aya/src/programs/xdp.rs

@@ -3,7 +3,7 @@
 use crate::util::KernelVersion;
 use bitflags;
 use libc::if_nametoindex;
-use std::{convert::TryFrom, ffi::CString, hash::Hash, io, mem, os::unix::io::RawFd};
+use std::{convert::TryFrom, ffi::CString, hash::Hash, io, mem, os::fd::RawFd};
 use thiserror::Error;
 
 use crate::{

+ 45 - 42
aya/src/sys/bpf.rs

@@ -3,7 +3,7 @@ use std::{
     ffi::{CStr, CString},
     io,
     mem::{self, MaybeUninit},
-    os::fd::{FromRawFd as _, OwnedFd, RawFd},
+    os::fd::{AsRawFd, BorrowedFd, FromRawFd as _, OwnedFd, RawFd},
     slice,
 };
 
@@ -35,9 +35,9 @@ use crate::{
 pub(crate) fn bpf_create_map(
     name: &CStr,
     def: &obj::Map,
-    btf_fd: Option<RawFd>,
+    btf_fd: Option<BorrowedFd<'_>>,
     kernel_version: KernelVersion,
-) -> SysResult {
+) -> SysResult<c_long> {
     let mut attr = unsafe { mem::zeroed::<bpf_attr>() };
 
     let u = unsafe { &mut attr.__bindgen_anon_1 };
@@ -75,7 +75,7 @@ pub(crate) fn bpf_create_map(
             _ => {
                 u.btf_key_type_id = m.def.btf_key_type_id;
                 u.btf_value_type_id = m.def.btf_value_type_id;
-                u.btf_fd = btf_fd.unwrap_or_default() as u32;
+                u.btf_fd = btf_fd.map(|fd| fd.as_raw_fd()).unwrap_or_default() as u32;
             }
         }
     }
@@ -93,7 +93,7 @@ pub(crate) fn bpf_create_map(
     sys_bpf(bpf_cmd::BPF_MAP_CREATE, &attr)
 }
 
-pub(crate) fn bpf_pin_object(fd: RawFd, path: &CStr) -> SysResult {
+pub(crate) fn bpf_pin_object(fd: RawFd, path: &CStr) -> SysResult<c_long> {
     let mut attr = unsafe { mem::zeroed::<bpf_attr>() };
     let u = unsafe { &mut attr.__bindgen_anon_4 };
     u.bpf_fd = fd as u32;
@@ -101,7 +101,7 @@ pub(crate) fn bpf_pin_object(fd: RawFd, path: &CStr) -> SysResult {
     sys_bpf(bpf_cmd::BPF_OBJ_PIN, &attr)
 }
 
-pub(crate) fn bpf_get_object(path: &CStr) -> SysResult {
+pub(crate) fn bpf_get_object(path: &CStr) -> SysResult<c_long> {
     let mut attr = unsafe { mem::zeroed::<bpf_attr>() };
     let u = unsafe { &mut attr.__bindgen_anon_4 };
     u.pathname = path.as_ptr() as u64;
@@ -115,7 +115,7 @@ pub(crate) struct BpfLoadProgramAttrs<'a> {
     pub(crate) license: &'a CStr,
     pub(crate) kernel_version: u32,
     pub(crate) expected_attach_type: Option<bpf_attach_type>,
-    pub(crate) prog_btf_fd: Option<RawFd>,
+    pub(crate) prog_btf_fd: Option<BorrowedFd<'a>>,
     pub(crate) attach_btf_obj_fd: Option<u32>,
     pub(crate) attach_btf_id: Option<u32>,
     pub(crate) attach_prog_fd: Option<RawFd>,
@@ -130,7 +130,7 @@ pub(crate) fn bpf_load_program(
     aya_attr: &BpfLoadProgramAttrs,
     log_buf: &mut [u8],
     verifier_log_level: VerifierLogLevel,
-) -> SysResult {
+) -> SysResult<c_long> {
     let mut attr = unsafe { mem::zeroed::<bpf_attr>() };
 
     let u = unsafe { &mut attr.__bindgen_anon_3 };
@@ -161,7 +161,7 @@ pub(crate) fn bpf_load_program(
     let func_info_buf = aya_attr.func_info.func_info_bytes();
 
     if let Some(btf_fd) = aya_attr.prog_btf_fd {
-        u.prog_btf_fd = btf_fd as u32;
+        u.prog_btf_fd = btf_fd.as_raw_fd() as u32;
         if aya_attr.line_info_rec_size > 0 {
             u.line_info = line_info_buf.as_ptr() as *const _ as u64;
             u.line_info_cnt = aya_attr.line_info.len() as u32;
@@ -272,7 +272,7 @@ pub(crate) fn bpf_map_update_elem<K: Pod, V: Pod>(
     key: Option<&K>,
     value: &V,
     flags: u64,
-) -> SysResult {
+) -> SysResult<c_long> {
     let mut attr = unsafe { mem::zeroed::<bpf_attr>() };
 
     let u = unsafe { &mut attr.__bindgen_anon_2 };
@@ -286,7 +286,7 @@ pub(crate) fn bpf_map_update_elem<K: Pod, V: Pod>(
     sys_bpf(bpf_cmd::BPF_MAP_UPDATE_ELEM, &attr)
 }
 
-pub(crate) fn bpf_map_push_elem<V: Pod>(fd: RawFd, value: &V, flags: u64) -> SysResult {
+pub(crate) fn bpf_map_push_elem<V: Pod>(fd: RawFd, value: &V, flags: u64) -> SysResult<c_long> {
     let mut attr = unsafe { mem::zeroed::<bpf_attr>() };
 
     let u = unsafe { &mut attr.__bindgen_anon_2 };
@@ -302,7 +302,7 @@ pub(crate) fn bpf_map_update_elem_ptr<K, V>(
     key: *const K,
     value: *mut V,
     flags: u64,
-) -> SysResult {
+) -> SysResult<c_long> {
     let mut attr = unsafe { mem::zeroed::<bpf_attr>() };
 
     let u = unsafe { &mut attr.__bindgen_anon_2 };
@@ -319,12 +319,12 @@ pub(crate) fn bpf_map_update_elem_per_cpu<K: Pod, V: Pod>(
     key: &K,
     values: &PerCpuValues<V>,
     flags: u64,
-) -> SysResult {
+) -> SysResult<c_long> {
     let mut mem = values.build_kernel_mem().map_err(|e| (-1, e))?;
     bpf_map_update_elem_ptr(fd, key, mem.as_mut_ptr(), flags)
 }
 
-pub(crate) fn bpf_map_delete_elem<K: Pod>(fd: RawFd, key: &K) -> SysResult {
+pub(crate) fn bpf_map_delete_elem<K: Pod>(fd: RawFd, key: &K) -> SysResult<c_long> {
     let mut attr = unsafe { mem::zeroed::<bpf_attr>() };
 
     let u = unsafe { &mut attr.__bindgen_anon_2 };
@@ -356,7 +356,7 @@ pub(crate) fn bpf_map_get_next_key<K: Pod>(
 }
 
 // since kernel 5.2
-pub(crate) fn bpf_map_freeze(fd: RawFd) -> SysResult {
+pub(crate) fn bpf_map_freeze(fd: RawFd) -> SysResult<c_long> {
     let mut attr = unsafe { mem::zeroed::<bpf_attr>() };
     let u = unsafe { &mut attr.__bindgen_anon_2 };
     u.map_fd = fd as u32;
@@ -370,7 +370,7 @@ pub(crate) fn bpf_link_create(
     attach_type: bpf_attach_type,
     btf_id: Option<u32>,
     flags: u32,
-) -> SysResult {
+) -> SysResult<c_long> {
     let mut attr = unsafe { mem::zeroed::<bpf_attr>() };
 
     attr.link_create.__bindgen_anon_1.prog_fd = prog_fd as u32;
@@ -390,7 +390,7 @@ pub(crate) fn bpf_link_update(
     new_prog_fd: RawFd,
     old_prog_fd: Option<RawFd>,
     flags: u32,
-) -> SysResult {
+) -> SysResult<c_long> {
     let mut attr = unsafe { mem::zeroed::<bpf_attr>() };
 
     attr.link_update.link_fd = link_fd as u32;
@@ -409,7 +409,7 @@ pub(crate) fn bpf_prog_attach(
     prog_fd: RawFd,
     target_fd: RawFd,
     attach_type: bpf_attach_type,
-) -> SysResult {
+) -> SysResult<c_long> {
     let mut attr = unsafe { mem::zeroed::<bpf_attr>() };
 
     attr.__bindgen_anon_5.attach_bpf_fd = prog_fd as u32;
@@ -423,7 +423,7 @@ pub(crate) fn bpf_prog_detach(
     prog_fd: RawFd,
     map_fd: RawFd,
     attach_type: bpf_attach_type,
-) -> SysResult {
+) -> SysResult<c_long> {
     let mut attr = unsafe { mem::zeroed::<bpf_attr>() };
 
     attr.__bindgen_anon_5.attach_bpf_fd = prog_fd as u32;
@@ -440,7 +440,7 @@ pub(crate) fn bpf_prog_query(
     attach_flags: Option<&mut u32>,
     prog_ids: &mut [u32],
     prog_cnt: &mut u32,
-) -> SysResult {
+) -> SysResult<c_long> {
     let mut attr = unsafe { mem::zeroed::<bpf_attr>() };
 
     attr.query.target_fd = target_fd as u32;
@@ -464,21 +464,8 @@ pub(crate) fn bpf_prog_get_fd_by_id(prog_id: u32) -> Result<OwnedFd, io::Error>
     let mut attr = unsafe { mem::zeroed::<bpf_attr>() };
 
     attr.__bindgen_anon_6.__bindgen_anon_1.prog_id = prog_id;
-
-    match sys_bpf(bpf_cmd::BPF_PROG_GET_FD_BY_ID, &attr) {
-        Ok(v) => {
-            let v = v.try_into().map_err(|_err| {
-                // _err is std::num::TryFromIntError or std::convert::Infallible depending on
-                // target, so we can't ascribe.
-                io::Error::new(
-                    io::ErrorKind::InvalidData,
-                    format!("bpf_prog_get_fd_by_id: invalid fd returned: {}", v),
-                )
-            })?;
-            Ok(unsafe { OwnedFd::from_raw_fd(v) })
-        }
-        Err((_, err)) => Err(err),
-    }
+    // SAFETY: BPF_PROG_GET_FD_BY_ID returns a new file descriptor.
+    unsafe { fd_sys_bpf(bpf_cmd::BPF_PROG_GET_FD_BY_ID, &attr).map_err(|(_, e)| e) }
 }
 
 pub(crate) fn bpf_prog_get_info_by_fd(prog_fd: RawFd) -> Result<bpf_prog_info, io::Error> {
@@ -545,7 +532,7 @@ pub(crate) fn btf_obj_get_info_by_fd(
     }
 }
 
-pub(crate) fn bpf_raw_tracepoint_open(name: Option<&CStr>, prog_fd: RawFd) -> SysResult {
+pub(crate) fn bpf_raw_tracepoint_open(name: Option<&CStr>, prog_fd: RawFd) -> SysResult<c_long> {
     let mut attr = unsafe { mem::zeroed::<bpf_attr>() };
 
     attr.raw_tracepoint.name = match name {
@@ -561,7 +548,7 @@ pub(crate) fn bpf_load_btf(
     raw_btf: &[u8],
     log_buf: &mut [u8],
     verifier_log_level: VerifierLogLevel,
-) -> SysResult {
+) -> SysResult<OwnedFd> {
     let mut attr = unsafe { mem::zeroed::<bpf_attr>() };
     let u = unsafe { &mut attr.__bindgen_anon_7 };
     u.btf = raw_btf.as_ptr() as *const _ as u64;
@@ -571,7 +558,23 @@ pub(crate) fn bpf_load_btf(
         u.btf_log_buf = log_buf.as_mut_ptr() as u64;
         u.btf_log_size = log_buf.len() as u32;
     }
-    sys_bpf(bpf_cmd::BPF_BTF_LOAD, &attr)
+    // SAFETY: `BPF_BTF_LOAD` returns a newly created fd.
+    unsafe { fd_sys_bpf(bpf_cmd::BPF_BTF_LOAD, &attr) }
+}
+
+// SAFETY: only use for bpf_cmd that return a new file descriptor on success.
+unsafe fn fd_sys_bpf(cmd: bpf_cmd, attr: &bpf_attr) -> SysResult<OwnedFd> {
+    let fd = sys_bpf(cmd, attr)?;
+    let fd = fd.try_into().map_err(|_| {
+        (
+            fd,
+            io::Error::new(
+                io::ErrorKind::InvalidData,
+                format!("{cmd:?}: invalid fd returned: {fd}"),
+            ),
+        )
+    })?;
+    Ok(OwnedFd::from_raw_fd(fd))
 }
 
 pub(crate) fn bpf_btf_get_fd_by_id(id: u32) -> Result<RawFd, io::Error> {
@@ -987,7 +990,7 @@ pub(crate) fn is_btf_type_tag_supported() -> bool {
     }
 }
 
-pub fn sys_bpf(cmd: bpf_cmd, attr: &bpf_attr) -> SysResult {
+pub fn sys_bpf(cmd: bpf_cmd, attr: &bpf_attr) -> SysResult<c_long> {
     syscall(Syscall::Bpf { cmd, attr })
 }
 
@@ -1002,10 +1005,10 @@ pub(crate) fn bpf_prog_get_next_id(id: u32) -> Result<Option<u32>, (c_long, io::
     }
 }
 
-pub(crate) fn retry_with_verifier_logs(
+pub(crate) fn retry_with_verifier_logs<T>(
     max_retries: usize,
-    f: impl Fn(&mut [u8]) -> SysResult,
-) -> (SysResult, String) {
+    f: impl Fn(&mut [u8]) -> SysResult<T>,
+) -> (SysResult<T>, String) {
     const MIN_LOG_BUF_SIZE: usize = 1024 * 10;
     const MAX_LOG_BUF_SIZE: usize = (std::u32::MAX >> 8) as usize;
 

+ 4 - 4
aya/src/sys/fake.rs

@@ -1,10 +1,10 @@
-use std::{cell::RefCell, io, ptr};
+use std::{cell::RefCell, ffi::c_long, io, ptr};
 
 use libc::c_void;
 
 use super::{SysResult, Syscall};
 
-type SyscallFn = unsafe fn(Syscall) -> SysResult;
+type SyscallFn = unsafe fn(Syscall) -> SysResult<c_long>;
 
 #[cfg(test)]
 thread_local! {
@@ -13,11 +13,11 @@ thread_local! {
 }
 
 #[cfg(test)]
-unsafe fn test_syscall(_call: Syscall) -> SysResult {
+unsafe fn test_syscall(_call: Syscall) -> SysResult<c_long> {
     Err((-1, io::Error::from_raw_os_error(libc::EINVAL)))
 }
 
 #[cfg(test)]
-pub(crate) fn override_syscall(call: unsafe fn(Syscall) -> SysResult) {
+pub(crate) fn override_syscall(call: unsafe fn(Syscall) -> SysResult<c_long>) {
     TEST_SYSCALL.with(|test_impl| *test_impl.borrow_mut() = call);
 }

+ 2 - 2
aya/src/sys/mod.rs

@@ -17,7 +17,7 @@ pub(crate) use perf_event::*;
 
 use crate::generated::{bpf_attr, bpf_cmd, perf_event_attr};
 
-pub(crate) type SysResult = Result<c_long, (c_long, io::Error)>;
+pub(crate) type SysResult<T> = Result<T, (c_long, io::Error)>;
 
 pub(crate) enum Syscall<'a> {
     Bpf {
@@ -38,7 +38,7 @@ pub(crate) enum Syscall<'a> {
     },
 }
 
-fn syscall(call: Syscall) -> SysResult {
+fn syscall(call: Syscall) -> SysResult<c_long> {
     #[cfg(test)]
     return TEST_SYSCALL.with(|test_impl| unsafe { test_impl.borrow()(call) });
 

+ 1 - 1
aya/src/sys/netlink.rs

@@ -1,4 +1,4 @@
-use std::{collections::HashMap, ffi::CStr, io, mem, os::unix::io::RawFd, ptr, slice};
+use std::{collections::HashMap, ffi::CStr, io, mem, os::fd::RawFd, ptr, slice};
 use thiserror::Error;
 
 use libc::{

+ 9 - 6
aya/src/sys/perf_event.rs

@@ -1,4 +1,7 @@
-use std::{ffi::CString, mem};
+use std::{
+    ffi::{c_long, CString},
+    mem,
+};
 
 use libc::{c_int, pid_t};
 
@@ -22,7 +25,7 @@ pub(crate) fn perf_event_open(
     sample_frequency: Option<u64>,
     wakeup: bool,
     flags: u32,
-) -> SysResult {
+) -> SysResult<c_long> {
     let mut attr = unsafe { mem::zeroed::<perf_event_attr>() };
 
     attr.config = config;
@@ -48,7 +51,7 @@ pub(crate) fn perf_event_open(
     })
 }
 
-pub(crate) fn perf_event_open_bpf(cpu: c_int) -> SysResult {
+pub(crate) fn perf_event_open_bpf(cpu: c_int) -> SysResult<c_long> {
     perf_event_open(
         PERF_TYPE_SOFTWARE as u32,
         PERF_COUNT_SW_BPF_OUTPUT as u64,
@@ -67,7 +70,7 @@ pub(crate) fn perf_event_open_probe(
     name: &str,
     offset: u64,
     pid: Option<pid_t>,
-) -> SysResult {
+) -> SysResult<c_long> {
     let mut attr = unsafe { mem::zeroed::<perf_event_attr>() };
 
     if let Some(ret_bit) = ret_bit {
@@ -93,7 +96,7 @@ pub(crate) fn perf_event_open_probe(
     })
 }
 
-pub(crate) fn perf_event_open_trace_point(id: u32, pid: Option<pid_t>) -> SysResult {
+pub(crate) fn perf_event_open_trace_point(id: u32, pid: Option<pid_t>) -> SysResult<c_long> {
     let mut attr = unsafe { mem::zeroed::<perf_event_attr>() };
 
     attr.size = mem::size_of::<perf_event_attr>() as u32;
@@ -112,7 +115,7 @@ pub(crate) fn perf_event_open_trace_point(id: u32, pid: Option<pid_t>) -> SysRes
     })
 }
 
-pub(crate) fn perf_event_ioctl(fd: c_int, request: c_int, arg: c_int) -> SysResult {
+pub(crate) fn perf_event_ioctl(fd: c_int, request: c_int, arg: c_int) -> SysResult<c_long> {
     let call = Syscall::PerfEventIoctl { fd, request, arg };
     #[cfg(not(test))]
     return syscall(call);