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