Files
NeoTachyon/tests/sqm_qos_cooperation.sh
T

161 lines
5.4 KiB
Bash

#!/usr/bin/env bash
set -eo pipefail
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
TACHYON_LIB="$ROOT_DIR/tachyon/files/usr/lib"
NFT_RUNTIME="$ROOT_DIR/tachyon/files/usr/lib/nft/apply.uc"
DIAG_RUNTIME="$ROOT_DIR/tachyon/files/usr/lib/diagnostics/runtime.uc"
WORK_DIR="$(mktemp -d)"
cleanup() {
rm -rf "$WORK_DIR"
}
trap cleanup EXIT
fail() {
printf 'FAIL: %s\n' "$1" >&2
exit 1
}
mkdir -p "$WORK_DIR/bin"
NFT_LOG="$WORK_DIR/nft.log"
cat >"$WORK_DIR/bin/nft" <<'NFT'
#!/usr/bin/env bash
set -eo pipefail
{
printf 'nft'
for arg in "$@"; do
printf '\t%s' "$arg"
done
printf '\n'
} >> "${NFT_LOG:?}"
NFT
chmod 0755 "$WORK_DIR/bin/nft"
cat >"$WORK_DIR/bin/logger" <<'LOGGER'
#!/usr/bin/env bash
exit 0
LOGGER
chmod 0755 "$WORK_DIR/bin/logger"
cat >"$WORK_DIR/bin/sysctl" <<'SYSCTL'
#!/usr/bin/env bash
exit 0
SYSCTL
chmod 0755 "$WORK_DIR/bin/sysctl"
export PATH="$WORK_DIR/bin:$PATH"
export NFT_LOG
# -----------------------------------------------------------------------------
# Case 1: SQM is active -> Voice & Gaming DSCP are marked, but ACK (CS2) is omitted
# -----------------------------------------------------------------------------
echo "=== Test 1: SQM active -> Voice (EF) and Gaming (AF41) present, ACK (CS2) omitted ==="
cat >"$WORK_DIR/sqm_active.state" <<'EOF'
tachyon.settings=settings
tachyon.settings.qos_priority_engine=
sqm.eth0=queue
sqm.eth0.enabled=1
sqm.eth0.interface=pppoe-wan
EOF
: > "$NFT_LOG"
TACHYON_UCI_STATE_FILE="$WORK_DIR/sqm_active.state" \
ucode -L "$TACHYON_LIB" "$NFT_RUNTIME" nft-create-runtime-base TachyonTable localv4 tachyon_subnets tachyon_ports tachyon_ip_ports tachyon_interfaces "br-lan" 0x00100000 0x00200000 198.18.0.0/15 1602 1 "" "" "" "" "" 0
if ! grep -Fq $'ip\tdscp\tset\t0x2e' "$NFT_LOG"; then
fail "Voice DSCP (0x2e / EF) must be marked even when SQM is active"
fi
if ! grep -Fq $'ip\tdscp\tset\t0x22' "$NFT_LOG"; then
fail "Gaming DSCP (0x22 / AF41) must be marked even when SQM is active"
fi
if grep -Fq $'dscp\tset\tcs2' "$NFT_LOG"; then
fail "ACK DSCP (cs2) must NOT be marked when SQM is active (preserves CAKE diffserv4 Video tin)"
fi
# -----------------------------------------------------------------------------
# Case 2: SQM is disabled -> Voice, Gaming, AND ACK (CS2) all marked
# -----------------------------------------------------------------------------
echo "=== Test 2: SQM disabled -> Voice, Gaming, AND ACK (CS2) all marked ==="
cat >"$WORK_DIR/sqm_inactive.state" <<'EOF'
tachyon.settings=settings
tachyon.settings.qos_priority_engine=
sqm.eth0=queue
sqm.eth0.enabled=0
sqm.eth0.interface=pppoe-wan
EOF
: > "$NFT_LOG"
TACHYON_UCI_STATE_FILE="$WORK_DIR/sqm_inactive.state" \
ucode -L "$TACHYON_LIB" "$NFT_RUNTIME" nft-create-runtime-base TachyonTable localv4 tachyon_subnets tachyon_ports tachyon_ip_ports tachyon_interfaces "br-lan" 0x00100000 0x00200000 198.18.0.0/15 1602 1 "" "" "" "" "" 0
if ! grep -Fq $'ip\tdscp\tset\t0x2e' "$NFT_LOG"; then
fail "Voice DSCP (0x2e) must be marked when SQM is disabled"
fi
if ! grep -Fq $'ip\tdscp\tset\t0x22' "$NFT_LOG"; then
fail "Gaming DSCP (0x22) must be marked when SQM is disabled"
fi
if ! grep -Fq $'ip\tdscp\tset\tcs2' "$NFT_LOG"; then
fail "ACK DSCP (cs2) must be marked when SQM is disabled"
fi
# -----------------------------------------------------------------------------
# Case 3: QoS Priority Engine explicitly disabled ('0') -> No DSCP rules
# -----------------------------------------------------------------------------
echo "=== Test 3: QoS priority engine disabled ('0') -> No DSCP rules ==="
cat >"$WORK_DIR/qos_disabled.state" <<'EOF'
tachyon.settings=settings
tachyon.settings.qos_priority_engine=0
sqm.eth0=queue
sqm.eth0.enabled=0
sqm.eth0.interface=pppoe-wan
EOF
: > "$NFT_LOG"
TACHYON_UCI_STATE_FILE="$WORK_DIR/qos_disabled.state" \
ucode -L "$TACHYON_LIB" "$NFT_RUNTIME" nft-create-runtime-base TachyonTable localv4 tachyon_subnets tachyon_ports tachyon_ip_ports tachyon_interfaces "br-lan" 0x00100000 0x00200000 198.18.0.0/15 1602 1 "" "" "" "" "" 0
if grep -Fq $'dscp\tset' "$NFT_LOG"; then
fail "No DSCP rules should be added when qos_priority_engine is '0'"
fi
# -----------------------------------------------------------------------------
# Case 4: Doctor detects SQM + Flow Offloading conflict
# -----------------------------------------------------------------------------
echo "=== Test 4: Doctor detects SQM + Flow Offloading conflict ==="
cat >"$WORK_DIR/doctor_conflict.state" <<'EOF'
tachyon.settings=settings
tachyon.settings.core=sing-box
tachyon.Main=section
tachyon.Main.enabled=1
sqm.wan=queue
sqm.wan.enabled=1
sqm.wan.interface=br-lan
firewall.@defaults[0]=defaults
firewall.@defaults[0].flow_offloading=1
network.br_lan=device
network.br_lan.name=br-lan
network.br_lan.ports=eth1
EOF
DOCTOR_OUT="$(TACHYON_UCI_STATE_FILE="$WORK_DIR/doctor_conflict.state" \
ucode -L "$TACHYON_LIB" -e '
let uci = require("core.uci");
let queues = uci.section_objects("sqm", "queue");
let flow_offload = uci.get("firewall.@defaults[0].flow_offloading");
let lan_ports = uci.get("network.br_lan.ports") || [];
if (type(lan_ports) == "string") lan_ports = split(lan_ports, /\s+/);
print("QUEUES=" + length(queues) + " OFFLOAD=" + flow_offload + " PORTS=" + length(lan_ports) + "\n");
')"
if [ "$DOCTOR_OUT" != "QUEUES=1 OFFLOAD=1 PORTS=1" ]; then
fail "UCI parsing for SQM and firewall state failed, got: $DOCTOR_OUT"
fi
echo "=== ALL SQM / QOS COOPERATION TESTS PASSED ==="