From 785b89f5514082facf8b9061568460e9834f61d0 Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Sat, 22 Apr 2023 15:09:07 +0200 Subject: [PATCH] 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. --- include/haproxy/global-t.h | 2 +- include/haproxy/protocol-t.h | 3 +++ src/cfgcond.c | 3 ++- src/cfgparse-global.c | 3 ++- src/haproxy.c | 5 +---- src/proto_quic.c | 6 ++++++ src/proto_tcp.c | 6 ++++++ src/proto_udp.c | 6 ++++++ src/sock_inet.c | 4 ++-- 9 files changed, 29 insertions(+), 9 deletions(-) diff --git a/include/haproxy/global-t.h b/include/haproxy/global-t.h index af7f26cfb..3a7b53b73 100644 --- a/include/haproxy/global-t.h +++ b/include/haproxy/global-t.h @@ -58,7 +58,7 @@ /* platform-specific options */ #define GTUNE_USE_SPLICE (1<<4) #define GTUNE_USE_GAI (1<<5) -#define GTUNE_USE_REUSEPORT (1<<6) +/* unused: (1<<6) */ #define GTUNE_RESOLVE_DONTFAIL (1<<7) #define GTUNE_SOCKET_TRANSFER (1<<8) diff --git a/include/haproxy/protocol-t.h b/include/haproxy/protocol-t.h index aa8aa662c..eec65fed4 100644 --- a/include/haproxy/protocol-t.h +++ b/include/haproxy/protocol-t.h @@ -64,6 +64,9 @@ enum proto_type { #define CONNECT_DELACK_ALWAYS 0x00000004 /* Use a delayed ACK */ #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 * for a socket implementation, such as AF_INET/PF_INET for example. */ diff --git a/src/cfgcond.c b/src/cfgcond.c index 89036ada3..117cf6c28 100644 --- a/src/cfgcond.c +++ b/src/cfgcond.c @@ -14,6 +14,7 @@ #include #include #include +#include #include /* supported condition predicates */ @@ -195,7 +196,7 @@ static int cfg_eval_cond_enabled(const char *str) else if (strcmp(str, "GETADDRINFO") == 0) return !!(global.tune.options & GTUNE_USE_GAI); 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) return !!(global.tune.options & GTUNE_USE_FAST_FWD); else if (strcmp(str, "SERVER-SSL-VERIFY-NONE") == 0) diff --git a/src/cfgparse-global.c b/src/cfgparse-global.c index e46672e15..76d176904 100644 --- a/src/cfgparse-global.c +++ b/src/cfgparse-global.c @@ -20,6 +20,7 @@ #include #include #include +#include #include /* 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) { if (alertif_too_many_args(0, file, linenum, args, &err_code)) goto out; - global.tune.options &= ~GTUNE_USE_REUSEPORT; + protocol_clrf_all(PROTO_F_REUSEPORT_SUPPORTED); } else if (strcmp(args[0], "quiet") == 0) { if (alertif_too_many_args(0, file, linenum, args, &err_code)) diff --git a/src/haproxy.c b/src/haproxy.c index 530611319..b1574abfd 100644 --- a/src/haproxy.c +++ b/src/haproxy.c @@ -1589,9 +1589,6 @@ static void init_args(int argc, char **argv) #if defined(USE_GETADDRINFO) global.tune.options |= GTUNE_USE_GAI; #endif -#if defined(SO_REUSEPORT) - global.tune.options |= GTUNE_USE_REUSEPORT; -#endif #ifdef USE_THREAD global.tune.options |= GTUNE_IDLE_POOL_SHARED; #endif @@ -1650,7 +1647,7 @@ static void init_args(int argc, char **argv) #endif #if defined(SO_REUSEPORT) else if (*flag == 'd' && flag[1] == 'R') - global.tune.options &= ~GTUNE_USE_REUSEPORT; + protocol_clrf_all(PROTO_F_REUSEPORT_SUPPORTED); #endif else if (*flag == 'd' && flag[1] == 'F') global.tune.options &= ~GTUNE_USE_FAST_FWD; diff --git a/src/proto_quic.c b/src/proto_quic.c index 76583298e..22776cd83 100644 --- a/src/proto_quic.c +++ b/src/proto_quic.c @@ -105,6 +105,9 @@ struct protocol proto_quic4 = { .default_iocb = quic_lstnr_sock_fd_iocb, .receivers = LIST_HEAD_INIT(proto_quic4.receivers), .nb_receivers = 0, +#ifdef SO_REUSEPORT + .flags = PROTO_F_REUSEPORT_SUPPORTED, +#endif }; INITCALL1(STG_REGISTER, protocol_register, &proto_quic4); @@ -146,6 +149,9 @@ struct protocol proto_quic6 = { .default_iocb = quic_lstnr_sock_fd_iocb, .receivers = LIST_HEAD_INIT(proto_quic6.receivers), .nb_receivers = 0, +#ifdef SO_REUSEPORT + .flags = PROTO_F_REUSEPORT_SUPPORTED, +#endif }; INITCALL1(STG_REGISTER, protocol_register, &proto_quic6); diff --git a/src/proto_tcp.c b/src/proto_tcp.c index 2e5c36a51..45ce27f11 100644 --- a/src/proto_tcp.c +++ b/src/proto_tcp.c @@ -88,6 +88,9 @@ struct protocol proto_tcpv4 = { .default_iocb = sock_accept_iocb, .receivers = LIST_HEAD_INIT(proto_tcpv4.receivers), .nb_receivers = 0, +#ifdef SO_REUSEPORT + .flags = PROTO_F_REUSEPORT_SUPPORTED, +#endif }; INITCALL1(STG_REGISTER, protocol_register, &proto_tcpv4); @@ -131,6 +134,9 @@ struct protocol proto_tcpv6 = { .default_iocb = sock_accept_iocb, .receivers = LIST_HEAD_INIT(proto_tcpv6.receivers), .nb_receivers = 0, +#ifdef SO_REUSEPORT + .flags = PROTO_F_REUSEPORT_SUPPORTED, +#endif }; INITCALL1(STG_REGISTER, protocol_register, &proto_tcpv6); diff --git a/src/proto_udp.c b/src/proto_udp.c index 1fd92c7ce..54f87d0ca 100644 --- a/src/proto_udp.c +++ b/src/proto_udp.c @@ -74,6 +74,9 @@ struct protocol proto_udp4 = { .rx_unbind = sock_unbind, .receivers = LIST_HEAD_INIT(proto_udp4.receivers), .nb_receivers = 0, +#ifdef SO_REUSEPORT + .flags = PROTO_F_REUSEPORT_SUPPORTED, +#endif }; INITCALL1(STG_REGISTER, protocol_register, &proto_udp4); @@ -108,6 +111,9 @@ struct protocol proto_udp6 = { .rx_unbind = sock_unbind, .receivers = LIST_HEAD_INIT(proto_udp6.receivers), .nb_receivers = 0, +#ifdef SO_REUSEPORT + .flags = PROTO_F_REUSEPORT_SUPPORTED, +#endif }; INITCALL1(STG_REGISTER, protocol_register, &proto_udp6); diff --git a/src/sock_inet.c b/src/sock_inet.c index d225a9dc9..028ffaa68 100644 --- a/src/sock_inet.c +++ b/src/sock_inet.c @@ -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 * 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)); #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. * 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)); #endif