diff --git a/lib/dns/db.c b/lib/dns/db.c index 43edbb76a4..1567111d20 100644 --- a/lib/dns/db.c +++ b/lib/dns/db.c @@ -41,6 +41,8 @@ #include #include #include +#include +#include /*** *** Private Types @@ -1214,3 +1216,260 @@ dns__db_logtoomanyrecords(dns_db_t *db, const dns_name_t *name, (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; +} diff --git a/lib/dns/db_p.h b/lib/dns/db_p.h index 2d920a823e..19788bbe4c 100644 --- a/lib/dns/db_p.h +++ b/lib/dns/db_p.h @@ -120,21 +120,31 @@ ISC_LANG_BEGINDECLS 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; - - isc_mem_t *mctx; - struct rcu_head rcu_head; }; -typedef struct { - dns_glue_t *glue_list; +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_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 { @@ -196,4 +206,20 @@ dns__db_logtoomanyrecords(dns_db_t *db, const dns_name_t *name, * 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 diff --git a/lib/dns/include/dns/rdataslab.h b/lib/dns/include/dns/rdataslab.h index 1a46d12d0f..3061f0ece4 100644 --- a/lib/dns/include/dns/rdataslab.h +++ b/lib/dns/include/dns/rdataslab.h @@ -132,9 +132,9 @@ struct dns_slabheader { */ 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 { diff --git a/lib/dns/include/dns/types.h b/lib/dns/include/dns/types.h index c4353aef4c..6b124bf734 100644 --- a/lib/dns/include/dns/types.h +++ b/lib/dns/include/dns/types.h @@ -94,6 +94,7 @@ typedef struct dns_forwarder dns_forwarder_t; 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; diff --git a/lib/dns/qpzone.c b/lib/dns/qpzone.c index 3acb6b7ea8..e15be4504f 100644 --- a/lib/dns/qpzone.c +++ b/lib/dns/qpzone.c @@ -369,64 +369,6 @@ set_index(void *what, unsigned int idx) { 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); @@ -513,7 +455,7 @@ qpdb_destroy(dns_db_t *arg) { * node count below. */ if (qpdb->current_version != NULL) { - free_gluetable(&qpdb->current_version->glue_stack); + dns__db_cleanup_gluelists(&qpdb->current_version->glue_stack); } /* @@ -1475,7 +1417,7 @@ closeversion(dns_db_t *db, dns_dbversion_t **versionp, 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, @@ -4020,10 +3962,6 @@ deletedata(dns_db_t *db ISC_ATTR_UNUSED, dns_dbnode_t *node ISC_ATTR_UNUSED, RWUNLOCK(&qpdb->lock, isc_rwlocktype_write); } header->heap_index = 0; - - if (header->glue_list) { - freeglue(header->glue_list); - } } /* @@ -4987,26 +4925,15 @@ nodefullname(dns_db_t *db, dns_dbnode_t *node, dns_name_t *name) { 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; @@ -5014,8 +4941,6 @@ glue_nsdname_cb(void *arg, const dns_name_t *name, dns_rdatatype_t qtype, qpznode_t *node_aaaa = NULL; dns_glue_t *glue = NULL; - UNUSED(unused); - /* * NS records want addresses in additional records. */ @@ -5023,6 +4948,8 @@ glue_nsdname_cb(void *arg, const dns_name_t *name, dns_rdatatype_t qtype, 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); @@ -5035,7 +4962,7 @@ glue_nsdname_cb(void *arg, const dns_name_t *name, dns_rdatatype_t qtype, 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); @@ -5055,7 +4982,7 @@ glue_nsdname_cb(void *arg, const dns_name_t *name, dns_rdatatype_t qtype, &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); @@ -5081,7 +5008,7 @@ glue_nsdname_cb(void *arg, const dns_name_t *name, dns_rdatatype_t qtype, * 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; @@ -5093,8 +5020,8 @@ glue_nsdname_cb(void *arg, const dns_name_t *name, dns_rdatatype_t qtype, } if (glue != NULL) { - glue->next = ctx->glue_list; - ctx->glue_list = glue; + glue->next = ctx->glue; + ctx->glue = glue; } result = ISC_R_SUCCESS; @@ -5125,162 +5052,30 @@ glue_nsdname_cb(void *arg, const dns_name_t *name, dns_rdatatype_t qtype, 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; } diff --git a/lib/dns/rbt-zonedb.c b/lib/dns/rbt-zonedb.c index ba7d46d241..226603dea5 100644 --- a/lib/dns/rbt-zonedb.c +++ b/lib/dns/rbt-zonedb.c @@ -2091,18 +2091,6 @@ setgluecachestats(dns_db_t *db, isc_stats_t *stats) { 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) { @@ -2117,6 +2105,8 @@ glue_nsdname_cb(void *arg, const dns_name_t *name, dns_rdatatype_t qtype, 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); @@ -2127,6 +2117,8 @@ glue_nsdname_cb(void *arg, const dns_name_t *name, dns_rdatatype_t qtype, 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); @@ -2140,7 +2132,7 @@ glue_nsdname_cb(void *arg, const dns_name_t *name, dns_rdatatype_t qtype, 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); @@ -2160,7 +2152,7 @@ glue_nsdname_cb(void *arg, const dns_name_t *name, dns_rdatatype_t qtype, &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); @@ -2186,7 +2178,10 @@ glue_nsdname_cb(void *arg, const dns_name_t *name, dns_rdatatype_t qtype, * 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; @@ -2198,8 +2193,8 @@ glue_nsdname_cb(void *arg, const dns_name_t *name, dns_rdatatype_t qtype, } if (glue != NULL) { - glue->next = ctx->glue_list; - ctx->glue_list = glue; + glue->next = ctx->glue; + ctx->glue = glue; } result = ISC_R_SUCCESS; @@ -2230,163 +2225,30 @@ glue_nsdname_cb(void *arg, const dns_name_t *name, dns_rdatatype_t qtype, 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; } diff --git a/lib/dns/rbtdb.c b/lib/dns/rbtdb.c index fc4ac5068e..8e8db1e4df 100644 --- a/lib/dns/rbtdb.c +++ b/lib/dns/rbtdb.c @@ -166,8 +166,6 @@ static void 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); @@ -623,7 +621,7 @@ dns__rbtdb_destroy(dns_db_t *arg) { * node count below. */ if (rbtdb->current_version != NULL) { - free_gluetable(rbtdb->current_version); + dns__db_cleanup_gluelists(&rbtdb->current_version->glue_stack); } /* @@ -1947,7 +1945,7 @@ dns__rbtdb_closeversion(dns_db_t *db, dns_dbversion_t **versionp, 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, @@ -4873,64 +4871,6 @@ dbiterator_origin(dns_dbiterator_t *iterator, dns_name_t *name) { 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) { @@ -4958,10 +4898,6 @@ dns__rbtdb_deletedata(dns_db_t *db ISC_ATTR_UNUSED, if (header->closest != NULL) { dns_slabheader_freeproof(db->mctx, &header->closest); } - } else { - if (header->glue_list) { - dns__rbtdb_freeglue(header->glue_list); - } } } diff --git a/lib/dns/rdataslab.c b/lib/dns/rdataslab.c index 29fc2debba..3da416e2ef 100644 --- a/lib/dns/rdataslab.c +++ b/lib/dns/rdataslab.c @@ -1081,15 +1081,12 @@ dns_slabheader_reset(dns_slabheader_t *h, dns_db_t *db, dns_dbnode_t *node) { 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.");