mirror of
https://github.com/torvalds/linux.git
synced 2026-07-28 01:55:51 +02: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:
parent
49bf9e5e7c
commit
5c6baef388
|
|
@ -1,3 +1,4 @@
|
||||||
# SPDX-License-Identifier: GPL-2.0-only
|
# SPDX-License-Identifier: GPL-2.0-only
|
||||||
napi_id_helper
|
napi_id_helper
|
||||||
psp_responder
|
psp_responder
|
||||||
|
so_txtime
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ TEST_INCLUDES := $(wildcard lib/py/*.py) \
|
||||||
|
|
||||||
TEST_GEN_FILES := \
|
TEST_GEN_FILES := \
|
||||||
napi_id_helper \
|
napi_id_helper \
|
||||||
|
so_txtime \
|
||||||
# end of TEST_GEN_FILES
|
# end of TEST_GEN_FILES
|
||||||
|
|
||||||
TEST_PROGS := \
|
TEST_PROGS := \
|
||||||
|
|
@ -21,6 +22,7 @@ TEST_PROGS := \
|
||||||
queues.py \
|
queues.py \
|
||||||
ring_reconfig.py \
|
ring_reconfig.py \
|
||||||
shaper.py \
|
shaper.py \
|
||||||
|
so_txtime.py \
|
||||||
stats.py \
|
stats.py \
|
||||||
xdp.py \
|
xdp.py \
|
||||||
# end of TEST_PROGS
|
# end of TEST_PROGS
|
||||||
|
|
|
||||||
|
|
@ -8,5 +8,7 @@ CONFIG_NETCONSOLE=m
|
||||||
CONFIG_NETCONSOLE_DYNAMIC=y
|
CONFIG_NETCONSOLE_DYNAMIC=y
|
||||||
CONFIG_NETCONSOLE_EXTENDED_LOG=y
|
CONFIG_NETCONSOLE_EXTENDED_LOG=y
|
||||||
CONFIG_NETDEVSIM=m
|
CONFIG_NETDEVSIM=m
|
||||||
|
CONFIG_NET_SCH_ETF=m
|
||||||
|
CONFIG_NET_SCH_FQ=m
|
||||||
CONFIG_VLAN_8021Q=m
|
CONFIG_VLAN_8021Q=m
|
||||||
CONFIG_XDP_SOCKETS=y
|
CONFIG_XDP_SOCKETS=y
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,8 @@
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <poll.h>
|
#include <poll.h>
|
||||||
|
|
||||||
|
#include "kselftest.h"
|
||||||
|
|
||||||
static int cfg_clockid = CLOCK_TAI;
|
static int cfg_clockid = CLOCK_TAI;
|
||||||
static uint16_t cfg_port = 8000;
|
static uint16_t cfg_port = 8000;
|
||||||
static int cfg_variance_us = 4000;
|
static int cfg_variance_us = 4000;
|
||||||
|
|
@ -43,6 +45,8 @@ static bool cfg_rx;
|
||||||
static uint64_t glob_tstart;
|
static uint64_t glob_tstart;
|
||||||
static uint64_t tdeliver_max;
|
static uint64_t tdeliver_max;
|
||||||
|
|
||||||
|
static int errors;
|
||||||
|
|
||||||
/* encode one timed transmission (of a 1B payload) */
|
/* encode one timed transmission (of a 1B payload) */
|
||||||
struct timed_send {
|
struct timed_send {
|
||||||
char data;
|
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",
|
fprintf(stderr, "payload:%c delay:%lld expected:%lld (us)\n",
|
||||||
rbuf[0], (long long)tstop, (long long)texpect);
|
rbuf[0], (long long)tstop, (long long)texpect);
|
||||||
|
|
||||||
if (rbuf[0] != ts->data)
|
if (rbuf[0] != ts->data) {
|
||||||
error(1, 0, "payload mismatch. expected %c", ts->data);
|
fprintf(stderr, "payload mismatch. expected %c\n", ts->data);
|
||||||
|
errors++;
|
||||||
|
}
|
||||||
|
|
||||||
if (llabs(tstop - texpect) > cfg_variance_us) {
|
if (llabs(tstop - texpect) > cfg_variance_us) {
|
||||||
fprintf(stderr, "exceeds variance (%d us)\n", cfg_variance_us);
|
fprintf(stderr, "exceeds variance (%d us)\n", cfg_variance_us);
|
||||||
if (!getenv("KSFT_MACHINE_SLOW"))
|
if (!getenv("KSFT_MACHINE_SLOW"))
|
||||||
exit(1);
|
errors++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -255,8 +261,12 @@ static void start_time_wait(void)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
now = gettime_ns(CLOCK_REALTIME);
|
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;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
err = usleep((cfg_start_time_ns - now) / 1000);
|
err = usleep((cfg_start_time_ns - now) / 1000);
|
||||||
if (err)
|
if (err)
|
||||||
|
|
@ -513,5 +523,10 @@ int main(int argc, char **argv)
|
||||||
else
|
else
|
||||||
do_test_tx((void *)&cfg_src_addr, cfg_alen);
|
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
|
socket
|
||||||
so_incoming_cpu
|
so_incoming_cpu
|
||||||
so_netns_cookie
|
so_netns_cookie
|
||||||
so_txtime
|
|
||||||
so_rcv_listener
|
so_rcv_listener
|
||||||
stress_reuseport_listen
|
stress_reuseport_listen
|
||||||
tap
|
tap
|
||||||
|
|
|
||||||
|
|
@ -83,7 +83,6 @@ TEST_PROGS := \
|
||||||
rxtimestamp.sh \
|
rxtimestamp.sh \
|
||||||
sctp_vrf.sh \
|
sctp_vrf.sh \
|
||||||
skf_net_off.sh \
|
skf_net_off.sh \
|
||||||
so_txtime.sh \
|
|
||||||
srv6_end_dt46_l3vpn_test.sh \
|
srv6_end_dt46_l3vpn_test.sh \
|
||||||
srv6_end_dt4_l3vpn_test.sh \
|
srv6_end_dt4_l3vpn_test.sh \
|
||||||
srv6_end_dt6_l3vpn_test.sh \
|
srv6_end_dt6_l3vpn_test.sh \
|
||||||
|
|
@ -157,7 +156,6 @@ TEST_GEN_FILES := \
|
||||||
skf_net_off \
|
skf_net_off \
|
||||||
so_netns_cookie \
|
so_netns_cookie \
|
||||||
so_rcv_listener \
|
so_rcv_listener \
|
||||||
so_txtime \
|
|
||||||
socket \
|
socket \
|
||||||
stress_reuseport_listen \
|
stress_reuseport_listen \
|
||||||
tcp_fastopen_backup_key \
|
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
|
|
||||||
Loading…
Reference in New Issue
Block a user