netring
High-performance zero-copy packet I/O for Linux, async-first.
netring provides packet capture and injection via AF_PACKET (TPACKET_V3
block-based mmap ring buffers) and AF_XDP (kernel-bypass via XDP sockets).
The recommended API is async/tokio; sync types are first-class but
mostly used as the underlying source for the async wrappers.
Quick start (async, recommended)
[]
= { = "0.8", = ["tokio"] }
// Capture: zero-copy borrowed batches via AsyncFd.
# async
// Stream-style consumption with futures::StreamExt
// (add `futures = "0.3"` to your Cargo.toml):
use StreamExt;
let mut stream = open?.into_stream;
while let Some = stream.next.await
// Inject with backpressure (awaits POLLOUT when ring is full):
# async
// AF_XDP (kernel bypass, 10M+ pps) — same shape as AsyncCapture:
#
# async
See docs/ASYNC_GUIDE.md for the full async story —
patterns, trade-offs, when to use which entry point, and Send/!Send
considerations.
Flow & session tracking
[]
= { = "0.8", = ["tokio", "flow"] }
= "0.3"
use StreamExt;
use AsyncCapture;
use FiveTuple;
use FlowEvent;
let cap = open?;
let mut stream = cap.flow_stream;
while let Some = stream.next.await
Pluggable flow keys (5-tuple, IpPair, MacPair, VLAN/MPLS/VXLAN/GTP-U
decap combinators, custom extractors), bidirectional sessions, TCP
state machine with Zeek-style history string, idle-timeout sweep,
LRU eviction, optional TCP reassembly hook (sync Reassembler or
async AsyncReassembler with channel_factory for backpressure).
The flow types live in a separate cross-platform crate
flowscope (no Linux, no
tokio, no async runtime — usable with pcap, tun-tap, embedded).
netring is the Linux capture integration; the underlying flow API
works on any source of &[u8] frames.
flowscope also ships feature-gated L7 modules: http (HTTP/1.x),
tls (TLS handshake observation, optional JA3), dns (DNS-over-UDP
parser + correlator), and pcap (offline replay).
BPF filtering
netring ships a typed classic-BPF builder — no shelling out to
tcpdump -dd, no native-library deps:
use ;
let filter = builder
.tcp
.dst_port
.or
.build
.unwrap;
let cap = builder
.interface
.bpf_filter
.build
.unwrap;
Vocabulary: eth_type / ipv4 / ipv6 / arp, vlan / vlan_id,
ip_proto / tcp / udp / icmp, src_host / dst_host / host,
src_net / dst_net / net, src_port / dst_port / port,
plus negate() and or(|b| ...). See
examples/bpf_filter.rs for a runnable
demo. The escape hatch BpfFilter::new(insns) still accepts raw
bytecode from tcpdump -dd or any other source.
BpfFilter::matches(&[u8]) -> bool runs the bytecode in pure Rust
for offline validation against pcap data.
Sync API
The sync types power the async wrappers and are also usable directly:
// Flat iterator — simplest path.
let mut cap = open.unwrap;
for pkt in cap.packets.take
// Batch processing with sequence-gap detection.
use Capture;
use Duration;
let mut cap = builder
.interface
.block_size
.build
.unwrap;
while let Some = cap.next_batch_blocking.unwrap
Features
| Feature | Default | Description |
|---|---|---|
tokio |
off | Async wrappers (AsyncCapture, AsyncInjector, AsyncXdpSocket, PacketStream) |
af-xdp |
off | AF_XDP kernel-bypass packet I/O (pure Rust, no native deps) |
xdp-loader |
off | Built-in redirect-all XDP program loader for AF_XDP via aya. Implies af-xdp. See async_xdp_self_loaded example. |
channel |
off | Thread + bounded channel adapter (runtime-agnostic) |
parse |
off | Packet header parsing via etherparse |
pcap |
off | Stream packets to PCAP files |
metrics |
off | metrics crate counters (netring_capture_*_total) |
flow |
off | Pluggable flow & session tracking (pulls flowscope, see Flow & session tracking above) |
Public API
| Concept | Sync type | Async wrapper |
|---|---|---|
| AF_PACKET RX | Capture |
AsyncCapture<Capture> |
| AF_PACKET TX | Injector |
AsyncInjector |
| AF_XDP (RX + TX) | XdpSocket |
AsyncXdpSocket |
| Bridge two interfaces | Bridge |
Bridge::run_async |
| Channel adapter | — | ChannelCapture (sync threads) |
Every type has a ::open(iface) shortcut for the simple case and a
::builder() for full configuration.
Default Configuration
| Parameter | Default | Description |
|---|---|---|
block_size |
4 MiB | Ring buffer block size |
block_count |
64 | Number of blocks (256 MiB total) |
frame_size |
2048 | Minimum frame size |
block_timeout_ms |
60 | Block retirement timeout |
fill_rxhash |
true | Kernel fills RX flow hash |
Performance Tuning
| Profile | block_size | block_count | timeout_ms | Notes |
|---|---|---|---|---|
| High throughput | 4 MiB | 128–256 | 60 | + FanoutMode::Cpu + thread pinning |
| Low latency | 256 KiB | 64 | 1–10 | + busy_poll_us(50).prefer_busy_poll(true).busy_poll_budget(64) (kernel ≥ 5.11) |
| Memory-constrained | 1 MiB | 16 | 100 | 16 MiB total ring |
| Jumbo frames | 4 MiB | 64 | 60 | frame_size(65536) |
See docs/TUNING_GUIDE.md for detailed tuning advice.
Fanout Modes
Distribute packets across multiple sockets for multi-threaded capture:
| Mode | Strategy |
|---|---|
Hash |
Flow hash (same flow → same socket) |
Cpu |
Route to CPU that received the NIC interrupt |
LoadBalance |
Round-robin |
Rollover |
Fill one socket, overflow to next |
Random |
Random distribution |
QueueMapping |
NIC hardware queue mapping |
use ;
let cap = builder
.interface
.fanout
.fanout_flags
.build
.unwrap;
Statistics
# let cap = open.unwrap;
let stats = cap.stats.unwrap;
println!;
Reading stats resets the kernel counters — call periodically for rate calculation.
System Requirements
- Linux kernel 3.2+ (for TPACKET_V3), 5.4+ (for AF_XDP)
- Rust 1.85+ (edition 2024)
Capabilities
| Capability | Required For |
|---|---|
CAP_NET_RAW |
Creating AF_PACKET / AF_XDP sockets |
CAP_IPC_LOCK |
MAP_LOCKED (or sufficient RLIMIT_MEMLOCK) |
CAP_NET_ADMIN |
Promiscuous mode |
# Recommended: use justfile (sudo only once for setcap)
# Manual alternative
Examples
Documentation
- Architecture — system design, lifetime model, ring layout
- API Overview — all types, methods, and configuration
- Tuning Guide — performance profiles, system tuning, monitoring
- Troubleshooting — common errors and fixes
License
Licensed under either of Apache License, Version 2.0 or MIT License at your option.