From be24feb252a2c905593e4c69dcfe0ee4fe98ee76 Mon Sep 17 00:00:00 2001 From: Evan Hunt Date: Tue, 3 Oct 2023 18:55:24 -0700 Subject: [PATCH] stub dns_qpmulti-based zone database implementation created files for a dns_qpmulti-based zone database, "qpzone". currently this only has create and destroy functions. --- lib/dns/Makefile.am | 2 + lib/dns/db.c | 9 + lib/dns/qpzone.c | 712 ++++++++++++++++++++++++++++++++++++++++++++ lib/dns/qpzone_p.h | 51 ++++ 4 files changed, 774 insertions(+) create mode 100644 lib/dns/qpzone.c create mode 100644 lib/dns/qpzone_p.h diff --git a/lib/dns/Makefile.am b/lib/dns/Makefile.am index 759c637856..0cef1256cb 100644 --- a/lib/dns/Makefile.am +++ b/lib/dns/Makefile.am @@ -216,6 +216,8 @@ libdns_la_SOURCES = \ probes.d \ qp.c \ qp_p.h \ + qpzone_p.h \ + qpzone.c \ rbt.c \ rbt-cachedb.c \ rbt-zonedb.c \ diff --git a/lib/dns/db.c b/lib/dns/db.c index 149fc95f89..98e2c3f8f9 100644 --- a/lib/dns/db.c +++ b/lib/dns/db.c @@ -63,6 +63,7 @@ struct dns_dbimplementation { #include "db_p.h" #include "qpdb_p.h" +#include "qpzone_p.h" #include "rbtdb_p.h" unsigned int dns_pps = 0U; @@ -73,6 +74,7 @@ static isc_once_t once = ISC_ONCE_INIT; static dns_dbimplementation_t rbtimp; static dns_dbimplementation_t qpimp; +static dns_dbimplementation_t qpzoneimp; static void initialize(void) { @@ -92,8 +94,15 @@ initialize(void) { .link = ISC_LINK_INITIALIZER, }; + qpzoneimp = (dns_dbimplementation_t){ + .name = "qpzone", + .create = dns__qpzone_create, + .link = ISC_LINK_INITIALIZER, + }; + ISC_LIST_APPEND(implementations, &rbtimp, link); ISC_LIST_APPEND(implementations, &qpimp, link); + ISC_LIST_APPEND(implementations, &qpzoneimp, link); } static dns_dbimplementation_t * diff --git a/lib/dns/qpzone.c b/lib/dns/qpzone.c new file mode 100644 index 0000000000..946ca06b3f --- /dev/null +++ b/lib/dns/qpzone.c @@ -0,0 +1,712 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +/*! \file */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "db_p.h" +#include "qpzone_p.h" + +#define CHECK(op) \ + do { \ + result = (op); \ + if (result != ISC_R_SUCCESS) \ + goto failure; \ + } while (0) + +#define EXISTS(header) \ + ((atomic_load_acquire(&(header)->attributes) & \ + DNS_SLABHEADERATTR_NONEXISTENT) == 0) +#define IGNORE(header) \ + ((atomic_load_acquire(&(header)->attributes) & \ + DNS_SLABHEADERATTR_IGNORE) != 0) +#define NXDOMAIN(header) \ + ((atomic_load_acquire(&(header)->attributes) & \ + DNS_SLABHEADERATTR_NXDOMAIN) != 0) +#define RESIGN(header) \ + ((atomic_load_acquire(&(header)->attributes) & \ + DNS_SLABHEADERATTR_RESIGN) != 0) +#define OPTOUT(header) \ + ((atomic_load_acquire(&(header)->attributes) & \ + DNS_SLABHEADERATTR_OPTOUT) != 0) +#define NEGATIVE(header) \ + ((atomic_load_acquire(&(header)->attributes) & \ + DNS_SLABHEADERATTR_NEGATIVE) != 0) +#define PREFETCH(header) \ + ((atomic_load_acquire(&(header)->attributes) & \ + DNS_SLABHEADERATTR_PREFETCH) != 0) +#define CASESET(header) \ + ((atomic_load_acquire(&(header)->attributes) & \ + DNS_SLABHEADERATTR_CASESET) != 0) +#define ZEROTTL(header) \ + ((atomic_load_acquire(&(header)->attributes) & \ + DNS_SLABHEADERATTR_ZEROTTL) != 0) +#define STATCOUNT(header) \ + ((atomic_load_acquire(&(header)->attributes) & \ + DNS_SLABHEADERATTR_STATCOUNT) != 0) + +#define QPDB_ATTR_LOADED 0x01 +#define QPDB_ATTR_LOADING 0x02 + +#define DEFAULT_NODE_LOCK_COUNT 7 /*%< Should be prime. */ + +/*% + * Note that "impmagic" is not the first four bytes of the struct, so + * ISC_MAGIC_VALID cannot be used. + */ +#define QPZONE_DB_MAGIC ISC_MAGIC('Q', 'Z', 'D', 'B') +#define VALID_QPZONE(qpdb) \ + ((qpdb) != NULL && (qpdb)->common.impmagic == QPZONE_DB_MAGIC) + +typedef struct qpzonedb qpzonedb_t; + +typedef struct qpdb_changed { + dns_rbtnode_t *node; + bool dirty; + ISC_LINK(struct qpdb_changed) link; +} qpdb_changed_t; + +typedef ISC_LIST(qpdb_changed_t) qpdb_changedlist_t; + +typedef struct qpdb_version qpdb_version_t; +struct qpdb_version { + /* Not locked */ + uint32_t serial; + qpzonedb_t *qpdb; + isc_refcount_t references; + /* Locked by database lock. */ + bool writer; + qpdb_changedlist_t changed_list; + dns_slabheaderlist_t resigned_list; + ISC_LINK(qpdb_version_t) link; + bool secure; + bool havensec3; + /* NSEC3 parameters */ + dns_hash_t hash; + uint8_t flags; + uint16_t iterations; + uint8_t salt_length; + unsigned char salt[DNS_NSEC3_SALTSIZE]; + + /* + * records and xfrsize are covered by rwlock. + */ + isc_rwlock_t rwlock; + uint64_t records; + uint64_t xfrsize; + + struct cds_wfs_stack glue_stack; +}; + +typedef ISC_LIST(qpdb_version_t) qpdb_versionlist_t; + +typedef struct qpdata { + dns_fixedname_t fn; + dns_name_t *name; + isc_mem_t *mctx; + isc_refcount_t references; + uint16_t locknum; + unsigned int : 0; + unsigned int nsec : 2; /*%< range is 0..3 */ + unsigned int : 0; +} qpdata_t; + +struct qpzonedb { + /* Unlocked. */ + dns_db_t common; + /* Locks the data in this struct */ + isc_rwlock_t lock; + /* Locks for tree nodes */ + int node_lock_count; + db_nodelock_t *node_locks; + qpdata_t *origin; + qpdata_t *nsec3_origin; + dns_stats_t *rrsetstats; /* cache DB only */ + isc_stats_t *cachestats; /* cache DB only */ + isc_stats_t *gluecachestats; /* zone DB only */ + /* Locked by lock. */ + unsigned int active; + unsigned int attributes; + uint32_t current_serial; + uint32_t least_serial; + uint32_t next_serial; + qpdb_version_t *current_version; + qpdb_version_t *future_version; + qpdb_versionlist_t open_versions; + isc_loop_t *loop; + + isc_heap_t **heaps; /* Resigning heaps, one per nodelock bucket */ + + dns_qpmulti_t *tree; /* Main QP trie for data storage */ + dns_qpmulti_t *nsec; /* NSEC nodes only */ + dns_qpmulti_t *nsec3; /* NSEC3 nodes only */ +}; + +static dns_dbmethods_t qpdb_zonemethods; + +#if DNS_DB_NODETRACE +#define qpdata_ref(ptr) qpdata__ref(ptr, __func__, __FILE__, __LINE__) +#define qpdata_unref(ptr) qpdata__unref(ptr, __func__, __FILE__, __LINE__) +#define qpdata_attach(ptr, ptrp) \ + qpdata__attach(ptr, ptrp, __func__, __FILE__, __LINE__) +#define qpdata_detach(ptrp) qpdata__detach(ptrp, __func__, __FILE__, __LINE__) +ISC_REFCOUNT_TRACE_DECL(qpdata); +#else +ISC_REFCOUNT_DECL(qpdata); +#endif + +/* QP trie methods */ +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, +}; + +/* + * Locking + * + * If a routine is going to lock more than one lock in this module, then + * the locking must be done in the following order: + * + * Tree Lock + * + * Node Lock (Only one from the set may be locked at one time by + * any caller) + * + * Database Lock + * + * Failure to follow this hierarchy can result in deadlock. + */ + +/*% + * Return which RRset should be resigned sooner. If the RRsets have the + * same signing time, prefer the other RRset over the SOA RRset. + */ +static bool +resign_sooner(void *v1, void *v2) { + dns_slabheader_t *h1 = v1; + dns_slabheader_t *h2 = v2; + + return (h1->resign < h2->resign || + (h1->resign == h2->resign && h1->resign_lsb < h2->resign_lsb) || + (h1->resign == h2->resign && h1->resign_lsb == h2->resign_lsb && + h2->type == DNS_SIGTYPE(dns_rdatatype_soa))); +} + +/*% + * This function sets the heap index into the header. + */ +static void +set_index(void *what, unsigned int idx) { + dns_slabheader_t *h = what; + + h->heap_index = idx; +} + +static void +freeglue(dns_glue_t *glue_list) { + if (glue_list == (void *)-1) { + return; + } + + dns_glue_t *glue = glue_list; + while (glue != NULL) { + dns_glue_t *next = glue->next; + + if (dns_rdataset_isassociated(&glue->rdataset_a)) { + dns_rdataset_disassociate(&glue->rdataset_a); + } + if (dns_rdataset_isassociated(&glue->sigrdataset_a)) { + dns_rdataset_disassociate(&glue->sigrdataset_a); + } + + if (dns_rdataset_isassociated(&glue->rdataset_aaaa)) { + dns_rdataset_disassociate(&glue->rdataset_aaaa); + } + if (dns_rdataset_isassociated(&glue->sigrdataset_aaaa)) { + dns_rdataset_disassociate(&glue->sigrdataset_aaaa); + } + + dns_rdataset_invalidate(&glue->rdataset_a); + dns_rdataset_invalidate(&glue->sigrdataset_a); + dns_rdataset_invalidate(&glue->rdataset_aaaa); + dns_rdataset_invalidate(&glue->sigrdataset_aaaa); + + isc_mem_putanddetach(&glue->mctx, glue, sizeof(*glue)); + + glue = next; + } +} + +static void +free_gluelist_rcu(struct rcu_head *rcu_head) { + dns_glue_t *glue = caa_container_of(rcu_head, dns_glue_t, rcu_head); + + freeglue(glue); +} + +static void +free_gluetable(struct cds_wfs_stack *glue_stack) { + struct cds_wfs_head *head = __cds_wfs_pop_all(glue_stack); + struct cds_wfs_node *node = NULL, *next = NULL; + + rcu_read_lock(); + cds_wfs_for_each_blocking_safe(head, node, next) { + dns_slabheader_t *header = + caa_container_of(node, dns_slabheader_t, wfs_node); + dns_glue_t *glue = rcu_xchg_pointer(&header->glue_list, NULL); + + call_rcu(&glue->rcu_head, free_gluelist_rcu); + } + rcu_read_unlock(); +} + +static void +free_qpdb(qpzonedb_t *qpdb, bool log) { + char buf[DNS_NAME_FORMATSIZE]; + dns_qpmulti_t **treep = NULL; + + REQUIRE(qpdb->current_version != NULL || EMPTY(qpdb->open_versions)); + REQUIRE(qpdb->future_version == NULL); + + if (qpdb->current_version != NULL) { + isc_refcount_decrementz(&qpdb->current_version->references); + + isc_refcount_destroy(&qpdb->current_version->references); + UNLINK(qpdb->open_versions, qpdb->current_version, link); + cds_wfs_destroy(&qpdb->current_version->glue_stack); + isc_rwlock_destroy(&qpdb->current_version->rwlock); + isc_mem_put(qpdb->common.mctx, qpdb->current_version, + sizeof(*qpdb->current_version)); + } + + for (;;) { + /* + * pick the next tree to destroy + */ + treep = &qpdb->tree; + if (*treep == NULL) { + treep = &qpdb->nsec; + if (*treep == NULL) { + treep = &qpdb->nsec3; + /* + * we're finished after clear cutting + */ + if (*treep == NULL) { + break; + } + } + } + + dns_qpmulti_destroy(treep); + } + + if (log) { + if (dns_name_dynamic(&qpdb->common.origin)) { + dns_name_format(&qpdb->common.origin, buf, sizeof(buf)); + } else { + strlcpy(buf, "", sizeof(buf)); + } + isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, + DNS_LOGMODULE_DB, ISC_LOG_DEBUG(1), + "done free_qpdb(%s)", buf); + } + if (dns_name_dynamic(&qpdb->common.origin)) { + dns_name_free(&qpdb->common.origin, qpdb->common.mctx); + } + for (int i = 0; i < qpdb->node_lock_count; i++) { + isc_refcount_destroy(&qpdb->node_locks[i].references); + NODE_DESTROYLOCK(&qpdb->node_locks[i].lock); + } + + /* + * Clean up heap objects. + */ + if (qpdb->heaps != NULL) { + for (int i = 0; i < qpdb->node_lock_count; i++) { + isc_heap_destroy(&qpdb->heaps[i]); + } + isc_mem_cput(qpdb->common.mctx, qpdb->heaps, + qpdb->node_lock_count, sizeof(isc_heap_t *)); + } + + if (qpdb->rrsetstats != NULL) { + dns_stats_detach(&qpdb->rrsetstats); + } + if (qpdb->cachestats != NULL) { + isc_stats_detach(&qpdb->cachestats); + } + if (qpdb->gluecachestats != NULL) { + isc_stats_detach(&qpdb->gluecachestats); + } + + isc_mem_cput(qpdb->common.mctx, qpdb->node_locks, qpdb->node_lock_count, + sizeof(db_nodelock_t)); + isc_refcount_destroy(&qpdb->common.references); + if (qpdb->loop != NULL) { + isc_loop_detach(&qpdb->loop); + } + + isc_rwlock_destroy(&qpdb->lock); + qpdb->common.magic = 0; + qpdb->common.impmagic = 0; + + if (qpdb->common.update_listeners != NULL) { + INSIST(!cds_lfht_destroy(qpdb->common.update_listeners, NULL)); + } + + isc_mem_putanddetach(&qpdb->common.mctx, qpdb, sizeof(*qpdb)); +} + +static void +qpzonedb_destroy(dns_db_t *arg) { + qpzonedb_t *qpdb = (qpzonedb_t *)arg; + unsigned int inactive = 0; + + if (qpdb->origin != NULL) { + qpdata_detach(&qpdb->origin); + } + if (qpdb->nsec3_origin != NULL) { + qpdata_detach(&qpdb->nsec3_origin); + } + + /* + * The current version's glue table needs to be freed early + * so the nodes are dereferenced before we check the active + * node count below. + */ + if (qpdb->current_version != NULL) { + free_gluetable(&qpdb->current_version->glue_stack); + } + + /* + * Even though there are no external direct references, there still + * may be nodes in use. + */ + for (int i = 0; i < qpdb->node_lock_count; i++) { + isc_rwlocktype_t nodelock = isc_rwlocktype_none; + NODE_WRLOCK(&qpdb->node_locks[i].lock, &nodelock); + qpdb->node_locks[i].exiting = true; + if (isc_refcount_current(&qpdb->node_locks[i].references) == 0) + { + inactive++; + } + NODE_UNLOCK(&qpdb->node_locks[i].lock, &nodelock); + } + + if (inactive != 0) { + bool want_free = false; + + RWLOCK(&qpdb->lock, isc_rwlocktype_write); + qpdb->active -= inactive; + if (qpdb->active == 0) { + want_free = true; + } + RWUNLOCK(&qpdb->lock, isc_rwlocktype_write); + + if (want_free) { + char buf[DNS_NAME_FORMATSIZE]; + if (dns_name_dynamic(&qpdb->common.origin)) { + dns_name_format(&qpdb->common.origin, buf, + sizeof(buf)); + } else { + strlcpy(buf, "", sizeof(buf)); + } + isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, + DNS_LOGMODULE_DB, ISC_LOG_DEBUG(1), + "calling free_qpdb(%s)", buf); + free_qpdb(qpdb, true); + } + } +} + +static qpdata_t * +new_qpdata(isc_mem_t *mctx, const dns_name_t *name) { + qpdata_t *newdata = isc_mem_get(mctx, sizeof(*newdata)); + *newdata = (qpdata_t){ + .references = ISC_REFCOUNT_INITIALIZER(1), + }; + newdata->name = dns_fixedname_initname(&newdata->fn); + dns_name_copy(name, newdata->name); + isc_mem_attach(mctx, &newdata->mctx); + +#ifdef DNS_DB_NODETRACE + fprintf(stderr, "new_qpdata:%s:%s:%d:%p->references = 1\n", __func__, + __FILE__, __LINE__ + 1, name); +#endif + return (newdata); +} + +static qpdb_version_t * +allocate_version(isc_mem_t *mctx, uint32_t serial, unsigned int references, + bool writer) { + qpdb_version_t *version = isc_mem_get(mctx, sizeof(*version)); + *version = (qpdb_version_t){ + .serial = serial, + .writer = writer, + .changed_list = ISC_LIST_INITIALIZER, + .resigned_list = ISC_LIST_INITIALIZER, + .link = ISC_LINK_INITIALIZER, + }; + + cds_wfs_init(&version->glue_stack); + + isc_refcount_init(&version->references, references); + + return (version); +} + +isc_result_t +dns__qpzone_create(isc_mem_t *mctx, const dns_name_t *origin, dns_dbtype_t type, + dns_rdataclass_t rdclass, unsigned int argc ISC_ATTR_UNUSED, + char **argv ISC_ATTR_UNUSED, void *driverarg ISC_ATTR_UNUSED, + dns_db_t **dbp) { + qpzonedb_t *qpdb = NULL; + isc_result_t result; + dns_qp_t *qp = NULL; + + REQUIRE(type != dns_dbtype_cache); + + qpdb = isc_mem_get(mctx, sizeof(*qpdb)); + *qpdb = (qpzonedb_t){ + .common.origin = DNS_NAME_INITEMPTY, + .common.rdclass = rdclass, + .node_lock_count = DEFAULT_NODE_LOCK_COUNT, + .current_serial = 1, + .least_serial = 1, + .next_serial = 2, + .open_versions = ISC_LIST_INITIALIZER, + }; + + isc_refcount_init(&qpdb->common.references, 1); + + qpdb->common.methods = &qpdb_zonemethods; + if (type == dns_dbtype_stub) { + qpdb->common.attributes |= DNS_DBATTR_STUB; + } + + isc_rwlock_init(&qpdb->lock); + + qpdb->node_locks = isc_mem_cget(mctx, qpdb->node_lock_count, + sizeof(db_nodelock_t)); + + qpdb->common.update_listeners = cds_lfht_new(16, 16, 0, 0, NULL); + + /* + * Create the heaps. + */ + qpdb->heaps = isc_mem_cget(mctx, qpdb->node_lock_count, + sizeof(isc_heap_t *)); + for (int i = 0; i < qpdb->node_lock_count; i++) { + qpdb->heaps[i] = NULL; + } + + for (int i = 0; i < (int)qpdb->node_lock_count; i++) { + isc_heap_create(mctx, resign_sooner, set_index, 0, + &qpdb->heaps[i]); + } + + qpdb->active = qpdb->node_lock_count; + + for (int i = 0; i < qpdb->node_lock_count; i++) { + NODE_INITLOCK(&qpdb->node_locks[i].lock); + isc_refcount_init(&qpdb->node_locks[i].references, 0); + qpdb->node_locks[i].exiting = false; + } + + /* + * Attach to the mctx. The database will persist so long as there + * are references to it, and attaching to the mctx ensures that our + * mctx won't disappear out from under us. + */ + isc_mem_attach(mctx, &qpdb->common.mctx); + + /* + * Make a copy of the origin name. + */ + result = dns_name_dupwithoffsets(origin, mctx, &qpdb->common.origin); + if (result != ISC_R_SUCCESS) { + free_qpdb(qpdb, false); + return (result); + } + + dns_qpmulti_create(mctx, &qpmethods, qpdb, &qpdb->tree); + dns_qpmulti_create(mctx, &qpmethods, qpdb, &qpdb->nsec); + dns_qpmulti_create(mctx, &qpmethods, qpdb, &qpdb->nsec3); + + /* + * In order to set the node callback bit correctly in zone databases, + * we need to know if the node has the origin name of the zone. + * In loading_addrdataset() we could simply compare the new name + * to the origin name, but this is expensive. Also, we don't know the + * node name in addrdataset(), so we need another way of knowing the + * zone's top. + * + * We now explicitly create a node for the zone's origin, and then + * we simply remember the node data's address. + */ + + dns_qpmulti_write(qpdb->tree, &qp); + qpdb->origin = new_qpdata(mctx, &qpdb->common.origin); + result = dns_qp_insert(qp, qpdb->origin, 0); + qpdb->origin->nsec = DNS_DB_NSEC_NORMAL; + dns_qpmulti_commit(qpdb->tree, &qp); + + if (result != ISC_R_SUCCESS) { + INSIST(result != ISC_R_EXISTS); + free_qpdb(qpdb, false); + return (result); + } + + INSIST(qpdb->origin != NULL); + + /* + * Add an apex node to the NSEC3 tree so that NSEC3 searches + * return partial matches when there is only a single NSEC3 + * record in the tree. + */ + dns_qpmulti_write(qpdb->nsec3, &qp); + qpdb->nsec3_origin = new_qpdata(mctx, &qpdb->common.origin); + qpdb->nsec3_origin->nsec = DNS_DB_NSEC_NSEC3; + result = dns_qp_insert(qp, qpdb->nsec3_origin, 0); + dns_qpmulti_commit(qpdb->nsec3, &qp); + + if (result != ISC_R_SUCCESS) { + INSIST(result != ISC_R_EXISTS); + free_qpdb(qpdb, false); + return (result); + } + + /* + * We need to give the origin nodes the right locknum. + */ + qpdb->origin->locknum = qpdb->nsec3_origin->locknum = + dns_name_hash(&qpdb->common.origin) % qpdb->node_lock_count; + + /* + * Version Initialization. + */ + qpdb->current_version = allocate_version(mctx, 1, 1, false); + qpdb->current_version->qpdb = qpdb; + isc_rwlock_init(&qpdb->current_version->rwlock); + + /* + * Keep the current version in the open list so that list operation + * won't happen in normal lookup operations. + */ + PREPEND(qpdb->open_versions, qpdb->current_version, link); + + qpdb->common.magic = DNS_DB_MAGIC; + qpdb->common.impmagic = QPZONE_DB_MAGIC; + + *dbp = (dns_db_t *)qpdb; + + return (ISC_R_SUCCESS); +} + +static dns_dbmethods_t qpdb_zonemethods = { + .destroy = qpzonedb_destroy, +}; + +static void +destroy_qpdata(qpdata_t *data) { + isc_mem_putanddetach(&data->mctx, data, sizeof(qpdata_t)); +} + +#ifdef DNS_DB_NODETRACE +ISC_REFCOUNT_TRACE_IMPL(qpdata, destroy_qpdata); +#else +ISC_REFCOUNT_IMPL(qpdata, destroy_qpdata); +#endif + +static void +qp_attach(void *uctx ISC_ATTR_UNUSED, void *pval, + uint32_t ival ISC_ATTR_UNUSED) { + qpdata_t *data = pval; + qpdata_ref(data); +} + +static void +qp_detach(void *uctx ISC_ATTR_UNUSED, void *pval, + uint32_t ival ISC_ATTR_UNUSED) { + qpdata_t *data = pval; + qpdata_detach(&data); +} + +static size_t +qp_makekey(dns_qpkey_t key, void *uctx ISC_ATTR_UNUSED, void *pval, + uint32_t ival ISC_ATTR_UNUSED) { + qpdata_t *data = pval; + return (dns_qpkey_fromname(key, data->name)); +} + +static void +qp_triename(void *uctx, char *buf, size_t size) { + UNUSED(uctx); /* XXX */ + snprintf(buf, size, "QPDB"); +} diff --git a/lib/dns/qpzone_p.h b/lib/dns/qpzone_p.h new file mode 100644 index 0000000000..23cd4ef191 --- /dev/null +++ b/lib/dns/qpzone_p.h @@ -0,0 +1,51 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +#pragma once + +#include +#include +#include + +#include +#include +#include + +/***** +***** Module Info +*****/ + +/*! \file + * \brief + * DNS QP-Trie DB Implementation + */ + +ISC_LANG_BEGINDECLS + +isc_result_t +dns__qpzone_create(isc_mem_t *mctx, const dns_name_t *base, dns_dbtype_t type, + dns_rdataclass_t rdclass, unsigned int argc, char **argv, + void *driverarg, dns_db_t **dbp); +/*%< + * Create a new database of type "qpzone". Called via dns_db_create(); + * see documentation for that function for more details. + * + * If argv[0] is set, it points to a valid memory context to be used for + * allocation of heap memory. Generally this is used for cache databases + * only. + * + * Requires: + * + * \li argc == 0 or argv[0] is a valid memory context. + */ +ISC_LANG_ENDDECLS