From: Amaury Denoyelle Date: Thu, 5 Dec 2024 14:35:36 +0000 (+0100) Subject: MINOR: quic: split startup check function X-Git-Tag: v3.2-dev1~29 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=cab2cc15c1a3070fd8d900aaf7f0bb6508d1210f;p=thirdparty%2Fhaproxy.git MINOR: quic: split startup check function Two features are tested on startup via quic_test_socketopts() : connection socket-owner mode support and GSO. Extract both test in their separated functions called by quic_test_socketopts(). This patch will allow to reuse easily QUIC features detection for build options report via haproxy -vv. --- diff --git a/src/proto_quic.c b/src/proto_quic.c index 28f3ecc133..61abda542d 100644 --- a/src/proto_quic.c +++ b/src/proto_quic.c @@ -702,6 +702,93 @@ static int quic_deallocate_dghdlrs(void) } REGISTER_POST_DEINIT(quic_deallocate_dghdlrs); +/* Checks that connection socket-owner mode is supported. + * Returns 1 if it is, 0 if not. A negative error code is used for an unknown + * error which leaves support status as unknown. + */ +static int quic_test_conn_socket_owner(void) +{ + int fdtest[2] = { -1, -1 }; + struct sockaddr_in lo_addr; + socklen_t addrlen __maybe_unused = sizeof(lo_addr); + int i, ret = 1; + + lo_addr.sin_family = AF_INET; + lo_addr.sin_addr.s_addr = ntohl(INADDR_LOOPBACK); + lo_addr.sin_port = 0; + + if ((fdtest[0] = socket(AF_INET, SOCK_DGRAM, 0)) < 0 || + (fdtest[1] = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { + ret = -1; + goto end; + } + + /* Connection socket-owner mode relies on several system features : + * - IP_PKTINFO or equivalent, to retrieve peer address for connect() + * - support for multiple UDP sockets bound on the same source address + */ + +#if defined(IP_PKTINFO) || defined(IP_RECVDSTADDR) + /* Bind first UDP socket on a random source port for loopback address. */ + if (setsockopt(fdtest[0], SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)) || + bind(fdtest[0], (struct sockaddr *)&lo_addr, sizeof(lo_addr))) { + ret = 0; + goto end; + } + + /* Retrieve bound port to reuse it for the second UDP socket. */ + if (getsockname(fdtest[0], (struct sockaddr *)&lo_addr, &addrlen)) { + ret = -1; + goto end; + } + + /* Bind second UDP socket on the same port as the first socket. */ + if (setsockopt(fdtest[1], SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)) || + bind(fdtest[1], (struct sockaddr *)&lo_addr, sizeof(lo_addr))) { + ret = 0; + goto end; + } +#else + ret = 0; + goto end; +#endif + + end: + for (i = 0; i <= 1; ++i) { + if (fdtest[i] >= 0) + close(fdtest[i]); + } + + return ret; +} + +/* Returns 1 if GSO is supported, 0 if not, or a negative error code if unknown. */ +static int quic_test_gso(void) +{ + int fdtest = -1; + int ret = 1; + + if ((fdtest = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { + ret = -1; + goto end; + } + +#ifdef UDP_SEGMENT + if (setsockopt(fdtest, SOL_UDP, UDP_SEGMENT, &zero, sizeof(zero))) { + ret = 0; + goto end; + } +#else + ret = 0; + goto end; +#endif + + end: + if (fdtest >= 0) + close(fdtest); + return ret; +} + /* Check for platform support of every advanced UDP network API features used * by the QUIC stack. For every unsupported feature, switch to a fallback * mechanism. A message is notified in this case when running in diagnostic @@ -712,86 +799,41 @@ REGISTER_POST_DEINIT(quic_deallocate_dghdlrs); */ static int quic_test_socketopts(void) { - int fdtest[2] = { -1, -1 }; - struct sockaddr_in lo_addr; - socklen_t addrlen; - int i; - - lo_addr.sin_family = AF_INET; - lo_addr.sin_addr.s_addr = INADDR_LOOPBACK; - lo_addr.sin_port = 0; + int ret; - /* Check if IP destination address can be retrieved on recvfrom() - * operation. - */ + /* Check for connection socket-owner mode support. */ if (global.tune.options & GTUNE_QUIC_SOCK_PER_CONN) { - if ((fdtest[0] = socket(AF_INET, SOCK_DGRAM, 0)) < 0) - goto err; - if ((fdtest[1] = socket(AF_INET, SOCK_DGRAM, 0)) < 0) + ret = quic_test_conn_socket_owner(); + if (ret < 0) { goto err; - -#if defined(IP_PKTINFO) || defined(IP_RECVDSTADDR) - /* Bind first UDP socket on a random source port for loopback address. */ - if (setsockopt(fdtest[0], SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)) || - bind(fdtest[0], (struct sockaddr *)&lo_addr, sizeof(lo_addr))) { - ha_diag_warning("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; } - - /* Retrieve bound port to reuse it for the second UDP socket. */ - if (getsockname(fdtest[0], (struct sockaddr *)&lo_addr, &addrlen)) - goto err; - - /* Bind second UDP socket on the same port as the first socket. */ - if (setsockopt(fdtest[1], SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)) || - bind(fdtest[1], (struct sockaddr *)&lo_addr, sizeof(lo_addr)) < 0) { - ha_diag_warning("Your platform does not seem to support multiple UDP sockets binded on the same address. " + else if (!ret) { + ha_diag_warning("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; } -#else - ha_diag_warning("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 } /* Check for UDP GSO support. */ if (!(global.tune.options & GTUNE_QUIC_NO_UDP_GSO)) { - if (fdtest[0] < 0 && (fdtest[0] = socket(AF_INET, SOCK_DGRAM, 0)) < 0) + ret = quic_test_gso(); + if (ret < 0) { goto err; - -#ifdef UDP_SEGMENT - if (setsockopt(fdtest[0], SOL_UDP, UDP_SEGMENT, &zero, sizeof(zero))) { + } + else if (!ret) { ha_diag_warning("Your platform does not support UDP GSO. " "This will be automatically disabled for QUIC transfer.\n"); global.tune.options |= GTUNE_QUIC_NO_UDP_GSO; } -#else - ha_diag_warning("Your platform does not support UDP GSO. " - "This will be automatically disabled for QUIC transfer.\n"); - global.tune.options |= GTUNE_QUIC_NO_UDP_GSO; -#endif - } - - for (i = 0; i <= 1; ++i) { - if (fdtest[i] >= 0) - close(fdtest[i]); } return ERR_NONE; err: - for (i = 0; i <= 1; ++i) { - if (fdtest[i] >= 0) - close(fdtest[i]); - } - ha_alert("Fatal error on %s(): %s.\n", __func__, strerror(errno)); return ERR_FATAL; } -INITCALL0(STG_REGISTER, quic_test_socketopts); +REGISTER_POST_CHECK(quic_test_socketopts); /* * Local variables: