Expand description
Simulate bad network conditions on loopback using tc-netem.
badnet provisions a pair of loopback addresses and wires them together
through a Linux traffic-control (tc) pipeline so that any traffic sent
from one address to the other passes through a configurable
tc-netem qdisc. This lets you reproduce packet loss, corruption,
duplication, delay, and reordering in ordinary integration tests without
touching real network interfaces.
§Platform requirements
Linux only. The calling process needs CAP_NET_ADMIN. Grant it with
setcap rather than running the whole process as root — running a test
binary as root gives it unrestricted access to the entire system, which is
far broader than what this library needs:
sudo setcap cap_net_admin+eip target/debug/deps/<test_binary>§Quick start
use std::net::UdpSocket;
use std::time::Duration;
use badnet::BadNet;
// Create a link that drops 10 % of packets.
let net = BadNet::builder()
.loss(0.10)
.build()?;
// Bind sockets to the two ends and communicate normally.
let tx = UdpSocket::bind(format!("{}:0", net.left_addr()))?;
let rx = UdpSocket::bind(format!("{}:9000", net.right_addr()))?;
rx.set_read_timeout(Some(Duration::from_millis(200)))?;
tx.send_to(b"hello", format!("{}:9000", net.right_addr()))?;
// … the link will drop ~10 % of these …
// The tc rules and loopback addresses are removed when `net` is dropped.§Isolation
Each BadNet instance claims a unique address pair and HTB class, so
multiple instances running concurrently do not interfere with each other.
§Reorder and gap
BadNetBuilder::reorder requires BadNetBuilder::delay to have been
called first (enforced at compile time via the typestate on
BadNetBuilder). BadNetBuilder::gap additionally requires
BadNetBuilder::reorder.
use std::time::Duration;
use badnet::BadNet;
// 20 ms delay, 30 % of packets reordered probabilistically.
let net = BadNet::builder()
.delay(Duration::from_millis(20))
.reorder(0.30)
.build()?;
// Every 5th packet reordered deterministically (reorder must be 1.0 for
// a fully deterministic pattern).
let net = BadNet::builder()
.delay(Duration::from_millis(20))
.reorder(1.0)
.gap(5)
.build()?;§Reproducible impairment with seeds
tc-netem uses an internal PRNG to decide which packets to drop, corrupt,
duplicate, or reorder. Passing the same seed on the same kernel version
produces an identical sequence of decisions, making test failures
reproducible:
use badnet::BadNet;
// Seed 42 produces the same loss decisions on every run.
let net = BadNet::builder().seed(42).loss(0.10).build()?;The default seed is 0. Vary the seed when you want statistically
independent runs rather than a fixed pattern.
Structs§
- BadNet
- A running virtual link backed by loopback addresses and
tc-netem. - BadNet
Builder - Builder for a
BadNetlink.