Commit f07b2fcc authored by Evan Hunt's avatar Evan Hunt
Browse files

3137. [func] Improve hardware scalability by allowing multiple

			worker threads to process incoming UDP packets.
			This can significantly increase query throughput
			on some systems.  [RT #22992]
parent 8181aa62
3137. [func] Improve hardware scalability by allowing multiple
worker threads to process incoming UDP packets.
This can significantly increase query throughput
on some systems. [RT #22992]
3136. [func] Add RFC 1918 reverse zones to the list of built-in
empty zones switched on by the 'empty-zones-enable'
option. [RT #24990]
......
......@@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: client.c,v 1.273 2011/05/05 23:44:52 marka Exp $ */
/* $Id: client.c,v 1.274 2011/07/28 04:04:36 each Exp $ */
#include <config.h>
......@@ -2530,8 +2530,10 @@ ns_clientmgr_createclients(ns_clientmgr_t *manager, unsigned int n,
ns_interface_t *ifp, isc_boolean_t tcp)
{
isc_result_t result = ISC_R_SUCCESS;
isc_boolean_t success = ISC_FALSE;
unsigned int i;
ns_client_t *client;
unsigned int disp;
REQUIRE(VALID_MANAGER(manager));
REQUIRE(n > 0);
......@@ -2546,61 +2548,68 @@ ns_clientmgr_createclients(ns_clientmgr_t *manager, unsigned int n,
LOCK(&manager->lock);
for (i = 0; i < n; i++) {
isc_event_t *ev;
/*
* Allocate a client. First try to get a recycled one;
* if that fails, make a new one.
*/
client = NULL;
if (!ns_g_clienttest)
client = ISC_LIST_HEAD(manager->inactive);
if (client != NULL) {
MTRACE("recycle");
ISC_LIST_UNLINK(manager->inactive, client, link);
client->list = NULL;
} else {
MTRACE("create new");
result = client_create(manager, &client);
if (result != ISC_R_SUCCESS)
break;
}
for (disp = 0; disp < n; disp++) {
for (i = 0; i < n; i++) {
isc_event_t *ev;
ns_interface_attach(ifp, &client->interface);
client->state = NS_CLIENTSTATE_READY;
INSIST(client->recursionquota == NULL);
/*
* Allocate a client. First try to get a recycled one;
* if that fails, make a new one.
*/
client = NULL;
if (!ns_g_clienttest)
client = ISC_LIST_HEAD(manager->inactive);
if (client != NULL) {
MTRACE("recycle");
ISC_LIST_UNLINK(manager->inactive, client,
link);
client->list = NULL;
} else {
MTRACE("create new");
result = client_create(manager, &client);
if (result != ISC_R_SUCCESS)
break;
}
if (tcp) {
client->attributes |= NS_CLIENTATTR_TCP;
isc_socket_attach(ifp->tcpsocket,
&client->tcplistener);
} else {
isc_socket_t *sock;
ns_interface_attach(ifp, &client->interface);
client->state = NS_CLIENTSTATE_READY;
INSIST(client->recursionquota == NULL);
dns_dispatch_attach(ifp->udpdispatch,
&client->dispatch);
sock = dns_dispatch_getsocket(client->dispatch);
isc_socket_attach(sock, &client->udpsocket);
}
client->manager = manager;
ISC_LIST_APPEND(manager->active, client, link);
client->list = &manager->active;
if (tcp) {
client->attributes |= NS_CLIENTATTR_TCP;
isc_socket_attach(ifp->tcpsocket,
&client->tcplistener);
} else {
isc_socket_t *sock;
INSIST(client->nctls == 0);
client->nctls++;
ev = &client->ctlevent;
isc_task_send(client->task, &ev);
}
if (i != 0) {
/*
* We managed to create at least one client, so we
* declare victory.
*/
result = ISC_R_SUCCESS;
dns_dispatch_attach(ifp->udpdispatch[disp],
&client->dispatch);
sock = dns_dispatch_getsocket(client->dispatch);
isc_socket_attach(sock, &client->udpsocket);
}
client->manager = manager;
ISC_LIST_APPEND(manager->active, client, link);
client->list = &manager->active;
INSIST(client->nctls == 0);
client->nctls++;
ev = &client->ctlevent;
isc_task_send(client->task, &ev);
success = ISC_TRUE;
}
}
UNLOCK(&manager->lock);
/*
* If managed to create at least one client for
* one dispatch, we declare victory.
*/
if (success)
return (ISC_R_SUCCESS);
return (result);
}
......
......@@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: interfacemgr.h,v 1.33 2007/06/19 23:46:59 tbox Exp $ */
/* $Id: interfacemgr.h,v 1.34 2011/07/28 04:04:36 each Exp $ */
#ifndef NAMED_INTERFACEMGR_H
#define NAMED_INTERFACEMGR_H 1
......@@ -65,7 +65,8 @@
#define NS_INTERFACE_VALID(t) ISC_MAGIC_VALID(t, IFACE_MAGIC)
#define NS_INTERFACEFLAG_ANYADDR 0x01U /*%< bound to "any" address */
#define MAX_UDP_DISPATCH 128 /*%< Maximum number of UDP dispatchers
to start per interface */
/*% The nameserver interface structure */
struct ns_interface {
unsigned int magic; /*%< Magic number. */
......@@ -76,11 +77,13 @@ struct ns_interface {
isc_sockaddr_t addr; /*%< Address and port. */
unsigned int flags; /*%< Interface characteristics */
char name[32]; /*%< Null terminated. */
dns_dispatch_t * udpdispatch; /*%< UDP dispatcher. */
dns_dispatch_t * udpdispatch[MAX_UDP_DISPATCH];
/*%< UDP dispatchers. */
isc_socket_t * tcpsocket; /*%< TCP socket. */
int ntcptarget; /*%< Desired number of concurrent
TCP accepts */
int ntcpcurrent; /*%< Current ditto, locked */
int nudpdispatch; /*%< Number of UDP dispatches */
ns_clientmgr_t * clientmgr; /*%< Client manager. */
ISC_LINK(ns_interface_t) link;
};
......
......@@ -15,13 +15,14 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: interfacemgr.c,v 1.97 2011/03/12 04:59:46 tbox Exp $ */
/* $Id: interfacemgr.c,v 1.98 2011/07/28 04:04:36 each Exp $ */
/*! \file */
#include <config.h>
#include <isc/interfaceiter.h>
#include <isc/os.h>
#include <isc/string.h>
#include <isc/task.h>
#include <isc/util.h>
......@@ -195,6 +196,7 @@ ns_interface_create(ns_interfacemgr_t *mgr, isc_sockaddr_t *addr,
strncpy(ifp->name, name, sizeof(ifp->name));
ifp->name[sizeof(ifp->name)-1] = '\0';
ifp->clientmgr = NULL;
int disp;
result = isc_mutex_init(&ifp->lock);
if (result != ISC_R_SUCCESS)
......@@ -210,7 +212,8 @@ ns_interface_create(ns_interfacemgr_t *mgr, isc_sockaddr_t *addr,
goto clientmgr_create_failure;
}
ifp->udpdispatch = NULL;
for (disp = 0; disp < MAX_UDP_DISPATCH; disp++)
ifp->udpdispatch[disp] = NULL;
ifp->tcpsocket = NULL;
/*
......@@ -221,6 +224,7 @@ ns_interface_create(ns_interfacemgr_t *mgr, isc_sockaddr_t *addr,
*/
ifp->ntcptarget = 1;
ifp->ntcpcurrent = 0;
ifp->nudpdispatch = 0;
ISC_LINK_INIT(ifp, link);
......@@ -247,6 +251,7 @@ ns_interface_listenudp(ns_interface_t *ifp) {
isc_result_t result;
unsigned int attrs;
unsigned int attrmask;
int disp, i;
attrs = 0;
attrs |= DNS_DISPATCHATTR_UDP;
......@@ -258,15 +263,25 @@ ns_interface_listenudp(ns_interface_t *ifp) {
attrmask = 0;
attrmask |= DNS_DISPATCHATTR_UDP | DNS_DISPATCHATTR_TCP;
attrmask |= DNS_DISPATCHATTR_IPV4 | DNS_DISPATCHATTR_IPV6;
result = dns_dispatch_getudp(ifp->mgr->dispatchmgr, ns_g_socketmgr,
ns_g_taskmgr, &ifp->addr,
4096, 1000, 32768, 8219, 8237,
attrs, attrmask, &ifp->udpdispatch);
if (result != ISC_R_SUCCESS) {
isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_ERROR,
"could not listen on UDP socket: %s",
isc_result_totext(result));
goto udp_dispatch_failure;
ifp->nudpdispatch = ISC_MIN(isc_os_ncpus(), MAX_UDP_DISPATCH);
for (disp = 0; disp < ifp->nudpdispatch; disp++) {
result = dns_dispatch_getudp_dup(ifp->mgr->dispatchmgr,
ns_g_socketmgr,
ns_g_taskmgr, &ifp->addr,
4096, 1000, 32768, 8219, 8237,
attrs, attrmask,
&ifp->udpdispatch[disp],
disp == 0
? NULL
: ifp->udpdispatch[0]);
if (result != ISC_R_SUCCESS) {
isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_ERROR,
"could not listen on UDP socket: %s",
isc_result_totext(result));
goto udp_dispatch_failure;
}
}
result = ns_clientmgr_createclients(ifp->clientmgr, ns_g_cpus,
......@@ -277,12 +292,17 @@ ns_interface_listenudp(ns_interface_t *ifp) {
isc_result_totext(result));
goto addtodispatch_failure;
}
return (ISC_R_SUCCESS);
addtodispatch_failure:
dns_dispatch_changeattributes(ifp->udpdispatch, 0,
DNS_DISPATCHATTR_NOLISTEN);
dns_dispatch_detach(&ifp->udpdispatch);
for (i = disp - 1; i <= 0; i--) {
dns_dispatch_changeattributes(ifp->udpdispatch[i], 0,
DNS_DISPATCHATTR_NOLISTEN);
dns_dispatch_detach(&(ifp->udpdispatch[i]));
}
ifp->nudpdispatch = 0;
udp_dispatch_failure:
return (result);
}
......@@ -397,14 +417,16 @@ static void
ns_interface_destroy(ns_interface_t *ifp) {
isc_mem_t *mctx = ifp->mgr->mctx;
REQUIRE(NS_INTERFACE_VALID(ifp));
int disp;
ns_interface_shutdown(ifp);
if (ifp->udpdispatch != NULL) {
dns_dispatch_changeattributes(ifp->udpdispatch, 0,
DNS_DISPATCHATTR_NOLISTEN);
dns_dispatch_detach(&ifp->udpdispatch);
}
for (disp = ifp->nudpdispatch; disp >= 0; disp--)
if (ifp->udpdispatch[disp] != NULL) {
dns_dispatch_changeattributes(ifp->udpdispatch[disp], 0,
DNS_DISPATCHATTR_NOLISTEN);
dns_dispatch_detach(&(ifp->udpdispatch[disp]));
}
if (ifp->tcpsocket != NULL)
isc_socket_detach(&ifp->tcpsocket);
......
......@@ -18,7 +18,7 @@ AC_DIVERT_PUSH(1)dnl
esyscmd([sed "s/^/# /" COPYRIGHT])dnl
AC_DIVERT_POP()dnl
AC_REVISION($Revision: 1.528 $)
AC_REVISION($Revision: 1.529 $)
AC_INIT(lib/dns/name.c)
AC_PREREQ(2.59)
......@@ -2552,7 +2552,7 @@ yes)
esac
AC_SUBST(ISC_PLATFORM_HAVEIFNAMETOINDEX)
AC_CHECK_FUNCS(nanosleep)
AC_CHECK_FUNCS(nanosleep usleep)
#
# Machine architecture dependent features
......
......@@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: dispatch.c,v 1.172 2011/04/06 10:27:16 marka Exp $ */
/* $Id: dispatch.c,v 1.173 2011/07/28 04:04:36 each Exp $ */
/*! \file */
......@@ -312,14 +312,16 @@ static isc_result_t get_udpsocket(dns_dispatchmgr_t *mgr,
dns_dispatch_t *disp,
isc_socketmgr_t *sockmgr,
isc_sockaddr_t *localaddr,
isc_socket_t **sockp);
isc_socket_t **sockp,
isc_socket_t *dup_socket);
static isc_result_t dispatch_createudp(dns_dispatchmgr_t *mgr,
isc_socketmgr_t *sockmgr,
isc_taskmgr_t *taskmgr,
isc_sockaddr_t *localaddr,
unsigned int maxrequests,
unsigned int attributes,
dns_dispatch_t **dispp);
dns_dispatch_t **dispp,
isc_socket_t *dup_socket);
static isc_boolean_t destroy_mgr_ok(dns_dispatchmgr_t *mgr);
static void destroy_mgr(dns_dispatchmgr_t **mgrp);
static isc_result_t qid_allocate(dns_dispatchmgr_t *mgr, unsigned int buckets,
......@@ -327,7 +329,8 @@ static isc_result_t qid_allocate(dns_dispatchmgr_t *mgr, unsigned int buckets,
isc_boolean_t needaddrtable);
static void qid_destroy(isc_mem_t *mctx, dns_qid_t **qidp);
static isc_result_t open_socket(isc_socketmgr_t *mgr, isc_sockaddr_t *local,
unsigned int options, isc_socket_t **sockp);
unsigned int options, isc_socket_t **sockp,
isc_socket_t *dup_socket);
static isc_boolean_t portavailable(dns_dispatchmgr_t *mgr, isc_socket_t *sock,
isc_sockaddr_t *sockaddrp);
......@@ -902,7 +905,8 @@ get_dispsocket(dns_dispatch_t *disp, isc_sockaddr_t *dest,
portentry = port_search(disp, port);
if (portentry != NULL)
bindoptions |= ISC_SOCKET_REUSEADDRESS;
result = open_socket(sockmgr, &localaddr, bindoptions, &sock);
result = open_socket(sockmgr, &localaddr, bindoptions, &sock,
NULL);
if (result == ISC_R_SUCCESS) {
if (portentry == NULL) {
portentry = new_portentry(disp, port);
......@@ -1787,19 +1791,14 @@ destroy_mgr(dns_dispatchmgr_t **mgrp) {
static isc_result_t
open_socket(isc_socketmgr_t *mgr, isc_sockaddr_t *local,
unsigned int options, isc_socket_t **sockp)
unsigned int options, isc_socket_t **sockp,
isc_socket_t *dup_socket)
{
isc_socket_t *sock;
isc_result_t result;
sock = *sockp;
if (sock == NULL) {
result = isc_socket_create(mgr, isc_sockaddr_pf(local),
isc_sockettype_udp, &sock);
if (result != ISC_R_SUCCESS)
return (result);
isc_socket_setname(sock, "dispatcher", NULL);
} else {
if (sock != NULL) {
#ifdef BIND9
result = isc_socket_open(sock);
if (result != ISC_R_SUCCESS)
......@@ -1807,8 +1806,19 @@ open_socket(isc_socketmgr_t *mgr, isc_sockaddr_t *local,
#else
INSIST(0);
#endif
} else if (dup_socket != NULL) {
result = isc_socket_dup(dup_socket, &sock);
if (result != ISC_R_SUCCESS)
return (result);
} else {
result = isc_socket_create(mgr, isc_sockaddr_pf(local),
isc_sockettype_udp, &sock);
if (result != ISC_R_SUCCESS)
return (result);
}
isc_socket_setname(sock, "dispatcher", NULL);
#ifndef ISC_ALLOW_MAPPED
isc_socket_ipv6only(sock, ISC_TRUE);
#endif
......@@ -2646,13 +2656,13 @@ dns_dispatch_createtcp(dns_dispatchmgr_t *mgr, isc_socket_t *sock,
}
isc_result_t
dns_dispatch_getudp(dns_dispatchmgr_t *mgr, isc_socketmgr_t *sockmgr,
dns_dispatch_getudp_dup(dns_dispatchmgr_t *mgr, isc_socketmgr_t *sockmgr,
isc_taskmgr_t *taskmgr, isc_sockaddr_t *localaddr,
unsigned int buffersize,
unsigned int maxbuffers, unsigned int maxrequests,
unsigned int buckets, unsigned int increment,
unsigned int attributes, unsigned int mask,
dns_dispatch_t **dispp)
dns_dispatch_t **dispp, dns_dispatch_t *dup_dispatch)
{
isc_result_t result;
dns_dispatch_t *disp = NULL;
......@@ -2683,28 +2693,31 @@ dns_dispatch_getudp(dns_dispatchmgr_t *mgr, isc_socketmgr_t *sockmgr,
/*
* See if we have a dispatcher that matches.
*/
result = dispatch_find(mgr, localaddr, attributes, mask, &disp);
if (result == ISC_R_SUCCESS) {
disp->refcount++;
if (disp->maxrequests < maxrequests)
disp->maxrequests = maxrequests;
if ((disp->attributes & DNS_DISPATCHATTR_NOLISTEN) == 0 &&
(attributes & DNS_DISPATCHATTR_NOLISTEN) != 0)
{
disp->attributes |= DNS_DISPATCHATTR_NOLISTEN;
if (disp->recv_pending != 0)
isc_socket_cancel(disp->socket, disp->task[0],
ISC_SOCKCANCEL_RECV);
}
if (dup_dispatch == NULL) {
result = dispatch_find(mgr, localaddr, attributes, mask, &disp);
if (result == ISC_R_SUCCESS) {
disp->refcount++;
if (disp->maxrequests < maxrequests)
disp->maxrequests = maxrequests;
if ((disp->attributes & DNS_DISPATCHATTR_NOLISTEN) == 0
&& (attributes & DNS_DISPATCHATTR_NOLISTEN) != 0)
{
disp->attributes |= DNS_DISPATCHATTR_NOLISTEN;
if (disp->recv_pending != 0)
isc_socket_cancel(disp->socket,
disp->task[0],
ISC_SOCKCANCEL_RECV);
}
UNLOCK(&disp->lock);
UNLOCK(&mgr->lock);
UNLOCK(&disp->lock);
UNLOCK(&mgr->lock);
*dispp = disp;
*dispp = disp;
return (ISC_R_SUCCESS);
return (ISC_R_SUCCESS);
}
}
createudp:
......@@ -2712,7 +2725,11 @@ dns_dispatch_getudp(dns_dispatchmgr_t *mgr, isc_socketmgr_t *sockmgr,
* Nope, create one.
*/
result = dispatch_createudp(mgr, sockmgr, taskmgr, localaddr,
maxrequests, attributes, &disp);
maxrequests, attributes, &disp,
dup_dispatch == NULL
? NULL
: dup_dispatch->socket);
if (result != ISC_R_SUCCESS) {
UNLOCK(&mgr->lock);
return (result);
......@@ -2720,9 +2737,24 @@ dns_dispatch_getudp(dns_dispatchmgr_t *mgr, isc_socketmgr_t *sockmgr,
UNLOCK(&mgr->lock);
*dispp = disp;
return (ISC_R_SUCCESS);
}
isc_result_t
dns_dispatch_getudp(dns_dispatchmgr_t *mgr, isc_socketmgr_t *sockmgr,
isc_taskmgr_t *taskmgr, isc_sockaddr_t *localaddr,
unsigned int buffersize,
unsigned int maxbuffers, unsigned int maxrequests,
unsigned int buckets, unsigned int increment,
unsigned int attributes, unsigned int mask,
dns_dispatch_t **dispp)
{
return dns_dispatch_getudp_dup(mgr, sockmgr, taskmgr, localaddr,
buffersize, maxbuffers, maxrequests, buckets, increment,
attributes, mask, dispp, NULL);
}
/*
* mgr should be locked.
*/
......@@ -2734,7 +2766,7 @@ dns_dispatch_getudp(dns_dispatchmgr_t *mgr, isc_socketmgr_t *sockmgr,
static isc_result_t
get_udpsocket(dns_dispatchmgr_t *mgr, dns_dispatch_t *disp,
isc_socketmgr_t *sockmgr, isc_sockaddr_t *localaddr,
isc_socket_t **sockp)
isc_socket_t **sockp, isc_socket_t *dup_socket)
{
unsigned int i, j;
isc_socket_t *held[DNS_DISPATCH_HELD];
......@@ -2774,7 +2806,7 @@ get_udpsocket(dns_dispatchmgr_t *mgr, dns_dispatch_t *disp,
nports)];
isc_sockaddr_setport(&localaddr_bound, prt);
result = open_socket(sockmgr, &localaddr_bound,
0, &sock);
0, &sock, NULL);
if (result == ISC_R_SUCCESS ||
result != ISC_R_ADDRINUSE) {
disp->localport = prt;
......@@ -2790,7 +2822,8 @@ get_udpsocket(dns_dispatchmgr_t *mgr, dns_dispatch_t *disp,
} else {
/* Allow to reuse address for non-random ports. */
result = open_socket(sockmgr, localaddr,
ISC_SOCKET_REUSEADDRESS, &sock);
ISC_SOCKET_REUSEADDRESS, &sock,
dup_socket);
if (result == ISC_R_SUCCESS)
*sockp = sock;
......@@ -2802,7 +2835,7 @@ get_udpsocket(dns_dispatchmgr_t *mgr, dns_dispatch_t *disp,
i = 0;
for (j = 0; j < 0xffffU; j++) {
result = open_socket(sockmgr, localaddr, 0, &sock);
result = open_socket(sockmgr, localaddr, 0, &sock, NULL);
if (result != ISC_R_SUCCESS)
goto end;
else if (!anyport)
......@@ -2841,7 +2874,8 @@ dispatch_createudp(dns_dispatchmgr_t *mgr, isc_socketmgr_t *sockmgr,
isc_sockaddr_t *localaddr,
unsigned int maxrequests,
unsigned int attributes,
dns_dispatch_t **dispp)
dns_dispatch_t **dispp,
isc_socket_t *dup_socket)
{
isc_result_t result;
dns_dispatch_t *disp;
......@@ -2857,9 +2891,21 @@ dispatch_createudp(dns_dispatchmgr_t *mgr, isc_socketmgr_t *sockmgr,
return (result);
if ((attributes & DNS_DISPATCHATTR_EXCLUSIVE) == 0) {
result = get_udpsocket(mgr, disp, sockmgr, localaddr, &sock);
result = get_udpsocket(mgr, disp, sockmgr, localaddr, &sock,
dup_socket);
if (result != ISC_R_SUCCESS)
goto deallocate_dispatch;
if (isc_log_wouldlog(dns_lctx, 90)) {
char addrbuf[ISC_SOCKADDR_FORMATSIZE];
isc_sockaddr_format(localaddr, addrbuf,
ISC_SOCKADDR_FORMATSIZE);
mgr_log(mgr, LVL(90), "dns_dispatch_createudp: Created"
" UDP dispatch for %s with socket fd %d\n",
addrbuf, isc_socket_getfd(sock));
}
} else {
isc_sockaddr_t sa_any;
......@@ -2871,7 +2917,7 @@ dispatch_createudp(dns_dispatchmgr_t *mgr, isc_socketmgr_t *sockmgr,
*/
isc_sockaddr_anyofpf(&sa_any, isc_sockaddr_pf(localaddr));
if (!isc_sockaddr_eqaddr(&sa_any, localaddr)) {
result = open_socket(sockmgr, localaddr, 0, &sock);
result = open_socket(sockmgr, localaddr, 0, &sock, NULL);
if (sock != NULL)
isc_socket_detach(&sock);
if (result != ISC_R_SUCCESS)
......@@ -2938,6 +2984,7 @@ dispatch_createudp(dns_dispatchmgr_t *mgr, isc_socketmgr_t *sockmgr,
dispatch_log(disp, LVL(90), "created socket %p", disp->socket);
*dispp = disp;
return (result);
/*
......
......@@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: dispatch.h,v 1.62 2009/01/27 23:47:54 tbox Exp $ */
/* $Id: dispatch.h,v 1.63 2011/07/28 04:04:37 each Exp $ */
#ifndef DNS_DISPATCH_H
#define DNS_DISPATCH_H 1
......@@ -245,6 +245,15 @@ dns_dispatch_getudp(dns_dispatchmgr_t *mgr, isc_socketmgr_t *sockmgr,
unsigned int buckets, unsigned int increment,
unsigned int attributes, unsigned int mask,
dns_dispatch_t **dispp);
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 buffersize,
unsigned int maxbuffers, unsigned int maxrequests,
unsigned int buckets, unsigned int increment,
unsigned int attributes, unsigned int mask,
dns_dispatch_t **dispp, dns_dispatch_t *dup);
/*%<
* Attach to existing dns_dispatch_t if one is found with dns_dispatchmgr_find,
* otherwise create a new UDP dispatch.
......