]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
Add option to configure load balance sockets
authorOndřej Surý <ondrej@isc.org>
Fri, 1 Apr 2022 12:43:14 +0000 (14:43 +0200)
committerOndřej Surý <ondrej@isc.org>
Mon, 4 Apr 2022 23:21:50 +0000 (01:21 +0200)
Previously, the option to enable kernel load balancing of the sockets
was always enabled when supported by the operating system (SO_REUSEPORT
on Linux and SO_REUSEPORT_LB on FreeBSD).

It was reported that in scenarios where the networking threads are also
responsible for processing long-running tasks (like RPZ processing, CATZ
processing or large zone transfers), this could lead to intermitten
brownouts for some clients, because the thread assigned by the operating
system might be busy.  In such scenarious, the overall performance would
be better served by threads competing over the sockets because the idle
threads can pick up the incoming traffic.

Add new configuration option (`load-balance-sockets`) to allow enabling
or disabling the load balancing of the sockets.

(cherry picked from commit 85c6e797aa84dfeecb096e7ca3eafb85a5a45f3f)

16 files changed:
bin/named/config.c
bin/named/named.conf.rst
bin/named/server.c
doc/arm/reference.rst
doc/man/named.conf.5in
doc/misc/options
doc/misc/options.active
doc/misc/options.grammar.rst
lib/isc/include/isc/netmgr.h
lib/isc/netmgr/netmgr-int.h
lib/isc/netmgr/netmgr.c
lib/isc/netmgr/tcp.c
lib/isc/netmgr/tcpdns.c
lib/isc/netmgr/udp.c
lib/isc/win32/libisc.def.in
lib/isccfg/namedconf.c

index 0b8522cbbfda53b4e6460091684cbf555f2a767a..90c00b2314e13db11447edf77becf534ca69bc11 100644 (file)
@@ -75,7 +75,15 @@ options {\n\
        interface-interval 60;\n\
 #      keep-response-order {none;};\n\
        listen-on {any;};\n\
-       listen-on-v6 {any;};\n\
+       listen-on-v6 {any;};\n"
+#if HAVE_SO_REUSEPORT_LB
+                           "\
+       load-balance-sockets yes;\n"
+#else
+                           "\
+       load-balance-sockets no;\n"
+#endif
+                           "\
 #      lock-file \"" NAMED_LOCALSTATEDIR "/run/named/named.lock\";\n\
        match-mapped-addresses no;\n\
        max-ixfr-ratio unlimited;\n\
index 477d6f290b66702fe7a4c02ddb06d149035e1774..4829ba02471e7be1e2c3b04b96c49ae8128856d1 100644 (file)
@@ -288,6 +288,7 @@ OPTIONS
            integer ] {
            address_match_element; ... };
        lmdb-mapsize sizeval;
+       load-balance-sockets boolean;
        lock-file ( quoted_string | none );
        managed-keys-directory quoted_string;
        masterfile-format ( map | raw | text );
index cdda71de49edb7b79902f4b2f4419cdf325e45a2..92a81ed5d50479d4428828f80e550acfb3660424 100644 (file)
@@ -8316,6 +8316,7 @@ load_configuration(const char *filename, named_server_t *server,
        uint32_t softquota = 0;
        uint32_t max;
        uint64_t initial, idle, keepalive, advertised;
+       bool loadbalancesockets;
        dns_aclenv_t *env =
                ns_interfacemgr_getaclenv(named_g_server->interfacemgr);
 
@@ -8788,6 +8789,28 @@ load_configuration(const char *filename, named_server_t *server,
        }
        ns_interfacemgr_setbacklog(server->interfacemgr, backlog);
 
+       obj = NULL;
+       result = named_config_get(maps, "load-balance-sockets", &obj);
+       INSIST(result == ISC_R_SUCCESS);
+       loadbalancesockets = cfg_obj_asboolean(obj);
+#if HAVE_SO_REUSEPORT_LB
+       if (first_time) {
+               isc_nm_setloadbalancesockets(named_g_netmgr,
+                                            cfg_obj_asboolean(obj));
+       } else if (loadbalancesockets !=
+                  isc_nm_getloadbalancesockets(named_g_netmgr)) {
+               cfg_obj_log(obj, named_g_lctx, ISC_LOG_WARNING,
+                           "changing load-balance-sockets value requires "
+                           "server restart");
+       }
+#else
+       if (loadbalancesockets) {
+               cfg_obj_log(
+                       obj, named_g_lctx, ISC_LOG_WARNING,
+                       "load-balance-sockets has no effect on this system");
+       }
+#endif
+
        /*
         * Configure the interface manager according to the "listen-on"
         * statement.
index 0bf87b74deffc3e917ebef02e98ab46d0add0549..d665d46cf4dc01bcc0c8aedde6545f05f1acbcee 100644 (file)
@@ -1691,6 +1691,29 @@ Boolean Options
    If ``yes``, respond to root key sentinel probes as described in
    draft-ietf-dnsop-kskroll-sentinel-08. The default is ``yes``.
 
+``load-balance-sockets``
+
+   This option enables kernel load-balancing of sockets on systems which support
+   it, including Linux and FreeBSD. This instructs the kernel to distribute
+   incoming socket connections among the networking threads based on a hashing
+   scheme. For more information, see the receive network flow classification
+   options (``rx-flow-hash``) section in the ``ethtool`` manual page. The
+   default is ``yes``.
+
+   Enabling ``load-balance-sockets`` significantly increases general throughput
+   when incoming traffic is distributed uniformly onto the threads by the
+   operating system. However, in cases where a worker thread is busy with a
+   long-lasting operation, such as processing a Response Policy Zone (RPZ) or
+   Catalog Zone update or an unusually large zone transfer, incoming traffic
+   that hashes onto that thread may be delayed. On servers where these events
+   occur frequently, it may be preferable to disable socket load-balancing so
+   that other threads can pick up the traffic that would have been sent to the
+   busy thread.
+
+   Note: this option can only be set when ``named`` first starts.
+   Changes will not take effect during reconfiguration; the server
+   must be restarted.
+
 ``message-compression``
    If ``yes``, DNS name compression is used in responses to regular
    queries (not including AXFR or IXFR, which always use compression).
index 0a8c0a6d0349df30c2ab69bcedfb5e075fb4af97..77499fd344f8bca83061a0e16ad7636714d14487 100644 (file)
@@ -340,6 +340,7 @@ options {
           integer ] {
           address_match_element; ... };
       lmdb\-mapsize sizeval;
+      load\-balance\-sockets boolean;
       lock\-file ( quoted_string | none );
       managed\-keys\-directory quoted_string;
       masterfile\-format ( map | raw | text );
index 36cf69f45d1518f69816584a49c90e4477e2c4f0..a7fcd160625be4d49ccc4b3557db29d8fbc298aa 100644 (file)
@@ -228,6 +228,7 @@ options {
             <integer> ] {
             <address_match_element>; ... }; // may occur multiple times
         lmdb-mapsize <sizeval>;
+        load-balance-sockets <boolean>;
         lock-file ( <quoted_string> | none );
         maintain-ixfr-base <boolean>; // ancient
         managed-keys-directory <quoted_string>;
index 256006d0399c28927e23c2303486f3a2afb2a82e..4f1661c3cb0f61f6a139bc16b5f1e31405eac7cd 100644 (file)
@@ -205,6 +205,7 @@ options {
             <integer> ] {
             <address_match_element>; ... }; // may occur multiple times
         lmdb-mapsize <sizeval>;
+        load-balance-sockets <boolean>;
         lock-file ( <quoted_string> | none );
         managed-keys-directory <quoted_string>;
         masterfile-format ( map | raw | text );
index 582053b40072461a58f8d1f1885bc9525b0efd76..3ab9ab9888735e6e37bf3be32f293d6dd0c2bc09 100644 (file)
            <integer> ] {
            <address_match_element>; ... };
        lmdb-mapsize <sizeval>;
+       load-balance-sockets <boolean>;
        lock-file ( <quoted_string> | none );
        managed-keys-directory <quoted_string>;
        masterfile-format ( map | raw | text );
index 7ec40e81b6f0a9421f748f5aa6e7dfea029af6f8..621e8f593598111afeaf8cbcf7d2e50970b7f5f4 100644 (file)
@@ -406,6 +406,17 @@ isc_nm_settimeouts(isc_nm_t *mgr, uint32_t init, uint32_t idle,
  * \li 'mgr' is a valid netmgr.
  */
 
+bool
+isc_nm_getloadbalancesockets(isc_nm_t *mgr);
+void
+isc_nm_setloadbalancesockets(isc_nm_t *mgr, bool enabled);
+/*%<
+ * Get and set value of load balancing of the sockets.
+ *
+ * Requires:
+ * \li 'mgr' is a valid netmgr.
+ */
+
 void
 isc_nm_gettimeouts(isc_nm_t *mgr, uint32_t *initial, uint32_t *idle,
                   uint32_t *keepalive, uint32_t *advertised);
index fe9fa831aa7e409d8d3dd01441ed427c96124d21..29f63fdf87f92d897825d6697658df7fb05b2e04 100644 (file)
@@ -660,6 +660,8 @@ struct isc_nm {
        atomic_uint_fast32_t workers_paused;
        atomic_uint_fast32_t maxudp;
 
+       bool load_balance_sockets;
+
        atomic_bool paused;
 
        /*
index efb8e64dbe6e1e9f7ad276a8add5a01d1a1333a2..ba5193d5a2550194e78b55be7c44636dbfc39a28 100644 (file)
@@ -310,6 +310,11 @@ isc__netmgr_create(isc_mem_t *mctx, uint32_t workers, isc_nm_t **netmgrp) {
        atomic_init(&mgr->workers_paused, 0);
        atomic_init(&mgr->paused, false);
        atomic_init(&mgr->closing, false);
+#if HAVE_SO_REUSEPORT_LB
+       mgr->load_balance_sockets = true;
+#else
+       mgr->load_balance_sockets = false;
+#endif
 
 #ifdef NETMGR_TRACE
        ISC_LIST_INIT(mgr->active_sockets);
@@ -660,6 +665,17 @@ isc_nm_settimeouts(isc_nm_t *mgr, uint32_t init, uint32_t idle,
        atomic_store(&mgr->advertised, advertised);
 }
 
+void
+isc_nm_setloadbalancesockets(isc_nm_t *mgr, bool enabled) {
+       REQUIRE(VALID_NM(mgr));
+
+#if HAVE_SO_REUSEPORT_LB
+       mgr->load_balance_sockets = enabled;
+#else
+       UNUSED(enabled);
+#endif
+}
+
 void
 isc_nm_gettimeouts(isc_nm_t *mgr, uint32_t *initial, uint32_t *idle,
                   uint32_t *keepalive, uint32_t *advertised) {
index bfadefc3197a5b70f98433b17690b897b40591a9..3e3e071c7d061d4971e3e1be6749f989b0679a04 100644 (file)
@@ -355,7 +355,7 @@ isc_nm_tcpconnect(isc_nm_t *mgr, isc_sockaddr_t *local, isc_sockaddr_t *peer,
 }
 
 static uv_os_sock_t
-isc__nm_tcp_lb_socket(sa_family_t sa_family) {
+isc__nm_tcp_lb_socket(isc_nm_t *mgr, sa_family_t sa_family) {
        isc_result_t result;
        uv_os_sock_t sock;
 
@@ -369,10 +369,10 @@ isc__nm_tcp_lb_socket(sa_family_t sa_family) {
        result = isc__nm_socket_reuse(sock);
        RUNTIME_CHECK(result == ISC_R_SUCCESS);
 
-#if HAVE_SO_REUSEPORT_LB
-       result = isc__nm_socket_reuse_lb(sock);
-       RUNTIME_CHECK(result == ISC_R_SUCCESS);
-#endif
+       if (mgr->load_balance_sockets) {
+               result = isc__nm_socket_reuse_lb(sock);
+               RUNTIME_CHECK(result == ISC_R_SUCCESS);
+       }
 
        return (sock);
 }
@@ -397,12 +397,13 @@ start_tcp_child(isc_nm_t *mgr, isc_sockaddr_t *iface, isc_nmsocket_t *sock,
        csock->pquota = sock->pquota;
        isc_quota_cb_init(&csock->quotacb, quota_accept_cb, csock);
 
-#if HAVE_SO_REUSEPORT_LB || defined(WIN32)
-       UNUSED(fd);
-       csock->fd = isc__nm_tcp_lb_socket(iface->type.sa.sa_family);
-#else
-       csock->fd = dup(fd);
-#endif
+       if (mgr->load_balance_sockets) {
+               UNUSED(fd);
+               csock->fd = isc__nm_tcp_lb_socket(mgr,
+                                                 iface->type.sa.sa_family);
+       } else {
+               csock->fd = dup(fd);
+       }
        REQUIRE(csock->fd >= 0);
 
        ievent = isc__nm_get_netievent_tcplisten(mgr, csock);
@@ -454,9 +455,9 @@ isc_nm_listentcp(isc_nm_t *mgr, isc_sockaddr_t *iface,
        sock->tid = 0;
        sock->fd = -1;
 
-#if !HAVE_SO_REUSEPORT_LB && !defined(WIN32)
-       fd = isc__nm_tcp_lb_socket(iface->type.sa.sa_family);
-#endif
+       if (!mgr->load_balance_sockets) {
+               fd = isc__nm_tcp_lb_socket(mgr, iface->type.sa.sa_family);
+       }
 
        isc_barrier_init(&sock->startlistening, sock->nchildren);
 
@@ -471,9 +472,9 @@ isc_nm_listentcp(isc_nm_t *mgr, isc_sockaddr_t *iface,
                start_tcp_child(mgr, iface, sock, fd, isc_nm_tid());
        }
 
-#if !HAVE_SO_REUSEPORT_LB && !defined(WIN32)
-       isc__nm_closesocket(fd);
-#endif
+       if (!mgr->load_balance_sockets) {
+               isc__nm_closesocket(fd);
+       }
 
        LOCK(&sock->lock);
        while (atomic_load(&sock->rchildren) != sock->nchildren) {
@@ -505,6 +506,7 @@ isc__nm_async_tcplisten(isc__networker_t *worker, isc__netievent_t *ev0) {
        int flags = 0;
        isc_nmsocket_t *sock = NULL;
        isc_result_t result;
+       isc_nm_t *mgr;
 
        REQUIRE(VALID_NMSOCK(ievent->sock));
        REQUIRE(ievent->sock->tid == isc_nm_tid());
@@ -512,6 +514,7 @@ isc__nm_async_tcplisten(isc__networker_t *worker, isc__netievent_t *ev0) {
 
        sock = ievent->sock;
        sa_family = sock->iface.type.sa.sa_family;
+       mgr = sock->mgr;
 
        REQUIRE(sock->type == isc_nm_tcpsocket);
        REQUIRE(sock->parent != NULL);
@@ -544,15 +547,7 @@ isc__nm_async_tcplisten(isc__networker_t *worker, isc__netievent_t *ev0) {
                flags = UV_TCP_IPV6ONLY;
        }
 
-#if HAVE_SO_REUSEPORT_LB || defined(WIN32)
-       r = isc_uv_tcp_freebind(&sock->uv_handle.tcp, &sock->iface.type.sa,
-                               flags);
-       if (r < 0) {
-               isc__nm_incstats(sock->mgr, sock->statsindex[STATID_BINDFAIL]);
-               goto done;
-       }
-#else
-       if (sock->parent->fd == -1) {
+       if (mgr->load_balance_sockets) {
                r = isc_uv_tcp_freebind(&sock->uv_handle.tcp,
                                        &sock->iface.type.sa, flags);
                if (r < 0) {
@@ -560,13 +555,23 @@ isc__nm_async_tcplisten(isc__networker_t *worker, isc__netievent_t *ev0) {
                                         sock->statsindex[STATID_BINDFAIL]);
                        goto done;
                }
-               sock->parent->uv_handle.tcp.flags = sock->uv_handle.tcp.flags;
-               sock->parent->fd = sock->fd;
        } else {
-               /* The socket is already bound, just copy the flags */
-               sock->uv_handle.tcp.flags = sock->parent->uv_handle.tcp.flags;
+               if (sock->parent->fd == -1) {
+                       r = isc_uv_tcp_freebind(&sock->uv_handle.tcp,
+                                               &sock->iface.type.sa, flags);
+                       if (r < 0) {
+                               isc__nm_incstats(sock->mgr, STATID_BINDFAIL);
+                               goto done;
+                       }
+                       sock->parent->uv_handle.tcp.flags =
+                               sock->uv_handle.tcp.flags;
+                       sock->parent->fd = sock->fd;
+               } else {
+                       /* The socket is already bound, just copy the flags */
+                       sock->uv_handle.tcp.flags =
+                               sock->parent->uv_handle.tcp.flags;
+               }
        }
-#endif
 
        /*
         * The callback will run in the same thread uv_listen() was called
index 2e87260f1eadd751d58819df025f3a0c0f174af1..f5b2ec56b6e37a34e42e5668ca7be0e4a0d4741f 100644 (file)
@@ -318,7 +318,7 @@ isc_nm_tcpdnsconnect(isc_nm_t *mgr, isc_sockaddr_t *local, isc_sockaddr_t *peer,
 }
 
 static uv_os_sock_t
-isc__nm_tcpdns_lb_socket(sa_family_t sa_family) {
+isc__nm_tcpdns_lb_socket(isc_nm_t *mgr, sa_family_t sa_family) {
        isc_result_t result;
        uv_os_sock_t sock;
 
@@ -332,10 +332,10 @@ isc__nm_tcpdns_lb_socket(sa_family_t sa_family) {
        result = isc__nm_socket_reuse(sock);
        RUNTIME_CHECK(result == ISC_R_SUCCESS);
 
-#if HAVE_SO_REUSEPORT_LB
-       result = isc__nm_socket_reuse_lb(sock);
-       RUNTIME_CHECK(result == ISC_R_SUCCESS);
-#endif
+       if (mgr->load_balance_sockets) {
+               result = isc__nm_socket_reuse_lb(sock);
+               RUNTIME_CHECK(result == ISC_R_SUCCESS);
+       }
 
        return (sock);
 }
@@ -370,12 +370,13 @@ start_tcpdns_child(isc_nm_t *mgr, isc_sockaddr_t *iface, isc_nmsocket_t *sock,
        csock->pquota = sock->pquota;
        isc_quota_cb_init(&csock->quotacb, quota_accept_cb, csock);
 
-#if HAVE_SO_REUSEPORT_LB || defined(WIN32)
-       UNUSED(fd);
-       csock->fd = isc__nm_tcpdns_lb_socket(iface->type.sa.sa_family);
-#else
-       csock->fd = dup(fd);
-#endif
+       if (mgr->load_balance_sockets) {
+               UNUSED(fd);
+               csock->fd = isc__nm_tcpdns_lb_socket(mgr,
+                                                    iface->type.sa.sa_family);
+       } else {
+               csock->fd = dup(fd);
+       }
        REQUIRE(csock->fd >= 0);
 
        ievent = isc__nm_get_netievent_tcpdnslisten(mgr, csock);
@@ -420,9 +421,9 @@ isc_nm_listentcpdns(isc_nm_t *mgr, isc_sockaddr_t *iface,
        sock->tid = 0;
        sock->fd = -1;
 
-#if !HAVE_SO_REUSEPORT_LB && !defined(WIN32)
-       fd = isc__nm_tcpdns_lb_socket(iface->type.sa.sa_family);
-#endif
+       if (!mgr->load_balance_sockets) {
+               fd = isc__nm_tcpdns_lb_socket(mgr, iface->type.sa.sa_family);
+       }
 
        isc_barrier_init(&sock->startlistening, sock->nchildren);
 
@@ -437,9 +438,9 @@ isc_nm_listentcpdns(isc_nm_t *mgr, isc_sockaddr_t *iface,
                start_tcpdns_child(mgr, iface, sock, fd, isc_nm_tid());
        }
 
-#if !HAVE_SO_REUSEPORT_LB && !defined(WIN32)
-       isc__nm_closesocket(fd);
-#endif
+       if (!mgr->load_balance_sockets) {
+               isc__nm_closesocket(fd);
+       }
 
        LOCK(&sock->lock);
        while (atomic_load(&sock->rchildren) != sock->nchildren) {
@@ -472,6 +473,7 @@ isc__nm_async_tcpdnslisten(isc__networker_t *worker, isc__netievent_t *ev0) {
        int flags = 0;
        isc_nmsocket_t *sock = NULL;
        isc_result_t result = ISC_R_UNSET;
+       isc_nm_t *mgr = NULL;
 
        REQUIRE(VALID_NMSOCK(ievent->sock));
        REQUIRE(ievent->sock->tid == isc_nm_tid());
@@ -479,6 +481,7 @@ isc__nm_async_tcpdnslisten(isc__networker_t *worker, isc__netievent_t *ev0) {
 
        sock = ievent->sock;
        sa_family = sock->iface.type.sa.sa_family;
+       mgr = sock->mgr;
 
        REQUIRE(sock->type == isc_nm_tcpdnssocket);
        REQUIRE(sock->parent != NULL);
@@ -510,15 +513,7 @@ isc__nm_async_tcpdnslisten(isc__networker_t *worker, isc__netievent_t *ev0) {
                flags = UV_TCP_IPV6ONLY;
        }
 
-#if HAVE_SO_REUSEPORT_LB || defined(WIN32)
-       r = isc_uv_tcp_freebind(&sock->uv_handle.tcp, &sock->iface.type.sa,
-                               flags);
-       if (r < 0) {
-               isc__nm_incstats(sock->mgr, sock->statsindex[STATID_BINDFAIL]);
-               goto done;
-       }
-#else
-       if (sock->parent->fd == -1) {
+       if (mgr->load_balance_sockets) {
                r = isc_uv_tcp_freebind(&sock->uv_handle.tcp,
                                        &sock->iface.type.sa, flags);
                if (r < 0) {
@@ -526,13 +521,23 @@ isc__nm_async_tcpdnslisten(isc__networker_t *worker, isc__netievent_t *ev0) {
                                         sock->statsindex[STATID_BINDFAIL]);
                        goto done;
                }
-               sock->parent->uv_handle.tcp.flags = sock->uv_handle.tcp.flags;
-               sock->parent->fd = sock->fd;
        } else {
-               /* The socket is already bound, just copy the flags */
-               sock->uv_handle.tcp.flags = sock->parent->uv_handle.tcp.flags;
+               if (sock->parent->fd == -1) {
+                       r = isc_uv_tcp_freebind(&sock->uv_handle.tcp,
+                                               &sock->iface.type.sa, flags);
+                       if (r < 0) {
+                               isc__nm_incstats(sock->mgr, STATID_BINDFAIL);
+                               goto done;
+                       }
+                       sock->parent->uv_handle.tcp.flags =
+                               sock->uv_handle.tcp.flags;
+                       sock->parent->fd = sock->fd;
+               } else {
+                       /* The socket is already bound, just copy the flags */
+                       sock->uv_handle.tcp.flags =
+                               sock->parent->uv_handle.tcp.flags;
+               }
        }
-#endif
 
        /*
         * The callback will run in the same thread uv_listen() was called
index 8a35889b510b6f39ed260a34bd939cbeeecdad8f..9a6546026157e8e1f6f93bcc79efae7746342e45 100644 (file)
@@ -59,7 +59,7 @@ static void
 stop_udp_child(isc_nmsocket_t *sock);
 
 static uv_os_sock_t
-isc__nm_udp_lb_socket(sa_family_t sa_family) {
+isc__nm_udp_lb_socket(isc_nm_t *mgr, sa_family_t sa_family) {
        isc_result_t result;
        uv_os_sock_t sock;
 
@@ -72,10 +72,10 @@ isc__nm_udp_lb_socket(sa_family_t sa_family) {
        result = isc__nm_socket_reuse(sock);
        RUNTIME_CHECK(result == ISC_R_SUCCESS);
 
-#if HAVE_SO_REUSEPORT_LB
-       result = isc__nm_socket_reuse_lb(sock);
-       RUNTIME_CHECK(result == ISC_R_SUCCESS);
-#endif
+       if (mgr->load_balance_sockets) {
+               result = isc__nm_socket_reuse_lb(sock);
+               RUNTIME_CHECK(result == ISC_R_SUCCESS);
+       }
 
        return (sock);
 }
@@ -97,12 +97,13 @@ start_udp_child(isc_nm_t *mgr, isc_sockaddr_t *iface, isc_nmsocket_t *sock,
        csock->extrahandlesize = sock->extrahandlesize;
        csock->tid = tid;
 
-#if HAVE_SO_REUSEPORT_LB || defined(WIN32)
-       UNUSED(fd);
-       csock->fd = isc__nm_udp_lb_socket(iface->type.sa.sa_family);
-#else
-       csock->fd = dup(fd);
-#endif
+       if (mgr->load_balance_sockets) {
+               UNUSED(fd);
+               csock->fd = isc__nm_udp_lb_socket(mgr,
+                                                 iface->type.sa.sa_family);
+       } else {
+               csock->fd = dup(fd);
+       }
        REQUIRE(csock->fd >= 0);
 
        ievent = isc__nm_get_netievent_udplisten(mgr, csock);
@@ -153,9 +154,9 @@ isc_nm_listenudp(isc_nm_t *mgr, isc_sockaddr_t *iface, isc_nm_recv_cb_t cb,
        sock->tid = 0;
        sock->fd = -1;
 
-#if !HAVE_SO_REUSEPORT_LB && !defined(WIN32)
-       fd = isc__nm_udp_lb_socket(iface->type.sa.sa_family);
-#endif
+       if (!mgr->load_balance_sockets) {
+               fd = isc__nm_udp_lb_socket(mgr, iface->type.sa.sa_family);
+       }
 
        isc_barrier_init(&sock->startlistening, sock->nchildren);
 
@@ -170,9 +171,9 @@ isc_nm_listenudp(isc_nm_t *mgr, isc_sockaddr_t *iface, isc_nm_recv_cb_t cb,
                start_udp_child(mgr, iface, sock, fd, isc_nm_tid());
        }
 
-#if !HAVE_SO_REUSEPORT_LB && !defined(WIN32)
-       isc__nm_closesocket(fd);
-#endif
+       if (!mgr->load_balance_sockets) {
+               isc__nm_closesocket(fd);
+       }
 
        LOCK(&sock->lock);
        while (atomic_load(&sock->rchildren) != sock->nchildren) {
@@ -207,6 +208,7 @@ isc__nm_async_udplisten(isc__networker_t *worker, isc__netievent_t *ev0) {
        int uv_init_flags = 0;
        sa_family_t sa_family;
        isc_result_t result = ISC_R_UNSET;
+       isc_nm_t *mgr = NULL;
 
        REQUIRE(VALID_NMSOCK(ievent->sock));
        REQUIRE(ievent->sock->tid == isc_nm_tid());
@@ -214,6 +216,7 @@ isc__nm_async_udplisten(isc__networker_t *worker, isc__netievent_t *ev0) {
 
        sock = ievent->sock;
        sa_family = sock->iface.type.sa.sa_family;
+       mgr = sock->mgr;
 
        REQUIRE(sock->type == isc_nm_udpsocket);
        REQUIRE(sock->parent != NULL);
@@ -246,16 +249,7 @@ isc__nm_async_udplisten(isc__networker_t *worker, isc__netievent_t *ev0) {
                uv_bind_flags |= UV_UDP_IPV6ONLY;
        }
 
-#if HAVE_SO_REUSEPORT_LB || defined(WIN32)
-       r = isc_uv_udp_freebind(&sock->uv_handle.udp,
-                               &sock->parent->iface.type.sa, uv_bind_flags);
-       if (r < 0) {
-               isc__nm_incstats(sock->mgr, sock->statsindex[STATID_BINDFAIL]);
-               goto done;
-       }
-#else
-       if (sock->parent->fd == -1) {
-               /* This thread is first, bind the socket */
+       if (mgr->load_balance_sockets) {
                r = isc_uv_udp_freebind(&sock->uv_handle.udp,
                                        &sock->parent->iface.type.sa,
                                        uv_bind_flags);
@@ -264,13 +258,25 @@ isc__nm_async_udplisten(isc__networker_t *worker, isc__netievent_t *ev0) {
                                         sock->statsindex[STATID_BINDFAIL]);
                        goto done;
                }
-               sock->parent->uv_handle.udp.flags = sock->uv_handle.udp.flags;
-               sock->parent->fd = sock->fd;
        } else {
-               /* The socket is already bound, just copy the flags */
-               sock->uv_handle.udp.flags = sock->parent->uv_handle.udp.flags;
+               if (sock->parent->fd == -1) {
+                       /* This thread is first, bind the socket */
+                       r = isc_uv_udp_freebind(&sock->uv_handle.udp,
+                                               &sock->parent->iface.type.sa,
+                                               uv_bind_flags);
+                       if (r < 0) {
+                               isc__nm_incstats(sock->mgr, STATID_BINDFAIL);
+                               goto done;
+                       }
+                       sock->parent->uv_handle.udp.flags =
+                               sock->uv_handle.udp.flags;
+                       sock->parent->fd = sock->fd;
+               } else {
+                       /* The socket is already bound, just copy the flags */
+                       sock->uv_handle.udp.flags =
+                               sock->parent->uv_handle.udp.flags;
+               }
        }
-#endif
 
 #ifdef ISC_RECV_BUFFER_SIZE
        uv_recv_buffer_size(&sock->uv_handle.handle,
index ab7ad73d202ec5bbfff914a76d175900f0286ed2..c68f6f66782abb63bda95a729e483a71f7db35c7 100644 (file)
@@ -472,6 +472,7 @@ isc_nm_read
 isc_nm_resume
 isc_nm_resumeread
 isc_nm_send
+isc_nm_setloadbalancesockets
 isc_nm_setstats
 isc_nm_settimeouts
 isc_nm_stoplistening
index 3526afd6dbf8b9fc1242a376f8af18b78a5562d6..d86f6f7105e7dd2343496e39d2ba06a1594e8f54 100644 (file)
@@ -1222,6 +1222,7 @@ static cfg_clausedef_t options_clauses[] = {
        { "keep-response-order", &cfg_type_bracketed_aml, 0 },
        { "listen-on", &cfg_type_listenon, CFG_CLAUSEFLAG_MULTI },
        { "listen-on-v6", &cfg_type_listenon, CFG_CLAUSEFLAG_MULTI },
+       { "load-balance-sockets", &cfg_type_boolean, 0 },
        { "lock-file", &cfg_type_qstringornone, 0 },
        { "managed-keys-directory", &cfg_type_qstring, 0 },
        { "match-mapped-addresses", &cfg_type_boolean, 0 },