Files
fips/examples/docker-network
Origami74andJohnathan Corgan 68b9652aa9 feat(docker): Add iperf3 testing, config templating, and test improvements
Docker testing infrastructure:
- Add iperf3 bandwidth testing (10s duration, 8 parallel streams)
- Install iperf3 in container, auto-start as daemon alongside FIPS
- Support --live flag for real-time iperf3 output during tests
- Aggregate [SUM] bandwidth reporting with correct units

Configuration templating system:
- Single node.template.yaml replacing per-node hand-written configs
- Topology definitions in configs/topologies/ (mesh.yaml, chain.yaml)
- generate-configs.sh script for automatic config generation
- Integrated into build.sh for regeneration on build
- Generated configs in generated-configs/ (gitignored)

Ping test improvements:
- Reduce to 1 ping per test for faster execution (~10s vs ~30s)
- Show response times (RTT) for each test
- Add Ctrl+C trap for clean exit
- Reduce convergence wait from 5s to 3s
2026-02-18 01:01:27 +00:00
..

Docker Network Test Harness

Multi-node integration test for FIPS using Docker containers. Two topologies are provided: a sparse mesh (5 nodes, 6 links) and a linear chain (5 nodes, 4 links). Both exercise the full FIPS stack including TUN devices, DNS resolution, peer link encryption, spanning tree construction, and discovery-driven multi-hop routing.

Prerequisites

  • Docker with the compose plugin
  • Rust toolchain (for building the FIPS binary)

Quick Start

Build the binary and copy it to the docker context:

./scripts/build.sh

Mesh Topology

docker compose --profile mesh build
docker compose --profile mesh up -d
./scripts/ping-test.sh mesh      # 20/20 expected (with response times)
./scripts/iperf-test.sh mesh     # bandwidth test
docker compose --profile mesh down

Chain Topology

docker compose --profile chain build
docker compose --profile chain up -d
./scripts/ping-test.sh chain     # 6/6 expected (with response times)
./scripts/iperf-test.sh chain    # bandwidth test
docker compose --profile chain down

Mesh Topology

Mesh Topology

Five nodes with 6 bidirectional UDP links forming a sparse, fully connected graph. Not all nodes are direct peers — non-adjacent pairs require discovery-driven multi-hop routing to establish end-to-end sessions.

The spanning tree is rooted at node A, which has the lexicographically smallest NodeAddr (the first 16 bytes of SHA-256(pubkey)). Tree edges are highlighted in blue in the diagram above.

The ping test exercises all 20 directed pairs (5 nodes x 4 targets each), covering both direct-peer and multi-hop paths.

Link Type
A — D tree edge (D's parent is A)
A — E tree edge (E's parent is A)
C — D tree edge (C's parent is D)
B — C tree edge (B's parent is C)
D — E non-tree link
C — E non-tree link

Chain Topology

Chain Topology

Five nodes in a linear chain: A — B — C — D — E. Each node peers only with its immediate neighbors. Multi-hop communication (e.g., A to E) requires the discovery protocol to find routes through intermediate nodes.

The ping test covers:

  • Adjacent hops: A→B, B→C (1 hop each)
  • Multi-hop: A→C (2 hops), A→D (3 hops), A→E (4 hops)
  • Reverse: E→A (4 hops)

Performance Testing

The iperf-test.sh script measures bandwidth between nodes using iperf3:

./scripts/iperf-test.sh [mesh|chain]

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.

Configuration Management

Node configurations are generated from templates to ensure consistency across all nodes:

File Structure

configs/
├── node.template.yaml          # Single template for all node configs
├── topologies/
│   ├── mesh.yaml              # Mesh topology definition (reference)
│   └── chain.yaml             # Chain topology definition (reference)
└── [mesh|chain]/              # Original hand-written configs (deprecated)

generated-configs/              # Auto-generated configs (gitignored)
├── mesh/
│   ├── node-a.yaml
│   ├── node-b.yaml
│   └── ...
└── chain/
    ├── node-a.yaml
    └── ...

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

These files serve as reference documentation and make it easy to understand and modify network topologies.

Generating Configs

The scripts/generate-configs.sh script reads the topology definitions (embedded in the script) and generates node configs into generated-configs/:

./scripts/generate-configs.sh [mesh|chain|all]

The build script (scripts/build.sh) automatically regenerates configs before building Docker images.

Modifying Topologies

To change network topologies, edit the get_mesh_peers() or get_chain_peers() functions in generate-configs.sh, then update the corresponding YAML file in configs/topologies/ for documentation.

Node Identities

All nodes use deterministic test keys (not for production use).

Node npub FIPS IPv6 Address Docker IP
A npub1sjlh2c3... fd69:e08d:65cc:3a6b:... 172.20.0.10
B npub1tdwa4vj... fd8e:302c:287e:b48d:... 172.20.0.11
C npub1cld9yay... fdac:a221:4069:5044:... 172.20.0.12
D npub1n9lpnv0... fdb6:8411:a191:6d48:... 172.20.0.13
E npub1wf8akf8... fded:7dee:d386:a546:... 172.20.0.14

Container Configuration

  • Base image: debian:bookworm-slim
  • Capabilities: CAP_NET_ADMIN (for TUN device creation)
  • Devices: /dev/net/tun mapped into each container
  • DNS: FIPS built-in resolver on 127.0.0.1:53
  • Transport: UDP on port 4000, MTU 1280
  • TUN: fips0 interface, MTU 1280

Each node resolves <npub>.fips DNS names to FIPS IPv6 addresses via its local DNS responder, which primes the identity cache for session establishment.

Troubleshooting

Stale images after code changes: Docker compose may cache old layers. Force a clean rebuild:

docker compose --profile mesh build --no-cache

Check node logs:

docker logs fips-node-a
docker logs -f fips-node-c    # follow

Verify DNS resolution inside a container:

docker exec fips-node-a dig AAAA npub1tdwa4vjrjl33pcjdpf2t4p027nl86xrx24g4d3avg4vwvayr3g8qhd84le.fips @127.0.0.1

Verify binary is up to date: Compare hashes between the local build and the binary inside the container:

md5sum examples/docker-network/fips
docker exec fips-node-a md5sum /usr/local/bin/fips

Increase convergence time: If tests fail intermittently, the 5-second convergence wait in ping-test.sh may be insufficient. Edit the sleep value at the top of the script.