xref: /DragonOS/kernel/src/bpf/map/lru.rs (revision fae6e9ade46a52976ad5d099643d51cc20876448)
1*fae6e9adSlinfeng use super::{BpfCallBackFn, BpfMapCommonOps, Result};
2*fae6e9adSlinfeng use crate::bpf::map::util::BpfMapMeta;
3*fae6e9adSlinfeng use crate::mm::percpu::{PerCpu, PerCpuVar};
4*fae6e9adSlinfeng use crate::smp::cpu::ProcessorId;
5*fae6e9adSlinfeng use alloc::vec::Vec;
6*fae6e9adSlinfeng use core::fmt::Debug;
7*fae6e9adSlinfeng use core::num::NonZero;
8*fae6e9adSlinfeng use lru::LruCache;
9*fae6e9adSlinfeng use system_error::SystemError;
10*fae6e9adSlinfeng 
11*fae6e9adSlinfeng type BpfHashMapKey = Vec<u8>;
12*fae6e9adSlinfeng type BpfHashMapValue = Vec<u8>;
13*fae6e9adSlinfeng /// This map is the LRU (Least Recently Used) variant of the BPF_MAP_TYPE_HASH.
14*fae6e9adSlinfeng /// It is a generic map type that stores a fixed maximum number of key/value pairs.
15*fae6e9adSlinfeng /// When the map starts to get at capacity, the approximately least recently
16*fae6e9adSlinfeng /// used elements is removed to make room for new elements.
17*fae6e9adSlinfeng ///
18*fae6e9adSlinfeng /// See https://docs.ebpf.io/linux/map-type/BPF_MAP_TYPE_LRU_HASH/
19*fae6e9adSlinfeng #[derive(Debug)]
20*fae6e9adSlinfeng pub struct LruMap {
21*fae6e9adSlinfeng     _max_entries: u32,
22*fae6e9adSlinfeng     data: LruCache<BpfHashMapKey, BpfHashMapValue>,
23*fae6e9adSlinfeng }
24*fae6e9adSlinfeng 
25*fae6e9adSlinfeng impl LruMap {
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         Ok(Self {
31*fae6e9adSlinfeng             _max_entries: attr.max_entries,
32*fae6e9adSlinfeng             data: LruCache::new(
33*fae6e9adSlinfeng                 NonZero::new(attr.max_entries as usize).ok_or(SystemError::EINVAL)?,
34*fae6e9adSlinfeng             ),
35*fae6e9adSlinfeng         })
36*fae6e9adSlinfeng     }
37*fae6e9adSlinfeng }
38*fae6e9adSlinfeng 
39*fae6e9adSlinfeng impl BpfMapCommonOps for LruMap {
lookup_elem(&mut self, key: &[u8]) -> Result<Option<&[u8]>>40*fae6e9adSlinfeng     fn lookup_elem(&mut self, key: &[u8]) -> Result<Option<&[u8]>> {
41*fae6e9adSlinfeng         let value = self.data.get(key).map(|v| v.as_slice());
42*fae6e9adSlinfeng         Ok(value)
43*fae6e9adSlinfeng     }
update_elem(&mut self, key: &[u8], value: &[u8], _flags: u64) -> Result<()>44*fae6e9adSlinfeng     fn update_elem(&mut self, key: &[u8], value: &[u8], _flags: u64) -> Result<()> {
45*fae6e9adSlinfeng         self.data.put(key.to_vec(), value.to_vec());
46*fae6e9adSlinfeng         Ok(())
47*fae6e9adSlinfeng     }
delete_elem(&mut self, key: &[u8]) -> Result<()>48*fae6e9adSlinfeng     fn delete_elem(&mut self, key: &[u8]) -> Result<()> {
49*fae6e9adSlinfeng         self.data.pop(key);
50*fae6e9adSlinfeng         Ok(())
51*fae6e9adSlinfeng     }
for_each_elem(&mut self, cb: BpfCallBackFn, ctx: *const u8, flags: u64) -> Result<u32>52*fae6e9adSlinfeng     fn for_each_elem(&mut self, cb: BpfCallBackFn, ctx: *const u8, flags: u64) -> Result<u32> {
53*fae6e9adSlinfeng         if flags != 0 {
54*fae6e9adSlinfeng             return Err(SystemError::EINVAL);
55*fae6e9adSlinfeng         }
56*fae6e9adSlinfeng         let mut total_used = 0;
57*fae6e9adSlinfeng         for (key, value) in self.data.iter() {
58*fae6e9adSlinfeng             let res = cb(key, value, ctx);
59*fae6e9adSlinfeng             // return value: 0 - continue, 1 - stop and return
60*fae6e9adSlinfeng             if res != 0 {
61*fae6e9adSlinfeng                 break;
62*fae6e9adSlinfeng             }
63*fae6e9adSlinfeng             total_used += 1;
64*fae6e9adSlinfeng         }
65*fae6e9adSlinfeng         Ok(total_used)
66*fae6e9adSlinfeng     }
lookup_and_delete_elem(&mut self, key: &[u8], value: &mut [u8]) -> Result<()>67*fae6e9adSlinfeng     fn lookup_and_delete_elem(&mut self, key: &[u8], value: &mut [u8]) -> Result<()> {
68*fae6e9adSlinfeng         let v = self
69*fae6e9adSlinfeng             .data
70*fae6e9adSlinfeng             .get(key)
71*fae6e9adSlinfeng             .map(|v| v.as_slice())
72*fae6e9adSlinfeng             .ok_or(SystemError::ENOENT)?;
73*fae6e9adSlinfeng         value.copy_from_slice(v);
74*fae6e9adSlinfeng         self.data.pop(key);
75*fae6e9adSlinfeng         Ok(())
76*fae6e9adSlinfeng     }
get_next_key(&self, key: Option<&[u8]>, next_key: &mut [u8]) -> Result<()>77*fae6e9adSlinfeng     fn get_next_key(&self, key: Option<&[u8]>, next_key: &mut [u8]) -> Result<()> {
78*fae6e9adSlinfeng         let mut iter = self.data.iter();
79*fae6e9adSlinfeng         if let Some(key) = key {
80*fae6e9adSlinfeng             for (k, _) in iter.by_ref() {
81*fae6e9adSlinfeng                 if k.as_slice() == key {
82*fae6e9adSlinfeng                     break;
83*fae6e9adSlinfeng                 }
84*fae6e9adSlinfeng             }
85*fae6e9adSlinfeng         }
86*fae6e9adSlinfeng         let res = iter.next();
87*fae6e9adSlinfeng         match res {
88*fae6e9adSlinfeng             Some((k, _)) => {
89*fae6e9adSlinfeng                 next_key.copy_from_slice(k.as_slice());
90*fae6e9adSlinfeng                 Ok(())
91*fae6e9adSlinfeng             }
92*fae6e9adSlinfeng             None => Err(SystemError::ENOENT),
93*fae6e9adSlinfeng         }
94*fae6e9adSlinfeng     }
95*fae6e9adSlinfeng }
96*fae6e9adSlinfeng 
97*fae6e9adSlinfeng /// See https://ebpf-docs.dylanreimerink.nl/linux/map-type/BPF_MAP_TYPE_LRU_PERCPU_HASH/
98*fae6e9adSlinfeng pub struct PerCpuLruMap {
99*fae6e9adSlinfeng     per_cpu_maps: PerCpuVar<LruMap>,
100*fae6e9adSlinfeng }
101*fae6e9adSlinfeng 
102*fae6e9adSlinfeng impl Debug for PerCpuLruMap {
fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result103*fae6e9adSlinfeng     fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
104*fae6e9adSlinfeng         f.debug_struct("PerCpuLruMap")
105*fae6e9adSlinfeng             .field("maps", &self.per_cpu_maps)
106*fae6e9adSlinfeng             .finish()
107*fae6e9adSlinfeng     }
108*fae6e9adSlinfeng }
109*fae6e9adSlinfeng 
110*fae6e9adSlinfeng impl PerCpuLruMap {
new(attr: &BpfMapMeta) -> Result<Self>111*fae6e9adSlinfeng     pub fn new(attr: &BpfMapMeta) -> Result<Self> {
112*fae6e9adSlinfeng         let num_cpus = PerCpu::MAX_CPU_NUM;
113*fae6e9adSlinfeng         let mut data = Vec::with_capacity(num_cpus as usize);
114*fae6e9adSlinfeng         for _ in 0..num_cpus {
115*fae6e9adSlinfeng             let array_map = LruMap::new(attr)?;
116*fae6e9adSlinfeng             data.push(array_map);
117*fae6e9adSlinfeng         }
118*fae6e9adSlinfeng         let per_cpu_maps = PerCpuVar::new(data).ok_or(SystemError::EINVAL)?;
119*fae6e9adSlinfeng         Ok(PerCpuLruMap { per_cpu_maps })
120*fae6e9adSlinfeng     }
121*fae6e9adSlinfeng }
122*fae6e9adSlinfeng 
123*fae6e9adSlinfeng impl BpfMapCommonOps for PerCpuLruMap {
lookup_elem(&mut self, key: &[u8]) -> Result<Option<&[u8]>>124*fae6e9adSlinfeng     fn lookup_elem(&mut self, key: &[u8]) -> Result<Option<&[u8]>> {
125*fae6e9adSlinfeng         self.per_cpu_maps.get_mut().lookup_elem(key)
126*fae6e9adSlinfeng     }
update_elem(&mut self, key: &[u8], value: &[u8], flags: u64) -> Result<()>127*fae6e9adSlinfeng     fn update_elem(&mut self, key: &[u8], value: &[u8], flags: u64) -> Result<()> {
128*fae6e9adSlinfeng         self.per_cpu_maps.get_mut().update_elem(key, value, flags)
129*fae6e9adSlinfeng     }
delete_elem(&mut self, key: &[u8]) -> Result<()>130*fae6e9adSlinfeng     fn delete_elem(&mut self, key: &[u8]) -> Result<()> {
131*fae6e9adSlinfeng         self.per_cpu_maps.get_mut().delete_elem(key)
132*fae6e9adSlinfeng     }
for_each_elem(&mut self, cb: BpfCallBackFn, ctx: *const u8, flags: u64) -> Result<u32>133*fae6e9adSlinfeng     fn for_each_elem(&mut self, cb: BpfCallBackFn, ctx: *const u8, flags: u64) -> Result<u32> {
134*fae6e9adSlinfeng         self.per_cpu_maps.get_mut().for_each_elem(cb, ctx, flags)
135*fae6e9adSlinfeng     }
lookup_and_delete_elem(&mut self, key: &[u8], value: &mut [u8]) -> Result<()>136*fae6e9adSlinfeng     fn lookup_and_delete_elem(&mut self, key: &[u8], value: &mut [u8]) -> Result<()> {
137*fae6e9adSlinfeng         self.per_cpu_maps
138*fae6e9adSlinfeng             .get_mut()
139*fae6e9adSlinfeng             .lookup_and_delete_elem(key, value)
140*fae6e9adSlinfeng     }
lookup_percpu_elem(&mut self, key: &[u8], cpu: u32) -> Result<Option<&[u8]>>141*fae6e9adSlinfeng     fn lookup_percpu_elem(&mut self, key: &[u8], cpu: u32) -> Result<Option<&[u8]>> {
142*fae6e9adSlinfeng         unsafe {
143*fae6e9adSlinfeng             self.per_cpu_maps
144*fae6e9adSlinfeng                 .force_get_mut(ProcessorId::new(cpu))
145*fae6e9adSlinfeng                 .lookup_elem(key)
146*fae6e9adSlinfeng         }
147*fae6e9adSlinfeng     }
get_next_key(&self, key: Option<&[u8]>, next_key: &mut [u8]) -> Result<()>148*fae6e9adSlinfeng     fn get_next_key(&self, key: Option<&[u8]>, next_key: &mut [u8]) -> Result<()> {
149*fae6e9adSlinfeng         self.per_cpu_maps.get_mut().get_next_key(key, next_key)
150*fae6e9adSlinfeng     }
151*fae6e9adSlinfeng }
152