]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
3939. [func] Improve UPDATE forwarding performance by allowing TCP
authorMark Andrews <marka@isc.org>
Thu, 4 Sep 2014 00:37:45 +0000 (10:37 +1000)
committerMark Andrews <marka@isc.org>
Thu, 4 Sep 2014 00:37:45 +0000 (10:37 +1000)
                        connections to be shared. [RT #37039]

12 files changed:
CHANGES
bin/tests/system/nsupdate/clean.sh
bin/tests/system/nsupdate/ns1/many.test.db.in [new file with mode: 0644]
bin/tests/system/nsupdate/ns1/named.conf
bin/tests/system/nsupdate/ns3/named.conf
bin/tests/system/nsupdate/setup.sh
bin/tests/system/nsupdate/tests.sh
lib/dns/dispatch.c
lib/dns/include/dns/dispatch.h
lib/dns/request.c
lib/dns/win32/libdns.def.in
lib/dns/zone.c

diff --git a/CHANGES b/CHANGES
index 7b30a34c81efb33482b5d6c80f3e70a5fcfaacae..43ed8c519957b36c68c27f55004959910adbae9d 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,6 @@
+3939.  [func]          Improve UPDATE forwarding performance by allowing TCP
+                       connections to be shared. [RT #37039]
+
 3938.  [placeholder]
 
 3937.  [func]          Added some debug logging to better indicate the
index 424cdf40c6a329724ee767a06eb16300fec806be..d4c1113fa230647af9485b30eea603439566ac93 100644 (file)
@@ -36,3 +36,5 @@ rm -f dig.out.*
 rm -f jp.out.ns3.*
 rm -f Kxxx.*
 rm -f typelist.out.*
+rm -f ns1/many.test.db ns3/many.test.db.jnl
+rm -f ns3/many.test.bk ns3/many.test.bk.jnl
diff --git a/bin/tests/system/nsupdate/ns1/many.test.db.in b/bin/tests/system/nsupdate/ns1/many.test.db.in
new file mode 100644 (file)
index 0000000..955e95d
--- /dev/null
@@ -0,0 +1,25 @@
+; Copyright (C) 2014  Internet Systems Consortium, Inc. ("ISC")
+;
+; Permission to use, copy, modify, and/or distribute this software for any
+; purpose with or without fee is hereby granted, provided that the above
+; copyright notice and this permission notice appear in all copies.
+;
+; THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+; REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+; AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+; INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+; LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+; OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+; PERFORMANCE OF THIS SOFTWARE.
+
+$ORIGIN .
+$TTL 300       ; 5 minutes
+many.test      IN SOA  ns1.example.nil. hostmaster.example.nil. (
+                               1          ; serial
+                               2000       ; refresh (2000 seconds)
+                               2000       ; retry (2000 seconds)
+                               1814400    ; expire (3 weeks)
+                               3600       ; minimum (1 hour)
+                               )
+many.test              NS      ns1.example.nil.
+many.test              NS      ns2.example.nil.
index f9e3b20d30e9d0f5c89ee976b21299ccf3020d6d..4263e381e455e8bb7acc9134dab340395135c1cc 100644 (file)
@@ -127,3 +127,9 @@ zone "keytests.nil" {
            grant sha512-key name sha512.keytests.nil. ANY;
        };
 };
+
+zone "many.test" {
+        type master;
+        allow-update { any; };
+        file "many.test.db";
+};
index 2abd522510e4e78444b19fc1f5d86a59af39e04a..8606b53f7db7a9464e68a4f343d15d20a36ad200 100644 (file)
@@ -16,7 +16,7 @@
 
 /* $Id: named.conf,v 1.5 2011/02/03 12:18:11 tbox Exp $ */
 
-// NS1
+// NS3
 
 controls { /* empty */ };
 
@@ -60,3 +60,10 @@ zone "dnskey.test" {
        allow-update { any; };
        file "dnskey.test.db.signed";
 };
+
+zone "many.test" {
+       type slave;
+       masters { 10.53.0.1; };
+       allow-update-forwarding { any; };
+       file "many.test.bk";
+};
index e3528dbf7e8871995ca919d103f9896bbc7d074d..eb048976ebaa9fed556e27ff9807981ba6c601d4 100644 (file)
@@ -62,3 +62,6 @@ $DDNSCONFGEN -q -r $RANDFILE -a hmac-sha384 -k sha384-key -z keytests.nil > ns1/
 $DDNSCONFGEN -q -r $RANDFILE -a hmac-sha512 -k sha512-key -z keytests.nil > ns1/sha512.key
 
 (cd ns3; $SHELL -e sign.sh)
+
+cp -f ns1/many.test.db.in ns1/many.test.db
+rm -f ns1/many.test.db.jnl
index 7dad50fef3e567ce0cebc16a1afea9b43a466ef6..309aa6b514d6dde9fb2d0a449fcc80dd12b9f017 100755 (executable)
@@ -597,5 +597,31 @@ serial=`$DIG +short yyyymmddvv.nil. soa @10.53.0.1 -p 5300 | awk '{print $3}'` |
 [ "$serial" -eq "$now" ] || ret=1
 [ $ret = 0 ] || { echo I:failed; status=1; }
 
+n=`expr $n + 1`
+echo "I:send many simultaneous updates via a update forwarder ($n)"
+ret=0
+for i in 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
+do
+(
+    for j in 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
+    do
+    (
+       $NSUPDATE << EOF
+server 10.53.0.3 5300
+zone many.test
+update add $i-$j.many.test 0 IN A 1.2.3.4
+send
+EOF
+    ) &
+    done
+    wait
+) &
+done
+wait
+dig axfr many.test @10.53.0.1 -p 5300 > dig.out.test$n
+lines=`awk '$4 == "A" { l++ } END { print l }' dig.out.test$n`
+test ${lines:-0} -eq 289 || ret=1
+[ $ret = 0 ] || { echo I:failed; status=1; }
+
 echo "I:exit status: $status"
 exit $status
index 5a90ee5e7b7e47073544d870c2a06182c6317399..9bfd6b98374d72920e4d1e85034fb42c76a74f42 100644 (file)
@@ -218,6 +218,7 @@ struct dns_dispatch {
        isc_socket_t           *socket;         /*%< isc socket attached to */
        isc_sockaddr_t          local;          /*%< local address */
        in_port_t               localport;      /*%< local UDP port */
+       isc_sockaddr_t          peer;           /*%< peer address (TCP) */
        isc_dscp_t              dscp;           /*%< "listen-on" DSCP value */
        unsigned int            maxrequests;    /*%< max requests */
        isc_event_t            *ctlevent;
@@ -2126,7 +2127,6 @@ dns_dispatchmgr_destroy(dns_dispatchmgr_t **mgrp) {
 
        LOCK(&mgr->lock);
        mgr->state |= MGR_SHUTTINGDOWN;
-
        killit = destroy_mgr_ok(mgr);
        UNLOCK(&mgr->lock);
 
@@ -2400,6 +2400,7 @@ dispatch_allocate(dns_dispatchmgr_t *mgr, unsigned int maxrequests,
        disp->refcount = 1;
        disp->recv_pending = 0;
        memset(&disp->local, 0, sizeof(disp->local));
+       memset(&disp->peer, 0, sizeof(disp->peer));
        disp->localport = 0;
        disp->shutting_down = 0;
        disp->shutdown_out = 0;
@@ -2507,6 +2508,23 @@ dns_dispatch_createtcp(dns_dispatchmgr_t *mgr, isc_socket_t *sock,
                       unsigned int buckets, unsigned int increment,
                       unsigned int attributes, dns_dispatch_t **dispp)
 {
+
+       attributes |= DNS_DISPATCHATTR_PRIVATE;  /* XXXMLG */
+
+       return (dns_dispatch_createtcp2(mgr, sock, taskmgr, NULL, NULL,
+                                       buffersize, maxbuffers, maxrequests,
+                                       buckets, increment, attributes,
+                                       dispp));
+}
+
+isc_result_t
+dns_dispatch_createtcp2(dns_dispatchmgr_t *mgr, isc_socket_t *sock,
+                       isc_taskmgr_t *taskmgr, isc_sockaddr_t *localaddr,
+                       isc_sockaddr_t *destaddr, unsigned int buffersize,
+                       unsigned int maxbuffers, unsigned int maxrequests,
+                       unsigned int buckets, unsigned int increment,
+                       unsigned int attributes, dns_dispatch_t **dispp)
+{
        isc_result_t result;
        dns_dispatch_t *disp;
 
@@ -2518,7 +2536,8 @@ dns_dispatch_createtcp(dns_dispatchmgr_t *mgr, isc_socket_t *sock,
        REQUIRE((attributes & DNS_DISPATCHATTR_TCP) != 0);
        REQUIRE((attributes & DNS_DISPATCHATTR_UDP) == 0);
 
-       attributes |= DNS_DISPATCHATTR_PRIVATE;  /* XXXMLG */
+       if (destaddr == NULL)
+               attributes |= DNS_DISPATCHATTR_PRIVATE;  /* XXXMLG */
 
        LOCK(&mgr->lock);
 
@@ -2565,6 +2584,23 @@ dns_dispatch_createtcp(dns_dispatchmgr_t *mgr, isc_socket_t *sock,
 
        disp->attributes = attributes;
 
+       if (localaddr == NULL) {
+               if (destaddr != NULL) {
+                       switch (isc_sockaddr_pf(destaddr)) {
+                       case AF_INET:
+                               isc_sockaddr_any(&disp->local);
+                               break;
+                       case AF_INET6:
+                               isc_sockaddr_any6(&disp->local);
+                               break;
+                       }
+               }
+       } else
+               disp->local = *localaddr;
+
+       if (destaddr != NULL)
+               disp->peer = *destaddr;
+
        /*
         * Append it to the dispatcher list.
         */
@@ -2573,7 +2609,6 @@ dns_dispatch_createtcp(dns_dispatchmgr_t *mgr, isc_socket_t *sock,
 
        mgr_log(mgr, LVL(90), "created TCP dispatcher %p", disp);
        dispatch_log(disp, LVL(90), "created task %p", disp->task[0]);
-
        *dispp = disp;
 
        return (ISC_R_SUCCESS);
@@ -2593,6 +2628,69 @@ dns_dispatch_createtcp(dns_dispatchmgr_t *mgr, isc_socket_t *sock,
        return (result);
 }
 
+isc_result_t
+dns_dispatch_gettcp(dns_dispatchmgr_t *mgr, isc_sockaddr_t *destaddr,
+                   isc_sockaddr_t *localaddr, dns_dispatch_t **dispp)
+{
+       dns_dispatch_t *disp;
+       isc_result_t result;
+       isc_sockaddr_t peeraddr;
+       isc_sockaddr_t sockname;
+       isc_sockaddr_t any;
+       unsigned int attributes, mask;
+       isc_boolean_t match = ISC_FALSE;
+
+       REQUIRE(VALID_DISPATCHMGR(mgr));
+       REQUIRE(destaddr != NULL);
+       REQUIRE(dispp != NULL && *dispp == NULL);
+
+       attributes = DNS_DISPATCHATTR_TCP;
+       mask = DNS_DISPATCHATTR_TCP | DNS_DISPATCHATTR_PRIVATE |
+              DNS_DISPATCHATTR_EXCLUSIVE;
+
+       if (localaddr == NULL) {
+               switch (isc_sockaddr_pf(destaddr)) {
+               case AF_INET:
+                       isc_sockaddr_any(&any);
+                       break;
+               case AF_INET6:
+                       isc_sockaddr_any6(&any);
+                       break;
+               default:
+                       return (ISC_R_NOTFOUND);
+               }
+               localaddr = &any;
+       }
+
+       LOCK(&mgr->lock);
+       disp = ISC_LIST_HEAD(mgr->list);
+       while (disp != NULL && !match) {
+               LOCK(&disp->lock);
+               if ((disp->shutting_down == 0) &&
+                   ATTRMATCH(disp->attributes, attributes, mask) &&
+                   (localaddr == NULL ||
+                    isc_sockaddr_eqaddr(localaddr, &disp->local))) {
+                       result = isc_socket_getsockname(disp->socket,
+                                                       &sockname);
+                       if (result == ISC_R_SUCCESS)
+                               result = isc_socket_getpeername(disp->socket,
+                                                               &peeraddr);
+                       if (result == ISC_R_SUCCESS &&
+                           isc_sockaddr_equal(destaddr, &peeraddr) &&
+                           isc_sockaddr_eqaddr(localaddr, &sockname)) {
+                               /* attach */
+                               disp->refcount++;
+                               *dispp = disp;
+                               match = ISC_TRUE;
+                       }
+               }
+               UNLOCK(&disp->lock);
+               disp = ISC_LIST_NEXT(disp, link);
+       }
+       UNLOCK(&mgr->lock);
+       return (match ? ISC_R_SUCCESS : ISC_R_NOTFOUND);
+}
+
 isc_result_t
 dns_dispatch_getudp_dup(dns_dispatchmgr_t *mgr, isc_socketmgr_t *sockmgr,
                    isc_taskmgr_t *taskmgr, isc_sockaddr_t *localaddr,
index ef5b9179ddd2743091d1751f8784d801f8b1348d..358a85984b919a340280fc2ca5b3f01a4fb484e3 100644 (file)
@@ -298,6 +298,13 @@ dns_dispatch_createtcp(dns_dispatchmgr_t *mgr, isc_socket_t *sock,
                       unsigned int maxbuffers, unsigned int maxrequests,
                       unsigned int buckets, unsigned int increment,
                       unsigned int attributes, dns_dispatch_t **dispp);
+isc_result_t
+dns_dispatch_createtcp2(dns_dispatchmgr_t *mgr, isc_socket_t *sock,
+                        isc_taskmgr_t *taskmgr, isc_sockaddr_t *localaddr,
+                        isc_sockaddr_t *destaddr, unsigned int buffersize,
+                        unsigned int maxbuffers, unsigned int maxrequests,
+                        unsigned int buckets, unsigned int increment,
+                        unsigned int attributes, dns_dispatch_t **dispp);
 /*%<
  * Create a new dns_dispatch and attach it to the provided isc_socket_t.
  *
@@ -369,6 +376,14 @@ dns_dispatch_starttcp(dns_dispatch_t *disp);
  *\li  'disp' is valid.
  */
 
+isc_result_t
+dns_dispatch_gettcp(dns_dispatchmgr_t *mgr, isc_sockaddr_t *destaddr,
+                    isc_sockaddr_t *localaddr, dns_dispatch_t **dispp);
+/*
+ * Attempt to connect to a existing TCP connection.
+ */
+
+
 isc_result_t
 dns_dispatch_addresponse2(dns_dispatch_t *disp, isc_sockaddr_t *dest,
                          isc_task_t *task, isc_taskaction_t action, void *arg,
index b21786875c49156d4cff7e516028189478681203..be8072c632eed4962c8f3fbeb6a5bac406da6dd6 100644 (file)
@@ -525,7 +525,7 @@ isblackholed(dns_dispatchmgr_t *dispatchmgr, isc_sockaddr_t *destaddr) {
 static isc_result_t
 create_tcp_dispatch(dns_requestmgr_t *requestmgr, isc_sockaddr_t *srcaddr,
                    isc_sockaddr_t *destaddr, isc_dscp_t dscp,
-                   dns_dispatch_t **dispatchp)
+                   isc_boolean_t *connected, dns_dispatch_t **dispatchp)
 {
        isc_result_t result;
        isc_socket_t *socket = NULL;
@@ -533,6 +533,17 @@ create_tcp_dispatch(dns_requestmgr_t *requestmgr, isc_sockaddr_t *srcaddr,
        unsigned int attrs;
        isc_sockaddr_t bind_any;
 
+       result = dns_dispatch_gettcp(requestmgr->dispatchmgr, destaddr,
+                                    srcaddr, dispatchp);
+       if (result == ISC_R_SUCCESS) {
+               *connected = ISC_TRUE;
+               char peer[ISC_SOCKADDR_FORMATSIZE];
+               isc_sockaddr_format(destaddr, peer, sizeof(peer));
+               req_log(ISC_LOG_DEBUG(1), "attached to existing TCP "
+                       "connection to %s", peer);
+               return (result);
+       }
+
        result = isc_socket_create(requestmgr->socketmgr,
                                   isc_sockaddr_pf(destaddr),
                                   isc_sockettype_tcp, &socket);
@@ -554,7 +565,6 @@ create_tcp_dispatch(dns_requestmgr_t *requestmgr, isc_sockaddr_t *srcaddr,
 
        attrs = 0;
        attrs |= DNS_DISPATCHATTR_TCP;
-       attrs |= DNS_DISPATCHATTR_PRIVATE;
        if (isc_sockaddr_pf(destaddr) == AF_INET)
                attrs |= DNS_DISPATCHATTR_IPV4;
        else
@@ -562,10 +572,11 @@ create_tcp_dispatch(dns_requestmgr_t *requestmgr, isc_sockaddr_t *srcaddr,
        attrs |= DNS_DISPATCHATTR_MAKEQUERY;
 
        isc_socket_dscp(socket, dscp);
-       result = dns_dispatch_createtcp(requestmgr->dispatchmgr,
-                                       socket, requestmgr->taskmgr,
-                                       4096, 2, 1, 1, 3, attrs,
-                                       dispatchp);
+       result = dns_dispatch_createtcp2(requestmgr->dispatchmgr,
+                                        socket, requestmgr->taskmgr,
+                                        srcaddr, destaddr,
+                                        4096, 32768, 32768, 16411, 16433,
+                                        attrs, dispatchp);
 cleanup:
        isc_socket_detach(&socket);
        return (result);
@@ -627,12 +638,15 @@ find_udp_dispatch(dns_requestmgr_t *requestmgr, isc_sockaddr_t *srcaddr,
 static isc_result_t
 get_dispatch(isc_boolean_t tcp, dns_requestmgr_t *requestmgr,
             isc_sockaddr_t *srcaddr, isc_sockaddr_t *destaddr,
-            isc_dscp_t dscp, dns_dispatch_t **dispatchp)
+            isc_dscp_t dscp, isc_boolean_t *connected,
+            dns_dispatch_t **dispatchp)
 {
        isc_result_t result;
+
        if (tcp)
                result = create_tcp_dispatch(requestmgr, srcaddr,
-                                            destaddr, dscp, dispatchp);
+                                            destaddr, dscp, connected,
+                                            dispatchp);
        else
                result = find_udp_dispatch(requestmgr, srcaddr,
                                           destaddr, dispatchp);
@@ -719,6 +733,7 @@ dns_request_createraw4(dns_requestmgr_t *requestmgr, isc_buffer_t *msgbuf,
        dns_messageid_t id;
        isc_boolean_t tcp = ISC_FALSE;
        isc_region_t r;
+       isc_boolean_t connected = ISC_FALSE;
 
        REQUIRE(VALID_REQUESTMGR(requestmgr));
        REQUIRE(msgbuf != NULL);
@@ -781,7 +796,7 @@ dns_request_createraw4(dns_requestmgr_t *requestmgr, isc_buffer_t *msgbuf,
                tcp = ISC_TRUE;
 
        result = get_dispatch(tcp, requestmgr, srcaddr, destaddr, dscp,
-                             &request->dispatch);
+                             &connected, &request->dispatch);
        if (result != ISC_R_SUCCESS)
                goto cleanup;
 
@@ -828,14 +843,14 @@ dns_request_createraw4(dns_requestmgr_t *requestmgr, isc_buffer_t *msgbuf,
                goto unlink;
 
        request->destaddr = *destaddr;
-       if (tcp) {
+       if (tcp && !connected) {
                result = isc_socket_connect(socket, destaddr, task,
                                            req_connected, request);
                if (result != ISC_R_SUCCESS)
                        goto unlink;
                request->flags |= DNS_REQUEST_F_CONNECTING|DNS_REQUEST_F_TCP;
        } else {
-               result = req_send(request, task, destaddr);
+               result = req_send(request, task, connected ? NULL : destaddr);
                if (result != ISC_R_SUCCESS)
                        goto unlink;
        }
@@ -935,6 +950,7 @@ dns_request_createvia4(dns_requestmgr_t *requestmgr, dns_message_t *message,
        dns_messageid_t id;
        isc_boolean_t tcp;
        isc_boolean_t setkey = ISC_TRUE;
+       isc_boolean_t connected = ISC_FALSE;
 
        REQUIRE(VALID_REQUESTMGR(requestmgr));
        REQUIRE(message != NULL);
@@ -994,7 +1010,7 @@ dns_request_createvia4(dns_requestmgr_t *requestmgr, dns_message_t *message,
  use_tcp:
        tcp = ISC_TF((options & DNS_REQUESTOPT_TCP) != 0);
        result = get_dispatch(tcp, requestmgr, srcaddr, destaddr, dscp,
-                             &request->dispatch);
+                             &connected, &request->dispatch);
        if (result != ISC_R_SUCCESS)
                goto cleanup;
 
@@ -1050,14 +1066,14 @@ dns_request_createvia4(dns_requestmgr_t *requestmgr, dns_message_t *message,
                goto unlink;
 
        request->destaddr = *destaddr;
-       if (tcp) {
+       if (tcp && !connected) {
                result = isc_socket_connect(socket, destaddr, task,
                                            req_connected, request);
                if (result != ISC_R_SUCCESS)
                        goto unlink;
                request->flags |= DNS_REQUEST_F_CONNECTING|DNS_REQUEST_F_TCP;
        } else {
-               result = req_send(request, task, destaddr);
+               result = req_send(request, task, connected ? NULL : destaddr);
                if (result != ISC_R_SUCCESS)
                        goto unlink;
        }
index 422f21c3eefb38b74dc327963c4cb1296faea97e..7cb9b7665d65f747002bdbb095a5691df864af77 100644 (file)
@@ -209,10 +209,12 @@ dns_dispatch_attach
 dns_dispatch_cancel
 dns_dispatch_changeattributes
 dns_dispatch_createtcp
+dns_dispatch_createtcp2
 dns_dispatch_detach
 dns_dispatch_getdscp
 dns_dispatch_getlocaladdress
 dns_dispatch_getsocket
+dns_dispatch_gettcp
 dns_dispatch_getudp
 dns_dispatch_getudp_dup
 dns_dispatch_importrecv
index b1c0f544e8784ecd2b290c19bc85dc2cde4f9859..709d5f8dd41c65542dc1a7f9c283c1644ff773cd 100644 (file)
@@ -14927,12 +14927,12 @@ sendtomaster(dns_forward_t *forward) {
                goto unlock;
        }
        result = dns_request_createraw4(forward->zone->view->requestmgr,
-                                      forward->msgbuf,
-                                      &src, &forward->addr, dscp,
-                                      DNS_REQUESTOPT_TCP, 15 /* XXX */,
-                                      0, 0, forward->zone->task,
-                                      forward_callback, forward,
-                                      &forward->request);
+                                       forward->msgbuf,
+                                       &src, &forward->addr, dscp,
+                                       DNS_REQUESTOPT_TCP, 15 /* XXX */,
+                                       0, 0, forward->zone->task,
+                                       forward_callback, forward,
+                                       &forward->request);
        if (result == ISC_R_SUCCESS) {
                if (!ISC_LINK_LINKED(forward, link))
                        ISC_LIST_APPEND(forward->zone->forwards, forward, link);