Browse Source

aya: Update XDP maps implementations

Map impls changed since this was first written.

Fixes: 2b726c8 ("aya: Implement XDP Map Types")
Tuetuopay 1 year ago
parent
commit
ede3e91014

+ 4 - 0
aya/src/bpf.rs

@@ -707,6 +707,10 @@ fn parse_map(data: (String, MapData)) -> Result<(String, Map), BpfError> {
         BPF_MAP_TYPE_STACK => Map::Stack(map),
         BPF_MAP_TYPE_STACK_TRACE => Map::StackTraceMap(map),
         BPF_MAP_TYPE_QUEUE => Map::Queue(map),
+        BPF_MAP_TYPE_CPUMAP => Map::CpuMap(map),
+        BPF_MAP_TYPE_DEVMAP => Map::DevMap(map),
+        BPF_MAP_TYPE_DEVMAP_HASH => Map::DevMapHash(map),
+        BPF_MAP_TYPE_XSKMAP => Map::XskMap(map),
         m => {
             warn!("The map {name} is of type {:#?} which is currently unsupported in Aya, use `allow_unsupported_maps()` to load it anyways", m);
             Map::Unsupported(map)

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

@@ -97,7 +97,7 @@ pub use queue::Queue;
 pub use sock::{SockHash, SockMap};
 pub use stack::Stack;
 pub use stack_trace::StackTraceMap;
-pub use xdp::XskMap;
+pub use xdp::{CpuMap, DevMap, DevMapHash, XskMap};
 
 #[derive(Error, Debug)]
 /// Errors occuring from working with Maps
@@ -267,6 +267,14 @@ pub enum Map {
     StackTraceMap(MapData),
     /// A [`Queue`] map
     Queue(MapData),
+    /// A [`CpuMap`] map
+    CpuMap(MapData),
+    /// A [`DevMap`] map
+    DevMap(MapData),
+    /// A [`DevMapHash`] map
+    DevMapHash(MapData),
+    /// A [`XskMap`] map
+    XskMap(MapData),
     /// An unsupported map type
     Unsupported(MapData),
 }
@@ -290,6 +298,10 @@ impl Map {
             Self::Stack(map) => map.obj.map_type(),
             Self::StackTraceMap(map) => map.obj.map_type(),
             Self::Queue(map) => map.obj.map_type(),
+            Self::CpuMap(map) => map.obj.map_type(),
+            Self::DevMap(map) => map.obj.map_type(),
+            Self::DevMapHash(map) => map.obj.map_type(),
+            Self::XskMap(map) => map.obj.map_type(),
             Self::Unsupported(map) => map.obj.map_type(),
         }
     }
@@ -349,6 +361,10 @@ impl_try_from_map!(() {
     SockMap,
     PerfEventArray,
     StackTraceMap,
+    CpuMap,
+    DevMap,
+    DevMapHash,
+    XskMap,
 });
 
 #[cfg(any(feature = "async_tokio", feature = "async_std"))]

+ 51 - 60
aya/src/maps/xdp/cpu_map.rs

@@ -1,15 +1,10 @@
 //! An array of available CPUs.
 
-use std::{
-    convert::TryFrom,
-    mem,
-    ops::{Deref, DerefMut},
-};
+use std::borrow::{Borrow, BorrowMut};
 
 use crate::{
-    generated::bpf_map_type::BPF_MAP_TYPE_CPUMAP,
-    maps::{Map, MapError, MapRef, MapRefMut},
-    sys::bpf_map_update_elem,
+    maps::{check_bounds, check_kv_size, IterableMap, MapData, MapError},
+    sys::{bpf_map_lookup_elem, bpf_map_update_elem, SyscallError},
 };
 
 /// An array of available CPUs.
@@ -19,15 +14,18 @@ use crate::{
 ///
 /// # Minimum kernel version
 ///
-/// The minimum kernel version required to use this feature is 4.2.
+/// The minimum kernel version required to use this feature is 4.15.
 ///
 /// # Examples
 /// ```no_run
-/// # let bpf = aya::Bpf::load(&[])?;
+/// # let elf_bytes = &[];
 /// use aya::maps::xdp::CpuMap;
-/// use std::convert::{TryFrom, TryInto};
 ///
-/// let mut cpumap = CpuMap::try_from(bpf.map_mut("CPUS")?)?;
+/// let mut bpf = aya::BpfLoader::new()
+///     .set_max_entries("CPUS", aya::util::nr_cpus().unwrap() as u32)
+///     .load(elf_bytes)
+///     .unwrap();
+/// let mut cpumap = CpuMap::try_from(bpf.map_mut("CPUS").unwrap())?;
 /// let flags = 0;
 /// let queue_size = 2048;
 /// for i in 0u32..8u32 {
@@ -37,52 +35,51 @@ use crate::{
 /// # Ok::<(), aya::BpfError>(())
 /// ```
 #[doc(alias = "BPF_MAP_TYPE_CPUMAP")]
-pub struct CpuMap<T: Deref<Target = Map>> {
+pub struct CpuMap<T> {
     inner: T,
 }
 
-impl<T: Deref<Target = Map>> CpuMap<T> {
-    fn new(map: T) -> Result<CpuMap<T>, MapError> {
-        let map_type = map.obj.def.map_type;
-        if map_type != BPF_MAP_TYPE_CPUMAP as u32 {
-            return Err(MapError::InvalidMapType {
-                map_type: map_type as u32,
-            });
-        }
-        let expected = mem::size_of::<u32>();
-        let size = map.obj.def.key_size as usize;
-        if size != expected {
-            return Err(MapError::InvalidKeySize { size, expected });
-        }
-
-        let expected = mem::size_of::<u32>();
-        let size = map.obj.def.value_size as usize;
-        if size != expected {
-            return Err(MapError::InvalidValueSize { size, expected });
-        }
-        let _fd = map.fd_or_err()?;
+impl<T: Borrow<MapData>> CpuMap<T> {
+    pub(crate) fn new(map: T) -> Result<Self, MapError> {
+        let data = map.borrow();
+        check_kv_size::<u32, u32>(data)?;
 
-        Ok(CpuMap { inner: map })
+        Ok(Self { inner: map })
     }
 
     /// Returns the number of elements in the array.
     ///
     /// This corresponds to the value of `bpf_map_def::max_entries` on the eBPF side.
     pub fn len(&self) -> u32 {
-        self.inner.obj.def.max_entries
+        self.inner.borrow().obj.max_entries()
     }
 
-    fn check_bounds(&self, index: u32) -> Result<(), MapError> {
-        let max_entries = self.inner.obj.def.max_entries;
-        if index >= self.inner.obj.def.max_entries {
-            Err(MapError::OutOfBounds { index, max_entries })
-        } else {
-            Ok(())
-        }
+    /// Returns the value stored at the given index.
+    ///
+    /// # Errors
+    ///
+    /// Returns [`MapError::OutOfBounds`] if `index` is out of bounds, [`MapError::SyscallError`]
+    /// if `bpf_map_lookup_elem` fails.
+    pub fn get(&self, index: u32, flags: u64) -> Result<u32, MapError> {
+        let data = self.inner.borrow();
+        check_bounds(data, index)?;
+        let fd = data.fd().as_fd();
+
+        let value =
+            bpf_map_lookup_elem(fd, &index, flags).map_err(|(_, io_error)| SyscallError {
+                call: "bpf_map_lookup_elem",
+                io_error,
+            })?;
+        value.ok_or(MapError::KeyNotFound)
+    }
+
+    /// An iterator over the elements of the map.
+    pub fn iter(&self) -> impl Iterator<Item = Result<u32, MapError>> + '_ {
+        (0..self.len()).map(move |i| self.get(i, 0))
     }
 }
 
-impl<T: Deref<Target = Map> + DerefMut<Target = Map>> CpuMap<T> {
+impl<T: BorrowMut<MapData>> CpuMap<T> {
     /// Sets the value of the element at the given index.
     ///
     /// # Errors
@@ -90,12 +87,12 @@ impl<T: Deref<Target = Map> + DerefMut<Target = Map>> CpuMap<T> {
     /// Returns [`MapError::OutOfBounds`] if `index` is out of bounds, [`MapError::SyscallError`]
     /// if `bpf_map_update_elem` fails.
     pub fn set(&mut self, index: u32, value: u32, flags: u64) -> Result<(), MapError> {
-        let fd = self.inner.fd_or_err()?;
-        self.check_bounds(index)?;
-        bpf_map_update_elem(fd, &index, &value, flags).map_err(|(code, io_error)| {
-            MapError::SyscallError {
-                call: "bpf_map_update_elem".to_owned(),
-                code,
+        let data = self.inner.borrow_mut();
+        check_bounds(data, index)?;
+        let fd = data.fd().as_fd();
+        bpf_map_update_elem(fd, Some(&index), &value, flags).map_err(|(_, io_error)| {
+            SyscallError {
+                call: "bpf_map_update_elem",
                 io_error,
             }
         })?;
@@ -103,18 +100,12 @@ impl<T: Deref<Target = Map> + DerefMut<Target = Map>> CpuMap<T> {
     }
 }
 
-impl TryFrom<MapRef> for CpuMap<MapRef> {
-    type Error = MapError;
-
-    fn try_from(a: MapRef) -> Result<CpuMap<MapRef>, MapError> {
-        CpuMap::new(a)
+impl<T: Borrow<MapData>> IterableMap<u32, u32> for CpuMap<T> {
+    fn map(&self) -> &MapData {
+        self.inner.borrow()
     }
-}
-
-impl TryFrom<MapRefMut> for CpuMap<MapRefMut> {
-    type Error = MapError;
 
-    fn try_from(a: MapRefMut) -> Result<CpuMap<MapRefMut>, MapError> {
-        CpuMap::new(a)
+    fn get(&self, key: &u32) -> Result<u32, MapError> {
+        self.get(*key, 0)
     }
 }

+ 50 - 62
aya/src/maps/xdp/dev_map.rs

@@ -1,15 +1,10 @@
 //! An array of network devices.
 
-use std::{
-    convert::TryFrom,
-    mem,
-    ops::{Deref, DerefMut},
-};
+use std::borrow::{Borrow, BorrowMut};
 
 use crate::{
-    generated::bpf_map_type::BPF_MAP_TYPE_DEVMAP,
-    maps::{Map, MapError, MapRef, MapRefMut},
-    sys::bpf_map_update_elem,
+    maps::{check_bounds, check_kv_size, IterableMap, MapData, MapError},
+    sys::{bpf_map_lookup_elem, bpf_map_update_elem, SyscallError},
 };
 
 /// An array of network devices.
@@ -19,67 +14,66 @@ use crate::{
 ///
 /// # Minimum kernel version
 ///
-/// The minimum kernel version required to use this feature is 4.2.
+/// The minimum kernel version required to use this feature is 4.14.
 ///
 /// # Examples
 /// ```no_run
-/// # let bpf = aya::Bpf::load(&[])?;
+/// # let mut bpf = aya::Bpf::load(&[])?;
 /// use aya::maps::xdp::DevMap;
-/// use std::convert::{TryFrom, TryInto};
 ///
-/// let mut devmap = DevMap::try_from(bpf.map_mut("IFACES")?)?;
-/// let ifindex = 32u32;
-/// devmap.set(ifindex, ifindex, 0);
+/// let mut devmap = DevMap::try_from(bpf.map_mut("IFACES").unwrap())?;
+/// let source = 32u32;
+/// let dest = 42u32;
+/// devmap.set(source, dest, 0);
 ///
 /// # Ok::<(), aya::BpfError>(())
 /// ```
 #[doc(alias = "BPF_MAP_TYPE_DEVMAP")]
-pub struct DevMap<T: Deref<Target = Map>> {
+pub struct DevMap<T> {
     inner: T,
 }
 
-impl<T: Deref<Target = Map>> DevMap<T> {
-    fn new(map: T) -> Result<DevMap<T>, MapError> {
-        let map_type = map.obj.def.map_type;
-        if map_type != BPF_MAP_TYPE_DEVMAP as u32 {
-            return Err(MapError::InvalidMapType {
-                map_type: map_type as u32,
-            });
-        }
-        let expected = mem::size_of::<u32>();
-        let size = map.obj.def.key_size as usize;
-        if size != expected {
-            return Err(MapError::InvalidKeySize { size, expected });
-        }
-
-        let expected = mem::size_of::<u32>();
-        let size = map.obj.def.value_size as usize;
-        if size != expected {
-            return Err(MapError::InvalidValueSize { size, expected });
-        }
-        let _fd = map.fd_or_err()?;
+impl<T: Borrow<MapData>> DevMap<T> {
+    pub(crate) fn new(map: T) -> Result<Self, MapError> {
+        let data = map.borrow();
+        check_kv_size::<u32, u32>(data)?;
 
-        Ok(DevMap { inner: map })
+        Ok(Self { inner: map })
     }
 
     /// Returns the number of elements in the array.
     ///
     /// This corresponds to the value of `bpf_map_def::max_entries` on the eBPF side.
     pub fn len(&self) -> u32 {
-        self.inner.obj.def.max_entries
+        self.inner.borrow().obj.max_entries()
     }
 
-    fn check_bounds(&self, index: u32) -> Result<(), MapError> {
-        let max_entries = self.inner.obj.def.max_entries;
-        if index >= self.inner.obj.def.max_entries {
-            Err(MapError::OutOfBounds { index, max_entries })
-        } else {
-            Ok(())
-        }
+    /// Returns the value stored at the given index.
+    ///
+    /// # Errors
+    ///
+    /// Returns [`MapError::OutOfBounds`] if `index` is out of bounds, [`MapError::SyscallError`]
+    /// if `bpf_map_lookup_elem` fails.
+    pub fn get(&self, index: u32, flags: u64) -> Result<u32, MapError> {
+        let data = self.inner.borrow();
+        check_bounds(data, index)?;
+        let fd = data.fd().as_fd();
+
+        let value =
+            bpf_map_lookup_elem(fd, &index, flags).map_err(|(_, io_error)| SyscallError {
+                call: "bpf_map_lookup_elem",
+                io_error,
+            })?;
+        value.ok_or(MapError::KeyNotFound)
+    }
+
+    /// An iterator over the elements of the array.
+    pub fn iter(&self) -> impl Iterator<Item = Result<u32, MapError>> + '_ {
+        (0..self.len()).map(move |i| self.get(i, 0))
     }
 }
 
-impl<T: Deref<Target = Map> + DerefMut<Target = Map>> DevMap<T> {
+impl<T: BorrowMut<MapData>> DevMap<T> {
     /// Sets the value of the element at the given index.
     ///
     /// # Errors
@@ -87,12 +81,12 @@ impl<T: Deref<Target = Map> + DerefMut<Target = Map>> DevMap<T> {
     /// Returns [`MapError::OutOfBounds`] if `index` is out of bounds, [`MapError::SyscallError`]
     /// if `bpf_map_update_elem` fails.
     pub fn set(&mut self, index: u32, value: u32, flags: u64) -> Result<(), MapError> {
-        let fd = self.inner.fd_or_err()?;
-        self.check_bounds(index)?;
-        bpf_map_update_elem(fd, &index, &value, flags).map_err(|(code, io_error)| {
-            MapError::SyscallError {
-                call: "bpf_map_update_elem".to_owned(),
-                code,
+        let data = self.inner.borrow_mut();
+        check_bounds(data, index)?;
+        let fd = data.fd().as_fd();
+        bpf_map_update_elem(fd, Some(&index), &value, flags).map_err(|(_, io_error)| {
+            SyscallError {
+                call: "bpf_map_update_elem",
                 io_error,
             }
         })?;
@@ -100,18 +94,12 @@ impl<T: Deref<Target = Map> + DerefMut<Target = Map>> DevMap<T> {
     }
 }
 
-impl TryFrom<MapRef> for DevMap<MapRef> {
-    type Error = MapError;
-
-    fn try_from(a: MapRef) -> Result<DevMap<MapRef>, MapError> {
-        DevMap::new(a)
+impl<T: Borrow<MapData>> IterableMap<u32, u32> for DevMap<T> {
+    fn map(&self) -> &MapData {
+        self.inner.borrow()
     }
-}
-
-impl TryFrom<MapRefMut> for DevMap<MapRefMut> {
-    type Error = MapError;
 
-    fn try_from(a: MapRefMut) -> Result<DevMap<MapRefMut>, MapError> {
-        DevMap::new(a)
+    fn get(&self, key: &u32) -> Result<u32, MapError> {
+        self.get(*key, 0)
     }
 }

+ 54 - 73
aya/src/maps/xdp/dev_map_hash.rs

@@ -1,118 +1,99 @@
-//! An array of network devices.
+//! An hashmap of network devices.
 
-use std::{
-    convert::TryFrom,
-    mem,
-    ops::{Deref, DerefMut},
-};
+use std::borrow::{Borrow, BorrowMut};
 
 use crate::{
-    generated::bpf_map_type::BPF_MAP_TYPE_DEVMAP_HASH,
-    maps::{Map, MapError, MapRef, MapRefMut},
-    sys::bpf_map_update_elem,
+    maps::{check_kv_size, hash_map, IterableMap, MapData, MapError, MapIter, MapKeys},
+    sys::{bpf_map_lookup_elem, SyscallError},
 };
 
-/// An array of network devices.
+/// An hashmap of network devices.
 ///
 /// XDP programs can use this map to redirect to other network
 /// devices.
 ///
 /// # Minimum kernel version
 ///
-/// The minimum kernel version required to use this feature is 4.2.
+/// The minimum kernel version required to use this feature is 5.4.
 ///
 /// # Examples
 /// ```no_run
-/// # let bpf = aya::Bpf::load(&[])?;
+/// # let mut bpf = aya::Bpf::load(&[])?;
 /// use aya::maps::xdp::DevMapHash;
-/// use std::convert::{TryFrom, TryInto};
 ///
-/// let mut devmap = DevMapHash::try_from(bpf.map_mut("IFACES")?)?;
+/// let mut devmap = DevMapHash::try_from(bpf.map_mut("IFACES").unwrap())?;
 /// let flags = 0;
 /// let ifindex = 32u32;
-/// devmap.set(ifindex, ifindex, flags);
+/// devmap.insert(ifindex, ifindex, flags);
 ///
 /// # Ok::<(), aya::BpfError>(())
 /// ```
 #[doc(alias = "BPF_MAP_TYPE_DEVMAP_HASH")]
-pub struct DevMapHash<T: Deref<Target = Map>> {
+pub struct DevMapHash<T> {
     inner: T,
 }
 
-impl<T: Deref<Target = Map>> DevMapHash<T> {
-    fn new(map: T) -> Result<DevMapHash<T>, MapError> {
-        let map_type = map.obj.def.map_type;
-        if map_type != BPF_MAP_TYPE_DEVMAP_HASH as u32 {
-            return Err(MapError::InvalidMapType {
-                map_type: map_type as u32,
-            });
-        }
-        let expected = mem::size_of::<u32>();
-        let size = map.obj.def.key_size as usize;
-        if size != expected {
-            return Err(MapError::InvalidKeySize { size, expected });
-        }
-
-        let expected = mem::size_of::<u32>();
-        let size = map.obj.def.value_size as usize;
-        if size != expected {
-            return Err(MapError::InvalidValueSize { size, expected });
-        }
-        let _fd = map.fd_or_err()?;
+impl<T: Borrow<MapData>> DevMapHash<T> {
+    pub(crate) fn new(map: T) -> Result<Self, MapError> {
+        let data = map.borrow();
+        check_kv_size::<u32, u32>(data)?;
 
-        Ok(DevMapHash { inner: map })
+        Ok(Self { inner: map })
     }
 
-    /// Returns the number of elements in the array.
+    /// Returns the value stored at the given index.
+    ///
+    /// # Errors
     ///
-    /// This corresponds to the value of `bpf_map_def::max_entries` on the eBPF side.
-    pub fn len(&self) -> u32 {
-        self.inner.obj.def.max_entries
+    /// Returns [`MapError::OutOfBounds`] if `index` is out of bounds, [`MapError::SyscallError`]
+    /// if `bpf_map_lookup_elem` fails.
+    pub fn get(&self, index: u32, flags: u64) -> Result<u32, MapError> {
+        let fd = self.inner.borrow().fd().as_fd();
+        let value =
+            bpf_map_lookup_elem(fd, &index, flags).map_err(|(_, io_error)| SyscallError {
+                call: "bpf_map_lookup_elem",
+                io_error,
+            })?;
+        value.ok_or(MapError::KeyNotFound)
+    }
+
+    /// An iterator over the elements of the devmap in arbitrary order.
+    pub fn iter(&self) -> MapIter<'_, u32, u32, Self> {
+        MapIter::new(self)
     }
 
-    fn check_bounds(&self, index: u32) -> Result<(), MapError> {
-        let max_entries = self.inner.obj.def.max_entries;
-        if index >= self.inner.obj.def.max_entries {
-            Err(MapError::OutOfBounds { index, max_entries })
-        } else {
-            Ok(())
-        }
+    /// An iterator visiting all keys in arbitrary order.
+    pub fn keys(&self) -> MapKeys<'_, u32> {
+        MapKeys::new(self.inner.borrow())
     }
 }
 
-impl<T: Deref<Target = Map> + DerefMut<Target = Map>> DevMapHash<T> {
-    /// Sets the value of the element at the given index.
+impl<T: BorrowMut<MapData>> DevMapHash<T> {
+    /// Inserts a value in the map.
     ///
     /// # Errors
     ///
-    /// Returns [`MapError::OutOfBounds`] if `index` is out of bounds, [`MapError::SyscallError`]
-    /// if `bpf_map_update_elem` fails.
-    pub fn set(&mut self, index: u32, value: u32, flags: u64) -> Result<(), MapError> {
-        let fd = self.inner.fd_or_err()?;
-        self.check_bounds(index)?;
-        bpf_map_update_elem(fd, &index, &value, flags).map_err(|(code, io_error)| {
-            MapError::SyscallError {
-                call: "bpf_map_update_elem".to_owned(),
-                code,
-                io_error,
-            }
-        })?;
-        Ok(())
+    /// Returns [`MapError::SyscallError`] if `bpf_map_update_elem` fails.
+    pub fn insert(&mut self, index: u32, value: u32, flags: u64) -> Result<(), MapError> {
+        hash_map::insert(self.inner.borrow_mut(), &index, &value, flags)
     }
-}
-
-impl TryFrom<MapRef> for DevMapHash<MapRef> {
-    type Error = MapError;
 
-    fn try_from(a: MapRef) -> Result<DevMapHash<MapRef>, MapError> {
-        DevMapHash::new(a)
+    /// Remove a value from the map.
+    ///
+    /// # Errors
+    ///
+    /// Returns [`MapError::SyscallError`] if `bpf_map_delete_elem` fails.
+    pub fn remove(&mut self, key: u32) -> Result<(), MapError> {
+        hash_map::remove(self.inner.borrow_mut(), &key)
     }
 }
 
-impl TryFrom<MapRefMut> for DevMapHash<MapRefMut> {
-    type Error = MapError;
+impl<T: Borrow<MapData>> IterableMap<u32, u32> for DevMapHash<T> {
+    fn map(&self) -> &MapData {
+        self.inner.borrow()
+    }
 
-    fn try_from(a: MapRefMut) -> Result<DevMapHash<MapRefMut>, MapError> {
-        DevMapHash::new(a)
+    fn get(&self, key: &u32) -> Result<u32, MapError> {
+        self.get(*key, 0)
     }
 }

+ 21 - 66
aya/src/maps/xdp/xsk_map.rs

@@ -1,16 +1,13 @@
 //! An array of AF_XDP sockets.
 
 use std::{
-    convert::TryFrom,
-    mem,
-    ops::{Deref, DerefMut},
-    os::unix::prelude::{AsRawFd, RawFd},
+    borrow::{Borrow, BorrowMut},
+    os::fd::{AsFd, AsRawFd, RawFd},
 };
 
 use crate::{
-    generated::bpf_map_type::BPF_MAP_TYPE_XSKMAP,
-    maps::{Map, MapError, MapRef, MapRefMut},
-    sys::bpf_map_update_elem,
+    maps::{check_bounds, check_kv_size, MapData, MapError},
+    sys::{bpf_map_update_elem, SyscallError},
 };
 
 /// An array of AF_XDP sockets.
@@ -20,67 +17,41 @@ use crate::{
 ///
 /// # Minimum kernel version
 ///
-/// The minimum kernel version required to use this feature is 4.2.
+/// The minimum kernel version required to use this feature is 4.18.
 ///
 /// # Examples
 /// ```no_run
-/// # let bpf = aya::Bpf::load(&[])?;
+/// # let mut bpf = aya::Bpf::load(&[])?;
 /// # let socket_fd = 1;
 /// use aya::maps::XskMap;
-/// use std::convert::{TryFrom, TryInto};
 ///
-/// let mut xskmap = XskMap::try_from(bpf.map_mut("SOCKETS")?)?;
+/// let mut xskmap = XskMap::try_from(bpf.map_mut("SOCKETS").unwrap())?;
 /// // socket_fd is the RawFd of an AF_XDP socket
 /// xskmap.set(0, socket_fd, 0);
 /// # Ok::<(), aya::BpfError>(())
 /// ```
 #[doc(alias = "BPF_MAP_TYPE_XSKMAP")]
-pub struct XskMap<T: Deref<Target = Map>> {
+pub struct XskMap<T> {
     inner: T,
 }
 
-impl<T: Deref<Target = Map>> XskMap<T> {
-    fn new(map: T) -> Result<XskMap<T>, MapError> {
-        let map_type = map.obj.def.map_type;
-        if map_type != BPF_MAP_TYPE_XSKMAP as u32 {
-            return Err(MapError::InvalidMapType {
-                map_type: map_type as u32,
-            });
-        }
-        let expected = mem::size_of::<u32>();
-        let size = map.obj.def.key_size as usize;
-        if size != expected {
-            return Err(MapError::InvalidKeySize { size, expected });
-        }
+impl<T: Borrow<MapData>> XskMap<T> {
+    pub(crate) fn new(map: T) -> Result<Self, MapError> {
+        let data = map.borrow();
+        check_kv_size::<u32, RawFd>(data)?;
 
-        let expected = mem::size_of::<RawFd>();
-        let size = map.obj.def.value_size as usize;
-        if size != expected {
-            return Err(MapError::InvalidValueSize { size, expected });
-        }
-        let _fd = map.fd_or_err()?;
-
-        Ok(XskMap { inner: map })
+        Ok(Self { inner: map })
     }
 
     /// Returns the number of elements in the array.
     ///
     /// This corresponds to the value of `bpf_map_def::max_entries` on the eBPF side.
     pub fn len(&self) -> u32 {
-        self.inner.obj.def.max_entries
-    }
-
-    fn check_bounds(&self, index: u32) -> Result<(), MapError> {
-        let max_entries = self.inner.obj.def.max_entries;
-        if index >= self.inner.obj.def.max_entries {
-            Err(MapError::OutOfBounds { index, max_entries })
-        } else {
-            Ok(())
-        }
+        self.inner.borrow().obj.max_entries()
     }
 }
 
-impl<T: Deref<Target = Map> + DerefMut<Target = Map>> XskMap<T> {
+impl<T: BorrowMut<MapData>> XskMap<T> {
     /// Sets the value of the element at the given index.
     ///
     /// # Errors
@@ -88,31 +59,15 @@ impl<T: Deref<Target = Map> + DerefMut<Target = Map>> XskMap<T> {
     /// Returns [`MapError::OutOfBounds`] if `index` is out of bounds, [`MapError::SyscallError`]
     /// if `bpf_map_update_elem` fails.
     pub fn set<V: AsRawFd>(&mut self, index: u32, value: V, flags: u64) -> Result<(), MapError> {
-        let fd = self.inner.fd_or_err()?;
-        self.check_bounds(index)?;
-        bpf_map_update_elem(fd, &index, &value.as_raw_fd(), flags).map_err(
-            |(code, io_error)| MapError::SyscallError {
-                call: "bpf_map_update_elem".to_owned(),
-                code,
+        let data = self.inner.borrow_mut();
+        check_bounds(data, index)?;
+        let fd = data.fd().as_fd();
+        bpf_map_update_elem(fd, Some(&index), &value.as_raw_fd(), flags).map_err(
+            |(_, io_error)| SyscallError {
+                call: "bpf_map_update_elem",
                 io_error,
             },
         )?;
         Ok(())
     }
 }
-
-impl TryFrom<MapRef> for XskMap<MapRef> {
-    type Error = MapError;
-
-    fn try_from(a: MapRef) -> Result<XskMap<MapRef>, MapError> {
-        XskMap::new(a)
-    }
-}
-
-impl TryFrom<MapRefMut> for XskMap<MapRefMut> {
-    type Error = MapError;
-
-    fn try_from(a: MapRefMut) -> Result<XskMap<MapRefMut>, MapError> {
-        XskMap::new(a)
-    }
-}