From 0f4021ec89ef2dc5c28355ecfde4b2c53b4b6429 Mon Sep 17 00:00:00 2001 From: Dave Tucker Date: Mon, 18 Sep 2023 17:32:37 +0100 Subject: [PATCH 1/2] aya: Remove MapData::pinned BPF objects can be pinned multiple times, to multiple different places. Tracking whether or not a map is pinned in a bool is therefore not sufficient. We could track this in a HashSet, but there is really no reason to track it at all. Signed-off-by: Dave Tucker --- aya/src/maps/mod.rs | 45 +++++++++++----------------------------- aya/src/pin.rs | 6 ------ xtask/public-api/aya.txt | 3 --- 3 files changed, 12 insertions(+), 42 deletions(-) diff --git a/aya/src/maps/mod.rs b/aya/src/maps/mod.rs index 163ce127f..6331e3a4f 100644 --- a/aya/src/maps/mod.rs +++ b/aya/src/maps/mod.rs @@ -409,8 +409,6 @@ pub(crate) fn check_v_size(map: &MapData) -> Result<(), MapError> { pub struct MapData { obj: obj::Map, fd: MapFd, - /// Indicates if this map has been pinned to bpffs - pub pinned: bool, } impl MapData { @@ -439,11 +437,7 @@ impl MapData { } })?; let fd = MapFd(fd); - Ok(Self { - obj, - fd, - pinned: false, - }) + Ok(Self { obj, fd }) } pub(crate) fn create_pinned>( @@ -471,11 +465,7 @@ impl MapData { }) { Ok(fd) => { let fd = MapFd(fd); - Ok(Self { - obj, - fd, - pinned: false, - }) + Ok(Self { obj, fd }) } Err(_) => { let mut map = Self::create(obj, name, btf_fd)?; @@ -489,7 +479,7 @@ impl MapData { } pub(crate) fn finalize(&mut self) -> Result<(), MapError> { - let Self { obj, fd, pinned: _ } = self; + let Self { obj, fd } = self; if !obj.data().is_empty() && obj.section_kind() != BpfSectionKind::Bss { bpf_map_update_elem_ptr(fd.as_fd(), &0 as *const _, obj.data_mut().as_mut_ptr(), 0) .map_err(|(_, io_error)| SyscallError { @@ -534,7 +524,6 @@ impl MapData { Ok(Self { obj: parse_map_info(info, PinningType::ByName), fd, - pinned: true, }) } @@ -550,44 +539,35 @@ impl MapData { Ok(Self { obj: parse_map_info(info, PinningType::None), fd, - pinned: false, }) } pub(crate) fn pin>(&mut self, name: &str, path: P) -> Result<(), PinError> { use std::os::unix::ffi::OsStrExt as _; - let Self { fd, pinned, obj: _ } = self; - if *pinned { - return Err(PinError::AlreadyPinned { name: name.into() }); - } + let Self { fd, obj: _ } = self; let path = path.as_ref().join(name); - let path_string = CString::new(path.as_os_str().as_bytes()) - .map_err(|error| PinError::InvalidPinPath { path, error })?; + let path_string = CString::new(path.as_os_str().as_bytes()).map_err(|error| { + PinError::InvalidPinPath { + path: path.clone(), + error, + } + })?; bpf_pin_object(fd.as_fd(), &path_string).map_err(|(_, io_error)| SyscallError { call: "BPF_OBJ_PIN", io_error, })?; - *pinned = true; Ok(()) } /// Returns the file descriptor of the map. pub fn fd(&self) -> &MapFd { - let Self { - obj: _, - fd, - pinned: _, - } = self; + let Self { obj: _, fd } = self; fd } pub(crate) fn obj(&self) -> &obj::Map { - let Self { - obj, - fd: _, - pinned: _, - } = self; + let Self { obj, fd: _ } = self; obj } } @@ -825,7 +805,6 @@ mod tests { Ok(MapData { obj: _, fd, - pinned: false }) => assert_eq!(fd.as_fd().as_raw_fd(), 42) ); } diff --git a/aya/src/pin.rs b/aya/src/pin.rs index 743df95fc..43e197ff3 100644 --- a/aya/src/pin.rs +++ b/aya/src/pin.rs @@ -6,12 +6,6 @@ use thiserror::Error; /// An error ocurred working with a pinned BPF object. #[derive(Error, Debug)] pub enum PinError { - /// The object has already been pinned. - #[error("the BPF object `{name}` has already been pinned")] - AlreadyPinned { - /// Object name. - name: String, - }, /// The object FD is not known by Aya. #[error("the BPF object `{name}`'s FD is not known")] NoFd { diff --git a/xtask/public-api/aya.txt b/xtask/public-api/aya.txt index 3f6dfad6d..59711f673 100644 --- a/xtask/public-api/aya.txt +++ b/xtask/public-api/aya.txt @@ -1218,7 +1218,6 @@ pub fn aya::maps::lpm_trie::LpmTrie::borrow_mut(&mut self) -> &mut T impl core::convert::From for aya::maps::lpm_trie::LpmTrie pub fn aya::maps::lpm_trie::LpmTrie::from(t: T) -> T pub struct aya::maps::MapData -pub aya::maps::MapData::pinned: bool impl aya::maps::MapData pub fn aya::maps::MapData::create(obj: aya_obj::maps::Map, name: &str, btf_fd: core::option::Option>) -> core::result::Result pub fn aya::maps::MapData::fd(&self) -> &aya::maps::MapFd @@ -1738,8 +1737,6 @@ pub fn aya::maps::stack_trace::StackTraceMap::get(&self, index: &u32) -> core pub fn aya::maps::stack_trace::StackTraceMap::map(&self) -> &aya::maps::MapData pub mod aya::pin pub enum aya::pin::PinError -pub aya::pin::PinError::AlreadyPinned -pub aya::pin::PinError::AlreadyPinned::name: alloc::string::String pub aya::pin::PinError::InvalidPinPath pub aya::pin::PinError::InvalidPinPath::error: alloc::ffi::c_str::NulError pub aya::pin::PinError::InvalidPinPath::path: std::path::PathBuf From 938f979fe7a82f6d31c3b7e926682864c507e381 Mon Sep 17 00:00:00 2001 From: Dave Tucker Date: Tue, 19 Sep 2023 13:38:20 +0100 Subject: [PATCH 2/2] aya: Make MapData::pin pub This is to solve a use-case where a user (in this case bpfd) may want to: - MapData::from_pin to open a pinned map from bpffs - MapData::pin to pin that object into another bpffs Both operations should be easily accomplished without needing to cast a MapData into a concrete Map type - e.g aya::maps::HashMap. Signed-off-by: Dave Tucker --- aya/src/maps/mod.rs | 33 +++++++++++++++++++++++++++++---- xtask/public-api/aya.txt | 1 + 2 files changed, 30 insertions(+), 4 deletions(-) diff --git a/aya/src/maps/mod.rs b/aya/src/maps/mod.rs index 6331e3a4f..191c58834 100644 --- a/aya/src/maps/mod.rs +++ b/aya/src/maps/mod.rs @@ -469,7 +469,8 @@ impl MapData { } Err(_) => { let mut map = Self::create(obj, name, btf_fd)?; - map.pin(name, path).map_err(|error| MapError::PinError { + let path = path.join(name); + map.pin(&path).map_err(|error| MapError::PinError { name: Some(name.into()), error, })?; @@ -542,14 +543,38 @@ impl MapData { }) } - pub(crate) fn pin>(&mut self, name: &str, path: P) -> Result<(), PinError> { + /// Allows the map to be pinned to the provided path. + /// + /// Any directories in the the path provided should have been created by the caller. + /// The path must be on a BPF filesystem. + /// + /// # Errors + /// + /// Returns a [`PinError::SyscallError`] if the underlying syscall fails. + /// This may also happen if the path already exists, in which case the wrapped + /// [`std::io::Error`] kind will be [`std::io::ErrorKind::AlreadyExists`]. + /// Returns a [`PinError::InvalidPinPath`] if the path provided cannot be + /// converted to a [`CString`]. + /// + /// # Example + /// + /// ```no_run + /// # let mut bpf = aya::Bpf::load(&[])?; + /// # use aya::maps::MapData; + /// + /// let mut map = MapData::from_pin("/sys/fs/bpf/my_map")?; + /// map.pin("/sys/fs/bpf/my_map2")?; + /// + /// # Ok::<(), Box>(()) + /// ``` + pub fn pin>(&mut self, path: P) -> Result<(), PinError> { use std::os::unix::ffi::OsStrExt as _; let Self { fd, obj: _ } = self; - let path = path.as_ref().join(name); + let path = path.as_ref(); let path_string = CString::new(path.as_os_str().as_bytes()).map_err(|error| { PinError::InvalidPinPath { - path: path.clone(), + path: path.to_path_buf(), error, } })?; diff --git a/xtask/public-api/aya.txt b/xtask/public-api/aya.txt index 59711f673..1cf6eb5c7 100644 --- a/xtask/public-api/aya.txt +++ b/xtask/public-api/aya.txt @@ -1223,6 +1223,7 @@ pub fn aya::maps::MapData::create(obj: aya_obj::maps::Map, name: &str, btf_fd: c 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 pub fn aya::maps::MapData::from_pin>(path: P) -> core::result::Result +pub fn aya::maps::MapData::pin>(&mut self, path: P) -> core::result::Result<(), aya::pin::PinError> impl core::fmt::Debug for aya::maps::MapData pub fn aya::maps::MapData::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result impl core::marker::Send for aya::maps::MapData