1*fae6e9adSlinfeng use super::Result; 2*fae6e9adSlinfeng use crate::bpf::map::util::{round_up, BpfMapUpdateElemFlags}; 3*fae6e9adSlinfeng use crate::bpf::map::{BpfCallBackFn, BpfMapCommonOps, BpfMapMeta}; 4*fae6e9adSlinfeng use crate::mm::percpu::{PerCpu, PerCpuVar}; 5*fae6e9adSlinfeng use crate::smp::cpu::ProcessorId; 6*fae6e9adSlinfeng use alloc::{collections::BTreeMap, vec::Vec}; 7*fae6e9adSlinfeng use core::fmt::Debug; 8*fae6e9adSlinfeng use system_error::SystemError; 9*fae6e9adSlinfeng 10*fae6e9adSlinfeng type BpfHashMapKey = Vec<u8>; 11*fae6e9adSlinfeng type BpfHashMapValue = Vec<u8>; 12*fae6e9adSlinfeng 13*fae6e9adSlinfeng /// The hash map type is a generic map type with no restrictions on the structure of the key and value. 14*fae6e9adSlinfeng /// Hash-maps are implemented using a hash table, allowing for lookups with arbitrary keys. 15*fae6e9adSlinfeng /// 16*fae6e9adSlinfeng /// See https://ebpf-docs.dylanreimerink.nl/linux/map-type/BPF_MAP_TYPE_HASH/ 17*fae6e9adSlinfeng #[derive(Debug)] 18*fae6e9adSlinfeng pub struct BpfHashMap { 19*fae6e9adSlinfeng _max_entries: u32, 20*fae6e9adSlinfeng _key_size: u32, 21*fae6e9adSlinfeng _value_size: u32, 22*fae6e9adSlinfeng data: BTreeMap<BpfHashMapKey, BpfHashMapValue>, 23*fae6e9adSlinfeng } 24*fae6e9adSlinfeng 25*fae6e9adSlinfeng impl BpfHashMap { new(attr: &BpfMapMeta) -> Result<Self>26*fae6e9adSlinfeng pub fn new(attr: &BpfMapMeta) -> Result<Self> { 27*fae6e9adSlinfeng if attr.value_size == 0 || attr.max_entries == 0 { 28*fae6e9adSlinfeng return Err(SystemError::EINVAL); 29*fae6e9adSlinfeng } 30*fae6e9adSlinfeng let value_size = round_up(attr.value_size as usize, 8); 31*fae6e9adSlinfeng Ok(Self { 32*fae6e9adSlinfeng _max_entries: attr.max_entries, 33*fae6e9adSlinfeng _key_size: attr.key_size, 34*fae6e9adSlinfeng _value_size: value_size as u32, 35*fae6e9adSlinfeng data: BTreeMap::new(), 36*fae6e9adSlinfeng }) 37*fae6e9adSlinfeng } 38*fae6e9adSlinfeng } 39*fae6e9adSlinfeng 40*fae6e9adSlinfeng impl BpfMapCommonOps for BpfHashMap { lookup_elem(&mut self, key: &[u8]) -> Result<Option<&[u8]>>41*fae6e9adSlinfeng fn lookup_elem(&mut self, key: &[u8]) -> Result<Option<&[u8]>> { 42*fae6e9adSlinfeng let value = self.data.get(key).map(|v| v.as_slice()); 43*fae6e9adSlinfeng Ok(value) 44*fae6e9adSlinfeng } update_elem(&mut self, key: &[u8], value: &[u8], flags: u64) -> Result<()>45*fae6e9adSlinfeng fn update_elem(&mut self, key: &[u8], value: &[u8], flags: u64) -> Result<()> { 46*fae6e9adSlinfeng let _flags = BpfMapUpdateElemFlags::from_bits_truncate(flags); 47*fae6e9adSlinfeng self.data.insert(key.to_vec(), value.to_vec()); 48*fae6e9adSlinfeng Ok(()) 49*fae6e9adSlinfeng } delete_elem(&mut self, key: &[u8]) -> Result<()>50*fae6e9adSlinfeng fn delete_elem(&mut self, key: &[u8]) -> Result<()> { 51*fae6e9adSlinfeng self.data.remove(key); 52*fae6e9adSlinfeng Ok(()) 53*fae6e9adSlinfeng } for_each_elem(&mut self, cb: BpfCallBackFn, ctx: *const u8, flags: u64) -> Result<u32>54*fae6e9adSlinfeng fn for_each_elem(&mut self, cb: BpfCallBackFn, ctx: *const u8, flags: u64) -> Result<u32> { 55*fae6e9adSlinfeng if flags != 0 { 56*fae6e9adSlinfeng return Err(SystemError::EINVAL); 57*fae6e9adSlinfeng } 58*fae6e9adSlinfeng let mut total_used = 0; 59*fae6e9adSlinfeng for (key, value) in self.data.iter() { 60*fae6e9adSlinfeng let res = cb(key, value, ctx); 61*fae6e9adSlinfeng // return value: 0 - continue, 1 - stop and return 62*fae6e9adSlinfeng if res != 0 { 63*fae6e9adSlinfeng break; 64*fae6e9adSlinfeng } 65*fae6e9adSlinfeng total_used += 1; 66*fae6e9adSlinfeng } 67*fae6e9adSlinfeng Ok(total_used) 68*fae6e9adSlinfeng } lookup_and_delete_elem(&mut self, key: &[u8], value: &mut [u8]) -> Result<()>69*fae6e9adSlinfeng fn lookup_and_delete_elem(&mut self, key: &[u8], value: &mut [u8]) -> Result<()> { 70*fae6e9adSlinfeng let v = self 71*fae6e9adSlinfeng .data 72*fae6e9adSlinfeng .get(key) 73*fae6e9adSlinfeng .map(|v| v.as_slice()) 74*fae6e9adSlinfeng .ok_or(SystemError::ENOENT)?; 75*fae6e9adSlinfeng value.copy_from_slice(v); 76*fae6e9adSlinfeng self.data.remove(key); 77*fae6e9adSlinfeng Ok(()) 78*fae6e9adSlinfeng } get_next_key(&self, key: Option<&[u8]>, next_key: &mut [u8]) -> Result<()>79*fae6e9adSlinfeng fn get_next_key(&self, key: Option<&[u8]>, next_key: &mut [u8]) -> Result<()> { 80*fae6e9adSlinfeng let mut iter = self.data.iter(); 81*fae6e9adSlinfeng if let Some(key) = key { 82*fae6e9adSlinfeng for (k, _) in iter.by_ref() { 83*fae6e9adSlinfeng if k.as_slice() == key { 84*fae6e9adSlinfeng break; 85*fae6e9adSlinfeng } 86*fae6e9adSlinfeng } 87*fae6e9adSlinfeng } 88*fae6e9adSlinfeng let res = iter.next(); 89*fae6e9adSlinfeng match res { 90*fae6e9adSlinfeng Some((k, _)) => { 91*fae6e9adSlinfeng next_key.copy_from_slice(k.as_slice()); 92*fae6e9adSlinfeng Ok(()) 93*fae6e9adSlinfeng } 94*fae6e9adSlinfeng None => Err(SystemError::ENOENT), 95*fae6e9adSlinfeng } 96*fae6e9adSlinfeng } 97*fae6e9adSlinfeng } 98*fae6e9adSlinfeng 99*fae6e9adSlinfeng /// This is the per-CPU variant of the [BpfHashMap] map type. 100*fae6e9adSlinfeng /// 101*fae6e9adSlinfeng /// See https://ebpf-docs.dylanreimerink.nl/linux/map-type/BPF_MAP_TYPE_PERCPU_HASH/ 102*fae6e9adSlinfeng pub struct PerCpuHashMap { 103*fae6e9adSlinfeng per_cpu_maps: PerCpuVar<BpfHashMap>, 104*fae6e9adSlinfeng } 105*fae6e9adSlinfeng 106*fae6e9adSlinfeng impl Debug for PerCpuHashMap { fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result107*fae6e9adSlinfeng fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { 108*fae6e9adSlinfeng f.debug_struct("PerCpuHashMap") 109*fae6e9adSlinfeng .field("maps", &self.per_cpu_maps) 110*fae6e9adSlinfeng .finish() 111*fae6e9adSlinfeng } 112*fae6e9adSlinfeng } 113*fae6e9adSlinfeng impl PerCpuHashMap { new(attr: &BpfMapMeta) -> Result<Self>114*fae6e9adSlinfeng pub fn new(attr: &BpfMapMeta) -> Result<Self> { 115*fae6e9adSlinfeng let num_cpus = PerCpu::MAX_CPU_NUM; 116*fae6e9adSlinfeng let mut data = Vec::with_capacity(num_cpus as usize); 117*fae6e9adSlinfeng for _ in 0..num_cpus { 118*fae6e9adSlinfeng let array_map = BpfHashMap::new(attr)?; 119*fae6e9adSlinfeng data.push(array_map); 120*fae6e9adSlinfeng } 121*fae6e9adSlinfeng let per_cpu_maps = PerCpuVar::new(data).ok_or(SystemError::EINVAL)?; 122*fae6e9adSlinfeng Ok(PerCpuHashMap { per_cpu_maps }) 123*fae6e9adSlinfeng } 124*fae6e9adSlinfeng } 125*fae6e9adSlinfeng impl BpfMapCommonOps for PerCpuHashMap { lookup_elem(&mut self, key: &[u8]) -> Result<Option<&[u8]>>126*fae6e9adSlinfeng fn lookup_elem(&mut self, key: &[u8]) -> Result<Option<&[u8]>> { 127*fae6e9adSlinfeng self.per_cpu_maps.get_mut().lookup_elem(key) 128*fae6e9adSlinfeng } update_elem(&mut self, key: &[u8], value: &[u8], flags: u64) -> Result<()>129*fae6e9adSlinfeng fn update_elem(&mut self, key: &[u8], value: &[u8], flags: u64) -> Result<()> { 130*fae6e9adSlinfeng self.per_cpu_maps.get_mut().update_elem(key, value, flags) 131*fae6e9adSlinfeng } delete_elem(&mut self, key: &[u8]) -> Result<()>132*fae6e9adSlinfeng fn delete_elem(&mut self, key: &[u8]) -> Result<()> { 133*fae6e9adSlinfeng self.per_cpu_maps.get_mut().delete_elem(key) 134*fae6e9adSlinfeng } for_each_elem(&mut self, cb: BpfCallBackFn, ctx: *const u8, flags: u64) -> Result<u32>135*fae6e9adSlinfeng fn for_each_elem(&mut self, cb: BpfCallBackFn, ctx: *const u8, flags: u64) -> Result<u32> { 136*fae6e9adSlinfeng self.per_cpu_maps.get_mut().for_each_elem(cb, ctx, flags) 137*fae6e9adSlinfeng } lookup_and_delete_elem(&mut self, key: &[u8], value: &mut [u8]) -> Result<()>138*fae6e9adSlinfeng fn lookup_and_delete_elem(&mut self, key: &[u8], value: &mut [u8]) -> Result<()> { 139*fae6e9adSlinfeng self.per_cpu_maps 140*fae6e9adSlinfeng .get_mut() 141*fae6e9adSlinfeng .lookup_and_delete_elem(key, value) 142*fae6e9adSlinfeng } lookup_percpu_elem(&mut self, key: &[u8], cpu: u32) -> Result<Option<&[u8]>>143*fae6e9adSlinfeng fn lookup_percpu_elem(&mut self, key: &[u8], cpu: u32) -> Result<Option<&[u8]>> { 144*fae6e9adSlinfeng unsafe { 145*fae6e9adSlinfeng self.per_cpu_maps 146*fae6e9adSlinfeng .force_get_mut(ProcessorId::new(cpu)) 147*fae6e9adSlinfeng .lookup_elem(key) 148*fae6e9adSlinfeng } 149*fae6e9adSlinfeng } get_next_key(&self, key: Option<&[u8]>, next_key: &mut [u8]) -> Result<()>150*fae6e9adSlinfeng fn get_next_key(&self, key: Option<&[u8]>, next_key: &mut [u8]) -> Result<()> { 151*fae6e9adSlinfeng self.per_cpu_maps.get_mut().get_next_key(key, next_key) 152*fae6e9adSlinfeng } first_value_ptr(&self) -> Result<*const u8>153*fae6e9adSlinfeng fn first_value_ptr(&self) -> Result<*const u8> { 154*fae6e9adSlinfeng self.per_cpu_maps.get_mut().first_value_ptr() 155*fae6e9adSlinfeng } 156*fae6e9adSlinfeng } 157