use std::task::{Context, Poll};
use crate::AsyncXdpSocket;
use crate::afxdp::XdpCaptureGuard;
use crate::error::{Error, Result};
use crate::packet::OwnedPacket;
use crate::xdp::XdpCapture;
pub struct AsyncXdpCapture {
sockets: Vec<AsyncXdpSocket>,
queue_ids: Vec<u32>,
_guard: XdpCaptureGuard,
cursor: usize,
}
impl AsyncXdpCapture {
pub fn new(capture: XdpCapture) -> Result<Self> {
let queue_ids = capture.queue_ids().to_vec();
let (sockets, guard) = capture.into_parts();
let sockets = sockets
.into_iter()
.map(AsyncXdpSocket::new)
.collect::<Result<Vec<_>>>()?;
Ok(Self {
sockets,
queue_ids,
_guard: guard,
cursor: 0,
})
}
pub fn open(iface: &str) -> Result<Self> {
Self::new(XdpCapture::open(iface)?)
}
pub fn queue_ids(&self) -> &[u32] {
&self.queue_ids
}
pub fn socket_count(&self) -> usize {
self.sockets.len()
}
pub fn is_zerocopy(&self) -> bool {
self.sockets.iter().all(|s| s.get_ref().is_zerocopy())
}
pub(crate) fn poll_read_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<()>> {
for sock in &mut self.sockets {
loop {
match sock.poll_read_ready_mut(cx) {
Poll::Ready(Ok(mut guard)) => {
if guard.get_inner_mut().rx_poll_ready() {
return Poll::Ready(Ok(()));
}
guard.clear_ready();
}
Poll::Ready(Err(e)) => return Poll::Ready(Err(Error::Io(e))),
Poll::Pending => break,
}
}
}
Poll::Pending
}
pub async fn readable(&mut self) -> Result<()> {
std::future::poll_fn(|cx| self.poll_read_ready(cx)).await
}
pub async fn recv(&mut self) -> Result<Vec<(u32, OwnedPacket)>> {
loop {
self.readable().await?;
let mut out = Vec::new();
let n = self.sockets.len();
for off in 0..n {
let i = (self.cursor + off) % n;
if self.sockets[i].get_mut().rx_poll_ready() {
let qid = self.queue_ids[i];
for p in self.sockets[i].get_mut().recv()? {
out.push((qid, p));
}
}
}
if !out.is_empty() {
return Ok(out);
}
}
}
pub fn into_parts(self) -> (Vec<AsyncXdpSocket>, XdpCaptureGuard) {
(self.sockets, self._guard)
}
}
#[cfg(feature = "flow")]
impl AsyncXdpCapture {
pub(crate) fn socket_rx_ready(&mut self, i: usize) -> bool {
self.sockets[i].get_mut().rx_poll_ready()
}
pub(crate) async fn socket_readable(
&mut self,
i: usize,
) -> Result<crate::async_adapters::tokio_xdp::XdpReadableGuard<'_>> {
self.sockets[i].readable().await
}
pub(crate) fn next_cursor(&mut self) -> usize {
let c = self.cursor;
if !self.sockets.is_empty() {
self.cursor = (self.cursor + 1) % self.sockets.len();
}
c
}
pub(crate) fn poll_drain_views(
&mut self,
cx: &mut Context<'_>,
sink: &mut dyn FnMut(crate::async_adapters::flow_source::SourcePacket<'_>),
) -> Poll<Result<crate::async_adapters::flow_source::DrainOutcome>> {
use crate::async_adapters::flow_source::{DrainOutcome, SourcePacket, view_from_parts};
let n = self.sockets.len();
for off in 0..n {
let i = (self.cursor + off) % n;
loop {
match self.sockets[i].poll_read_ready_mut(cx) {
Poll::Ready(Ok(mut guard)) => {
if guard.get_inner_mut().rx_poll_ready() {
let inner = guard.get_inner_mut();
if let Some(batch) = inner.next_batch() {
for pkt in &batch {
let view = view_from_parts(
pkt.data(),
pkt.timestamp(),
pkt.rx_metadata(),
);
sink(SourcePacket {
view,
data: pkt.data(),
direction: crate::packet::PacketDirection::Unknown(0),
original_len: pkt.len(),
});
}
drop(batch);
self.cursor = (i + 1) % n;
return Poll::Ready(Ok(DrainOutcome::Drained));
}
}
guard.clear_ready();
}
Poll::Ready(Err(e)) => return Poll::Ready(Err(Error::Io(e))),
Poll::Pending => break,
}
}
}
Poll::Pending
}
pub(crate) fn detailed_stats(
&self,
) -> Result<(crate::stats::CaptureStats, crate::stats::DropBreakdown)> {
let mut agg = crate::afxdp::XdpStats::default();
for s in &self.sockets {
agg = agg.saturating_add(s.statistics()?);
}
Ok((agg.to_capture_stats(), agg.into()))
}
pub fn capture_stats(&self) -> Result<crate::stats::CaptureStats> {
self.detailed_stats().map(|(s, _)| s)
}
}