Instead of an RBT for the forwarders table, use a QP trie.
We now use reference counting for dns_forwarders_t. When a forwarders
object is retrieved by dns_fwdtable_find(), it must now be explicitly
detached by the caller afterward.
QP tries require stored objects to include their names, so the
the forwarders object now has that. This obviates the need to
pass back a separate 'foundname' value from dns_fwdtable_find().
dns_name_totext(name, true, &namebuf);
isc_buffer_putuint8(&namebuf, 0);
- result = dns_fwdtable_find(cz->view->fwdtable, name, NULL,
- &dnsforwarders);
+ result = dns_fwdtable_find(cz->view->fwdtable, name, &dnsforwarders);
if (result == ISC_R_SUCCESS &&
dnsforwarders->fwdpolicy == dns_fwdpolicy_only)
{
if (zoneconf != NULL) {
cfg_obj_destroy(cfg->add_parser, &zoneconf);
}
+ if (dnsforwarders != NULL) {
+ dns_forwarders_detach(&dnsforwarders);
+ }
dns_catz_entry_detach(cz->origin, &cz->entry);
dns_catz_zone_detach(&cz->origin);
dns_view_detach(&cz->view);
empty = empty_zones[++empty_zone])
{
dns_forwarders_t *dnsforwarders = NULL;
+ dns_fwdpolicy_t fwdpolicy = dns_fwdpolicy_none;
/*
* Look for zone on drop list.
* If we would forward this name don't add a
* empty zone for it.
*/
- result = dns_fwdtable_find(view->fwdtable, name, NULL,
+ result = dns_fwdtable_find(view->fwdtable, name,
&dnsforwarders);
- if ((result == ISC_R_SUCCESS ||
- result == DNS_R_PARTIALMATCH) &&
- dnsforwarders->fwdpolicy == dns_fwdpolicy_only)
+ if (result == ISC_R_SUCCESS ||
+ result == DNS_R_PARTIALMATCH)
{
+ fwdpolicy = dnsforwarders->fwdpolicy;
+ dns_forwarders_detach(&dnsforwarders);
+ }
+ if (fwdpolicy == dns_fwdpolicy_only) {
continue;
}
ipv4only_zone++)
{
dns_forwarders_t *dnsforwarders = NULL;
+ dns_fwdpolicy_t fwdpolicy = dns_fwdpolicy_none;
CHECK(dns_name_fromstring(
name, zones[ipv4only_zone].name, 0, NULL));
/*
* If we would forward this name don't add it.
*/
- result = dns_fwdtable_find(view->fwdtable, name, NULL,
+ result = dns_fwdtable_find(view->fwdtable, name,
&dnsforwarders);
- if ((result == ISC_R_SUCCESS ||
- result == DNS_R_PARTIALMATCH) &&
- dnsforwarders->fwdpolicy == dns_fwdpolicy_only)
+ if (result == ISC_R_SUCCESS ||
+ result == DNS_R_PARTIALMATCH)
{
+ fwdpolicy = dnsforwarders->fwdpolicy;
+ dns_forwarders_detach(&dnsforwarders);
+ }
+ if (fwdpolicy == dns_fwdpolicy_only) {
continue;
}
#include <isc/magic.h>
#include <isc/mem.h>
#include <isc/result.h>
-#include <isc/rwlock.h>
#include <isc/util.h>
+#include <dns/fixedname.h>
#include <dns/forward.h>
#include <dns/name.h>
-#include <dns/rbt.h>
+#include <dns/qp.h>
#include <dns/types.h>
+#include <dns/view.h>
struct dns_fwdtable {
/* Unlocked. */
unsigned int magic;
isc_mem_t *mctx;
- isc_rwlock_t rwlock;
- /* Locked by lock. */
- dns_rbt_t *table;
+ dns_qpmulti_t *table;
};
#define FWDTABLEMAGIC ISC_MAGIC('F', 'w', 'd', 'T')
#define VALID_FWDTABLE(ft) ISC_MAGIC_VALID(ft, FWDTABLEMAGIC)
static void
-auto_detach(void *, void *);
+qp_attach(void *uctx, void *pval, uint32_t ival);
+static void
+qp_detach(void *uctx, void *pval, uint32_t ival);
+static size_t
+qp_makekey(dns_qpkey_t key, void *uctx, void *pval, uint32_t ival);
+static void
+qp_triename(void *uctx, char *buf, size_t size);
-isc_result_t
-dns_fwdtable_create(isc_mem_t *mctx, dns_fwdtable_t **fwdtablep) {
- dns_fwdtable_t *fwdtable;
- isc_result_t result;
+static dns_qpmethods_t qpmethods = {
+ qp_attach,
+ qp_detach,
+ qp_makekey,
+ qp_triename,
+};
+
+void
+dns_fwdtable_create(isc_mem_t *mctx, dns_view_t *view,
+ dns_fwdtable_t **fwdtablep) {
+ dns_fwdtable_t *fwdtable = NULL;
REQUIRE(fwdtablep != NULL && *fwdtablep == NULL);
fwdtable = isc_mem_get(mctx, sizeof(*fwdtable));
+ *fwdtable = (dns_fwdtable_t){ .magic = FWDTABLEMAGIC };
- fwdtable->table = NULL;
- result = dns_rbt_create(mctx, auto_detach, fwdtable, &fwdtable->table);
- if (result != ISC_R_SUCCESS) {
- goto cleanup_fwdtable;
- }
+ dns_qpmulti_create(mctx, &qpmethods, view, &fwdtable->table);
- isc_rwlock_init(&fwdtable->rwlock);
- fwdtable->mctx = NULL;
isc_mem_attach(mctx, &fwdtable->mctx);
- fwdtable->magic = FWDTABLEMAGIC;
*fwdtablep = fwdtable;
+}
- return (ISC_R_SUCCESS);
+static dns_forwarders_t *
+new_forwarders(isc_mem_t *mctx, const dns_name_t *name,
+ dns_fwdpolicy_t fwdpolicy) {
+ dns_forwarders_t *forwarders = NULL;
-cleanup_fwdtable:
- isc_mem_put(mctx, fwdtable, sizeof(*fwdtable));
+ forwarders = isc_mem_get(mctx, sizeof(*forwarders));
+ *forwarders = (dns_forwarders_t){
+ .fwdpolicy = fwdpolicy,
+ .fwdrs = ISC_LIST_INITIALIZER,
+ };
+ isc_mem_attach(mctx, &forwarders->mctx);
+ isc_refcount_init(&forwarders->references, 1);
- return (result);
+ forwarders->name = dns_fixedname_initname(&forwarders->fn);
+ dns_name_copy(name, forwarders->name);
+
+ return (forwarders);
}
isc_result_t
dns_fwdtable_addfwd(dns_fwdtable_t *fwdtable, const dns_name_t *name,
dns_forwarderlist_t *fwdrs, dns_fwdpolicy_t fwdpolicy) {
isc_result_t result;
- dns_forwarders_t *forwarders;
- dns_forwarder_t *fwd, *nfwd;
+ dns_forwarders_t *forwarders = NULL;
+ dns_forwarder_t *fwd = NULL, *nfwd = NULL;
+ dns_qp_t *qp = NULL;
REQUIRE(VALID_FWDTABLE(fwdtable));
- forwarders = isc_mem_get(fwdtable->mctx, sizeof(*forwarders));
+ forwarders = new_forwarders(fwdtable->mctx, name, fwdpolicy);
- ISC_LIST_INIT(forwarders->fwdrs);
for (fwd = ISC_LIST_HEAD(*fwdrs); fwd != NULL;
fwd = ISC_LIST_NEXT(fwd, link))
{
ISC_LINK_INIT(nfwd, link);
ISC_LIST_APPEND(forwarders->fwdrs, nfwd, link);
}
- forwarders->fwdpolicy = fwdpolicy;
- RWLOCK(&fwdtable->rwlock, isc_rwlocktype_write);
- result = dns_rbt_addname(fwdtable->table, name, forwarders);
- RWUNLOCK(&fwdtable->rwlock, isc_rwlocktype_write);
+ dns_qpmulti_write(fwdtable->table, &qp);
+ result = dns_qp_insert(qp, forwarders, 0);
+ dns_qp_compact(qp, DNS_QPGC_MAYBE);
+ dns_qpmulti_commit(fwdtable->table, &qp);
- if (result != ISC_R_SUCCESS) {
+ if (result == ISC_R_SUCCESS) {
+ dns_forwarders_detach(&forwarders);
+ } else {
goto cleanup;
}
dns_fwdtable_add(dns_fwdtable_t *fwdtable, const dns_name_t *name,
isc_sockaddrlist_t *addrs, dns_fwdpolicy_t fwdpolicy) {
isc_result_t result;
- dns_forwarders_t *forwarders;
- dns_forwarder_t *fwd;
- isc_sockaddr_t *sa;
+ dns_forwarders_t *forwarders = NULL;
+ dns_forwarder_t *fwd = NULL;
+ isc_sockaddr_t *sa = NULL;
+ dns_qp_t *qp = NULL;
REQUIRE(VALID_FWDTABLE(fwdtable));
- forwarders = isc_mem_get(fwdtable->mctx, sizeof(*forwarders));
+ forwarders = new_forwarders(fwdtable->mctx, name, fwdpolicy);
- ISC_LIST_INIT(forwarders->fwdrs);
for (sa = ISC_LIST_HEAD(*addrs); sa != NULL;
sa = ISC_LIST_NEXT(sa, link))
{
.link = ISC_LINK_INITIALIZER };
ISC_LIST_APPEND(forwarders->fwdrs, fwd, link);
}
- forwarders->fwdpolicy = fwdpolicy;
- RWLOCK(&fwdtable->rwlock, isc_rwlocktype_write);
- result = dns_rbt_addname(fwdtable->table, name, forwarders);
- RWUNLOCK(&fwdtable->rwlock, isc_rwlocktype_write);
+ dns_qpmulti_write(fwdtable->table, &qp);
+ result = dns_qp_insert(qp, forwarders, 0);
+ dns_qp_compact(qp, DNS_QPGC_MAYBE);
+ dns_qpmulti_commit(fwdtable->table, &qp);
- if (result != ISC_R_SUCCESS) {
+ if (result == ISC_R_SUCCESS) {
+ dns_forwarders_detach(&forwarders);
+ } else {
goto cleanup;
}
isc_result_t
dns_fwdtable_find(dns_fwdtable_t *fwdtable, const dns_name_t *name,
- dns_name_t *foundname, dns_forwarders_t **forwardersp) {
+ dns_forwarders_t **forwardersp) {
isc_result_t result;
+ dns_qpread_t qpr;
+ void *pval = NULL;
REQUIRE(VALID_FWDTABLE(fwdtable));
- RWLOCK(&fwdtable->rwlock, isc_rwlocktype_read);
- result = dns_rbt_findname(fwdtable->table, name, 0, foundname,
- (void **)forwardersp);
- RWUNLOCK(&fwdtable->rwlock, isc_rwlocktype_read);
+ dns_qpmulti_query(fwdtable->table, &qpr);
+ result = dns_qp_findname_ancestor(&qpr, name, 0, &pval, NULL);
+ if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH) {
+ dns_forwarders_t *fwdrs = pval;
+ *forwardersp = fwdrs;
+ dns_forwarders_ref(fwdrs);
+ }
+ dns_qpread_destroy(fwdtable->table, &qpr);
return (result);
}
void
dns_fwdtable_destroy(dns_fwdtable_t **fwdtablep) {
- dns_fwdtable_t *fwdtable;
+ dns_fwdtable_t *fwdtable = NULL;
REQUIRE(fwdtablep != NULL && VALID_FWDTABLE(*fwdtablep));
fwdtable = *fwdtablep;
*fwdtablep = NULL;
- dns_rbt_destroy(&fwdtable->table);
- isc_rwlock_destroy(&fwdtable->rwlock);
+ dns_qpmulti_destroy(&fwdtable->table);
fwdtable->magic = 0;
isc_mem_putanddetach(&fwdtable->mctx, fwdtable, sizeof(*fwdtable));
***/
static void
-auto_detach(void *data, void *arg) {
- dns_forwarders_t *forwarders = data;
- dns_fwdtable_t *fwdtable = arg;
- dns_forwarder_t *fwd;
-
- UNUSED(arg);
+destroy_forwarders(dns_forwarders_t *forwarders) {
+ dns_forwarder_t *fwd = NULL;
while (!ISC_LIST_EMPTY(forwarders->fwdrs)) {
fwd = ISC_LIST_HEAD(forwarders->fwdrs);
ISC_LIST_UNLINK(forwarders->fwdrs, fwd, link);
if (fwd->tlsname != NULL) {
- dns_name_free(fwd->tlsname, fwdtable->mctx);
- isc_mem_put(fwdtable->mctx, fwd->tlsname,
+ dns_name_free(fwd->tlsname, forwarders->mctx);
+ isc_mem_put(forwarders->mctx, fwd->tlsname,
sizeof(*fwd->tlsname));
}
- isc_mem_put(fwdtable->mctx, fwd, sizeof(*fwd));
+ isc_mem_put(forwarders->mctx, fwd, sizeof(*fwd));
}
- isc_mem_put(fwdtable->mctx, forwarders, sizeof(*forwarders));
+ isc_mem_putanddetach(&forwarders->mctx, forwarders,
+ sizeof(*forwarders));
+}
+
+#if DNS_FORWARD_TRACE
+ISC_REFCOUNT_TRACE_IMPL(dns_forwarders, destroy_forwarders);
+#else
+ISC_REFCOUNT_IMPL(dns_forwarders, destroy_forwarders);
+#endif
+
+static void
+qp_attach(void *uctx ISC_ATTR_UNUSED, void *pval,
+ uint32_t ival ISC_ATTR_UNUSED) {
+ dns_forwarders_t *forwarders = pval;
+ dns_forwarders_ref(forwarders);
+}
+
+static void
+qp_detach(void *uctx ISC_ATTR_UNUSED, void *pval,
+ uint32_t ival ISC_ATTR_UNUSED) {
+ dns_forwarders_t *forwarders = pval;
+ dns_forwarders_detach(&forwarders);
+}
+
+static size_t
+qp_makekey(dns_qpkey_t key, void *uctx ISC_ATTR_UNUSED, void *pval,
+ uint32_t ival ISC_ATTR_UNUSED) {
+ dns_forwarders_t *fwd = pval;
+ return (dns_qpkey_fromname(key, fwd->name));
+}
+
+static void
+qp_triename(void *uctx, char *buf, size_t size) {
+ dns_view_t *view = uctx;
+ snprintf(buf, size, "view %s forwarder table", view->name);
}
/*! \file dns/forward.h */
#include <isc/lang.h>
+#include <isc/mem.h>
+#include <isc/refcount.h>
#include <isc/result.h>
#include <isc/sockaddr.h>
+#include <dns/fixedname.h>
+#include <dns/qp.h>
#include <dns/types.h>
+/* Define to 1 for detailed reference tracing */
+#undef DNS_FORWARD_TRACE
+
ISC_LANG_BEGINDECLS
struct dns_forwarder {
struct dns_forwarders {
dns_forwarderlist_t fwdrs;
dns_fwdpolicy_t fwdpolicy;
+ isc_mem_t *mctx;
+ isc_refcount_t references;
+ dns_fixedname_t fn;
+ dns_name_t *name;
};
-isc_result_t
-dns_fwdtable_create(isc_mem_t *mctx, dns_fwdtable_t **fwdtablep);
+void
+dns_fwdtable_create(isc_mem_t *mctx, dns_view_t *view,
+ dns_fwdtable_t **fwdtablep);
/*%<
* Creates a new forwarding table.
*
* Requires:
* \li mctx is a valid memory context.
* \li fwdtablep != NULL && *fwdtablep == NULL
- *
- * Returns:
- * \li #ISC_R_SUCCESS
- * \li #ISC_R_NOMEMORY
*/
isc_result_t
isc_result_t
dns_fwdtable_find(dns_fwdtable_t *fwdtable, const dns_name_t *name,
- dns_name_t *foundname, dns_forwarders_t **forwardersp);
+ dns_forwarders_t **forwardersp);
/*%<
* Finds a domain in the forwarding table. The closest matching parent
* domain is returned.
* \li fwdtable is a valid forwarding table.
* \li name is a valid name
* \li forwardersp != NULL && *forwardersp == NULL
- * \li foundname to be NULL or a valid name with buffer.
*
* Returns:
* \li #ISC_R_SUCCESS Success
* \li #DNS_R_PARTIALMATCH Superdomain found with data
* \li #ISC_R_NOTFOUND No match
- * \li #ISC_R_NOSPACE Concatenating nodes to form foundname failed
*/
void
* \li all memory associated with the forwarding table is freed.
*/
+#if DNS_FORWARD_TRACE
+#define dns_forwarders_ref(ptr) \
+ dns_forwarders__ref(ptr, __func__, __FILE__, __LINE__)
+#define dns_forwarders_unref(ptr) \
+ dns_forwarders__unref(ptr, __func__, __FILE__, __LINE__)
+#define dns_forwarders_attach(ptr, ptrp) \
+ dns_forwarders__attach(ptr, ptrp, __func__, __FILE__, __LINE__)
+#define dns_forwarders_detach(ptrp) \
+ dns_forwarders__detach(ptrp, __func__, __FILE__, __LINE__)
+ISC_REFCOUNT_TRACE_DECL(dns_forwarders);
+#else
+ISC_REFCOUNT_DECL(dns_forwarders);
+#endif
ISC_LANG_ENDDECLS
dns_forwarders_t *forwarders = NULL;
dns_name_t *name = fctx->name;
dns_name_t suffix;
- dns_fixedname_t fixed;
- dns_name_t *domain;
/*
* DS records are found in the parent server.
name = &suffix;
}
- domain = dns_fixedname_initname(&fixed);
- result = dns_fwdtable_find(res->view->fwdtable, name, domain,
+ result = dns_fwdtable_find(res->view->fwdtable, name,
&forwarders);
if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH) {
fwd = ISC_LIST_HEAD(forwarders->fwdrs);
fctx->fwdpolicy = forwarders->fwdpolicy;
- dns_name_copy(domain, fctx->fwdname);
+ dns_name_copy(forwarders->name, fctx->fwdname);
if (fctx->fwdpolicy == dns_fwdpolicy_only &&
- isstrictsubdomain(domain, fctx->domain))
+ isstrictsubdomain(forwarders->name, fctx->domain))
{
fcount_decr(fctx);
- dns_name_copy(domain, fctx->domain);
+ dns_name_copy(forwarders->name, fctx->domain);
result = fcount_incr(fctx, true);
if (result != ISC_R_SUCCESS) {
+ dns_forwarders_detach(&forwarders);
return (result);
}
}
+ dns_forwarders_detach(&forwarders);
}
}
if (domain == NULL) {
dns_forwarders_t *forwarders = NULL;
- dns_fixedname_t fixed;
- dns_name_t *fname = dns_fixedname_initname(&fixed);
unsigned int labels;
const dns_name_t *fwdname = name;
dns_name_t suffix;
/* Find the forwarder for this name. */
result = dns_fwdtable_find(fctx->res->view->fwdtable, fwdname,
- fname, &forwarders);
+ &forwarders);
if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH) {
fctx->fwdpolicy = forwarders->fwdpolicy;
- dns_name_copy(fname, fctx->fwdname);
+ dns_name_copy(forwarders->name, fctx->fwdname);
+ dns_forwarders_detach(&forwarders);
}
- if (fctx->fwdpolicy != dns_fwdpolicy_only) {
+ if (fctx->fwdpolicy == dns_fwdpolicy_only) {
+ /*
+ * We're in forward-only mode. Set the query
+ * domain.
+ */
+ dns_name_copy(fctx->fwdname, fctx->domain);
+ dns_name_copy(fctx->fwdname, fctx->qmindcname);
+ /*
+ * Disable query minimization
+ */
+ options &= ~DNS_FETCHOPT_QMINIMIZE;
+ } else {
dns_fixedname_t dcfixed;
dns_name_t *dcname = dns_fixedname_initname(&dcfixed);
if (dns_rdatatype_atparent(fctx->type)) {
findoptions |= DNS_DBFIND_NOEXACT;
}
- result = dns_view_findzonecut(res->view, name, fname,
- dcname, fctx->now,
- findoptions, true, true,
- &fctx->nameservers, NULL);
+ result = dns_view_findzonecut(
+ res->view, name, fctx->fwdname, dcname,
+ fctx->now, findoptions, true, true,
+ &fctx->nameservers, NULL);
if (result != ISC_R_SUCCESS) {
goto cleanup_nameservers;
}
- dns_name_copy(fname, fctx->domain);
+ dns_name_copy(fctx->fwdname, fctx->domain);
dns_name_copy(dcname, fctx->qmindcname);
fctx->ns_ttl = fctx->nameservers.ttl;
fctx->ns_ttl_ok = true;
- } else {
- /*
- * We're in forward-only mode. Set the query
- * domain.
- */
- dns_name_copy(fname, fctx->domain);
- dns_name_copy(fname, fctx->qmindcname);
- /*
- * Disable query minimization
- */
- options &= ~DNS_FETCHOPT_QMINIMIZE;
}
} else {
dns_name_copy(domain, fctx->domain);
name_external(const dns_name_t *name, dns_rdatatype_t type, fetchctx_t *fctx) {
isc_result_t result;
dns_forwarders_t *forwarders = NULL;
- dns_fixedname_t fixed;
- dns_name_t *fname = dns_fixedname_initname(&fixed);
dns_name_t *apex = NULL;
dns_name_t suffix;
dns_zone_t *zone = NULL;
/*
* Look for a forward declaration below 'name'.
*/
- result = dns_fwdtable_find(fctx->res->view->fwdtable, name, fname,
+ result = dns_fwdtable_find(fctx->res->view->fwdtable, name,
&forwarders);
if (ISFORWARDER(fctx->addrinfo)) {
* See if the forwarder declaration is better.
*/
if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH) {
- return (!dns_name_equal(fname, fctx->fwdname));
+ bool better = !dns_name_equal(forwarders->name,
+ fctx->fwdname);
+ dns_forwarders_detach(&forwarders);
+ return (better);
}
/*
* changed: play it safe and don't cache.
*/
return (true);
- } else if ((result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH) &&
- forwarders->fwdpolicy == dns_fwdpolicy_only &&
- !ISC_LIST_EMPTY(forwarders->fwdrs))
- {
+ } else if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH) {
/*
* If 'name' is covered by a 'forward only' clause then we
* can't cache this response.
*/
- return (true);
+ bool nocache = (forwarders->fwdpolicy == dns_fwdpolicy_only &&
+ !ISC_LIST_EMPTY(forwarders->fwdrs));
+ dns_forwarders_detach(&forwarders);
+ return (nocache);
}
return (false);
dns_zt_create(mctx, view, &view->zonetable);
- result = dns_fwdtable_create(mctx, &view->fwdtable);
- if (result != ISC_R_SUCCESS) {
- UNEXPECTED_ERROR("dns_fwdtable_create() failed: %s",
- isc_result_totext(result));
- result = ISC_R_UNEXPECTED;
- goto cleanup_zt;
- }
+ dns_fwdtable_create(mctx, view, &view->fwdtable);
dns_tsigkeyring_create(view->mctx, &view->dynamickeys);
isc_refcount_decrementz(&view->references);
isc_refcount_destroy(&view->references);
- if (view->fwdtable != NULL) {
- dns_fwdtable_destroy(&view->fwdtable);
- }
-
-cleanup_zt:
+ dns_fwdtable_destroy(&view->fwdtable);
dns_zt_detach(&view->zonetable);
isc_rwlock_destroy(&view->sfd_lock);