xref: /DragonOS/kernel/src/bpf/map/array_map.rs (revision fae6e9ade46a52976ad5d099643d51cc20876448)
1*fae6e9adSlinfeng //! BPF_MAP_TYPE_ARRAY and BPF_MAP_TYPE_PERCPU_ARRAY
2*fae6e9adSlinfeng //!
3*fae6e9adSlinfeng //!
4*fae6e9adSlinfeng //! See https://docs.kernel.org/bpf/map_array.html
5*fae6e9adSlinfeng 
6*fae6e9adSlinfeng use super::super::Result;
7*fae6e9adSlinfeng use crate::bpf::map::util::round_up;
8*fae6e9adSlinfeng use crate::bpf::map::{BpfCallBackFn, BpfMapCommonOps, BpfMapMeta};
9*fae6e9adSlinfeng use crate::mm::percpu::{PerCpu, PerCpuVar};
10*fae6e9adSlinfeng use crate::smp::cpu::{smp_cpu_manager, ProcessorId};
11*fae6e9adSlinfeng use alloc::{vec, vec::Vec};
12*fae6e9adSlinfeng use core::{
13*fae6e9adSlinfeng     fmt::{Debug, Formatter},
14*fae6e9adSlinfeng     ops::{Index, IndexMut},
15*fae6e9adSlinfeng };
16*fae6e9adSlinfeng use log::info;
17*fae6e9adSlinfeng use system_error::SystemError;
18*fae6e9adSlinfeng 
19*fae6e9adSlinfeng /// The array map type is a generic map type with no restrictions on the structure of the value.
20*fae6e9adSlinfeng /// Like a normal array, the array map has a numeric key starting at 0 and incrementing.
21*fae6e9adSlinfeng ///
22*fae6e9adSlinfeng /// See https://ebpf-docs.dylanreimerink.nl/linux/map-type/BPF_MAP_TYPE_ARRAY/
23*fae6e9adSlinfeng #[derive(Debug)]
24*fae6e9adSlinfeng pub struct ArrayMap {
25*fae6e9adSlinfeng     max_entries: u32,
26*fae6e9adSlinfeng     data: ArrayMapData,
27*fae6e9adSlinfeng }
28*fae6e9adSlinfeng 
29*fae6e9adSlinfeng struct ArrayMapData {
30*fae6e9adSlinfeng     elem_size: u32,
31*fae6e9adSlinfeng     /// The data is stored in a Vec<u8> with the size of elem_size * max_entries.
32*fae6e9adSlinfeng     data: Vec<u8>,
33*fae6e9adSlinfeng }
34*fae6e9adSlinfeng 
35*fae6e9adSlinfeng impl Debug for ArrayMapData {
fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result36*fae6e9adSlinfeng     fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
37*fae6e9adSlinfeng         f.debug_struct("ArrayMapData")
38*fae6e9adSlinfeng             .field("elem_size", &self.elem_size)
39*fae6e9adSlinfeng             .field("data_len", &self.data.len())
40*fae6e9adSlinfeng             .finish()
41*fae6e9adSlinfeng     }
42*fae6e9adSlinfeng }
43*fae6e9adSlinfeng 
44*fae6e9adSlinfeng impl ArrayMapData {
new(elem_size: u32, max_entries: u32) -> Self45*fae6e9adSlinfeng     pub fn new(elem_size: u32, max_entries: u32) -> Self {
46*fae6e9adSlinfeng         debug_assert!(elem_size % 8 == 0);
47*fae6e9adSlinfeng         let total_size = elem_size * max_entries;
48*fae6e9adSlinfeng         let data = vec![0; total_size as usize];
49*fae6e9adSlinfeng         ArrayMapData { elem_size, data }
50*fae6e9adSlinfeng     }
51*fae6e9adSlinfeng }
52*fae6e9adSlinfeng 
53*fae6e9adSlinfeng impl Index<u32> for ArrayMapData {
54*fae6e9adSlinfeng     type Output = [u8];
index(&self, index: u32) -> &Self::Output55*fae6e9adSlinfeng     fn index(&self, index: u32) -> &Self::Output {
56*fae6e9adSlinfeng         let start = index * self.elem_size;
57*fae6e9adSlinfeng         &self.data[start as usize..(start + self.elem_size) as usize]
58*fae6e9adSlinfeng     }
59*fae6e9adSlinfeng }
60*fae6e9adSlinfeng 
61*fae6e9adSlinfeng impl IndexMut<u32> for ArrayMapData {
index_mut(&mut self, index: u32) -> &mut Self::Output62*fae6e9adSlinfeng     fn index_mut(&mut self, index: u32) -> &mut Self::Output {
63*fae6e9adSlinfeng         let start = index * self.elem_size;
64*fae6e9adSlinfeng         &mut self.data[start as usize..(start + self.elem_size) as usize]
65*fae6e9adSlinfeng     }
66*fae6e9adSlinfeng }
67*fae6e9adSlinfeng 
68*fae6e9adSlinfeng impl ArrayMap {
new(attr: &BpfMapMeta) -> Result<Self>69*fae6e9adSlinfeng     pub fn new(attr: &BpfMapMeta) -> Result<Self> {
70*fae6e9adSlinfeng         if attr.value_size == 0 || attr.max_entries == 0 || attr.key_size != 4 {
71*fae6e9adSlinfeng             return Err(SystemError::EINVAL);
72*fae6e9adSlinfeng         }
73*fae6e9adSlinfeng         let elem_size = round_up(attr.value_size as usize, 8);
74*fae6e9adSlinfeng         let data = ArrayMapData::new(elem_size as u32, attr.max_entries);
75*fae6e9adSlinfeng         Ok(ArrayMap {
76*fae6e9adSlinfeng             max_entries: attr.max_entries,
77*fae6e9adSlinfeng             data,
78*fae6e9adSlinfeng         })
79*fae6e9adSlinfeng     }
80*fae6e9adSlinfeng }
81*fae6e9adSlinfeng 
82*fae6e9adSlinfeng impl BpfMapCommonOps for ArrayMap {
lookup_elem(&mut self, key: &[u8]) -> Result<Option<&[u8]>>83*fae6e9adSlinfeng     fn lookup_elem(&mut self, key: &[u8]) -> Result<Option<&[u8]>> {
84*fae6e9adSlinfeng         if key.len() != 4 {
85*fae6e9adSlinfeng             return Err(SystemError::EINVAL);
86*fae6e9adSlinfeng         }
87*fae6e9adSlinfeng         let index = u32::from_ne_bytes(key.try_into().map_err(|_| SystemError::EINVAL)?);
88*fae6e9adSlinfeng         if index >= self.max_entries {
89*fae6e9adSlinfeng             return Err(SystemError::EINVAL);
90*fae6e9adSlinfeng         }
91*fae6e9adSlinfeng         let val = self.data.index(index);
92*fae6e9adSlinfeng         Ok(Some(val))
93*fae6e9adSlinfeng     }
update_elem(&mut self, key: &[u8], value: &[u8], _flags: u64) -> Result<()>94*fae6e9adSlinfeng     fn update_elem(&mut self, key: &[u8], value: &[u8], _flags: u64) -> Result<()> {
95*fae6e9adSlinfeng         if key.len() != 4 {
96*fae6e9adSlinfeng             return Err(SystemError::EINVAL);
97*fae6e9adSlinfeng         }
98*fae6e9adSlinfeng         let index = u32::from_ne_bytes(key.try_into().map_err(|_| SystemError::EINVAL)?);
99*fae6e9adSlinfeng         if index >= self.max_entries {
100*fae6e9adSlinfeng             return Err(SystemError::EINVAL);
101*fae6e9adSlinfeng         }
102*fae6e9adSlinfeng         if value.len() > self.data.elem_size as usize {
103*fae6e9adSlinfeng             return Err(SystemError::EINVAL);
104*fae6e9adSlinfeng         }
105*fae6e9adSlinfeng         let old_value = self.data.index_mut(index);
106*fae6e9adSlinfeng         old_value[..value.len()].copy_from_slice(value);
107*fae6e9adSlinfeng         Ok(())
108*fae6e9adSlinfeng     }
109*fae6e9adSlinfeng     /// For ArrayMap, delete_elem is not supported.
delete_elem(&mut self, _key: &[u8]) -> Result<()>110*fae6e9adSlinfeng     fn delete_elem(&mut self, _key: &[u8]) -> Result<()> {
111*fae6e9adSlinfeng         Err(SystemError::EINVAL)
112*fae6e9adSlinfeng     }
for_each_elem(&mut self, cb: BpfCallBackFn, ctx: *const u8, flags: u64) -> Result<u32>113*fae6e9adSlinfeng     fn for_each_elem(&mut self, cb: BpfCallBackFn, ctx: *const u8, flags: u64) -> Result<u32> {
114*fae6e9adSlinfeng         if flags != 0 {
115*fae6e9adSlinfeng             return Err(SystemError::EINVAL);
116*fae6e9adSlinfeng         }
117*fae6e9adSlinfeng         let mut total_used = 0;
118*fae6e9adSlinfeng         for i in 0..self.max_entries {
119*fae6e9adSlinfeng             let key = i.to_ne_bytes();
120*fae6e9adSlinfeng             let value = self.data.index(i);
121*fae6e9adSlinfeng             total_used += 1;
122*fae6e9adSlinfeng             let res = cb(&key, value, ctx);
123*fae6e9adSlinfeng             // return value: 0 - continue, 1 - stop and return
124*fae6e9adSlinfeng             if res != 0 {
125*fae6e9adSlinfeng                 break;
126*fae6e9adSlinfeng             }
127*fae6e9adSlinfeng         }
128*fae6e9adSlinfeng         Ok(total_used)
129*fae6e9adSlinfeng     }
130*fae6e9adSlinfeng 
lookup_and_delete_elem(&mut self, _key: &[u8], _value: &mut [u8]) -> Result<()>131*fae6e9adSlinfeng     fn lookup_and_delete_elem(&mut self, _key: &[u8], _value: &mut [u8]) -> Result<()> {
132*fae6e9adSlinfeng         Err(SystemError::EINVAL)
133*fae6e9adSlinfeng     }
134*fae6e9adSlinfeng 
get_next_key(&self, key: Option<&[u8]>, next_key: &mut [u8]) -> Result<()>135*fae6e9adSlinfeng     fn get_next_key(&self, key: Option<&[u8]>, next_key: &mut [u8]) -> Result<()> {
136*fae6e9adSlinfeng         if let Some(key) = key {
137*fae6e9adSlinfeng             if key.len() != 4 {
138*fae6e9adSlinfeng                 return Err(SystemError::EINVAL);
139*fae6e9adSlinfeng             }
140*fae6e9adSlinfeng             let index = u32::from_ne_bytes(key.try_into().map_err(|_| SystemError::EINVAL)?);
141*fae6e9adSlinfeng             if index == self.max_entries - 1 {
142*fae6e9adSlinfeng                 return Err(SystemError::ENOENT);
143*fae6e9adSlinfeng             }
144*fae6e9adSlinfeng             let next_index = index + 1;
145*fae6e9adSlinfeng             next_key.copy_from_slice(&next_index.to_ne_bytes());
146*fae6e9adSlinfeng         } else {
147*fae6e9adSlinfeng             next_key.copy_from_slice(&0u32.to_ne_bytes());
148*fae6e9adSlinfeng         }
149*fae6e9adSlinfeng         Ok(())
150*fae6e9adSlinfeng     }
151*fae6e9adSlinfeng 
freeze(&self) -> Result<()>152*fae6e9adSlinfeng     fn freeze(&self) -> Result<()> {
153*fae6e9adSlinfeng         info!("fake freeze done for ArrayMap");
154*fae6e9adSlinfeng         Ok(())
155*fae6e9adSlinfeng     }
first_value_ptr(&self) -> Result<*const u8>156*fae6e9adSlinfeng     fn first_value_ptr(&self) -> Result<*const u8> {
157*fae6e9adSlinfeng         Ok(self.data.data.as_ptr())
158*fae6e9adSlinfeng     }
159*fae6e9adSlinfeng }
160*fae6e9adSlinfeng 
161*fae6e9adSlinfeng /// This is the per-CPU variant of the [ArrayMap] map type.
162*fae6e9adSlinfeng ///
163*fae6e9adSlinfeng /// See https://ebpf-docs.dylanreimerink.nl/linux/map-type/BPF_MAP_TYPE_PERCPU_ARRAY/
164*fae6e9adSlinfeng pub struct PerCpuArrayMap {
165*fae6e9adSlinfeng     per_cpu_data: PerCpuVar<ArrayMap>,
166*fae6e9adSlinfeng }
167*fae6e9adSlinfeng 
168*fae6e9adSlinfeng impl Debug for PerCpuArrayMap {
fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result169*fae6e9adSlinfeng     fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
170*fae6e9adSlinfeng         f.debug_struct("PerCpuArrayMap")
171*fae6e9adSlinfeng             .field("data", &self.per_cpu_data)
172*fae6e9adSlinfeng             .finish()
173*fae6e9adSlinfeng     }
174*fae6e9adSlinfeng }
175*fae6e9adSlinfeng 
176*fae6e9adSlinfeng impl PerCpuArrayMap {
new(attr: &BpfMapMeta) -> Result<Self>177*fae6e9adSlinfeng     pub fn new(attr: &BpfMapMeta) -> Result<Self> {
178*fae6e9adSlinfeng         let num_cpus = PerCpu::MAX_CPU_NUM;
179*fae6e9adSlinfeng         let mut data = Vec::with_capacity(num_cpus as usize);
180*fae6e9adSlinfeng         for _ in 0..num_cpus {
181*fae6e9adSlinfeng             let array_map = ArrayMap::new(attr)?;
182*fae6e9adSlinfeng             data.push(array_map);
183*fae6e9adSlinfeng         }
184*fae6e9adSlinfeng         let per_cpu_data = PerCpuVar::new(data).ok_or(SystemError::EINVAL)?;
185*fae6e9adSlinfeng         Ok(PerCpuArrayMap { per_cpu_data })
186*fae6e9adSlinfeng     }
187*fae6e9adSlinfeng }
188*fae6e9adSlinfeng 
189*fae6e9adSlinfeng impl BpfMapCommonOps for PerCpuArrayMap {
lookup_elem(&mut self, key: &[u8]) -> Result<Option<&[u8]>>190*fae6e9adSlinfeng     fn lookup_elem(&mut self, key: &[u8]) -> Result<Option<&[u8]>> {
191*fae6e9adSlinfeng         self.per_cpu_data.get_mut().lookup_elem(key)
192*fae6e9adSlinfeng     }
update_elem(&mut self, key: &[u8], value: &[u8], flags: u64) -> Result<()>193*fae6e9adSlinfeng     fn update_elem(&mut self, key: &[u8], value: &[u8], flags: u64) -> Result<()> {
194*fae6e9adSlinfeng         self.per_cpu_data.get_mut().update_elem(key, value, flags)
195*fae6e9adSlinfeng     }
delete_elem(&mut self, key: &[u8]) -> Result<()>196*fae6e9adSlinfeng     fn delete_elem(&mut self, key: &[u8]) -> Result<()> {
197*fae6e9adSlinfeng         self.per_cpu_data.get_mut().delete_elem(key)
198*fae6e9adSlinfeng     }
for_each_elem(&mut self, cb: BpfCallBackFn, ctx: *const u8, flags: u64) -> Result<u32>199*fae6e9adSlinfeng     fn for_each_elem(&mut self, cb: BpfCallBackFn, ctx: *const u8, flags: u64) -> Result<u32> {
200*fae6e9adSlinfeng         self.per_cpu_data.get_mut().for_each_elem(cb, ctx, flags)
201*fae6e9adSlinfeng     }
lookup_and_delete_elem(&mut self, _key: &[u8], _value: &mut [u8]) -> Result<()>202*fae6e9adSlinfeng     fn lookup_and_delete_elem(&mut self, _key: &[u8], _value: &mut [u8]) -> Result<()> {
203*fae6e9adSlinfeng         Err(SystemError::EINVAL)
204*fae6e9adSlinfeng     }
lookup_percpu_elem(&mut self, key: &[u8], cpu: u32) -> Result<Option<&[u8]>>205*fae6e9adSlinfeng     fn lookup_percpu_elem(&mut self, key: &[u8], cpu: u32) -> Result<Option<&[u8]>> {
206*fae6e9adSlinfeng         unsafe {
207*fae6e9adSlinfeng             self.per_cpu_data
208*fae6e9adSlinfeng                 .force_get_mut(ProcessorId::new(cpu))
209*fae6e9adSlinfeng                 .lookup_elem(key)
210*fae6e9adSlinfeng         }
211*fae6e9adSlinfeng     }
get_next_key(&self, key: Option<&[u8]>, next_key: &mut [u8]) -> Result<()>212*fae6e9adSlinfeng     fn get_next_key(&self, key: Option<&[u8]>, next_key: &mut [u8]) -> Result<()> {
213*fae6e9adSlinfeng         self.per_cpu_data.get_mut().get_next_key(key, next_key)
214*fae6e9adSlinfeng     }
first_value_ptr(&self) -> Result<*const u8>215*fae6e9adSlinfeng     fn first_value_ptr(&self) -> Result<*const u8> {
216*fae6e9adSlinfeng         self.per_cpu_data.get_mut().first_value_ptr()
217*fae6e9adSlinfeng     }
218*fae6e9adSlinfeng }
219*fae6e9adSlinfeng 
220*fae6e9adSlinfeng /// See https://ebpf-docs.dylanreimerink.nl/linux/map-type/BPF_MAP_TYPE_PERF_EVENT_ARRAY/
221*fae6e9adSlinfeng pub struct PerfEventArrayMap {
222*fae6e9adSlinfeng     // The value is the file descriptor of the perf event.
223*fae6e9adSlinfeng     fds: ArrayMapData,
224*fae6e9adSlinfeng }
225*fae6e9adSlinfeng 
226*fae6e9adSlinfeng impl Debug for PerfEventArrayMap {
fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result227*fae6e9adSlinfeng     fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
228*fae6e9adSlinfeng         f.debug_struct("PerfEventArrayMap")
229*fae6e9adSlinfeng             .field("fds", &self.fds)
230*fae6e9adSlinfeng             .finish()
231*fae6e9adSlinfeng     }
232*fae6e9adSlinfeng }
233*fae6e9adSlinfeng 
234*fae6e9adSlinfeng impl PerfEventArrayMap {
new(attr: &BpfMapMeta) -> Result<Self>235*fae6e9adSlinfeng     pub fn new(attr: &BpfMapMeta) -> Result<Self> {
236*fae6e9adSlinfeng         let num_cpus = smp_cpu_manager().possible_cpus_count();
237*fae6e9adSlinfeng         if attr.key_size != 4 || attr.value_size != 4 || attr.max_entries != num_cpus {
238*fae6e9adSlinfeng             return Err(SystemError::EINVAL);
239*fae6e9adSlinfeng         }
240*fae6e9adSlinfeng         let fds = ArrayMapData::new(4, num_cpus);
241*fae6e9adSlinfeng         Ok(PerfEventArrayMap { fds })
242*fae6e9adSlinfeng     }
243*fae6e9adSlinfeng }
244*fae6e9adSlinfeng 
245*fae6e9adSlinfeng impl BpfMapCommonOps for PerfEventArrayMap {
lookup_elem(&mut self, key: &[u8]) -> Result<Option<&[u8]>>246*fae6e9adSlinfeng     fn lookup_elem(&mut self, key: &[u8]) -> Result<Option<&[u8]>> {
247*fae6e9adSlinfeng         let cpu_id = u32::from_ne_bytes(key.try_into().map_err(|_| SystemError::EINVAL)?);
248*fae6e9adSlinfeng         let value = self.fds.index(cpu_id);
249*fae6e9adSlinfeng         Ok(Some(value))
250*fae6e9adSlinfeng     }
update_elem(&mut self, key: &[u8], value: &[u8], _flags: u64) -> Result<()>251*fae6e9adSlinfeng     fn update_elem(&mut self, key: &[u8], value: &[u8], _flags: u64) -> Result<()> {
252*fae6e9adSlinfeng         assert_eq!(value.len(), 4);
253*fae6e9adSlinfeng         let cpu_id = u32::from_ne_bytes(key.try_into().map_err(|_| SystemError::EINVAL)?);
254*fae6e9adSlinfeng         let old_value = self.fds.index_mut(cpu_id);
255*fae6e9adSlinfeng         old_value.copy_from_slice(value);
256*fae6e9adSlinfeng         Ok(())
257*fae6e9adSlinfeng     }
delete_elem(&mut self, key: &[u8]) -> Result<()>258*fae6e9adSlinfeng     fn delete_elem(&mut self, key: &[u8]) -> Result<()> {
259*fae6e9adSlinfeng         let cpu_id = u32::from_ne_bytes(key.try_into().map_err(|_| SystemError::EINVAL)?);
260*fae6e9adSlinfeng         self.fds.index_mut(cpu_id).copy_from_slice(&[0; 4]);
261*fae6e9adSlinfeng         Ok(())
262*fae6e9adSlinfeng     }
for_each_elem(&mut self, cb: BpfCallBackFn, ctx: *const u8, _flags: u64) -> Result<u32>263*fae6e9adSlinfeng     fn for_each_elem(&mut self, cb: BpfCallBackFn, ctx: *const u8, _flags: u64) -> Result<u32> {
264*fae6e9adSlinfeng         let mut total_used = 0;
265*fae6e9adSlinfeng         let num_cpus = smp_cpu_manager().possible_cpus_count();
266*fae6e9adSlinfeng         for i in 0..num_cpus {
267*fae6e9adSlinfeng             let key = i.to_ne_bytes();
268*fae6e9adSlinfeng             let value = self.fds.index(i);
269*fae6e9adSlinfeng             total_used += 1;
270*fae6e9adSlinfeng             let res = cb(&key, value, ctx);
271*fae6e9adSlinfeng             if res != 0 {
272*fae6e9adSlinfeng                 break;
273*fae6e9adSlinfeng             }
274*fae6e9adSlinfeng         }
275*fae6e9adSlinfeng         Ok(total_used)
276*fae6e9adSlinfeng     }
lookup_and_delete_elem(&mut self, _key: &[u8], _value: &mut [u8]) -> Result<()>277*fae6e9adSlinfeng     fn lookup_and_delete_elem(&mut self, _key: &[u8], _value: &mut [u8]) -> Result<()> {
278*fae6e9adSlinfeng         Err(SystemError::EINVAL)
279*fae6e9adSlinfeng     }
first_value_ptr(&self) -> Result<*const u8>280*fae6e9adSlinfeng     fn first_value_ptr(&self) -> Result<*const u8> {
281*fae6e9adSlinfeng         Ok(self.fds.data.as_ptr())
282*fae6e9adSlinfeng     }
283*fae6e9adSlinfeng }
284