use std::env;
use std::error::Error;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
use std::time::Duration;
use netmap_rs::prelude::*;
fn main() -> Result<(), Box<dyn Error>> {
let args: Vec<String> = env::args().collect();
if args.len() < 2 || !args[1].contains('^') {
eprintln!(
"Usage: {} <interface_name_with_caret_suffix>",
args[0]
);
eprintln!("Example: {} netmap:eth0^", args[0]);
return Err("Invalid arguments: Interface name must include '^' suffix.".into());
}
let if_name = &args[1];
println!(
"Attempting to open host stack rings for interface: {}",
if_name
);
let nm_desc = NetmapBuilder::new(if_name)
.num_rx_rings(1) .num_tx_rings(0) .build()?;
println!(
"Successfully opened interface {}. Number of host RX rings available: {}",
if_name,
nm_desc.num_rx_rings()
);
if nm_desc.num_rx_rings() == 0 {
eprintln!("No host RX rings available for interface {}. Exiting.", if_name);
return Ok(());
}
let mut rx_ring = nm_desc.rx_ring(0)?;
println!("Listening for packets on host RX ring 0...");
let running = Arc::new(AtomicBool::new(true));
let r = running.clone();
ctrlc::set_handler(move || {
println!("\nCtrl-C received, stopping packet reception...");
r.store(false, Ordering::Relaxed);
})
.expect("Error setting Ctrl-C handler");
let mut packets_received = 0u64;
while running.load(Ordering::Relaxed) {
rx_ring.sync();
let mut batch_count = 0;
while let Some(frame) = rx_ring.recv() {
if frame.is_empty() {
continue;
}
packets_received += 1;
batch_count +=1;
println!(
"Received packet #{} on host ring: len = {} bytes. Payload (first 32 bytes): {:?}",
packets_received,
frame.len(),
&frame.payload()[..std::cmp::min(frame.len(), 32)]
);
}
if batch_count == 0 && running.load(Ordering::Relaxed) {
std::thread::sleep(Duration::from_millis(10));
}
}
println!("\nFinished. Total packets received from host stack: {}", packets_received);
Ok(())
}