use std::io;
use crate::{
ring::XskRingProd,
socket::{Fd, Socket},
};
use super::frame::FrameDesc;
#[derive(Debug)]
pub struct FillQueue {
ring: XskRingProd,
_socket: Socket,
}
impl FillQueue {
pub(crate) fn new(ring: XskRingProd, socket: Socket) -> Self {
Self {
ring,
_socket: socket,
}
}
#[inline]
pub unsafe fn produce(&mut self, descs: &[FrameDesc]) -> usize {
let nb = descs.len() as u32;
if nb == 0 {
return 0;
}
let mut idx = 0;
let cnt = unsafe { libxdp_sys::xsk_ring_prod__reserve(self.ring.as_ptr(), nb, &mut idx) };
if cnt > 0 {
for desc in descs.iter().take(cnt as usize) {
unsafe {
*libxdp_sys::xsk_ring_prod__fill_addr(self.ring.as_ptr(), idx) =
desc.addr as u64
};
idx = idx.wrapping_add(1);
}
unsafe { libxdp_sys::xsk_ring_prod__submit(self.ring.as_ptr(), cnt) };
}
cnt as usize
}
#[inline]
pub unsafe fn produce_one(&mut self, desc: &FrameDesc) -> usize {
let mut idx = 0;
let cnt = unsafe { libxdp_sys::xsk_ring_prod__reserve(self.ring.as_ptr(), 1, &mut idx) };
if cnt > 0 {
unsafe {
*libxdp_sys::xsk_ring_prod__fill_addr(self.ring.as_ptr(), idx) = desc.addr as u64
};
unsafe { libxdp_sys::xsk_ring_prod__submit(self.ring.as_ptr(), cnt) };
}
cnt as usize
}
#[inline]
pub unsafe fn produce_and_wakeup(
&mut self,
descs: &[FrameDesc],
socket_fd: &mut Fd,
poll_timeout: i32,
) -> io::Result<usize> {
let cnt = unsafe { self.produce(descs) };
if cnt > 0 && self.needs_wakeup() {
self.wakeup(socket_fd, poll_timeout)?;
}
Ok(cnt)
}
#[inline]
pub unsafe fn produce_one_and_wakeup(
&mut self,
desc: &FrameDesc,
socket_fd: &mut Fd,
poll_timeout: i32,
) -> io::Result<usize> {
let cnt = unsafe { self.produce_one(desc) };
if cnt > 0 && self.needs_wakeup() {
self.wakeup(socket_fd, poll_timeout)?;
}
Ok(cnt)
}
#[inline]
pub fn wakeup(&self, fd: &mut Fd, poll_timeout: i32) -> io::Result<()> {
fd.poll_read(poll_timeout)?;
Ok(())
}
#[inline]
pub fn needs_wakeup(&self) -> bool {
unsafe { libxdp_sys::xsk_ring_prod__needs_wakeup(self.ring.as_ptr()) != 0 }
}
}