Skip to main content

aya_friday/maps/
stack.rs

1//! A LIFO stack.
2
3use std::{
4    borrow::{Borrow, BorrowMut},
5    marker::PhantomData,
6    os::fd::AsFd as _,
7};
8
9use crate::{
10    Pod,
11    maps::{MapData, MapError, check_kv_size},
12    sys::{SyscallError, bpf_map_lookup_and_delete_elem, bpf_map_update_elem},
13};
14
15/// A LIFO stack.
16///
17/// # Minimum kernel version
18///
19/// The minimum kernel version required to use this feature is 4.20.
20///
21/// # Examples
22/// ```no_run
23/// # let mut bpf = aya::Ebpf::load(&[])?;
24/// use aya::maps::Stack;
25///
26/// let mut stack = Stack::try_from(bpf.map_mut("STACK").unwrap())?;
27/// stack.push(42, 0)?;
28/// stack.push(43, 0)?;
29/// assert_eq!(stack.pop(0)?, 43);
30/// # Ok::<(), aya::EbpfError>(())
31/// ```
32#[doc(alias = "BPF_MAP_TYPE_STACK")]
33pub struct Stack<T, V: Pod> {
34    pub(crate) inner: T,
35    _v: PhantomData<V>,
36}
37
38impl<T: Borrow<MapData>, V: Pod> Stack<T, V> {
39    pub(crate) fn new(map: T) -> Result<Self, MapError> {
40        let data = map.borrow();
41        check_kv_size::<(), V>(data)?;
42
43        Ok(Self {
44            inner: map,
45            _v: PhantomData,
46        })
47    }
48
49    /// Returns the number of elements the stack can hold.
50    ///
51    /// This corresponds to the value of `bpf_map_def::max_entries` on the eBPF side.
52    pub fn capacity(&self) -> u32 {
53        self.inner.borrow().obj.max_entries()
54    }
55}
56
57impl<T: BorrowMut<MapData>, V: Pod> Stack<T, V> {
58    /// Removes the last element and returns it.
59    ///
60    /// # Errors
61    ///
62    /// Returns [`MapError::ElementNotFound`] if the stack is empty, [`MapError::SyscallError`]
63    /// if `bpf_map_lookup_and_delete_elem` fails.
64    pub fn pop(&mut self, flags: u64) -> Result<V, MapError> {
65        let fd = self.inner.borrow().fd().as_fd();
66
67        let value =
68            bpf_map_lookup_and_delete_elem::<u32, _>(fd, None, flags).map_err(|io_error| {
69                SyscallError {
70                    call: "bpf_map_lookup_and_delete_elem",
71                    io_error,
72                }
73            })?;
74        value.ok_or(MapError::ElementNotFound)
75    }
76
77    /// Pushes an element on the stack.
78    ///
79    /// # Errors
80    ///
81    /// [`MapError::SyscallError`] if `bpf_map_update_elem` fails.
82    pub fn push(&mut self, value: impl Borrow<V>, flags: u64) -> Result<(), MapError> {
83        let fd = self.inner.borrow().fd().as_fd();
84        bpf_map_update_elem(fd, None::<&u32>, value.borrow(), flags)
85            .map_err(|io_error| SyscallError {
86                call: "bpf_map_update_elem",
87                io_error,
88            })
89            .map_err(Into::into)
90    }
91}