From: Bochao Cao <[email protected]>
test_xdp_features.sh waits for any xdp_features listener to appear and
uses pidof during cleanup. A concurrent test can therefore make another
test proceed before its own DUT is ready, and cleanup kills every
xdp_features process on the host. The readiness loop also has no timeout,
so a DUT that exits before listening leaves the test hung indefinitely.
Track one active DUT at a time, wait for ss to report that exact PID with
a bounded retry loop, and reap it after each test. Consult the shell job
table before signaling the DUT so a stale PID cannot target an unrelated
process. On failure, terminate the shell job with SIGKILL and reap it so
blocked I/O cannot hang cleanup. Install an EXIT trap and signal handlers
so failure paths also remove network setup.
Fixes: 4dba3e7852b7 ("selftests/bpf: introduce XDP compliance test tool")
Closes: https://bugs.debian.org/1136522
Signed-off-by: Bochao Cao <[email protected]>
---
Tests:
- bash -n tools/testing/selftests/bpf/test_xdp_features.sh
- make -C tools/testing/selftests/bpf xdp_features
- sudo tools/testing/selftests/bpf/test_xdp_features.sh
- verified cleanup terminates a blocked DUT without affecting an unrelated
process
---
Changes in v2:
- Clarify that avoiding name-wide process matching, rather than dropping a
dependency, is the motivation.
- Track and reap one active DUT at a time instead of retaining historical PIDs.
- Address PID reuse by signaling only the current Bash job during cleanup.
- Use SIGKILL on failure cleanup so blocked DUT I/O cannot hang wait
indefinitely.
- Link to v1:
https://patch.msgid.link/20260805-xdp-dut-process-lifecycle-gmail-v1-1-45984df8d...@gmail.com
---
tools/testing/selftests/bpf/test_xdp_features.sh | 82 ++++++++++++++++++------
1 file changed, 62 insertions(+), 20 deletions(-)
diff --git a/tools/testing/selftests/bpf/test_xdp_features.sh
b/tools/testing/selftests/bpf/test_xdp_features.sh
index 0aa71c4455c0..35ce0d4e2418 100755
--- a/tools/testing/selftests/bpf/test_xdp_features.sh
+++ b/tools/testing/selftests/bpf/test_xdp_features.sh
@@ -8,6 +8,7 @@ readonly V0_IP6=2001:db8::11
readonly V1_IP6=2001:db8::1
ret=1
+dut_pid=""
setup() {
{
@@ -30,77 +31,118 @@ setup() {
} > /dev/null 2>&1
}
+terminate_dut_server() {
+ [ -z "$dut_pid" ] && return
+
+ # Use the shell job instead of a PID which may have been reused.
+ if [ "$(jobs -pr %% 2> /dev/null)" = "$dut_pid" ]; then
+ kill -KILL %% 2> /dev/null || true
+ fi
+
+ wait "$dut_pid" 2> /dev/null || true
+ dut_pid=""
+}
+
cleanup() {
- ip link del v1 2> /dev/null
- ip netns del ${NS} 2> /dev/null
- [ "$(pidof xdp_features)" = "" ] || kill $(pidof xdp_features) 2>
/dev/null
+ terminate_dut_server
+ ip link del v1 2> /dev/null || true
+ ip netns del "${NS}" 2> /dev/null || true
}
wait_for_dut_server() {
- while sleep 1; do
- ss -tlp | grep -q xdp_features
- [ $? -eq 0 ] && break
+ local i
+
+ for ((i = 0; i < 10; i++)); do
+ if [ "$(jobs -pr %% 2> /dev/null)" != "$dut_pid" ]; then
+ echo "xdp_features server $dut_pid exited before
accepting connections" >&2
+ return 1
+ fi
+
+ if ss -tlp 2> /dev/null | grep -q "pid=$dut_pid,"; then
+ return 0
+ fi
+
+ sleep 1
done
+
+ echo "Timed out waiting for xdp_features server $dut_pid" >&2
+ return 1
+}
+
+start_dut_server() {
+ ./xdp_features "$@" &
+ dut_pid=$!
+ wait_for_dut_server
+}
+
+reap_dut_server() {
+ local status=0
+
+ wait "$dut_pid" || status=$?
+ dut_pid=""
+ return "$status"
}
test_xdp_features() {
setup
## XDP_PASS
- ./xdp_features -f XDP_PASS -D $V1_IP6 -T $V0_IP6 v1 &
- wait_for_dut_server
+ start_dut_server -f XDP_PASS -D $V1_IP6 -T $V0_IP6 v1
ip netns exec ${NS} ./xdp_features -t -f XDP_PASS \
-D $V1_IP6 -C $V1_IP6 \
-T $V0_IP6 v0
[ $? -ne 0 ] && exit
+ reap_dut_server
## XDP_DROP
- ./xdp_features -f XDP_DROP -D ::ffff:$V1_IP4 -T ::ffff:$V0_IP4 v1 &
- wait_for_dut_server
+ start_dut_server -f XDP_DROP -D ::ffff:$V1_IP4 -T ::ffff:$V0_IP4 v1
ip netns exec ${NS} ./xdp_features -t -f XDP_DROP \
-D ::ffff:$V1_IP4 \
-C ::ffff:$V1_IP4 \
-T ::ffff:$V0_IP4 v0
[ $? -ne 0 ] && exit
+ reap_dut_server
## XDP_ABORTED
- ./xdp_features -f XDP_ABORTED -D $V1_IP6 -T $V0_IP6 v1 &
- wait_for_dut_server
+ start_dut_server -f XDP_ABORTED -D $V1_IP6 -T $V0_IP6 v1
ip netns exec ${NS} ./xdp_features -t -f XDP_ABORTED \
-D $V1_IP6 -C $V1_IP6 \
-T $V0_IP6 v0
[ $? -ne 0 ] && exit
+ reap_dut_server
## XDP_TX
- ./xdp_features -f XDP_TX -D ::ffff:$V1_IP4 -T ::ffff:$V0_IP4 v1 &
- wait_for_dut_server
+ start_dut_server -f XDP_TX -D ::ffff:$V1_IP4 -T ::ffff:$V0_IP4 v1
ip netns exec ${NS} ./xdp_features -t -f XDP_TX \
-D ::ffff:$V1_IP4 \
-C ::ffff:$V1_IP4 \
-T ::ffff:$V0_IP4 v0
[ $? -ne 0 ] && exit
+ reap_dut_server
## XDP_REDIRECT
- ./xdp_features -f XDP_REDIRECT -D $V1_IP6 -T $V0_IP6 v1 &
- wait_for_dut_server
+ start_dut_server -f XDP_REDIRECT -D $V1_IP6 -T $V0_IP6 v1
ip netns exec ${NS} ./xdp_features -t -f XDP_REDIRECT \
-D $V1_IP6 -C $V1_IP6 \
-T $V0_IP6 v0
[ $? -ne 0 ] && exit
+ reap_dut_server
## XDP_NDO_XMIT
- ./xdp_features -f XDP_NDO_XMIT -D ::ffff:$V1_IP4 -T ::ffff:$V0_IP4 v1 &
- wait_for_dut_server
+ start_dut_server -f XDP_NDO_XMIT -D ::ffff:$V1_IP4 -T ::ffff:$V0_IP4 v1
ip netns exec ${NS} ./xdp_features -t -f XDP_NDO_XMIT \
-D ::ffff:$V1_IP4 \
-C ::ffff:$V1_IP4 \
-T ::ffff:$V0_IP4 v0
ret=$?
- cleanup
+ reap_dut_server
}
set -e
-trap cleanup 2 3 6 9
+trap cleanup EXIT
+trap 'exit 129' HUP
+trap 'exit 130' INT
+trap 'exit 143' TERM
test_xdp_features
---
base-commit: 07cb86aa50816b070b99c89bf948762ef035a1f2
change-id: 20260805-xdp-dut-process-lifecycle-gmail-6d60bf8dcdf1
Best regards,
--
Bochao Cao <[email protected]>