Commit c8f13134 authored by Jakub Kicinski's avatar Jakub Kicinski
Browse files

Merge branch 'selftests-drv-net-tso-fix-issues-with-tso-selftest'

Daniel Zahka says:

====================
selftests: drv-net: tso: fix issues with tso selftest

There are a couple issues with the tso selftest.

 - Features required for test cases are detected by searching the set
   of active features at test start, so if a feature is supported by
   hw, but disabled, the test will report that the feature under test
   is not available and fail.
 - The vxlan test cases do not use the correct ip link flags based on
   the gso feature under test
 - The non-tunneled tso6 test case is showing up with the wrong name.

With all patches applied test output is:

  # Detected qstat for LSO wire-packets
  TAP version 13
  1..14
  ok 1 tso.ipv4
  # Testing with mangleid enabled
  ok 2 tso.vxlan4_ipv4
  ok 3 tso.vxlan4_ipv6
  # Testing with mangleid enabled
  ok 4 tso.vxlan_csum4_ipv4
  ok 5 tso.vxlan_csum4_ipv6
  # Testing with mangleid enabled
  ok 6 tso.gre4_ipv4
  ok 7 tso.gre4_ipv6
  ok 8 tso.ipv6
  # Testing with mangleid enabled
  ok 9 tso.vxlan6_ipv4
  ok 10 tso.vxlan6_ipv6
  # Testing with mangleid enabled
  ok 11 tso.vxlan_csum6_ipv4
  ok 12 tso.vxlan_csum6_ipv6
  # Testing with mangleid enabled
  ok 13 tso.gre6_ipv4
  ok 14 tso.gre6_ipv6
  # Totals: pass:14 fail:0 xfail:0 xpass:0 skip:0 error:0
====================

Link: https://patch.msgid.link/20250723184740.4075410-1-daniel.zahka@gmail.com


Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parents 407c114c b25b44cd
Loading
Loading
Loading
Loading
+59 −40
Original line number Diff line number Diff line
@@ -102,7 +102,7 @@ def build_tunnel(cfg, outer_ipver, tun_info):
    remote_addr = cfg.remote_addr_v[outer_ipver]

    tun_type = tun_info[0]
    tun_arg  = tun_info[2]
    tun_arg  = tun_info[1]
    ip(f"link add {tun_type}-ksft type {tun_type} {tun_arg} local {local_addr} remote {remote_addr} dev {cfg.ifname}")
    defer(ip, f"link del {tun_type}-ksft")
    ip(f"link set dev {tun_type}-ksft up")
@@ -119,15 +119,30 @@ def build_tunnel(cfg, outer_ipver, tun_info):
    return remote_v4, remote_v6


def restore_wanted_features(cfg):
    features_cmd = ""
    for feature in cfg.hw_features:
        setting = "on" if feature in cfg.wanted_features else "off"
        features_cmd += f" {feature} {setting}"
    try:
        ethtool(f"-K {cfg.ifname} {features_cmd}")
    except Exception as e:
        ksft_pr(f"WARNING: failure restoring wanted features: {e}")


def test_builder(name, cfg, outer_ipver, feature, tun=None, inner_ipver=None):
    """Construct specific tests from the common template."""
    def f(cfg):
        cfg.require_ipver(outer_ipver)
        defer(restore_wanted_features, cfg)

        if not cfg.have_stat_super_count and \
           not cfg.have_stat_wire_count:
            raise KsftSkipEx(f"Device does not support LSO queue stats")

        if feature not in cfg.hw_features:
            raise KsftSkipEx(f"Device does not support {feature}")

        ipver = outer_ipver
        if tun:
            remote_v4, remote_v6 = build_tunnel(cfg, ipver, tun)
@@ -136,36 +151,21 @@ def test_builder(name, cfg, outer_ipver, feature, tun=None, inner_ipver=None):
            remote_v4 = cfg.remote_addr_v["4"]
            remote_v6 = cfg.remote_addr_v["6"]

        tun_partial = tun and tun[1]
        # Tunnel which can silently fall back to gso-partial
        has_gso_partial = tun and 'tx-gso-partial' in cfg.features

        # For TSO4 via partial we need mangleid
        if ipver == "4" and feature in cfg.partial_features:
            ksft_pr("Testing with mangleid enabled")
            if 'tx-tcp-mangleid-segmentation' not in cfg.features:
                ethtool(f"-K {cfg.ifname} tx-tcp-mangleid-segmentation on")
                defer(ethtool, f"-K {cfg.ifname} tx-tcp-mangleid-segmentation off")

        # First test without the feature enabled.
        ethtool(f"-K {cfg.ifname} {feature} off")
        if has_gso_partial:
            ethtool(f"-K {cfg.ifname} tx-gso-partial off")
        run_one_stream(cfg, ipver, remote_v4, remote_v6, should_lso=False)

        # Now test with the feature enabled.
        # For compatible tunnels only - just GSO partial, not specific feature.
        if has_gso_partial:
        ethtool(f"-K {cfg.ifname} tx-gso-partial off")
        ethtool(f"-K {cfg.ifname} tx-tcp-mangleid-segmentation off")
        if feature in cfg.partial_features:
            ethtool(f"-K {cfg.ifname} tx-gso-partial on")
            run_one_stream(cfg, ipver, remote_v4, remote_v6,
                           should_lso=tun_partial)
            if ipver == "4":
                ksft_pr("Testing with mangleid enabled")
                ethtool(f"-K {cfg.ifname} tx-tcp-mangleid-segmentation on")

        # Full feature enabled.
        if feature in cfg.features:
        ethtool(f"-K {cfg.ifname} {feature} on")
        run_one_stream(cfg, ipver, remote_v4, remote_v6, should_lso=True)
        else:
            raise KsftXfailEx(f"Device does not support {feature}")

    f.__name__ = name + ((outer_ipver + "_") if tun else "") + "ipv" + inner_ipver
    return f
@@ -176,23 +176,39 @@ def query_nic_features(cfg) -> None:
    cfg.have_stat_super_count = False
    cfg.have_stat_wire_count = False

    cfg.features = set()
    features = cfg.ethnl.features_get({"header": {"dev-index": cfg.ifindex}})
    for f in features["active"]["bits"]["bit"]:
        cfg.features.add(f["name"])

    cfg.wanted_features = set()
    for f in features["wanted"]["bits"]["bit"]:
        cfg.wanted_features.add(f["name"])

    cfg.hw_features = set()
    hw_all_features_cmd = ""
    for f in features["hw"]["bits"]["bit"]:
        if f.get("value", False):
            feature = f["name"]
            cfg.hw_features.add(feature)
            hw_all_features_cmd += f" {feature} on"
    try:
        ethtool(f"-K {cfg.ifname} {hw_all_features_cmd}")
    except Exception as e:
        ksft_pr(f"WARNING: failure enabling all hw features: {e}")
        ksft_pr("partial gso feature detection may be impacted")

    # Check which features are supported via GSO partial
    cfg.partial_features = set()
    if 'tx-gso-partial' in cfg.features:
    if 'tx-gso-partial' in cfg.hw_features:
        ethtool(f"-K {cfg.ifname} tx-gso-partial off")

        no_partial = set()
        features = cfg.ethnl.features_get({"header": {"dev-index": cfg.ifindex}})
        for f in features["active"]["bits"]["bit"]:
            no_partial.add(f["name"])
        cfg.partial_features = cfg.features - no_partial
        cfg.partial_features = cfg.hw_features - no_partial
        ethtool(f"-K {cfg.ifname} tx-gso-partial on")

    restore_wanted_features(cfg)

    stats = cfg.netnl.qstats_get({"ifindex": cfg.ifindex}, dump=True)
    if stats:
        if 'tx-hw-gso-packets' in stats[0]:
@@ -211,13 +227,14 @@ def main() -> None:
        query_nic_features(cfg)

        test_info = (
            # name,       v4/v6  ethtool_feature              tun:(type,    partial, args)
            # name,       v4/v6  ethtool_feature               tun:(type, args, inner ip versions)
            ("",           "4", "tx-tcp-segmentation",         None),
            ("",           "6", "tx-tcp6-segmentation",        None),
            ("vxlan",        "", "tx-udp_tnl-segmentation",       ("vxlan",  True,  "id 100 dstport 4789 noudpcsum")),
            ("vxlan_csum",   "", "tx-udp_tnl-csum-segmentation",  ("vxlan",  False, "id 100 dstport 4789 udpcsum")),
            ("gre",         "4", "tx-gre-segmentation",           ("gre",    False,  "")),
            ("gre",         "6", "tx-gre-segmentation",           ("ip6gre", False,  "")),
            ("vxlan",      "4", "tx-udp_tnl-segmentation",     ("vxlan", "id 100 dstport 4789 noudpcsum", ("4", "6"))),
            ("vxlan",      "6", "tx-udp_tnl-segmentation",     ("vxlan", "id 100 dstport 4789 udp6zerocsumtx udp6zerocsumrx", ("4", "6"))),
            ("vxlan_csum", "", "tx-udp_tnl-csum-segmentation", ("vxlan", "id 100 dstport 4789 udpcsum", ("4", "6"))),
            ("gre",        "4", "tx-gre-segmentation",         ("gre",   "", ("4", "6"))),
            ("gre",        "6", "tx-gre-segmentation",         ("ip6gre","", ("4", "6"))),
        )

        cases = []
@@ -227,11 +244,13 @@ def main() -> None:
                if info[1] and outer_ipver != info[1]:
                    continue

                cases.append(test_builder(info[0], cfg, outer_ipver, info[2],
                                          tun=info[3], inner_ipver="4"))
                if info[3]:
                    cases.append(test_builder(info[0], cfg, outer_ipver, info[2],
                                              tun=info[3], inner_ipver="6"))
                    cases += [
                        test_builder(info[0], cfg, outer_ipver, info[2], info[3], inner_ipver)
                        for inner_ipver in info[3][2]
                    ]
                else:
                    cases.append(test_builder(info[0], cfg, outer_ipver, info[2], None, outer_ipver))

        ksft_run(cases=cases, args=(cfg, ))
    ksft_exit()