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
Daniel Zahka (3): selftests: drv-net: tso: enable test cases based on hw_features selftests: drv-net: tso: fix vxlan tunnel flags to get correct gso_type selftests: drv-net: tso: fix non-tunneled tso6 test case name
tools/testing/selftests/drivers/net/hw/tso.py | 99 +++++++++++-------- 1 file changed, 59 insertions(+), 40 deletions(-)
tso.py uses the active features at the time of test execution as the set of available gso features to test. This means if a gso feature is supported but toggled off at test start, the test will be skipped with a "Device does not support {feature}" message.
Instead, we can enumerate the set of toggleable features by capturing the driver's hw_features bitmap. To avoid configuration side-effects from running the test, we also snapshot the wanted_features flag set before making any feature changes, and then attempt to restore the same set of wanted_features before test exit.
Fixes: 0d0f4174f6c8 ("selftests: drv-net: add a simple TSO test") Signed-off-by: Daniel Zahka daniel.zahka@gmail.com --- tools/testing/selftests/drivers/net/hw/tso.py | 52 ++++++++++++++----- 1 file changed, 40 insertions(+), 12 deletions(-)
diff --git a/tools/testing/selftests/drivers/net/hw/tso.py b/tools/testing/selftests/drivers/net/hw/tso.py index 3370827409aa..f8386e3d88cd 100755 --- a/tools/testing/selftests/drivers/net/hw/tso.py +++ b/tools/testing/selftests/drivers/net/hw/tso.py @@ -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) @@ -138,12 +153,12 @@ def test_builder(name, cfg, outer_ipver, feature, tun=None, inner_ipver=None):
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 + has_gso_partial = tun and 'tx-gso-partial' in cfg.hw_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: + if 'tx-tcp-mangleid-segmentation' not in cfg.hw_features: ethtool(f"-K {cfg.ifname} tx-tcp-mangleid-segmentation on") defer(ethtool, f"-K {cfg.ifname} tx-tcp-mangleid-segmentation off")
@@ -161,11 +176,8 @@ def test_builder(name, cfg, outer_ipver, feature, tun=None, inner_ipver=None): should_lso=tun_partial)
# 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}") + ethtool(f"-K {cfg.ifname} {feature} on") + run_one_stream(cfg, ipver, remote_v4, remote_v6, should_lso=True)
f.__name__ = name + ((outer_ipver + "_") if tun else "") + "ipv" + inner_ipver return f @@ -176,23 +188,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]:
When vxlan is used with ipv6 as the outer network header, the correct ip link parameters for acheiving the SKB_GSO_UDP_TUNNEL gso type is "udp6zerocsumtx udp6zerocsumrx". Otherwise the gso type will be SKB_GSO_UDP_TUNNEL_CSUM.
This bug was the reason for the second of the three possible invocations of run_one_stream() invocations, so that can be deleted as well. We only need to test with the feature off and on.
Fixes: 0d0f4174f6c8 ("selftests: drv-net: add a simple TSO test") Signed-off-by: Daniel Zahka daniel.zahka@gmail.com --- tools/testing/selftests/drivers/net/hw/tso.py | 37 +++++++------------ 1 file changed, 13 insertions(+), 24 deletions(-)
diff --git a/tools/testing/selftests/drivers/net/hw/tso.py b/tools/testing/selftests/drivers/net/hw/tso.py index f8386e3d88cd..6461a83b3d0e 100755 --- a/tools/testing/selftests/drivers/net/hw/tso.py +++ b/tools/testing/selftests/drivers/net/hw/tso.py @@ -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") @@ -151,29 +151,17 @@ 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.hw_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.hw_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. ethtool(f"-K {cfg.ifname} {feature} on") @@ -239,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) ("", "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")), + ("vxlan", "6", "tx-udp_tnl-segmentation", ("vxlan", "id 100 dstport 4789 udp6zerocsumtx udp6zerocsumrx")), + ("vxlan_csum", "", "tx-udp_tnl-csum-segmentation", ("vxlan", "id 100 dstport 4789 udpcsum")), + ("gre", "4", "tx-gre-segmentation", ("gre", "")), + ("gre", "6", "tx-gre-segmentation", ("ip6gre", "")), )
cases = []
The non-tunneled tso6 test case was showing up as: ok 8 tso.ipv4
This is because of the way test_builder() uses the inner_ipver arg in test naming, and how test_info is iterated over in main(). Given that some tunnels not supported yet, e.g. ipip or sit, only support ipv4 or ipv6 as the inner network protocol, I think the best fix here is to call test_builder() in separate branches for tunneled and non-tunneled tests, and to make supported inner l3 types an explicit attribute of tunnel test cases.
# 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
Fixes: 0d0f4174f6c8 ("selftests: drv-net: add a simple TSO test") Signed-off-by: Daniel Zahka daniel.zahka@gmail.com --- tools/testing/selftests/drivers/net/hw/tso.py | 26 ++++++++++--------- 1 file changed, 14 insertions(+), 12 deletions(-)
diff --git a/tools/testing/selftests/drivers/net/hw/tso.py b/tools/testing/selftests/drivers/net/hw/tso.py index 6461a83b3d0e..5fddb5056a20 100755 --- a/tools/testing/selftests/drivers/net/hw/tso.py +++ b/tools/testing/selftests/drivers/net/hw/tso.py @@ -227,14 +227,14 @@ def main() -> None: query_nic_features(cfg)
test_info = ( - # name, v4/v6 ethtool_feature tun:(type, args) - ("", "4", "tx-tcp-segmentation", None), - ("", "6", "tx-tcp6-segmentation", None), - ("vxlan", "4", "tx-udp_tnl-segmentation", ("vxlan", "id 100 dstport 4789 noudpcsum")), - ("vxlan", "6", "tx-udp_tnl-segmentation", ("vxlan", "id 100 dstport 4789 udp6zerocsumtx udp6zerocsumrx")), - ("vxlan_csum", "", "tx-udp_tnl-csum-segmentation", ("vxlan", "id 100 dstport 4789 udpcsum")), - ("gre", "4", "tx-gre-segmentation", ("gre", "")), - ("gre", "6", "tx-gre-segmentation", ("ip6gre", "")), + # name, v4/v6 ethtool_feature tun:(type, args, inner ip versions) + ("", "4", "tx-tcp-segmentation", None), + ("", "6", "tx-tcp6-segmentation", None), + ("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 = [] @@ -244,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()
Hello:
This series was applied to netdev/net.git (main) by Jakub Kicinski kuba@kernel.org:
On Wed, 23 Jul 2025 11:47:35 -0700 you wrote:
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.
[...]
Here is the summary with links: - [net,1/3] selftests: drv-net: tso: enable test cases based on hw_features https://git.kernel.org/netdev/net/c/266b835e5e84 - [net,2/3] selftests: drv-net: tso: fix vxlan tunnel flags to get correct gso_type https://git.kernel.org/netdev/net/c/2cfbcc5d8af9 - [net,3/3] selftests: drv-net: tso: fix non-tunneled tso6 test case name https://git.kernel.org/netdev/net/c/b25b44cd178c
You are awesome, thank you!
linux-kselftest-mirror@lists.linaro.org