patches and low-level development discussion
 help / color / mirror / code / Atom feed
* [PATCH] release/checks/integration: fix race condition
@ 2025-12-18 18:58 Alyssa Ross
  2026-01-15 15:53 ` Alyssa Ross
  0 siblings, 1 reply; 2+ messages in thread
From: Alyssa Ross @ 2025-12-18 18:58 UTC (permalink / raw)
  To: devel; +Cc: Yureka Lilian

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


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

end of thread, other threads:[~2026-01-15 15:53 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-12-18 18:58 [PATCH] release/checks/integration: fix race condition Alyssa Ross
2026-01-15 15:53 ` Alyssa Ross

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).