From 5bddf39fb2b90f56ff3255bbc6515e898fde2360 Mon Sep 17 00:00:00 2001 From: Amaury Denoyelle Date: Wed, 26 Jun 2024 17:09:08 +0200 Subject: [PATCH] MINOR: quic: extend detection of UDP API OS features QUIC haproxy implementation relies on specific OS features to activate some UDP optimization. One of these is the ability to bind multiple sockets on the same address, which is necessary to have a dedicated socket for each QUIC connections. This feature support is tested during startup via an internal proto-quic function. It automatically deactivate socket per connection if OS is not compatible. The purpose of this patch is to render this QUIC feature detection code more generic. Function is renamed quic_test_socketopts() and is still invoked on startup. Its internal code has been refactored to be able to implement other features support test in it. Return value has also been changed and is now taken into account. In case of ERR_FATAL, haproxy startup will be interrupted. This happens on socket() syscall failure used to duplicate a QUIC listener FD. This commit will become necessary to detect GSO support on startup. --- src/proto_quic.c | 67 ++++++++++++++++++++++++------------------------ 1 file changed, 34 insertions(+), 33 deletions(-) diff --git a/src/proto_quic.c b/src/proto_quic.c index 0899cd9709..2e5ad64804 100644 --- a/src/proto_quic.c +++ b/src/proto_quic.c @@ -517,47 +517,50 @@ static int quic_alloc_rxbufs_listener(struct listener *l) return 0; } -/* Check if platform supports the required feature set for quic-conn owned - * socket. 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. +/* Check for platform support of a set of advanced UDP network API features + * used by haproxy QUIC stack. Automatically disable unsupported features. + * Listener serves to test the ability of binding multiple sockets on the + * same address. */ -static int quic_test_sock_per_conn_support(struct listener *l) +static int quic_test_socketopts(struct listener *l) { const struct receiver *rx = &l->rx; - int ret = 1, fdtest; + int fdtest = -1; /* Check if IP destination address can be retrieved on recvfrom() * operation. */ -#if !defined(IP_PKTINFO) && !defined(IP_RECVDSTADDR) - ha_alert("Your platform does not seem to support UDP source address retrieval through IP_PKTINFO or an alternative flag. " - "QUIC connections will use listener socket.\n"); - ret = 0; -#endif - - /* 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 listener. If bind system call fails, deactivate socket per - * connection. All other errors are not taken into account. - */ - if (ret) { + if (global.tune.options & GTUNE_QUIC_SOCK_PER_CONN) { 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; - } + rx->proto->sock_type, rx->proto->sock_prot); + if (fdtest < 0) + goto err; - close(fdtest); +#if defined(IP_PKTINFO) || defined(IP_RECVDSTADDR) + /* 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 listener. If bind system call fails, deactivate socket per + * connection. All other errors are not taken into account. + */ + 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"); + global.tune.options &= ~GTUNE_QUIC_SOCK_PER_CONN; } +#else + ha_alert("Your platform does not seem to support UDP source address retrieval through IP_PKTINFO or an alternative flag. " + "QUIC connections will use listener socket.\n"); + global.tune.options &= ~GTUNE_QUIC_SOCK_PER_CONN; +#endif } - return ret; + close(fdtest); + return ERR_NONE; + + err: + ha_alert("Fatal error on quic_test_sockopts(): %s.\n", strerror(errno)); + return ERR_FATAL; } /* This function tries to bind a QUIC4/6 listener. It may return a warning or @@ -621,10 +624,8 @@ static int quic_bind_listener(struct listener *listener, char *errmsg, int errle 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; - } + if (quic_test_socketopts(listener)) + return ERR_FATAL; if (global.tune.frontend_rcvbuf) setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &global.tune.frontend_rcvbuf, sizeof(global.tune.frontend_rcvbuf));