+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
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
--- /dev/null
+; 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.
grant sha512-key name sha512.keytests.nil. ANY;
};
};
+
+zone "many.test" {
+ type master;
+ allow-update { any; };
+ file "many.test.db";
+};
/* $Id: named.conf,v 1.5 2011/02/03 12:18:11 tbox Exp $ */
-// NS1
+// NS3
controls { /* empty */ };
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";
+};
$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
[ "$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
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;
LOCK(&mgr->lock);
mgr->state |= MGR_SHUTTINGDOWN;
-
killit = destroy_mgr_ok(mgr);
UNLOCK(&mgr->lock);
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;
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;
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);
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.
*/
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);
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,
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.
*
*\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,
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;
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);
attrs = 0;
attrs |= DNS_DISPATCHATTR_TCP;
- attrs |= DNS_DISPATCHATTR_PRIVATE;
if (isc_sockaddr_pf(destaddr) == AF_INET)
attrs |= DNS_DISPATCHATTR_IPV4;
else
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);
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);
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);
tcp = ISC_TRUE;
result = get_dispatch(tcp, requestmgr, srcaddr, destaddr, dscp,
- &request->dispatch);
+ &connected, &request->dispatch);
if (result != ISC_R_SUCCESS)
goto cleanup;
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;
}
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);
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;
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;
}
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
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);