use std::marker::PhantomData;
use super::XdpSocket;
pub struct XdpPacket<'a> {
data: &'a [u8],
len: u32,
options: u32,
addr: u64,
}
impl<'a> XdpPacket<'a> {
#[inline]
pub fn data(&self) -> &'a [u8] {
self.data
}
#[inline]
pub fn len(&self) -> usize {
self.len as usize
}
#[inline]
pub fn is_empty(&self) -> bool {
self.len == 0
}
#[inline]
pub fn options(&self) -> u32 {
self.options
}
#[inline]
pub fn umem_addr(&self) -> u64 {
self.addr
}
#[inline]
pub fn timestamp(&self) -> Option<crate::Timestamp> {
None
}
pub fn to_owned(&self) -> crate::OwnedPacket {
crate::OwnedPacket {
data: self.data.to_vec(),
timestamp: crate::Timestamp::default(),
original_len: self.len(),
status: crate::packet::PacketStatus::default(),
direction: crate::packet::PacketDirection::Unknown(0),
rxhash: 0,
vlan_tci: 0,
vlan_tpid: 0,
ll_protocol: 0,
source_ll_addr: [0u8; 8],
source_ll_addr_len: 0,
}
}
}
pub struct XdpBatch<'a> {
socket: &'a mut XdpSocket,
tok: super::ring::PeekToken,
_no_send_marker: PhantomData<*const ()>,
}
impl<'a> XdpBatch<'a> {
#[inline]
pub(super) fn new(socket: &'a mut XdpSocket, tok: super::ring::PeekToken) -> Self {
Self {
socket,
tok,
_no_send_marker: PhantomData,
}
}
#[inline]
pub fn len(&self) -> usize {
self.tok.n as usize
}
#[inline]
pub fn is_empty(&self) -> bool {
self.tok.n == 0
}
pub fn iter(&self) -> XdpBatchIter<'_> {
XdpBatchIter { batch: self, i: 0 }
}
}
impl<'a, 'b> IntoIterator for &'b XdpBatch<'a> {
type Item = XdpPacket<'b>;
type IntoIter = XdpBatchIter<'b>;
fn into_iter(self) -> XdpBatchIter<'b> {
self.iter()
}
}
impl std::fmt::Debug for XdpBatch<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("XdpBatch")
.field("n", &self.tok.n)
.field("start", &self.tok.start)
.finish()
}
}
impl Drop for XdpBatch<'_> {
fn drop(&mut self) {
for i in 0..self.tok.n {
let desc: libc::xdp_desc = self.socket.rx.read_at(self.tok, i);
self.socket.umem.free_frame(desc.addr);
}
self.socket.rx.consumer_release(self.tok);
self.socket.refill();
}
}
pub struct XdpBatchIter<'a> {
batch: &'a XdpBatch<'a>,
i: u32,
}
impl<'a> Iterator for XdpBatchIter<'a> {
type Item = XdpPacket<'a>;
fn next(&mut self) -> Option<XdpPacket<'a>> {
loop {
if self.i >= self.batch.tok.n {
return None;
}
let desc: libc::xdp_desc = self.batch.socket.rx.read_at(self.batch.tok, self.i);
self.i += 1;
match self
.batch
.socket
.umem
.data_checked(desc.addr, desc.len as usize)
{
Some(data) => {
return Some(XdpPacket {
data,
len: desc.len,
options: desc.options,
addr: desc.addr,
});
}
None => {
tracing::warn!(
addr = desc.addr,
len = desc.len,
"AF_XDP next_batch: malformed descriptor; skipping"
);
}
}
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
(0, Some((self.batch.tok.n - self.i) as usize))
}
}
impl std::fmt::Debug for XdpBatchIter<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("XdpBatchIter")
.field("i", &self.i)
.field("n", &self.batch.tok.n)
.finish()
}
}