From f34cc4f62cd6730fc315ace47b9ae90a82a07ec0 Mon Sep 17 00:00:00 2001 From: Mark Andrews Date: Thu, 4 Sep 2014 10:37:45 +1000 Subject: [PATCH] 3939. [func] Improve UPDATE forwarding performance by allowing TCP connections to be shared. [RT #37039] (cherry picked from commit 74717eef53ba5d6aefc80eb262bbb090ff4bb3b5) --- lib/dns/dispatch.c | 112 ++++++++++++++++++++++++++++++++- lib/dns/include/dns/dispatch.h | 15 +++++ lib/dns/request.c | 46 ++++++++++---- lib/dns/win32/libdns.def | 2 + 4 files changed, 159 insertions(+), 16 deletions(-) diff --git a/lib/dns/dispatch.c b/lib/dns/dispatch.c index c93651d..ee82241 100644 --- a/lib/dns/dispatch.c +++ b/lib/dns/dispatch.c @@ -228,6 +228,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) */ unsigned int maxrequests; /*%< max requests */ isc_event_t *ctlevent; @@ -2327,7 +2328,6 @@ dns_dispatchmgr_destroy(dns_dispatchmgr_t **mgrp) { LOCK(&mgr->lock); mgr->state |= MGR_SHUTTINGDOWN; - killit = destroy_mgr_ok(mgr); UNLOCK(&mgr->lock); @@ -2601,6 +2601,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; @@ -2702,6 +2703,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; @@ -2713,7 +2731,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); @@ -2760,6 +2779,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. */ @@ -2768,7 +2804,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); @@ -2788,6 +2823,77 @@ 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) +{ +#ifdef BIND9 + 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); +#else + UNUSED(mgr); + UNUSED(destaddr); + UNUSED(localaddr); + UNUSED(dispp); + return ISC_R_NOTIMPLEMENTED; +#endif +} + isc_result_t dns_dispatch_getudp_dup(dns_dispatchmgr_t *mgr, isc_socketmgr_t *sockmgr, isc_taskmgr_t *taskmgr, isc_sockaddr_t *localaddr, diff --git a/lib/dns/include/dns/dispatch.h b/lib/dns/include/dns/dispatch.h index 1235f7c..be9cd66 100644 --- a/lib/dns/include/dns/dispatch.h +++ b/lib/dns/include/dns/dispatch.h @@ -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, diff --git a/lib/dns/request.c b/lib/dns/request.c index 5c76f9a..9fb6f44 100644 --- a/lib/dns/request.c +++ b/lib/dns/request.c @@ -510,7 +510,8 @@ 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, dns_dispatch_t **dispatchp) + isc_sockaddr_t *destaddr, isc_boolean_t *connected, + dns_dispatch_t **dispatchp) { isc_result_t result; isc_socket_t *socket = NULL; @@ -518,6 +519,20 @@ create_tcp_dispatch(dns_requestmgr_t *requestmgr, isc_sockaddr_t *srcaddr, unsigned int attrs; isc_sockaddr_t bind_any; + *connected = ISC_FALSE; +#ifdef BIND9 + 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); + } +#endif + result = isc_socket_create(requestmgr->socketmgr, isc_sockaddr_pf(destaddr), isc_sockettype_tcp, &socket); @@ -538,16 +553,16 @@ create_tcp_dispatch(dns_requestmgr_t *requestmgr, isc_sockaddr_t *srcaddr, #endif 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_IPV6; attrs |= DNS_DISPATCHATTR_MAKEQUERY; - 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); @@ -609,12 +624,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_boolean_t *connected, dns_dispatch_t **dispatchp) { isc_result_t result; + if (tcp) result = create_tcp_dispatch(requestmgr, srcaddr, - destaddr, dispatchp); + destaddr, connected, + dispatchp); else result = find_udp_dispatch(requestmgr, srcaddr, destaddr, dispatchp); @@ -686,6 +704,7 @@ dns_request_createraw3(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); @@ -747,7 +766,7 @@ dns_request_createraw3(dns_requestmgr_t *requestmgr, isc_buffer_t *msgbuf, tcp = ISC_TRUE; result = get_dispatch(tcp, requestmgr, srcaddr, destaddr, - &request->dispatch); + &connected, &request->dispatch); if (result != ISC_R_SUCCESS) goto cleanup; @@ -794,14 +813,14 @@ dns_request_createraw3(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; } @@ -886,6 +905,7 @@ dns_request_createvia3(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); @@ -944,7 +964,7 @@ dns_request_createvia3(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, - &request->dispatch); + &connected, &request->dispatch); if (result != ISC_R_SUCCESS) goto cleanup; @@ -1000,14 +1020,14 @@ dns_request_createvia3(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; } diff --git a/lib/dns/win32/libdns.def b/lib/dns/win32/libdns.def index 5e20491..9aebe16 100644 --- a/lib/dns/win32/libdns.def +++ b/lib/dns/win32/libdns.def @@ -176,9 +176,11 @@ dns_dispatch_attach dns_dispatch_cancel dns_dispatch_changeattributes dns_dispatch_createtcp +dns_dispatch_createtcp2 dns_dispatch_detach dns_dispatch_getlocaladdress dns_dispatch_getsocket +dns_dispatch_gettcp dns_dispatch_getudp dns_dispatch_getudp_dup dns_dispatch_importrecv -- 2.20.1