MEDIUM: make SO_REUSEPORT configurable
With Linux officially introducing SO_REUSEPORT support in 3.9 and
its mainstream adoption we have seen more people running into strange
SO_REUSEPORT related issues (a process management issue turning into
hard to diagnose problems because the kernel load-balances between the
new and an obsolete haproxy instance).
Also some people simply want the guarantee that the bind fails when
the old process is still bound.
This change makes SO_REUSEPORT configurable, introducing the command
line argument "-dR" and the noreuseport configuration directive.
A backport to 1.6 should be considered.
diff --git a/doc/configuration.txt b/doc/configuration.txt
index 1a7114e..52e6cf4 100644
--- a/doc/configuration.txt
+++ b/doc/configuration.txt
@@ -578,6 +578,7 @@
- nopoll
- nosplice
- nogetaddrinfo
+ - noreuseport
- spread-checks
- server-state-base
- server-state-file
@@ -1130,6 +1131,10 @@
Disables the use of getaddrinfo(3) for name resolving. It is equivalent to
the command line argument "-dG". Deprecated gethostbyname(3) will be used.
+noreuseport
+ Disables the use of SO_REUSEPORT - see socket(7). It is equivalent to the
+ command line argument "-dR".
+
spread-checks <0..50, in percent>
Sometimes it is desirable to avoid sending agent and health checks to
servers at exact intervals, for instance when many logical servers are
diff --git a/include/types/global.h b/include/types/global.h
index 71eacf2..2a9bf56 100644
--- a/include/types/global.h
+++ b/include/types/global.h
@@ -63,6 +63,7 @@
/* platform-specific options */
#define GTUNE_USE_SPLICE (1<<4)
#define GTUNE_USE_GAI (1<<5)
+#define GTUNE_USE_REUSEPORT (1<<6)
/* Access level for a stats socket */
#define ACCESS_LVL_NONE 0
diff --git a/src/cfgparse.c b/src/cfgparse.c
index 09077d8..7b58ef6 100644
--- a/src/cfgparse.c
+++ b/src/cfgparse.c
@@ -664,6 +664,11 @@
goto out;
global.tune.options &= ~GTUNE_USE_GAI;
}
+ else if (!strcmp(args[0], "noreuseport")) {
+ if (alertif_too_many_args(0, file, linenum, args, &err_code))
+ goto out;
+ global.tune.options &= ~GTUNE_USE_REUSEPORT;
+ }
else if (!strcmp(args[0], "quiet")) {
if (alertif_too_many_args(0, file, linenum, args, &err_code))
goto out;
diff --git a/src/haproxy.c b/src/haproxy.c
index 96ecd0d..b1c10b6 100644
--- a/src/haproxy.c
+++ b/src/haproxy.c
@@ -459,6 +459,9 @@
#if defined(USE_GETADDRINFO)
" -dG disables getaddrinfo() usage\n"
#endif
+#if defined(SO_REUSEPORT)
+ " -dR disables SO_REUSEPORT usage\n"
+#endif
" -dV disables SSL verify on servers side\n"
" -sf/-st [pid ]* finishes/terminates old pids.\n"
"\n",
@@ -726,6 +729,9 @@
#if defined(USE_GETADDRINFO)
global.tune.options |= GTUNE_USE_GAI;
#endif
+#if defined(SO_REUSEPORT)
+ global.tune.options |= GTUNE_USE_REUSEPORT;
+#endif
pid = getpid();
progname = *argv;
@@ -769,6 +775,10 @@
else if (*flag == 'd' && flag[1] == 'G')
global.tune.options &= ~GTUNE_USE_GAI;
#endif
+#if defined(SO_REUSEPORT)
+ else if (*flag == 'd' && flag[1] == 'R')
+ global.tune.options &= ~GTUNE_USE_REUSEPORT;
+#endif
else if (*flag == 'd' && flag[1] == 'V')
global.ssl_server_verify = SSL_SERVER_VERIFY_NONE;
else if (*flag == 'V')
diff --git a/src/proto_tcp.c b/src/proto_tcp.c
index b614e6b..91d6688 100644
--- a/src/proto_tcp.c
+++ b/src/proto_tcp.c
@@ -823,10 +823,10 @@
setsockopt(fd, SOL_SOCKET, SO_LINGER, &nolinger, sizeof(struct linger));
#ifdef SO_REUSEPORT
- /* OpenBSD supports this. As it's present in old libc versions of Linux,
- * it might return an error that we will silently ignore.
+ /* 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)
+ if (!ext && (global.tune.options & GTUNE_USE_REUSEPORT))
setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &one, sizeof(one));
#endif