MINOR: quic: startup detect for quic-conn owned socket support
To be able to use individual sockets for QUIC connections, we rely on
the OS network stack which must support UDP sockets binding on the same
local address.
Add a detection code for this feature executed on startup. When the
first QUIC listener socket is binded, a test socket is created and
binded on the same address. If the bind call fails, we consider that
it's impossible to use individual socket for QUIC connections.
A new global option GTUNE_QUIC_SOCK_PER_CONN is defined. If startup
detect fails, this value is resetted from global options. For the
moment, there is no code to activate the option : this will be in a
follow-up patch with the introduction of a new configuration option.
This change is part of quic-conn owned socket implementation.
It may be backported to 2.7 after a period of observation.
diff --git a/include/haproxy/global-t.h b/include/haproxy/global-t.h
index 0cdb361..2e9b61b 100644
--- a/include/haproxy/global-t.h
+++ b/include/haproxy/global-t.h
@@ -78,6 +78,7 @@
#define GTUNE_DISABLE_H2_WEBSOCKET (1<<21)
#define GTUNE_DISABLE_ACTIVE_CLOSE (1<<22)
#define GTUNE_QUICK_EXIT (1<<23)
+#define GTUNE_QUIC_SOCK_PER_CONN (1<<24)
/* SSL server verify mode */
enum {
diff --git a/src/proto_quic.c b/src/proto_quic.c
index 7267b67..003e510 100644
--- a/src/proto_quic.c
+++ b/src/proto_quic.c
@@ -570,6 +570,40 @@
return 0;
}
+/* Check if platform supports the required feature set for quic-conn owned
+ * socket. <l> listener must already be binded; a dummy socket will be opened
+ * on the same address as one of the support test.
+ *
+ * Returns true if platform is deemed compatible else false.
+ */
+static int quic_test_sock_per_conn_support(struct listener *l)
+{
+ const struct receiver *rx = &l->rx;
+ int ret = 1, fdtest;
+
+ /* Check if platform support multiple UDP sockets bind on the same
+ * local address. Create a dummy socket and bind it on the same address
+ * as <l> listener. If bind system call fails, deactivate socket per
+ * connection. All other errors are not taken into account.
+ */
+ if (ret) {
+ fdtest = socket(rx->proto->fam->sock_domain,
+ rx->proto->sock_type, rx->proto->sock_prot);
+ if (fdtest > 0) {
+ if (setsockopt(fdtest, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)) &&
+ bind(fdtest, (struct sockaddr *)&rx->addr, rx->proto->fam->sock_addrlen) < 0) {
+ ha_alert("Your platform does not seem to support multiple UDP sockets binded on the same address. "
+ "QUIC connections will use listener socket.\n");
+ ret = 0;
+ }
+
+ close(fdtest);
+ }
+ }
+
+ return ret;
+}
+
/* This function tries to bind a QUIC4/6 listener. It may return a warning or
* an error message in <errmsg> if the message is at most <errlen> bytes long
* (including '\0'). Note that <errmsg> may be NULL if <errlen> is also zero.
@@ -626,6 +660,11 @@
goto udp_return;
}
+ if (global.tune.options & GTUNE_QUIC_SOCK_PER_CONN) {
+ if (!quic_test_sock_per_conn_support(listener))
+ global.tune.options &= ~GTUNE_QUIC_SOCK_PER_CONN;
+ }
+
listener_set_state(listener, LI_LISTEN);
udp_return: