Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

selftests: drv-net: replace the nsim ring test with a drv-net one

We are trying to move away from netdevsim-only tests and towards
tests which can be run both against netdevsim and real drivers.

Replace the simple bash script we have for checking ethtool -g/-G
on netdevsim with a Python test tweaking those params as well
as channel count.

The new test is not exactly equivalent to the netdevsim one,
but real drivers don't often support random ring sizes,
let alone modifying max values via debugfs.

Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Link: https://patch.msgid.link/20251029164930.2923448-1-kuba@kernel.org
Signed-off-by: Jakub Kicinski <kuba@kernel.org>

+168 -86
+1
tools/testing/selftests/drivers/net/Makefile
··· 22 22 ping.py \ 23 23 psp.py \ 24 24 queues.py \ 25 + ring_reconfig.py \ 25 26 shaper.py \ 26 27 stats.py \ 27 28 xdp.py \
-1
tools/testing/selftests/drivers/net/netdevsim/Makefile
··· 8 8 ethtool-features.sh \ 9 9 ethtool-fec.sh \ 10 10 ethtool-pause.sh \ 11 - ethtool-ring.sh \ 12 11 fib.sh \ 13 12 fib_notifications.sh \ 14 13 hw_stats_l3.sh \
-85
tools/testing/selftests/drivers/net/netdevsim/ethtool-ring.sh
··· 1 - #!/bin/bash 2 - # SPDX-License-Identifier: GPL-2.0-only 3 - 4 - source ethtool-common.sh 5 - 6 - function get_value { 7 - local query="${SETTINGS_MAP[$1]}" 8 - 9 - echo $(ethtool -g $NSIM_NETDEV | \ 10 - tail -n +$CURR_SETT_LINE | \ 11 - awk -F':' -v pattern="$query:" '$0 ~ pattern {gsub(/[\t ]/, "", $2); print $2}') 12 - } 13 - 14 - function update_current_settings { 15 - for key in ${!SETTINGS_MAP[@]}; do 16 - CURRENT_SETTINGS[$key]=$(get_value $key) 17 - done 18 - echo ${CURRENT_SETTINGS[@]} 19 - } 20 - 21 - if ! ethtool -h | grep -q set-ring >/dev/null; then 22 - echo "SKIP: No --set-ring support in ethtool" 23 - exit 4 24 - fi 25 - 26 - NSIM_NETDEV=$(make_netdev) 27 - 28 - set -o pipefail 29 - 30 - declare -A SETTINGS_MAP=( 31 - ["rx"]="RX" 32 - ["rx-mini"]="RX Mini" 33 - ["rx-jumbo"]="RX Jumbo" 34 - ["tx"]="TX" 35 - ) 36 - 37 - declare -A EXPECTED_SETTINGS=( 38 - ["rx"]="" 39 - ["rx-mini"]="" 40 - ["rx-jumbo"]="" 41 - ["tx"]="" 42 - ) 43 - 44 - declare -A CURRENT_SETTINGS=( 45 - ["rx"]="" 46 - ["rx-mini"]="" 47 - ["rx-jumbo"]="" 48 - ["tx"]="" 49 - ) 50 - 51 - MAX_VALUE=$((RANDOM % $((2**32-1)))) 52 - RING_MAX_LIST=$(ls $NSIM_DEV_DFS/ethtool/ring/) 53 - 54 - for ring_max_entry in $RING_MAX_LIST; do 55 - echo $MAX_VALUE > $NSIM_DEV_DFS/ethtool/ring/$ring_max_entry 56 - done 57 - 58 - CURR_SETT_LINE=$(ethtool -g $NSIM_NETDEV | grep -i -m1 -n 'Current hardware settings' | cut -f1 -d:) 59 - 60 - # populate the expected settings map 61 - for key in ${!SETTINGS_MAP[@]}; do 62 - EXPECTED_SETTINGS[$key]=$(get_value $key) 63 - done 64 - 65 - # test 66 - for key in ${!SETTINGS_MAP[@]}; do 67 - value=$((RANDOM % $MAX_VALUE)) 68 - 69 - ethtool -G $NSIM_NETDEV "$key" "$value" 70 - 71 - EXPECTED_SETTINGS[$key]="$value" 72 - expected=${EXPECTED_SETTINGS[@]} 73 - current=$(update_current_settings) 74 - 75 - check $? "$current" "$expected" 76 - set +x 77 - done 78 - 79 - if [ $num_errors -eq 0 ]; then 80 - echo "PASSED all $((num_passes)) checks" 81 - exit 0 82 - else 83 - echo "FAILED $num_errors/$((num_errors+num_passes)) checks" 84 - exit 1 85 - fi
+167
tools/testing/selftests/drivers/net/ring_reconfig.py
··· 1 + #!/usr/bin/env python3 2 + # SPDX-License-Identifier: GPL-2.0 3 + 4 + """ 5 + Test channel and ring size configuration via ethtool (-L / -G). 6 + """ 7 + 8 + from lib.py import ksft_run, ksft_exit, ksft_pr 9 + from lib.py import ksft_eq 10 + from lib.py import NetDrvEpEnv, EthtoolFamily, GenerateTraffic 11 + from lib.py import defer, NlError 12 + 13 + 14 + def channels(cfg) -> None: 15 + """ 16 + Twiddle channel counts in various combinations of parameters. 17 + We're only looking for driver adhering to the requested config 18 + if the config is accepted and crashes. 19 + """ 20 + ehdr = {'header':{'dev-index': cfg.ifindex}} 21 + chans = cfg.eth.channels_get(ehdr) 22 + 23 + all_keys = ["rx", "tx", "combined"] 24 + mixes = [{"combined"}, {"rx", "tx"}, {"rx", "combined"}, {"tx", "combined"}, 25 + {"rx", "tx", "combined"},] 26 + 27 + # Get the set of keys that device actually supports 28 + restore = {} 29 + supported = set() 30 + for key in all_keys: 31 + if key + "-max" in chans: 32 + supported.add(key) 33 + restore |= {key + "-count": chans[key + "-count"]} 34 + 35 + defer(cfg.eth.channels_set, ehdr | restore) 36 + 37 + def test_config(config): 38 + try: 39 + cfg.eth.channels_set(ehdr | config) 40 + get = cfg.eth.channels_get(ehdr) 41 + for k, v in config.items(): 42 + ksft_eq(get.get(k, 0), v) 43 + except NlError as e: 44 + failed.append(mix) 45 + ksft_pr("Can't set", config, e) 46 + else: 47 + ksft_pr("Okay", config) 48 + 49 + failed = [] 50 + for mix in mixes: 51 + if not mix.issubset(supported): 52 + continue 53 + 54 + # Set all the values in the mix to 1, other supported to 0 55 + config = {} 56 + for key in all_keys: 57 + config[key + "-count"] = 1 if key in mix else 0 58 + test_config(config) 59 + 60 + for mix in mixes: 61 + if not mix.issubset(supported): 62 + continue 63 + if mix in failed: 64 + continue 65 + 66 + # Set all the values in the mix to max, other supported to 0 67 + config = {} 68 + for key in all_keys: 69 + config[key + "-count"] = chans[key + '-max'] if key in mix else 0 70 + test_config(config) 71 + 72 + 73 + def _configure_min_ring_cnt(cfg) -> None: 74 + """ Try to configure a single Rx/Tx ring. """ 75 + ehdr = {'header':{'dev-index': cfg.ifindex}} 76 + chans = cfg.eth.channels_get(ehdr) 77 + 78 + all_keys = ["rx-count", "tx-count", "combined-count"] 79 + restore = {} 80 + config = {} 81 + for key in all_keys: 82 + if key in chans: 83 + restore[key] = chans[key] 84 + config[key] = 0 85 + 86 + if chans.get('combined-count', 0) > 1: 87 + config['combined-count'] = 1 88 + elif chans.get('rx-count', 0) > 1 and chans.get('tx-count', 0) > 1: 89 + config['tx-count'] = 1 90 + config['rx-count'] = 1 91 + else: 92 + # looks like we're already on 1 channel 93 + return 94 + 95 + cfg.eth.channels_set(ehdr | config) 96 + defer(cfg.eth.channels_set, ehdr | restore) 97 + 98 + 99 + def ringparam(cfg) -> None: 100 + """ 101 + Tweak the ringparam configuration. Try to run some traffic over min 102 + ring size to make sure it actually functions. 103 + """ 104 + ehdr = {'header':{'dev-index': cfg.ifindex}} 105 + rings = cfg.eth.rings_get(ehdr) 106 + 107 + restore = {} 108 + maxes = {} 109 + params = set() 110 + for key in rings.keys(): 111 + if 'max' in key: 112 + param = key[:-4] 113 + maxes[param] = rings[key] 114 + params.add(param) 115 + restore[param] = rings[param] 116 + 117 + defer(cfg.eth.rings_set, ehdr | restore) 118 + 119 + # Speed up the reconfig by configuring just one ring 120 + _configure_min_ring_cnt(cfg) 121 + 122 + # Try to reach min on all settings 123 + for param in params: 124 + val = rings[param] 125 + while True: 126 + try: 127 + cfg.eth.rings_set({'header':{'dev-index': cfg.ifindex}, 128 + param: val // 2}) 129 + if val == 0: 130 + break 131 + val //= 2 132 + except NlError: 133 + break 134 + 135 + get = cfg.eth.rings_get(ehdr) 136 + ksft_eq(get[param], val) 137 + 138 + ksft_pr(f"Reached min for '{param}' at {val} (max {rings[param]})") 139 + 140 + GenerateTraffic(cfg).wait_pkts_and_stop(10000) 141 + 142 + # Try max across all params, if the driver supports large rings 143 + # this may OOM so we ignore errors 144 + try: 145 + ksft_pr("Applying max settings") 146 + config = {p: maxes[p] for p in params} 147 + cfg.eth.rings_set(ehdr | config) 148 + except NlError as e: 149 + ksft_pr("Can't set max params", config, e) 150 + else: 151 + GenerateTraffic(cfg).wait_pkts_and_stop(10000) 152 + 153 + 154 + def main() -> None: 155 + """ Ksft boiler plate main """ 156 + 157 + with NetDrvEpEnv(__file__) as cfg: 158 + cfg.eth = EthtoolFamily() 159 + 160 + ksft_run([channels, 161 + ringparam], 162 + args=(cfg, )) 163 + ksft_exit() 164 + 165 + 166 + if __name__ == "__main__": 167 + main()