]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
[master] Improve handling of TCP_FASTOPEN on FreeBSD
authorMichał Kępień <michal@isc.org>
Mon, 18 Sep 2017 06:34:41 +0000 (08:34 +0200)
committerMichał Kępień <michal@isc.org>
Mon, 18 Sep 2017 06:34:41 +0000 (08:34 +0200)
4726. [port] Prevent setsockopt() errors related to TCP_FASTOPEN
from being logged on FreeBSD if the kernel does not
support it.  Notify the user when the kernel does
support TCP_FASTOPEN, but it is disabled by sysctl.
Add a new configure option, --disable-tcp-fastopen, to
disable use of TCP_FASTOPEN altogether. [RT #44754]

CHANGES
configure.in
doc/misc/tcp-fast-open
lib/isc/unix/socket.c

diff --git a/CHANGES b/CHANGES
index 192637a3adec7a2c85081cc35a5862b1dddd65c7..4b069a046a862f251199e830f3ab4b3aa0a08972 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,10 @@
+4726.  [port]          Prevent setsockopt() errors related to TCP_FASTOPEN
+                       from being logged on FreeBSD if the kernel does not
+                       support it.  Notify the user when the kernel does
+                       support TCP_FASTOPEN, but it is disabled by sysctl.
+                       Add a new configure option, --disable-tcp-fastopen, to
+                       disable use of TCP_FASTOPEN altogether. [RT #44754]
+
 4725.  [bug]           Nsupdate: "recvsoa" was incorrectly reported for
                        failures in sending the update message.  The correct
                        location to be reported is "update_completed".
index 1a8ba22695f1ee73cba8ec7d45dd86a12e6dba2c..f71a7fcbbf5b57f80b21d904a9cf638f388946d7 100644 (file)
@@ -3361,10 +3361,18 @@ AC_TRY_COMPILE([
 AC_SUBST(ISC_PLATFORM_NEEDPORTT)
 
 #
-# Look for TCP_FASTOPEN
+# Allow forcibly disabling TCP Fast Open support as autodetection might yield
+# confusing results on some systems (e.g. FreeBSD; see set_tcp_fastopen()
+# comment in lib/isc/unix/socket.c).
 #
+
+AC_ARG_ENABLE(tcp_fastopen,
+       [  --disable-tcp-fastopen  disable TCP Fast Open support [[default=autodetect]]])
+
 AC_MSG_CHECKING(for TCP_FASTOPEN socket option)
-AC_EGREP_CPP(has_tfo, [
+case "$enable_tcp_fastopen" in
+yes|''|autodetect)
+       AC_EGREP_CPP(has_tfo, [
 #include <sys/types.h>
 #include <sys/socket.h>
 #include <netinet/tcp.h>
@@ -3372,10 +3380,17 @@ AC_EGREP_CPP(has_tfo, [
 int has_tfo() { return (0); }
 #endif
 ],
-       [AC_MSG_RESULT(yes)
-       ISC_PLATFORM_HAVETFO="#define ISC_PLATFORM_HAVETFO 1"],
-       [AC_MSG_RESULT(no)
-       ISC_PLATFORM_HAVETFO="#undef ISC_PLATFORM_HAVETFO"])
+               [AC_MSG_RESULT(yes)
+               ISC_PLATFORM_HAVETFO="#define ISC_PLATFORM_HAVETFO 1"],
+               [AC_MSG_RESULT(no)
+               ISC_PLATFORM_HAVETFO="#undef ISC_PLATFORM_HAVETFO"])
+
+               ;;
+       no)
+               AC_MSG_RESULT(disabled)
+               ISC_PLATFORM_HAVETFO="#undef ISC_PLATFORM_HAVETFO"
+               ;;
+esac
 AC_SUBST(ISC_PLATFORM_HAVETFO)
 
 #
index edde691f11801c02b23ca17ef6590e70a9c88b29..4fdcd760fe3746c0b0f36d46b7fa27d9c279286d 100644 (file)
@@ -19,6 +19,10 @@ System specific notes:
  - FreeBSD doesn't interpret the argument as a queue length but
   only as an on/off switch.
 
+ - Using TCP Fast Open on FreeBSD, as of versions 10.3 and 11.0, requires
+   compiling a custom kernel and setting the "net.inet.tcp.fastopen.enabled"
+   sysctl to 1.
+
  - Apple OS X/macOS allows only 0 or 1 so the code puts 1 for this system.
 
  - Windows 10 uses a 0/1 char flag? Note that TCP_FASTOPEN is defined
index 0f6ea564f610d590fd71f845980ba13555acd472..4299c20d0a845177777f1d91a4f9df6217035045 100644 (file)
@@ -14,6 +14,9 @@
 #include <sys/types.h>
 #include <sys/socket.h>
 #include <sys/stat.h>
+#ifdef HAVE_SYS_SYSCTL_H
+#include <sys/sysctl.h>
+#endif
 #include <sys/time.h>
 #include <sys/uio.h>
 
@@ -5649,6 +5652,69 @@ isc__socket_filter(isc_socket_t *sock0, const char *filter) {
 #endif
 }
 
+/*
+ * Try enabling TCP Fast Open for a given socket if the OS supports it.
+ */
+static void
+set_tcp_fastopen(isc__socket_t *sock, unsigned int backlog) {
+#if defined(ISC_PLATFORM_HAVETFO) && defined(TCP_FASTOPEN)
+       char strbuf[ISC_STRERRORSIZE];
+
+/*
+ * FreeBSD, as of versions 10.3 and 11.0, defines TCP_FASTOPEN while also
+ * shipping a default kernel without TFO support, so we special-case it by
+ * performing an additional runtime check for TFO support using sysctl to
+ * prevent setsockopt() errors from being logged.
+ */
+#if defined(__FreeBSD__) && defined(HAVE_SYSCTLBYNAME)
+#define SYSCTL_TFO "net.inet.tcp.fastopen.enabled"
+       unsigned int enabled;
+       size_t enabledlen = sizeof(enabled);
+       static isc_boolean_t tfo_notice_logged = ISC_FALSE;
+
+       if (sysctlbyname(SYSCTL_TFO, &enabled, &enabledlen, NULL, 0) < 0) {
+               /*
+                * This kernel does not support TCP Fast Open.  There is
+                * nothing more we can do.
+                */
+               return;
+       } else if (enabled == 0) {
+               /*
+                * This kernel does support TCP Fast Open, but it is disabled
+                * by sysctl.  Notify the user, but do not nag.
+                */
+               if (!tfo_notice_logged) {
+                       isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
+                                     ISC_LOGMODULE_SOCKET, ISC_LOG_NOTICE,
+                                     "TCP_FASTOPEN support is disabled by "
+                                     "sysctl (" SYSCTL_TFO " = 0)");
+                       tfo_notice_logged = ISC_TRUE;
+               }
+               return;
+       }
+#endif
+
+#ifdef __APPLE__
+       backlog = 1;
+#else
+       backlog = backlog / 2;
+       if (backlog == 0)
+               backlog = 1;
+#endif
+       if (setsockopt(sock->fd, IPPROTO_TCP, TCP_FASTOPEN,
+                      (void *)&backlog, sizeof(backlog)) < 0) {
+               isc__strerror(errno, strbuf, sizeof(strbuf));
+               UNEXPECTED_ERROR(__FILE__, __LINE__,
+                                "setsockopt(%d, TCP_FASTOPEN) failed with %s",
+                                sock->fd, strbuf);
+               /* TCP_FASTOPEN is experimental so ignore failures */
+       }
+#else
+       UNUSED(sock);
+       UNUSED(backlog);
+#endif
+}
+
 /*
  * Set up to listen on a given socket.  We do this by creating an internal
  * event that will be dispatched when the socket has read activity.  The
@@ -5685,23 +5751,7 @@ isc__socket_listen(isc_socket_t *sock0, unsigned int backlog) {
                return (ISC_R_UNEXPECTED);
        }
 
-#if defined(ISC_PLATFORM_HAVETFO) && defined(TCP_FASTOPEN)
-#ifdef __APPLE__
-       backlog = 1;
-#else
-       backlog = backlog / 2;
-       if (backlog == 0)
-               backlog = 1;
-#endif
-       if (setsockopt(sock->fd, IPPROTO_TCP, TCP_FASTOPEN,
-                      (void *)&backlog, sizeof(backlog)) < 0) {
-               isc__strerror(errno, strbuf, sizeof(strbuf));
-               UNEXPECTED_ERROR(__FILE__, __LINE__,
-                                "setsockopt(%d, TCP_FASTOPEN) failed with %s",
-                                sock->fd, strbuf);
-               /* TCP_FASTOPEN is experimental so ignore failures */
-       }
-#endif
+       set_tcp_fastopen(sock, backlog);
 
        sock->listener = 1;