use alloc::sync::Arc;
use crate::Socket;
use crate::xdp::XdpDesc;
use crate::xsk::{
BufIdx, CompletionQueue, DeviceQueue, DeviceQueueRegistration, DeviceRings, FillQueue,
RingCons, RingProd, RingRx, RingTx,
};
impl DeviceQueue {
pub fn fill(&mut self, max: u32) -> WriteFill<'_> {
WriteFill {
idx: BufIdxIter::reserve(&mut self.fcq.prod, max),
queue: &mut self.fcq.prod,
}
}
pub fn complete(&mut self, n: u32) -> ReadComplete<'_> {
ReadComplete {
idx: BufIdxIter::peek(&mut self.fcq.cons, n),
queue: &mut self.fcq.cons,
}
}
pub fn available(&self) -> u32 {
self.fcq.cons.count_pending()
}
pub fn pending(&self) -> u32 {
self.fcq.prod.count_pending()
}
pub fn as_raw_fd(&self) -> libc::c_int {
self.socket.fd.0
}
pub fn needs_wakeup(&self) -> bool {
self.fcq.prod.check_flags() & RingTx::XDP_RING_NEED_WAKEUP != 0
}
pub fn wake(&mut self) {
let mut poll = libc::pollfd {
fd: self.socket.fd.0,
events: 0,
revents: 0,
};
let _err = unsafe { libc::poll(&mut poll as *mut _, 1, 0) };
}
pub fn into_parts(self) -> (FillQueue, CompletionQueue) {
let Self {
fcq,
socket,
registration,
} = self;
let DeviceRings { prod, cons, .. } = fcq;
let Socket { fd, .. } = socket;
let registration = Arc::new(registration);
let fill_queue = FillQueue {
fd: fd.clone(),
prod,
registration: registration.clone(),
};
let completion_queue = CompletionQueue {
fd,
cons,
registration,
};
(fill_queue, completion_queue)
}
}
impl FillQueue {
pub fn fill(&mut self, max: u32) -> WriteFill<'_> {
WriteFill {
idx: BufIdxIter::reserve(&mut self.prod, max),
queue: &mut self.prod,
}
}
pub fn pending(&self) -> u32 {
self.prod.count_pending()
}
pub fn as_raw_fd(&self) -> libc::c_int {
self.fd.0
}
pub fn needs_wakeup(&self) -> bool {
self.prod.check_flags() & RingTx::XDP_RING_NEED_WAKEUP != 0
}
pub fn wake(&mut self) {
let mut poll = libc::pollfd {
fd: self.fd.0,
events: 0,
revents: 0,
};
let _err = unsafe { libc::poll(&mut poll as *mut _, 1, 0) };
}
}
impl CompletionQueue {
pub fn complete(&mut self, n: u32) -> ReadComplete<'_> {
ReadComplete {
idx: BufIdxIter::peek(&mut self.cons, n),
queue: &mut self.cons,
}
}
pub fn available(&self) -> u32 {
self.cons.count_pending()
}
pub fn as_raw_fd(&self) -> libc::c_int {
self.fd.0
}
}
impl Drop for DeviceQueueRegistration {
fn drop(&mut self) {
self.devices.remove(&self.ctx);
}
}
impl RingRx {
pub fn receive(&mut self, n: u32) -> ReadRx<'_> {
ReadRx {
idx: BufIdxIter::peek(&mut self.ring, n),
queue: &mut self.ring,
}
}
pub fn available(&self) -> u32 {
self.ring.count_pending()
}
pub fn as_raw_fd(&self) -> libc::c_int {
self.fd.0
}
}
impl RingTx {
const XDP_RING_NEED_WAKEUP: u32 = 1 << 0;
pub fn transmit(&mut self, n: u32) -> WriteTx<'_> {
WriteTx {
idx: BufIdxIter::reserve(&mut self.ring, n),
queue: &mut self.ring,
}
}
pub fn pending(&self) -> u32 {
self.ring.count_pending()
}
pub fn needs_wakeup(&self) -> bool {
self.ring.check_flags() & Self::XDP_RING_NEED_WAKEUP != 0
}
pub fn wake(&self) {
let _ = unsafe {
libc::sendto(
self.fd.0,
core::ptr::null_mut(),
0,
libc::MSG_DONTWAIT,
core::ptr::null_mut(),
0,
)
};
}
pub fn as_raw_fd(&self) -> libc::c_int {
self.fd.0
}
}
struct BufIdxIter {
base: BufIdx,
buffers: u32,
remain: u32,
}
#[must_use = "Does nothing unless the writes are committed"]
pub struct WriteFill<'queue> {
idx: BufIdxIter,
queue: &'queue mut RingProd,
}
#[must_use = "Does nothing unless the reads are committed"]
pub struct ReadComplete<'queue> {
idx: BufIdxIter,
queue: &'queue mut RingCons,
}
#[must_use = "Does nothing unless the writes are committed"]
pub struct WriteTx<'queue> {
idx: BufIdxIter,
queue: &'queue mut RingProd,
}
#[must_use = "Does nothing unless the reads are committed"]
pub struct ReadRx<'queue> {
idx: BufIdxIter,
queue: &'queue mut RingCons,
}
impl Iterator for BufIdxIter {
type Item = BufIdx;
fn next(&mut self) -> Option<BufIdx> {
let next = self.remain.checked_sub(1)?;
self.remain = next;
let ret = self.base;
self.base.0 = self.base.0.wrapping_add(1);
Some(ret)
}
}
impl BufIdxIter {
fn peek(queue: &mut RingCons, n: u32) -> Self {
let mut this = BufIdxIter {
buffers: 0,
remain: 0,
base: BufIdx(0),
};
this.buffers = queue.peek(1..=n, &mut this.base);
this.remain = this.buffers;
this
}
fn reserve(queue: &mut RingProd, n: u32) -> Self {
let mut this = BufIdxIter {
buffers: 0,
remain: 0,
base: BufIdx(0),
};
this.buffers = queue.reserve(1..=n, &mut this.base);
this.remain = this.buffers;
this
}
fn commit_prod(&mut self, queue: &mut RingProd) {
if self.buffers > 0 {
let count = self.buffers - self.remain;
queue.submit(count);
self.buffers -= count;
self.base.0 += count;
}
}
fn release_cons(&mut self, queue: &mut RingCons) {
if self.buffers > 0 {
let count = self.buffers - self.remain;
queue.release(count);
self.buffers -= count;
self.base.0 += count;
}
}
}
impl WriteFill<'_> {
pub fn capacity(&self) -> u32 {
self.idx.buffers
}
pub fn insert_once(&mut self, nr: u64) -> bool {
self.insert(core::iter::once(nr)) > 0
}
pub fn insert(&mut self, it: impl Iterator<Item = u64>) -> u32 {
let mut n = 0;
for (item, bufidx) in it.zip(self.idx.by_ref()) {
n += 1;
unsafe { *self.queue.fill_addr(bufidx).as_ptr() = item };
}
n
}
pub fn commit(&mut self) {
self.idx.commit_prod(self.queue)
}
}
impl Drop for WriteFill<'_> {
fn drop(&mut self) {
if self.idx.buffers != 0 {
self.queue.cancel(self.idx.buffers)
}
}
}
impl ReadComplete<'_> {
pub fn capacity(&self) -> u32 {
self.idx.buffers
}
pub fn read(&mut self) -> Option<u64> {
let bufidx = self.idx.next()?;
Some(unsafe { *self.queue.comp_addr(bufidx).as_ptr() })
}
pub fn release(&mut self) {
self.idx.release_cons(self.queue)
}
}
impl Drop for ReadComplete<'_> {
fn drop(&mut self) {
if self.idx.buffers != 0 {
self.queue.cancel(self.idx.buffers)
}
}
}
impl Iterator for ReadComplete<'_> {
type Item = u64;
fn next(&mut self) -> Option<u64> {
self.read()
}
}
impl WriteTx<'_> {
pub fn capacity(&self) -> u32 {
self.idx.buffers
}
pub fn insert_once(&mut self, nr: XdpDesc) -> bool {
self.insert(core::iter::once(nr)) > 0
}
pub fn insert(&mut self, it: impl Iterator<Item = XdpDesc>) -> u32 {
let mut n = 0;
for (item, bufidx) in it.zip(self.idx.by_ref()) {
n += 1;
unsafe { *self.queue.tx_desc(bufidx).as_ptr() = item };
}
n
}
pub fn commit(&mut self) {
self.idx.commit_prod(self.queue);
}
}
impl Drop for WriteTx<'_> {
fn drop(&mut self) {
if self.idx.buffers != 0 {
self.queue.cancel(self.idx.buffers)
}
}
}
impl ReadRx<'_> {
pub fn capacity(&self) -> u32 {
self.idx.buffers
}
pub fn read(&mut self) -> Option<XdpDesc> {
let bufidx = self.idx.next()?;
Some(unsafe { *self.queue.rx_desc(bufidx).as_ptr() })
}
pub fn release(&mut self) {
self.idx.release_cons(self.queue)
}
}
impl Drop for ReadRx<'_> {
fn drop(&mut self) {
if self.idx.buffers != 0 {
self.queue.cancel(self.idx.buffers)
}
}
}
impl Iterator for ReadRx<'_> {
type Item = XdpDesc;
fn next(&mut self) -> Option<XdpDesc> {
self.read()
}
}