1#!/usr/bin/env python3 2# SPDX-License-Identifier: GPL-2.0 3 4from lib.py import ksft_run, ksft_exit 5from lib.py import ksft_ge, ksft_eq 6from lib.py import KsftSkipEx 7from lib.py import ksft_disruptive 8from lib.py import EthtoolFamily, NetdevFamily 9from lib.py import NetDrvEnv 10from lib.py import cmd, ip, defer 11 12 13def read_affinity(irq) -> str: 14 with open(f'/proc/irq/{irq}/smp_affinity', 'r') as fp: 15 return fp.read().lstrip("0,").strip() 16 17 18def write_affinity(irq, what) -> str: 19 if what != read_affinity(irq): 20 with open(f'/proc/irq/{irq}/smp_affinity', 'w') as fp: 21 fp.write(what) 22 23 24def check_irqs_reported(cfg) -> None: 25 """ Check that device reports IRQs for NAPI instances """ 26 napis = cfg.netnl.napi_get({"ifindex": cfg.ifindex}, dump=True) 27 irqs = sum(['irq' in x for x in napis]) 28 29 ksft_ge(irqs, 1) 30 ksft_eq(irqs, len(napis)) 31 32 33def _check_reconfig(cfg, reconfig_cb) -> None: 34 napis = cfg.netnl.napi_get({"ifindex": cfg.ifindex}, dump=True) 35 for n in reversed(napis): 36 if 'irq' in n: 37 break 38 else: 39 raise KsftSkipEx(f"Device has no NAPI with IRQ attribute (#napis: {len(napis)}") 40 41 old = read_affinity(n['irq']) 42 # pick an affinity that's not the current one 43 new = "3" if old != "3" else "5" 44 write_affinity(n['irq'], new) 45 defer(write_affinity, n['irq'], old) 46 47 reconfig_cb(cfg) 48 49 ksft_eq(read_affinity(n['irq']), new, comment="IRQ affinity changed after reconfig") 50 51 52def check_reconfig_queues(cfg) -> None: 53 def reconfig(cfg) -> None: 54 channels = cfg.ethnl.channels_get({'header': {'dev-index': cfg.ifindex}}) 55 if channels['combined-count'] == 0: 56 rx_type = 'rx' 57 else: 58 rx_type = 'combined' 59 cur_queue_cnt = channels[f'{rx_type}-count'] 60 max_queue_cnt = channels[f'{rx_type}-max'] 61 62 cmd(f"ethtool -L {cfg.ifname} {rx_type} 1") 63 cmd(f"ethtool -L {cfg.ifname} {rx_type} {max_queue_cnt}") 64 cmd(f"ethtool -L {cfg.ifname} {rx_type} {cur_queue_cnt}") 65 66 _check_reconfig(cfg, reconfig) 67 68 69def check_reconfig_xdp(cfg) -> None: 70 def reconfig(cfg) -> None: 71 ip(f"link set dev %s xdp obj %s sec xdp" % 72 (cfg.ifname, cfg.net_lib_dir / "xdp_dummy.bpf.o")) 73 ip(f"link set dev %s xdp off" % cfg.ifname) 74 75 _check_reconfig(cfg, reconfig) 76 77 78@ksft_disruptive 79def check_down(cfg) -> None: 80 def reconfig(cfg) -> None: 81 ip("link set dev %s down" % cfg.ifname) 82 ip("link set dev %s up" % cfg.ifname) 83 84 _check_reconfig(cfg, reconfig) 85 86 87def main() -> None: 88 with NetDrvEnv(__file__, nsim_test=False) as cfg: 89 cfg.ethnl = EthtoolFamily() 90 cfg.netnl = NetdevFamily() 91 92 ksft_run([check_irqs_reported, check_reconfig_queues, 93 check_reconfig_xdp, check_down], 94 args=(cfg, )) 95 ksft_exit() 96 97 98if __name__ == "__main__": 99 main() 100