]> git.99rst.org Git - openwrt-packages.git/commitdiff
tcpreplay: fix CI tests for the QEMU runtime
authorAlexandru Ardelean <redacted>
Thu, 20 Aug 2026 18:01:43 +0000 (21:01 +0300)
committerAlexandru Ardelean <redacted>
Mon, 24 Aug 2026 17:05:46 +0000 (20:05 +0300)
The generic per-executable version probe and the old test.sh both invoke
tcpreplay --version. Under the QEMU test runtime tcpreplay and
tcpreplay-edit abort at startup on the interface link probe
("eth0: SIOCETHTOOL(ETHTOOL_GLINK) ioctl failed: Not a tty") before
autoopts can print the version, which fails the tcpreplay-all test and
warns on the standalone tcpreplay/tcpreplay-edit packages.

Add a test-version.sh that disables the flaky generic probe and asserts
each tool's version without needing an interface, and rewrite test.sh to
exercise the file-processing core (tcpcapinfo dissect, tcprewrite edit,
tcpprep cache) on a small synthesized capture instead of shelling out to
--version, which the CI infrastructure already covers.

Signed-off-by: Alexandru Ardelean <redacted>
net/tcpreplay/test-version.sh [new file with mode: 0755]
net/tcpreplay/test.sh [changed mode: 0644->0755]

diff --git a/net/tcpreplay/test-version.sh b/net/tcpreplay/test-version.sh
new file mode 100755 (executable)
index 0000000..e0a7326
--- /dev/null
@@ -0,0 +1,42 @@
+#!/bin/sh
+
+# shellcheck shell=busybox
+
+# tcpreplay and tcpreplay-edit probe a network interface's link state while
+# parsing their options, so under the QEMU runtime running any of these tools
+# with --version is unreliable: tcpreplay/tcpreplay-edit either abort
+# ("eth0: SIOCETHTOOL(ETHTOOL_GLINK) ioctl failed: Not a tty") or hang forever
+# (observed on big-endian mips). Do not execute the binaries here at all;
+# assert the version string compiled into each one instead. Actually running
+# the file-processing tools is covered by test.sh. The presence of this script
+# also disables the generic per-executable probe, which would otherwise run
+# the same hanging --version.
+
+version="$2"
+
+check() {
+       bin="/usr/bin/$1"
+       [ -x "$bin" ] || {
+               echo "missing executable: $bin" >&2
+               return 1
+       }
+       grep -qaF "$version" "$bin" || {
+               echo "version $version not found in $bin" >&2
+               return 1
+       }
+}
+
+case "$1" in
+tcpbridge | tcpcapinfo | tcpliveplay | tcpprep | tcpreplay | tcpreplay-edit | tcprewrite)
+       check "$1"
+       ;;
+tcpreplay-all)
+       # Meta-package: ships no binary of its own, the modules arrive as
+       # dependencies. Validate a representative always-present module.
+       check tcprewrite
+       ;;
+*)
+       echo "Untested package: $1" >&2
+       exit 1
+       ;;
+esac
old mode 100644 (file)
new mode 100755 (executable)
index b7a8462..fcba1c0
@@ -1,15 +1,53 @@
 #!/bin/sh
 
+# shellcheck shell=busybox
+
+# Exercise the suite through the meta-package, which installs every tool.
+# Live replay (tcpreplay/tcpbridge/tcpliveplay) needs a real interface and
+# cannot run under the QEMU runtime, so drive the file-processing core
+# (dissect, rewrite, cache) instead; the version of every binary is asserted
+# separately in test-version.sh.
 [ "$1" = "tcpreplay-all" ] || exit 0
 
-EXEC_LIST="tcpbridge tcpliveplay tcpreplay tcprewrite tcpcapinfo tcpprep tcpreplay-edit"
+pcap="/tmp/tcpreplay-$$.pcap"
+out="/tmp/tcpreplay-$$-out.pcap"
+cache="/tmp/tcpreplay-$$.cache"
+trap 'rm -f "$pcap" "$out" "$cache"' EXIT
+
+# A minimal LINKTYPE_ETHERNET capture holding one Ethernet/IPv4/UDP frame
+# (ports 4096->8080 so tcpprep does not attempt DNS parsing, plus payload so
+# the frame clears tcpprep's minimum length), written byte-for-byte with
+# printf octal escapes because base64 is not in the runtime busybox:
+# 24-byte pcap header + 16-byte record + 60-byte frame.
+printf '\324\303\262\241\002\000\004\000\000\000\000\000\000\000\000\000\377\377\000\000\001\000\000\000\000\000\000\000\000\000\000\000\074\000\000\000\074\000\000\000\377\377\377\377\377\377\000\021\042\063\104\125\010\000\105\000\000\056\000\001\000\000\100\021\000\000\012\000\000\001\012\000\000\002\020\000\037\220\000\032\000\000\164\143\160\162\145\160\154\141\171\055\164\145\163\164\000\000\000\000' >"$pcap"
+
+# tcpcapinfo: the pcap dissector must read the header of the capture we wrote.
+tcpcapinfo "$pcap" 2>&1 | grep -q "snaplen" || {
+       echo "tcpcapinfo failed to dissect the capture"
+       exit 1
+}
+
+# tcprewrite: remap the destination IP and fix checksums; a successful edit
+# writes a non-empty output capture.
+tcprewrite --infile="$pcap" --outfile="$out" \
+       --dstipmap=0.0.0.0/0:192.168.9.0/24 --fixcsum || {
+       echo "tcprewrite failed to rewrite the capture"
+       exit 1
+}
+[ -s "$out" ] || {
+       echo "tcprewrite produced no output capture"
+       exit 1
+}
 
-for executable in $EXEC_LIST ; do
-       $executable --version
-       $executable --version 2>&1 | grep "$2"
-       [ $? == 0 ] || {
-               echo "Problem or incorrect version for '$executable'"
-               exit 1
-       }
-done
+# tcpprep: build a replay cache by auto-splitting the endpoints; the cache
+# file must be created.
+tcpprep --auto=bridge --pcap="$pcap" --cachefile="$cache" || {
+       echo "tcpprep failed to build a cache file"
+       exit 1
+}
+[ -s "$cache" ] || {
+       echo "tcpprep produced no cache file"
+       exit 1
+}
 
+echo "tcpreplay suite: functional test passed"
git clone https://git.99rst.org/PROJECT