mirror of
http://git.haproxy.org/git/haproxy.git/
synced 2025-02-12 16:37:20 +00:00
MINOR: quic: convert startup check in a freestanding function
quic_test_socketopts() function is used to detect system support for QUIC network stack. Previously, it relies on an already bound listener instance, notably to ensure that two UDP sockets can be bound on the same source address. Improve quic_test_socketopts() to run without any listener argument. It now automatically instantiates and manipulates two dummy sockets FDs to check for multi-bind support. This brings two advantages : * the function is now called via an initcall * it will easily be reusable to implement build option description
This commit is contained in:
parent
d4f6f2df5e
commit
e7fd458c14
163
src/proto_quic.c
163
src/proto_quic.c
@ -516,75 +516,6 @@ static int quic_alloc_rxbufs_listener(struct listener *l)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Check for platform support of a set of advanced UDP network API features
|
||||
* used by haproxy QUIC stack. Automatically disable unsupported features.
|
||||
* Listener <l> serves to test the ability of binding multiple sockets on the
|
||||
* same address.
|
||||
*/
|
||||
static int quic_test_socketopts(struct listener *l)
|
||||
{
|
||||
const struct receiver *rx = &l->rx;
|
||||
int fdtest = -1;
|
||||
|
||||
/* Check if IP destination address can be retrieved on recvfrom()
|
||||
* operation.
|
||||
*/
|
||||
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)
|
||||
goto err;
|
||||
|
||||
#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 <l> 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_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;
|
||||
}
|
||||
#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) {
|
||||
fdtest = socket(rx->proto->fam->sock_domain,
|
||||
rx->proto->sock_type, rx->proto->sock_prot);
|
||||
if (fdtest < 0)
|
||||
goto err;
|
||||
}
|
||||
|
||||
#ifdef UDP_SEGMENT
|
||||
if (setsockopt(fdtest, SOL_UDP, UDP_SEGMENT, &zero, sizeof(zero))) {
|
||||
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
|
||||
}
|
||||
|
||||
if (fdtest >= 0)
|
||||
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
|
||||
* 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.
|
||||
@ -646,9 +577,6 @@ static int quic_bind_listener(struct listener *listener, char *errmsg, int errle
|
||||
goto udp_return;
|
||||
}
|
||||
|
||||
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));
|
||||
|
||||
@ -774,6 +702,97 @@ static int quic_deallocate_dghdlrs(void)
|
||||
}
|
||||
REGISTER_POST_DEINIT(quic_deallocate_dghdlrs);
|
||||
|
||||
/* 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
|
||||
* mode.
|
||||
*
|
||||
* Returns ERR_NONE if every checks performed, wether or not some features are
|
||||
* not available. ERR_FATAL is reported if checks cannot be executed.
|
||||
*/
|
||||
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;
|
||||
|
||||
/* Check if IP destination address can be retrieved on recvfrom()
|
||||
* operation.
|
||||
*/
|
||||
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)
|
||||
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. "
|
||||
"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)
|
||||
goto err;
|
||||
|
||||
#ifdef UDP_SEGMENT
|
||||
if (setsockopt(fdtest[0], SOL_UDP, UDP_SEGMENT, &zero, sizeof(zero))) {
|
||||
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);
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
* c-indent-level: 8
|
||||
|
Loading…
Reference in New Issue
Block a user