mirror of
https://github.com/jmcorgan/fips.git
synced 2026-07-30 19:46:15 +00:00
testing: add boringtun throughput benchmark and iperf ref-compare harness
New testing/boringtun/ harness runs two Cloudflare BoringTun userspace WireGuard containers with iperf3 between them, giving a single-hop userspace tunnel baseline for comparison against FIPS throughput numbers. Local WG key generation runs through the harness image so the host needs no wireguard-tools. New testing/static/scripts/iperf-compare-refs.sh builds two git refs into separate fips-test:* images via git worktree and runs the same static iperf topology against both, with RUNS-based repetition and aggregate avg/min/max reporting. testing/static/scripts/iperf-test.sh gains DURATION, PARALLEL, SETTLE_SECONDS, IPERF_TIMEOUT env knobs and a per-path iperf timeout. testing/static/docker-compose.yml selects the image under test via FIPS_TEST_IMAGE; testing/scripts/build.sh respects CARGO_TARGET_DIR. Author benchmark on aarch64 Docker Desktop: boringtun bob -> alice : 1000.13 Mbits/sec
This commit is contained in:
committed by
Johnathan Corgan
parent
09eb5ad6bf
commit
b05c80e5f5
@@ -0,0 +1 @@
|
||||
generated/
|
||||
@@ -0,0 +1,28 @@
|
||||
# Minimal boringtun-cli image for throughput benchmarking against FIPS.
|
||||
# Userspace WireGuard (boringtun) + wireguard-tools + iperf3 in one
|
||||
# image. Run two containers on a docker bridge, configure a WG peer
|
||||
# between them, then iperf3 client→server across the tunnel.
|
||||
|
||||
FROM rust:1-bookworm AS build
|
||||
# 0.6.0 (crates.io HEAD) is from 2022 and turns in ~1.7 Mbps in
|
||||
# this harness — clearly broken. Pull the boringtun-cli binary from
|
||||
# the cloudflare HEAD instead; it gets the post-0.6 perf fixes and
|
||||
# the multi-threaded recv loop.
|
||||
RUN git clone --depth 1 https://github.com/cloudflare/boringtun /usr/src/boringtun \
|
||||
&& cargo install --path /usr/src/boringtun/boringtun-cli
|
||||
|
||||
FROM debian:bookworm-slim
|
||||
ENV DEBIAN_FRONTEND=noninteractive
|
||||
RUN apt-get update \
|
||||
&& apt-get install -y --no-install-recommends \
|
||||
iperf3 \
|
||||
iproute2 \
|
||||
wireguard-tools \
|
||||
iputils-ping \
|
||||
netcat-openbsd \
|
||||
ca-certificates \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
COPY --from=build /usr/local/cargo/bin/boringtun-cli /usr/local/bin/boringtun-cli
|
||||
COPY entrypoint.sh /entrypoint.sh
|
||||
RUN chmod +x /entrypoint.sh
|
||||
ENTRYPOINT ["/entrypoint.sh"]
|
||||
@@ -0,0 +1,29 @@
|
||||
# BoringTun Throughput Baseline
|
||||
|
||||
This harness runs two userspace WireGuard peers with Cloudflare BoringTun and
|
||||
measures single-stream TCP throughput with `iperf3`. It is intended as a simple
|
||||
baseline for comparing FIPS tunnel throughput against another userspace tunnel.
|
||||
|
||||
```bash
|
||||
docker build -t boringtun-test:latest testing/boringtun
|
||||
testing/boringtun/scripts/generate-keys.sh
|
||||
docker compose -f testing/boringtun/docker-compose.yml up -d
|
||||
testing/boringtun/scripts/bench.sh
|
||||
docker compose -f testing/boringtun/docker-compose.yml down
|
||||
```
|
||||
|
||||
The generated WireGuard key material is written under
|
||||
`testing/boringtun/generated/` and is ignored by git.
|
||||
|
||||
For FIPS-to-FIPS revision comparisons, use the static topology comparison
|
||||
script:
|
||||
|
||||
```bash
|
||||
testing/static/scripts/iperf-compare-refs.sh origin/master HEAD mesh
|
||||
```
|
||||
|
||||
That script builds each ref into a separate `fips-test:*` image, runs the
|
||||
same static `iperf3` topology against both images, and prints a bandwidth
|
||||
summary for each path. Override `DURATION`, `PARALLEL`, `SETTLE_SECONDS`, or
|
||||
`IPERF_TIMEOUT` in the environment when needed. Set `RUNS=3` or similar to
|
||||
repeat each ref and print aggregate results.
|
||||
@@ -0,0 +1,46 @@
|
||||
# Minimal 2-node boringtun setup for iperf3 throughput comparison.
|
||||
# Both containers join the same docker bridge; each runs a boringtun
|
||||
# userspace WireGuard tunnel and they peer with each other over UDP.
|
||||
# Inner WG IPs: 10.99.0.1/24 (alice) <-> 10.99.0.2/24 (bob).
|
||||
|
||||
networks:
|
||||
bt-net:
|
||||
driver: bridge
|
||||
ipam:
|
||||
config:
|
||||
- subnet: 172.99.0.0/24
|
||||
|
||||
x-boringtun-common: &boringtun-common
|
||||
image: boringtun-test:latest
|
||||
cap_add:
|
||||
- NET_ADMIN
|
||||
devices:
|
||||
- /dev/net/tun:/dev/net/tun
|
||||
sysctls:
|
||||
- net.ipv4.conf.all.forwarding=1
|
||||
restart: "no"
|
||||
env_file:
|
||||
- ./generated/peers.env
|
||||
|
||||
services:
|
||||
alice:
|
||||
<<: *boringtun-common
|
||||
container_name: bt-alice
|
||||
hostname: alice
|
||||
environment:
|
||||
- ROLE=alice
|
||||
- PEER_HOST=bob
|
||||
networks:
|
||||
bt-net:
|
||||
ipv4_address: 172.99.0.10
|
||||
|
||||
bob:
|
||||
<<: *boringtun-common
|
||||
container_name: bt-bob
|
||||
hostname: bob
|
||||
environment:
|
||||
- ROLE=bob
|
||||
- PEER_HOST=alice
|
||||
networks:
|
||||
bt-net:
|
||||
ipv4_address: 172.99.0.11
|
||||
Executable
+72
@@ -0,0 +1,72 @@
|
||||
#!/bin/bash
|
||||
# Bring up a boringtun-userspace WireGuard tunnel and then sleep
|
||||
# indefinitely so the benchmark scripts can drive it via docker exec.
|
||||
#
|
||||
# Required env:
|
||||
# ROLE "alice" or "bob"
|
||||
# ALICE_WG_IP WG inner IP for alice (e.g. 10.99.0.1/24)
|
||||
# BOB_WG_IP WG inner IP for bob (e.g. 10.99.0.2/24)
|
||||
# ALICE_PUB alice's WG public key
|
||||
# BOB_PUB bob's WG public key
|
||||
# ALICE_PRIV alice's WG private key
|
||||
# BOB_PRIV bob's WG private key
|
||||
# PEER_HOST the other container's hostname on the docker bridge
|
||||
# PEER_PORT the other container's WG UDP port (default 51820)
|
||||
#
|
||||
# boringtun-cli runs in foreground (--foreground) so wg-quick-style
|
||||
# configuration is done manually via `ip`, `wg`, and `wg set`.
|
||||
|
||||
set -e
|
||||
|
||||
PORT="${PEER_PORT:-51820}"
|
||||
case "$ROLE" in
|
||||
alice)
|
||||
OUR_IP="$ALICE_WG_IP"
|
||||
OUR_PRIV="$ALICE_PRIV"
|
||||
PEER_PUB="$BOB_PUB"
|
||||
;;
|
||||
bob)
|
||||
OUR_IP="$BOB_WG_IP"
|
||||
OUR_PRIV="$BOB_PRIV"
|
||||
PEER_PUB="$ALICE_PUB"
|
||||
;;
|
||||
*)
|
||||
echo "ROLE must be alice or bob, got '$ROLE'" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
echo "[$ROLE] starting boringtun-cli foreground on wg0"
|
||||
# `--foreground` keeps the userspace driver in the container
|
||||
# foreground. boringtun-cli sets WG_TUN_NAME_FILE to /tmp/wg0.name
|
||||
# when --foreground; we just hardcode the device name.
|
||||
boringtun-cli --foreground --disable-drop-privileges wg0 &
|
||||
BORINGTUN_PID=$!
|
||||
|
||||
# wait for the tun device to appear
|
||||
for i in $(seq 1 50); do
|
||||
if ip link show wg0 >/dev/null 2>&1; then
|
||||
break
|
||||
fi
|
||||
sleep 0.1
|
||||
done
|
||||
|
||||
echo "[$ROLE] configuring wg0 with $OUR_IP listening on $PORT"
|
||||
PRIV_FILE=$(mktemp)
|
||||
chmod 600 "$PRIV_FILE"
|
||||
printf '%s' "$OUR_PRIV" >"$PRIV_FILE"
|
||||
wg set wg0 private-key "$PRIV_FILE" listen-port "$PORT"
|
||||
rm -f "$PRIV_FILE"
|
||||
|
||||
ip address add "$OUR_IP" dev wg0
|
||||
ip link set up dev wg0
|
||||
|
||||
echo "[$ROLE] adding peer pubkey, endpoint $PEER_HOST:$PORT"
|
||||
wg set wg0 peer "$PEER_PUB" allowed-ips 10.99.0.0/24 endpoint "$PEER_HOST:$PORT" persistent-keepalive 25
|
||||
|
||||
echo "[$ROLE] ready"
|
||||
wg show wg0
|
||||
|
||||
# Park here so the container stays up; we'll run iperf3 etc via
|
||||
# docker exec.
|
||||
wait $BORINGTUN_PID
|
||||
Executable
+25
@@ -0,0 +1,25 @@
|
||||
#!/bin/bash
|
||||
# End-to-end iperf3 bandwidth test between two boringtun containers.
|
||||
# Output mirrors testing/static/scripts/iperf-test.sh so the FIPS
|
||||
# numbers are directly comparable.
|
||||
set -euo pipefail
|
||||
|
||||
DURATION="${DURATION:-10}"
|
||||
PARALLEL="${PARALLEL:-1}"
|
||||
|
||||
echo "=== boringtun iperf3 throughput (single TCP stream, ${DURATION}s) ==="
|
||||
|
||||
# Run iperf3 server on alice (background), client on bob.
|
||||
docker exec -d bt-alice iperf3 -s -1 -B 10.99.0.1 -p 5201
|
||||
sleep 1
|
||||
|
||||
# wait for tun handshake to settle (boringtun + WG keepalive)
|
||||
sleep 2
|
||||
|
||||
# Client: bob → alice over WG (10.99.0.1)
|
||||
OUT=$(docker exec bt-bob iperf3 -c 10.99.0.1 -p 5201 -t "$DURATION" -P "$PARALLEL" -J)
|
||||
|
||||
# Pull SUM bps.
|
||||
MBPS=$(echo "$OUT" | python3 -c "import json,sys; d=json.load(sys.stdin); print(f\"{d['end']['sum_received']['bits_per_second'] / 1_000_000:.2f}\")")
|
||||
|
||||
echo "boringtun bob -> alice : ${MBPS} Mbits/sec"
|
||||
Executable
+40
@@ -0,0 +1,40 @@
|
||||
#!/bin/bash
|
||||
# Generate WG keypairs for alice and bob and write the
|
||||
# generated/peers.env file the docker-compose.yml reads.
|
||||
# Idempotent: skips if file already exists.
|
||||
set -e
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
OUT_DIR="$SCRIPT_DIR/../generated"
|
||||
ENV_FILE="$OUT_DIR/peers.env"
|
||||
|
||||
if [ -f "$ENV_FILE" ]; then
|
||||
echo "$ENV_FILE already exists; reusing keys"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
mkdir -p "$OUT_DIR"
|
||||
|
||||
# Use the built boringtun-test image to generate keys — host may
|
||||
# not have wireguard-tools installed. The `pubkey` step needs `-i`
|
||||
# so stdin is piped through; `genkey` doesn't need it but matching
|
||||
# flags keeps the two calls symmetric.
|
||||
GEN_CMD="docker run --rm --entrypoint wg boringtun-test:latest"
|
||||
PUB_CMD="docker run --rm -i --entrypoint wg boringtun-test:latest"
|
||||
|
||||
ALICE_PRIV=$($GEN_CMD genkey)
|
||||
ALICE_PUB=$(printf '%s' "$ALICE_PRIV" | $PUB_CMD pubkey)
|
||||
BOB_PRIV=$($GEN_CMD genkey)
|
||||
BOB_PUB=$(printf '%s' "$BOB_PRIV" | $PUB_CMD pubkey)
|
||||
|
||||
cat >"$ENV_FILE" <<EOF
|
||||
ALICE_PRIV=$ALICE_PRIV
|
||||
ALICE_PUB=$ALICE_PUB
|
||||
BOB_PRIV=$BOB_PRIV
|
||||
BOB_PUB=$BOB_PUB
|
||||
ALICE_WG_IP=10.99.0.1/24
|
||||
BOB_WG_IP=10.99.0.2/24
|
||||
PEER_PORT=51820
|
||||
EOF
|
||||
chmod 600 "$ENV_FILE"
|
||||
echo "wrote $ENV_FILE"
|
||||
Reference in New Issue
Block a user