1*fae6e9adSlinfeng use super::{BpfMapCommonOps, Result}; 2*fae6e9adSlinfeng use crate::bpf::map::util::{BpfMapMeta, BpfMapUpdateElemFlags}; 3*fae6e9adSlinfeng use alloc::vec::Vec; 4*fae6e9adSlinfeng use core::fmt::Debug; 5*fae6e9adSlinfeng use core::ops::Deref; 6*fae6e9adSlinfeng use core::ops::DerefMut; 7*fae6e9adSlinfeng use system_error::SystemError; 8*fae6e9adSlinfeng 9*fae6e9adSlinfeng type BpfQueueValue = Vec<u8>; 10*fae6e9adSlinfeng /// BPF_MAP_TYPE_QUEUE provides FIFO storage and BPF_MAP_TYPE_STACK provides LIFO storage for BPF programs. 11*fae6e9adSlinfeng /// These maps support peek, pop and push operations that are exposed to BPF programs through the respective helpers. 12*fae6e9adSlinfeng /// These operations are exposed to userspace applications using the existing bpf syscall in the following way: 13*fae6e9adSlinfeng /// - `BPF_MAP_LOOKUP_ELEM` -> `peek` 14*fae6e9adSlinfeng /// - `BPF_MAP_UPDATE_ELEM` -> `push` 15*fae6e9adSlinfeng /// - `BPF_MAP_LOOKUP_AND_DELETE_ELEM ` -> `pop` 16*fae6e9adSlinfeng /// 17*fae6e9adSlinfeng /// See https://docs.kernel.org/bpf/map_queue_stack.html 18*fae6e9adSlinfeng pub trait SpecialMap: Debug + Send + Sync + 'static { 19*fae6e9adSlinfeng /// Returns the number of elements the queue can hold. push(&mut self, value: BpfQueueValue, flags: BpfMapUpdateElemFlags) -> Result<()>20*fae6e9adSlinfeng fn push(&mut self, value: BpfQueueValue, flags: BpfMapUpdateElemFlags) -> Result<()>; 21*fae6e9adSlinfeng /// Removes the first element and returns it. pop(&mut self) -> Option<BpfQueueValue>22*fae6e9adSlinfeng fn pop(&mut self) -> Option<BpfQueueValue>; 23*fae6e9adSlinfeng /// Returns the first element without removing it. peek(&self) -> Option<&BpfQueueValue>24*fae6e9adSlinfeng fn peek(&self) -> Option<&BpfQueueValue>; 25*fae6e9adSlinfeng } 26*fae6e9adSlinfeng 27*fae6e9adSlinfeng /// The queue map type is a generic map type, resembling a FIFO (First-In First-Out) queue. 28*fae6e9adSlinfeng /// 29*fae6e9adSlinfeng /// This map type has no keys, only values. The size and type of the values can be specified by the user 30*fae6e9adSlinfeng /// to fit a large variety of use cases. The typical use-case for this map type is to keep track of 31*fae6e9adSlinfeng /// a pool of elements such as available network ports when implementing NAT (network address translation). 32*fae6e9adSlinfeng /// 33*fae6e9adSlinfeng /// As apposed to most map types, this map type uses a custom set of helpers to pop, peek and push elements. 34*fae6e9adSlinfeng /// 35*fae6e9adSlinfeng /// See https://ebpf-docs.dylanreimerink.nl/linux/map-type/BPF_MAP_TYPE_QUEUE/ 36*fae6e9adSlinfeng #[derive(Debug)] 37*fae6e9adSlinfeng pub struct QueueMap { 38*fae6e9adSlinfeng max_entries: u32, 39*fae6e9adSlinfeng data: Vec<BpfQueueValue>, 40*fae6e9adSlinfeng } 41*fae6e9adSlinfeng 42*fae6e9adSlinfeng impl QueueMap { new(attr: &BpfMapMeta) -> Result<Self>43*fae6e9adSlinfeng pub fn new(attr: &BpfMapMeta) -> Result<Self> { 44*fae6e9adSlinfeng if attr.value_size == 0 || attr.max_entries == 0 || attr.key_size != 0 { 45*fae6e9adSlinfeng return Err(SystemError::EINVAL); 46*fae6e9adSlinfeng } 47*fae6e9adSlinfeng let data = Vec::with_capacity(attr.max_entries as usize); 48*fae6e9adSlinfeng Ok(Self { 49*fae6e9adSlinfeng max_entries: attr.max_entries, 50*fae6e9adSlinfeng data, 51*fae6e9adSlinfeng }) 52*fae6e9adSlinfeng } 53*fae6e9adSlinfeng } 54*fae6e9adSlinfeng 55*fae6e9adSlinfeng impl SpecialMap for QueueMap { push(&mut self, value: BpfQueueValue, flags: BpfMapUpdateElemFlags) -> Result<()>56*fae6e9adSlinfeng fn push(&mut self, value: BpfQueueValue, flags: BpfMapUpdateElemFlags) -> Result<()> { 57*fae6e9adSlinfeng if self.data.len() == self.max_entries as usize { 58*fae6e9adSlinfeng if flags.contains(BpfMapUpdateElemFlags::BPF_EXIST) { 59*fae6e9adSlinfeng // remove the first element 60*fae6e9adSlinfeng self.data.remove(0); 61*fae6e9adSlinfeng } else { 62*fae6e9adSlinfeng return Err(SystemError::ENOSPC); 63*fae6e9adSlinfeng } 64*fae6e9adSlinfeng } 65*fae6e9adSlinfeng self.data.push(value); 66*fae6e9adSlinfeng Ok(()) 67*fae6e9adSlinfeng } pop(&mut self) -> Option<BpfQueueValue>68*fae6e9adSlinfeng fn pop(&mut self) -> Option<BpfQueueValue> { 69*fae6e9adSlinfeng if self.data.is_empty() { 70*fae6e9adSlinfeng return None; 71*fae6e9adSlinfeng } 72*fae6e9adSlinfeng Some(self.data.remove(0)) 73*fae6e9adSlinfeng } peek(&self) -> Option<&BpfQueueValue>74*fae6e9adSlinfeng fn peek(&self) -> Option<&BpfQueueValue> { 75*fae6e9adSlinfeng self.data.first() 76*fae6e9adSlinfeng } 77*fae6e9adSlinfeng } 78*fae6e9adSlinfeng /// The stack map type is a generic map type, resembling a stack data structure. 79*fae6e9adSlinfeng /// 80*fae6e9adSlinfeng /// See https://ebpf-docs.dylanreimerink.nl/linux/map-type/BPF_MAP_TYPE_STACK/ 81*fae6e9adSlinfeng #[derive(Debug)] 82*fae6e9adSlinfeng pub struct StackMap(QueueMap); 83*fae6e9adSlinfeng 84*fae6e9adSlinfeng impl StackMap { new(attr: &BpfMapMeta) -> Result<Self>85*fae6e9adSlinfeng pub fn new(attr: &BpfMapMeta) -> Result<Self> { 86*fae6e9adSlinfeng QueueMap::new(attr).map(StackMap) 87*fae6e9adSlinfeng } 88*fae6e9adSlinfeng } 89*fae6e9adSlinfeng 90*fae6e9adSlinfeng impl Deref for StackMap { 91*fae6e9adSlinfeng type Target = QueueMap; deref(&self) -> &Self::Target92*fae6e9adSlinfeng fn deref(&self) -> &Self::Target { 93*fae6e9adSlinfeng &self.0 94*fae6e9adSlinfeng } 95*fae6e9adSlinfeng } 96*fae6e9adSlinfeng 97*fae6e9adSlinfeng impl DerefMut for StackMap { deref_mut(&mut self) -> &mut Self::Target98*fae6e9adSlinfeng fn deref_mut(&mut self) -> &mut Self::Target { 99*fae6e9adSlinfeng &mut self.0 100*fae6e9adSlinfeng } 101*fae6e9adSlinfeng } 102*fae6e9adSlinfeng 103*fae6e9adSlinfeng impl SpecialMap for StackMap { push(&mut self, value: BpfQueueValue, flags: BpfMapUpdateElemFlags) -> Result<()>104*fae6e9adSlinfeng fn push(&mut self, value: BpfQueueValue, flags: BpfMapUpdateElemFlags) -> Result<()> { 105*fae6e9adSlinfeng if self.data.len() == self.max_entries as usize { 106*fae6e9adSlinfeng if flags.contains(BpfMapUpdateElemFlags::BPF_EXIST) { 107*fae6e9adSlinfeng // remove the last element 108*fae6e9adSlinfeng self.data.pop(); 109*fae6e9adSlinfeng } else { 110*fae6e9adSlinfeng return Err(SystemError::ENOSPC); 111*fae6e9adSlinfeng } 112*fae6e9adSlinfeng } 113*fae6e9adSlinfeng self.data.push(value); 114*fae6e9adSlinfeng Ok(()) 115*fae6e9adSlinfeng } pop(&mut self) -> Option<BpfQueueValue>116*fae6e9adSlinfeng fn pop(&mut self) -> Option<BpfQueueValue> { 117*fae6e9adSlinfeng self.data.pop() 118*fae6e9adSlinfeng } peek(&self) -> Option<&BpfQueueValue>119*fae6e9adSlinfeng fn peek(&self) -> Option<&BpfQueueValue> { 120*fae6e9adSlinfeng self.data.last() 121*fae6e9adSlinfeng } 122*fae6e9adSlinfeng } 123*fae6e9adSlinfeng 124*fae6e9adSlinfeng impl<T: SpecialMap> BpfMapCommonOps for T { 125*fae6e9adSlinfeng /// Equal to [QueueMap::peek] lookup_elem(&mut self, _key: &[u8]) -> Result<Option<&[u8]>>126*fae6e9adSlinfeng fn lookup_elem(&mut self, _key: &[u8]) -> Result<Option<&[u8]>> { 127*fae6e9adSlinfeng Ok(self.peek().map(|v| v.as_slice())) 128*fae6e9adSlinfeng } 129*fae6e9adSlinfeng /// Equal to [QueueMap::push] update_elem(&mut self, _key: &[u8], value: &[u8], flags: u64) -> Result<()>130*fae6e9adSlinfeng fn update_elem(&mut self, _key: &[u8], value: &[u8], flags: u64) -> Result<()> { 131*fae6e9adSlinfeng let flag = BpfMapUpdateElemFlags::from_bits_truncate(flags); 132*fae6e9adSlinfeng self.push(value.to_vec(), flag) 133*fae6e9adSlinfeng } 134*fae6e9adSlinfeng /// Equal to [QueueMap::pop] lookup_and_delete_elem(&mut self, _key: &[u8], value: &mut [u8]) -> Result<()>135*fae6e9adSlinfeng fn lookup_and_delete_elem(&mut self, _key: &[u8], value: &mut [u8]) -> Result<()> { 136*fae6e9adSlinfeng if let Some(v) = self.pop() { 137*fae6e9adSlinfeng value.copy_from_slice(&v); 138*fae6e9adSlinfeng Ok(()) 139*fae6e9adSlinfeng } else { 140*fae6e9adSlinfeng Err(SystemError::ENOENT) 141*fae6e9adSlinfeng } 142*fae6e9adSlinfeng } push_elem(&mut self, value: &[u8], flags: u64) -> Result<()>143*fae6e9adSlinfeng fn push_elem(&mut self, value: &[u8], flags: u64) -> Result<()> { 144*fae6e9adSlinfeng self.update_elem(&[], value, flags) 145*fae6e9adSlinfeng } pop_elem(&mut self, value: &mut [u8]) -> Result<()>146*fae6e9adSlinfeng fn pop_elem(&mut self, value: &mut [u8]) -> Result<()> { 147*fae6e9adSlinfeng self.lookup_and_delete_elem(&[], value) 148*fae6e9adSlinfeng } peek_elem(&self, value: &mut [u8]) -> Result<()>149*fae6e9adSlinfeng fn peek_elem(&self, value: &mut [u8]) -> Result<()> { 150*fae6e9adSlinfeng self.peek() 151*fae6e9adSlinfeng .map(|v| value.copy_from_slice(v)) 152*fae6e9adSlinfeng .ok_or(SystemError::ENOENT) 153*fae6e9adSlinfeng } 154*fae6e9adSlinfeng } 155