public inbox for passt-dev@passt.top
 help / color / mirror / code / Atom feed
From: David Gibson <david@gibson.dropbear.id.au>
To: passt-dev@passt.top, Stefano Brivio <sbrivio@redhat.com>
Cc: David Gibson <david@gibson.dropbear.id.au>
Subject: [PATCH 5/6] doc: Test behaviour of closing duplicate UDP sockets
Date: Wed, 17 Jul 2024 14:52:22 +1000	[thread overview]
Message-ID: <20240717045223.2309975-6-david@gibson.dropbear.id.au> (raw)
In-Reply-To: <20240717045223.2309975-1-david@gibson.dropbear.id.au>

To simplify lifetime management of "listening" UDP sockets, UDP flow
support needs to duplicate existing bound sockets.  Those duplicates will
be close()d when their corresponding flow expires, but we expect the
original to still receive datagrams as always.  That is, we expect the
close() on the duplicate to remove the duplicated fd, but not to close the
underlying UDP socket.

Add a test program to doc/platform-requirements to verify this requirement.

Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
 doc/platform-requirements/.gitignore      |   1 +
 doc/platform-requirements/Makefile        |   4 +-
 doc/platform-requirements/udp-close-dup.c | 105 ++++++++++++++++++++++
 3 files changed, 108 insertions(+), 2 deletions(-)
 create mode 100644 doc/platform-requirements/udp-close-dup.c

diff --git a/doc/platform-requirements/.gitignore b/doc/platform-requirements/.gitignore
index 555031d8..3b5a10ac 100644
--- a/doc/platform-requirements/.gitignore
+++ b/doc/platform-requirements/.gitignore
@@ -1,2 +1,3 @@
 /reuseaddr-priority
 /recv-zero
+/udp-close-dup
diff --git a/doc/platform-requirements/Makefile b/doc/platform-requirements/Makefile
index 82aaac29..6a7d3748 100644
--- a/doc/platform-requirements/Makefile
+++ b/doc/platform-requirements/Makefile
@@ -3,8 +3,8 @@
 # Copyright Red Hat
 # Author: David Gibson <david@gibson.dropbear.id.au>
 
-TARGETS = reuseaddr-priority recv-zero
-SRCS = reuseaddr-priority.c recv-zero.c
+TARGETS = reuseaddr-priority recv-zero udp-close-dup
+SRCS = reuseaddr-priority.c recv-zero.c udp-close-dup.c
 CFLAGS = -Wall
 
 all: cppcheck clang-tidy $(TARGETS:%=check-%)
diff --git a/doc/platform-requirements/udp-close-dup.c b/doc/platform-requirements/udp-close-dup.c
new file mode 100644
index 00000000..99060fcb
--- /dev/null
+++ b/doc/platform-requirements/udp-close-dup.c
@@ -0,0 +1,105 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+/* udp-close-dup.c
+ *
+ * Verify that closing one dup() of a UDP socket won't stop other dups from
+ * receiving packets.
+ *
+ * Copyright Red Hat
+ * Author: David Gibson <david@gibson.dropbear.id.au>
+ */
+
+#include <arpa/inet.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "common.h"
+
+#define DSTPORT	13257U
+
+/* 127.0.0.1:DSTPORT */
+static const struct sockaddr_in lo_dst = SOCKADDR_INIT(INADDR_LOOPBACK, DSTPORT);
+
+enum dup_method {
+	DUP_DUP,
+	DUP_FCNTL,
+	NUM_METHODS,
+};
+
+static void test_close_dup(enum dup_method method)
+{
+	long token;
+	int s1, s2, send_s;
+	ssize_t rc;
+
+	s1 = sock_reuseaddr();
+	if (bind(s1, (struct sockaddr *)&lo_dst, sizeof(lo_dst)) < 0)
+		die("bind(): %s\n", strerror(errno));
+
+	send_s = sock_reuseaddr();
+	if (connect(send_s, (struct sockaddr *)&lo_dst, sizeof(lo_dst)) < 0)
+		die("connect(): %s\n", strerror(errno));
+
+	/* Receive before duplicating */
+	token = random();
+	send_token(send_s, token);
+	recv_token(s1, token);
+
+	switch (method) {
+	case DUP_DUP:
+		/* NOLINTNEXTLINE(android-cloexec-dup) */
+		s2 = dup(s1);
+		if (s2 < 0)
+			die("dup(): %s\n", strerror(errno));
+		break;
+	case DUP_FCNTL:
+		s2 = fcntl(s1, F_DUPFD_CLOEXEC, 0);
+		if (s2 < 0)
+			die("F_DUPFD_CLOEXEC: %s\n", strerror(errno));
+		break;
+	default:
+		die("Bad method\n");
+	}
+
+	/* Receive via original handle */
+	token = random();
+	send_token(send_s, token);
+	recv_token(s1, token);
+
+	/* Receive via duplicated handle */
+	token = random();
+	send_token(send_s, token);
+	recv_token(s2, token);
+
+	/* Close duplicate */
+	rc = close(s2);
+	if (rc < 0)
+		die("close() dup: %s\n", strerror(errno));
+
+	/* Receive after closing duplicate */
+	token = random();
+	send_token(send_s, token);
+	recv_token(s1, token);
+}
+
+int main(int argc, char *argv[])
+{
+	enum dup_method method;
+
+	(void)argc;
+	(void)argv;
+
+	for (method = 0; method < NUM_METHODS; method++)
+		test_close_dup(method);
+
+	printf("Closing dup()ed UDP sockets seems to work as expected\n");
+
+	exit(0);
+}
-- 
@@ -0,0 +1,105 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+/* udp-close-dup.c
+ *
+ * Verify that closing one dup() of a UDP socket won't stop other dups from
+ * receiving packets.
+ *
+ * Copyright Red Hat
+ * Author: David Gibson <david@gibson.dropbear.id.au>
+ */
+
+#include <arpa/inet.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "common.h"
+
+#define DSTPORT	13257U
+
+/* 127.0.0.1:DSTPORT */
+static const struct sockaddr_in lo_dst = SOCKADDR_INIT(INADDR_LOOPBACK, DSTPORT);
+
+enum dup_method {
+	DUP_DUP,
+	DUP_FCNTL,
+	NUM_METHODS,
+};
+
+static void test_close_dup(enum dup_method method)
+{
+	long token;
+	int s1, s2, send_s;
+	ssize_t rc;
+
+	s1 = sock_reuseaddr();
+	if (bind(s1, (struct sockaddr *)&lo_dst, sizeof(lo_dst)) < 0)
+		die("bind(): %s\n", strerror(errno));
+
+	send_s = sock_reuseaddr();
+	if (connect(send_s, (struct sockaddr *)&lo_dst, sizeof(lo_dst)) < 0)
+		die("connect(): %s\n", strerror(errno));
+
+	/* Receive before duplicating */
+	token = random();
+	send_token(send_s, token);
+	recv_token(s1, token);
+
+	switch (method) {
+	case DUP_DUP:
+		/* NOLINTNEXTLINE(android-cloexec-dup) */
+		s2 = dup(s1);
+		if (s2 < 0)
+			die("dup(): %s\n", strerror(errno));
+		break;
+	case DUP_FCNTL:
+		s2 = fcntl(s1, F_DUPFD_CLOEXEC, 0);
+		if (s2 < 0)
+			die("F_DUPFD_CLOEXEC: %s\n", strerror(errno));
+		break;
+	default:
+		die("Bad method\n");
+	}
+
+	/* Receive via original handle */
+	token = random();
+	send_token(send_s, token);
+	recv_token(s1, token);
+
+	/* Receive via duplicated handle */
+	token = random();
+	send_token(send_s, token);
+	recv_token(s2, token);
+
+	/* Close duplicate */
+	rc = close(s2);
+	if (rc < 0)
+		die("close() dup: %s\n", strerror(errno));
+
+	/* Receive after closing duplicate */
+	token = random();
+	send_token(send_s, token);
+	recv_token(s1, token);
+}
+
+int main(int argc, char *argv[])
+{
+	enum dup_method method;
+
+	(void)argc;
+	(void)argv;
+
+	for (method = 0; method < NUM_METHODS; method++)
+		test_close_dup(method);
+
+	printf("Closing dup()ed UDP sockets seems to work as expected\n");
+
+	exit(0);
+}
-- 
2.45.2


  parent reply	other threads:[~2024-07-17  4:52 UTC|newest]

Thread overview: 14+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-07-17  4:52 [PATCH 0/6] Of course there are more flow table preliminaries David Gibson
2024-07-17  4:52 ` [PATCH 1/6] flow, icmp, tcp: Clean up helpers for getting flow from index David Gibson
2024-07-17  4:52 ` [PATCH 2/6] flow, tcp_splice: Prefer 'sidei' for variables referring to side index David Gibson
2024-07-17  5:20   ` Stefano Brivio
2024-07-17  5:28     ` David Gibson
2024-07-17  5:50       ` David Gibson
2024-07-17  7:20         ` Stefano Brivio
2024-07-17  7:27           ` David Gibson
2024-07-17  4:52 ` [PATCH 3/6] flow: Introduce flow_foreach_sidei() macro David Gibson
2024-07-17  4:52 ` [PATCH 4/6] tcp_splice: Use parameterised macros for per-side event/flag bits David Gibson
2024-07-17  4:52 ` David Gibson [this message]
2024-07-17  4:52 ` [PATCH 6/6] doc: Extend zero-recv test with methods using msghdr David Gibson
2024-07-17 15:06   ` Stefano Brivio
2024-07-17 15:07 ` [PATCH 0/6] Of course there are more flow table preliminaries Stefano Brivio

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=20240717045223.2309975-6-david@gibson.dropbear.id.au \
    --to=david@gibson.dropbear.id.au \
    --cc=passt-dev@passt.top \
    --cc=sbrivio@redhat.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.
Code repositories for project(s) associated with this public inbox

	https://passt.top/passt

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 IMAP folder(s).