#include <dns/rdataclass.h>
#include <dns/rdataset.h>
#include <dns/rdatasetiter.h>
+#include <dns/rdataslab.h>
+#include <dns/stats.h>
/***
*** Private Types
(db->attributes & DNS_DBATTR_CACHE) != 0 ? "cache" : "zone",
isc_result_totext(DNS_R_TOOMANYRECORDS), limit);
}
+
+void
+dns__db_free_glue(isc_mem_t *mctx, dns_glue_t *glue) {
+ 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);
+
+ dns_name_free(&glue->name, mctx);
+
+ isc_mem_put(mctx, glue, sizeof(*glue));
+
+ glue = next;
+ }
+}
+
+void
+dns__db_destroy_gluelist(dns_gluelist_t **gluelistp) {
+ REQUIRE(gluelistp != NULL);
+ if (*gluelistp == NULL) {
+ return;
+ }
+
+ dns_gluelist_t *gluelist = *gluelistp;
+
+ dns__db_free_glue(gluelist->mctx, gluelist->glue);
+
+ isc_mem_putanddetach(&gluelist->mctx, gluelist, sizeof(*gluelist));
+}
+
+void
+dns__db_free_gluelist_rcu(struct rcu_head *rcu_head) {
+ dns_gluelist_t *gluelist = caa_container_of(rcu_head, dns_gluelist_t,
+ rcu_head);
+ dns__db_destroy_gluelist(&gluelist);
+}
+
+void
+dns__db_cleanup_gluelists(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_gluelist_t *gluelist =
+ caa_container_of(node, dns_gluelist_t, wfs_node);
+ dns_slabheader_t *header = rcu_xchg_pointer(&gluelist->header,
+ NULL);
+ (void)rcu_cmpxchg_pointer(&header->gluelist, gluelist, NULL);
+
+ call_rcu(&gluelist->rcu_head, dns__db_free_gluelist_rcu);
+ }
+ rcu_read_unlock();
+}
+
+#define IS_REQUIRED_GLUE(r) (((r)->attributes & DNS_RDATASETATTR_REQUIRED) != 0)
+
+static void
+addglue_to_message(dns_glue_t *ge, dns_message_t *msg) {
+ for (; ge != NULL; ge = ge->next) {
+ dns_name_t *name = NULL;
+ dns_rdataset_t *rdataset_a = NULL;
+ dns_rdataset_t *sigrdataset_a = NULL;
+ dns_rdataset_t *rdataset_aaaa = NULL;
+ dns_rdataset_t *sigrdataset_aaaa = NULL;
+ bool prepend_name = false;
+
+ dns_message_gettempname(msg, &name);
+
+ dns_name_copy(&ge->name, name);
+
+ if (dns_rdataset_isassociated(&ge->rdataset_a)) {
+ dns_message_gettemprdataset(msg, &rdataset_a);
+ }
+
+ if (dns_rdataset_isassociated(&ge->sigrdataset_a)) {
+ dns_message_gettemprdataset(msg, &sigrdataset_a);
+ }
+
+ if (dns_rdataset_isassociated(&ge->rdataset_aaaa)) {
+ dns_message_gettemprdataset(msg, &rdataset_aaaa);
+ }
+
+ if (dns_rdataset_isassociated(&ge->sigrdataset_aaaa)) {
+ dns_message_gettemprdataset(msg, &sigrdataset_aaaa);
+ }
+
+ if (rdataset_a != NULL) {
+ dns_rdataset_clone(&ge->rdataset_a, rdataset_a);
+ ISC_LIST_APPEND(name->list, rdataset_a, link);
+ if (IS_REQUIRED_GLUE(rdataset_a)) {
+ prepend_name = true;
+ }
+ }
+
+ if (sigrdataset_a != NULL) {
+ dns_rdataset_clone(&ge->sigrdataset_a, sigrdataset_a);
+ ISC_LIST_APPEND(name->list, sigrdataset_a, link);
+ }
+
+ if (rdataset_aaaa != NULL) {
+ dns_rdataset_clone(&ge->rdataset_aaaa, rdataset_aaaa);
+ ISC_LIST_APPEND(name->list, rdataset_aaaa, link);
+ if (IS_REQUIRED_GLUE(rdataset_aaaa)) {
+ prepend_name = true;
+ }
+ }
+ if (sigrdataset_aaaa != NULL) {
+ dns_rdataset_clone(&ge->sigrdataset_aaaa,
+ sigrdataset_aaaa);
+ ISC_LIST_APPEND(name->list, sigrdataset_aaaa, link);
+ }
+
+ dns_message_addname(msg, name, DNS_SECTION_ADDITIONAL);
+
+ /*
+ * When looking for required glue, dns_message_rendersection()
+ * only processes the first rdataset associated with the first
+ * name added to the ADDITIONAL section. dns_message_addname()
+ * performs an append on the list of names in a given section,
+ * so if any glue record was marked as required, we need to
+ * move the name it is associated with to the beginning of the
+ * list for the ADDITIONAL section or else required glue might
+ * not be rendered.
+ */
+ if (prepend_name) {
+ ISC_LIST_UNLINK(msg->sections[DNS_SECTION_ADDITIONAL],
+ name, link);
+ ISC_LIST_PREPEND(msg->sections[DNS_SECTION_ADDITIONAL],
+ name, link);
+ }
+ }
+}
+
+static dns_gluelist_t *
+new_gluelist(dns_db_t *db, dns_slabheader_t *header,
+ const dns_dbversion_t *dbversion) {
+ dns_gluelist_t *gluelist = isc_mem_get(db->mctx, sizeof(*gluelist));
+ *gluelist = (dns_gluelist_t){
+ .version = dbversion,
+ .header = header,
+ };
+
+ isc_mem_attach(db->mctx, &gluelist->mctx);
+
+ cds_wfs_node_init(&gluelist->wfs_node);
+
+ return gluelist;
+}
+
+static dns_gluelist_t *
+create_gluelist(dns_db_t *db, dns_dbversion_t *dbversion, dns_dbnode_t *dbnode,
+ dns_rdataset_t *rdataset, dns_additionaldatafunc_t add) {
+ dns_slabheader_t *header = dns_slabheader_fromrdataset(rdataset);
+ dns_glue_additionaldata_ctx_t ctx = {
+ .db = db,
+ .version = dbversion,
+ .node = dbnode,
+ };
+ dns_gluelist_t *gluelist = new_gluelist(ctx.db, header, ctx.version);
+
+ /*
+ * Get the owner name of the NS RRset - it will be necessary for
+ * identifying required glue in glue_nsdname_cb() (by
+ * determining which NS records in the delegation are
+ * in-bailiwick).
+ */
+
+ (void)dns_rdataset_additionaldata(rdataset, dns_rootname, add, &ctx);
+
+ gluelist->glue = ctx.glue;
+
+ return gluelist;
+}
+
+isc_result_t
+dns__db_addglue(dns_db_t *db, dns_dbversion_t *dbversion,
+ dns_rdataset_t *rdataset, dns_message_t *msg,
+ dns_additionaldatafunc_t add,
+ struct cds_wfs_stack *glue_stack) {
+ dns_dbnode_t *dbnode = (dns_dbnode_t *)rdataset->slab.node;
+ dns_slabheader_t *header = dns_slabheader_fromrdataset(rdataset);
+ dns_glue_t *glue = NULL;
+ isc_result_t result = ISC_R_SUCCESS;
+
+ REQUIRE(rdataset->type == dns_rdatatype_ns);
+
+ rcu_read_lock();
+
+ dns_gluelist_t *gluelist = rcu_dereference(header->gluelist);
+ if (gluelist == NULL || gluelist->version != dbversion) {
+ /* No or old glue list was found in the table. */
+
+ dns_gluelist_t *xchg_gluelist = gluelist;
+ dns_gluelist_t *old_gluelist = (void *)-1;
+ dns_gluelist_t *new_gluelist =
+ create_gluelist(db, dbversion, dbnode, rdataset, add);
+
+ while (old_gluelist != xchg_gluelist &&
+ (xchg_gluelist == NULL ||
+ xchg_gluelist->version != dbversion))
+ {
+ old_gluelist = xchg_gluelist;
+ xchg_gluelist = rcu_cmpxchg_pointer(
+ &header->gluelist, old_gluelist, new_gluelist);
+ }
+
+ if (old_gluelist == xchg_gluelist) {
+ /* CAS was successful */
+ cds_wfs_push(glue_stack, &new_gluelist->wfs_node);
+ gluelist = new_gluelist;
+ } else {
+ dns__db_destroy_gluelist(&new_gluelist);
+ gluelist = xchg_gluelist;
+ }
+ }
+
+ glue = gluelist->glue;
+
+ if (glue != NULL) {
+ addglue_to_message(glue, msg);
+ result = ISC_R_NOTFOUND;
+ }
+
+ rcu_read_unlock();
+
+ return result;
+}
+
+dns_glue_t *
+dns__db_new_glue(isc_mem_t *mctx, const dns_name_t *name) {
+ dns_glue_t *glue = isc_mem_get(mctx, sizeof(*glue));
+ *glue = (dns_glue_t){
+ .name = DNS_NAME_INITEMPTY,
+ };
+
+ dns_name_dup(name, mctx, &glue->name);
+
+ return glue;
+}
struct dns_glue {
struct dns_glue *next;
- dns_fixedname_t fixedname;
+ dns_name_t name;
dns_rdataset_t rdataset_a;
dns_rdataset_t sigrdataset_a;
dns_rdataset_t rdataset_aaaa;
dns_rdataset_t sigrdataset_aaaa;
+};
+struct dns_gluelist {
isc_mem_t *mctx;
+
+ const dns_dbversion_t *version;
+ dns_slabheader_t *header;
+
+ struct dns_glue *glue;
+
struct rcu_head rcu_head;
+ struct cds_wfs_node wfs_node;
};
-typedef struct {
- dns_glue_t *glue_list;
+typedef struct dns_glue_additionaldata_ctx {
dns_db_t *db;
dns_dbversion_t *version;
- dns_name_t *nodename;
+ dns_dbnode_t *node;
+
+ dns_glue_t *glue;
} dns_glue_additionaldata_ctx_t;
typedef struct {
* the addition is to create a new rdataset or to merge to an existing one.
*/
+void
+dns__db_free_glue(isc_mem_t *mctx, dns_glue_t *glue);
+void
+dns__db_destroy_gluelist(dns_gluelist_t **gluelistp);
+void
+dns__db_free_gluelist_rcu(struct rcu_head *rcu_head);
+void
+dns__db_cleanup_gluelists(struct cds_wfs_stack *glue_stack);
+isc_result_t
+dns__db_addglue(dns_db_t *db, dns_dbversion_t *dbversion,
+ dns_rdataset_t *rdataset, dns_message_t *msg,
+ dns_additionaldatafunc_t add, struct cds_wfs_stack *glue_stack);
+
+dns_glue_t *
+dns__db_new_glue(isc_mem_t *mctx, const dns_name_t *name);
+
ISC_LANG_ENDDECLS
*/
unsigned char upper[32];
- isc_heap_t *heap;
- dns_glue_t *glue_list;
- struct cds_wfs_node wfs_node;
+ isc_heap_t *heap;
+
+ dns_gluelist_t *gluelist;
};
enum {
typedef struct dns_fwdtable dns_fwdtable_t;
typedef struct dns_geoip_databases dns_geoip_databases_t;
typedef struct dns_glue dns_glue_t;
+typedef struct dns_gluelist dns_gluelist_t;
typedef struct dns_iptable dns_iptable_t;
typedef uint32_t dns_iterations_t;
typedef struct dns_kasp dns_kasp_t;
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_db_rcu(struct rcu_head *rcu_head) {
qpzonedb_t *qpdb = caa_container_of(rcu_head, qpzonedb_t, rcu_head);
* node count below.
*/
if (qpdb->current_version != NULL) {
- free_gluetable(&qpdb->current_version->glue_stack);
+ dns__db_cleanup_gluelists(&qpdb->current_version->glue_stack);
}
/*
if (cleanup_version != NULL) {
isc_refcount_destroy(&cleanup_version->references);
INSIST(EMPTY(cleanup_version->changed_list));
- free_gluetable(&cleanup_version->glue_stack);
+ dns__db_cleanup_gluelists(&cleanup_version->glue_stack);
cds_wfs_destroy(&cleanup_version->glue_stack);
isc_rwlock_destroy(&cleanup_version->rwlock);
isc_mem_put(qpdb->common.mctx, cleanup_version,
RWUNLOCK(&qpdb->lock, isc_rwlocktype_write);
}
header->heap_index = 0;
-
- if (header->glue_list) {
- freeglue(header->glue_list);
- }
}
/*
return ISC_R_SUCCESS;
}
-static dns_glue_t *
-new_gluelist(isc_mem_t *mctx, dns_name_t *name) {
- dns_glue_t *glue = isc_mem_get(mctx, sizeof(*glue));
- *glue = (dns_glue_t){ 0 };
- dns_name_t *gluename = dns_fixedname_initname(&glue->fixedname);
-
- isc_mem_attach(mctx, &glue->mctx);
- dns_name_copy(name, gluename);
-
- return glue;
-}
-
static isc_result_t
glue_nsdname_cb(void *arg, const dns_name_t *name, dns_rdatatype_t qtype,
- dns_rdataset_t *unused DNS__DB_FLARG) {
+ dns_rdataset_t *rdataset ISC_ATTR_UNUSED DNS__DB_FLARG) {
dns_glue_additionaldata_ctx_t *ctx = NULL;
isc_result_t result;
dns_fixedname_t fixedname_a;
dns_name_t *name_a = NULL;
dns_rdataset_t rdataset_a, sigrdataset_a;
+ const qpznode_t *node = NULL;
qpznode_t *node_a = NULL;
dns_fixedname_t fixedname_aaaa;
dns_name_t *name_aaaa = NULL;
qpznode_t *node_aaaa = NULL;
dns_glue_t *glue = NULL;
- UNUSED(unused);
-
/*
* NS records want addresses in additional records.
*/
ctx = (dns_glue_additionaldata_ctx_t *)arg;
+ node = (qpznode_t *)ctx->node;
+
name_a = dns_fixedname_initname(&fixedname_a);
dns_rdataset_init(&rdataset_a);
dns_rdataset_init(&sigrdataset_a);
DNS_DBFIND_GLUEOK, 0, (dns_dbnode_t **)&node_a, name_a,
&rdataset_a, &sigrdataset_a DNS__DB_FLARG_PASS);
if (result == DNS_R_GLUE) {
- glue = new_gluelist(ctx->db->mctx, name_a);
+ glue = dns__db_new_glue(ctx->db->mctx, name_a);
dns_rdataset_init(&glue->rdataset_a);
dns_rdataset_init(&glue->sigrdataset_a);
&sigrdataset_aaaa DNS__DB_FLARG_PASS);
if (result == DNS_R_GLUE) {
if (glue == NULL) {
- glue = new_gluelist(ctx->db->mctx, name_aaaa);
+ glue = dns__db_new_glue(ctx->db->mctx, name_aaaa);
dns_rdataset_init(&glue->rdataset_a);
dns_rdataset_init(&glue->sigrdataset_a);
* attributes for the first rdataset associated with the first name
* added to the ADDITIONAL section.
*/
- if (glue != NULL && dns_name_issubdomain(name, ctx->nodename)) {
+ if (glue != NULL && dns_name_issubdomain(name, &node->name)) {
if (dns_rdataset_isassociated(&glue->rdataset_a)) {
glue->rdataset_a.attributes |=
DNS_RDATASETATTR_REQUIRED;
}
if (glue != NULL) {
- glue->next = ctx->glue_list;
- ctx->glue_list = glue;
+ glue->next = ctx->glue;
+ ctx->glue = glue;
}
result = ISC_R_SUCCESS;
return result;
}
-#define IS_REQUIRED_GLUE(r) (((r)->attributes & DNS_RDATASETATTR_REQUIRED) != 0)
-
-static void
-addglue_to_message(dns_glue_t *ge, dns_message_t *msg) {
- for (; ge != NULL; ge = ge->next) {
- dns_name_t *name = NULL;
- dns_rdataset_t *rdataset_a = NULL;
- dns_rdataset_t *sigrdataset_a = NULL;
- dns_rdataset_t *rdataset_aaaa = NULL;
- dns_rdataset_t *sigrdataset_aaaa = NULL;
- dns_name_t *gluename = dns_fixedname_name(&ge->fixedname);
- bool prepend_name = false;
-
- dns_message_gettempname(msg, &name);
-
- dns_name_copy(gluename, name);
-
- if (dns_rdataset_isassociated(&ge->rdataset_a)) {
- dns_message_gettemprdataset(msg, &rdataset_a);
- }
-
- if (dns_rdataset_isassociated(&ge->sigrdataset_a)) {
- dns_message_gettemprdataset(msg, &sigrdataset_a);
- }
-
- if (dns_rdataset_isassociated(&ge->rdataset_aaaa)) {
- dns_message_gettemprdataset(msg, &rdataset_aaaa);
- }
-
- if (dns_rdataset_isassociated(&ge->sigrdataset_aaaa)) {
- dns_message_gettemprdataset(msg, &sigrdataset_aaaa);
- }
-
- if (rdataset_a != NULL) {
- dns_rdataset_clone(&ge->rdataset_a, rdataset_a);
- ISC_LIST_APPEND(name->list, rdataset_a, link);
- if (IS_REQUIRED_GLUE(rdataset_a)) {
- prepend_name = true;
- }
- }
-
- if (sigrdataset_a != NULL) {
- dns_rdataset_clone(&ge->sigrdataset_a, sigrdataset_a);
- ISC_LIST_APPEND(name->list, sigrdataset_a, link);
- }
-
- if (rdataset_aaaa != NULL) {
- dns_rdataset_clone(&ge->rdataset_aaaa, rdataset_aaaa);
- ISC_LIST_APPEND(name->list, rdataset_aaaa, link);
- if (IS_REQUIRED_GLUE(rdataset_aaaa)) {
- prepend_name = true;
- }
- }
- if (sigrdataset_aaaa != NULL) {
- dns_rdataset_clone(&ge->sigrdataset_aaaa,
- sigrdataset_aaaa);
- ISC_LIST_APPEND(name->list, sigrdataset_aaaa, link);
- }
-
- dns_message_addname(msg, name, DNS_SECTION_ADDITIONAL);
-
- /*
- * When looking for required glue, dns_message_rendersection()
- * only processes the first rdataset associated with the first
- * name added to the ADDITIONAL section. dns_message_addname()
- * performs an append on the list of names in a given section,
- * so if any glue record was marked as required, we need to
- * move the name it is associated with to the beginning of the
- * list for the ADDITIONAL section or else required glue might
- * not be rendered.
- */
- if (prepend_name) {
- ISC_LIST_UNLINK(msg->sections[DNS_SECTION_ADDITIONAL],
- name, link);
- ISC_LIST_PREPEND(msg->sections[DNS_SECTION_ADDITIONAL],
- name, link);
- }
- }
-}
-
-static dns_glue_t *
-newglue(qpzonedb_t *qpdb, qpz_version_t *version, qpznode_t *node,
- dns_rdataset_t *rdataset) {
- dns_fixedname_t nodename;
- dns_glue_additionaldata_ctx_t ctx = {
- .db = (dns_db_t *)qpdb,
- .version = (dns_dbversion_t *)version,
- .nodename = dns_fixedname_initname(&nodename),
- };
-
- /*
- * Get the owner name of the NS RRset - it will be necessary for
- * identifying required glue in glue_nsdname_cb() (by
- * determining which NS records in the delegation are
- * in-bailiwick).
- */
- dns_name_copy(&node->name, ctx.nodename);
-
- (void)dns_rdataset_additionaldata(rdataset, dns_rootname,
- glue_nsdname_cb, &ctx);
-
- return ctx.glue_list;
-}
-
static isc_result_t
addglue(dns_db_t *db, dns_dbversion_t *dbversion, dns_rdataset_t *rdataset,
dns_message_t *msg) {
qpzonedb_t *qpdb = (qpzonedb_t *)db;
qpz_version_t *version = dbversion;
- qpznode_t *node = (qpznode_t *)rdataset->slab.node;
- dns_slabheader_t *header = dns_slabheader_fromrdataset(rdataset);
+ isc_result_t result;
REQUIRE(rdataset->type == dns_rdatatype_ns);
REQUIRE(qpdb == (qpzonedb_t *)rdataset->slab.db);
REQUIRE(qpdb == version->qpdb);
REQUIRE(!IS_STUB(qpdb));
- rcu_read_lock();
-
- dns_glue_t *glue = rcu_dereference(header->glue_list);
- if (glue == NULL) {
- /* No cached glue was found in the table. Get new glue. */
- glue = newglue(qpdb, version, node, rdataset);
-
- /* Cache the glue or (void *)-1 if no glue was found. */
- dns_glue_t *old_glue = rcu_cmpxchg_pointer(
- &header->glue_list, NULL, (glue) ? glue : (void *)-1);
- if (old_glue != NULL) {
- /* Somebody else was faster */
- freeglue(glue);
- glue = old_glue;
- } else if (glue != NULL) {
- cds_wfs_push(&version->glue_stack, &header->wfs_node);
- }
- }
-
- /* We have a cached result. Add it to the message and return. */
+ result = dns__db_addglue(db, dbversion, rdataset, msg, glue_nsdname_cb,
+ &version->glue_stack);
if (qpdb->gluecachestats != NULL) {
- isc_stats_increment(
- qpdb->gluecachestats,
- (glue == (void *)-1)
- ? dns_gluecachestatscounter_hits_absent
- : dns_gluecachestatscounter_hits_present);
- }
+ isc_statscounter_t counter =
+ (result == ISC_R_SUCCESS)
+ ? dns_gluecachestatscounter_hits_present
+ : dns_gluecachestatscounter_hits_absent;
- /*
- * (void *)-1 is a special value that means no glue is present in the
- * zone.
- */
- if (glue != (void *)-1) {
- addglue_to_message(glue, msg);
+ isc_stats_increment(qpdb->gluecachestats, counter);
}
- rcu_read_unlock();
-
return ISC_R_SUCCESS;
}
return ISC_R_SUCCESS;
}
-static dns_glue_t *
-new_gluelist(isc_mem_t *mctx, dns_name_t *name) {
- dns_glue_t *glue = isc_mem_get(mctx, sizeof(*glue));
- *glue = (dns_glue_t){ 0 };
- dns_name_t *gluename = dns_fixedname_initname(&glue->fixedname);
-
- isc_mem_attach(mctx, &glue->mctx);
- dns_name_copy(name, gluename);
-
- return glue;
-}
-
static isc_result_t
glue_nsdname_cb(void *arg, const dns_name_t *name, dns_rdatatype_t qtype,
dns_rdataset_t *unused DNS__DB_FLARG) {
dns_rdataset_t rdataset_aaaa, sigrdataset_aaaa;
dns_rbtnode_t *node_aaaa = NULL;
dns_glue_t *glue = NULL;
+ dns_fixedname_t f_nodename;
+ dns_name_t *nodename = dns_fixedname_initname(&f_nodename);
UNUSED(unused);
ctx = (dns_glue_additionaldata_ctx_t *)arg;
+ dns__rbtdb_nodefullname(ctx->db, ctx->node, nodename);
+
name_a = dns_fixedname_initname(&fixedname_a);
dns_rdataset_init(&rdataset_a);
dns_rdataset_init(&sigrdataset_a);
name_a, &rdataset_a,
&sigrdataset_a DNS__DB_FLARG_PASS);
if (result == DNS_R_GLUE) {
- glue = new_gluelist(ctx->db->mctx, name_a);
+ glue = dns__db_new_glue(ctx->db->mctx, name_a);
dns_rdataset_init(&glue->rdataset_a);
dns_rdataset_init(&glue->sigrdataset_a);
&sigrdataset_aaaa DNS__DB_FLARG_PASS);
if (result == DNS_R_GLUE) {
if (glue == NULL) {
- glue = new_gluelist(ctx->db->mctx, name_aaaa);
+ glue = dns__db_new_glue(ctx->db->mctx, name_aaaa);
dns_rdataset_init(&glue->rdataset_a);
dns_rdataset_init(&glue->sigrdataset_a);
* attributes for the first rdataset associated with the first name
* added to the ADDITIONAL section.
*/
- if (glue != NULL && dns_name_issubdomain(name, ctx->nodename)) {
+ isc_result_t dns_rbt_fullnamefromnode(dns_rbtnode_t * node,
+ dns_name_t * name);
+
+ if (glue != NULL && dns_name_issubdomain(name, nodename)) {
if (dns_rdataset_isassociated(&glue->rdataset_a)) {
glue->rdataset_a.attributes |=
DNS_RDATASETATTR_REQUIRED;
}
if (glue != NULL) {
- glue->next = ctx->glue_list;
- ctx->glue_list = glue;
+ glue->next = ctx->glue;
+ ctx->glue = glue;
}
result = ISC_R_SUCCESS;
return result;
}
-#define IS_REQUIRED_GLUE(r) (((r)->attributes & DNS_RDATASETATTR_REQUIRED) != 0)
-
-static void
-addglue_to_message(dns_glue_t *ge, dns_message_t *msg) {
- for (; ge != NULL; ge = ge->next) {
- dns_name_t *name = NULL;
- dns_rdataset_t *rdataset_a = NULL;
- dns_rdataset_t *sigrdataset_a = NULL;
- dns_rdataset_t *rdataset_aaaa = NULL;
- dns_rdataset_t *sigrdataset_aaaa = NULL;
- dns_name_t *gluename = dns_fixedname_name(&ge->fixedname);
- bool prepend_name = false;
-
- dns_message_gettempname(msg, &name);
-
- dns_name_copy(gluename, name);
-
- if (dns_rdataset_isassociated(&ge->rdataset_a)) {
- dns_message_gettemprdataset(msg, &rdataset_a);
- }
-
- if (dns_rdataset_isassociated(&ge->sigrdataset_a)) {
- dns_message_gettemprdataset(msg, &sigrdataset_a);
- }
-
- if (dns_rdataset_isassociated(&ge->rdataset_aaaa)) {
- dns_message_gettemprdataset(msg, &rdataset_aaaa);
- }
-
- if (dns_rdataset_isassociated(&ge->sigrdataset_aaaa)) {
- dns_message_gettemprdataset(msg, &sigrdataset_aaaa);
- }
-
- if (rdataset_a != NULL) {
- dns_rdataset_clone(&ge->rdataset_a, rdataset_a);
- ISC_LIST_APPEND(name->list, rdataset_a, link);
- if (IS_REQUIRED_GLUE(rdataset_a)) {
- prepend_name = true;
- }
- }
-
- if (sigrdataset_a != NULL) {
- dns_rdataset_clone(&ge->sigrdataset_a, sigrdataset_a);
- ISC_LIST_APPEND(name->list, sigrdataset_a, link);
- }
-
- if (rdataset_aaaa != NULL) {
- dns_rdataset_clone(&ge->rdataset_aaaa, rdataset_aaaa);
- ISC_LIST_APPEND(name->list, rdataset_aaaa, link);
- if (IS_REQUIRED_GLUE(rdataset_aaaa)) {
- prepend_name = true;
- }
- }
- if (sigrdataset_aaaa != NULL) {
- dns_rdataset_clone(&ge->sigrdataset_aaaa,
- sigrdataset_aaaa);
- ISC_LIST_APPEND(name->list, sigrdataset_aaaa, link);
- }
-
- dns_message_addname(msg, name, DNS_SECTION_ADDITIONAL);
-
- /*
- * When looking for required glue, dns_message_rendersection()
- * only processes the first rdataset associated with the first
- * name added to the ADDITIONAL section. dns_message_addname()
- * performs an append on the list of names in a given section,
- * so if any glue record was marked as required, we need to
- * move the name it is associated with to the beginning of the
- * list for the ADDITIONAL section or else required glue might
- * not be rendered.
- */
- if (prepend_name) {
- ISC_LIST_UNLINK(msg->sections[DNS_SECTION_ADDITIONAL],
- name, link);
- ISC_LIST_PREPEND(msg->sections[DNS_SECTION_ADDITIONAL],
- name, link);
- }
- }
-}
-
-static dns_glue_t *
-newglue(dns_rbtdb_t *rbtdb, dns_rbtdb_version_t *rbtversion,
- dns_rbtnode_t *node, dns_rdataset_t *rdataset) {
- dns_fixedname_t nodename;
- dns_glue_additionaldata_ctx_t ctx = {
- .db = (dns_db_t *)rbtdb,
- .version = (dns_dbversion_t *)rbtversion,
- .nodename = dns_fixedname_initname(&nodename),
- };
-
- /*
- * Get the owner name of the NS RRset - it will be necessary for
- * identifying required glue in glue_nsdname_cb() (by
- * determining which NS records in the delegation are
- * in-bailiwick).
- */
- dns__rbtdb_nodefullname((dns_db_t *)rbtdb, node, ctx.nodename);
-
- (void)dns_rdataset_additionaldata(rdataset, dns_rootname,
- glue_nsdname_cb, &ctx);
-
- return ctx.glue_list;
-}
-
static isc_result_t
-addglue(dns_db_t *db, dns_dbversion_t *version, dns_rdataset_t *rdataset,
+addglue(dns_db_t *db, dns_dbversion_t *dbversion, dns_rdataset_t *rdataset,
dns_message_t *msg) {
dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db;
- dns_rbtdb_version_t *rbtversion = version;
- dns_rbtnode_t *node = (dns_rbtnode_t *)rdataset->slab.node;
- dns_slabheader_t *header = dns_slabheader_fromrdataset(rdataset);
+ dns_rbtdb_version_t *rbtversion = dbversion;
+ isc_result_t result;
REQUIRE(rdataset->type == dns_rdatatype_ns);
REQUIRE(rbtdb == (dns_rbtdb_t *)rdataset->slab.db);
REQUIRE(rbtdb == rbtversion->rbtdb);
REQUIRE(!IS_CACHE(rbtdb) && !IS_STUB(rbtdb));
- rcu_read_lock();
-
- dns_glue_t *glue = rcu_dereference(header->glue_list);
- if (glue == NULL) {
- /* No cached glue was found in the table. Get new glue. */
- glue = newglue(rbtdb, rbtversion, node, rdataset);
-
- /* Cache the glue or (void *)-1 if no glue was found. */
- dns_glue_t *old_glue = rcu_cmpxchg_pointer(
- &header->glue_list, NULL, (glue) ? glue : (void *)-1);
- if (old_glue != NULL) {
- /* Somebody else was faster */
- dns__rbtdb_freeglue(glue);
- glue = old_glue;
- } else if (glue != NULL) {
- cds_wfs_push(&rbtversion->glue_stack,
- &header->wfs_node);
- }
- }
-
- /* We have a cached result. Add it to the message and return. */
+ result = dns__db_addglue(db, dbversion, rdataset, msg, glue_nsdname_cb,
+ &rbtversion->glue_stack);
if (rbtdb->gluecachestats != NULL) {
- isc_stats_increment(
- rbtdb->gluecachestats,
- (glue == (void *)-1)
- ? dns_gluecachestatscounter_hits_absent
- : dns_gluecachestatscounter_hits_present);
- }
+ isc_statscounter_t counter =
+ (result == ISC_R_SUCCESS)
+ ? dns_gluecachestatscounter_hits_present
+ : dns_gluecachestatscounter_hits_absent;
- /*
- * (void *)-1 is a special value that means no glue is present in the
- * zone.
- */
- if (glue != (void *)-1) {
- addglue_to_message(glue, msg);
+ isc_stats_increment(rbtdb->gluecachestats, counter);
}
- rcu_read_unlock();
-
return ISC_R_SUCCESS;
}
delete_callback(void *data, void *arg);
static void
prune_tree(void *arg);
-static void
-free_gluetable(dns_rbtdb_version_t *version);
static void
rdatasetiter_destroy(dns_rdatasetiter_t **iteratorp DNS__DB_FLARG);
* node count below.
*/
if (rbtdb->current_version != NULL) {
- free_gluetable(rbtdb->current_version);
+ dns__db_cleanup_gluelists(&rbtdb->current_version->glue_stack);
}
/*
if (cleanup_version != NULL) {
isc_refcount_destroy(&cleanup_version->references);
INSIST(EMPTY(cleanup_version->changed_list));
- free_gluetable(cleanup_version);
+ dns__db_cleanup_gluelists(&cleanup_version->glue_stack);
cds_wfs_destroy(&cleanup_version->glue_stack);
isc_rwlock_destroy(&cleanup_version->rwlock);
isc_mem_put(rbtdb->common.mctx, cleanup_version,
return ISC_R_SUCCESS;
}
-void
-dns__rbtdb_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);
-
- dns__rbtdb_freeglue(glue);
-}
-
-static void
-free_gluetable(dns_rbtdb_version_t *rbtversion) {
- struct cds_wfs_head *head = __cds_wfs_pop_all(&rbtversion->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();
-}
-
void
dns__rbtdb_deletedata(dns_db_t *db ISC_ATTR_UNUSED,
dns_dbnode_t *node ISC_ATTR_UNUSED, void *data) {
if (header->closest != NULL) {
dns_slabheader_freeproof(db->mctx, &header->closest);
}
- } else {
- if (header->glue_list) {
- dns__rbtdb_freeglue(header->glue_list);
- }
}
}
ISC_LINK_INIT(h, link);
h->heap_index = 0;
h->heap = NULL;
- h->glue_list = NULL;
h->db = db;
h->node = node;
atomic_init(&h->attributes, 0);
atomic_init(&h->last_refresh_fail_ts, 0);
- cds_wfs_node_init(&h->wfs_node);
-
STATIC_ASSERT((sizeof(h->attributes) == 2),
"The .attributes field of dns_slabheader_t needs to be "
"16-bit int type exactly.");