1#!/usr/bin/env python3 2# SPDX-License-Identifier: GPL-2.0 3 4import re 5from os import path 6from lib.py import ksft_run, ksft_exit, KsftSkipEx, ksft_variants, KsftNamedVariant 7from lib.py import NetDrvEpEnv 8from lib.py import bkg, cmd, defer, ethtool, rand_port, wait_port_listen 9from lib.py import EthtoolFamily 10 11SKIP_CODE = 42 12 13def create_rss_ctx(cfg): 14 output = ethtool(f"-X {cfg.ifname} context new start {cfg.target} equal 1").stdout 15 values = re.search(r'New RSS context is (\d+)', output).group(1) 16 return int(values) 17 18 19def set_flow_rule(cfg): 20 output = ethtool(f"-N {cfg.ifname} flow-type tcp6 dst-port {cfg.port} action {cfg.target}").stdout 21 values = re.search(r'ID (\d+)', output).group(1) 22 return int(values) 23 24 25def set_flow_rule_rss(cfg, rss_ctx_id): 26 output = ethtool(f"-N {cfg.ifname} flow-type tcp6 dst-port {cfg.port} context {rss_ctx_id}").stdout 27 values = re.search(r'ID (\d+)', output).group(1) 28 return int(values) 29 30 31def single(cfg): 32 channels = cfg.ethnl.channels_get({'header': {'dev-index': cfg.ifindex}}) 33 channels = channels['combined-count'] 34 if channels < 2: 35 raise KsftSkipEx('Test requires NETIF with at least 2 combined channels') 36 37 rings = cfg.ethnl.rings_get({'header': {'dev-index': cfg.ifindex}}) 38 rx_rings = rings['rx'] 39 hds_thresh = rings.get('hds-thresh', 0) 40 41 cfg.ethnl.rings_set({'header': {'dev-index': cfg.ifindex}, 42 'tcp-data-split': 'enabled', 43 'hds-thresh': 0, 44 'rx': 64}) 45 defer(cfg.ethnl.rings_set, {'header': {'dev-index': cfg.ifindex}, 46 'tcp-data-split': 'unknown', 47 'hds-thresh': hds_thresh, 48 'rx': rx_rings}) 49 50 cfg.target = channels - 1 51 ethtool(f"-X {cfg.ifname} equal {cfg.target}") 52 defer(ethtool, f"-X {cfg.ifname} default") 53 54 flow_rule_id = set_flow_rule(cfg) 55 defer(ethtool, f"-N {cfg.ifname} delete {flow_rule_id}") 56 57 58def rss(cfg): 59 channels = cfg.ethnl.channels_get({'header': {'dev-index': cfg.ifindex}}) 60 channels = channels['combined-count'] 61 if channels < 2: 62 raise KsftSkipEx('Test requires NETIF with at least 2 combined channels') 63 64 rings = cfg.ethnl.rings_get({'header': {'dev-index': cfg.ifindex}}) 65 rx_rings = rings['rx'] 66 hds_thresh = rings.get('hds-thresh', 0) 67 68 cfg.ethnl.rings_set({'header': {'dev-index': cfg.ifindex}, 69 'tcp-data-split': 'enabled', 70 'hds-thresh': 0, 71 'rx': 64}) 72 defer(cfg.ethnl.rings_set, {'header': {'dev-index': cfg.ifindex}, 73 'tcp-data-split': 'unknown', 74 'hds-thresh': hds_thresh, 75 'rx': rx_rings}) 76 77 cfg.target = channels - 1 78 ethtool(f"-X {cfg.ifname} equal {cfg.target}") 79 defer(ethtool, f"-X {cfg.ifname} default") 80 81 rss_ctx_id = create_rss_ctx(cfg) 82 defer(ethtool, f"-X {cfg.ifname} delete context {rss_ctx_id}") 83 84 flow_rule_id = set_flow_rule_rss(cfg, rss_ctx_id) 85 defer(ethtool, f"-N {cfg.ifname} delete {flow_rule_id}") 86 87 88@ksft_variants([ 89 KsftNamedVariant("single", single), 90 KsftNamedVariant("rss", rss), 91]) 92def test_zcrx(cfg, setup) -> None: 93 cfg.require_ipver('6') 94 95 setup(cfg) 96 rx_cmd = f"{cfg.bin_local} -s -p {cfg.port} -i {cfg.ifname} -q {cfg.target}" 97 tx_cmd = f"{cfg.bin_remote} -c -h {cfg.addr_v['6']} -p {cfg.port} -l 12840" 98 with bkg(rx_cmd, exit_wait=True): 99 wait_port_listen(cfg.port, proto="tcp") 100 cmd(tx_cmd, host=cfg.remote) 101 102 103@ksft_variants([ 104 KsftNamedVariant("single", single), 105 KsftNamedVariant("rss", rss), 106]) 107def test_zcrx_oneshot(cfg, setup) -> None: 108 cfg.require_ipver('6') 109 110 setup(cfg) 111 rx_cmd = f"{cfg.bin_local} -s -p {cfg.port} -i {cfg.ifname} -q {cfg.target} -o 4" 112 tx_cmd = f"{cfg.bin_remote} -c -h {cfg.addr_v['6']} -p {cfg.port} -l 4096 -z 16384" 113 with bkg(rx_cmd, exit_wait=True): 114 wait_port_listen(cfg.port, proto="tcp") 115 cmd(tx_cmd, host=cfg.remote) 116 117 118def test_zcrx_large_chunks(cfg) -> None: 119 """Test zcrx with large buffer chunks.""" 120 121 cfg.require_ipver('6') 122 123 combined_chans = _get_combined_channels(cfg) 124 if combined_chans < 2: 125 raise KsftSkipEx('at least 2 combined channels required') 126 (rx_ring, hds_thresh) = _get_current_settings(cfg) 127 port = rand_port() 128 129 ethtool(f"-G {cfg.ifname} tcp-data-split on") 130 defer(ethtool, f"-G {cfg.ifname} tcp-data-split auto") 131 132 ethtool(f"-G {cfg.ifname} hds-thresh 0") 133 defer(ethtool, f"-G {cfg.ifname} hds-thresh {hds_thresh}") 134 135 ethtool(f"-G {cfg.ifname} rx 64") 136 defer(ethtool, f"-G {cfg.ifname} rx {rx_ring}") 137 138 ethtool(f"-X {cfg.ifname} equal {combined_chans - 1}") 139 defer(ethtool, f"-X {cfg.ifname} default") 140 141 flow_rule_id = _set_flow_rule(cfg, port, combined_chans - 1) 142 defer(ethtool, f"-N {cfg.ifname} delete {flow_rule_id}") 143 144 rx_cmd = f"{cfg.bin_local} -s -p {port} -i {cfg.ifname} -q {combined_chans - 1} -x 2" 145 tx_cmd = f"{cfg.bin_remote} -c -h {cfg.addr_v['6']} -p {port} -l 12840" 146 147 probe = cmd(rx_cmd + " -d", fail=False) 148 if probe.ret == SKIP_CODE: 149 raise KsftSkipEx(probe.stdout) 150 151 with bkg(rx_cmd, exit_wait=True): 152 wait_port_listen(port, proto="tcp") 153 cmd(tx_cmd, host=cfg.remote) 154 155 156def main() -> None: 157 with NetDrvEpEnv(__file__) as cfg: 158 cfg.bin_local = path.abspath(path.dirname(__file__) + "/../../../drivers/net/hw/iou-zcrx") 159 cfg.bin_remote = cfg.remote.deploy(cfg.bin_local) 160 161 cfg.ethnl = EthtoolFamily() 162 cfg.port = rand_port() 163 ksft_run(globs=globals(), cases=[test_zcrx, test_zcrx_oneshot], args=(cfg, )) 164 ksft_exit() 165 166 167if __name__ == "__main__": 168 main() 169