public inbox for passt-dev@passt.top
 help / color / mirror / code / Atom feed
From: David Gibson <david@gibson.dropbear.id.au>
To: Stefano Brivio <sbrivio@redhat.com>, passt-dev@passt.top
Cc: David Gibson <david@gibson.dropbear.id.au>
Subject: [PATCH v2 1/4] util: Split construction of bind socket address from the rest of sock_l4()
Date: Fri, 14 Jun 2024 11:51:05 +1000	[thread overview]
Message-ID: <20240614015108.2761502-2-david@gibson.dropbear.id.au> (raw)
In-Reply-To: <20240614015108.2761502-1-david@gibson.dropbear.id.au>

sock_l4() creates, binds and otherwise prepares a new socket.  It builds
the socket address to bind from separately provided address and port.
However, we have use cases coming up where it's more natural to construct
the socket address in the caller.

Prepare for this by adding sock_l4_sa() which takes a pre-constructed
socket address, and rewriting sock_l4() in terms of it.

Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
 util.c | 123 ++++++++++++++++++++++++++++++++-------------------------
 1 file changed, 70 insertions(+), 53 deletions(-)

diff --git a/util.c b/util.c
index 44461801..4e3d84a1 100644
--- a/util.c
+++ b/util.c
@@ -33,36 +33,25 @@
 #include "log.h"
 
 /**
- * sock_l4() - Create and bind socket for given L4, add to epoll list
+ * sock_l4_sa() - Create and bind socket to socket address, add to epoll list                                                         
  * @c:		Execution context
- * @af:		Address family, AF_INET or AF_INET6
  * @proto:	Protocol number
- * @bind_addr:	Address for binding, NULL for any
+ * @sa:		Socket address to bind to
+ * @sl:		Length of @sa
  * @ifname:	Interface for binding, NULL for any
- * @port:	Port, host order
+ * @v6only:	Set IPV6_V6ONLY socket option
  * @data:	epoll reference portion for protocol handlers
  *
  * Return: newly created socket, negative error code on failure
  */
-int sock_l4(const struct ctx *c, sa_family_t af, uint8_t proto,
-	    const void *bind_addr, const char *ifname, uint16_t port,
-	    uint32_t data)
+static int sock_l4_sa(const struct ctx *c, uint8_t proto,
+		      const void *sa, socklen_t sl,
+		      const char *ifname, bool v6only, uint32_t data)
 {
+	sa_family_t af = ((const struct sockaddr *)sa)->sa_family;
 	union epoll_ref ref = { .data = data };
-	struct sockaddr_in addr4 = {
-		.sin_family = AF_INET,
-		.sin_port = htons(port),
-		{ 0 }, { 0 },
-	};
-	struct sockaddr_in6 addr6 = {
-		.sin6_family = AF_INET6,
-		.sin6_port = htons(port),
-		0, IN6ADDR_ANY_INIT, 0,
-	};
-	const struct sockaddr *sa;
-	bool dual_stack = false;
-	int fd, sl, y = 1, ret;
 	struct epoll_event ev;
+	int fd, y = 1, ret;
 
 	switch (proto) {
 	case IPPROTO_TCP:
@@ -79,13 +68,6 @@ int sock_l4(const struct ctx *c, sa_family_t af, uint8_t proto,
 		return -EPFNOSUPPORT;	/* Not implemented. */
 	}
 
-	if (af == AF_UNSPEC) {
-		if (!DUAL_STACK_SOCKETS || bind_addr)
-			return -EINVAL;
-		dual_stack = true;
-		af = AF_INET6;
-	}
-
 	if (proto == IPPROTO_TCP)
 		fd = socket(af, SOCK_STREAM | SOCK_NONBLOCK, proto);
 	else
@@ -104,30 +86,9 @@ int sock_l4(const struct ctx *c, sa_family_t af, uint8_t proto,
 
 	ref.fd = fd;
 
-	if (af == AF_INET) {
-		if (bind_addr)
-			addr4.sin_addr = *(struct in_addr *)bind_addr;
-
-		sa = (const struct sockaddr *)&addr4;
-		sl = sizeof(addr4);
-	} else {
-		if (bind_addr) {
-			addr6.sin6_addr = *(struct in6_addr *)bind_addr;
-
-			if (!memcmp(bind_addr, &c->ip6.addr_ll,
-			    sizeof(c->ip6.addr_ll)))
-				addr6.sin6_scope_id = c->ifi6;
-		}
-
-		sa = (const struct sockaddr *)&addr6;
-		sl = sizeof(addr6);
-
-		if (!dual_stack)
-			if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY,
-				       &y, sizeof(y)))
-				debug("Failed to set IPV6_V6ONLY on socket %i",
-				      fd);
-	}
+	if (v6only)
+		if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &y, sizeof(y)))
+			debug("Failed to set IPV6_V6ONLY on socket %i", fd);
 
 	if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &y, sizeof(y)))
 		debug("Failed to set SO_REUSEADDR on socket %i", fd);
@@ -140,9 +101,12 @@ int sock_l4(const struct ctx *c, sa_family_t af, uint8_t proto,
 		 */
 		if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE,
 			       ifname, strlen(ifname))) {
+			char str[SOCKADDR_STRLEN];
+
 			ret = -errno;
-			warn("Can't bind %s socket for port %u to %s, closing",
-			     EPOLL_TYPE_STR(proto), port, ifname);
+			warn("Can't bind %s socket for %s to %s, closing",
+			     EPOLL_TYPE_STR(proto),
+			     sockaddr_ntop(sa, str, sizeof(str)), ifname);
 			close(fd);
 			return ret;
 		}
@@ -178,6 +142,59 @@ int sock_l4(const struct ctx *c, sa_family_t af, uint8_t proto,
 
 	return fd;
 }
+/**
+ * sock_l4() - Create and bind socket for given L4, add to epoll list
+ * @c:		Execution context
+ * @af:		Address family, AF_INET or AF_INET6
+ * @proto:	Protocol number
+ * @bind_addr:	Address for binding, NULL for any
+ * @ifname:	Interface for binding, NULL for any
+ * @port:	Port, host order
+ * @data:	epoll reference portion for protocol handlers
+ *
+ * Return: newly created socket, negative error code on failure
+ */
+int sock_l4(const struct ctx *c, sa_family_t af, uint8_t proto,
+	    const void *bind_addr, const char *ifname, uint16_t port,
+	    uint32_t data)
+{
+	switch (af) {
+	case AF_INET: {
+		struct sockaddr_in addr4 = {
+			.sin_family = AF_INET,
+			.sin_port = htons(port),
+			{ 0 }, { 0 },
+		};
+		if (bind_addr)
+			addr4.sin_addr = *(struct in_addr *)bind_addr;
+		return sock_l4_sa(c, proto, &addr4, sizeof(addr4), ifname,
+				  false, data);
+	}
+
+	case AF_UNSPEC:
+		if (!DUAL_STACK_SOCKETS || bind_addr)
+			 return -EINVAL;
+		/* fallthrough */
+	case AF_INET6: {
+		struct sockaddr_in6 addr6 = {
+			.sin6_family = AF_INET6,
+			.sin6_port = htons(port),
+			0, IN6ADDR_ANY_INIT, 0,
+		};
+		if (bind_addr) {
+			addr6.sin6_addr = *(struct in6_addr *)bind_addr;
+
+			if (!memcmp(bind_addr, &c->ip6.addr_ll,
+			    sizeof(c->ip6.addr_ll)))
+				addr6.sin6_scope_id = c->ifi6;
+		}
+		return sock_l4_sa(c, proto, &addr6, sizeof(addr6), ifname,
+				  af == AF_INET6, data);
+	}
+	default:
+		return -EINVAL;
+	}
+}
 
 /**
  * sock_probe_mem() - Check if setting high SO_SNDBUF and SO_RCVBUF is allowed
-- 
@@ -33,36 +33,25 @@
 #include "log.h"
 
 /**
- * sock_l4() - Create and bind socket for given L4, add to epoll list
+ * sock_l4_sa() - Create and bind socket to socket address, add to epoll list                                                         
  * @c:		Execution context
- * @af:		Address family, AF_INET or AF_INET6
  * @proto:	Protocol number
- * @bind_addr:	Address for binding, NULL for any
+ * @sa:		Socket address to bind to
+ * @sl:		Length of @sa
  * @ifname:	Interface for binding, NULL for any
- * @port:	Port, host order
+ * @v6only:	Set IPV6_V6ONLY socket option
  * @data:	epoll reference portion for protocol handlers
  *
  * Return: newly created socket, negative error code on failure
  */
-int sock_l4(const struct ctx *c, sa_family_t af, uint8_t proto,
-	    const void *bind_addr, const char *ifname, uint16_t port,
-	    uint32_t data)
+static int sock_l4_sa(const struct ctx *c, uint8_t proto,
+		      const void *sa, socklen_t sl,
+		      const char *ifname, bool v6only, uint32_t data)
 {
+	sa_family_t af = ((const struct sockaddr *)sa)->sa_family;
 	union epoll_ref ref = { .data = data };
-	struct sockaddr_in addr4 = {
-		.sin_family = AF_INET,
-		.sin_port = htons(port),
-		{ 0 }, { 0 },
-	};
-	struct sockaddr_in6 addr6 = {
-		.sin6_family = AF_INET6,
-		.sin6_port = htons(port),
-		0, IN6ADDR_ANY_INIT, 0,
-	};
-	const struct sockaddr *sa;
-	bool dual_stack = false;
-	int fd, sl, y = 1, ret;
 	struct epoll_event ev;
+	int fd, y = 1, ret;
 
 	switch (proto) {
 	case IPPROTO_TCP:
@@ -79,13 +68,6 @@ int sock_l4(const struct ctx *c, sa_family_t af, uint8_t proto,
 		return -EPFNOSUPPORT;	/* Not implemented. */
 	}
 
-	if (af == AF_UNSPEC) {
-		if (!DUAL_STACK_SOCKETS || bind_addr)
-			return -EINVAL;
-		dual_stack = true;
-		af = AF_INET6;
-	}
-
 	if (proto == IPPROTO_TCP)
 		fd = socket(af, SOCK_STREAM | SOCK_NONBLOCK, proto);
 	else
@@ -104,30 +86,9 @@ int sock_l4(const struct ctx *c, sa_family_t af, uint8_t proto,
 
 	ref.fd = fd;
 
-	if (af == AF_INET) {
-		if (bind_addr)
-			addr4.sin_addr = *(struct in_addr *)bind_addr;
-
-		sa = (const struct sockaddr *)&addr4;
-		sl = sizeof(addr4);
-	} else {
-		if (bind_addr) {
-			addr6.sin6_addr = *(struct in6_addr *)bind_addr;
-
-			if (!memcmp(bind_addr, &c->ip6.addr_ll,
-			    sizeof(c->ip6.addr_ll)))
-				addr6.sin6_scope_id = c->ifi6;
-		}
-
-		sa = (const struct sockaddr *)&addr6;
-		sl = sizeof(addr6);
-
-		if (!dual_stack)
-			if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY,
-				       &y, sizeof(y)))
-				debug("Failed to set IPV6_V6ONLY on socket %i",
-				      fd);
-	}
+	if (v6only)
+		if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &y, sizeof(y)))
+			debug("Failed to set IPV6_V6ONLY on socket %i", fd);
 
 	if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &y, sizeof(y)))
 		debug("Failed to set SO_REUSEADDR on socket %i", fd);
@@ -140,9 +101,12 @@ int sock_l4(const struct ctx *c, sa_family_t af, uint8_t proto,
 		 */
 		if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE,
 			       ifname, strlen(ifname))) {
+			char str[SOCKADDR_STRLEN];
+
 			ret = -errno;
-			warn("Can't bind %s socket for port %u to %s, closing",
-			     EPOLL_TYPE_STR(proto), port, ifname);
+			warn("Can't bind %s socket for %s to %s, closing",
+			     EPOLL_TYPE_STR(proto),
+			     sockaddr_ntop(sa, str, sizeof(str)), ifname);
 			close(fd);
 			return ret;
 		}
@@ -178,6 +142,59 @@ int sock_l4(const struct ctx *c, sa_family_t af, uint8_t proto,
 
 	return fd;
 }
+/**
+ * sock_l4() - Create and bind socket for given L4, add to epoll list
+ * @c:		Execution context
+ * @af:		Address family, AF_INET or AF_INET6
+ * @proto:	Protocol number
+ * @bind_addr:	Address for binding, NULL for any
+ * @ifname:	Interface for binding, NULL for any
+ * @port:	Port, host order
+ * @data:	epoll reference portion for protocol handlers
+ *
+ * Return: newly created socket, negative error code on failure
+ */
+int sock_l4(const struct ctx *c, sa_family_t af, uint8_t proto,
+	    const void *bind_addr, const char *ifname, uint16_t port,
+	    uint32_t data)
+{
+	switch (af) {
+	case AF_INET: {
+		struct sockaddr_in addr4 = {
+			.sin_family = AF_INET,
+			.sin_port = htons(port),
+			{ 0 }, { 0 },
+		};
+		if (bind_addr)
+			addr4.sin_addr = *(struct in_addr *)bind_addr;
+		return sock_l4_sa(c, proto, &addr4, sizeof(addr4), ifname,
+				  false, data);
+	}
+
+	case AF_UNSPEC:
+		if (!DUAL_STACK_SOCKETS || bind_addr)
+			 return -EINVAL;
+		/* fallthrough */
+	case AF_INET6: {
+		struct sockaddr_in6 addr6 = {
+			.sin6_family = AF_INET6,
+			.sin6_port = htons(port),
+			0, IN6ADDR_ANY_INIT, 0,
+		};
+		if (bind_addr) {
+			addr6.sin6_addr = *(struct in6_addr *)bind_addr;
+
+			if (!memcmp(bind_addr, &c->ip6.addr_ll,
+			    sizeof(c->ip6.addr_ll)))
+				addr6.sin6_scope_id = c->ifi6;
+		}
+		return sock_l4_sa(c, proto, &addr6, sizeof(addr6), ifname,
+				  af == AF_INET6, data);
+	}
+	default:
+		return -EINVAL;
+	}
+}
 
 /**
  * sock_probe_mem() - Check if setting high SO_SNDBUF and SO_RCVBUF is allowed
-- 
2.45.2


  reply	other threads:[~2024-06-14  1:51 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-06-14  1:51 [PATCH v2 0/4] Even more flow table preliminaries David Gibson
2024-06-14  1:51 ` David Gibson [this message]
2024-06-14  1:51 ` [PATCH v2 2/4] udp: Fold checking of splice flag into udp_mmh_splice_port() David Gibson
2024-06-14  1:51 ` [PATCH v2 3/4] udp: Rework how we divide queued datagrams between sending methods David Gibson
2024-06-14  1:51 ` [PATCH v2 4/4] udp: Move management of udp[46]_localname into udp_splice_send() David Gibson
2024-06-14 11:14 ` [PATCH v2 0/4] Even 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=20240614015108.2761502-2-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).