aya_friday/maps/hash_map/
per_cpu_hash_map.rs1use std::{
3 borrow::{Borrow, BorrowMut},
4 marker::PhantomData,
5 os::fd::AsFd as _,
6};
7
8use crate::{
9 Pod,
10 maps::{
11 IterableMap, MapData, MapError, MapIter, MapKeys, PerCpuValues, check_kv_size, hash_map,
12 },
13 sys::{SyscallError, bpf_map_lookup_elem_per_cpu, bpf_map_update_elem_per_cpu},
14};
15
16#[doc(alias = "BPF_MAP_TYPE_LRU_PERCPU_HASH")]
44#[doc(alias = "BPF_MAP_TYPE_PERCPU_HASH")]
45pub struct PerCpuHashMap<T, K: Pod, V: Pod> {
46 pub(crate) inner: T,
47 _kv: PhantomData<(K, V)>,
48}
49
50impl<T: Borrow<MapData>, K: Pod, V: Pod> PerCpuHashMap<T, K, V> {
51 pub(crate) fn new(map: T) -> Result<Self, MapError> {
52 let data = map.borrow();
53 check_kv_size::<K, V>(data)?;
54
55 Ok(Self {
56 inner: map,
57 _kv: PhantomData,
58 })
59 }
60
61 pub fn get(&self, key: &K, flags: u64) -> Result<PerCpuValues<V>, MapError> {
63 let fd = self.inner.borrow().fd().as_fd();
64 let values =
65 bpf_map_lookup_elem_per_cpu(fd, key, flags).map_err(|io_error| SyscallError {
66 call: "bpf_map_lookup_elem",
67 io_error,
68 })?;
69 values.ok_or(MapError::KeyNotFound)
70 }
71
72 pub fn iter(&self) -> MapIter<'_, K, PerCpuValues<V>, Self> {
75 MapIter::new(self)
76 }
77
78 pub fn keys(&self) -> MapKeys<'_, K> {
81 MapKeys::new(self.inner.borrow())
82 }
83}
84
85impl<'a, T: Borrow<MapData>, K: Pod, V: Pod> IntoIterator for &'a PerCpuHashMap<T, K, V> {
86 type Item = Result<(K, PerCpuValues<V>), MapError>;
87 type IntoIter = MapIter<'a, K, PerCpuValues<V>, PerCpuHashMap<T, K, V>>;
88
89 fn into_iter(self) -> Self::IntoIter {
90 self.iter()
91 }
92}
93
94impl<T: BorrowMut<MapData>, K: Pod, V: Pod> PerCpuHashMap<T, K, V> {
95 pub fn insert(
125 &mut self,
126 key: impl Borrow<K>,
127 values: PerCpuValues<V>,
128 flags: u64,
129 ) -> Result<(), MapError> {
130 let fd = self.inner.borrow_mut().fd().as_fd();
131 bpf_map_update_elem_per_cpu(fd, key.borrow(), &values, flags)
132 .map_err(|io_error| SyscallError {
133 call: "bpf_map_update_elem",
134 io_error,
135 })
136 .map_err(Into::into)
137 }
138
139 pub fn remove(&mut self, key: &K) -> Result<(), MapError> {
141 hash_map::remove(self.inner.borrow_mut(), key)
142 }
143}
144
145impl<T: Borrow<MapData>, K: Pod, V: Pod> IterableMap<K, PerCpuValues<V>>
146 for PerCpuHashMap<T, K, V>
147{
148 fn map(&self) -> &MapData {
149 self.inner.borrow()
150 }
151
152 fn get(&self, key: &K) -> Result<PerCpuValues<V>, MapError> {
153 Self::get(self, key, 0)
154 }
155}
156
157#[cfg(test)]
158mod tests {
159 use std::io;
160
161 use assert_matches::assert_matches;
162 use aya_obj::generated::bpf_map_type;
163 use libc::ENOENT;
164
165 use super::*;
166 use crate::{
167 maps::{Map, test_utils},
168 sys::{SysResult, override_syscall},
169 };
170
171 fn sys_error(value: i32) -> SysResult {
172 Err((-1, io::Error::from_raw_os_error(value)))
173 }
174
175 #[test]
176 fn test_try_from_ok() {
177 let map = Map::PerCpuHashMap(test_utils::new_map(test_utils::new_obj_map::<u32>(
178 bpf_map_type::BPF_MAP_TYPE_PERCPU_HASH,
179 )));
180 let _unused: PerCpuHashMap<_, u32, u32> = map.try_into().unwrap();
181 }
182 #[test]
183 fn test_try_from_ok_lru() {
184 let map_data = || {
185 test_utils::new_map(test_utils::new_obj_map::<u32>(
186 bpf_map_type::BPF_MAP_TYPE_LRU_PERCPU_HASH,
187 ))
188 };
189 let map = Map::PerCpuHashMap(map_data());
190 let _unused: PerCpuHashMap<_, u32, u32> = map.try_into().unwrap();
191 let map = Map::PerCpuLruHashMap(map_data());
192 let _unused: PerCpuHashMap<_, u32, u32> = map.try_into().unwrap();
193 }
194 #[test]
195 fn test_get_not_found() {
196 let map_data = || {
197 test_utils::new_map(test_utils::new_obj_map::<u32>(
198 bpf_map_type::BPF_MAP_TYPE_LRU_PERCPU_HASH,
199 ))
200 };
201 let map = Map::PerCpuHashMap(map_data());
202 let map = PerCpuHashMap::<_, u32, u32>::try_from(&map).unwrap();
203
204 override_syscall(|_| sys_error(ENOENT));
205
206 assert_matches!(map.get(&1, 0), Err(MapError::KeyNotFound));
207 }
208}