From 5b128942894addcbf27631490d5aa8589ce8526b Mon Sep 17 00:00:00 2001 From: Damien Arnodo Date: Mon, 20 Jul 2026 16:09:39 +0000 Subject: [PATCH] Add iperf3 traffic generator for DC<->Campus gold VRF path Host containers sit idle otherwise, leaving IPFabric ARP/MAC tables and Grafana throughput graphs empty until someone manually generates traffic. Refs #55 --- scripts/README.md | 30 +++++++++++++ scripts/generate_traffic.sh | 85 +++++++++++++++++++++++++++++++++++++ 2 files changed, 115 insertions(+) create mode 100755 scripts/generate_traffic.sh diff --git a/scripts/README.md b/scripts/README.md index 878dc76..1867a9b 100644 --- a/scripts/README.md +++ b/scripts/README.md @@ -133,3 +133,33 @@ default layout. data for any VTEP node — likely an Arista internal-vs-front-panel VLAN translation gap. Only affects that one decorative tooltip metric, not node/link status or traffic coloring. Tracked in #44. + +# scripts/generate_traffic.sh + +Generates real DC↔Campus traffic over VRF `gold` using `iperf3` (bundled +in the `network-multitool` image every host container runs), with a live +bandwidth dashboard. Without this, host containers sit idle and IPFabric +ARP/MAC tables, Grafana throughput graphs, and the weathermap panel stay +empty until someone manually generates traffic (see #55). + +## Quickstart + +```bash +./scripts/generate_traffic.sh +``` + +## How it works + +- Starts `iperf3 -s` on the DC gold-VRF servers: `dc-server2` + (10.34.34.102), `dc-server4` (10.78.78.104). +- Runs `iperf3 -c` from the paired campus gold-VRF hosts: `campus-host1` + → dc-server2, `campus-host2` → dc-server4 — exercising the full + DC→Core→Campus stitched EVPN Type-5 path end to end. +- Redraws a terminal dashboard every second for the run duration: server + list, and live Mbits/sec per client session parsed from `iperf3 -i 1` + output. +- On exit (duration end or Ctrl-C), kills the client processes and stops + the `iperf3 -s` processes on the DC servers — no leftover state. + +`dc-server1`/`dc-server3` (VLAN 40, VRF default, no gateway) are out of +scope — this script only exercises the routed gold VRF path. diff --git a/scripts/generate_traffic.sh b/scripts/generate_traffic.sh new file mode 100755 index 0000000..75fd9fc --- /dev/null +++ b/scripts/generate_traffic.sh @@ -0,0 +1,85 @@ +#!/usr/bin/env bash +# Generates DC<->Campus traffic over VRF gold using iperf3 (bundled in the +# network-multitool image every host container runs), with a live +# server/client bandwidth dashboard. Refs #55. +set -euo pipefail + +DURATION="${1:?Usage: $0 }" +if ! [[ "$DURATION" =~ ^[0-9]+$ ]] || [[ "$DURATION" -lt 1 ]]; then + echo "Duration must be a positive integer (seconds)" >&2 + exit 1 +fi + +LAB_PREFIX="clab-arista-evpn-fabric" +PORT=5301 + +# server_name:server_ip:client_name — gold VRF pairs, stitched EVPN +# Type-5 path DC -> Core -> Campus (see README Host Addressing table) +PAIRS=( + "dc-server2:10.34.34.102:campus-host1" + "dc-server4:10.78.78.104:campus-host2" +) + +WORKDIR="$(mktemp -d)" +CLIENT_PIDS=() + +cleanup() { + for pid in "${CLIENT_PIDS[@]:-}"; do + kill "$pid" >/dev/null 2>&1 || true + done + for pair in "${PAIRS[@]}"; do + IFS=':' read -r server _ _ <<<"$pair" + docker exec "${LAB_PREFIX}-${server}" pkill -f "iperf3 -s -p ${PORT}" >/dev/null 2>&1 || true + done + rm -rf "$WORKDIR" +} +trap cleanup EXIT INT TERM + +echo "Starting iperf3 servers..." +for pair in "${PAIRS[@]}"; do + IFS=':' read -r server server_ip _ <<<"$pair" + docker exec -d "${LAB_PREFIX}-${server}" iperf3 -s -p "$PORT" +done +sleep 1 + +echo "Starting iperf3 clients for ${DURATION}s..." +for pair in "${PAIRS[@]}"; do + IFS=':' read -r server server_ip client <<<"$pair" + logfile="${WORKDIR}/${client}.log" + docker exec "${LAB_PREFIX}-${client}" iperf3 -c "$server_ip" -p "$PORT" \ + -t "$DURATION" -i 1 --forceflush -f m >"$logfile" 2>&1 & + CLIENT_PIDS+=("$!") +done + +for ((elapsed = 0; elapsed <= DURATION; elapsed++)); do + clear + echo "EVPN/VXLAN lab traffic generator — ${elapsed}/${DURATION}s" + echo + echo "Servers (iperf3 -s):" + for pair in "${PAIRS[@]}"; do + IFS=':' read -r server server_ip _ <<<"$pair" + echo " ${server} (${server_ip}:${PORT})" + done + echo + echo "Clients (live bandwidth):" + for pair in "${PAIRS[@]}"; do + IFS=':' read -r server server_ip client <<<"$pair" + logfile="${WORKDIR}/${client}.log" + last_line="$(grep -E 'Mbits/sec' "$logfile" 2>/dev/null | tail -1 || true)" + bw="$(sed -E 's/.*[[:space:]]([0-9.]+ Mbits\/sec).*/\1/' <<<"$last_line")" + [[ -z "$last_line" ]] && bw="waiting..." + printf " %-13s -> %-13s : %s\n" "$client" "$server" "$bw" + done + sleep 1 +done + +wait "${CLIENT_PIDS[@]}" 2>/dev/null || true + +echo +echo "Done. Summary:" +for pair in "${PAIRS[@]}"; do + IFS=':' read -r server _ client <<<"$pair" + logfile="${WORKDIR}/${client}.log" + summary="$(grep -E 'receiver' "$logfile" 2>/dev/null || true)" + echo " ${client} -> ${server}: ${summary:-no data}" +done