From: Stanislav Fomichev <stfomichev@gmail.com>
To: Jakub Kicinski <kuba@kernel.org>
Cc: davem@davemloft.net, netdev@vger.kernel.org, edumazet@google.com,
pabeni@redhat.com, andrew+netdev@lunn.ch, horms@kernel.org,
willemb@google.com, shuah@kernel.org, petrm@nvidia.com
Subject: Re: [PATCH net-next 3/3] selftests: drv-net: add a simple TSO test
Date: Wed, 12 Feb 2025 18:49:38 -0800 [thread overview]
Message-ID: <Z61dwqIp7PD_-m0B@mini-arch> (raw)
In-Reply-To: <20250213003454.1333711-4-kuba@kernel.org>
On 02/12, Jakub Kicinski wrote:
> Add a simple test for TSO. Send a few MB of data and check device
> stats to verify that the device was performing segmentation.
> Do the same thing over a few tunnel types.
>
> Injecting GSO packets directly would give us more ability to test
> corner cases, but perhaps starting simple is good enough?
>
> # ./ksft-net-drv/drivers/net/hw/tso.py
> # Detected qstat for LSO wire-packets
> KTAP version 1
> 1..14
> ok 1 tso.ipv4 # SKIP Test requires IPv4 connectivity
> ok 2 tso.vxlan4_ipv4 # SKIP Test requires IPv4 connectivity
> ok 3 tso.vxlan6_ipv4 # SKIP Test requires IPv4 connectivity
> ok 4 tso.vxlan_csum4_ipv4 # SKIP Test requires IPv4 connectivity
> ok 5 tso.vxlan_csum6_ipv4 # SKIP Test requires IPv4 connectivity
> ok 6 tso.gre4_ipv4 # SKIP Test requires IPv4 connectivity
> ok 7 tso.gre6_ipv4 # SKIP Test requires IPv4 connectivity
> ok 8 tso.ipv6
> ok 9 tso.vxlan4_ipv6
> ok 10 tso.vxlan6_ipv6
> ok 11 tso.vxlan_csum4_ipv6
> ok 12 tso.vxlan_csum6_ipv6
> ok 13 tso.gre4_ipv6
> ok 14 tso.gre6_ipv6
> # Totals: pass:7 fail:0 xfail:0 xpass:0 skip:7 error:0
>
> Note that the test currently depends on the driver reporting
> the LSO count via qstat, which appears to be relatively rare
> (virtio, cisco/enic, sfc/efc; but virtio needs host support).
>
> Signed-off-by: Jakub Kicinski <kuba@kernel.org>
> ---
> .../testing/selftests/drivers/net/hw/Makefile | 1 +
> tools/testing/selftests/drivers/net/hw/tso.py | 226 ++++++++++++++++++
> 2 files changed, 227 insertions(+)
> create mode 100755 tools/testing/selftests/drivers/net/hw/tso.py
>
> diff --git a/tools/testing/selftests/drivers/net/hw/Makefile b/tools/testing/selftests/drivers/net/hw/Makefile
> index 21ba64ce1e34..ae783e18be83 100644
> --- a/tools/testing/selftests/drivers/net/hw/Makefile
> +++ b/tools/testing/selftests/drivers/net/hw/Makefile
> @@ -15,6 +15,7 @@ TEST_PROGS = \
> nic_performance.py \
> pp_alloc_fail.py \
> rss_ctx.py \
> + tso.py \
> #
>
> TEST_FILES := \
> diff --git a/tools/testing/selftests/drivers/net/hw/tso.py b/tools/testing/selftests/drivers/net/hw/tso.py
> new file mode 100755
> index 000000000000..ee3e207d85b3
> --- /dev/null
> +++ b/tools/testing/selftests/drivers/net/hw/tso.py
> @@ -0,0 +1,226 @@
> +#!/usr/bin/env python3
> +# SPDX-License-Identifier: GPL-2.0
> +
> +"""Run the tools/testing/selftests/net/csum testsuite."""
> +
> +import fcntl
> +import socket
> +import struct
> +import termios
> +import time
> +
> +from lib.py import ksft_pr, ksft_run, ksft_exit, KsftSkipEx, KsftXfailEx
> +from lib.py import ksft_eq, ksft_ge, ksft_lt
> +from lib.py import EthtoolFamily, NetdevFamily, NetDrvEpEnv
> +from lib.py import bkg, cmd, defer, ethtool, ip, rand_port, wait_port_listen
> +
> +
> +def sock_wait_drain(sock, max_wait=1000):
> + """Wait for all pending write data on the socket to get ACKed."""
> + for _ in range(max_wait):
> + one = b'\0' * 4
> + outq = fcntl.ioctl(sock.fileno(), termios.TIOCOUTQ, one)
> + outq = struct.unpack("I", outq)[0]
> + if outq == 0:
> + break
> + time.sleep(0.01)
> + ksft_eq(outq, 0)
> +
> +
> +def tcp_sock_get_retrans(sock):
> + """Get the number of retransmissions for the TCP socket."""
> + info = sock.getsockopt(socket.SOL_TCP, socket.TCP_INFO, 512)
> + return struct.unpack("I", info[100:104])[0]
> +
> +
> +def run_one_stream(cfg, ipv4, remote_v4, remote_v6, should_lso):
> + cfg.require_cmd("socat", remote=True)
> +
> + port = rand_port()
> + listen_cmd = f"socat -{cfg.addr_ipver} -t 2 -u TCP-LISTEN:{port},reuseport /dev/null,ignoreeof"
> +
> + with bkg(listen_cmd, host=cfg.remote) as nc:
> + wait_port_listen(port, host=cfg.remote)
> +
> + if ipv4:
> + sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
> + sock.connect((remote_v4, port))
> + else:
> + sock = socket.socket(socket.AF_INET6, socket.SOCK_STREAM)
> + sock.connect((remote_v6, port))
> +
> + # Small send to make sure the connection is working.
> + sock.send("ping".encode())
> + sock_wait_drain(sock)
> +
> + # Send 4MB of data, record the LSO packet count.
> + qstat_old = cfg.netnl.qstats_get({"ifindex": cfg.ifindex}, dump=True)[0]
> + buf = b"0" * 1024 * 1024 * 4
> + sock.send(buf)
> + sock_wait_drain(sock)
> + qstat_new = cfg.netnl.qstats_get({"ifindex": cfg.ifindex}, dump=True)[0]
> +
> + # No math behind the 10 here, but try to catch cases where
> + # TCP falls back to non-LSO.
> + ksft_lt(tcp_sock_get_retrans(sock), 10)
> + sock.close()
> +
> + # Check that at least 90% of the data was sent as LSO packets.
> + # System noise may cause false negatives, it is what it is.
> + total_lso_wire = len(buf) * 0.90 // cfg.dev["mtu"]
> + total_lso_super = len(buf) * 0.90 // cfg.dev["tso_max_size"]
> + if should_lso:
> + if cfg.have_stat_super_count:
> + ksft_ge(qstat_new['tx-hw-gso-packets'] -
> + qstat_old['tx-hw-gso-packets'],
> + total_lso_super,
> + comment="Number of LSO super-packets with LSO enabled")
> + if cfg.have_stat_wire_count:
> + ksft_ge(qstat_new['tx-hw-gso-wire-packets'] -
> + qstat_old['tx-hw-gso-wire-packets'],
> + total_lso_wire,
> + comment="Number of LSO wire-packets with LSO enabled")
> + else:
[..]
> + if cfg.have_stat_super_count:
> + ksft_lt(qstat_new['tx-hw-gso-packets'] -
> + qstat_old['tx-hw-gso-packets'],
> + 100, comment="Number of LSO super-packets with LSO disabled")
> + if cfg.have_stat_wire_count:
> + ksft_lt(qstat_new['tx-hw-gso-wire-packets'] -
> + qstat_old['tx-hw-gso-wire-packets'],
> + 1000, comment="Number of LSO wire-packets with LSO disabled")
Why do you expect there to be some noise (100/1000) with the feature
disabled?
next prev parent reply other threads:[~2025-02-13 2:49 UTC|newest]
Thread overview: 14+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-02-13 0:34 [PATCH net-next 0/3] selftests: drv-net: add a simple TSO test Jakub Kicinski
2025-02-13 0:34 ` [PATCH net-next 1/3] selftests: drv-net: resolve remote interface name Jakub Kicinski
2025-02-13 14:31 ` Petr Machata
2025-02-13 15:55 ` Jakub Kicinski
2025-02-13 16:23 ` Petr Machata
2025-02-13 0:34 ` [PATCH net-next 2/3] selftests: drv-net: get detailed interface info Jakub Kicinski
2025-02-13 14:39 ` Petr Machata
2025-02-13 0:34 ` [PATCH net-next 3/3] selftests: drv-net: add a simple TSO test Jakub Kicinski
2025-02-13 2:49 ` Stanislav Fomichev [this message]
2025-02-13 4:18 ` Jakub Kicinski
2025-02-13 16:02 ` Willem de Bruijn
2025-02-13 17:01 ` Jakub Kicinski
2025-02-13 16:01 ` Willem de Bruijn
2025-02-13 17:07 ` Jakub Kicinski
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=Z61dwqIp7PD_-m0B@mini-arch \
--to=stfomichev@gmail.com \
--cc=andrew+netdev@lunn.ch \
--cc=davem@davemloft.net \
--cc=edumazet@google.com \
--cc=horms@kernel.org \
--cc=kuba@kernel.org \
--cc=netdev@vger.kernel.org \
--cc=pabeni@redhat.com \
--cc=petrm@nvidia.com \
--cc=shuah@kernel.org \
--cc=willemb@google.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.