#[cfg(all(feature = "tokio", feature = "af-xdp", feature = "xdp-loader"))]
#[tokio::main]
async fn main() -> Result<(), netring::Error> {
use aya::Ebpf;
use netring::XdpSocket;
use netring::xdp::{XdpFlags, XdpProgram};
use std::time::{Duration, Instant};
let iface = std::env::args().nth(1).unwrap_or_else(|| "lo".into());
let bytecode_path = match std::env::args().nth(2) {
Some(p) => p,
None => {
eprintln!(
"no bytecode_path provided. \
Pass a compiled XDP program (.o) as the second arg."
);
return Ok(());
}
};
eprintln!("loading {bytecode_path} via aya, attaching to {iface}");
let bytes = std::fs::read(&bytecode_path)
.map_err(|e| netring::Error::Config(format!("read bytecode: {e}")))?;
let bpf = Ebpf::load(&bytes).map_err(|e| netring::Error::Config(format!("aya load: {e}")))?;
let prog_name = std::env::var("XDP_PROG_NAME").unwrap_or_else(|_| "xdp_sock_prog".into());
let map_name = std::env::var("XDP_MAP_NAME").unwrap_or_else(|_| "xsks_map".into());
let prog = XdpProgram::from_aya(bpf, &prog_name, &map_name);
let mut sock = XdpSocket::builder()
.interface(&iface)
.queue_id(0)
.frame_size(2048)
.frame_count(4096)
.with_program(prog) .xdp_attach_flags(XdpFlags::SKB_MODE)
.force_replace(true)
.build()?;
let deadline = Instant::now() + Duration::from_secs(5);
let mut packets: u64 = 0;
while Instant::now() < deadline {
let batch = sock.recv()?;
for _pkt in &batch {
packets += 1;
}
if batch.is_empty() {
tokio::time::sleep(Duration::from_micros(200)).await;
} else {
tokio::task::yield_now().await;
}
}
eprintln!("captured {packets} packets — program will detach on Drop");
Ok(())
}
#[cfg(not(all(feature = "tokio", feature = "af-xdp", feature = "xdp-loader")))]
fn main() {
eprintln!("Build with --features tokio,af-xdp,xdp-loader");
}