1*ecca75aeSJakub Kicinski#!/usr/bin/env python3 2*ecca75aeSJakub Kicinski# SPDX-License-Identifier: GPL-2.0 3*ecca75aeSJakub Kicinski 4*ecca75aeSJakub Kicinski""" 5*ecca75aeSJakub KicinskiTest channel and ring size configuration via ethtool (-L / -G). 6*ecca75aeSJakub Kicinski""" 7*ecca75aeSJakub Kicinski 8*ecca75aeSJakub Kicinskifrom lib.py import ksft_run, ksft_exit, ksft_pr 9*ecca75aeSJakub Kicinskifrom lib.py import ksft_eq 10*ecca75aeSJakub Kicinskifrom lib.py import NetDrvEpEnv, EthtoolFamily, GenerateTraffic 11*ecca75aeSJakub Kicinskifrom lib.py import defer, NlError 12*ecca75aeSJakub Kicinski 13*ecca75aeSJakub Kicinski 14*ecca75aeSJakub Kicinskidef channels(cfg) -> None: 15*ecca75aeSJakub Kicinski """ 16*ecca75aeSJakub Kicinski Twiddle channel counts in various combinations of parameters. 17*ecca75aeSJakub Kicinski We're only looking for driver adhering to the requested config 18*ecca75aeSJakub Kicinski if the config is accepted and crashes. 19*ecca75aeSJakub Kicinski """ 20*ecca75aeSJakub Kicinski ehdr = {'header':{'dev-index': cfg.ifindex}} 21*ecca75aeSJakub Kicinski chans = cfg.eth.channels_get(ehdr) 22*ecca75aeSJakub Kicinski 23*ecca75aeSJakub Kicinski all_keys = ["rx", "tx", "combined"] 24*ecca75aeSJakub Kicinski mixes = [{"combined"}, {"rx", "tx"}, {"rx", "combined"}, {"tx", "combined"}, 25*ecca75aeSJakub Kicinski {"rx", "tx", "combined"},] 26*ecca75aeSJakub Kicinski 27*ecca75aeSJakub Kicinski # Get the set of keys that device actually supports 28*ecca75aeSJakub Kicinski restore = {} 29*ecca75aeSJakub Kicinski supported = set() 30*ecca75aeSJakub Kicinski for key in all_keys: 31*ecca75aeSJakub Kicinski if key + "-max" in chans: 32*ecca75aeSJakub Kicinski supported.add(key) 33*ecca75aeSJakub Kicinski restore |= {key + "-count": chans[key + "-count"]} 34*ecca75aeSJakub Kicinski 35*ecca75aeSJakub Kicinski defer(cfg.eth.channels_set, ehdr | restore) 36*ecca75aeSJakub Kicinski 37*ecca75aeSJakub Kicinski def test_config(config): 38*ecca75aeSJakub Kicinski try: 39*ecca75aeSJakub Kicinski cfg.eth.channels_set(ehdr | config) 40*ecca75aeSJakub Kicinski get = cfg.eth.channels_get(ehdr) 41*ecca75aeSJakub Kicinski for k, v in config.items(): 42*ecca75aeSJakub Kicinski ksft_eq(get.get(k, 0), v) 43*ecca75aeSJakub Kicinski except NlError as e: 44*ecca75aeSJakub Kicinski failed.append(mix) 45*ecca75aeSJakub Kicinski ksft_pr("Can't set", config, e) 46*ecca75aeSJakub Kicinski else: 47*ecca75aeSJakub Kicinski ksft_pr("Okay", config) 48*ecca75aeSJakub Kicinski 49*ecca75aeSJakub Kicinski failed = [] 50*ecca75aeSJakub Kicinski for mix in mixes: 51*ecca75aeSJakub Kicinski if not mix.issubset(supported): 52*ecca75aeSJakub Kicinski continue 53*ecca75aeSJakub Kicinski 54*ecca75aeSJakub Kicinski # Set all the values in the mix to 1, other supported to 0 55*ecca75aeSJakub Kicinski config = {} 56*ecca75aeSJakub Kicinski for key in all_keys: 57*ecca75aeSJakub Kicinski config[key + "-count"] = 1 if key in mix else 0 58*ecca75aeSJakub Kicinski test_config(config) 59*ecca75aeSJakub Kicinski 60*ecca75aeSJakub Kicinski for mix in mixes: 61*ecca75aeSJakub Kicinski if not mix.issubset(supported): 62*ecca75aeSJakub Kicinski continue 63*ecca75aeSJakub Kicinski if mix in failed: 64*ecca75aeSJakub Kicinski continue 65*ecca75aeSJakub Kicinski 66*ecca75aeSJakub Kicinski # Set all the values in the mix to max, other supported to 0 67*ecca75aeSJakub Kicinski config = {} 68*ecca75aeSJakub Kicinski for key in all_keys: 69*ecca75aeSJakub Kicinski config[key + "-count"] = chans[key + '-max'] if key in mix else 0 70*ecca75aeSJakub Kicinski test_config(config) 71*ecca75aeSJakub Kicinski 72*ecca75aeSJakub Kicinski 73*ecca75aeSJakub Kicinskidef _configure_min_ring_cnt(cfg) -> None: 74*ecca75aeSJakub Kicinski """ Try to configure a single Rx/Tx ring. """ 75*ecca75aeSJakub Kicinski ehdr = {'header':{'dev-index': cfg.ifindex}} 76*ecca75aeSJakub Kicinski chans = cfg.eth.channels_get(ehdr) 77*ecca75aeSJakub Kicinski 78*ecca75aeSJakub Kicinski all_keys = ["rx-count", "tx-count", "combined-count"] 79*ecca75aeSJakub Kicinski restore = {} 80*ecca75aeSJakub Kicinski config = {} 81*ecca75aeSJakub Kicinski for key in all_keys: 82*ecca75aeSJakub Kicinski if key in chans: 83*ecca75aeSJakub Kicinski restore[key] = chans[key] 84*ecca75aeSJakub Kicinski config[key] = 0 85*ecca75aeSJakub Kicinski 86*ecca75aeSJakub Kicinski if chans.get('combined-count', 0) > 1: 87*ecca75aeSJakub Kicinski config['combined-count'] = 1 88*ecca75aeSJakub Kicinski elif chans.get('rx-count', 0) > 1 and chans.get('tx-count', 0) > 1: 89*ecca75aeSJakub Kicinski config['tx-count'] = 1 90*ecca75aeSJakub Kicinski config['rx-count'] = 1 91*ecca75aeSJakub Kicinski else: 92*ecca75aeSJakub Kicinski # looks like we're already on 1 channel 93*ecca75aeSJakub Kicinski return 94*ecca75aeSJakub Kicinski 95*ecca75aeSJakub Kicinski cfg.eth.channels_set(ehdr | config) 96*ecca75aeSJakub Kicinski defer(cfg.eth.channels_set, ehdr | restore) 97*ecca75aeSJakub Kicinski 98*ecca75aeSJakub Kicinski 99*ecca75aeSJakub Kicinskidef ringparam(cfg) -> None: 100*ecca75aeSJakub Kicinski """ 101*ecca75aeSJakub Kicinski Tweak the ringparam configuration. Try to run some traffic over min 102*ecca75aeSJakub Kicinski ring size to make sure it actually functions. 103*ecca75aeSJakub Kicinski """ 104*ecca75aeSJakub Kicinski ehdr = {'header':{'dev-index': cfg.ifindex}} 105*ecca75aeSJakub Kicinski rings = cfg.eth.rings_get(ehdr) 106*ecca75aeSJakub Kicinski 107*ecca75aeSJakub Kicinski restore = {} 108*ecca75aeSJakub Kicinski maxes = {} 109*ecca75aeSJakub Kicinski params = set() 110*ecca75aeSJakub Kicinski for key in rings.keys(): 111*ecca75aeSJakub Kicinski if 'max' in key: 112*ecca75aeSJakub Kicinski param = key[:-4] 113*ecca75aeSJakub Kicinski maxes[param] = rings[key] 114*ecca75aeSJakub Kicinski params.add(param) 115*ecca75aeSJakub Kicinski restore[param] = rings[param] 116*ecca75aeSJakub Kicinski 117*ecca75aeSJakub Kicinski defer(cfg.eth.rings_set, ehdr | restore) 118*ecca75aeSJakub Kicinski 119*ecca75aeSJakub Kicinski # Speed up the reconfig by configuring just one ring 120*ecca75aeSJakub Kicinski _configure_min_ring_cnt(cfg) 121*ecca75aeSJakub Kicinski 122*ecca75aeSJakub Kicinski # Try to reach min on all settings 123*ecca75aeSJakub Kicinski for param in params: 124*ecca75aeSJakub Kicinski val = rings[param] 125*ecca75aeSJakub Kicinski while True: 126*ecca75aeSJakub Kicinski try: 127*ecca75aeSJakub Kicinski cfg.eth.rings_set({'header':{'dev-index': cfg.ifindex}, 128*ecca75aeSJakub Kicinski param: val // 2}) 129*ecca75aeSJakub Kicinski if val == 0: 130*ecca75aeSJakub Kicinski break 131*ecca75aeSJakub Kicinski val //= 2 132*ecca75aeSJakub Kicinski except NlError: 133*ecca75aeSJakub Kicinski break 134*ecca75aeSJakub Kicinski 135*ecca75aeSJakub Kicinski get = cfg.eth.rings_get(ehdr) 136*ecca75aeSJakub Kicinski ksft_eq(get[param], val) 137*ecca75aeSJakub Kicinski 138*ecca75aeSJakub Kicinski ksft_pr(f"Reached min for '{param}' at {val} (max {rings[param]})") 139*ecca75aeSJakub Kicinski 140*ecca75aeSJakub Kicinski GenerateTraffic(cfg).wait_pkts_and_stop(10000) 141*ecca75aeSJakub Kicinski 142*ecca75aeSJakub Kicinski # Try max across all params, if the driver supports large rings 143*ecca75aeSJakub Kicinski # this may OOM so we ignore errors 144*ecca75aeSJakub Kicinski try: 145*ecca75aeSJakub Kicinski ksft_pr("Applying max settings") 146*ecca75aeSJakub Kicinski config = {p: maxes[p] for p in params} 147*ecca75aeSJakub Kicinski cfg.eth.rings_set(ehdr | config) 148*ecca75aeSJakub Kicinski except NlError as e: 149*ecca75aeSJakub Kicinski ksft_pr("Can't set max params", config, e) 150*ecca75aeSJakub Kicinski else: 151*ecca75aeSJakub Kicinski GenerateTraffic(cfg).wait_pkts_and_stop(10000) 152*ecca75aeSJakub Kicinski 153*ecca75aeSJakub Kicinski 154*ecca75aeSJakub Kicinskidef main() -> None: 155*ecca75aeSJakub Kicinski """ Ksft boiler plate main """ 156*ecca75aeSJakub Kicinski 157*ecca75aeSJakub Kicinski with NetDrvEpEnv(__file__) as cfg: 158*ecca75aeSJakub Kicinski cfg.eth = EthtoolFamily() 159*ecca75aeSJakub Kicinski 160*ecca75aeSJakub Kicinski ksft_run([channels, 161*ecca75aeSJakub Kicinski ringparam], 162*ecca75aeSJakub Kicinski args=(cfg, )) 163*ecca75aeSJakub Kicinski ksft_exit() 164*ecca75aeSJakub Kicinski 165*ecca75aeSJakub Kicinski 166*ecca75aeSJakub Kicinskiif __name__ == "__main__": 167*ecca75aeSJakub Kicinski main() 168