xref: /linux/tools/testing/selftests/drivers/net/so_txtime.py (revision 91ec2035134982b98fab0609a9fd8480e8217dc1)
1#!/usr/bin/env python3
2# SPDX-License-Identifier: GPL-2.0
3
4"""Regression tests for the SO_TXTIME interface.
5
6Test delivery time in FQ and ETF qdiscs.
7"""
8
9import os
10import time
11
12from lib.py import ksft_exit, ksft_run, ksft_variants
13from lib.py import KsftNamedVariant, KsftSkipEx
14from lib.py import NetDrvEpEnv, bkg, cmd, defer, tc
15from lib.py import CmdExitFailure
16
17
18def test_so_txtime(cfg, clockid, ipver, args_tx, args_rx, expect_success):
19    """Main function. Run so_txtime as sender and receiver."""
20    slow_machine = os.environ.get('KSFT_MACHINE_SLOW')
21
22    if not hasattr(cfg, "bin_remote"):
23        cfg.bin_local = cfg.test_dir / "so_txtime"
24        cfg.bin_remote = cfg.remote.deploy(cfg.bin_local)
25
26    tstart = time.time_ns() + (2000_000_000 if slow_machine else 200_000_000)
27
28    cmd_addr = f"-S {cfg.addr_v[ipver]} -D {cfg.remote_addr_v[ipver]}"
29    cmd_args = f"-{ipver} -c {clockid} -t {tstart} {cmd_addr}"
30    cmd_rx = f"{cfg.bin_remote} {cmd_args} {args_rx} -r"
31    cmd_tx = f"{cfg.bin_local} -m 100 {cmd_args} {args_tx}"
32
33    expect_fail = not expect_success
34    if slow_machine:
35        expect_success = False
36
37    with bkg(cmd_rx, host=cfg.remote, fail=expect_success,
38             expect_fail=expect_fail, exit_wait=True):
39        cmd(cmd_tx)
40
41
42def _qdisc_setup(ifname, qdisc, optargs=""):
43    """Replace root qdisc. Restore the original after the test.
44
45    If the original is mq, children will be of type default_qdisc.
46    """
47    orig = tc(f"qdisc show dev {ifname} root", json=True)[0].get("kind", None)
48    defer(tc, f"qdisc replace dev {ifname} root {orig}")
49    try:
50        tc(f"qdisc del dev {ifname} root")
51    except CmdExitFailure:
52        pass
53    tc(f"qdisc replace dev {ifname} root handle 1: {qdisc} {optargs}")
54
55
56def _test_variants_fq():
57    for ipver in ["4", "6"]:
58        for testcase in [
59            ["no_delay", "a,-1", "a,-1"],
60            ["zero_delay", "a,0", "a,0"],
61            ["one_pkt", "a,10", "a,10"],
62            ["in_order", "a,10,b,20", "a,10,b,20"],
63            ["reverse_order", "a,20,b,10", "b,10,a,20"],
64        ]:
65            name = f"v{ipver}_{testcase[0]}"
66            yield KsftNamedVariant(name, ipver, testcase[1], testcase[2])
67
68
69@ksft_variants(_test_variants_fq())
70def test_so_txtime_fq_mono(cfg, ipver, args_tx, args_rx):
71    """Run all variants of monotonic (fq) tests."""
72    cfg.require_ipver(ipver)
73    _qdisc_setup(cfg.ifname, "fq")
74    test_so_txtime(cfg, "mono", ipver, args_tx, args_rx, True)
75
76
77@ksft_variants(_test_variants_fq())
78def test_so_txtime_fq_tai(cfg, ipver, args_tx, args_rx):
79    """Run all variants of fq tests, but pass CLOCK_TAI to test conversion."""
80    cfg.require_ipver(ipver)
81    _qdisc_setup(cfg.ifname, "fq")
82    test_so_txtime(cfg, "tai", ipver, args_tx, args_rx, True)
83
84
85def _test_variants_etf():
86    for ipver in ["4", "6"]:
87        for testcase in [
88            ["no_delay", "a,-1", "a,-1", False],
89            ["zero_delay", "a,0", "a,0", False],
90            ["one_pkt", "a,10", "a,10", True],
91            ["in_order", "a,10,b,20", "a,10,b,20", True],
92            ["reverse_order", "a,20,b,10", "b,10,a,20", True],
93        ]:
94            name = f"v{ipver}_{testcase[0]}"
95            yield KsftNamedVariant(
96                name, ipver, testcase[1], testcase[2], testcase[3]
97            )
98
99
100@ksft_variants(_test_variants_etf())
101def test_so_txtime_etf(cfg, ipver, args_tx, args_rx, expect_fail):
102    """Run all variants of etf tests."""
103    cfg.require_ipver(ipver)
104
105    # root qdisc for background traffic (e.g., bkg())
106    _qdisc_setup(cfg.ifname, "prio")
107
108    # leaf ETF qdisc only for intended packets
109    try:
110        etf_args = "clockid CLOCK_TAI delta 400000"
111        tc(f"qdisc add dev {cfg.ifname} parent 1:1 handle 10: etf {etf_args}")
112    except Exception as e:
113        raise KsftSkipEx("tc does not support qdisc etf. skipping") from e
114
115    # redirect mark 100 to leaf
116    filter_args = "protocol all handle 100 fw flowid 1:1"
117    tc(f"filter add dev {cfg.ifname} parent 1: {filter_args}")
118
119    test_so_txtime(cfg, "tai", ipver, args_tx, args_rx, expect_fail)
120
121
122def main() -> None:
123    """Boilerplate ksft main."""
124    with NetDrvEpEnv(__file__) as cfg:
125        ksft_run(
126            [test_so_txtime_fq_mono, test_so_txtime_fq_tai, test_so_txtime_etf],
127            args=(cfg,),
128        )
129    ksft_exit()
130
131
132if __name__ == "__main__":
133    main()
134