mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-07-23 09:47:31 -04:00
selftests: drv-net: convert so_txtime to drv-net
In preparation for extending to pacing hardware offload, convert the so_txtime.sh test to a drv-net test that can be run against netdevsim and real hardware. Also update so_txtime.c to not exit on first failure, but run to completion and report exit code there. This helps with debugging unexpected results, especially when processing multiple packets, as happens in the "reverse_order" testcase. Signed-off-by: Willem de Bruijn <willemb@google.com> ---- v6 -> v7 - update test to use new argument expect_fail - v6 received Reviewed-by, but dropped due to above (minor) change v5 -> v6 - fix order in tools/testing/selftests/drivers/net/config v4 -> v5 - move qdisc setup/restore into each test - add tc to utils.py (separate patch) - test expected failure (separate patch) - fix pylint - convert fail to pass for timing errors if KSFT_MACHINE_SLOW (cmd does not special case KSFT_SKIP process returncode yet) Responses to sashiko review - The test converts per packet failure to errors, to continue testing other packets, but other error() cases are not in scope. - The test starts sender and receiver at an absolute future time, like the original test. This assumes ~msec scale sync'ed clocks. - The tc qdisc replace command works fine with noqueue. Tested manually. v3 -> v4 - restore original qdisc after test - drop unnecessary underscore in tap test names v2 -> v3 - Makefile: so_txtime from YNL_GEN_FILES to TEST_GEN_FILES (Sashiko, NIPA) v1 -> v2 - move so_txtime.c for net/lib to drivers/net (Jakub) - fix drivers/net/config order (Jakub) - detect passing when failure is expected (Jakub, Sashiko) - pass pylint --disable=R (Jakub) - only call ksft_run once (Jakub) - do not sleep if waiting time is negative (Sashiko) - add \n when converting error() to fprintf() (Sashiko) - 4 space indentation, instead of 2 space - increase sync delay from 100 to 200ms, to fix rare vng flakes Link: https://patch.msgid.link/20260504174056.565319-4-willemdebruijn.kernel@gmail.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
committed by
Jakub Kicinski
parent
49bf9e5e7c
commit
5c6baef388
@@ -1,3 +1,4 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
napi_id_helper
|
||||
psp_responder
|
||||
so_txtime
|
||||
|
||||
@@ -7,6 +7,7 @@ TEST_INCLUDES := $(wildcard lib/py/*.py) \
|
||||
|
||||
TEST_GEN_FILES := \
|
||||
napi_id_helper \
|
||||
so_txtime \
|
||||
# end of TEST_GEN_FILES
|
||||
|
||||
TEST_PROGS := \
|
||||
@@ -21,6 +22,7 @@ TEST_PROGS := \
|
||||
queues.py \
|
||||
ring_reconfig.py \
|
||||
shaper.py \
|
||||
so_txtime.py \
|
||||
stats.py \
|
||||
xdp.py \
|
||||
# end of TEST_PROGS
|
||||
|
||||
@@ -8,5 +8,7 @@ CONFIG_NETCONSOLE=m
|
||||
CONFIG_NETCONSOLE_DYNAMIC=y
|
||||
CONFIG_NETCONSOLE_EXTENDED_LOG=y
|
||||
CONFIG_NETDEVSIM=m
|
||||
CONFIG_NET_SCH_ETF=m
|
||||
CONFIG_NET_SCH_FQ=m
|
||||
CONFIG_VLAN_8021Q=m
|
||||
CONFIG_XDP_SOCKETS=y
|
||||
|
||||
@@ -33,6 +33,8 @@
|
||||
#include <unistd.h>
|
||||
#include <poll.h>
|
||||
|
||||
#include "kselftest.h"
|
||||
|
||||
static int cfg_clockid = CLOCK_TAI;
|
||||
static uint16_t cfg_port = 8000;
|
||||
static int cfg_variance_us = 4000;
|
||||
@@ -43,6 +45,8 @@ static bool cfg_rx;
|
||||
static uint64_t glob_tstart;
|
||||
static uint64_t tdeliver_max;
|
||||
|
||||
static int errors;
|
||||
|
||||
/* encode one timed transmission (of a 1B payload) */
|
||||
struct timed_send {
|
||||
char data;
|
||||
@@ -131,13 +135,15 @@ static void do_recv_one(int fdr, struct timed_send *ts)
|
||||
fprintf(stderr, "payload:%c delay:%lld expected:%lld (us)\n",
|
||||
rbuf[0], (long long)tstop, (long long)texpect);
|
||||
|
||||
if (rbuf[0] != ts->data)
|
||||
error(1, 0, "payload mismatch. expected %c", ts->data);
|
||||
if (rbuf[0] != ts->data) {
|
||||
fprintf(stderr, "payload mismatch. expected %c\n", ts->data);
|
||||
errors++;
|
||||
}
|
||||
|
||||
if (llabs(tstop - texpect) > cfg_variance_us) {
|
||||
fprintf(stderr, "exceeds variance (%d us)\n", cfg_variance_us);
|
||||
if (!getenv("KSFT_MACHINE_SLOW"))
|
||||
exit(1);
|
||||
errors++;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -255,8 +261,12 @@ static void start_time_wait(void)
|
||||
return;
|
||||
|
||||
now = gettime_ns(CLOCK_REALTIME);
|
||||
if (cfg_start_time_ns < now)
|
||||
if (cfg_start_time_ns < now) {
|
||||
fprintf(stderr, "FAIL: start time already passed\n");
|
||||
if (!getenv("KSFT_MACHINE_SLOW"))
|
||||
errors++;
|
||||
return;
|
||||
}
|
||||
|
||||
err = usleep((cfg_start_time_ns - now) / 1000);
|
||||
if (err)
|
||||
@@ -513,5 +523,10 @@ int main(int argc, char **argv)
|
||||
else
|
||||
do_test_tx((void *)&cfg_src_addr, cfg_alen);
|
||||
|
||||
return 0;
|
||||
if (errors) {
|
||||
fprintf(stderr, "FAIL: %d errors\n", errors);
|
||||
return KSFT_FAIL;
|
||||
}
|
||||
|
||||
return KSFT_PASS;
|
||||
}
|
||||
96
tools/testing/selftests/drivers/net/so_txtime.py
Executable file
96
tools/testing/selftests/drivers/net/so_txtime.py
Executable file
@@ -0,0 +1,96 @@
|
||||
#!/usr/bin/env python3
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
"""Regression tests for the SO_TXTIME interface.
|
||||
|
||||
Test delivery time in FQ and ETF qdiscs.
|
||||
"""
|
||||
|
||||
import time
|
||||
|
||||
from lib.py import ksft_exit, ksft_run, ksft_variants
|
||||
from lib.py import KsftNamedVariant, KsftSkipEx
|
||||
from lib.py import NetDrvEpEnv, bkg, cmd, defer, tc
|
||||
|
||||
|
||||
def test_so_txtime(cfg, clockid, ipver, args_tx, args_rx, expect_success):
|
||||
"""Main function. Run so_txtime as sender and receiver."""
|
||||
bin_path = cfg.test_dir / "so_txtime"
|
||||
|
||||
tstart = time.time_ns() + 200_000_000
|
||||
|
||||
cmd_addr = f"-S {cfg.addr_v[ipver]} -D {cfg.remote_addr_v[ipver]}"
|
||||
cmd_base = f"{bin_path} -{ipver} -c {clockid} -t {tstart} {cmd_addr}"
|
||||
cmd_rx = f"{cmd_base} {args_rx} -r"
|
||||
cmd_tx = f"{cmd_base} {args_tx}"
|
||||
|
||||
with bkg(cmd_rx, host=cfg.remote, fail=expect_success,
|
||||
expect_fail=(not expect_success), exit_wait=True):
|
||||
cmd(cmd_tx)
|
||||
|
||||
|
||||
def _qdisc_setup(ifname, qdisc, optargs=""):
|
||||
"""Replace root qdisc. Restore the original after the test.
|
||||
|
||||
If the original is mq, children will be of type default_qdisc.
|
||||
"""
|
||||
orig = tc(f"qdisc show dev {ifname} root", json=True)[0].get("kind", None)
|
||||
defer(tc, f"qdisc replace dev {ifname} root {orig}")
|
||||
tc(f"qdisc replace dev {ifname} root {qdisc} {optargs}")
|
||||
|
||||
|
||||
def _test_variants_mono():
|
||||
for ipver in ["4", "6"]:
|
||||
for testcase in [
|
||||
["no_delay", "a,-1", "a,-1"],
|
||||
["zero_delay", "a,0", "a,0"],
|
||||
["one_pkt", "a,10", "a,10"],
|
||||
["in_order", "a,10,b,20", "a,10,b,20"],
|
||||
["reverse_order", "a,20,b,10", "b,20,a,20"],
|
||||
]:
|
||||
name = f"v{ipver}_{testcase[0]}"
|
||||
yield KsftNamedVariant(name, ipver, testcase[1], testcase[2])
|
||||
|
||||
|
||||
@ksft_variants(_test_variants_mono())
|
||||
def test_so_txtime_mono(cfg, ipver, args_tx, args_rx):
|
||||
"""Run all variants of monotonic (fq) tests."""
|
||||
_qdisc_setup(cfg.ifname, "fq")
|
||||
test_so_txtime(cfg, "mono", ipver, args_tx, args_rx, True)
|
||||
|
||||
|
||||
def _test_variants_etf():
|
||||
for ipver in ["4", "6"]:
|
||||
for testcase in [
|
||||
["no_delay", "a,-1", "a,-1", False],
|
||||
["zero_delay", "a,0", "a,0", False],
|
||||
["one_pkt", "a,10", "a,10", True],
|
||||
["in_order", "a,10,b,20", "a,10,b,20", True],
|
||||
["reverse_order", "a,20,b,10", "b,10,a,20", True],
|
||||
]:
|
||||
name = f"v{ipver}_{testcase[0]}"
|
||||
yield KsftNamedVariant(
|
||||
name, ipver, testcase[1], testcase[2], testcase[3]
|
||||
)
|
||||
|
||||
|
||||
@ksft_variants(_test_variants_etf())
|
||||
def test_so_txtime_etf(cfg, ipver, args_tx, args_rx, expect_fail):
|
||||
"""Run all variants of etf tests."""
|
||||
try:
|
||||
_qdisc_setup(cfg.ifname, "etf", "clockid CLOCK_TAI delta 400000")
|
||||
except Exception as e:
|
||||
raise KsftSkipEx("tc does not support qdisc etf. skipping") from e
|
||||
|
||||
test_so_txtime(cfg, "tai", ipver, args_tx, args_rx, expect_fail)
|
||||
|
||||
|
||||
def main() -> None:
|
||||
"""Boilerplate ksft main."""
|
||||
with NetDrvEpEnv(__file__) as cfg:
|
||||
ksft_run([test_so_txtime_mono, test_so_txtime_etf], args=(cfg,))
|
||||
ksft_exit()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
1
tools/testing/selftests/net/.gitignore
vendored
1
tools/testing/selftests/net/.gitignore
vendored
@@ -40,7 +40,6 @@ skf_net_off
|
||||
socket
|
||||
so_incoming_cpu
|
||||
so_netns_cookie
|
||||
so_txtime
|
||||
so_rcv_listener
|
||||
stress_reuseport_listen
|
||||
tap
|
||||
|
||||
@@ -83,7 +83,6 @@ TEST_PROGS := \
|
||||
rxtimestamp.sh \
|
||||
sctp_vrf.sh \
|
||||
skf_net_off.sh \
|
||||
so_txtime.sh \
|
||||
srv6_end_dt46_l3vpn_test.sh \
|
||||
srv6_end_dt4_l3vpn_test.sh \
|
||||
srv6_end_dt6_l3vpn_test.sh \
|
||||
@@ -157,7 +156,6 @@ TEST_GEN_FILES := \
|
||||
skf_net_off \
|
||||
so_netns_cookie \
|
||||
so_rcv_listener \
|
||||
so_txtime \
|
||||
socket \
|
||||
stress_reuseport_listen \
|
||||
tcp_fastopen_backup_key \
|
||||
|
||||
@@ -1,110 +0,0 @@
|
||||
#!/bin/bash
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
#
|
||||
# Regression tests for the SO_TXTIME interface
|
||||
|
||||
set -e
|
||||
|
||||
readonly ksft_skip=4
|
||||
readonly DEV="veth0"
|
||||
readonly BIN="./so_txtime"
|
||||
|
||||
readonly RAND="$(mktemp -u XXXXXX)"
|
||||
readonly NSPREFIX="ns-${RAND}"
|
||||
readonly NS1="${NSPREFIX}1"
|
||||
readonly NS2="${NSPREFIX}2"
|
||||
|
||||
readonly SADDR4='192.168.1.1'
|
||||
readonly DADDR4='192.168.1.2'
|
||||
readonly SADDR6='fd::1'
|
||||
readonly DADDR6='fd::2'
|
||||
|
||||
cleanup() {
|
||||
ip netns del "${NS2}"
|
||||
ip netns del "${NS1}"
|
||||
}
|
||||
|
||||
trap cleanup EXIT
|
||||
|
||||
# Create virtual ethernet pair between network namespaces
|
||||
ip netns add "${NS1}"
|
||||
ip netns add "${NS2}"
|
||||
|
||||
ip link add "${DEV}" netns "${NS1}" type veth \
|
||||
peer name "${DEV}" netns "${NS2}"
|
||||
|
||||
# Bring the devices up
|
||||
ip -netns "${NS1}" link set "${DEV}" up
|
||||
ip -netns "${NS2}" link set "${DEV}" up
|
||||
|
||||
# Set fixed MAC addresses on the devices
|
||||
ip -netns "${NS1}" link set dev "${DEV}" address 02:02:02:02:02:02
|
||||
ip -netns "${NS2}" link set dev "${DEV}" address 06:06:06:06:06:06
|
||||
|
||||
# Add fixed IP addresses to the devices
|
||||
ip -netns "${NS1}" addr add 192.168.1.1/24 dev "${DEV}"
|
||||
ip -netns "${NS2}" addr add 192.168.1.2/24 dev "${DEV}"
|
||||
ip -netns "${NS1}" addr add fd::1/64 dev "${DEV}" nodad
|
||||
ip -netns "${NS2}" addr add fd::2/64 dev "${DEV}" nodad
|
||||
|
||||
run_test() {
|
||||
local readonly IP="$1"
|
||||
local readonly CLOCK="$2"
|
||||
local readonly TXARGS="$3"
|
||||
local readonly RXARGS="$4"
|
||||
|
||||
if [[ "${IP}" == "4" ]]; then
|
||||
local readonly SADDR="${SADDR4}"
|
||||
local readonly DADDR="${DADDR4}"
|
||||
elif [[ "${IP}" == "6" ]]; then
|
||||
local readonly SADDR="${SADDR6}"
|
||||
local readonly DADDR="${DADDR6}"
|
||||
else
|
||||
echo "Invalid IP version ${IP}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
local readonly START="$(date +%s%N --date="+ 0.1 seconds")"
|
||||
|
||||
ip netns exec "${NS2}" "${BIN}" -"${IP}" -c "${CLOCK}" -t "${START}" -S "${SADDR}" -D "${DADDR}" "${RXARGS}" -r &
|
||||
ip netns exec "${NS1}" "${BIN}" -"${IP}" -c "${CLOCK}" -t "${START}" -S "${SADDR}" -D "${DADDR}" "${TXARGS}"
|
||||
wait "$!"
|
||||
}
|
||||
|
||||
do_test() {
|
||||
run_test $@
|
||||
[ $? -ne 0 ] && ret=1
|
||||
}
|
||||
|
||||
do_fail_test() {
|
||||
run_test $@
|
||||
[ $? -eq 0 ] && ret=1
|
||||
}
|
||||
|
||||
ip netns exec "${NS1}" tc qdisc add dev "${DEV}" root fq
|
||||
set +e
|
||||
ret=0
|
||||
do_test 4 mono a,-1 a,-1
|
||||
do_test 6 mono a,0 a,0
|
||||
do_test 6 mono a,10 a,10
|
||||
do_test 4 mono a,10,b,20 a,10,b,20
|
||||
do_test 6 mono a,20,b,10 b,20,a,20
|
||||
|
||||
if ip netns exec "${NS1}" tc qdisc replace dev "${DEV}" root etf clockid CLOCK_TAI delta 400000; then
|
||||
do_fail_test 4 tai a,-1 a,-1
|
||||
do_fail_test 6 tai a,0 a,0
|
||||
do_test 6 tai a,10 a,10
|
||||
do_test 4 tai a,10,b,20 a,10,b,20
|
||||
do_test 6 tai a,20,b,10 b,10,a,20
|
||||
else
|
||||
echo "tc ($(tc -V)) does not support qdisc etf. skipping"
|
||||
[ $ret -eq 0 ] && ret=$ksft_skip
|
||||
fi
|
||||
|
||||
if [ $ret -eq 0 ]; then
|
||||
echo OK. All tests passed
|
||||
elif [[ $ret -ne $ksft_skip && -n "$KSFT_MACHINE_SLOW" ]]; then
|
||||
echo "Ignoring errors due to slow environment" 1>&2
|
||||
ret=0
|
||||
fi
|
||||
exit $ret
|
||||
Reference in New Issue
Block a user