mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH net] selftests/net: run tun tests in a dedicated network namespace
@ 2026-09-05  8:53 Edoardo Canepa
  2026-09-10  0:56 ` netdev-bot+sashiko
  0 siblings, 1 reply; 3+ messages in thread
From: Edoardo Canepa @ 2026-09-05  8:53 UTC (permalink / raw)
  To: netdev
  Cc: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Simon Horman, Shuah Khan, Xu Du, Po-Hsu Lin, linux-kselftest,
	linux-kernel

The tun_vnet_udptnl fixture creates a fresh tap device and installs an
IPv6 outer neighbor entry as NUD_PERMANENT before sending packets.  On
systems where systemd-udevd is running and a systemd .link file sets

    MACAddressPolicy=persistent

(the default shipped by systemd in 99-default.link, so this is what
most systemd-based hosts inherit), systemd-udevd's net_setup_link
builtin asynchronously sends an RTM_SETLINK to reassign the freshly
created tap device's MAC to a machine-persistent value.  When that
netlink message races the test's ip_neigh_add() call, the address
change kicks the following path:

    do_setlink
    -> netif_set_mac_address
       -> call_netdevice_notifiers_info
          -> ndisc_netdev_event
             -> neigh_changeaddr
                -> neigh_flush_dev(tbl, dev, /* skip_perm = */ false)

which flushes every neighbor entry on the interface, including the one
the test just installed as NUD_PERMANENT.  The subsequent packet
therefore hits __neigh_create(), triggers NDISC, and times out with:

  tun.c:947:send_gso_packet:Expected ret (0) == variant->data_size (1423)
  tun.c:948:send_gso_packet:Expected r_num_mss (0) == variant->r_num_mss (2)

The failure is non-deterministic and can affect both directions.  Both
recv_gso_packet and send_gso_packet variants can hit it; the failure
reproduces on a plain systemd-based VM with no containers, and is
triggered whenever the udev worker's RTM_SETLINK lands after the test
has installed its neighbor entry.

Fix by calling unshare(CLONE_NEWNET) once, from main(), before invoking
the kselftest_harness.  All tap and geneve devices are then created in
a namespace that systemd-udevd (running in the init netns) does not
watch, so its RTM_SETLINK never fires against them.  This mirrors the
approach used by selftests/net/ipsec.c, which also unshares from main()
rather than per-fixture; it keeps the harness output ordering intact
and avoids paying the netns-creation cost on every variant.

Verified on a plain systemd-based VM running the affected kernel:
1000 repeated invocations of
tun_vnet_udptnl.4in6_nogsosz_1byte.recv_gso_packet produce 7 failures
without the fix and zero failures with it.  A 20-iteration run of the
full test binary produces 4 failed runs (across different variants,
all send_gso_packet) without the fix and zero failed runs with it.

Reported-by: Po-Hsu Lin <po-hsu.lin@canonical.com>
Closes: https://bugs.launchpad.net/bugs/2158217
Fixes: 24e59f26eef2 ("selftest: tun: Add helpers for GSO over UDP tunnel")
Assisted-by: LLM
Signed-off-by: Edoardo Canepa <edoardo.canepa@canonical.com>
---
 tools/testing/selftests/net/tun.c | 11 ++++++++++-
 1 file changed, 10 insertions(+), 1 deletion(-)

diff --git a/tools/testing/selftests/net/tun.c b/tools/testing/selftests/net/tun.c
index abe488bac50b..7f118ba3ae0b 100644
--- a/tools/testing/selftests/net/tun.c
+++ b/tools/testing/selftests/net/tun.c
@@ -4,6 +4,7 @@
 
 #include <errno.h>
 #include <fcntl.h>
+#include <sched.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -985,4 +986,12 @@ XFAIL_ADD(tun_vnet_udptnl, 6in4_over_maxbytes, recv_gso_packet);
 XFAIL_ADD(tun_vnet_udptnl, 4in6_over_maxbytes, recv_gso_packet);
 XFAIL_ADD(tun_vnet_udptnl, 6in6_over_maxbytes, recv_gso_packet);
 
-TEST_HARNESS_MAIN
+int main(int argc, char **argv)
+{
+	if (unshare(CLONE_NEWNET) < 0) {
+		perror("unshare(CLONE_NEWNET)");
+		return 1;
+	}
+
+	return test_harness_run(argc, argv);
+}

base-commit: 80dd7e754b3aa9637a0758ad93fa209f9650ec48
-- 
2.53.0


^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [PATCH net] selftests/net: run tun tests in a dedicated network namespace
  2026-09-05  8:53 [PATCH net] selftests/net: run tun tests in a dedicated network namespace Edoardo Canepa
@ 2026-09-10  0:56 ` netdev-bot+sashiko
  2026-09-11  0:28   ` Jakub Kicinski
  0 siblings, 1 reply; 3+ messages in thread
From: netdev-bot+sashiko @ 2026-09-10  0:56 UTC (permalink / raw)
  To: edoardo.canepa
  Cc: netdev, davem, edumazet, kuba, pabeni, horms, shuah, xudu,
	po-hsu.lin, linux-kselftest, linux-kernel

Thank you for your contribution! Sashiko AI review found 1 potential
issue(s) to consider:

Critical: 0 · High: 0 · Medium: 1 · Low: 0

- [Medium] In the newly added main() in tools/testing/selftests/net/tun.c
  (lines 989-997), any failure of unshare(CLONE_NEWNET) is treated as a…

--

selftests/net: run tun tests in a dedicated network namespace

The patch replaces TEST_HARNESS_MAIN in tools/testing/selftests/net/tun.c
with a hand-written main() that calls unshare(CLONE_NEWNET) before running
the harness, so tap and geneve devices are created outside the init netns
that systemd-udevd watches.

Closes: https://bugs.launchpad.net/bugs/2158217

> diff --git a/tools/testing/selftests/net/tun.c b/tools/testing/selftests/net/tun.c
> index abe488bac50bb..7f118ba3ae0bb 100644
> --- a/tools/testing/selftests/net/tun.c
> +++ b/tools/testing/selftests/net/tun.c

[ ... ]

> @@ -985,4 +986,12 @@ XFAIL_ADD(tun_vnet_udptnl, 6in4_over_maxbytes, recv_gso_packet);
> XFAIL_ADD(tun_vnet_udptnl, 4in6_over_maxbytes, recv_gso_packet);
> XFAIL_ADD(tun_vnet_udptnl, 6in6_over_maxbytes, recv_gso_packet);
>
> -TEST_HARNESS_MAIN
> +int main(int argc, char **argv)
> +{
> +	if (unshare(CLONE_NEWNET) < 0) {
> +		perror("unshare(CLONE_NEWNET)");
> +		return 1;
> +	}
> +
> +	return test_harness_run(argc, argv);
> +}

[Severity: Medium]
Should an unshare() failure here be reported as FAIL for the whole binary?

Returning 1 from main() is KSFT_FAIL, and since test_harness_run() is never
reached, ksft_print_header() and ksft_set_plan() never run either, so the
binary emits no "TAP version 13" line, no "1..N" plan and no per-test result
lines at all.  Would a runner then be able to tell "network namespaces
unavailable" apart from a real tun/tap regression?

There appear to be two reachable ways to land in this path without any
actual tun/tap problem:

CONFIG_NET_NS=n, where the stub in include/net/net_namespace.h rejects the
flag outright:

  static inline struct net *copy_net_ns(u64 flags,
	struct user_namespace *user_ns, struct net *old_net)
  {
	if (flags & CLONE_NEWNET)
		return ERR_PTR(-EINVAL);
	return old_net;
  }

and running with CAP_NET_ADMIN but without CAP_SYS_ADMIN (for example a
container started with --cap-add=NET_ADMIN), where unshare(CLONE_NEWNET)
fails with EPERM.

In both cases the pre-existing tun fixture is aborted too, even though
FIXTURE_SETUP(tun) only does:

  self->fd = tun_alloc(self->ifname);
  ASSERT_GE(self->fd, 0);

which needs /dev/net/tun and CAP_NET_ADMIN, but no network namespace.  Was
losing that coverage intended?

Would returning KSFT_SKIP (4) fit the convention better here?  The precedent
named in the changelog, "This mirrors the approach used by
selftests/net/ipsec.c, which also unshares from main()", handles the same
failure differently in selftests/net/ipsec.c:main():

  if (init_namespaces())
	ksft_exit_skip("Failed to create namespaces\n");

Other harness call sites do the same, for example
selftests/arm64/gcs/gcs-locking.c:main():

  ksft_print_msg("GCS was enabled, test unsupported\n");
  return KSFT_SKIP;

and selftests/net/icmp_rfc4884.c keeps the unshare inside
FIXTURE_SETUP(rfc4884) so the failure stays attributable inside the TAP
stream:

  ret = unshare(CLONE_NEWNET);
  ASSERT_EQ(ret, 0) {
	TH_LOG("unshare(CLONE_NEWNET) failed: %s", strerror(errno));
  }

One more question on the changelog: the patch adds CAP_SYS_ADMIN in the
current user namespace and CONFIG_NET_NS as new prerequisites for the entire
binary.  Should that be mentioned in the commit message?

-- 
Sashiko AI review · https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20260905085318.3416670-1-edoardo.canepa%40canonical.com

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [PATCH net] selftests/net: run tun tests in a dedicated network namespace
  2026-09-10  0:56 ` netdev-bot+sashiko
@ 2026-09-11  0:28   ` Jakub Kicinski
  0 siblings, 0 replies; 3+ messages in thread
From: Jakub Kicinski @ 2026-09-11  0:28 UTC (permalink / raw)
  To: netdev-bot+sashiko
  Cc: edoardo.canepa, netdev, davem, edumazet, pabeni, horms, shuah,
	xudu, po-hsu.lin, linux-kselftest, linux-kernel

On Thu, 10 Sep 2026 00:56:15 +0000 netdev-bot+sashiko@kernel.org wrote:
> - [Medium] In the newly added main() in tools/testing/selftests/net/tun.c
>   (lines 989-997), any failure of unshare(CLONE_NEWNET) is treated as a…

Seems fair, at a glance it seems like we just need to add this code to
two setup functions instead of creating a real main().
-- 
pw-bot: cr

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2026-09-11  0:28 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-09-05  8:53 [PATCH net] selftests/net: run tun tests in a dedicated network namespace Edoardo Canepa
2026-09-10  0:56 ` netdev-bot+sashiko
2026-09-11  0:28   ` Jakub Kicinski

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®