Add a selftest that verifies symmetric RSS hash is working as intended. The test runs iterations of traffic, swapping the src/dst UDP 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 | 85 +++++++++++++++++++ 2 files changed, 86 insertions(+) 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 ae783e18be83..fb1b655b4939 100644 --- a/tools/testing/selftests/drivers/net/hw/Makefile +++ b/tools/testing/selftests/drivers/net/hw/Makefile @@ -16,6 +16,7 @@ TEST_PROGS = \ pp_alloc_fail.py \ rss_ctx.py \ tso.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..c0e7eb87533f --- /dev/null +++ b/tools/testing/selftests/drivers/net/hw/rss_input_xfrm.py @@ -0,0 +1,85 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: GPL-2.0 + +import socket +from lib.py import ksft_run, ksft_exit, ksft_eq, ksft_ge, cmd +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 + + +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 traffic(cfg, local_port, remote_port, ipver): + af_inet = socket.AF_INET if ipver == "4" else socket.AF_INET6 + sock = socket.socket(af_inet, socket.SOCK_DGRAM) + sock.bind(('', local_port)) + sock.connect((cfg.remote_addr_v[ipver], remote_port)) + tgt = f"{ipver}:[{cfg.addr_v[ipver]}]:{local_port},sourceport={remote_port}" + cmd("echo a | socat - UDP" + tgt, host=cfg.remote) + sock.recvmsg(100) + return sock.getsockopt(socket.SOL_SOCKET, socket.SO_INCOMING_CPU) + + +def test_rss_input_xfrm(cfg, ipver): + """ + Test symmetric input_xfrm. + If symmetric RSS hash is configured, send traffic twice, swapping the + src/dst UDP 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): + cpus = set() + for _ in range(8): + port1 = _get_rand_port(cfg.remote) + port2 = _get_rand_port(cfg.remote) + cpu1 = traffic(cfg, port1, port2, ipver) + cpu2 = traffic(cfg, port2, port1, ipver) + cpus.update([cpu1, cpu2]) + + ksft_eq( + cpu1, cpu2, comment=f"Received traffic on different cpus ({cpu1} != {cpu2}) with ports ({port1 = }, {port2 = }) while symmetric hash is configured") + + ksft_ge(len(cpus), 2, comment=f"Received traffic on less than two cpus") + else: + raise KsftSkipEx("Symmetric RSS hash not requested") + + +def test_rss_input_xfrm_ipv4(cfg): + cfg.require_ipver("4") + test_rss_input_xfrm(cfg, "4") + + +def test_rss_input_xfrm_ipv6(cfg): + cfg.require_ipver("6") + test_rss_input_xfrm(cfg, "6") + + +def main() -> None: + with NetDrvEpEnv(__file__, nsim_test=False) as cfg: + cfg.ethnl = EthtoolFamily() + cfg.netdevnl = NetdevFamily() + + ksft_run([test_rss_input_xfrm_ipv4, test_rss_input_xfrm_ipv6], + args=(cfg, )) + ksft_exit() + + +if __name__ == "__main__": + main() -- 2.40.1