From e5df56727edbcd96662a1e5c2f61027a2f76fd9c Mon Sep 17 00:00:00 2001 From: Ershaad Basheer Date: Mon, 11 Aug 2025 15:02:38 -0700 Subject: [PATCH] aya: allow specifying a pin path for a named map This commit extends the EbpfLoader with set_map_pin_path that allows the caller to associate a named map with a pin path. One note is that this path is an absolute path, not relative to `map_pin_path`, and it forces the map to be loaded from that path. --- aya/src/bpf.rs | 59 +++++++++++++++++++++++++++++++++++++-------- aya/src/maps/mod.rs | 7 ++++-- 2 files changed, 54 insertions(+), 12 deletions(-) diff --git a/aya/src/bpf.rs b/aya/src/bpf.rs index c1b67955..da166f5a 100644 --- a/aya/src/bpf.rs +++ b/aya/src/bpf.rs @@ -119,7 +119,13 @@ pub struct EbpfLoader<'a> { btf: Option>, map_pin_path: Option, globals: HashMap<&'a str, (&'a [u8], bool)>, + // Max entries overrides the max_entries field of the map that matches the provided name + // before the map is created. max_entries: HashMap<&'a str, u32>, + // Map pin path overrides the pin path of the map that matches the provided name before + // it is created. + map_pin_path_by_name: HashMap<&'a str, std::borrow::Cow<'a, Path>>, + extensions: HashSet<&'a str>, verifier_log_level: VerifierLogLevel, allow_unsupported_maps: bool, @@ -158,6 +164,7 @@ impl<'a> EbpfLoader<'a> { map_pin_path: None, globals: HashMap::new(), max_entries: HashMap::new(), + map_pin_path_by_name: HashMap::new(), extensions: HashSet::new(), verifier_log_level: VerifierLogLevel::default(), allow_unsupported_maps: false, @@ -301,6 +308,32 @@ impl<'a> EbpfLoader<'a> { self } + /// Set the pin path for the map that matches the provided name. + /// + /// Note that this is an absolute path to the pinned map; it is not a prefix + /// to be combined with the map name, and it is not relative to the + /// configured base directory for pinned maps. + /// + /// # Example + /// + /// ```no_run + /// use aya::EbpfLoader; + /// + /// let bpf = EbpfLoader::new() + /// .set_map_pin_path("map", "/sys/fs/bpf/my-pinned-map") + /// .load_file("file.o")?; + /// # Ok::<(), aya::EbpfError>(()) + /// ``` + /// + pub fn set_map_pin_path>>( + &mut self, + name: &'a str, + path: P, + ) -> &mut Self { + self.map_pin_path_by_name.insert(name, path.into()); + self + } + /// Treat the provided program as an [`Extension`] /// /// When attempting to load the program with the provided `name` @@ -384,6 +417,7 @@ impl<'a> EbpfLoader<'a> { extensions, verifier_log_level, allow_unsupported_maps, + map_pin_path_by_name, } = self; let mut obj = Object::parse(data)?; obj.patch_map_data(globals.clone())?; @@ -483,16 +517,21 @@ impl<'a> EbpfLoader<'a> { _ => (), } let btf_fd = btf_fd.as_deref().map(|fd| fd.as_fd()); - let mut map = match obj.pinning() { - PinningType::None => MapData::create(obj, &name, btf_fd)?, - PinningType::ByName => { - // pin maps in /sys/fs/bpf by default to align with libbpf - // behavior https://github.com/libbpf/libbpf/blob/v1.2.2/src/libbpf.c#L2161. - let path = map_pin_path - .as_deref() - .unwrap_or_else(|| Path::new("/sys/fs/bpf")); - - MapData::create_pinned_by_name(path, obj, &name, btf_fd)? + let mut map = if let Some(pin_path) = map_pin_path_by_name.get(name.as_str()) { + MapData::create_pinned_by_name(pin_path, obj, &name, btf_fd)? + } else { + match obj.pinning() { + PinningType::None => MapData::create(obj, &name, btf_fd)?, + PinningType::ByName => { + // pin maps in /sys/fs/bpf by default to align with libbpf + // behavior https://github.com/libbpf/libbpf/blob/v1.2.2/src/libbpf.c#L2161. + let path = map_pin_path + .as_deref() + .unwrap_or_else(|| Path::new("/sys/fs/bpf")); + let path = path.join(&name); + + MapData::create_pinned_by_name(path, obj, &name, btf_fd)? + } } }; map.finalize()?; diff --git a/aya/src/maps/mod.rs b/aya/src/maps/mod.rs index d8593a40..d24c845b 100644 --- a/aya/src/maps/mod.rs +++ b/aya/src/maps/mod.rs @@ -649,13 +649,16 @@ impl MapData { use std::os::unix::ffi::OsStrExt as _; // try to open map in case it's already pinned - let path = path.as_ref().join(name); + let path = path.as_ref(); let path_string = match CString::new(path.as_os_str().as_bytes()) { Ok(path) => path, Err(error) => { return Err(MapError::PinError { name: Some(name.into()), - error: PinError::InvalidPinPath { path, error }, + error: PinError::InvalidPinPath { + path: path.to_path_buf(), + error, + }, }); } };