]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
use a qp-trie for the NTA table
authorEvan Hunt <each@isc.org>
Wed, 5 Apr 2023 07:36:37 +0000 (00:36 -0700)
committerOndřej Surý <ondrej@isc.org>
Tue, 15 Aug 2023 12:24:46 +0000 (14:24 +0200)
replace the red-black tree used by the negative trust anchor table
with a QP trie.

because of this change, dns_ntatable_init() can no longer fail, and
neither can dns_view_initntatable(). these functions have both been
changed to type void.

bin/named/server.c
lib/dns/include/dns/nta.h
lib/dns/include/dns/view.h
lib/dns/nta.c
lib/dns/view.c
tests/dns/keytable_test.c
tests/dns/qp_test.c

index c88ca57423ac9ff17186f9e219665ed355f12f64..5d7e000396792c595e958e6418387600dbc005b1 100644 (file)
@@ -1124,13 +1124,7 @@ configure_view_dnsseckeys(dns_view_t *view, const cfg_obj_t *vconfig,
                return (ISC_R_UNEXPECTED);
        }
 
-       result = dns_view_initntatable(view, named_g_loopmgr);
-       if (result != ISC_R_SUCCESS) {
-               isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
-                             NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
-                             "couldn't create NTA table");
-               return (ISC_R_UNEXPECTED);
-       }
+       dns_view_initntatable(view, named_g_loopmgr);
 
        if (auto_root && view->rdclass == dns_rdataclass_in) {
                const cfg_obj_t *builtin_keys = NULL;
index 6b1d573520094830e368f298b043da7ae25928e3..308f3f5b687b33471ae5d7bda95511584bd9c7f1 100644 (file)
 #include <dns/types.h>
 #include <dns/view.h>
 
+/* Define to 1 for detailed reference tracing */
+#undef DNS_NTA_TRACE
+
 ISC_LANG_BEGINDECLS
 
 #define NTATABLE_MAGIC    ISC_MAGIC('N', 'T', 'A', 't')
 #define VALID_NTATABLE(nt) ISC_MAGIC_VALID(nt, NTATABLE_MAGIC)
 
-isc_result_t
+void
 dns_ntatable_create(dns_view_t *view, isc_loopmgr_t *loopmgr,
                    dns_ntatable_t **ntatablep);
 /*%<
@@ -54,22 +57,27 @@ dns_ntatable_create(dns_view_t *view, isc_loopmgr_t *loopmgr,
  * Requires:
  *
  *\li  'view' is a valid view.
- *
- *\li  'tmgr' is a valid timer manager.
- *
+ *\li  'loopmgr' is a valid loopmgr.
  *\li  ntatablep != NULL && *ntatablep == NULL
  *
  * Ensures:
  *
- *\li  On success, *ntatablep is a valid, empty NTA table.
- *
- * Returns:
- *
- *\li  ISC_R_SUCCESS
- *\li  Any other result indicates failure.
+ *\li  *ntatablep is a valid, empty NTA table.
  */
 
+#if DNS_NTA_TRACE
+#define dns_ntatable_ref(ptr) \
+       dns_ntatable__ref(ptr, __func__, __FILE__, __LINE__)
+#define dns_ntatable_unref(ptr) \
+       dns_ntatable__unref(ptr, __func__, __FILE__, __LINE__)
+#define dns_ntatable_attach(ptr, ptrp) \
+       dns_ntatable__attach(ptr, ptrp, __func__, __FILE__, __LINE__)
+#define dns_ntatable_detach(ptrp) \
+       dns_ntatable__detach(ptrp, __func__, __FILE__, __LINE__)
+ISC_REFCOUNT_TRACE_DECL(dns_ntatable);
+#else
 ISC_REFCOUNT_DECL(dns_ntatable);
+#endif
 /*%
  * Reference counting for dns_ntatable
  */
@@ -162,6 +170,16 @@ dns_ntatable_shutdown(dns_ntatable_t *ntatable);
 
 /* Internal */
 typedef struct dns__nta dns__nta_t;
+#if DNS_NTA_TRACE
+#define dns__nta_ref(ptr)   dns__nta__ref(ptr, __func__, __FILE__, __LINE__)
+#define dns__nta_unref(ptr) dns__nta__unref(ptr, __func__, __FILE__, __LINE__)
+#define dns__nta_attach(ptr, ptrp) \
+       dns__nta__attach(ptr, ptrp, __func__, __FILE__, __LINE__)
+#define dns__nta_detach(ptrp) \
+       dns__nta__detach(ptrp, __func__, __FILE__, __LINE__)
+ISC_REFCOUNT_TRACE_DECL(dns__nta);
+#else
 ISC_REFCOUNT_DECL(dns__nta);
+#endif
 
 ISC_LANG_ENDDECLS
index 89dd7da6e6214088c7adac42b36560d6908e4cde..9269e27b5675fc7346cdd5dab60d1b7f4565b5de 100644 (file)
@@ -932,17 +932,14 @@ dns_view_iscacheshared(dns_view_t *view);
  *\li  #false otherwise.
  */
 
-isc_result_t
+void
 dns_view_initntatable(dns_view_t *view, isc_loopmgr_t *loopmgr);
 /*%<
  * Initialize the negative trust anchor table for the view.
  *
  * Requires:
  * \li 'view' is valid.
- *
- * Returns:
- *\li  ISC_R_SUCCESS
- *\li  Any other result indicates failure
+ * \li 'loopmgr' is a valid loopmgr.
  */
 
 isc_result_t
index cee1ea171419723b9354756ea5ca72fc7a0627d0..7f2895dd2f513ed74ea5024a03c73e58d289fe1d 100644 (file)
 #include <dns/log.h>
 #include <dns/name.h>
 #include <dns/nta.h>
-#include <dns/rbt.h>
+#include <dns/qp.h>
 #include <dns/rdataset.h>
 #include <dns/resolver.h>
 #include <dns/time.h>
 
 struct dns_ntatable {
-       /* Unlocked. */
        unsigned int magic;
        isc_mem_t *mctx;
        dns_view_t *view;
        isc_rwlock_t rwlock;
        isc_loopmgr_t *loopmgr;
-       /* Protected by atomics */
        isc_refcount_t references;
-       /* Locked by rwlock. */
-       dns_rbt_t *table;
+       dns_qpmulti_t *table;
        atomic_bool shuttingdown;
 };
 
 struct dns__nta {
        unsigned int magic;
        isc_mem_t *mctx;
+       isc_loop_t *loop;
        isc_refcount_t references;
        dns_ntatable_t *ntatable;
        bool forced;
-       isc_loop_t *loop;
        isc_timer_t *timer;
        dns_fetch_t *fetch;
        dns_rdataset_t rdataset;
@@ -66,6 +63,7 @@ struct dns__nta {
        dns_fixedname_t fn;
        dns_name_t *name;
        isc_stdtime_t expiry;
+       bool shuttingdown;
 };
 
 #define NTA_MAGIC     ISC_MAGIC('N', 'T', 'A', 'n')
@@ -74,11 +72,28 @@ struct dns__nta {
 static void
 dns__nta_shutdown(dns__nta_t *nta);
 
+static 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);
+
+static dns_qpmethods_t qpmethods = {
+       qp_attach,
+       qp_detach,
+       qp_makekey,
+       qp_triename,
+};
+
 static void
 dns__nta_destroy(dns__nta_t *nta) {
-       isc_refcount_destroy(&nta->references);
-       nta->magic = 0;
        REQUIRE(nta->timer == NULL);
+
+       nta->magic = 0;
+       isc_refcount_destroy(&nta->references);
        if (dns_rdataset_isassociated(&nta->rdataset)) {
                dns_rdataset_disassociate(&nta->rdataset);
        }
@@ -93,23 +108,16 @@ dns__nta_destroy(dns__nta_t *nta) {
        isc_mem_putanddetach(&nta->mctx, nta, sizeof(*nta));
 }
 
+#if DNS_NTA_TRACE
+ISC_REFCOUNT_TRACE_IMPL(dns__nta, dns__nta_destroy);
+#else
 ISC_REFCOUNT_IMPL(dns__nta, dns__nta_destroy);
+#endif
 
-static void
-dns__nta_free(void *data, void *arg) {
-       dns__nta_t *nta = (dns__nta_t *)data;
-
-       UNUSED(arg);
-
-       dns__nta_shutdown(nta);
-       dns__nta_detach(&nta); /* for nta_create() */
-}
-
-isc_result_t
+void
 dns_ntatable_create(dns_view_t *view, isc_loopmgr_t *loopmgr,
                    dns_ntatable_t **ntatablep) {
-       dns_ntatable_t *ntatable;
-       isc_result_t result;
+       dns_ntatable_t *ntatable = NULL;
 
        REQUIRE(ntatablep != NULL && *ntatablep == NULL);
 
@@ -121,38 +129,30 @@ dns_ntatable_create(dns_view_t *view, isc_loopmgr_t *loopmgr,
        isc_mem_attach(view->mctx, &ntatable->mctx);
        dns_view_weakattach(view, &ntatable->view);
 
-       result = dns_rbt_create(ntatable->mctx, dns__nta_free, NULL,
-                               &ntatable->table);
-       if (result != ISC_R_SUCCESS) {
-               goto cleanup;
-       }
-
        isc_rwlock_init(&ntatable->rwlock);
+       dns_qpmulti_create(view->mctx, &qpmethods, view, &ntatable->table);
 
        isc_refcount_init(&ntatable->references, 1);
 
        ntatable->magic = NTATABLE_MAGIC;
        *ntatablep = ntatable;
-
-       return (ISC_R_SUCCESS);
-
-cleanup:
-       isc_mem_putanddetach(&ntatable->mctx, ntatable, sizeof(*ntatable));
-
-       return (result);
 }
 
 static void
 dns__ntatable_destroy(dns_ntatable_t *ntatable) {
        isc_refcount_destroy(&ntatable->references);
        ntatable->magic = 0;
-       dns_rbt_destroy(&ntatable->table);
        isc_rwlock_destroy(&ntatable->rwlock);
+       dns_qpmulti_destroy(&ntatable->table);
        INSIST(ntatable->view == NULL);
        isc_mem_putanddetach(&ntatable->mctx, ntatable, sizeof(*ntatable));
 }
 
+#if DNS_NTA_TRACE
+ISC_REFCOUNT_TRACE_IMPL(dns_ntatable, dns__ntatable_destroy);
+#else
 ISC_REFCOUNT_IMPL(dns_ntatable, dns__ntatable_destroy);
+#endif
 
 static void
 fetch_done(void *arg) {
@@ -301,7 +301,8 @@ dns_ntatable_add(dns_ntatable_t *ntatable, const dns_name_t *name, bool force,
                 isc_stdtime_t now, uint32_t lifetime) {
        isc_result_t result = ISC_R_SUCCESS;
        dns__nta_t *nta = NULL;
-       dns_rbtnode_t *node = NULL;
+       dns_qp_t *qp = NULL;
+       void *pval = NULL;
 
        REQUIRE(VALID_NTATABLE(ntatable));
 
@@ -310,150 +311,144 @@ dns_ntatable_add(dns_ntatable_t *ntatable, const dns_name_t *name, bool force,
        }
 
        RWLOCK(&ntatable->rwlock, isc_rwlocktype_write);
-
+       dns_qpmulti_write(ntatable->table, &qp);
        nta_create(ntatable, name, &nta);
-
-       nta->expiry = now + lifetime;
        nta->forced = force;
 
-       result = dns_rbt_addnode(ntatable->table, name, &node);
+       result = dns_qp_insert(qp, nta, 0);
        switch (result) {
        case ISC_R_EXISTS:
-               result = ISC_R_SUCCESS;
-               if (node->data != NULL) {
-                       /* NTA already exists, just update the timer */
-                       dns__nta_t *node_nta = (dns__nta_t *)node->data;
-                       node_nta->expiry = nta->expiry;
+               result = dns_qp_getname(qp, nta->name, &pval, NULL);
+               if (result == ISC_R_SUCCESS) {
+                       /*
+                        * an NTA already existed: throw away the
+                        * new one and update the old one.
+                        */
                        dns__nta_detach(&nta); /* for nta_create */
+                       nta = pval;
                        break;
                }
-               /* Node was empty, update as if new */
+               /* update the NTA's timer as if it were new */
                FALLTHROUGH;
        case ISC_R_SUCCESS:
-               INSIST(node != NULL);
-               INSIST(node->data == NULL);
+               nta->expiry = now + lifetime;
                if (!force) {
                        settimer(ntatable, nta, lifetime);
                }
-               node->data = nta;
                break;
        default:
                break;
        }
 
+       dns_qp_compact(qp, DNS_QPGC_MAYBE);
+       dns_qpmulti_commit(ntatable->table, &qp);
        RWUNLOCK(&ntatable->rwlock, isc_rwlocktype_write);
 
        return (result);
 }
 
-/*
- * Caller must hold a write lock on rwlock.
- */
-static isc_result_t
-deletenode(dns_ntatable_t *ntatable, const dns_name_t *name) {
+isc_result_t
+dns_ntatable_delete(dns_ntatable_t *ntatable, const dns_name_t *name) {
        isc_result_t result;
-       dns_rbtnode_t *node = NULL;
+       dns_qp_t *qp = NULL;
+       void *pval = NULL;
 
-       result = dns_rbt_findnode(ntatable->table, name, NULL, &node, NULL,
-                                 DNS_RBTFIND_NOOPTIONS, NULL, NULL);
-       switch (result) {
-       case ISC_R_SUCCESS:
-               if (node->data == NULL) {
-                       /* Found empty node */
-                       return (ISC_R_NOTFOUND);
-               }
+       REQUIRE(VALID_NTATABLE(ntatable));
+       REQUIRE(name != NULL);
 
-               result = dns_rbt_deletenode(ntatable->table, node, false);
-               return (result);
-       case DNS_R_PARTIALMATCH:
-               return (ISC_R_NOTFOUND);
-       default:
-               return (result);
+       dns_qpmulti_write(ntatable->table, &qp);
+       result = dns_qp_deletename(qp, name, &pval, NULL);
+       if (result == ISC_R_SUCCESS) {
+               dns__nta_t *n = pval;
+               dns__nta_shutdown(n);
+               dns__nta_detach(&n);
        }
+       dns_qp_compact(qp, DNS_QPGC_MAYBE);
+       dns_qpmulti_commit(ntatable->table, &qp);
+
+       return (result);
 }
 
-isc_result_t
-dns_ntatable_delete(dns_ntatable_t *ntatable, const dns_name_t *name) {
+static void
+delete_expired(void *arg) {
+       dns__nta_t *nta = arg;
+       dns_ntatable_t *ntatable = nta->ntatable;
        isc_result_t result;
+       dns_qp_t *qp = NULL;
+       void *pval = NULL;
 
        REQUIRE(VALID_NTATABLE(ntatable));
-       REQUIRE(name != NULL);
 
        RWLOCK(&ntatable->rwlock, isc_rwlocktype_write);
-       result = deletenode(ntatable, name);
+       dns_qpmulti_write(ntatable->table, &qp);
+       result = dns_qp_getname(qp, nta->name, &pval, NULL);
+       if (result == ISC_R_SUCCESS &&
+           ((dns__nta_t *)pval)->expiry == nta->expiry && !nta->shuttingdown)
+       {
+               char nb[DNS_NAME_FORMATSIZE];
+               dns_name_format(nta->name, nb, sizeof(nb));
+               isc_log_write(dns_lctx, DNS_LOGCATEGORY_DNSSEC,
+                             DNS_LOGMODULE_NTA, ISC_LOG_INFO,
+                             "deleting expired NTA at %s", nb);
+               dns_qp_deletename(qp, nta->name, NULL, NULL);
+               dns__nta_shutdown(nta);
+               dns__nta_unref(nta);
+       }
+       dns_qp_compact(qp, DNS_QPGC_MAYBE);
+       dns_qpmulti_commit(ntatable->table, &qp);
        RWUNLOCK(&ntatable->rwlock, isc_rwlocktype_write);
-
-       return (result);
+       dns__nta_detach(&nta);
+       dns_ntatable_detach(&ntatable);
 }
 
 bool
 dns_ntatable_covered(dns_ntatable_t *ntatable, isc_stdtime_t now,
                     const dns_name_t *name, const dns_name_t *anchor) {
        isc_result_t result;
-       dns_fixedname_t fn;
-       dns_rbtnode_t *node;
-       dns_name_t *foundname;
        dns__nta_t *nta = NULL;
        bool answer = false;
-       isc_rwlocktype_t locktype;
-       char nb[DNS_NAME_FORMATSIZE];
+       dns_qpread_t qpr;
+       void *pval = NULL;
 
        REQUIRE(VALID_NTATABLE(ntatable));
        REQUIRE(dns_name_isabsolute(name));
 
-       foundname = dns_fixedname_initname(&fn);
+       RWLOCK(&ntatable->rwlock, isc_rwlocktype_read);
+       dns_qpmulti_query(ntatable->table, &qpr);
+       result = dns_qp_findname_ancestor(&qpr, name, 0, &pval, NULL);
+       nta = pval;
 
-       locktype = isc_rwlocktype_read;
-relock:
-       RWLOCK(&ntatable->rwlock, locktype);
-again:
-       node = NULL;
-       result = dns_rbt_findnode(ntatable->table, name, foundname, &node, NULL,
-                                 DNS_RBTFIND_NOOPTIONS, NULL, NULL);
        switch (result) {
        case ISC_R_SUCCESS:
-               /* Found a node */
+               /* Exact match */
                break;
        case DNS_R_PARTIALMATCH:
-               if (!dns_name_issubdomain(foundname, anchor)) {
-                       goto unlock;
+               /*
+                * Found a NTA that's an ancestor of 'name'; we
+                * now have to make sure 'anchor' isn't below it.
+                */
+               if (!dns_name_issubdomain(nta->name, anchor)) {
+                       goto done;
                }
-               /* Found a parental node */
-               result = ISC_R_SUCCESS;
+               /* Ancestor match */
                break;
        default:
-               goto unlock;
-       }
-
-       INSIST(result == ISC_R_SUCCESS);
-       nta = (dns__nta_t *)node->data;
-       if (nta->expiry > now) {
-               /* We got non-expired answer */
-               answer = true;
-               goto unlock;
+               /* Found nothing */
+               goto done;
        }
 
-       /* Deal with expired NTA */
-       if (locktype == isc_rwlocktype_read) {
-               RWUNLOCK(&ntatable->rwlock, locktype);
-               locktype = isc_rwlocktype_write;
-               goto relock;
+       if (nta->expiry <= now) {
+               /* NTA is expired */
+               dns__nta_ref(nta);
+               dns_ntatable_ref(nta->ntatable);
+               isc_async_current(nta->ntatable->loopmgr, delete_expired, nta);
+               goto done;
        }
 
-       dns_name_format(foundname, nb, sizeof(nb));
-       isc_log_write(dns_lctx, DNS_LOGCATEGORY_DNSSEC, DNS_LOGMODULE_NTA,
-                     ISC_LOG_INFO, "deleting expired NTA at %s", nb);
-
-       /* We already found the node under the lock, so just delete it */
-       result = dns_rbt_deletenode(ntatable->table, node, false);
-       INSIST(result == ISC_R_SUCCESS);
-
-       /* Look again */
-       goto again;
-
-unlock:
-       RWUNLOCK(&ntatable->rwlock, locktype);
-
+       answer = true;
+done:
+       RWUNLOCK(&ntatable->rwlock, isc_rwlocktype_read);
+       dns_qpread_destroy(ntatable->table, &qpr);
        return (answer);
 }
 
@@ -473,150 +468,109 @@ putstr(isc_buffer_t **b, const char *str) {
 isc_result_t
 dns_ntatable_totext(dns_ntatable_t *ntatable, const char *view,
                    isc_buffer_t **buf) {
-       isc_result_t result;
-       dns_rbtnode_t *node;
-       dns_rbtnodechain_t chain;
-       bool first = true;
+       isc_result_t result = ISC_R_SUCCESS;
        isc_stdtime_t now = isc_stdtime_now();
+       dns_qpread_t qpr;
+       dns_qpiter_t iter;
+       bool first = true;
+       void *pval = NULL;
 
        REQUIRE(VALID_NTATABLE(ntatable));
 
        RWLOCK(&ntatable->rwlock, isc_rwlocktype_read);
-       dns_rbtnodechain_init(&chain);
-       result = dns_rbtnodechain_first(&chain, ntatable->table, NULL, NULL);
-       if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN) {
-               if (result == ISC_R_NOTFOUND) {
-                       result = ISC_R_SUCCESS;
-               }
-               goto cleanup;
-       }
-       for (;;) {
-               dns_rbtnodechain_current(&chain, NULL, NULL, &node);
-               if (node->data != NULL) {
-                       dns__nta_t *n = (dns__nta_t *)node->data;
-                       char nbuf[DNS_NAME_FORMATSIZE];
-                       char tbuf[ISC_FORMATHTTPTIMESTAMP_SIZE];
-                       char obuf[DNS_NAME_FORMATSIZE +
-                                 ISC_FORMATHTTPTIMESTAMP_SIZE +
-                                 sizeof("expired:  \n")];
-                       dns_fixedname_t fn;
-                       dns_name_t *name;
-                       isc_time_t t;
-
-                       name = dns_fixedname_initname(&fn);
-                       dns_rbt_fullnamefromnode(node, name);
-                       dns_name_format(name, nbuf, sizeof(nbuf));
-
-                       if (n->expiry != 0xffffffffU) {
-                               /* Normal NTA entries */
-                               isc_time_set(&t, n->expiry, 0);
-                               isc_time_formattimestamp(&t, tbuf,
-                                                        sizeof(tbuf));
-
-                               snprintf(obuf, sizeof(obuf), "%s%s%s%s: %s %s",
-                                        first ? "" : "\n", nbuf,
-                                        view != NULL ? "/" : "",
-                                        view != NULL ? view : "",
-                                        n->expiry <= now ? "expired"
-                                                         : "expiry",
-                                        tbuf);
-                       } else {
-                               /* "validate-except" entries */
-                               snprintf(obuf, sizeof(obuf), "%s%s%s%s: %s",
-                                        first ? "" : "\n", nbuf,
-                                        view != NULL ? "/" : "",
-                                        view != NULL ? view : "", "permanent");
-                       }
-
-                       first = false;
-                       result = putstr(buf, obuf);
-                       if (result != ISC_R_SUCCESS) {
-                               goto cleanup;
-                       }
+       dns_qpmulti_query(ntatable->table, &qpr);
+       dns_qpiter_init(&qpr, &iter);
+
+       while (dns_qpiter_next(&iter, &pval, NULL) == ISC_R_SUCCESS) {
+               dns__nta_t *n = pval;
+               char nbuf[DNS_NAME_FORMATSIZE];
+               char tbuf[ISC_FORMATHTTPTIMESTAMP_SIZE];
+               char obuf[DNS_NAME_FORMATSIZE + ISC_FORMATHTTPTIMESTAMP_SIZE +
+                         sizeof("expired:  \n")];
+               isc_time_t t;
+
+               dns_name_format(n->name, nbuf, sizeof(nbuf));
+
+               if (n->expiry != 0xffffffffU) {
+                       /* Normal NTA entries */
+                       isc_time_set(&t, n->expiry, 0);
+                       isc_time_formattimestamp(&t, tbuf, sizeof(tbuf));
+
+                       snprintf(obuf, sizeof(obuf), "%s%s%s%s: %s %s",
+                                first ? "" : "\n", nbuf,
+                                view != NULL ? "/" : "",
+                                view != NULL ? view : "",
+                                n->expiry <= now ? "expired" : "expiry", tbuf);
+               } else {
+                       /* "validate-except" entries */
+                       snprintf(obuf, sizeof(obuf), "%s%s%s%s: %s",
+                                first ? "" : "\n", nbuf,
+                                view != NULL ? "/" : "",
+                                view != NULL ? view : "", "permanent");
                }
-               result = dns_rbtnodechain_next(&chain, NULL, NULL);
-               if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN) {
-                       if (result == ISC_R_NOMORE) {
-                               result = ISC_R_SUCCESS;
-                       }
-                       break;
+
+               first = false;
+               result = putstr(buf, obuf);
+               if (result != ISC_R_SUCCESS) {
+                       goto cleanup;
                }
        }
 
 cleanup:
-       dns_rbtnodechain_invalidate(&chain);
+       dns_qpread_destroy(ntatable->table, &qpr);
        RWUNLOCK(&ntatable->rwlock, isc_rwlocktype_read);
        return (result);
 }
 
 isc_result_t
 dns_ntatable_save(dns_ntatable_t *ntatable, FILE *fp) {
-       isc_result_t result;
-       dns_rbtnode_t *node;
-       dns_rbtnodechain_t chain;
+       isc_result_t result = ISC_R_SUCCESS;
        isc_stdtime_t now = isc_stdtime_now();
+       dns_qpread_t qpr;
+       dns_qpiter_t iter;
        bool written = false;
+       void *pval = NULL;
 
        REQUIRE(VALID_NTATABLE(ntatable));
 
        RWLOCK(&ntatable->rwlock, isc_rwlocktype_read);
-       dns_rbtnodechain_init(&chain);
-       result = dns_rbtnodechain_first(&chain, ntatable->table, NULL, NULL);
-       if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN) {
-               goto cleanup;
-       }
-
-       for (;;) {
-               dns_rbtnodechain_current(&chain, NULL, NULL, &node);
-               if (node->data != NULL) {
-                       isc_buffer_t b;
-                       char nbuf[DNS_NAME_FORMATSIZE + 1], tbuf[80];
-                       dns_fixedname_t fn;
-                       dns_name_t *name;
-                       dns__nta_t *n = (dns__nta_t *)node->data;
-
-                       /*
-                        * Skip this node if the expiry is already in the
-                        * past, or if this is a "validate-except" entry.
-                        */
-                       if (n->expiry <= now || n->expiry == 0xffffffffU) {
-                               goto skip;
-                       }
-
-                       name = dns_fixedname_initname(&fn);
-                       dns_rbt_fullnamefromnode(node, name);
+       dns_qpmulti_query(ntatable->table, &qpr);
+       dns_qpiter_init(&qpr, &iter);
+
+       while (dns_qpiter_next(&iter, &pval, NULL) == ISC_R_SUCCESS) {
+               dns__nta_t *n = pval;
+               isc_buffer_t b;
+               char nbuf[DNS_NAME_FORMATSIZE + 1], tbuf[80];
+
+               /*
+                * Skip this node if the expiry is already in the
+                * past, or if this is a "validate-except" entry.
+                */
+               if (n->expiry <= now || n->expiry == 0xffffffffU) {
+                       continue;
+               }
 
-                       isc_buffer_init(&b, nbuf, sizeof(nbuf));
-                       result = dns_name_totext(name, false, &b);
-                       if (result != ISC_R_SUCCESS) {
-                               goto skip;
-                       }
+               isc_buffer_init(&b, nbuf, sizeof(nbuf));
+               result = dns_name_totext(n->name, false, &b);
+               if (result != ISC_R_SUCCESS) {
+                       continue;
+               }
 
-                       /* Zero terminate. */
-                       isc_buffer_putuint8(&b, 0);
+               /* Zero terminate */
+               isc_buffer_putuint8(&b, 0);
 
-                       isc_buffer_init(&b, tbuf, sizeof(tbuf));
-                       dns_time32_totext(n->expiry, &b);
+               isc_buffer_init(&b, tbuf, sizeof(tbuf));
+               dns_time32_totext(n->expiry, &b);
 
-                       /* Zero terminate. */
-                       isc_buffer_putuint8(&b, 0);
+               /* Zero terminate */
+               isc_buffer_putuint8(&b, 0);
 
-                       fprintf(fp, "%s %s %s\n", nbuf,
-                               n->forced ? "forced" : "regular", tbuf);
-                       written = true;
-               }
-       skip:
-               result = dns_rbtnodechain_next(&chain, NULL, NULL);
-               if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN) {
-                       if (result == ISC_R_NOMORE) {
-                               result = ISC_R_SUCCESS;
-                       }
-                       break;
-               }
+               fprintf(fp, "%s %s %s\n", nbuf,
+                       n->forced ? "forced" : "regular", tbuf);
+               written = true;
        }
 
-cleanup:
-       dns_rbtnodechain_invalidate(&chain);
+       dns_qpread_destroy(ntatable->table, &qpr);
        RWUNLOCK(&ntatable->rwlock, isc_rwlocktype_read);
 
        if (result == ISC_R_SUCCESS && !written) {
@@ -630,6 +584,13 @@ static void
 dns__nta_shutdown_cb(dns__nta_t *nta) {
        REQUIRE(VALID_NTA(nta));
 
+       if (isc_log_wouldlog(dns_lctx, ISC_LOG_DEBUG(3))) {
+               char nb[DNS_NAME_FORMATSIZE];
+               dns_name_format(nta->name, nb, sizeof(nb));
+               isc_log_write(dns_lctx, DNS_LOGCATEGORY_DNSSEC,
+                             DNS_LOGMODULE_NTA, ISC_LOG_DEBUG(3),
+                             "shutting down NTA %p at %s", nta, nb);
+       }
        if (nta->timer) {
                isc_timer_stop(nta->timer);
                isc_timer_destroy(&nta->timer);
@@ -644,32 +605,56 @@ dns__nta_shutdown(dns__nta_t *nta) {
 
        dns__nta_ref(nta);
        isc_async_run(nta->loop, (isc_job_cb)dns__nta_shutdown_cb, nta);
+       nta->shuttingdown = true;
 }
 
 void
 dns_ntatable_shutdown(dns_ntatable_t *ntatable) {
-       isc_result_t result;
-       dns_rbtnode_t *node;
-       dns_rbtnodechain_t chain;
+       dns_qpread_t qpr;
+       dns_qpiter_t iter;
+       void *pval = NULL;
 
        REQUIRE(VALID_NTATABLE(ntatable));
 
        RWLOCK(&ntatable->rwlock, isc_rwlocktype_write);
+       dns_qpmulti_query(ntatable->table, &qpr);
        ntatable->shuttingdown = true;
 
-       dns_rbtnodechain_init(&chain);
-       result = dns_rbtnodechain_first(&chain, ntatable->table, NULL, NULL);
-       while (result == ISC_R_SUCCESS || result == DNS_R_NEWORIGIN) {
-               dns_rbtnodechain_current(&chain, NULL, NULL, &node);
-               if (node->data != NULL) {
-                       dns__nta_t *nta = (dns__nta_t *)node->data;
-                       dns__nta_shutdown(nta);
-               }
-               result = dns_rbtnodechain_next(&chain, NULL, NULL);
+       dns_qpiter_init(&qpr, &iter);
+       while (dns_qpiter_next(&iter, &pval, NULL) == ISC_R_SUCCESS) {
+               dns__nta_t *n = pval;
+               dns__nta_shutdown(n);
+               dns__nta_detach(&n);
        }
 
-       dns_rbtnodechain_invalidate(&chain);
-
+       dns_qpread_destroy(ntatable->table, &qpr);
        dns_view_weakdetach(&ntatable->view);
        RWUNLOCK(&ntatable->rwlock, isc_rwlocktype_write);
 }
+
+static void
+qp_attach(void *uctx ISC_ATTR_UNUSED, void *pval,
+         uint32_t ival ISC_ATTR_UNUSED) {
+       dns__nta_t *nta = pval;
+       dns__nta_ref(nta);
+}
+
+static void
+qp_detach(void *uctx ISC_ATTR_UNUSED, void *pval,
+         uint32_t ival ISC_ATTR_UNUSED) {
+       dns__nta_t *nta = pval;
+       dns__nta_detach(&nta);
+}
+
+static size_t
+qp_makekey(dns_qpkey_t key, void *uctx ISC_ATTR_UNUSED, void *pval,
+          uint32_t ival ISC_ATTR_UNUSED) {
+       dns__nta_t *nta = pval;
+       return (dns_qpkey_fromname(key, nta->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);
+}
index 1fe0c16dabd93a72abc9797e396de1bba2bd8b95..3683ea0472b563ae98312068c383f418090cfb21 100644 (file)
@@ -1564,13 +1564,13 @@ dns_view_freezezones(dns_view_t *view, bool value) {
        return (result);
 }
 
-isc_result_t
+void
 dns_view_initntatable(dns_view_t *view, isc_loopmgr_t *loopmgr) {
        REQUIRE(DNS_VIEW_VALID(view));
        if (view->ntatable_priv != NULL) {
                dns_ntatable_detach(&view->ntatable_priv);
        }
-       return (dns_ntatable_create(view, loopmgr, &view->ntatable_priv));
+       dns_ntatable_create(view, loopmgr, &view->ntatable_priv);
 }
 
 isc_result_t
index eea42150bd2ab09687c276e7dba79c5c0b2b2ba2..93e13e6cc3bf1b5836df043b356bff4723793bbb 100644 (file)
@@ -174,8 +174,7 @@ create_tables(void) {
                         ISC_R_SUCCESS);
 
        assert_int_equal(dns_keytable_create(mctx, &keytable), ISC_R_SUCCESS);
-       assert_int_equal(dns_ntatable_create(view, loopmgr, &ntatable),
-                        ISC_R_SUCCESS);
+       dns_ntatable_create(view, loopmgr, &ntatable);
 
        /* Add a normal key */
        dns_test_namefromstring("example.com.", &fn);
@@ -611,8 +610,7 @@ ISC_LOOP_TEST_IMPL(nta) {
        result = dns_view_getsecroots(myview, &keytable);
        assert_int_equal(result, ISC_R_SUCCESS);
 
-       result = dns_view_initntatable(myview, loopmgr);
-       assert_int_equal(result, ISC_R_SUCCESS);
+       dns_view_initntatable(myview, loopmgr);
        result = dns_view_getntatable(myview, &ntatable);
        assert_int_equal(result, ISC_R_SUCCESS);
 
@@ -686,12 +684,12 @@ ISC_LOOP_TEST_IMPL(nta) {
        assert_false(covered);
        assert_true(issecure);
 
+       isc_loopmgr_shutdown(loopmgr);
+
        /* Clean up */
        dns_ntatable_detach(&ntatable);
        dns_keytable_detach(&keytable);
        dns_view_detach(&myview);
-
-       isc_loopmgr_shutdown(loopmgr);
 }
 
 ISC_TEST_LIST_START
index 4d30f74b522b6cd700a9276a203b05adbdad8263..fb95350f1f3d3e9565c8bc005dea8b6e8ce2fc8d 100644 (file)
@@ -325,6 +325,8 @@ ISC_RUN_TEST_IMPL(partialmatch) {
                  "foo.bar." },
                { "my.web.foo.bar.", DNS_QPFIND_NOEXACT, DNS_R_PARTIALMATCH,
                  "web.foo.bar." },
+               { "my.other.foo.bar.", DNS_QPFIND_NOEXACT, DNS_R_PARTIALMATCH,
+                 "foo.bar." },
                { NULL, 0, 0, NULL },
        };
        check_partialmatch(qp, check1);