Durchlauf 1 ist gemessen (Ergebnis folgt separat im Runbook). Fuer den Durchlauf
mit laufendem Videocall brauchte es Werkzeug, das es noch nicht gab:
- tp6-monitor-core.sh haengt EINE persistente SSH-Sitzung an den Core und laesst
dort eine Console-Schleife laufen, die im 2-s-Takt CPU, WAN-Rate und die
Registration-Table-Werte eines WLAN-Clients als CSV ausgibt. Nur Lesezugriffe.
Unter CAPsMAN fuehrt der Manager die Tabelle, deshalb wird der Core abgefragt
und nicht ap1/ap2. Zwei RouterOS-Fallen sind im Code kommentiert: die Console
parst eine per SSH uebergebene Mehrzeilen-Eingabe zeilenweise, und in der
Einzeiler-Form braucht jeder do={}-Block ein abschliessendes Semikolon.
- tp6-marker/server.py ist die Konsole fuer die Person am Telefon: Phasenkarte
mit Klartext-Anweisung, Countdown, Fortschritt, Marker-Buttons und Not-Aus,
bedienbar vom iPad. Die Buttons sind server-seitig gerenderte Formulare und
die Anleitung aktualisiert sich notfalls per meta-refresh -- auf dem iPad ist
das JavaScript ausgefallen, uebrig blieb nur der eine statische Button.
- tp6-call-run.sh fuehrt Durchlauf 2 mit denselben Messparametern wie Durchlauf 1
(3 Flows x 430 KB/s, 24 Pings, 30 s Settle) und ergaenzt Ruhephasen davor und
danach, Phasenmarken, eine PID-Datei fuer den Not-Aus und einen Heartbeat.
Der Heartbeat ist kein Detail: ohne ihn geht der Start-Klick still ins Leere,
der Call laeuft ohne Last, und "keine Probleme" liest sich wie ein Ergebnis,
obwohl es eine Nicht-Messung ist -- genau so passiert, 5,5 Minuten lang.
- tp6-auswertung.py schneidet die Sampler-CSV an den Phasenmarken auf und meldet
neben min/avg/max auch die Ereignisse, die im Mittelwert untergehen: Roaming,
Re-Assoc und Verschwinden des Clients.
- tp6-bufferbloat-messung.sh schickt jetzt User-Agent und Referer mit. Ohne die
beantwortet speed.cloudflare.com /__down mit 403 und einem Byte: die Flows
sind sofort tot, die Ping-Reihe sieht sauber aus, und die Download-Seite gilt
faelschlich als bufferbloat-frei. Aufgefallen ist es nur, weil der Sampler am
Core 164 kbit statt 50 Mbit zeigte.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
85 lines
3.5 KiB
Bash
Executable File
85 lines
3.5 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
#
|
|
# TP6 — Core-Sampler (read-only)
|
|
#
|
|
# Haengt EINE persistente SSH-Sitzung an crs326-core und laesst dort eine Console-Schleife
|
|
# laufen, die im festen Takt eine CSV-Zeile ausgibt: Core-CPU, WAN-Rate auf vlan100 und
|
|
# — optional — die Registration-Table-Werte EINES WLAN-Clients.
|
|
#
|
|
# 🔴 Ausschliesslich Lesezugriffe (get / find / monitor-traffic once). Kein Write, kein
|
|
# /system script, kein /system logging. Aendert nichts am Netz.
|
|
#
|
|
# 🔴 Unter CAPsMAN fuehrt der MANAGER die Registration-Table — deshalb wird der CORE
|
|
# abgefragt und nicht ap1/ap2, wo die Tabelle leer waere.
|
|
#
|
|
# Aufruf:
|
|
# bash docs/tp6-monitor-core.sh --out /pfad/sampler.csv # nur CPU/WAN
|
|
# bash docs/tp6-monitor-core.sh --out /pfad/sampler.csv --mac F2:62:4C:E1:AF:09
|
|
#
|
|
# Beenden: Ctrl-C (oder kill auf die PID).
|
|
|
|
set -uo pipefail
|
|
|
|
MAC=""
|
|
INTERVAL=2
|
|
OUT=""
|
|
ROUTER_IP="10.40.99.1"
|
|
|
|
while [[ $# -gt 0 ]]; do
|
|
case "$1" in
|
|
--mac) MAC="${2:-}"; shift 2 ;;
|
|
--interval) INTERVAL="${2:-2}"; shift 2 ;;
|
|
--out) OUT="${2:-}"; shift 2 ;;
|
|
--ip) ROUTER_IP="${2:-}"; shift 2 ;;
|
|
*) echo "unbekanntes Argument: $1" >&2; exit 2 ;;
|
|
esac
|
|
done
|
|
|
|
[[ -n "$OUT" ]] || { echo "--out fehlt" >&2; exit 2; }
|
|
|
|
# Passwort aus dem Credential-Store. Wird NIE ausgegeben.
|
|
PW="$(grep -m1 '^CRS326_CORE_PASS=' ~/.secrets/credentials.env | cut -d= -f2- | sed 's/^["'"'"']//; s/["'"'"']$//')"
|
|
[[ -n "$PW" ]] || { echo "CRS326_CORE_PASS nicht in ~/.secrets/credentials.env gefunden" >&2; exit 1; }
|
|
|
|
# RouterOS-Schleife. Platzhalter werden unten ersetzt (RouterOS nutzt $ selbst, daher kein
|
|
# Shell-Interpolieren im Schleifenkoerper).
|
|
read -r -d '' ROS <<'ROS_EOF'
|
|
:local m "__MAC__";
|
|
:while (true) do={
|
|
:local cpu [/system resource get cpu-load];
|
|
:local w [/interface monitor-traffic vlan100 once as-value];
|
|
:local line ([/system clock get time] . "," . $cpu . "," . ($w->"rx-bits-per-second") . "," . ($w->"tx-bits-per-second"));
|
|
:if ([:len $m] > 0) do={
|
|
:local id [/interface/wifi/registration-table find where mac-address=$m];
|
|
:if ([:len $id] = 0) do={
|
|
:set line ($line . ",absent,,,,,,");
|
|
} else={
|
|
:local r [/interface/wifi/registration-table get [:pick $id 0]];
|
|
:set line ($line . "," . ($r->"interface") . "," . ($r->"signal") . "," . ($r->"tx-rate") . "," . ($r->"rx-rate") . "," . ($r->"tx-bits-per-second") . "," . ($r->"rx-bits-per-second") . "," . ($r->"uptime") . "," . ($r->"last-activity"));
|
|
};
|
|
};
|
|
:put $line;
|
|
:delay __DELAY__s;
|
|
}
|
|
ROS_EOF
|
|
|
|
ROS="${ROS//__MAC__/$MAC}"
|
|
ROS="${ROS//__DELAY__/$INTERVAL}"
|
|
# 🔴 Die RouterOS-Console parst eine per SSH uebergebene Mehrzeilen-Eingabe ZEILENWEISE
|
|
# ("expected closing brace"). Das Skript muss deshalb als EINE Zeile ankommen —
|
|
# und jeder do={}-Block braucht dann ein abschliessendes ";", sonst kommt
|
|
# "expected end of command".
|
|
ROS="$(printf '%s' "$ROS" | tr '\n' ' ')"
|
|
|
|
echo "ts_epoch,ts_local,ros_time,cpu,wan_rx_bps,wan_tx_bps,sta_iface,sta_signal,sta_tx_rate,sta_rx_rate,sta_tx_bps,sta_rx_bps,sta_uptime,sta_last_activity" > "$OUT"
|
|
|
|
echo "Sampler laeuft -> $OUT (Takt ${INTERVAL}s${MAC:+, Client $MAC})"
|
|
|
|
# Lokaler Zeitstempel beim Eintreffen der Zeile. Bewusst kein awk: das BSD-awk auf macOS
|
|
# kennt systime()/strftime() nicht (das ist gawk).
|
|
sshpass -p "$PW" ssh -o StrictHostKeyChecking=no -o ConnectTimeout=8 \
|
|
-o ServerAliveInterval=15 "admin@${ROUTER_IP}" "$ROS" 2>"${OUT%.csv}.stderr.log" \
|
|
| while IFS= read -r line; do
|
|
printf '%s,%s,%s\n' "$(date +%s)" "$(date +%H:%M:%S)" "$line" >> "$OUT"
|
|
done
|