patches and low-level development discussion
 help / color / mirror / code / Atom feed
From: Alyssa Ross <hi@alyssa.is>
To: devel@spectrum-os.org
Cc: Yureka Lilian <yureka@cyberchaos.dev>
Subject: [PATCH] release/checks/integration: fix race condition
Date: Thu, 18 Dec 2025 19:58:30 +0100	[thread overview]
Message-ID: <20251218185830.89957-1-hi@alyssa.is> (raw)

By default, IPv6 addresses are in the tentative state and can't be
bound to until the kernel has asychronously done Duplicate Address
Detection.  This was the cause of us needing to retry the bind, and
sometimes even that wasn't enough.  Since we're in a fresh network
namespace, we know there can't be a duplicate address, so we can add
the address with the IFA_F_NODAD flag to skip this and make the
address available for binding immediately.  We can't set that flag
using the ioctl interface we were using before, so switch to netlink.

This is slightly lazy netlink — we hardcode the index of the loopback
address, and don't bother with extended errors — but I think that's
fine for a test where readability is the most important thing.

I've run the test 100 times with this change and didn't see any bind
failures, which is a big improvement over the failure rate I was
seeing before.

Fixes: cdf1891e ("release/checks/integration: Adapt networking test for ipv6")
Signed-off-by: Alyssa Ross <hi@alyssa.is>
---
 release/checks/integration/networking.c | 89 +++++++++++++++++++------
 1 file changed, 70 insertions(+), 19 deletions(-)

diff --git a/release/checks/integration/networking.c b/release/checks/integration/networking.c
index 68f00b98..7d02f557 100644
--- a/release/checks/integration/networking.c
+++ b/release/checks/integration/networking.c
@@ -12,14 +12,14 @@
 #include <arpa/inet.h>
 #include <net/if.h>
 
-#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <linux/if_addr.h>
 #include <linux/ipv6.h>
+#include <linux/rtnetlink.h>
 
 static int setup_server(void)
 {
 	int fd;
-	struct ifreq ifr;
-	struct in6_ifreq ifr6;
 
 	struct sockaddr_in6 addr = {
 		.sin6_family = AF_INET6,
@@ -27,30 +27,83 @@ static int setup_server(void)
 		.sin6_addr = { .s6_addr = { 0xfd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02 } },
 	};
 
-	sprintf(ifr.ifr_name, "lo");
+	struct {
+		struct nlmsghdr nh;
+		struct ifaddrmsg ifa;
+		struct rtattr attr;
+		struct in6_addr addr;
+	} newaddr_req = {
+		{
+			.nlmsg_len = sizeof newaddr_req,
+			.nlmsg_type = RTM_NEWADDR,
+			.nlmsg_flags = NLM_F_ACK | NLM_F_REQUEST,
+		},
+		{
+			.ifa_family = AF_INET6,
+			.ifa_prefixlen = 128,
+			.ifa_flags = IFA_F_NODAD,
+			.ifa_index = 1,
+		},
+		{
+			.rta_len = sizeof newaddr_req.attr + sizeof newaddr_req.addr,
+			.rta_type = IFA_ADDRESS,
+		},
+		addr.sin6_addr,
+	};
 
-	ifr6.ifr6_ifindex = 1;
-	ifr6.ifr6_addr = addr.sin6_addr;
-	ifr6.ifr6_prefixlen = 128;
+	struct {
+		struct nlmsghdr nh;
+		struct ifinfomsg ifi;
+	} newlink_req = {
+		{
+			.nlmsg_len = sizeof newlink_req,
+			.nlmsg_type = RTM_NEWLINK,
+			.nlmsg_flags = NLM_F_ACK | NLM_F_REQUEST,
+		},
+		{
+			.ifi_index = 1,
+			.ifi_flags = IFF_UP,
+			.ifi_change = IFF_UP,
+		},
+	};
 
-	if ((fd = socket(AF_INET6, SOCK_STREAM|SOCK_CLOEXEC, 0)) == -1) {
+	struct {
+		struct nlmsghdr nh;
+		struct nlmsgerr err;
+	} res;
+
+	if ((fd = socket(AF_NETLINK, SOCK_DGRAM|SOCK_CLOEXEC, NETLINK_ROUTE)) == -1) {
 		perror("socket");
 		exit(EXIT_FAILURE);
 	}
 
-	if (ioctl(fd, SIOCGIFFLAGS, &ifr) == -1) {
-		perror("SIOCGIFFLAGS");
+	if (send(fd, &newaddr_req, sizeof newaddr_req, 0) == -1) {
+		perror("send");
 		exit(EXIT_FAILURE);
 	}
 
-	ifr.ifr_flags |= IFF_UP;
-	if (ioctl(fd, SIOCSIFFLAGS, &ifr) == -1) {
-		perror("SIOCSIFFLAGS");
+	if (recv(fd, &res, sizeof res, 0) == -1) {
+		perror("recv");
 		exit(EXIT_FAILURE);
 	}
 
-	if (ioctl(fd, SIOCSIFADDR, &ifr6) == -1) {
-		perror("SIOCSIFADDR");
+	if (res.err.error) {
+		fprintf(stderr, "RTM_NEWADDR: %s", strerror(-res.err.error));
+		exit(EXIT_FAILURE);
+	}
+
+	if (send(fd, &newlink_req, sizeof newlink_req, 0) == -1) {
+		perror("send");
+		exit(EXIT_FAILURE);
+	}
+
+	if (recv(fd, &res, sizeof res, 0) == -1) {
+		perror("recv");
+		exit(EXIT_FAILURE);
+	}
+
+	if (res.err.error) {
+		fprintf(stderr, "RTM_NEWLINK: %s", strerror(-res.err.error));
 		exit(EXIT_FAILURE);
 	}
 
@@ -61,11 +114,9 @@ static int setup_server(void)
 		exit(EXIT_FAILURE);
 	}
 
-	int tries = 0;
-	while (bind(fd, &addr, sizeof addr) == -1) {
+	if (bind(fd, &addr, sizeof addr) == -1) {
 		perror("bind");
-		if (tries++ >= 5)
-			exit(EXIT_FAILURE);
+		exit(EXIT_FAILURE);
 	}
 
 	if (listen(fd, 1) == -1) {

base-commit: 77f8d28f076b16a64faef83c5cf374995770ff70
-- 
2.51.0


             reply	other threads:[~2025-12-18 18:59 UTC|newest]

Thread overview: 2+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-12-18 18:58 Alyssa Ross [this message]
2026-01-15 15:53 ` [PATCH] release/checks/integration: fix race condition Alyssa Ross

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=20251218185830.89957-1-hi@alyssa.is \
    --to=hi@alyssa.is \
    --cc=devel@spectrum-os.org \
    --cc=yureka@cyberchaos.dev \
    /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.
Code repositories for project(s) associated with this public inbox

	https://spectrum-os.org/git/crosvm
	https://spectrum-os.org/git/doc
	https://spectrum-os.org/git/mktuntap
	https://spectrum-os.org/git/nixpkgs
	https://spectrum-os.org/git/spectrum
	https://spectrum-os.org/git/ucspi-vsock
	https://spectrum-os.org/git/www

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).