mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Todd Freed <toddfreed@meta.com>
To: <netdev@vger.kernel.org>, <toddfreed@meta.com>
Cc: "David S. Miller" <davem@davemloft.net>,
	"Andrew Lunn" <andrew+netdev@lunn.ch>,
	"Björn Töpel" <bjorn@kernel.org>,
	"Boris Pismenny" <borisp@nvidia.com>,
	"Cosmin Ratiu" <cratiu@nvidia.com>,
	"Daniel Zahka" <daniel.zahka@gmail.com>,
	"David Ahern" <dsahern@kernel.org>,
	"Dragos Tatulea" <dtatulea@nvidia.com>,
	"Eric Dumazet" <edumazet@kernel.org>,
	"Ido Schimmel" <idosch@nvidia.com>,
	"Jakub Kicinski" <kuba@kernel.org>,
	"John Fastabend" <john.fastabend@gmail.com>,
	"Leon Romanovsky" <leon@kernel.org>,
	linux-kernel@vger.kernel.org, linux-kselftest@vger.kernel.org,
	linux-rdma@vger.kernel.org, "Mark Bloch" <mbloch@nvidia.com>,
	"Paolo Abeni" <pabeni@redhat.com>,
	"Raed Salem" <raeds@nvidia.com>,
	"Rahul Rameshbabu" <rrameshbabu@nvidia.com>,
	"Sabrina Dubroca" <sd@queasysnail.net>,
	"Saeed Mahameed" <saeedm@nvidia.com>,
	"Shuah Khan" <shuah@kernel.org>,
	"Simon Horman" <horms@kernel.org>,
	"Tariq Toukan" <tariqt@nvidia.com>,
	"Wei Wang" <weiwan@google.com>,
	"Willem de Bruijn" <willemdebruijn.kernel@gmail.com>
Subject: [PATCH net v5 7/8] selftests: drv-net: psp: test that ipv4 psp packets aren't fragmented
Date: Tue, 10 Nov 2026 16:18:30 -0800	[thread overview]
Message-ID: <20261111001831.3710881-8-toddfreed@meta.com> (raw)
In-Reply-To: <20261111001831.3710881-1-toddfreed@meta.com>

make the ipv4 packets of a psp tcp socket need fragmenting, and check
that they're dropped (IpFragFails) and not transmitted unencrypted.

tcp sizes its segments from the route mtu. with IP_PMTUDISC_OMIT, ip
fragments them to the device mtu, and doesn't set df. so the test sets a
route mtu of twice the larger of the two device mtus (at most 65535) on
both ends (the peer's mss limits ours too), keeping the device and
source address of the current route, and IP_PMTUDISC_OMIT on the
socket. tcp mtu probing (tcp_mtu_probing 2) would cap the mss at the
probing base, so the test turns it off. if the peer isn't on-link, or
the socket's mss doesn't need fragmenting, the test is skipped.

a software filter on the peer counts, and drops, the ipv4 fragments
which reach it from the socket's address, and the test asserts there are
none. IpFragFails is per netns, so it only confirms that the packets
were dropped.

while both route mtus are in place, a new ssh connection to the remote
over these addresses can stall: its segments are sized from the route
mtu, and sent with df set. so the local route is added last, and removed
before the next remote command.

no ipv6 test: the stack only fragments ipv6 tcp packets when something
like ipvs sets ignore_df on them (see "net: don't fragment decrypted
skbs"), which this test doesn't set up.

without the fix in "net: don't fragment decrypted skbs", the packets are
fragmented, and the fragments go out unencrypted. they reach the peer,
IpFragFails doesn't move, and the test fails.

Signed-off-by: Todd Freed <toddfreed@meta.com>
---
 tools/testing/selftests/drivers/net/psp.py | 101 +++++++++++++++++++++
 1 file changed, 101 insertions(+)

diff --git a/tools/testing/selftests/drivers/net/psp.py b/tools/testing/selftests/drivers/net/psp.py
index 7e251439a2fd..5dac62ad96b0 100755
--- a/tools/testing/selftests/drivers/net/psp.py
+++ b/tools/testing/selftests/drivers/net/psp.py
@@ -26,6 +26,8 @@ from lib.py import bkg, rand_port, wait_port_listen
 from lib.py import ip, tc
 
 TCP_ULP = 31
+IP_MTU_DISCOVER = 10
+IP_PMTUDISC_OMIT = 5
 
 
 def _get_outq(s):
@@ -799,6 +801,105 @@ def data_send_ipv6_exthdr(cfg, opt, val):
         _close_psp_conn(cfg, s)
 
 
+def _ipv4_snmp(key):
+    """ An Ip: counter of this netns, from /proc/net/snmp """
+    with open("/proc/net/snmp", encoding="utf-8") as f:
+        ip_lines = [line.split() for line in f if line.startswith("Ip:")]
+    return int(ip_lines[1][ip_lines[0].index(key)])
+
+
+def _ipv4_route_mtu(dst, mtu, host=None):
+    """ Add a route to @dst with @mtu, keeping the device and source of
+    the current one, which must be on-link. Returns the defer removing it.
+    """
+    route = ip(f"-4 route get {dst}", json=True, host=host)[0]
+    if route.get("gateway"):
+        raise KsftSkipEx(f"{dst} isn't on-link")
+    try:
+        ip(f"route add {dst}/32 dev {route['dev']} src {route['prefsrc']} "
+           f"mtu {mtu}", host=host)
+    except CmdExitFailure as e:
+        raise KsftSkipEx(f"can't set the route mtu to {dst}: {e}") from e
+    return defer(ip, f"route del {dst}/32 dev {route['dev']}", host=host)
+
+
+def data_send_ipv4_frags(cfg):
+    """ Test that IPv4 packets of a PSP TCP socket aren't fragmented """
+    cfg.require_ipver("4")
+    _init_psp_dev(cfg)
+
+    # Fragments which get out reach the remote. Set up the count before
+    # connecting, so a skip doesn't leave the responder mid key exchange.
+    # The socket's source is the one the kernel picks, which may not be
+    # LOCAL_V4, and the fragments would leave through the route's device
+    rem = cfg.remote_addr_v["4"]
+    route = ip(f"-4 route get {rem}", json=True)[0]
+    if route["dev"] != cfg.ifname:
+        raise KsftSkipEx(f"{rem} isn't routed through {cfg.ifname}")
+    loc = route["prefsrc"]
+    remote_frags = _remote_count(cfg, "ip",
+                                 f"src_ip {loc} dst_ip {rem} ip_flags frag")
+    if not remote_frags:
+        raise KsftSkipEx("can't count fragments on the remote")
+
+    # TCP sizes its segments from the route MTU. With IP_PMTUDISC_OMIT, IP
+    # fragments them to the device MTU. Set a route MTU above the device
+    # MTU on both ends, since the peer's MSS limits ours too. While both
+    # are in place, a new ssh connection to the remote over these addresses
+    # can stall, so add the local one last, and remove it first.
+    mtu = min(2 * max(cfg.dev['mtu'], cfg.remote_dev['mtu']), 65535)
+    _ipv4_route_mtu(loc, mtu, host=cfg.remote)
+    local_route = _ipv4_route_mtu(rem, mtu)
+
+    # With MTU probing on, TCP caps the MSS at the probing base, whatever
+    # the route MTU
+    probing_path = "/proc/sys/net/ipv4/tcp_mtu_probing"
+    with open(probing_path, encoding="utf-8") as fp:
+        probing = fp.read().strip()
+    if int(probing) > 1:
+        def set_probing(val):
+            with open(probing_path, "w", encoding="utf-8") as fp:
+                fp.write(val)
+        set_probing("0")
+        defer(set_probing, probing)
+
+    s = _make_psp_conn(cfg, 0, "4")
+    try:
+        rx_assoc = cfg.pspnl.rx_assoc({"version": 0,
+                                       "dev-id": cfg.psp_dev_id,
+                                       "sock-fd": s.fileno()})
+        tx = _spi_xchg(s, rx_assoc['rx-key'])
+        cfg.pspnl.tx_assoc({"dev-id": cfg.psp_dev_id,
+                            "version": 0,
+                            "tx-key": tx,
+                            "sock-fd": s.fileno()})
+        s.setsockopt(socket.IPPROTO_IP, IP_MTU_DISCOVER, IP_PMTUDISC_OMIT)
+        mss = s.getsockopt(socket.IPPROTO_TCP, socket.TCP_MAXSEG)
+        if mss + 40 <= cfg.dev['mtu']:
+            raise KsftSkipEx(f"mss {mss} needs no fragmenting")
+
+        fails = _ipv4_snmp("FragFails")
+        # The packets are dropped, so the send may not complete (with a
+        # jumbo device MTU, the socket buffer can take all of it)
+        s.settimeout(3)
+        try:
+            s.sendall(b'f' * 200000)
+        except socket.timeout:
+            pass
+        fails = _ipv4_snmp("FragFails") - fails
+
+        # Before the next ssh to the remote, see above
+        local_route.exec()
+
+        # Fragments would go out unencrypted: the packets must be dropped
+        # instead of fragmented. FragFails is per netns, so it only
+        # confirms the drop: the remote count is what decides.
+        ksft_eq(remote_frags(), 0, comment="fragments reached the remote")
+        ksft_gt(fails, 0, comment="packets dropped instead of fragmented")
+    finally:
+        _close_psp_conn(cfg, s)
+
+
 def _get_psp_ver_ip_variants():
     for ver in range(4):
         for ipv in ("4", "6"):
-- 
2.53.0-Meta


  parent reply	other threads:[~2026-11-11  0:19 UTC|newest]

Thread overview: 9+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-11-11  0:18 [PATCH net v5 0/8] psp, tls: don't send offloaded contents in cleartext Todd Freed
2026-11-11  0:18 ` [PATCH net v5 1/8] net/mlx5e: ring the tx doorbell when an accel offload drops a packet Todd Freed
2026-11-11  0:18 ` [PATCH net v5 2/8] psp: don't encapsulate ipv6 packets with extension headers Todd Freed
2026-11-11  0:18 ` [PATCH net v5 3/8] net: don't fragment decrypted skbs Todd Freed
2026-11-11  0:18 ` [PATCH net v5 4/8] ipv4: icmp: don't quote decrypted payload in icmp errors Todd Freed
2026-11-11  0:18 ` [PATCH net v5 5/8] ipv6: icmpv6: don't quote decrypted payload in icmpv6 errors Todd Freed
2026-11-11  0:18 ` [PATCH net v5 6/8] selftests: drv-net: psp: test ipv6 tcp socket with extension headers Todd Freed
2026-11-11  0:18 ` Todd Freed [this message]
2026-11-11  0:18 ` [PATCH net v5 8/8] net/mlx5e: psp: tso: replace only the length in checksum seed Todd Freed

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=20261111001831.3710881-8-toddfreed@meta.com \
    --to=toddfreed@meta.com \
    --cc=andrew+netdev@lunn.ch \
    --cc=bjorn@kernel.org \
    --cc=borisp@nvidia.com \
    --cc=cratiu@nvidia.com \
    --cc=daniel.zahka@gmail.com \
    --cc=davem@davemloft.net \
    --cc=dsahern@kernel.org \
    --cc=dtatulea@nvidia.com \
    --cc=edumazet@kernel.org \
    --cc=horms@kernel.org \
    --cc=idosch@nvidia.com \
    --cc=john.fastabend@gmail.com \
    --cc=kuba@kernel.org \
    --cc=leon@kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-kselftest@vger.kernel.org \
    --cc=linux-rdma@vger.kernel.org \
    --cc=mbloch@nvidia.com \
    --cc=netdev@vger.kernel.org \
    --cc=pabeni@redhat.com \
    --cc=raeds@nvidia.com \
    --cc=rrameshbabu@nvidia.com \
    --cc=saeedm@nvidia.com \
    --cc=sd@queasysnail.net \
    --cc=shuah@kernel.org \
    --cc=tariqt@nvidia.com \
    --cc=weiwan@google.com \
    --cc=willemdebruijn.kernel@gmail.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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®