xref: /DragonOS/kernel/src/bpf/map/hash_map.rs (revision fae6e9ade46a52976ad5d099643d51cc20876448)
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