Browse Source

aya: support loading a map by fd

This adds support to loading maps by fd similarly to the way programs
can be loaded by fd.
Adam Preuss 1 year ago
parent
commit
36420d9297
3 changed files with 58 additions and 2 deletions
  1. 42 2
      aya/src/maps/mod.rs
  2. 15 0
      aya/src/sys/bpf.rs
  3. 1 0
      xtask/public-api/aya.txt

+ 42 - 2
aya/src/maps/mod.rs

@@ -68,8 +68,9 @@ use crate::{
     obj::{self, parse_map_info, BpfSectionKind},
     pin::PinError,
     sys::{
-        bpf_create_map, bpf_get_object, bpf_map_freeze, bpf_map_get_info_by_fd,
-        bpf_map_get_next_key, bpf_map_update_elem_ptr, bpf_pin_object, SyscallError,
+        bpf_create_map, bpf_get_object, bpf_map_freeze, bpf_map_get_fd_by_id,
+        bpf_map_get_info_by_fd, bpf_map_get_next_key, bpf_map_update_elem_ptr, bpf_pin_object,
+        SyscallError,
     },
     util::{nr_cpus, KernelVersion},
     PinningType, Pod,
@@ -648,6 +649,13 @@ impl MapData {
         })
     }
 
+    /// Loads a map from a map id.
+    pub fn from_id(id: u32) -> Result<Self, MapError> {
+        bpf_map_get_fd_by_id(id)
+            .map_err(MapError::from)
+            .and_then(Self::from_fd)
+    }
+
     /// Loads a map from a file descriptor.
     ///
     /// If loading from a BPF Filesystem (bpffs) you should use [`Map::from_pin`](crate::maps::MapData::from_pin).
@@ -935,6 +943,38 @@ mod tests {
         })
     }
 
+    #[test]
+    fn test_from_map_id() {
+        override_syscall(|call| match call {
+            Syscall::Bpf {
+                cmd: bpf_cmd::BPF_MAP_GET_FD_BY_ID,
+                attr,
+            } => {
+                assert_eq!(
+                    unsafe { attr.__bindgen_anon_6.__bindgen_anon_1.map_id },
+                    1234
+                );
+                Ok(42)
+            }
+            Syscall::Bpf {
+                cmd: bpf_cmd::BPF_OBJ_GET_INFO_BY_FD,
+                attr,
+            } => {
+                assert_eq!(unsafe { attr.info.bpf_fd }, 42);
+                Ok(0)
+            }
+            _ => Err((-1, io::Error::from_raw_os_error(EFAULT))),
+        });
+
+        assert_matches!(
+            MapData::from_id(1234),
+            Ok(MapData {
+                obj: _,
+                fd,
+            }) => assert_eq!(fd.as_fd().as_raw_fd(), 42)
+        );
+    }
+
     #[test]
     fn test_create() {
         override_syscall(|call| match call {

+ 15 - 0
aya/src/sys/bpf.rs

@@ -550,6 +550,21 @@ pub(crate) fn bpf_prog_get_info_by_fd(
     })
 }
 
+pub(crate) fn bpf_map_get_fd_by_id(map_id: u32) -> Result<OwnedFd, SyscallError> {
+    let mut attr = unsafe { mem::zeroed::<bpf_attr>() };
+
+    attr.__bindgen_anon_6.__bindgen_anon_1.map_id = map_id;
+
+    // SAFETY: BPF_MAP_GET_FD_BY_ID returns a new file descriptor.
+    unsafe { fd_sys_bpf(bpf_cmd::BPF_MAP_GET_FD_BY_ID, &mut attr) }.map_err(|(code, io_error)| {
+        assert_eq!(code, -1);
+        SyscallError {
+            call: "bpf_map_get_fd_by_id",
+            io_error,
+        }
+    })
+}
+
 pub(crate) fn bpf_map_get_info_by_fd(fd: BorrowedFd<'_>) -> Result<bpf_map_info, SyscallError> {
     bpf_obj_get_info_by_fd(fd, |_| {})
 }

+ 1 - 0
xtask/public-api/aya.txt

@@ -1686,6 +1686,7 @@ impl aya::maps::MapData
 pub fn aya::maps::MapData::create(obj: aya_obj::maps::Map, name: &str, btf_fd: core::option::Option<std::os::fd::owned::BorrowedFd<'_>>) -> core::result::Result<Self, aya::maps::MapError>
 pub fn aya::maps::MapData::fd(&self) -> &aya::maps::MapFd
 pub fn aya::maps::MapData::from_fd(fd: std::os::fd::owned::OwnedFd) -> core::result::Result<Self, aya::maps::MapError>
+pub fn aya::maps::MapData::from_id(id: u32) -> core::result::Result<Self, aya::maps::MapError>
 pub fn aya::maps::MapData::from_pin<P: core::convert::AsRef<std::path::Path>>(path: P) -> core::result::Result<Self, aya::maps::MapError>
 pub fn aya::maps::MapData::pin<P: core::convert::AsRef<std::path::Path>>(&mut self, path: P) -> core::result::Result<(), aya::pin::PinError>
 impl core::fmt::Debug for aya::maps::MapData