xref: /DragonOS/kernel/src/bpf/map/mod.rs (revision fae6e9ade46a52976ad5d099643d51cc20876448)
1*fae6e9adSlinfeng mod array_map;
2*fae6e9adSlinfeng mod hash_map;
3*fae6e9adSlinfeng mod lru;
4*fae6e9adSlinfeng mod queue;
5*fae6e9adSlinfeng mod util;
6*fae6e9adSlinfeng 
7*fae6e9adSlinfeng use super::Result;
8*fae6e9adSlinfeng use crate::bpf::map::array_map::{ArrayMap, PerCpuArrayMap, PerfEventArrayMap};
9*fae6e9adSlinfeng use crate::bpf::map::hash_map::PerCpuHashMap;
10*fae6e9adSlinfeng use crate::bpf::map::util::{BpfMapGetNextKeyArg, BpfMapMeta, BpfMapUpdateArg};
11*fae6e9adSlinfeng use crate::filesystem::vfs::file::{File, FileMode};
12*fae6e9adSlinfeng use crate::filesystem::vfs::syscall::ModeType;
13*fae6e9adSlinfeng use crate::filesystem::vfs::{FilePrivateData, FileSystem, FileType, IndexNode, Metadata};
14*fae6e9adSlinfeng use crate::include::bindings::linux_bpf::{bpf_attr, bpf_map_type};
15*fae6e9adSlinfeng use crate::libs::casting::DowncastArc;
16*fae6e9adSlinfeng use crate::libs::spinlock::{SpinLock, SpinLockGuard};
17*fae6e9adSlinfeng use crate::process::ProcessManager;
18*fae6e9adSlinfeng use crate::syscall::user_access::{UserBufferReader, UserBufferWriter};
19*fae6e9adSlinfeng use alloc::boxed::Box;
20*fae6e9adSlinfeng use alloc::string::String;
21*fae6e9adSlinfeng use alloc::sync::Arc;
22*fae6e9adSlinfeng use alloc::vec::Vec;
23*fae6e9adSlinfeng use core::any::Any;
24*fae6e9adSlinfeng use core::fmt::Debug;
25*fae6e9adSlinfeng use intertrait::CastFromSync;
26*fae6e9adSlinfeng use log::{error, info};
27*fae6e9adSlinfeng use system_error::SystemError;
28*fae6e9adSlinfeng 
29*fae6e9adSlinfeng #[derive(Debug)]
30*fae6e9adSlinfeng pub struct BpfMap {
31*fae6e9adSlinfeng     inner_map: SpinLock<Box<dyn BpfMapCommonOps>>,
32*fae6e9adSlinfeng     meta: BpfMapMeta,
33*fae6e9adSlinfeng }
34*fae6e9adSlinfeng 
35*fae6e9adSlinfeng pub type BpfCallBackFn = fn(key: &[u8], value: &[u8], ctx: *const u8) -> i32;
36*fae6e9adSlinfeng 
37*fae6e9adSlinfeng pub trait BpfMapCommonOps: Send + Sync + Debug + CastFromSync {
38*fae6e9adSlinfeng     /// Lookup an element in the map.
39*fae6e9adSlinfeng     ///
40*fae6e9adSlinfeng     /// See https://ebpf-docs.dylanreimerink.nl/linux/helper-function/bpf_map_lookup_elem/
lookup_elem(&mut self, _key: &[u8]) -> Result<Option<&[u8]>>41*fae6e9adSlinfeng     fn lookup_elem(&mut self, _key: &[u8]) -> Result<Option<&[u8]>> {
42*fae6e9adSlinfeng         Err(SystemError::ENOSYS)
43*fae6e9adSlinfeng     }
44*fae6e9adSlinfeng     /// Update an element in the map.
45*fae6e9adSlinfeng     ///
46*fae6e9adSlinfeng     /// See https://ebpf-docs.dylanreimerink.nl/linux/helper-function/bpf_map_update_elem/
update_elem(&mut self, _key: &[u8], _value: &[u8], _flags: u64) -> Result<()>47*fae6e9adSlinfeng     fn update_elem(&mut self, _key: &[u8], _value: &[u8], _flags: u64) -> Result<()> {
48*fae6e9adSlinfeng         Err(SystemError::ENOSYS)
49*fae6e9adSlinfeng     }
50*fae6e9adSlinfeng     /// Delete an element from the map.
51*fae6e9adSlinfeng     ///
52*fae6e9adSlinfeng     /// See https://ebpf-docs.dylanreimerink.nl/linux/helper-function/bpf_map_delete_elem/
delete_elem(&mut self, _key: &[u8]) -> Result<()>53*fae6e9adSlinfeng     fn delete_elem(&mut self, _key: &[u8]) -> Result<()> {
54*fae6e9adSlinfeng         Err(SystemError::ENOSYS)
55*fae6e9adSlinfeng     }
56*fae6e9adSlinfeng     /// For each element in map, call callback_fn function with map,
57*fae6e9adSlinfeng     /// callback_ctx and other map-specific parameters.
58*fae6e9adSlinfeng     ///
59*fae6e9adSlinfeng     /// See https://ebpf-docs.dylanreimerink.nl/linux/helper-function/bpf_for_each_map_elem/
for_each_elem(&mut self, _cb: BpfCallBackFn, _ctx: *const u8, _flags: u64) -> Result<u32>60*fae6e9adSlinfeng     fn for_each_elem(&mut self, _cb: BpfCallBackFn, _ctx: *const u8, _flags: u64) -> Result<u32> {
61*fae6e9adSlinfeng         Err(SystemError::ENOSYS)
62*fae6e9adSlinfeng     }
63*fae6e9adSlinfeng     /// Look up an element with the given key in the map referred to by the file descriptor fd,
64*fae6e9adSlinfeng     /// and if found, delete the element.
lookup_and_delete_elem(&mut self, _key: &[u8], _value: &mut [u8]) -> Result<()>65*fae6e9adSlinfeng     fn lookup_and_delete_elem(&mut self, _key: &[u8], _value: &mut [u8]) -> Result<()> {
66*fae6e9adSlinfeng         Err(SystemError::ENOSYS)
67*fae6e9adSlinfeng     }
68*fae6e9adSlinfeng 
69*fae6e9adSlinfeng     /// erform a lookup in percpu map for an entry associated to key on cpu.
lookup_percpu_elem(&mut self, _key: &[u8], _cpu: u32) -> Result<Option<&[u8]>>70*fae6e9adSlinfeng     fn lookup_percpu_elem(&mut self, _key: &[u8], _cpu: u32) -> Result<Option<&[u8]>> {
71*fae6e9adSlinfeng         Err(SystemError::ENOSYS)
72*fae6e9adSlinfeng     }
73*fae6e9adSlinfeng     /// Get the next key in the map. If key is None, get the first key.
74*fae6e9adSlinfeng     ///
75*fae6e9adSlinfeng     /// Called from syscall
get_next_key(&self, _key: Option<&[u8]>, _next_key: &mut [u8]) -> Result<()>76*fae6e9adSlinfeng     fn get_next_key(&self, _key: Option<&[u8]>, _next_key: &mut [u8]) -> Result<()> {
77*fae6e9adSlinfeng         Err(SystemError::ENOSYS)
78*fae6e9adSlinfeng     }
79*fae6e9adSlinfeng 
80*fae6e9adSlinfeng     /// Push an element value in map.
push_elem(&mut self, _value: &[u8], _flags: u64) -> Result<()>81*fae6e9adSlinfeng     fn push_elem(&mut self, _value: &[u8], _flags: u64) -> Result<()> {
82*fae6e9adSlinfeng         Err(SystemError::ENOSYS)
83*fae6e9adSlinfeng     }
84*fae6e9adSlinfeng 
85*fae6e9adSlinfeng     /// Pop an element value from map.
pop_elem(&mut self, _value: &mut [u8]) -> Result<()>86*fae6e9adSlinfeng     fn pop_elem(&mut self, _value: &mut [u8]) -> Result<()> {
87*fae6e9adSlinfeng         Err(SystemError::ENOSYS)
88*fae6e9adSlinfeng     }
89*fae6e9adSlinfeng 
90*fae6e9adSlinfeng     /// Peek an element value from map.
peek_elem(&self, _value: &mut [u8]) -> Result<()>91*fae6e9adSlinfeng     fn peek_elem(&self, _value: &mut [u8]) -> Result<()> {
92*fae6e9adSlinfeng         Err(SystemError::ENOSYS)
93*fae6e9adSlinfeng     }
94*fae6e9adSlinfeng 
95*fae6e9adSlinfeng     /// Freeze the map.
96*fae6e9adSlinfeng     ///
97*fae6e9adSlinfeng     /// It's useful for .rodata maps.
freeze(&self) -> Result<()>98*fae6e9adSlinfeng     fn freeze(&self) -> Result<()> {
99*fae6e9adSlinfeng         Err(SystemError::ENOSYS)
100*fae6e9adSlinfeng     }
101*fae6e9adSlinfeng 
102*fae6e9adSlinfeng     /// Get the first value pointer.
first_value_ptr(&self) -> Result<*const u8>103*fae6e9adSlinfeng     fn first_value_ptr(&self) -> Result<*const u8> {
104*fae6e9adSlinfeng         Err(SystemError::ENOSYS)
105*fae6e9adSlinfeng     }
106*fae6e9adSlinfeng }
107*fae6e9adSlinfeng impl DowncastArc for dyn BpfMapCommonOps {
as_any_arc(self: Arc<Self>) -> Arc<dyn Any>108*fae6e9adSlinfeng     fn as_any_arc(self: Arc<Self>) -> Arc<dyn Any> {
109*fae6e9adSlinfeng         self
110*fae6e9adSlinfeng     }
111*fae6e9adSlinfeng }
112*fae6e9adSlinfeng impl BpfMap {
new(map: Box<dyn BpfMapCommonOps>, meta: BpfMapMeta) -> Self113*fae6e9adSlinfeng     pub fn new(map: Box<dyn BpfMapCommonOps>, meta: BpfMapMeta) -> Self {
114*fae6e9adSlinfeng         assert_ne!(meta.key_size, 0);
115*fae6e9adSlinfeng         BpfMap {
116*fae6e9adSlinfeng             inner_map: SpinLock::new(map),
117*fae6e9adSlinfeng             meta,
118*fae6e9adSlinfeng         }
119*fae6e9adSlinfeng     }
120*fae6e9adSlinfeng 
inner_map(&self) -> &SpinLock<Box<dyn BpfMapCommonOps>>121*fae6e9adSlinfeng     pub fn inner_map(&self) -> &SpinLock<Box<dyn BpfMapCommonOps>> {
122*fae6e9adSlinfeng         &self.inner_map
123*fae6e9adSlinfeng     }
124*fae6e9adSlinfeng 
key_size(&self) -> usize125*fae6e9adSlinfeng     pub fn key_size(&self) -> usize {
126*fae6e9adSlinfeng         self.meta.key_size as usize
127*fae6e9adSlinfeng     }
128*fae6e9adSlinfeng 
value_size(&self) -> usize129*fae6e9adSlinfeng     pub fn value_size(&self) -> usize {
130*fae6e9adSlinfeng         self.meta.value_size as usize
131*fae6e9adSlinfeng     }
132*fae6e9adSlinfeng }
133*fae6e9adSlinfeng 
134*fae6e9adSlinfeng impl IndexNode for BpfMap {
open(&self, _data: SpinLockGuard<FilePrivateData>, _mode: &FileMode) -> Result<()>135*fae6e9adSlinfeng     fn open(&self, _data: SpinLockGuard<FilePrivateData>, _mode: &FileMode) -> Result<()> {
136*fae6e9adSlinfeng         Ok(())
137*fae6e9adSlinfeng     }
close(&self, _data: SpinLockGuard<FilePrivateData>) -> Result<()>138*fae6e9adSlinfeng     fn close(&self, _data: SpinLockGuard<FilePrivateData>) -> Result<()> {
139*fae6e9adSlinfeng         Ok(())
140*fae6e9adSlinfeng     }
read_at( &self, _offset: usize, _len: usize, _buf: &mut [u8], _data: SpinLockGuard<FilePrivateData>, ) -> Result<usize>141*fae6e9adSlinfeng     fn read_at(
142*fae6e9adSlinfeng         &self,
143*fae6e9adSlinfeng         _offset: usize,
144*fae6e9adSlinfeng         _len: usize,
145*fae6e9adSlinfeng         _buf: &mut [u8],
146*fae6e9adSlinfeng         _data: SpinLockGuard<FilePrivateData>,
147*fae6e9adSlinfeng     ) -> Result<usize> {
148*fae6e9adSlinfeng         Err(SystemError::ENOSYS)
149*fae6e9adSlinfeng     }
150*fae6e9adSlinfeng 
write_at( &self, _offset: usize, _len: usize, _buf: &[u8], _data: SpinLockGuard<FilePrivateData>, ) -> Result<usize>151*fae6e9adSlinfeng     fn write_at(
152*fae6e9adSlinfeng         &self,
153*fae6e9adSlinfeng         _offset: usize,
154*fae6e9adSlinfeng         _len: usize,
155*fae6e9adSlinfeng         _buf: &[u8],
156*fae6e9adSlinfeng         _data: SpinLockGuard<FilePrivateData>,
157*fae6e9adSlinfeng     ) -> Result<usize> {
158*fae6e9adSlinfeng         Err(SystemError::ENOSYS)
159*fae6e9adSlinfeng     }
160*fae6e9adSlinfeng 
metadata(&self) -> Result<Metadata>161*fae6e9adSlinfeng     fn metadata(&self) -> Result<Metadata> {
162*fae6e9adSlinfeng         let meta = Metadata {
163*fae6e9adSlinfeng             mode: ModeType::from_bits_truncate(0o755),
164*fae6e9adSlinfeng             file_type: FileType::File,
165*fae6e9adSlinfeng             ..Default::default()
166*fae6e9adSlinfeng         };
167*fae6e9adSlinfeng         Ok(meta)
168*fae6e9adSlinfeng     }
169*fae6e9adSlinfeng 
resize(&self, _len: usize) -> Result<()>170*fae6e9adSlinfeng     fn resize(&self, _len: usize) -> Result<()> {
171*fae6e9adSlinfeng         Ok(())
172*fae6e9adSlinfeng     }
173*fae6e9adSlinfeng 
fs(&self) -> Arc<dyn FileSystem>174*fae6e9adSlinfeng     fn fs(&self) -> Arc<dyn FileSystem> {
175*fae6e9adSlinfeng         todo!("BpfMap does not have a filesystem")
176*fae6e9adSlinfeng     }
177*fae6e9adSlinfeng 
as_any_ref(&self) -> &dyn Any178*fae6e9adSlinfeng     fn as_any_ref(&self) -> &dyn Any {
179*fae6e9adSlinfeng         self
180*fae6e9adSlinfeng     }
181*fae6e9adSlinfeng 
list(&self) -> Result<Vec<String>>182*fae6e9adSlinfeng     fn list(&self) -> Result<Vec<String>> {
183*fae6e9adSlinfeng         Err(SystemError::ENOSYS)
184*fae6e9adSlinfeng     }
185*fae6e9adSlinfeng }
186*fae6e9adSlinfeng 
187*fae6e9adSlinfeng /// Create a map and return a file descriptor that refers to
188*fae6e9adSlinfeng /// the map.  The close-on-exec file descriptor flag
189*fae6e9adSlinfeng /// is automatically enabled for the new file descriptor.
190*fae6e9adSlinfeng ///
191*fae6e9adSlinfeng /// See https://ebpf-docs.dylanreimerink.nl/linux/syscall/BPF_MAP_CREATE/
bpf_map_create(attr: &bpf_attr) -> Result<usize>192*fae6e9adSlinfeng pub fn bpf_map_create(attr: &bpf_attr) -> Result<usize> {
193*fae6e9adSlinfeng     let map_meta = BpfMapMeta::try_from(attr)?;
194*fae6e9adSlinfeng     info!("The map attr is {:#?}", map_meta);
195*fae6e9adSlinfeng     let map: Box<dyn BpfMapCommonOps> = match map_meta.map_type {
196*fae6e9adSlinfeng         bpf_map_type::BPF_MAP_TYPE_ARRAY => {
197*fae6e9adSlinfeng             let array_map = ArrayMap::new(&map_meta)?;
198*fae6e9adSlinfeng             Box::new(array_map)
199*fae6e9adSlinfeng         }
200*fae6e9adSlinfeng         bpf_map_type::BPF_MAP_TYPE_PERCPU_ARRAY => {
201*fae6e9adSlinfeng             let per_cpu_array_map = PerCpuArrayMap::new(&map_meta)?;
202*fae6e9adSlinfeng             Box::new(per_cpu_array_map)
203*fae6e9adSlinfeng         }
204*fae6e9adSlinfeng         bpf_map_type::BPF_MAP_TYPE_PERF_EVENT_ARRAY => {
205*fae6e9adSlinfeng             let perf_event_array_map = PerfEventArrayMap::new(&map_meta)?;
206*fae6e9adSlinfeng             Box::new(perf_event_array_map)
207*fae6e9adSlinfeng         }
208*fae6e9adSlinfeng 
209*fae6e9adSlinfeng         bpf_map_type::BPF_MAP_TYPE_CPUMAP
210*fae6e9adSlinfeng         | bpf_map_type::BPF_MAP_TYPE_DEVMAP
211*fae6e9adSlinfeng         | bpf_map_type::BPF_MAP_TYPE_DEVMAP_HASH => {
212*fae6e9adSlinfeng             error!("bpf map type {:?} not implemented", map_meta.map_type);
213*fae6e9adSlinfeng             Err(SystemError::EINVAL)?
214*fae6e9adSlinfeng         }
215*fae6e9adSlinfeng         bpf_map_type::BPF_MAP_TYPE_HASH => {
216*fae6e9adSlinfeng             let hash_map = hash_map::BpfHashMap::new(&map_meta)?;
217*fae6e9adSlinfeng             Box::new(hash_map)
218*fae6e9adSlinfeng         }
219*fae6e9adSlinfeng         bpf_map_type::BPF_MAP_TYPE_PERCPU_HASH => {
220*fae6e9adSlinfeng             let per_cpu_hash_map = PerCpuHashMap::new(&map_meta)?;
221*fae6e9adSlinfeng             Box::new(per_cpu_hash_map)
222*fae6e9adSlinfeng         }
223*fae6e9adSlinfeng         bpf_map_type::BPF_MAP_TYPE_QUEUE => {
224*fae6e9adSlinfeng             let queue_map = queue::QueueMap::new(&map_meta)?;
225*fae6e9adSlinfeng             Box::new(queue_map)
226*fae6e9adSlinfeng         }
227*fae6e9adSlinfeng         bpf_map_type::BPF_MAP_TYPE_STACK => {
228*fae6e9adSlinfeng             let stack_map = queue::StackMap::new(&map_meta)?;
229*fae6e9adSlinfeng             Box::new(stack_map)
230*fae6e9adSlinfeng         }
231*fae6e9adSlinfeng         bpf_map_type::BPF_MAP_TYPE_LRU_HASH => {
232*fae6e9adSlinfeng             let lru_hash_map = lru::LruMap::new(&map_meta)?;
233*fae6e9adSlinfeng             Box::new(lru_hash_map)
234*fae6e9adSlinfeng         }
235*fae6e9adSlinfeng         bpf_map_type::BPF_MAP_TYPE_LRU_PERCPU_HASH => {
236*fae6e9adSlinfeng             let lru_per_cpu_hash_map = lru::PerCpuLruMap::new(&map_meta)?;
237*fae6e9adSlinfeng             Box::new(lru_per_cpu_hash_map)
238*fae6e9adSlinfeng         }
239*fae6e9adSlinfeng         _ => {
240*fae6e9adSlinfeng             unimplemented!("bpf map type {:?} not implemented", map_meta.map_type)
241*fae6e9adSlinfeng         }
242*fae6e9adSlinfeng     };
243*fae6e9adSlinfeng     let bpf_map = BpfMap::new(map, map_meta);
244*fae6e9adSlinfeng     let fd_table = ProcessManager::current_pcb().fd_table();
245*fae6e9adSlinfeng     let file = File::new(Arc::new(bpf_map), FileMode::O_RDWR | FileMode::O_CLOEXEC)?;
246*fae6e9adSlinfeng     let fd = fd_table.write().alloc_fd(file, None).map(|x| x as usize)?;
247*fae6e9adSlinfeng     info!("create map with fd: [{}]", fd);
248*fae6e9adSlinfeng     Ok(fd)
249*fae6e9adSlinfeng }
250*fae6e9adSlinfeng 
251*fae6e9adSlinfeng /// Create or update an element (key/value pair) in a specified map.
252*fae6e9adSlinfeng ///
253*fae6e9adSlinfeng /// See https://ebpf-docs.dylanreimerink.nl/linux/syscall/BPF_MAP_UPDATE_ELEM/
bpf_map_update_elem(attr: &bpf_attr) -> Result<usize>254*fae6e9adSlinfeng pub fn bpf_map_update_elem(attr: &bpf_attr) -> Result<usize> {
255*fae6e9adSlinfeng     let arg = BpfMapUpdateArg::from(attr);
256*fae6e9adSlinfeng     info!("<bpf_map_update_elem>: {:#x?}", arg);
257*fae6e9adSlinfeng     let map = get_map_file(arg.map_fd as i32)?;
258*fae6e9adSlinfeng     let meta = &map.meta;
259*fae6e9adSlinfeng     let key_size = meta.key_size as usize;
260*fae6e9adSlinfeng     let value_size = meta.value_size as usize;
261*fae6e9adSlinfeng 
262*fae6e9adSlinfeng     let key_buf = UserBufferReader::new(arg.key as *const u8, key_size, true)?;
263*fae6e9adSlinfeng     let value_buf = UserBufferReader::new(arg.value as *const u8, value_size, true)?;
264*fae6e9adSlinfeng 
265*fae6e9adSlinfeng     let key = key_buf.read_from_user(0)?;
266*fae6e9adSlinfeng     let value = value_buf.read_from_user(0)?;
267*fae6e9adSlinfeng     map.inner_map.lock().update_elem(key, value, arg.flags)?;
268*fae6e9adSlinfeng     info!("bpf_map_update_elem ok");
269*fae6e9adSlinfeng     Ok(0)
270*fae6e9adSlinfeng }
271*fae6e9adSlinfeng 
bpf_map_freeze(attr: &bpf_attr) -> Result<usize>272*fae6e9adSlinfeng pub fn bpf_map_freeze(attr: &bpf_attr) -> Result<usize> {
273*fae6e9adSlinfeng     let arg = BpfMapUpdateArg::from(attr);
274*fae6e9adSlinfeng     let map_fd = arg.map_fd;
275*fae6e9adSlinfeng     info!("<bpf_map_freeze>: map_fd: {:}", map_fd);
276*fae6e9adSlinfeng     let map = get_map_file(map_fd as i32)?;
277*fae6e9adSlinfeng     map.inner_map.lock().freeze()?;
278*fae6e9adSlinfeng     Ok(0)
279*fae6e9adSlinfeng }
280*fae6e9adSlinfeng 
281*fae6e9adSlinfeng ///  Look up an element by key in a specified map and return its value.
282*fae6e9adSlinfeng ///
283*fae6e9adSlinfeng /// See https://ebpf-docs.dylanreimerink.nl/linux/syscall/BPF_MAP_LOOKUP_ELEM/
bpf_lookup_elem(attr: &bpf_attr) -> Result<usize>284*fae6e9adSlinfeng pub fn bpf_lookup_elem(attr: &bpf_attr) -> Result<usize> {
285*fae6e9adSlinfeng     let arg = BpfMapUpdateArg::from(attr);
286*fae6e9adSlinfeng     // info!("<bpf_lookup_elem>: {:#x?}", arg);
287*fae6e9adSlinfeng     let map = get_map_file(arg.map_fd as _)?;
288*fae6e9adSlinfeng     let meta = &map.meta;
289*fae6e9adSlinfeng     let key_size = meta.key_size as usize;
290*fae6e9adSlinfeng     let value_size = meta.value_size as usize;
291*fae6e9adSlinfeng 
292*fae6e9adSlinfeng     let key_buf = UserBufferReader::new(arg.key as *const u8, key_size, true)?;
293*fae6e9adSlinfeng     let mut value_buf = UserBufferWriter::new(arg.value as *mut u8, value_size, true)?;
294*fae6e9adSlinfeng 
295*fae6e9adSlinfeng     let key = key_buf.read_from_user(0)?;
296*fae6e9adSlinfeng 
297*fae6e9adSlinfeng     let mut inner = map.inner_map.lock();
298*fae6e9adSlinfeng     let r_value = inner.lookup_elem(key)?;
299*fae6e9adSlinfeng     if let Some(r_value) = r_value {
300*fae6e9adSlinfeng         value_buf.copy_to_user(r_value, 0)?;
301*fae6e9adSlinfeng         Ok(0)
302*fae6e9adSlinfeng     } else {
303*fae6e9adSlinfeng         Err(SystemError::ENOENT)
304*fae6e9adSlinfeng     }
305*fae6e9adSlinfeng }
306*fae6e9adSlinfeng /// Look up an element by key in a specified map and return the key of the next element.
307*fae6e9adSlinfeng ///
308*fae6e9adSlinfeng /// - If key is `None`, the operation returns zero and sets the next_key pointer to the key of the first element.
309*fae6e9adSlinfeng /// - If key is `Some(T)`, the operation returns zero and sets the next_key pointer to the key of the next element.
310*fae6e9adSlinfeng /// - If key is the last element, returns -1 and errno is set to ENOENT.
311*fae6e9adSlinfeng ///
312*fae6e9adSlinfeng /// See https://ebpf-docs.dylanreimerink.nl/linux/syscall/BPF_MAP_GET_NEXT_KEY/
bpf_map_get_next_key(attr: &bpf_attr) -> Result<usize>313*fae6e9adSlinfeng pub fn bpf_map_get_next_key(attr: &bpf_attr) -> Result<usize> {
314*fae6e9adSlinfeng     let arg = BpfMapGetNextKeyArg::from(attr);
315*fae6e9adSlinfeng     // info!("<bpf_map_get_next_key>: {:#x?}", arg);
316*fae6e9adSlinfeng     let map = get_map_file(arg.map_fd as i32)?;
317*fae6e9adSlinfeng     let meta = &map.meta;
318*fae6e9adSlinfeng     let key_size = meta.key_size as usize;
319*fae6e9adSlinfeng 
320*fae6e9adSlinfeng     let key = if let Some(key_ptr) = arg.key {
321*fae6e9adSlinfeng         let key_buf = UserBufferReader::new(key_ptr as *const u8, key_size, true)?;
322*fae6e9adSlinfeng         let key = key_buf.read_from_user(0)?.to_vec();
323*fae6e9adSlinfeng         Some(key)
324*fae6e9adSlinfeng     } else {
325*fae6e9adSlinfeng         None
326*fae6e9adSlinfeng     };
327*fae6e9adSlinfeng     let key = key.as_deref();
328*fae6e9adSlinfeng     let mut next_key_buf = UserBufferWriter::new(arg.next_key as *mut u8, key_size, true)?;
329*fae6e9adSlinfeng     let inner = map.inner_map.lock();
330*fae6e9adSlinfeng     let next_key = next_key_buf.buffer(0)?;
331*fae6e9adSlinfeng     inner.get_next_key(key, next_key)?;
332*fae6e9adSlinfeng     // info!("next_key: {:?}", next_key);
333*fae6e9adSlinfeng     Ok(0)
334*fae6e9adSlinfeng }
335*fae6e9adSlinfeng 
336*fae6e9adSlinfeng /// Look up and delete an element by key in a specified map.
337*fae6e9adSlinfeng ///
338*fae6e9adSlinfeng /// # WARN
339*fae6e9adSlinfeng ///
340*fae6e9adSlinfeng /// Not all map types (particularly array maps) support this operation,
341*fae6e9adSlinfeng /// instead a zero value can be written to the map value. Check the map types page to check for support.
342*fae6e9adSlinfeng ///
343*fae6e9adSlinfeng /// See https://ebpf-docs.dylanreimerink.nl/linux/syscall/BPF_MAP_DELETE_ELEM/
bpf_map_delete_elem(attr: &bpf_attr) -> Result<usize>344*fae6e9adSlinfeng pub fn bpf_map_delete_elem(attr: &bpf_attr) -> Result<usize> {
345*fae6e9adSlinfeng     let arg = BpfMapUpdateArg::from(attr);
346*fae6e9adSlinfeng     // info!("<bpf_map_delete_elem>: {:#x?}", arg);
347*fae6e9adSlinfeng     let map = get_map_file(arg.map_fd as i32)?;
348*fae6e9adSlinfeng     let meta = &map.meta;
349*fae6e9adSlinfeng     let key_size = meta.key_size as usize;
350*fae6e9adSlinfeng 
351*fae6e9adSlinfeng     let key_buf = UserBufferReader::new(arg.key as *const u8, key_size, true)?;
352*fae6e9adSlinfeng     let key = key_buf.read_from_user(0)?;
353*fae6e9adSlinfeng     map.inner_map.lock().delete_elem(key)?;
354*fae6e9adSlinfeng     Ok(0)
355*fae6e9adSlinfeng }
356*fae6e9adSlinfeng 
357*fae6e9adSlinfeng /// Iterate and fetch multiple elements in a map.
358*fae6e9adSlinfeng ///
359*fae6e9adSlinfeng /// See https://ebpf-docs.dylanreimerink.nl/linux/syscall/BPF_MAP_LOOKUP_BATCH/
bpf_map_lookup_batch(_attr: &bpf_attr) -> Result<usize>360*fae6e9adSlinfeng pub fn bpf_map_lookup_batch(_attr: &bpf_attr) -> Result<usize> {
361*fae6e9adSlinfeng     todo!()
362*fae6e9adSlinfeng }
363*fae6e9adSlinfeng 
364*fae6e9adSlinfeng /// Look up an element with the given key in the map referred to by the file descriptor fd,
365*fae6e9adSlinfeng /// and if found, delete the element.
366*fae6e9adSlinfeng ///
367*fae6e9adSlinfeng /// For BPF_MAP_TYPE_QUEUE and BPF_MAP_TYPE_STACK map types, the flags argument needs to be set to 0,
368*fae6e9adSlinfeng /// but for other map types, it may be specified as:
369*fae6e9adSlinfeng /// - BPF_F_LOCK : If this flag is set, the command will acquire the spin-lock of the map value we are looking up.
370*fae6e9adSlinfeng ///
371*fae6e9adSlinfeng /// If the map contains no spin-lock in its value, -EINVAL will be returned by the command.
372*fae6e9adSlinfeng ///
373*fae6e9adSlinfeng /// The BPF_MAP_TYPE_QUEUE and BPF_MAP_TYPE_STACK map types implement this command as a “pop” operation,
374*fae6e9adSlinfeng /// deleting the top element rather than one corresponding to key.
375*fae6e9adSlinfeng /// The key and key_len parameters should be zeroed when issuing this operation for these map types.
376*fae6e9adSlinfeng ///
377*fae6e9adSlinfeng /// This command is only valid for the following map types:
378*fae6e9adSlinfeng /// - BPF_MAP_TYPE_QUEUE
379*fae6e9adSlinfeng /// - BPF_MAP_TYPE_STACK
380*fae6e9adSlinfeng /// - BPF_MAP_TYPE_HASH
381*fae6e9adSlinfeng /// - BPF_MAP_TYPE_PERCPU_HASH
382*fae6e9adSlinfeng /// - BPF_MAP_TYPE_LRU_HASH
383*fae6e9adSlinfeng /// - BPF_MAP_TYPE_LRU_PERCPU_HASH
384*fae6e9adSlinfeng ///
385*fae6e9adSlinfeng ///
386*fae6e9adSlinfeng /// See https://ebpf-docs.dylanreimerink.nl/linux/syscall/BPF_MAP_LOOKUP_AND_DELETE_ELEM/
bpf_map_lookup_and_delete_elem(attr: &bpf_attr) -> Result<usize>387*fae6e9adSlinfeng pub fn bpf_map_lookup_and_delete_elem(attr: &bpf_attr) -> Result<usize> {
388*fae6e9adSlinfeng     let arg = BpfMapUpdateArg::from(attr);
389*fae6e9adSlinfeng     // info!("<bpf_map_lookup_and_delete_elem>: {:#x?}", arg);
390*fae6e9adSlinfeng     let map = get_map_file(arg.map_fd as i32)?;
391*fae6e9adSlinfeng     let meta = &map.meta;
392*fae6e9adSlinfeng     let key_size = meta.key_size as usize;
393*fae6e9adSlinfeng     let value_size = meta.value_size as usize;
394*fae6e9adSlinfeng 
395*fae6e9adSlinfeng     let key_buf = UserBufferReader::new(arg.key as *const u8, key_size, true)?;
396*fae6e9adSlinfeng     let mut value_buf = UserBufferWriter::new(arg.value as *mut u8, value_size, true)?;
397*fae6e9adSlinfeng 
398*fae6e9adSlinfeng     let value = value_buf.buffer(0)?;
399*fae6e9adSlinfeng     let key = key_buf.read_from_user(0)?;
400*fae6e9adSlinfeng     let mut inner = map.inner_map.lock();
401*fae6e9adSlinfeng     inner.lookup_and_delete_elem(key, value)?;
402*fae6e9adSlinfeng     Ok(0)
403*fae6e9adSlinfeng }
404*fae6e9adSlinfeng 
get_map_file(fd: i32) -> Result<Arc<BpfMap>>405*fae6e9adSlinfeng fn get_map_file(fd: i32) -> Result<Arc<BpfMap>> {
406*fae6e9adSlinfeng     let fd_table = ProcessManager::current_pcb().fd_table();
407*fae6e9adSlinfeng     let map = fd_table
408*fae6e9adSlinfeng         .read()
409*fae6e9adSlinfeng         .get_file_by_fd(fd)
410*fae6e9adSlinfeng         .ok_or(SystemError::EBADF)?;
411*fae6e9adSlinfeng     let map = map
412*fae6e9adSlinfeng         .inode()
413*fae6e9adSlinfeng         .downcast_arc::<BpfMap>()
414*fae6e9adSlinfeng         .ok_or(SystemError::EINVAL)?;
415*fae6e9adSlinfeng     Ok(map)
416*fae6e9adSlinfeng }
417