| #!/usr/bin/env python3 |
| # SPDX-License-Identifier: GPL-2.0 |
| |
| """ |
| Test channel and ring size configuration via ethtool (-L / -G). |
| """ |
| |
| from lib.py import ksft_run, ksft_exit, ksft_pr |
| from lib.py import ksft_eq |
| from lib.py import NetDrvEpEnv, EthtoolFamily, GenerateTraffic |
| from lib.py import defer, NlError |
| |
| |
| def channels(cfg) -> None: |
| """ |
| Twiddle channel counts in various combinations of parameters. |
| We're only looking for driver adhering to the requested config |
| if the config is accepted and crashes. |
| """ |
| ehdr = {'header':{'dev-index': cfg.ifindex}} |
| chans = cfg.eth.channels_get(ehdr) |
| |
| all_keys = ["rx", "tx", "combined"] |
| mixes = [{"combined"}, {"rx", "tx"}, {"rx", "combined"}, {"tx", "combined"}, |
| {"rx", "tx", "combined"},] |
| |
| # Get the set of keys that device actually supports |
| restore = {} |
| supported = set() |
| for key in all_keys: |
| if key + "-max" in chans: |
| supported.add(key) |
| restore |= {key + "-count": chans[key + "-count"]} |
| |
| defer(cfg.eth.channels_set, ehdr | restore) |
| |
| def test_config(config): |
| try: |
| cfg.eth.channels_set(ehdr | config) |
| get = cfg.eth.channels_get(ehdr) |
| for k, v in config.items(): |
| ksft_eq(get.get(k, 0), v) |
| except NlError as e: |
| failed.append(mix) |
| ksft_pr("Can't set", config, e) |
| else: |
| ksft_pr("Okay", config) |
| |
| failed = [] |
| for mix in mixes: |
| if not mix.issubset(supported): |
| continue |
| |
| # Set all the values in the mix to 1, other supported to 0 |
| config = {} |
| for key in all_keys: |
| config[key + "-count"] = 1 if key in mix else 0 |
| test_config(config) |
| |
| for mix in mixes: |
| if not mix.issubset(supported): |
| continue |
| if mix in failed: |
| continue |
| |
| # Set all the values in the mix to max, other supported to 0 |
| config = {} |
| for key in all_keys: |
| config[key + "-count"] = chans[key + '-max'] if key in mix else 0 |
| test_config(config) |
| |
| |
| def _configure_min_ring_cnt(cfg) -> None: |
| """ Try to configure a single Rx/Tx ring. """ |
| ehdr = {'header':{'dev-index': cfg.ifindex}} |
| chans = cfg.eth.channels_get(ehdr) |
| |
| all_keys = ["rx-count", "tx-count", "combined-count"] |
| restore = {} |
| config = {} |
| for key in all_keys: |
| if key in chans: |
| restore[key] = chans[key] |
| config[key] = 0 |
| |
| if chans.get('combined-count', 0) > 1: |
| config['combined-count'] = 1 |
| elif chans.get('rx-count', 0) > 1 and chans.get('tx-count', 0) > 1: |
| config['tx-count'] = 1 |
| config['rx-count'] = 1 |
| else: |
| # looks like we're already on 1 channel |
| return |
| |
| cfg.eth.channels_set(ehdr | config) |
| defer(cfg.eth.channels_set, ehdr | restore) |
| |
| |
| def ringparam(cfg) -> None: |
| """ |
| Tweak the ringparam configuration. Try to run some traffic over min |
| ring size to make sure it actually functions. |
| """ |
| ehdr = {'header':{'dev-index': cfg.ifindex}} |
| rings = cfg.eth.rings_get(ehdr) |
| |
| restore = {} |
| maxes = {} |
| params = set() |
| for key in rings.keys(): |
| if 'max' in key: |
| param = key[:-4] |
| maxes[param] = rings[key] |
| params.add(param) |
| restore[param] = rings[param] |
| |
| defer(cfg.eth.rings_set, ehdr | restore) |
| |
| # Speed up the reconfig by configuring just one ring |
| _configure_min_ring_cnt(cfg) |
| |
| # Try to reach min on all settings |
| for param in params: |
| val = rings[param] |
| while True: |
| try: |
| cfg.eth.rings_set({'header':{'dev-index': cfg.ifindex}, |
| param: val // 2}) |
| if val == 0: |
| break |
| val //= 2 |
| except NlError: |
| break |
| |
| get = cfg.eth.rings_get(ehdr) |
| ksft_eq(get[param], val) |
| |
| ksft_pr(f"Reached min for '{param}' at {val} (max {rings[param]})") |
| |
| GenerateTraffic(cfg).wait_pkts_and_stop(10000) |
| |
| # Try max across all params, if the driver supports large rings |
| # this may OOM so we ignore errors |
| try: |
| ksft_pr("Applying max settings") |
| config = {p: maxes[p] for p in params} |
| cfg.eth.rings_set(ehdr | config) |
| except NlError as e: |
| ksft_pr("Can't set max params", config, e) |
| else: |
| GenerateTraffic(cfg).wait_pkts_and_stop(10000) |
| |
| |
| def main() -> None: |
| """ Ksft boiler plate main """ |
| |
| with NetDrvEpEnv(__file__) as cfg: |
| cfg.eth = EthtoolFamily() |
| |
| ksft_run([channels, |
| ringparam], |
| args=(cfg, )) |
| ksft_exit() |
| |
| |
| if __name__ == "__main__": |
| main() |