1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
//! Declarative backend selection (issue #106) — one line picks the capture
//! backend instead of hand-wiring `interface` / `xdp_interface` / `xdp_queues`.
//!
//! [`Backend::Auto`] runs a cap-free capability probe and resolves to a
//! concrete backend (self-loading AF_XDP when the `xdp-loader` feature is
//! compiled in, else AF_PACKET), **logging the chosen plan** so it is never a
//! black box. The resolved plan is also queryable via
//! `MonitorBuilder::resolved_capture_plan()` before `build()`.
//!
//! ```sh
//! cargo run --example monitor_auto_backend --features "tokio,flow" -- eth0
//! # AF_XDP rung lights up only when built with the loader:
//! cargo run --example monitor_auto_backend \
//! --features "tokio,flow,af-xdp,xdp-loader" -- eth0
//! ```
//!
//! `lo` works for smoke-testing. The example prints the resolved plan, then
//! counts TCP flow starts for a few seconds.
use std::time::Duration;
use netring::prelude::*;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// `tracing` shows the `netring::monitor::auto` plan line `capture()` logs.
let filter = tracing_subscriber::EnvFilter::try_from_default_env()
.unwrap_or_else(|_| tracing_subscriber::EnvFilter::new("netring::monitor::auto=info"));
tracing_subscriber::fmt()
.with_env_filter(filter)
.try_init()
.ok();
let iface = std::env::args().nth(1).unwrap_or_else(|| "lo".into());
let dur_secs: u64 = std::env::args()
.nth(2)
.and_then(|s| s.parse().ok())
.unwrap_or(10);
// One declarative line: probe the host + interface, pick + log the backend.
let builder = Monitor::builder()
.capture(&iface, Backend::Auto)
.protocol::<Tcp>();
// Observe what Auto chose without scraping logs.
for (iface, plan) in builder.resolved_capture_plan() {
eprintln!("monitor_auto_backend: {iface} -> {plan}");
}
eprintln!("monitor_auto_backend: capturing on {iface} for {dur_secs}s");
builder
.on::<FlowStarted<Tcp>>(|_evt: &FlowStarted<Tcp>| {
eprintln!("flow started");
Ok(())
})
.sink(StdoutSink::default())
.build()?
.run_for(Duration::from_secs(dur_secs))
.await?;
eprintln!("monitor_auto_backend: done");
Ok(())
}