| 1 | |
| 2 | |
| 3 |
|
| 4 | from lib.py import ksft_disruptive, ksft_exit, ksft_run
|
| 5 | from lib.py import ksft_eq, ksft_not_in, ksft_raises, KsftSkipEx, KsftFailEx
|
| 6 | from lib.py import EthtoolFamily, NetdevFamily, NlError
|
| 7 | from lib.py import NetDrvEnv
|
| 8 | from lib.py import bkg, cmd, defer, ip
|
| 9 | import errno
|
| 10 | import glob
|
| 11 | import os
|
| 12 | import socket
|
| 13 | import struct
|
| 14 |
|
| 15 | def sys_get_queues(ifname, qtype='rx') -> int:
|
| 16 | folders = glob.glob(f'/sys/class/net/{ifname}/queues/{qtype}-*')
|
| 17 | return len(folders)
|
| 18 |
|
| 19 |
|
| 20 | def nl_get_queues(cfg, nl, qtype='rx'):
|
| 21 | queues = nl.queue_get({'ifindex': cfg.ifindex}, dump=True)
|
| 22 | if queues:
|
| 23 | return len([q for q in queues if q['type'] == qtype])
|
| 24 | return None
|
| 25 |
|
| 26 |
|
| 27 | def check_xsk(cfg, nl, xdp_queue_id=0) -> None:
|
| 28 | |
| 29 | xdp = cmd(f'{cfg.net_lib_dir / "xdp_helper"} - -', fail=False)
|
| 30 | if xdp.ret == 255:
|
| 31 | raise KsftSkipEx('AF_XDP unsupported')
|
| 32 | elif xdp.ret > 0:
|
| 33 | raise KsftFailEx('unable to create AF_XDP socket')
|
| 34 |
|
| 35 | with bkg(f'{cfg.net_lib_dir / "xdp_helper"} {cfg.ifindex} {xdp_queue_id}',
|
| 36 | ksft_wait=3):
|
| 37 |
|
| 38 | rx = tx = False
|
| 39 |
|
| 40 | queues = nl.queue_get({'ifindex': cfg.ifindex}, dump=True)
|
| 41 | if not queues:
|
| 42 | raise KsftSkipEx("Netlink reports no queues")
|
| 43 |
|
| 44 | for q in queues:
|
| 45 | if q['id'] == 0:
|
| 46 | if q['type'] == 'rx':
|
| 47 | rx = True
|
| 48 | if q['type'] == 'tx':
|
| 49 | tx = True
|
| 50 |
|
| 51 | ksft_eq(q.get('xsk', None), {},
|
| 52 | comment="xsk attr on queue we configured")
|
| 53 | else:
|
| 54 | ksft_not_in('xsk', q,
|
| 55 | comment="xsk attr on queue we didn't configure")
|
| 56 |
|
| 57 | ksft_eq(rx, True)
|
| 58 | ksft_eq(tx, True)
|
| 59 |
|
| 60 |
|
| 61 | def get_queues(cfg, nl) -> None:
|
| 62 | snl = NetdevFamily(recv_size=4096)
|
| 63 |
|
| 64 | for qtype in ['rx', 'tx']:
|
| 65 | queues = nl_get_queues(cfg, snl, qtype)
|
| 66 | if not queues:
|
| 67 | raise KsftSkipEx('queue-get not supported by device')
|
| 68 |
|
| 69 | expected = sys_get_queues(cfg.dev['ifname'], qtype)
|
| 70 | ksft_eq(queues, expected)
|
| 71 |
|
| 72 |
|
| 73 | def addremove_queues(cfg, nl) -> None:
|
| 74 | queues = nl_get_queues(cfg, nl)
|
| 75 | if not queues:
|
| 76 | raise KsftSkipEx('queue-get not supported by device')
|
| 77 |
|
| 78 | curr_queues = sys_get_queues(cfg.dev['ifname'])
|
| 79 | if curr_queues == 1:
|
| 80 | raise KsftSkipEx('cannot decrement queue: already at 1')
|
| 81 |
|
| 82 | netnl = EthtoolFamily()
|
| 83 | channels = netnl.channels_get({'header': {'dev-index': cfg.ifindex}})
|
| 84 | rx_type = 'rx'
|
| 85 | if channels.get('combined-count', 0) > 0:
|
| 86 | rx_type = 'combined'
|
| 87 |
|
| 88 | expected = curr_queues - 1
|
| 89 | cmd(f"ethtool -L {cfg.dev['ifname']} {rx_type} {expected}", timeout=10)
|
| 90 | queues = nl_get_queues(cfg, nl)
|
| 91 | ksft_eq(queues, expected)
|
| 92 |
|
| 93 | expected = curr_queues
|
| 94 | cmd(f"ethtool -L {cfg.dev['ifname']} {rx_type} {expected}", timeout=10)
|
| 95 | queues = nl_get_queues(cfg, nl)
|
| 96 | ksft_eq(queues, expected)
|
| 97 |
|
| 98 |
|
| 99 | @ksft_disruptive
|
| 100 | def check_down(cfg, nl) -> None:
|
| 101 | |
| 102 | napis = nl.napi_get({'ifindex': cfg.ifindex}, dump=True)
|
| 103 |
|
| 104 | ip(f"link set dev {cfg.dev['ifname']} down")
|
| 105 | defer(ip, f"link set dev {cfg.dev['ifname']} up")
|
| 106 |
|
| 107 | with ksft_raises(NlError) as cm:
|
| 108 | nl.queue_get({'ifindex': cfg.ifindex, 'id': 0, 'type': 'rx'})
|
| 109 | ksft_eq(cm.exception.nl_msg.error, -errno.ENOENT)
|
| 110 |
|
| 111 | if napis:
|
| 112 | with ksft_raises(NlError) as cm:
|
| 113 | nl.napi_get({'id': napis[0]['id']})
|
| 114 | ksft_eq(cm.exception.nl_msg.error, -errno.ENOENT)
|
| 115 |
|
| 116 |
|
| 117 | def main() -> None:
|
| 118 | with NetDrvEnv(__file__, queue_count=100) as cfg:
|
| 119 | ksft_run([get_queues, addremove_queues, check_down, check_xsk],
|
| 120 | args=(cfg, NetdevFamily()))
|
| 121 | ksft_exit()
|
| 122 |
|
| 123 |
|
| 124 | if __name__ == "__main__":
|
| 125 | main()
|