Add a selftest that verifies symmetric RSS hash is working as intended. The test runs two iterations of iperf3 traffic, swapping the src/dst TCP ports, and verifies that the same RX queue is receiving the traffic in both cases. Reviewed-by: Nimrod Oren <noren@xxxxxxxxxx> Signed-off-by: Gal Pressman <gal@xxxxxxxxxx> --- .../testing/selftests/drivers/net/hw/Makefile | 1 + .../drivers/net/hw/rss_input_xfrm.py | 77 +++++++++++++++++++ .../selftests/drivers/net/lib/py/load.py | 7 +- 3 files changed, 83 insertions(+), 2 deletions(-) create mode 100755 tools/testing/selftests/drivers/net/hw/rss_input_xfrm.py diff --git a/tools/testing/selftests/drivers/net/hw/Makefile b/tools/testing/selftests/drivers/net/hw/Makefile index 21ba64ce1e34..23dca086f84f 100644 --- a/tools/testing/selftests/drivers/net/hw/Makefile +++ b/tools/testing/selftests/drivers/net/hw/Makefile @@ -15,6 +15,7 @@ TEST_PROGS = \ nic_performance.py \ pp_alloc_fail.py \ rss_ctx.py \ + rss_input_xfrm.py \ # TEST_FILES := \ diff --git a/tools/testing/selftests/drivers/net/hw/rss_input_xfrm.py b/tools/testing/selftests/drivers/net/hw/rss_input_xfrm.py new file mode 100755 index 000000000000..e32df852f091 --- /dev/null +++ b/tools/testing/selftests/drivers/net/hw/rss_input_xfrm.py @@ -0,0 +1,77 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: GPL-2.0 + +from lib.py import ksft_run, ksft_exit, ksft_eq, ksft_pr +from lib.py import NetDrvEpEnv +from lib.py import EthtoolFamily, NetdevFamily +from lib.py import KsftSkipEx +from lib.py import rand_port, check_port_available_remote +from lib.py import GenerateTraffic +from rss_ctx import _get_rx_cnts + + +def _get_active_rx_queue(cnts): + return cnts.index(max(cnts)) + + +def _get_rand_port(remote): + for _ in range(1000): + port = rand_port() + try: + check_port_available_remote(port, remote) + return port + except: + continue + + raise Exception("Can't find any free unprivileged port") + + +def test_rss_input_xfrm(cfg): + """ + Test symmetric input_xfrm. + If symmetric RSS hash is configured, send traffic twice, swapping the + src/dst TCP ports, and verify that the same queue is receiving the traffic + in both cases (IPs are constant). + """ + + input_xfrm = cfg.ethnl.rss_get( + {'header': {'dev-name': cfg.ifname}}).get('input_xfrm') + + # Check for symmetric xor/or-xor + if input_xfrm and (input_xfrm == 1 or input_xfrm == 2): + port1 = _get_rand_port(cfg.remote) + port2 = _get_rand_port(cfg.remote) + ksft_pr(f'Running traffic on ports: {port1 = }, {port2 = }') + + cnts = _get_rx_cnts(cfg) + GenerateTraffic(cfg, port=port1, parallel=1, + cport=port2).wait_pkts_and_stop(20000) + cnts = _get_rx_cnts(cfg, prev=cnts) + rxq1 = _get_active_rx_queue(cnts) + ksft_pr(f'Received traffic on {rxq1 = }') + + cnts = _get_rx_cnts(cfg) + GenerateTraffic(cfg, port=port2, parallel=1, + cport=port1).wait_pkts_and_stop(20000) + cnts = _get_rx_cnts(cfg, prev=cnts) + rxq2 = _get_active_rx_queue(cnts) + ksft_pr(f'Received traffic on {rxq2 = }') + + ksft_eq( + rxq1, rxq2, comment=f"Received traffic on different queues ({rxq1} != {rxq2}) while symmetric hash is configured") + else: + raise KsftSkipEx("Symmetric RSS hash not requested") + + +def main() -> None: + with NetDrvEpEnv(__file__, nsim_test=False) as cfg: + cfg.ethnl = EthtoolFamily() + cfg.netdevnl = NetdevFamily() + + ksft_run([test_rss_input_xfrm], + args=(cfg, )) + ksft_exit() + + +if __name__ == "__main__": + main() diff --git a/tools/testing/selftests/drivers/net/lib/py/load.py b/tools/testing/selftests/drivers/net/lib/py/load.py index da5af2c680fa..76aaa65c0367 100644 --- a/tools/testing/selftests/drivers/net/lib/py/load.py +++ b/tools/testing/selftests/drivers/net/lib/py/load.py @@ -5,7 +5,7 @@ import time from lib.py import ksft_pr, cmd, ip, rand_port, wait_port_listen, bkg class GenerateTraffic: - def __init__(self, env, port=None): + def __init__(self, env, port=None, cport=None, parallel=16): env.require_cmd("iperf3", remote=True) self.env = env @@ -15,7 +15,10 @@ class GenerateTraffic: self._iperf_server = cmd(f"iperf3 -s -1 -p {port}", background=True) wait_port_listen(port) time.sleep(0.1) - self._iperf_client = cmd(f"iperf3 -c {env.addr} -P 16 -p {port} -t 86400", + client_cmd = f"iperf3 -c {env.addr} -P {parallel} -p {port} -t 86400" + if cport and parallel == 1: + client_cmd = f"{client_cmd} --cport {cport}" + self._iperf_client = cmd(client_cmd, background=True, host=env.remote) # Wait for traffic to ramp up -- 2.40.1