2
0
mirror of https://gitlab.isc.org/isc-projects/bind9 synced 2025-08-30 22:15:20 +00:00

Rework rbtdb.c:find_coveringnsec() to use the auxilary nsec rbt

this improves the performance of looking for NSEC and RRSIG(NSEC)
records in the cache by skipping lots of nodes in the main trees
in the cache without these records present.  This is a simplified
version of previous_closest_nsec() which uses the same underlying
mechanism to look for NSEC and RRSIG(NSEC) records in authorative
zones.

The auxilary NSEC tree was already being maintained as a side effect
of looking for the covering NSEC in large zones where there can be
lots of glue records that needed to be skipped.  Nodes are added
to the tree whenever a NSEC record is added to the primary tree.
They are removed when the corresponding node is removed from the
primary tree.

Having nodes in the NSEC tree w/o NSEC records in the primary tree
should not impact on synth-from-dnssec efficiency as that node would
have held the NSEC we would have been needed to synthesise the
response.  Removing the node when the NSEC RRset expires would only
cause rbtdb to return a NSEC which would be rejected at a higher
level.
This commit is contained in:
Mark Andrews
2021-09-29 13:55:46 +10:00
committed by Petr Špaček
parent 240b8a3afc
commit 3a5652ccb1

View File

@@ -4764,94 +4764,116 @@ find_deepest_zonecut(rbtdb_search_t *search, dns_rbtnode_t *node,
return (result);
}
/*
* Look for a potentially covering NSEC in the cache where `name`
* is known to not exist. This uses the auxiliary NSEC tree to find
* the potential NSEC owner.
*/
static isc_result_t
find_coveringnsec(rbtdb_search_t *search, dns_dbnode_t **nodep,
isc_stdtime_t now, dns_name_t *foundname,
dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset) {
dns_rbtnode_t *node;
rdatasetheader_t *header, *header_next, *header_prev;
rdatasetheader_t *found, *foundsig;
bool empty_node;
isc_result_t result;
dns_fixedname_t fname, forigin;
dns_name_t *name, *origin;
rbtdb_rdatatype_t matchtype, sigmatchtype;
nodelock_t *lock;
isc_rwlocktype_t locktype;
find_coveringnsec(rbtdb_search_t *search, const dns_name_t *name,
dns_dbnode_t **nodep, isc_stdtime_t now,
dns_name_t *foundname, dns_rdataset_t *rdataset,
dns_rdataset_t *sigrdataset) {
dns_fixedname_t fprefix, forigin, ftarget;
dns_name_t *prefix, *origin, *target;
dns_rbtnode_t *node = NULL;
dns_rbtnodechain_t chain;
isc_result_t result;
isc_rwlocktype_t locktype;
nodelock_t *lock;
rbtdb_rdatatype_t matchtype, sigmatchtype;
rdatasetheader_t *found, *foundsig;
rdatasetheader_t *header, *header_next, *header_prev;
chain = search->chain;
/*
* Look for the node in the auxilary tree.
*/
dns_rbtnodechain_init(&chain);
target = dns_fixedname_initname(&ftarget);
result = dns_rbt_findnode(search->rbtdb->nsec, name, target, &node,
&chain, DNS_RBTFIND_EMPTYDATA, NULL, NULL);
if (result != DNS_R_PARTIALMATCH) {
dns_rbtnodechain_reset(&chain);
return (ISC_R_NOTFOUND);
}
prefix = dns_fixedname_initname(&fprefix);
origin = dns_fixedname_initname(&forigin);
target = dns_fixedname_initname(&ftarget);
locktype = isc_rwlocktype_read;
matchtype = RBTDB_RDATATYPE_VALUE(dns_rdatatype_nsec, 0);
sigmatchtype = RBTDB_RDATATYPE_VALUE(dns_rdatatype_rrsig,
dns_rdatatype_nsec);
do {
node = NULL;
name = dns_fixedname_initname(&fname);
origin = dns_fixedname_initname(&forigin);
result = dns_rbtnodechain_current(&chain, name, origin, &node);
if (result != ISC_R_SUCCESS) {
return (result);
/*
* Extract predecessor from chain.
*/
result = dns_rbtnodechain_current(&chain, prefix, origin, NULL);
dns_rbtnodechain_reset(&chain);
if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN) {
return (ISC_R_NOTFOUND);
}
result = dns_name_concatenate(prefix, origin, target, NULL);
if (result != ISC_R_SUCCESS) {
return (ISC_R_NOTFOUND);
}
/*
* Lookup the predecessor in the main tree.
*/
node = NULL;
result = dns_rbt_findnode(search->rbtdb->tree, target, foundname, &node,
NULL, DNS_RBTFIND_EMPTYDATA, NULL, NULL);
if (result != ISC_R_SUCCESS) {
return (ISC_R_NOTFOUND);
}
found = NULL;
foundsig = NULL;
header_prev = NULL;
lock = &(search->rbtdb->node_locks[node->locknum].lock);
NODE_LOCK(lock, locktype);
for (header = node->data; header != NULL; header = header_next) {
header_next = header->next;
if (check_stale_header(node, header, &locktype, lock, search,
&header_prev)) {
continue;
}
locktype = isc_rwlocktype_read;
lock = &(search->rbtdb->node_locks[node->locknum].lock);
NODE_LOCK(lock, locktype);
found = NULL;
foundsig = NULL;
empty_node = true;
header_prev = NULL;
for (header = node->data; header != NULL; header = header_next)
{
header_next = header->next;
if (check_stale_header(node, header, &locktype, lock,
search, &header_prev)) {
continue;
}
if (NONEXISTENT(header) ||
RBTDB_RDATATYPE_BASE(header->type) == 0) {
header_prev = header;
continue;
}
/*
* Don't stop on provable noqname / RRSIG.
*/
if (header->noqname == NULL &&
RBTDB_RDATATYPE_BASE(header->type) !=
dns_rdatatype_rrsig)
{
empty_node = false;
}
if (header->type == matchtype) {
found = header;
} else if (header->type == sigmatchtype) {
foundsig = header;
}
if (NONEXISTENT(header) ||
RBTDB_RDATATYPE_BASE(header->type) == 0) {
header_prev = header;
continue;
}
if (found != NULL) {
result = dns_name_concatenate(name, origin, foundname,
NULL);
if (result != ISC_R_SUCCESS) {
goto unlock_node;
}
bind_rdataset(search->rbtdb, node, found, now, locktype,
rdataset);
if (header->type == matchtype) {
found = header;
if (foundsig != NULL) {
bind_rdataset(search->rbtdb, node, foundsig,
now, locktype, sigrdataset);
break;
}
} else if (header->type == sigmatchtype) {
foundsig = header;
if (found != NULL) {
break;
}
new_reference(search->rbtdb, node, locktype);
*nodep = node;
result = DNS_R_COVERINGNSEC;
} else if (!empty_node) {
result = ISC_R_NOTFOUND;
} else {
result = dns_rbtnodechain_prev(&chain, NULL, NULL);
}
unlock_node:
NODE_UNLOCK(lock, locktype);
} while (empty_node && result == ISC_R_SUCCESS);
header_prev = header;
}
if (found != NULL) {
bind_rdataset(search->rbtdb, node, found, now, locktype,
rdataset);
if (foundsig != NULL) {
bind_rdataset(search->rbtdb, node, foundsig, now,
locktype, sigrdataset);
}
new_reference(search->rbtdb, node, locktype);
*nodep = node;
result = DNS_R_COVERINGNSEC;
} else {
result = ISC_R_NOTFOUND;
}
NODE_UNLOCK(lock, locktype);
return (result);
}
@@ -4911,7 +4933,7 @@ cache_find(dns_db_t *db, const dns_name_t *name, dns_dbversion_t *version,
if (result == DNS_R_PARTIALMATCH) {
if ((search.options & DNS_DBFIND_COVERINGNSEC) != 0) {
result = find_coveringnsec(&search, nodep, now,
result = find_coveringnsec(&search, name, nodep, now,
foundname, rdataset,
sigrdataset);
if (result == DNS_R_COVERINGNSEC) {