mirror of
https://github.com/jmcorgan/fips.git
synced 2026-07-22 07:48:26 +00:00
Add network impairment script, fix iperf loopback bug
Add netem.sh for simulating adverse network conditions (delay, loss, jitter, duplication, reordering, corruption) on Docker test containers using tc/netem. Includes three presets (lossy, congested, terrible) and apply/remove/status actions. Fix iperf-test.sh bug where all tests connected the client to its own FIPS npub (loopback) instead of the remote server's npub, meaning previous iperf results measured loopback performance rather than cross-node throughput. Document netem.sh in README.md.
This commit is contained in:
@@ -86,12 +86,63 @@ The `iperf-test.sh` script measures bandwidth between nodes using iperf3:
|
||||
```
|
||||
|
||||
The test runs iperf3 with the following parameters:
|
||||
|
||||
- Duration: 10 seconds (`-t 10`)
|
||||
- Parallel streams: 8 (`-P 8`)
|
||||
- Protocol: TCP over IPv6
|
||||
|
||||
This exercises the full FIPS stack including encryption, routing, and TUN device performance.
|
||||
|
||||
## Network Impairment
|
||||
|
||||
The `netem.sh` script simulates adverse network conditions using `tc`/`netem`
|
||||
on all running containers:
|
||||
|
||||
```bash
|
||||
./scripts/netem.sh [mesh|chain] <apply|remove|status> [options]
|
||||
```
|
||||
|
||||
### Options
|
||||
|
||||
| Option | Description |
|
||||
|--------|-------------|
|
||||
| `--delay <ms>` | Fixed delay in milliseconds |
|
||||
| `--jitter <ms>` | Delay variation (requires `--delay`) |
|
||||
| `--loss <percent>` | Packet loss percentage |
|
||||
| `--loss-corr <percent>` | Loss correlation for bursty loss |
|
||||
| `--duplicate <percent>` | Packet duplication percentage |
|
||||
| `--reorder <percent>` | Packet reordering probability (requires `--delay`) |
|
||||
| `--corrupt <percent>` | Bit-level corruption percentage |
|
||||
|
||||
### Presets
|
||||
|
||||
| Preset | Parameters |
|
||||
|--------|------------|
|
||||
| `lossy` | 5% loss, 25% correlation |
|
||||
| `congested` | 50ms delay, 20ms jitter, 2% loss |
|
||||
| `terrible` | 100ms delay, 40ms jitter, 10% loss, 1% dup, 5% reorder |
|
||||
|
||||
### Examples
|
||||
|
||||
```bash
|
||||
# Apply 50ms delay with 5% packet loss
|
||||
./scripts/netem.sh mesh apply --delay 50 --loss 5
|
||||
|
||||
# Use a preset
|
||||
./scripts/netem.sh chain apply --preset congested
|
||||
|
||||
# Check current rules
|
||||
./scripts/netem.sh mesh status
|
||||
|
||||
# Remove all impairment
|
||||
./scripts/netem.sh mesh remove
|
||||
```
|
||||
|
||||
Rules are applied to egress on each container's `eth0` interface. With all
|
||||
containers impaired equally, both directions of every link see the effect.
|
||||
The script uses `tc qdisc replace` so it can be re-run safely without
|
||||
removing rules first.
|
||||
|
||||
## Configuration Management
|
||||
|
||||
Node configurations are generated from templates to ensure consistency across all nodes:
|
||||
@@ -119,6 +170,7 @@ generated-configs/ # Auto-generated configs (gitignored)
|
||||
### Topology Files
|
||||
|
||||
The `configs/topologies/` directory contains YAML files documenting each network topology:
|
||||
|
||||
- Node identities (nsec, npub)
|
||||
- Docker IP addresses
|
||||
- Peer connections for each node
|
||||
|
||||
@@ -95,31 +95,31 @@ if [ "$PROFILE" = "mesh" ]; then
|
||||
echo ""
|
||||
echo "Testing mesh topology paths:"
|
||||
|
||||
# Direct peer links
|
||||
iperf_test node-a node-d "$NPUB_D" "A → D (direct peer)"
|
||||
iperf_test node-a node-e "$NPUB_E" "A → E (direct peer)"
|
||||
|
||||
# Multi-hop paths
|
||||
iperf_test node-a node-b "$NPUB_B" "A → B (multi-hop)"
|
||||
iperf_test node-a node-c "$NPUB_C" "A → C (multi-hop)"
|
||||
|
||||
# Reverse test
|
||||
iperf_test node-e node-a "$NPUB_A" "E → A (direct peer)"
|
||||
# Direct peer links (client on A, server on D/E)
|
||||
iperf_test node-d node-a "$NPUB_D" "A → D (direct peer)"
|
||||
iperf_test node-e node-a "$NPUB_E" "A → E (direct peer)"
|
||||
|
||||
# Multi-hop paths (client on A, server on B/C)
|
||||
iperf_test node-b node-a "$NPUB_B" "A → B (multi-hop)"
|
||||
iperf_test node-c node-a "$NPUB_C" "A → C (multi-hop)"
|
||||
|
||||
# Reverse test (client on E, server on A)
|
||||
iperf_test node-a node-e "$NPUB_A" "E → A (direct peer)"
|
||||
|
||||
elif [ "$PROFILE" = "chain" ]; then
|
||||
echo ""
|
||||
echo "Testing chain topology paths:"
|
||||
|
||||
# Adjacent hop
|
||||
iperf_test node-a node-b "$NPUB_B" "A → B (1 hop)"
|
||||
|
||||
# Multi-hop tests
|
||||
iperf_test node-a node-c "$NPUB_C" "A → C (2 hops)"
|
||||
iperf_test node-a node-d "$NPUB_D" "A → D (3 hops)"
|
||||
iperf_test node-a node-e "$NPUB_E" "A → E (4 hops)"
|
||||
|
||||
# Reverse multi-hop
|
||||
iperf_test node-e node-a "$NPUB_A" "E → A (4 hops)"
|
||||
# Adjacent hop (client on A, server on B)
|
||||
iperf_test node-b node-a "$NPUB_B" "A → B (1 hop)"
|
||||
|
||||
# Multi-hop tests (client on A, server on C/D/E)
|
||||
iperf_test node-c node-a "$NPUB_C" "A → C (2 hops)"
|
||||
iperf_test node-d node-a "$NPUB_D" "A → D (3 hops)"
|
||||
iperf_test node-e node-a "$NPUB_E" "A → E (4 hops)"
|
||||
|
||||
# Reverse multi-hop (client on E, server on A)
|
||||
iperf_test node-a node-e "$NPUB_A" "E → A (4 hops)"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
|
||||
245
examples/docker-network/scripts/netem.sh
Executable file
245
examples/docker-network/scripts/netem.sh
Executable file
@@ -0,0 +1,245 @@
|
||||
#!/bin/bash
|
||||
# Network impairment simulation using tc/netem on FIPS Docker containers.
|
||||
#
|
||||
# Usage: ./netem.sh <mesh|chain> <apply|remove|status> [options]
|
||||
#
|
||||
# Actions:
|
||||
# apply - Apply netem rules to all containers in the profile
|
||||
# remove - Remove netem rules from all containers
|
||||
# status - Show current tc qdisc state on each container
|
||||
#
|
||||
# Options (for apply):
|
||||
# --delay <ms> Fixed delay in milliseconds
|
||||
# --jitter <ms> Delay variation (requires --delay)
|
||||
# --loss <percent> Packet loss percentage
|
||||
# --loss-corr <percent> Loss correlation for bursty loss
|
||||
# --duplicate <percent> Packet duplication percentage
|
||||
# --reorder <percent> Packet reordering probability
|
||||
# --corrupt <percent> Bit-level corruption percentage
|
||||
#
|
||||
# Presets (shorthand for common combinations):
|
||||
# --preset lossy 5% loss, 25% correlation
|
||||
# --preset congested 50ms delay, 20ms jitter, 2% loss
|
||||
# --preset terrible 100ms delay, 40ms jitter, 10% loss, 1% dup, 5% reorder
|
||||
#
|
||||
# Examples:
|
||||
# ./netem.sh mesh apply --delay 50 --loss 5
|
||||
# ./netem.sh chain apply --preset congested
|
||||
# ./netem.sh mesh status
|
||||
# ./netem.sh mesh remove
|
||||
set -e
|
||||
|
||||
trap 'echo ""; echo "Interrupted"; exit 130' INT
|
||||
|
||||
NODES="a b c d e"
|
||||
IFACE="eth0"
|
||||
|
||||
# Defaults
|
||||
DELAY=0
|
||||
JITTER=0
|
||||
LOSS=0
|
||||
LOSS_CORR=0
|
||||
DUPLICATE=0
|
||||
REORDER=0
|
||||
CORRUPT=0
|
||||
|
||||
usage() {
|
||||
echo "Usage: $0 <mesh|chain> <apply|remove|status> [options]"
|
||||
echo ""
|
||||
echo "Actions:"
|
||||
echo " apply - Apply netem rules to all containers"
|
||||
echo " remove - Remove netem rules from all containers"
|
||||
echo " status - Show current tc qdisc on each container"
|
||||
echo ""
|
||||
echo "Options (for apply):"
|
||||
echo " --delay <ms> Fixed delay"
|
||||
echo " --jitter <ms> Delay variation (requires --delay)"
|
||||
echo " --loss <percent> Packet loss"
|
||||
echo " --loss-corr <percent> Loss correlation"
|
||||
echo " --duplicate <percent> Packet duplication"
|
||||
echo " --reorder <percent> Packet reordering"
|
||||
echo " --corrupt <percent> Bit-level corruption"
|
||||
echo " --preset <name> Use a named preset (lossy, congested, terrible)"
|
||||
exit 1
|
||||
}
|
||||
|
||||
apply_preset() {
|
||||
case "$1" in
|
||||
lossy)
|
||||
LOSS=5
|
||||
LOSS_CORR=25
|
||||
;;
|
||||
congested)
|
||||
DELAY=50
|
||||
JITTER=20
|
||||
LOSS=2
|
||||
;;
|
||||
terrible)
|
||||
DELAY=100
|
||||
JITTER=40
|
||||
LOSS=10
|
||||
DUPLICATE=1
|
||||
REORDER=5
|
||||
;;
|
||||
*)
|
||||
echo "Error: Unknown preset '$1'" >&2
|
||||
echo "Available presets: lossy, congested, terrible" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
# Parse arguments
|
||||
[ $# -lt 2 ] && usage
|
||||
|
||||
PROFILE="$1"
|
||||
ACTION="$2"
|
||||
shift 2
|
||||
|
||||
case "$PROFILE" in
|
||||
mesh|chain) ;;
|
||||
*) echo "Error: Profile must be 'mesh' or 'chain'" >&2; exit 1 ;;
|
||||
esac
|
||||
|
||||
case "$ACTION" in
|
||||
apply|remove|status) ;;
|
||||
*) echo "Error: Action must be 'apply', 'remove', or 'status'" >&2; exit 1 ;;
|
||||
esac
|
||||
|
||||
# Parse options
|
||||
while [ $# -gt 0 ]; do
|
||||
case "$1" in
|
||||
--delay) DELAY="$2"; shift 2 ;;
|
||||
--jitter) JITTER="$2"; shift 2 ;;
|
||||
--loss) LOSS="$2"; shift 2 ;;
|
||||
--loss-corr) LOSS_CORR="$2"; shift 2 ;;
|
||||
--duplicate) DUPLICATE="$2"; shift 2 ;;
|
||||
--reorder) REORDER="$2"; shift 2 ;;
|
||||
--corrupt) CORRUPT="$2"; shift 2 ;;
|
||||
--preset) apply_preset "$2"; shift 2 ;;
|
||||
*)
|
||||
echo "Error: Unknown option '$1'" >&2
|
||||
usage
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
# Build netem parameter string from non-zero values
|
||||
build_netem_params() {
|
||||
local params=""
|
||||
|
||||
if [ "$DELAY" != "0" ]; then
|
||||
params="delay ${DELAY}ms"
|
||||
if [ "$JITTER" != "0" ]; then
|
||||
params="$params ${JITTER}ms"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ "$LOSS" != "0" ]; then
|
||||
params="$params loss ${LOSS}%"
|
||||
if [ "$LOSS_CORR" != "0" ]; then
|
||||
params="$params ${LOSS_CORR}%"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ "$DUPLICATE" != "0" ]; then
|
||||
params="$params duplicate ${DUPLICATE}%"
|
||||
fi
|
||||
|
||||
if [ "$REORDER" != "0" ]; then
|
||||
if [ "$DELAY" = "0" ]; then
|
||||
echo "Error: --reorder requires --delay (reordering needs a delay queue)" >&2
|
||||
exit 1
|
||||
fi
|
||||
params="$params reorder ${REORDER}%"
|
||||
fi
|
||||
|
||||
if [ "$CORRUPT" != "0" ]; then
|
||||
params="$params corrupt ${CORRUPT}%"
|
||||
fi
|
||||
|
||||
echo "$params"
|
||||
}
|
||||
|
||||
# Check if a container is running
|
||||
container_running() {
|
||||
docker inspect -f '{{.State.Running}}' "$1" 2>/dev/null | grep -q true
|
||||
}
|
||||
|
||||
do_apply() {
|
||||
local params
|
||||
params=$(build_netem_params)
|
||||
|
||||
if [ -z "$params" ]; then
|
||||
echo "Error: No impairment parameters specified" >&2
|
||||
echo "Use --delay, --loss, --duplicate, --reorder, --corrupt, or --preset" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "=== Applying netem: $params ==="
|
||||
echo ""
|
||||
|
||||
for node in $NODES; do
|
||||
local container="fips-node-$node"
|
||||
echo -n " $container ... "
|
||||
if ! container_running "$container"; then
|
||||
echo "SKIP (not running)"
|
||||
continue
|
||||
fi
|
||||
if docker exec "$container" tc qdisc replace dev "$IFACE" root netem $params 2>&1; then
|
||||
echo "OK"
|
||||
else
|
||||
echo "FAIL"
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
do_remove() {
|
||||
echo "=== Removing netem rules ==="
|
||||
echo ""
|
||||
|
||||
for node in $NODES; do
|
||||
local container="fips-node-$node"
|
||||
echo -n " $container ... "
|
||||
if ! container_running "$container"; then
|
||||
echo "SKIP (not running)"
|
||||
continue
|
||||
fi
|
||||
# Suppress error if no qdisc exists
|
||||
if docker exec "$container" tc qdisc del dev "$IFACE" root 2>/dev/null; then
|
||||
echo "OK"
|
||||
else
|
||||
echo "OK (no rules)"
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
do_status() {
|
||||
echo "=== netem status ==="
|
||||
echo ""
|
||||
|
||||
for node in $NODES; do
|
||||
local container="fips-node-$node"
|
||||
echo " $container:"
|
||||
if ! container_running "$container"; then
|
||||
echo " (not running)"
|
||||
continue
|
||||
fi
|
||||
local output
|
||||
output=$(docker exec "$container" tc qdisc show dev "$IFACE" 2>&1)
|
||||
if echo "$output" | grep -q "netem"; then
|
||||
echo " $output"
|
||||
else
|
||||
echo " (no netem rules)"
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
case "$ACTION" in
|
||||
apply) do_apply ;;
|
||||
remove) do_remove ;;
|
||||
status) do_status ;;
|
||||
esac
|
||||
|
||||
echo ""
|
||||
echo "Done."
|
||||
Reference in New Issue
Block a user