#!/bin/sh # mesh-speedtest — quick throughput probe across the wg1 mesh. # # Default: from current host, pull a chunk from each peer over ssh and report # Mbps + a streaming verdict. Bytes traverse the wg1 tunnel; ssh adds a thin # layer of double-encryption, so numbers run a few % below raw wg throughput # but are stable for "can I stream from here?" decisions. # # Usage: # mesh-speedtest # download from each peer (64 MiB) # mesh-speedtest -s 256 # use 256 MiB chunks (slower, more stable) # mesh-speedtest -u # upload (push to each peer) instead # mesh-speedtest -p plum,black # restrict to specific peers # # Peers are the wg1 mesh: apricot, black, plum, quinn-vps. Self is skipped. set -eu size_mib=64 direction=down peer_filter="" while [ $# -gt 0 ]; do case $1 in -s) size_mib=$2; shift 2 ;; -u) direction=up; shift ;; -p) peer_filter=$2; shift 2 ;; -h|--help) sed -n '2,18p' "$0" | sed 's/^# \{0,1\}//'; exit 0 ;; *) echo "unknown arg: $1" >&2; exit 2 ;; esac done all_peers="apricot black plum quinn-vps" self=$(hostname -s 2>/dev/null || hostname) case $self in plum|*plum*) self=plum ;; apricot*) self=apricot ;; black*) self=black ;; quinn-vps*|*1984*) self=quinn-vps ;; esac verdict() { mbps=$1 awk -v m="$mbps" 'BEGIN{ if (m >= 40) print "4K HDR ok"; else if (m >= 25) print "4K ok"; else if (m >= 12) print "1080p high ok"; else if (m >= 5) print "1080p ok"; else if (m >= 3) print "720p ok"; else if (m >= 1.5) print "480p / rsync first for HD"; else print "rsync only"; }' } # Run one direction against one peer. Echo " " or " ERR". probe() { peer=$1 bytes=$((size_mib * 1024 * 1024)) start=$(date +%s.%N 2>/dev/null || date +%s) if [ "$direction" = down ]; then ssh -o ConnectTimeout=5 -o BatchMode=yes "$peer" \ "dd if=/dev/zero bs=1M count=$size_mib status=none" \ > /dev/null 2>/tmp/mesh-speedtest.$$.$peer.err || { echo "$peer ERR"; return; } else dd if=/dev/zero bs=1M count=$size_mib status=none 2>/dev/null \ | ssh -o ConnectTimeout=5 -o BatchMode=yes "$peer" \ "dd of=/dev/null bs=1M status=none" \ 2>/tmp/mesh-speedtest.$$.$peer.err || { echo "$peer ERR"; return; } fi end=$(date +%s.%N 2>/dev/null || date +%s) secs=$(awk -v s="$start" -v e="$end" 'BEGIN{d=e-s; if(d<0.001)d=0.001; printf "%.3f",d}') mbps=$(awk -v b="$bytes" -v t="$secs" 'BEGIN{printf "%.1f", (b*8)/(t*1000000)}') echo "$peer $mbps $secs" } # Build peer list. peers="" if [ -n "$peer_filter" ]; then peers=$(echo "$peer_filter" | tr ',' ' ') else for p in $all_peers; do [ "$p" = "$self" ] && continue peers="$peers $p" done fi label=$([ "$direction" = down ] && echo "download from" || echo "upload to") printf "mesh-speedtest: %s peers, %d MiB chunks (self=%s)\n\n" "$label" "$size_mib" "$self" printf "%-12s %10s %8s %s\n" "peer" "Mbps" "secs" "verdict" printf "%-12s %10s %8s %s\n" "----" "----" "----" "-------" # Run probes sequentially; parallel would skew Mbps via shared uplink. for p in $peers; do out=$(probe "$p") case $out in *ERR) err=$(cat /tmp/mesh-speedtest.$$.$p.err 2>/dev/null | head -1) printf "%-12s %10s %8s %s\n" "$p" "-" "-" "ssh failed: ${err:-unreachable}" ;; *) peer_n=$(echo "$out" | awk '{print $1}') mbps=$(echo "$out" | awk '{print $2}') secs=$(echo "$out" | awk '{print $3}') v=$(verdict "$mbps") printf "%-12s %10s %8s %s\n" "$peer_n" "$mbps" "$secs" "$v" ;; esac rm -f /tmp/mesh-speedtest.$$.$p.err done # Average across reachable peers (informational only — wildly different paths). echo ""