aya_friday/maps/queue.rs
1//! A FIFO queue.
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_push_elem},
13};
14
15/// A FIFO queue.
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::Queue;
25///
26/// let mut queue = Queue::try_from(bpf.map_mut("ARRAY").unwrap())?;
27/// queue.push(42, 0)?;
28/// queue.push(43, 0)?;
29/// assert_eq!(queue.pop(0)?, 42);
30/// # Ok::<(), aya::EbpfError>(())
31/// ```
32#[doc(alias = "BPF_MAP_TYPE_QUEUE")]
33pub struct Queue<T, V: Pod> {
34 pub(crate) inner: T,
35 _v: PhantomData<V>,
36}
37
38impl<T: Borrow<MapData>, V: Pod> Queue<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 queue 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> Queue<T, V> {
58 /// Removes the first element and returns it.
59 ///
60 /// # Errors
61 ///
62 /// Returns [`MapError::ElementNotFound`] if the queue 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 /// Appends an element at the end of the queue.
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_push_elem(fd, value.borrow(), flags)
85 .map_err(|io_error| SyscallError {
86 call: "bpf_map_push_elem",
87 io_error,
88 })
89 .map_err(Into::into)
90 }
91}