MINOR: protocol: move the global reuseport flag to the protocols

Some protocol support SO_REUSEPORT and others not. Some have such a
limitation in the kernel, and others in haproxy itself (e.g. sock_unix
cannot support multiple bindings since each one will unbind the previous
one). Also it's really protocol-dependent and not just family-dependent
because on Linux for some time it was supported for TCP and not UDP.

Let's move the definition to the protocols instead. Now it's preset in
tcp/udp/quic when SO_REUSEPORT is defined, and is otherwise left unset.
The enabled() config condition test validates IPv4 (generally sufficient),
and -dR / noreuseport all protocols at once.
This commit is contained in:
Willy Tarreau 2023-04-22 15:09:07 +02:00
parent 65df7e028d
commit 785b89f551
9 changed files with 29 additions and 9 deletions

View File

@ -58,7 +58,7 @@
/* platform-specific options */ /* platform-specific options */
#define GTUNE_USE_SPLICE (1<<4) #define GTUNE_USE_SPLICE (1<<4)
#define GTUNE_USE_GAI (1<<5) #define GTUNE_USE_GAI (1<<5)
#define GTUNE_USE_REUSEPORT (1<<6) /* unused: (1<<6) */
#define GTUNE_RESOLVE_DONTFAIL (1<<7) #define GTUNE_RESOLVE_DONTFAIL (1<<7)
#define GTUNE_SOCKET_TRANSFER (1<<8) #define GTUNE_SOCKET_TRANSFER (1<<8)

View File

@ -64,6 +64,9 @@ enum proto_type {
#define CONNECT_DELACK_ALWAYS 0x00000004 /* Use a delayed ACK */ #define CONNECT_DELACK_ALWAYS 0x00000004 /* Use a delayed ACK */
#define CONNECT_CAN_USE_TFO 0x00000008 /* We can use TFO for this connection */ #define CONNECT_CAN_USE_TFO 0x00000008 /* We can use TFO for this connection */
/* Flags for protocol->flags */
#define PROTO_F_REUSEPORT_SUPPORTED 0x00000001 /* SO_REUSEPORT is supported */
/* protocol families define standard functions acting on a given address family /* protocol families define standard functions acting on a given address family
* for a socket implementation, such as AF_INET/PF_INET for example. * for a socket implementation, such as AF_INET/PF_INET for example.
*/ */

View File

@ -14,6 +14,7 @@
#include <haproxy/arg.h> #include <haproxy/arg.h>
#include <haproxy/cfgcond.h> #include <haproxy/cfgcond.h>
#include <haproxy/global.h> #include <haproxy/global.h>
#include <haproxy/proto_tcp.h>
#include <haproxy/tools.h> #include <haproxy/tools.h>
/* supported condition predicates */ /* supported condition predicates */
@ -195,7 +196,7 @@ static int cfg_eval_cond_enabled(const char *str)
else if (strcmp(str, "GETADDRINFO") == 0) else if (strcmp(str, "GETADDRINFO") == 0)
return !!(global.tune.options & GTUNE_USE_GAI); return !!(global.tune.options & GTUNE_USE_GAI);
else if (strcmp(str, "REUSEPORT") == 0) else if (strcmp(str, "REUSEPORT") == 0)
return !!(global.tune.options & GTUNE_USE_REUSEPORT); return !!(proto_tcpv4.flags & PROTO_F_REUSEPORT_SUPPORTED);
else if (strcmp(str, "FAST-FORWARD") == 0) else if (strcmp(str, "FAST-FORWARD") == 0)
return !!(global.tune.options & GTUNE_USE_FAST_FWD); return !!(global.tune.options & GTUNE_USE_FAST_FWD);
else if (strcmp(str, "SERVER-SSL-VERIFY-NONE") == 0) else if (strcmp(str, "SERVER-SSL-VERIFY-NONE") == 0)

View File

@ -20,6 +20,7 @@
#include <haproxy/global.h> #include <haproxy/global.h>
#include <haproxy/log.h> #include <haproxy/log.h>
#include <haproxy/peers.h> #include <haproxy/peers.h>
#include <haproxy/protocol.h>
#include <haproxy/tools.h> #include <haproxy/tools.h>
/* some keywords that are still being parsed using strcmp() and are not /* some keywords that are still being parsed using strcmp() and are not
@ -171,7 +172,7 @@ int cfg_parse_global(const char *file, int linenum, char **args, int kwm)
else if (strcmp(args[0], "noreuseport") == 0) { else if (strcmp(args[0], "noreuseport") == 0) {
if (alertif_too_many_args(0, file, linenum, args, &err_code)) if (alertif_too_many_args(0, file, linenum, args, &err_code))
goto out; goto out;
global.tune.options &= ~GTUNE_USE_REUSEPORT; protocol_clrf_all(PROTO_F_REUSEPORT_SUPPORTED);
} }
else if (strcmp(args[0], "quiet") == 0) { else if (strcmp(args[0], "quiet") == 0) {
if (alertif_too_many_args(0, file, linenum, args, &err_code)) if (alertif_too_many_args(0, file, linenum, args, &err_code))

View File

@ -1589,9 +1589,6 @@ static void init_args(int argc, char **argv)
#if defined(USE_GETADDRINFO) #if defined(USE_GETADDRINFO)
global.tune.options |= GTUNE_USE_GAI; global.tune.options |= GTUNE_USE_GAI;
#endif #endif
#if defined(SO_REUSEPORT)
global.tune.options |= GTUNE_USE_REUSEPORT;
#endif
#ifdef USE_THREAD #ifdef USE_THREAD
global.tune.options |= GTUNE_IDLE_POOL_SHARED; global.tune.options |= GTUNE_IDLE_POOL_SHARED;
#endif #endif
@ -1650,7 +1647,7 @@ static void init_args(int argc, char **argv)
#endif #endif
#if defined(SO_REUSEPORT) #if defined(SO_REUSEPORT)
else if (*flag == 'd' && flag[1] == 'R') else if (*flag == 'd' && flag[1] == 'R')
global.tune.options &= ~GTUNE_USE_REUSEPORT; protocol_clrf_all(PROTO_F_REUSEPORT_SUPPORTED);
#endif #endif
else if (*flag == 'd' && flag[1] == 'F') else if (*flag == 'd' && flag[1] == 'F')
global.tune.options &= ~GTUNE_USE_FAST_FWD; global.tune.options &= ~GTUNE_USE_FAST_FWD;

View File

@ -105,6 +105,9 @@ struct protocol proto_quic4 = {
.default_iocb = quic_lstnr_sock_fd_iocb, .default_iocb = quic_lstnr_sock_fd_iocb,
.receivers = LIST_HEAD_INIT(proto_quic4.receivers), .receivers = LIST_HEAD_INIT(proto_quic4.receivers),
.nb_receivers = 0, .nb_receivers = 0,
#ifdef SO_REUSEPORT
.flags = PROTO_F_REUSEPORT_SUPPORTED,
#endif
}; };
INITCALL1(STG_REGISTER, protocol_register, &proto_quic4); INITCALL1(STG_REGISTER, protocol_register, &proto_quic4);
@ -146,6 +149,9 @@ struct protocol proto_quic6 = {
.default_iocb = quic_lstnr_sock_fd_iocb, .default_iocb = quic_lstnr_sock_fd_iocb,
.receivers = LIST_HEAD_INIT(proto_quic6.receivers), .receivers = LIST_HEAD_INIT(proto_quic6.receivers),
.nb_receivers = 0, .nb_receivers = 0,
#ifdef SO_REUSEPORT
.flags = PROTO_F_REUSEPORT_SUPPORTED,
#endif
}; };
INITCALL1(STG_REGISTER, protocol_register, &proto_quic6); INITCALL1(STG_REGISTER, protocol_register, &proto_quic6);

View File

@ -88,6 +88,9 @@ struct protocol proto_tcpv4 = {
.default_iocb = sock_accept_iocb, .default_iocb = sock_accept_iocb,
.receivers = LIST_HEAD_INIT(proto_tcpv4.receivers), .receivers = LIST_HEAD_INIT(proto_tcpv4.receivers),
.nb_receivers = 0, .nb_receivers = 0,
#ifdef SO_REUSEPORT
.flags = PROTO_F_REUSEPORT_SUPPORTED,
#endif
}; };
INITCALL1(STG_REGISTER, protocol_register, &proto_tcpv4); INITCALL1(STG_REGISTER, protocol_register, &proto_tcpv4);
@ -131,6 +134,9 @@ struct protocol proto_tcpv6 = {
.default_iocb = sock_accept_iocb, .default_iocb = sock_accept_iocb,
.receivers = LIST_HEAD_INIT(proto_tcpv6.receivers), .receivers = LIST_HEAD_INIT(proto_tcpv6.receivers),
.nb_receivers = 0, .nb_receivers = 0,
#ifdef SO_REUSEPORT
.flags = PROTO_F_REUSEPORT_SUPPORTED,
#endif
}; };
INITCALL1(STG_REGISTER, protocol_register, &proto_tcpv6); INITCALL1(STG_REGISTER, protocol_register, &proto_tcpv6);

View File

@ -74,6 +74,9 @@ struct protocol proto_udp4 = {
.rx_unbind = sock_unbind, .rx_unbind = sock_unbind,
.receivers = LIST_HEAD_INIT(proto_udp4.receivers), .receivers = LIST_HEAD_INIT(proto_udp4.receivers),
.nb_receivers = 0, .nb_receivers = 0,
#ifdef SO_REUSEPORT
.flags = PROTO_F_REUSEPORT_SUPPORTED,
#endif
}; };
INITCALL1(STG_REGISTER, protocol_register, &proto_udp4); INITCALL1(STG_REGISTER, protocol_register, &proto_udp4);
@ -108,6 +111,9 @@ struct protocol proto_udp6 = {
.rx_unbind = sock_unbind, .rx_unbind = sock_unbind,
.receivers = LIST_HEAD_INIT(proto_udp6.receivers), .receivers = LIST_HEAD_INIT(proto_udp6.receivers),
.nb_receivers = 0, .nb_receivers = 0,
#ifdef SO_REUSEPORT
.flags = PROTO_F_REUSEPORT_SUPPORTED,
#endif
}; };
INITCALL1(STG_REGISTER, protocol_register, &proto_udp6); INITCALL1(STG_REGISTER, protocol_register, &proto_udp6);

View File

@ -376,7 +376,7 @@ int sock_inet_bind_receiver(struct receiver *rx, char **errmsg)
/* OpenBSD and Linux 3.9 support this. As it's present in old libc versions of /* OpenBSD and Linux 3.9 support this. As it's present in old libc versions of
* Linux, it might return an error that we will silently ignore. * Linux, it might return an error that we will silently ignore.
*/ */
if (!ext && (global.tune.options & GTUNE_USE_REUSEPORT)) if (!ext && (rx->proto->flags & PROTO_F_REUSEPORT_SUPPORTED))
setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &one, sizeof(one)); setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &one, sizeof(one));
#endif #endif
@ -384,7 +384,7 @@ int sock_inet_bind_receiver(struct receiver *rx, char **errmsg)
/* FreeBSD 12 and above use this to load-balance incoming connections. /* FreeBSD 12 and above use this to load-balance incoming connections.
* This is limited to 256 listeners per group however. * This is limited to 256 listeners per group however.
*/ */
if (!ext && (global.tune.options & GTUNE_USE_REUSEPORT)) if (!ext && (rx->proto->flags & PROTO_F_REUSEPORT_SUPPORTED))
setsockopt(fd, SOL_SOCKET, SO_REUSEPORT_LB, &one, sizeof(one)); setsockopt(fd, SOL_SOCKET, SO_REUSEPORT_LB, &one, sizeof(one));
#endif #endif