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