Доработка. Проверка шаг 4: радио-смоук на антеннах через test_udp_tunnel.sh (TXGAIN=-20)
This commit is contained in:
129
scripts/test_udp_tunnel.sh
Normal file
129
scripts/test_udp_tunnel.sh
Normal file
@@ -0,0 +1,129 @@
|
||||
#!/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
|
||||
Reference in New Issue
Block a user