Path: blob/master/tools/testing/selftests/drivers/net/hds.py
49564 views
#!/usr/bin/env python31# SPDX-License-Identifier: GPL-2.023import errno4import os5import random6from typing import Union7from lib.py import ksft_run, ksft_exit, ksft_eq, ksft_raises, KsftSkipEx8from lib.py import CmdExitFailure, EthtoolFamily, NlError9from lib.py import NetDrvEnv10from lib.py import defer, ethtool, ip111213def _get_hds_mode(cfg, netnl) -> str:14try:15rings = netnl.rings_get({'header': {'dev-index': cfg.ifindex}})16except NlError as e:17raise KsftSkipEx('ring-get not supported by device')18if 'tcp-data-split' not in rings:19raise KsftSkipEx('tcp-data-split not supported by device')20return rings['tcp-data-split']212223def _xdp_onoff(cfg):24prog = cfg.net_lib_dir / "xdp_dummy.bpf.o"25ip("link set dev %s xdp obj %s sec xdp" %26(cfg.ifname, prog))27ip("link set dev %s xdp off" % cfg.ifname)282930def _ioctl_ringparam_modify(cfg, netnl) -> None:31"""32Helper for performing a hopefully unimportant IOCTL SET.33IOCTL does not support HDS, so it should not affect the HDS config.34"""35try:36rings = netnl.rings_get({'header': {'dev-index': cfg.ifindex}})37except NlError as e:38raise KsftSkipEx('ring-get not supported by device')3940if 'tx' not in rings:41raise KsftSkipEx('setting Tx ring size not supported')4243try:44ethtool(f"--disable-netlink -G {cfg.ifname} tx {rings['tx'] // 2}")45except CmdExitFailure as e:46ethtool(f"--disable-netlink -G {cfg.ifname} tx {rings['tx'] * 2}")47defer(ethtool, f"-G {cfg.ifname} tx {rings['tx']}")484950def get_hds(cfg, netnl) -> None:51_get_hds_mode(cfg, netnl)525354def get_hds_thresh(cfg, netnl) -> None:55try:56rings = netnl.rings_get({'header': {'dev-index': cfg.ifindex}})57except NlError as e:58raise KsftSkipEx('ring-get not supported by device')59if 'hds-thresh' not in rings:60raise KsftSkipEx('hds-thresh not supported by device')616263def _hds_reset(cfg, netnl, rings) -> None:64cur = netnl.rings_get({'header': {'dev-index': cfg.ifindex}})6566arg = {'header': {'dev-index': cfg.ifindex}}67if cur.get('tcp-data-split') != rings.get('tcp-data-split'):68# Try to reset to "unknown" first, we don't know if the setting69# was the default or user chose it. Default seems more likely.70arg['tcp-data-split'] = "unknown"71netnl.rings_set(arg)72cur = netnl.rings_get({'header': {'dev-index': cfg.ifindex}})73if cur['tcp-data-split'] == rings['tcp-data-split']:74del arg['tcp-data-split']75else:76# Try the explicit setting77arg['tcp-data-split'] = rings['tcp-data-split']78if cur.get('hds-thresh') != rings.get('hds-thresh'):79arg['hds-thresh'] = rings['hds-thresh']80if len(arg) > 1:81netnl.rings_set(arg)828384def _defer_reset_hds(cfg, netnl) -> Union[dict, None]:85try:86rings = netnl.rings_get({'header': {'dev-index': cfg.ifindex}})87if 'hds-thresh' in rings or 'tcp-data-split' in rings:88defer(_hds_reset, cfg, netnl, rings)89except NlError as e:90pass919293def set_hds_enable(cfg, netnl) -> None:94_defer_reset_hds(cfg, netnl)95try:96netnl.rings_set({'header': {'dev-index': cfg.ifindex}, 'tcp-data-split': 'enabled'})97except NlError as e:98if e.error == errno.EINVAL:99raise KsftSkipEx("disabling of HDS not supported by the device")100elif e.error == errno.EOPNOTSUPP:101raise KsftSkipEx("ring-set not supported by the device")102try:103rings = netnl.rings_get({'header': {'dev-index': cfg.ifindex}})104except NlError as e:105raise KsftSkipEx('ring-get not supported by device')106if 'tcp-data-split' not in rings:107raise KsftSkipEx('tcp-data-split not supported by device')108109ksft_eq('enabled', rings['tcp-data-split'])110111def set_hds_disable(cfg, netnl) -> None:112_defer_reset_hds(cfg, netnl)113try:114netnl.rings_set({'header': {'dev-index': cfg.ifindex}, 'tcp-data-split': 'disabled'})115except NlError as e:116if e.error == errno.EINVAL:117raise KsftSkipEx("disabling of HDS not supported by the device")118elif e.error == errno.EOPNOTSUPP:119raise KsftSkipEx("ring-set not supported by the device")120try:121rings = netnl.rings_get({'header': {'dev-index': cfg.ifindex}})122except NlError as e:123raise KsftSkipEx('ring-get not supported by device')124if 'tcp-data-split' not in rings:125raise KsftSkipEx('tcp-data-split not supported by device')126127ksft_eq('disabled', rings['tcp-data-split'])128129def set_hds_thresh_zero(cfg, netnl) -> None:130_defer_reset_hds(cfg, netnl)131try:132netnl.rings_set({'header': {'dev-index': cfg.ifindex}, 'hds-thresh': 0})133except NlError as e:134if e.error == errno.EINVAL:135raise KsftSkipEx("hds-thresh-set not supported by the device")136elif e.error == errno.EOPNOTSUPP:137raise KsftSkipEx("ring-set not supported by the device")138try:139rings = netnl.rings_get({'header': {'dev-index': cfg.ifindex}})140except NlError as e:141raise KsftSkipEx('ring-get not supported by device')142if 'hds-thresh' not in rings:143raise KsftSkipEx('hds-thresh not supported by device')144145ksft_eq(0, rings['hds-thresh'])146147def set_hds_thresh_random(cfg, netnl) -> None:148_defer_reset_hds(cfg, netnl)149try:150rings = netnl.rings_get({'header': {'dev-index': cfg.ifindex}})151except NlError as e:152raise KsftSkipEx('ring-get not supported by device')153if 'hds-thresh' not in rings:154raise KsftSkipEx('hds-thresh not supported by device')155if 'hds-thresh-max' not in rings:156raise KsftSkipEx('hds-thresh-max not defined by device')157158if rings['hds-thresh-max'] < 2:159raise KsftSkipEx('hds-thresh-max is too small')160elif rings['hds-thresh-max'] == 2:161hds_thresh = 1162else:163while True:164hds_thresh = random.randint(1, rings['hds-thresh-max'] - 1)165if hds_thresh != rings['hds-thresh']:166break167168try:169netnl.rings_set({'header': {'dev-index': cfg.ifindex}, 'hds-thresh': hds_thresh})170except NlError as e:171if e.error == errno.EINVAL:172raise KsftSkipEx("hds-thresh-set not supported by the device")173elif e.error == errno.EOPNOTSUPP:174raise KsftSkipEx("ring-set not supported by the device")175rings = netnl.rings_get({'header': {'dev-index': cfg.ifindex}})176ksft_eq(hds_thresh, rings['hds-thresh'])177178def set_hds_thresh_max(cfg, netnl) -> None:179_defer_reset_hds(cfg, netnl)180try:181rings = netnl.rings_get({'header': {'dev-index': cfg.ifindex}})182except NlError as e:183raise KsftSkipEx('ring-get not supported by device')184if 'hds-thresh' not in rings:185raise KsftSkipEx('hds-thresh not supported by device')186try:187netnl.rings_set({'header': {'dev-index': cfg.ifindex}, 'hds-thresh': rings['hds-thresh-max']})188except NlError as e:189if e.error == errno.EINVAL:190raise KsftSkipEx("hds-thresh-set not supported by the device")191elif e.error == errno.EOPNOTSUPP:192raise KsftSkipEx("ring-set not supported by the device")193rings = netnl.rings_get({'header': {'dev-index': cfg.ifindex}})194ksft_eq(rings['hds-thresh'], rings['hds-thresh-max'])195196def set_hds_thresh_gt(cfg, netnl) -> None:197_defer_reset_hds(cfg, netnl)198try:199rings = netnl.rings_get({'header': {'dev-index': cfg.ifindex}})200except NlError as e:201raise KsftSkipEx('ring-get not supported by device')202if 'hds-thresh' not in rings:203raise KsftSkipEx('hds-thresh not supported by device')204if 'hds-thresh-max' not in rings:205raise KsftSkipEx('hds-thresh-max not defined by device')206hds_gt = rings['hds-thresh-max'] + 1207with ksft_raises(NlError) as e:208netnl.rings_set({'header': {'dev-index': cfg.ifindex}, 'hds-thresh': hds_gt})209ksft_eq(e.exception.nl_msg.error, -errno.EINVAL)210211212def set_xdp(cfg, netnl) -> None:213"""214Enable single-buffer XDP on the device.215When HDS is in "auto" / UNKNOWN mode, XDP installation should work.216"""217mode = _get_hds_mode(cfg, netnl)218if mode == 'enabled':219_defer_reset_hds(cfg, netnl)220netnl.rings_set({'header': {'dev-index': cfg.ifindex},221'tcp-data-split': 'unknown'})222223_xdp_onoff(cfg)224225226def enabled_set_xdp(cfg, netnl) -> None:227"""228Enable single-buffer XDP on the device.229When HDS is in "enabled" mode, XDP installation should not work.230"""231_get_hds_mode(cfg, netnl)232netnl.rings_set({'header': {'dev-index': cfg.ifindex},233'tcp-data-split': 'enabled'})234235defer(netnl.rings_set, {'header': {'dev-index': cfg.ifindex},236'tcp-data-split': 'unknown'})237238with ksft_raises(CmdExitFailure) as e:239_xdp_onoff(cfg)240241242def set_xdp(cfg, netnl) -> None:243"""244Enable single-buffer XDP on the device.245When HDS is in "auto" / UNKNOWN mode, XDP installation should work.246"""247mode = _get_hds_mode(cfg, netnl)248if mode == 'enabled':249netnl.rings_set({'header': {'dev-index': cfg.ifindex},250'tcp-data-split': 'unknown'})251252_xdp_onoff(cfg)253254255def enabled_set_xdp(cfg, netnl) -> None:256"""257Enable single-buffer XDP on the device.258When HDS is in "enabled" mode, XDP installation should not work.259"""260_get_hds_mode(cfg, netnl) # Trigger skip if not supported261262netnl.rings_set({'header': {'dev-index': cfg.ifindex},263'tcp-data-split': 'enabled'})264defer(netnl.rings_set, {'header': {'dev-index': cfg.ifindex},265'tcp-data-split': 'unknown'})266267with ksft_raises(CmdExitFailure) as e:268_xdp_onoff(cfg)269270271def ioctl(cfg, netnl) -> None:272mode1 = _get_hds_mode(cfg, netnl)273_ioctl_ringparam_modify(cfg, netnl)274mode2 = _get_hds_mode(cfg, netnl)275276ksft_eq(mode1, mode2)277278279def ioctl_set_xdp(cfg, netnl) -> None:280"""281Like set_xdp(), but we perturb the settings via the legacy ioctl.282"""283mode = _get_hds_mode(cfg, netnl)284if mode == 'enabled':285netnl.rings_set({'header': {'dev-index': cfg.ifindex},286'tcp-data-split': 'unknown'})287288_ioctl_ringparam_modify(cfg, netnl)289290_xdp_onoff(cfg)291292293def ioctl_enabled_set_xdp(cfg, netnl) -> None:294"""295Enable single-buffer XDP on the device.296When HDS is in "enabled" mode, XDP installation should not work.297"""298_get_hds_mode(cfg, netnl) # Trigger skip if not supported299300netnl.rings_set({'header': {'dev-index': cfg.ifindex},301'tcp-data-split': 'enabled'})302defer(netnl.rings_set, {'header': {'dev-index': cfg.ifindex},303'tcp-data-split': 'unknown'})304305with ksft_raises(CmdExitFailure) as e:306_xdp_onoff(cfg)307308309def main() -> None:310with NetDrvEnv(__file__, queue_count=3) as cfg:311ksft_run([get_hds,312get_hds_thresh,313set_hds_disable,314set_hds_enable,315set_hds_thresh_random,316set_hds_thresh_zero,317set_hds_thresh_max,318set_hds_thresh_gt,319set_xdp,320enabled_set_xdp,321ioctl,322ioctl_set_xdp,323ioctl_enabled_set_xdp],324args=(cfg, EthtoolFamily()))325ksft_exit()326327if __name__ == "__main__":328main()329330331