From: Alexandru Ardelean Date: Thu, 20 Aug 2026 18:01:43 +0000 (+0300) Subject: tcpreplay: fix CI tests for the QEMU runtime X-Git-Url: http://git.99rst.org/?a=commitdiff_plain;h=89f358cf36f4b45a0ed5d1411184a5de8be936c6;p=openwrt-packages.git tcpreplay: fix CI tests for the QEMU runtime 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 --- diff --git a/net/tcpreplay/test-version.sh b/net/tcpreplay/test-version.sh new file mode 100755 index 000000000..e0a73267c --- /dev/null +++ b/net/tcpreplay/test-version.sh @@ -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 diff --git a/net/tcpreplay/test.sh b/net/tcpreplay/test.sh old mode 100644 new mode 100755 index b7a846261..fcba1c094 --- a/net/tcpreplay/test.sh +++ b/net/tcpreplay/test.sh @@ -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"