1da87cabaSGal Pressman#!/usr/bin/env python3 2da87cabaSGal Pressman# SPDX-License-Identifier: GPL-2.0 3da87cabaSGal Pressman 4da87cabaSGal Pressmanimport multiprocessing 5da87cabaSGal Pressmanimport socket 6da87cabaSGal Pressmanfrom lib.py import ksft_run, ksft_exit, ksft_eq, ksft_ge, cmd, fd_read_timeout 7da87cabaSGal Pressmanfrom lib.py import NetDrvEpEnv 8da87cabaSGal Pressmanfrom lib.py import EthtoolFamily, NetdevFamily 9da87cabaSGal Pressmanfrom lib.py import KsftSkipEx, KsftFailEx 10da87cabaSGal Pressmanfrom lib.py import rand_port 11da87cabaSGal Pressman 12da87cabaSGal Pressman 13da87cabaSGal Pressmandef traffic(cfg, local_port, remote_port, ipver): 14da87cabaSGal Pressman af_inet = socket.AF_INET if ipver == "4" else socket.AF_INET6 15da87cabaSGal Pressman sock = socket.socket(af_inet, socket.SOCK_DGRAM) 16da87cabaSGal Pressman sock.bind(("", local_port)) 17da87cabaSGal Pressman sock.connect((cfg.remote_addr_v[ipver], remote_port)) 18da87cabaSGal Pressman tgt = f"{ipver}:[{cfg.addr_v[ipver]}]:{local_port},sourceport={remote_port}" 19da87cabaSGal Pressman cmd("echo a | socat - UDP" + tgt, host=cfg.remote) 20da87cabaSGal Pressman fd_read_timeout(sock.fileno(), 5) 21da87cabaSGal Pressman return sock.getsockopt(socket.SOL_SOCKET, socket.SO_INCOMING_CPU) 22da87cabaSGal Pressman 23da87cabaSGal Pressman 24da87cabaSGal Pressmandef test_rss_input_xfrm(cfg, ipver): 25da87cabaSGal Pressman """ 26da87cabaSGal Pressman Test symmetric input_xfrm. 27da87cabaSGal Pressman If symmetric RSS hash is configured, send traffic twice, swapping the 28da87cabaSGal Pressman src/dst UDP ports, and verify that the same queue is receiving the traffic 29da87cabaSGal Pressman in both cases (IPs are constant). 30da87cabaSGal Pressman """ 31da87cabaSGal Pressman 32da87cabaSGal Pressman if multiprocessing.cpu_count() < 2: 33da87cabaSGal Pressman raise KsftSkipEx("Need at least two CPUs to test symmetric RSS hash") 34da87cabaSGal Pressman 35c76bab22SGal Pressman cfg.require_cmd("socat", remote=True) 36c76bab22SGal Pressman 37c76bab22SGal Pressman if not hasattr(socket, "SO_INCOMING_CPU"): 38c76bab22SGal Pressman raise KsftSkipEx("socket.SO_INCOMING_CPU was added in Python 3.11") 39c76bab22SGal Pressman 40da87cabaSGal Pressman input_xfrm = cfg.ethnl.rss_get( 41*07caaf87SJakub Kicinski {'header': {'dev-name': cfg.ifname}}).get('input-xfrm') 42da87cabaSGal Pressman 43da87cabaSGal Pressman # Check for symmetric xor/or-xor 44da87cabaSGal Pressman if not input_xfrm or (input_xfrm != 1 and input_xfrm != 2): 45da87cabaSGal Pressman raise KsftSkipEx("Symmetric RSS hash not requested") 46da87cabaSGal Pressman 47da87cabaSGal Pressman cpus = set() 48da87cabaSGal Pressman successful = 0 49da87cabaSGal Pressman for _ in range(100): 50da87cabaSGal Pressman try: 51da87cabaSGal Pressman port1 = rand_port(socket.SOCK_DGRAM) 52da87cabaSGal Pressman port2 = rand_port(socket.SOCK_DGRAM) 53da87cabaSGal Pressman cpu1 = traffic(cfg, port1, port2, ipver) 54da87cabaSGal Pressman cpu2 = traffic(cfg, port2, port1, ipver) 55da87cabaSGal Pressman cpus.update([cpu1, cpu2]) 56da87cabaSGal Pressman ksft_eq( 57da87cabaSGal Pressman cpu1, cpu2, comment=f"Received traffic on different cpus with ports ({port1 = }, {port2 = }) while symmetric hash is configured") 58da87cabaSGal Pressman 59da87cabaSGal Pressman successful += 1 60da87cabaSGal Pressman if successful == 10: 61da87cabaSGal Pressman break 62da87cabaSGal Pressman except: 63da87cabaSGal Pressman continue 64da87cabaSGal Pressman else: 65da87cabaSGal Pressman raise KsftFailEx("Failed to run traffic") 66da87cabaSGal Pressman 67da87cabaSGal Pressman ksft_ge(len(cpus), 2, 68da87cabaSGal Pressman comment=f"Received traffic on less than two cpus {cpus = }") 69da87cabaSGal Pressman 70da87cabaSGal Pressman 71da87cabaSGal Pressmandef test_rss_input_xfrm_ipv4(cfg): 72da87cabaSGal Pressman cfg.require_ipver("4") 73da87cabaSGal Pressman test_rss_input_xfrm(cfg, "4") 74da87cabaSGal Pressman 75da87cabaSGal Pressman 76da87cabaSGal Pressmandef test_rss_input_xfrm_ipv6(cfg): 77da87cabaSGal Pressman cfg.require_ipver("6") 78da87cabaSGal Pressman test_rss_input_xfrm(cfg, "6") 79da87cabaSGal Pressman 80da87cabaSGal Pressman 81da87cabaSGal Pressmandef main() -> None: 82da87cabaSGal Pressman with NetDrvEpEnv(__file__, nsim_test=False) as cfg: 83da87cabaSGal Pressman cfg.ethnl = EthtoolFamily() 84da87cabaSGal Pressman cfg.netdevnl = NetdevFamily() 85da87cabaSGal Pressman 86da87cabaSGal Pressman ksft_run([test_rss_input_xfrm_ipv4, test_rss_input_xfrm_ipv6], 87da87cabaSGal Pressman args=(cfg, )) 88da87cabaSGal Pressman ksft_exit() 89da87cabaSGal Pressman 90da87cabaSGal Pressman 91da87cabaSGal Pressmanif __name__ == "__main__": 92da87cabaSGal Pressman main() 93