]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
3980. [bug] Improve --with-tuning=large by self tuning of SO_RCVBUF
authorMark Andrews <marka@isc.org>
Sat, 18 Oct 2014 01:40:13 +0000 (12:40 +1100)
committerMark Andrews <marka@isc.org>
Sat, 18 Oct 2014 01:40:13 +0000 (12:40 +1100)
                        size. [RT #37187]

CHANGES
lib/isc/unix/socket.c

diff --git a/CHANGES b/CHANGES
index 1094623f0dc036c738e56455a2d5dceb429b02ec..67d50aee4625f5dc2b8b063a9eabfb0fbac07503 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,6 @@
+3980.  [bug]           Improve --with-tuning=large by self tuning of SO_RCVBUF
+                       size. [RT #37187]
+
 3979.  [bug]           Negative trust anchor fetches were not properly
                        managed. [RT #37488]
 
index 7a9e625caefba7ac3318de9ffe42f102af08a9aa..37995aeb42d37d30bb52c70727fc0d04a7c594b3 100644 (file)
@@ -2413,6 +2413,62 @@ free_socket(isc__socket_t **socketp) {
        *socketp = NULL;
 }
 
+#ifdef SO_RCVBUF
+static isc_once_t      rcvbuf_once = ISC_ONCE_INIT;
+static int             rcvbuf = RCVBUFSIZE;
+
+static void
+set_rcvbuf(void) {
+       int fd;
+       int max = rcvbuf, min;
+       ISC_SOCKADDR_LEN_T len;
+
+       fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+#if defined(ISC_PLATFORM_HAVEIPV6)
+       if (fd == -1) {
+               switch (errno) {
+               case EPROTONOSUPPORT:
+               case EPFNOSUPPORT:
+               case EAFNOSUPPORT:
+               /*
+                * Linux 2.2 (and maybe others) return EINVAL instead of
+                * EAFNOSUPPORT.
+                */
+               case EINVAL:
+                       fd = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
+                       break;
+               }
+       }
+#endif
+       if (fd == -1)
+               return;
+
+       len = sizeof(min);
+       if (getsockopt(fd, SOL_SOCKET, SO_RCVBUF, (void *)&min, &len) >= 0 &&
+           min < rcvbuf) {
+ again:
+               if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (void *)&rcvbuf,
+                              sizeof(rcvbuf)) == -1) {
+                       if (errno == ENOBUFS && rcvbuf > min) {
+                               max = rcvbuf - 1;
+                               rcvbuf = (rcvbuf + min) / 2;
+                               goto again;
+                       } else {
+                               rcvbuf = min;
+                               goto cleanup;
+                       }
+               } else
+                       min = rcvbuf;
+               if (min != max) {
+                       rcvbuf = max;
+                       goto again;
+               }
+       }
+ cleanup:
+       close (fd);
+}
+#endif
+
 #ifdef SO_BSDCOMPAT
 /*
  * This really should not be necessary to do.  Having to workout
@@ -2785,15 +2841,15 @@ opensocket(isc__socketmgr_t *manager, isc__socket_t *sock,
 #if defined(SO_RCVBUF)
                optlen = sizeof(size);
                if (getsockopt(sock->fd, SOL_SOCKET, SO_RCVBUF,
-                              (void *)&size, &optlen) >= 0 &&
-                    size < RCVBUFSIZE) {
-                       size = RCVBUFSIZE;
+                              (void *)&size, &optlen) >= 0 && size < rcvbuf) {
+                       RUNTIME_CHECK(isc_once_do(&rcvbuf_once,
+                                                 set_rcvbuf) == ISC_R_SUCCESS);
                        if (setsockopt(sock->fd, SOL_SOCKET, SO_RCVBUF,
-                                      (void *)&size, sizeof(size)) == -1) {
+                              (void *)&rcvbuf, sizeof(rcvbuf)) == -1) {
                                isc__strerror(errno, strbuf, sizeof(strbuf));
                                UNEXPECTED_ERROR(__FILE__, __LINE__,
                                        "setsockopt(%d, SO_RCVBUF, %d) %s: %s",
-                                       sock->fd, size,
+                                       sock->fd, rcvbuf,
                                        isc_msgcat_get(isc_msgcat,
                                                       ISC_MSGSET_GENERAL,
                                                       ISC_MSG_FAILED,