Files
Pluto-SDR/scripts/test_udp_tunnel.sh

130 lines
7.7 KiB
Bash
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env bash
# test_udp_tunnel.sh — e2e-тест UDP-туннеля (§10 п.8):
# хост-файл → udp_probe send → UDP → udp_gw -l → transmitter → ЭФИР →
# receiver → udp_gw -d → UDP → udp_probe recv → файл → md5-сверка
# Использование: scripts/test_udp_tunnel.sh [ipA] [ipB] [размер_КБ]
# По умолчанию: адреса из toolchain.env, 64 КБ, симплекс 915 МГц.
#
# ВНИМАНИЕ: правило №7 (кабель+аттенюатор) для udp_gw не применимо — шлюз не
# трогает PHY ни на байт (record-слой поверх уже принятого байтового потока),
# его логика проверена `make gwtest` + loopback на плате. Прогон штатно идёт
# на антеннах: TXGAIN=-20 scripts/test_udp_tunnel.sh
set -euo pipefail
source "$(dirname "$0")/../toolchain.env"
A="${1:-$PLUTO_A}" # передатчик
B="${2:-$PLUTO_B}" # приёмник
SIZE_KB="${3:-64}"
FREQ=915000000
RATE=1920000 # НЕ поднимать: бюджет CPU, docs/BENCHMARK.md
BW=1500000
TXGAIN="${TXGAIN:--30}" # OTA: переопредели, напр. TXGAIN=-20 scripts/test_udp_tunnel.sh
FEC="${FEC:-rs8}"
PAUSE="${PAUSE:-3000}" # ≤1 МБ — 3000 чист (§12.6); длинные прогоны — 4000
GROUPFEC="${GROUPFEC:-1}"
[ "$GROUPFEC" = 1 ] && GFLAG="-G" || GFLAG=""
PORT_A="${PORT_A:-6000}" # udp_gw -l на плате A (вход туннеля)
PORT_B="${PORT_B:-6001}" # udp_probe recv на плате B (выход туннеля)
CHUNK="${CHUNK:-1000}" # размер датаграммы; >1016 Б рекорд рвётся на 2 кадра
PACE_MS="${PACE_MS:-15}" # 1000 Б / 15 мс ≈ 65 КБ/сс запасом под потолок
# `-G -p 3000` ≈107 КБ/с. На 10 мс (≈100 КБ/с) вход
# упирается в потолок и шлюз штатно дропает.
IDLE="${IDLE:-30}" # сторожевой таймер udp_probe recv. ВАЖНО: тикает
# с момента СТАРТА, не с первой датаграммы → зазор
# старт-B→передача должен быть скриптованным (~4 с),
# а не ручной вставкой команд. Штатное завершение —
# активный killall из шага [5], не по таймауту.
if command -v sshpass >/dev/null; then
SSH=(sshpass -p "$PLUTO_PASS" ssh -o StrictHostKeyChecking=no)
else
SSH=(ssh)
echo "подсказка: apt install sshpass — и пароль вводить не придётся"
fi
if command -v sshpass >/dev/null; then
SCP=(sshpass -p "$PLUTO_PASS" scp -O -o StrictHostKeyChecking=no)
else
SCP=(scp -O)
fi
echo "=== [1/6] Тестовый файл ${SIZE_KB} КБ (чанк ${CHUNK} Б, темп ${PACE_MS} мс) ==="
dd if=/dev/urandom of=/tmp/probe_in.bin bs=1024 count="$SIZE_KB" status=none
MD5_SRC=$(md5sum /tmp/probe_in.bin | cut -d' ' -f1)
DGRAMS=$(( (SIZE_KB * 1024 + CHUNK - 1) / CHUNK ))
echo "md5: $MD5_SRC | ожидается датаграмм: $DGRAMS"
echo "=== [2/6] Заливка файла на Pluto A ($A) ==="
"${SCP[@]}" /tmp/probe_in.bin "root@$A:/tmp/"
echo "=== [3/6] Старт цепочки на Pluto B ($B): receiver | udp_gw -d → udp_probe recv ==="
# heredoc в `sh -s`: stdin ssh занят скриптом → фоновый ssh не ловит SIGTTIN
# (без этого `ssh ... &` уходит в «Остановлен» при попытке читать терминал).
"${SSH[@]}" "root@$B" 'sh -s' <<EOF &
rm -f /tmp/probe_out.bin /tmp/rx.log /tmp/gwd.log /tmp/probe_rx.log
/tmp/receiver -f $FREQ -r $RATE -b $BW -c $FEC -u local: 2>/tmp/rx.log \
| /tmp/udp_gw -d 127.0.0.1:$PORT_B 2>/tmp/gwd.log &
/tmp/udp_probe recv $PORT_B $IDLE > /tmp/probe_out.bin 2>/tmp/probe_rx.log
killall receiver udp_gw 2>/dev/null || true
EOF
B_PID=$!
sleep 4 # дать приёмнику прогреться до старта TX
echo "=== [4/6] Передача с Pluto A: udp_probe send → udp_gw -l → transmitter ==="
# mkfifo: у пайпа `$!` — только последний процесс, а гейтвей надо убить отдельно
# (его выход = EOF транзмиттеру → штатное завершение передачи).
"${SSH[@]}" "root@$A" 'sh -s' <<EOF
rm -f /tmp/tx.log /tmp/gwl.log /tmp/probe_tx.log /tmp/gw.fifo
mkfifo /tmp/gw.fifo
/tmp/udp_gw -l $PORT_A > /tmp/gw.fifo 2>/tmp/gwl.log &
GWP=\$!
/tmp/transmitter -f $FREQ -r $RATE -b $BW -g $TXGAIN -p $PAUSE \
-c $FEC $GFLAG -u local: < /tmp/gw.fifo 2>/tmp/tx.log &
TXP=\$!
sleep 1
/tmp/udp_probe send 127.0.0.1:$PORT_A $CHUNK $PACE_MS \
< /tmp/probe_in.bin 2>/tmp/probe_tx.log
sleep 2
kill \$GWP 2>/dev/null || true
wait \$TXP
rm -f /tmp/gw.fifo
EOF
echo "=== [5/6] Гашение цепочки B ==="
sleep 3 # дохлебать хвост эфира
# udp_probe по SIGTERM печатает статистику и закрывает файл — гасим активно,
# не дожидаясь IDLE (тот же паттерн sleep+kill, что в test_file_link.sh).
"${SSH[@]}" -n "root@$B" "killall udp_probe receiver udp_gw 2>/dev/null || true" || true
wait "$B_PID" 2>/dev/null || true
echo "=== [6/6] Сверка ==="
MD5_DST=$("${SSH[@]}" -n "root@$B" "md5sum /tmp/probe_out.bin 2>/dev/null | cut -d' ' -f1" || echo ет_файла")
SIZE_DST=$("${SSH[@]}" -n "root@$B" "wc -c < /tmp/probe_out.bin 2>/dev/null" || echo 0)
echo "источник: $MD5_SRC ($((SIZE_KB*1024)) байт)"
echo "туннель: $MD5_DST ($SIZE_DST байт)"
echo
echo "--- A: udp_probe send ---"; "${SSH[@]}" -n "root@$A" "cat /tmp/probe_tx.log" || true
echo "--- A: udp_gw -l (вход) ---"; "${SSH[@]}" -n "root@$A" "tail -2 /tmp/gwl.log" || true
echo "--- A: transmitter ---"; "${SSH[@]}" -n "root@$A" "tail -4 /tmp/tx.log" || true
echo "--- B: receiver ---"; "${SSH[@]}" -n "root@$B" "tail -6 /tmp/rx.log" || true
echo "--- B: udp_gw -d (выход) ---";"${SSH[@]}" -n "root@$B" "tail -2 /tmp/gwd.log" || true
echo "--- B: udp_probe recv ---"; "${SSH[@]}" -n "root@$B" "cat /tmp/probe_rx.log" || true
echo
if [ "$MD5_SRC" = "$MD5_DST" ]; then
echo "РЕЗУЛЬТАТ: OK — туннель прозрачен, $DGRAMS датаграмм доставлены байт-в-байт"
else
echo "РЕЗУЛЬТАТ: FAIL — разбор по счётчикам выше:"
echo " - 'дыр(id)' > 0 или 'ресинк' > 0 при живом потоке → НЕ баг туннеля:"
echo " радиопотери сверх group-FEC 16+2 (на симплексе ARQ нет, техдолг #6)."
echo " Контракт соблюдён: дыры посчитаны, поток рекордов не развалился."
echo " Меры: TXGAIN ближе к 20, антенны разнести/переориентировать."
echo " - 'дропов' > 0 у 'udp_gw -l (вход)' → вход быстрее линка (~107 КБ/с"
echo " на -G -p 3000): подними PACE_MS. Это контрактный дроп, семантика UDP."
echo " - размер 0 и в rx.log 0 кадров → приёмник не работал во время передачи:"
echo " частота/усиление/антенны, либо цепочка B умерла по IDLE (=$IDLE с)."
echo " - размер совпал, md5 нет → искажение полезной нагрузки: техдолг #1/#3."
fi