1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
use core::ptr::NonNull;
use crate::{btf_maps::btf_map_def, lookup};
btf_map_def!(
/// A BTF-compatible BPF hash map that stores references to other maps (hash of maps).
///
/// This map type allows you to store file descriptors of other BPF maps
/// indexed by arbitrary keys, enabling dynamic map selection at runtime.
///
/// # Minimum kernel version
///
/// The minimum kernel version required to use this feature is 5.7.
///
/// # Example
///
/// ```rust,no_run
/// use aya_ebpf::{btf_maps::{Array, HashOfMaps}, macros::btf_map};
///
/// // The inner map definition is parsed from BTF at load time.
/// #[btf_map]
/// static OUTER: HashOfMaps<u32, Array<u32, 10>, 4> = HashOfMaps::new();
/// ```
pub struct HashOfMaps<K, V; const MAX_ENTRIES: usize, const FLAGS: usize = 0>,
map_type: BPF_MAP_TYPE_HASH_OF_MAPS,
max_entries: MAX_ENTRIES,
map_flags: FLAGS,
key_type: K,
value_type: u32,
inner_map: V,
);
impl<K, V, const MAX_ENTRIES: usize, const FLAGS: usize> HashOfMaps<K, V, MAX_ENTRIES, FLAGS> {
/// Retrieve the inner map associated with `key` from the map.
///
/// # Safety
///
/// Unless the map flag `BPF_F_NO_PREALLOC` is used, the kernel does not guarantee the
/// atomicity of `insert` or `remove`, and any element removed from the map might get
/// aliased by another element in the map, causing garbage to be read, or corruption in
/// case of writes.
#[inline(always)]
pub unsafe fn get(&self, key: &K) -> Option<&V> {
// SAFETY: We only read from the map through BPF helpers.
// The struct fields are never accessed - only the address is used.
unsafe { self.lookup(key).map(|p| p.as_ref()) }
}
#[inline(always)]
unsafe fn lookup(&self, key: &K) -> Option<NonNull<V>> {
lookup(self.as_ptr(), key)
}
}
impl<K, V: crate::btf_maps::MapDef, const MAX_ENTRIES: usize, const FLAGS: usize>
HashOfMaps<K, V, MAX_ENTRIES, FLAGS>
{
/// Looks up a value directly in the inner map associated with `outer_key`.
///
/// Performs both the outer and inner `bpf_map_lookup_elem` calls in a
/// single method, producing fewer BPF instructions between the two
/// helpers. This reduces verifier state explosion in tight loops.
///
/// # Safety
///
/// See [`get`](Self::get).
#[inline(always)]
pub unsafe fn get_value(&self, outer_key: &K, inner_key: &V::Key) -> Option<&V::Value> {
let inner: NonNull<V> = lookup(self.as_ptr(), outer_key)?;
// SAFETY: The caller upholds the aliasing invariants (see `get`).
unsafe { crate::btf_maps::lookup_inner(inner, inner_key) }
}
/// Same as [`get_value`](Self::get_value) but returns a mutable pointer.
///
/// # Safety
///
/// See [`get_value`](Self::get_value).
#[inline(always)]
pub unsafe fn get_value_ptr_mut(
&self,
outer_key: &K,
inner_key: &V::Key,
) -> Option<*mut V::Value> {
let inner: NonNull<V> = lookup(self.as_ptr(), outer_key)?;
crate::btf_maps::lookup_inner_ptr_mut(inner, inner_key)
}
}