1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100
use crate::ring::XskRingCons;
use super::{frame::FrameDesc, Umem};
/// Used to transfer ownership of [`Umem`](super::Umem) frames from
/// kernel-space to user-space.
///
/// Frames received in this queue are those that have been sent via
/// the [`TxQueue`](crate::socket::TxQueue).
///
/// For more information see the
/// [docs](https://www.kernel.org/doc/html/latest/networking/af_xdp.html#umem-completion-ring).
#[derive(Debug)]
pub struct CompQueue {
ring: XskRingCons,
_umem: Umem,
}
impl CompQueue {
pub(crate) fn new(ring: XskRingCons, umem: Umem) -> Self {
Self { ring, _umem: umem }
}
/// Update `descs` with details of frames whose contents have been
/// sent (after submission via the [`TxQueue`]) and may now be
/// used again. Returns the number of elements of `descs` which
/// have been updated.
///
/// The number of entries updated will be less than or equal to
/// the length of `descs`. Entries will be updated sequentially
/// from the start of `descs` until the end.
///
/// Free frames should eventually be added back on to either the
/// [`FillQueue`] or the [`TxQueue`].
///
/// # Safety
///
/// The frames passed to this queue must belong to the same
/// [`Umem`] that this `CompQueue` instance is tied to.
///
/// [`TxQueue`]: crate::socket::TxQueue
/// [`FillQueue`]: crate::FillQueue
#[inline]
pub unsafe fn consume(&mut self, descs: &mut [FrameDesc]) -> usize {
let nb = descs.len() as u64;
if nb == 0 {
return 0;
}
let mut idx = 0;
let cnt = unsafe { libbpf_sys::_xsk_ring_cons__peek(self.ring.as_mut(), nb, &mut idx) };
if cnt > 0 {
for desc in descs.iter_mut().take(cnt as usize) {
let addr =
unsafe { *libbpf_sys::_xsk_ring_cons__comp_addr(self.ring.as_ref(), idx) };
desc.addr = addr as usize;
desc.lengths.data = 0;
desc.lengths.headroom = 0;
desc.options = 0;
idx += 1;
}
unsafe { libbpf_sys::_xsk_ring_cons__release(self.ring.as_mut(), cnt) };
}
cnt as usize
}
/// Same as [`consume`] but for a single frame descriptor.
///
/// # Safety
///
/// See [`consume`].
///
/// [`consume`]: Self::consume
#[inline]
pub unsafe fn consume_one(&mut self, desc: &mut FrameDesc) -> usize {
let mut idx = 0;
let cnt = unsafe { libbpf_sys::_xsk_ring_cons__peek(self.ring.as_mut(), 1, &mut idx) };
if cnt > 0 {
let addr = unsafe { *libbpf_sys::_xsk_ring_cons__comp_addr(self.ring.as_ref(), idx) };
desc.addr = addr as usize;
desc.lengths.data = 0;
desc.lengths.headroom = 0;
desc.options = 0;
unsafe { libbpf_sys::_xsk_ring_cons__release(self.ring.as_mut(), cnt) };
}
cnt as usize
}
}