diff --git a/aya/src/bpf.rs b/aya/src/bpf.rs index d37cf097..6d3f299b 100644 --- a/aya/src/bpf.rs +++ b/aya/src/bpf.rs @@ -123,6 +123,10 @@ pub struct EbpfLoader<'a> { // 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, @@ -161,6 +165,7 @@ impl<'a> EbpfLoader<'a> { default_map_pin_directory: 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, @@ -218,6 +223,9 @@ impl<'a> EbpfLoader<'a> { /// Pinned maps will be loaded from `path/MAP_NAME`. /// The caller is responsible for ensuring the directory exists. /// + /// Note that if a path is provided for a specific map via [`EbpfLoader::map_pin_path`], + /// it will take precedence over this path. + /// /// # Example /// /// ```no_run @@ -304,6 +312,33 @@ 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. + /// + /// Each call to this function with the same name overwrites the path to the + /// pinned map; last one wins. + /// + /// # Example + /// + /// ```no_run + /// # use std::path::Path; + /// + /// # let mut loader = aya::EbpfLoader::new(); + /// # let pin_path = Path::new("/sys/fs/bpf/my-pinned-map"); + /// let bpf = loader + /// .map_pin_path("map", pin_path) + /// .load_file("file.o")?; + /// # Ok::<(), aya::EbpfError>(()) + /// ``` + /// + pub fn 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` @@ -387,6 +422,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())?; @@ -491,16 +527,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 = default_map_pin_directory - .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 = default_map_pin_directory + .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 2d28a20b..348838b3 100644 --- a/aya/src/maps/mod.rs +++ b/aya/src/maps/mod.rs @@ -616,13 +616,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, + }, }); } }; @@ -636,7 +639,7 @@ impl MapData { }), Err(_) => { let map = Self::create(obj, name, btf_fd)?; - map.pin(&path).map_err(|error| MapError::PinError { + map.pin(path).map_err(|error| MapError::PinError { name: Some(name.into()), error, })?; diff --git a/xtask/public-api/aya.txt b/xtask/public-api/aya.txt index c5d0648b..8c588781 100644 --- a/xtask/public-api/aya.txt +++ b/xtask/public-api/aya.txt @@ -10746,6 +10746,7 @@ pub fn aya::EbpfLoader<'a>::default_map_pin_directory::extension(&mut self, name: &'a str) -> &mut Self pub fn aya::EbpfLoader<'a>::load(&mut self, data: &[u8]) -> core::result::Result pub fn aya::EbpfLoader<'a>::load_file>(&mut self, path: P) -> core::result::Result +pub fn aya::EbpfLoader<'a>::map_pin_path>>(&mut self, name: &'a str, path: P) -> &mut Self pub fn aya::EbpfLoader<'a>::new() -> Self pub fn aya::EbpfLoader<'a>::set_global>>(&mut self, name: &'a str, value: T, must_exist: bool) -> &mut Self pub fn aya::EbpfLoader<'a>::set_max_entries(&mut self, name: &'a str, size: u32) -> &mut Self