#![cfg(feature = "integration-tests")]
mod helpers;
use helpers::VethPair;
use netring::bridge::{Bridge, BridgeAction, BridgeDirection};
use std::time::Duration;
#[test]
fn bridge_run_iterations_smoke() {
let veth = match VethPair::create("nrtest_a", "nrtest_b") {
Some(v) => v,
None => {
eprintln!("skipping: needs CAP_NET_ADMIN to create veth");
return;
}
};
let mut bridge = Bridge::builder()
.interface_a(&veth.a)
.interface_b(&veth.b)
.poll_timeout(Duration::from_millis(50))
.build()
.expect("build bridge");
let mut total_seen = 0u64;
bridge
.run_iterations(3, |_pkt, dir| {
match dir {
BridgeDirection::AtoB | BridgeDirection::BtoA => total_seen += 1,
}
BridgeAction::Forward
})
.expect("run_iterations");
let stats = bridge.cumulative_stats().expect("stats");
eprintln!(
"bridge_run_iterations_smoke: saw {total_seen} packets, drops a→b={} b→a={}",
stats.a_to_b.drops, stats.b_to_a.drops
);
}
#[test]
fn bridge_builder_into_inner() {
let veth = match VethPair::create("nrtest_c", "nrtest_d") {
Some(v) => v,
None => {
eprintln!("skipping: needs CAP_NET_ADMIN to create veth");
return;
}
};
let bridge = Bridge::builder()
.interface_a(&veth.a)
.interface_b(&veth.b)
.build()
.expect("build bridge");
let handles = bridge.into_inner();
use std::os::fd::AsRawFd;
let fds = [
handles.rx_a.as_raw_fd(),
handles.tx_b.as_raw_fd(),
handles.rx_b.as_raw_fd(),
handles.tx_a.as_raw_fd(),
];
for i in 0..fds.len() {
for j in (i + 1)..fds.len() {
assert_ne!(fds[i], fds[j], "duplicate fd at {i}/{j}");
}
}
}