2
0
mirror of https://gitlab.isc.org/isc-projects/bind9 synced 2025-08-29 13:38:26 +00:00

reduce steps for negative caching

whenever ncache_adderesult() was called, some preparatory code
was run first; this has now been moved into a single function
negcache() to reduce code duplication.
This commit is contained in:
Evan Hunt 2025-02-27 12:43:52 -08:00 committed by Ondřej Surý
parent 7371c4882a
commit 51a4e00d1d
No known key found for this signature in database
GPG Key ID: 2820F37E873DEA41

View File

@ -661,10 +661,9 @@ fctx_minimize_qname(fetchctx_t *fctx);
static void static void
fctx_destroy(fetchctx_t *fctx); fctx_destroy(fetchctx_t *fctx);
static isc_result_t static isc_result_t
ncache_adderesult(dns_message_t *message, dns_db_t *cache, dns_dbnode_t *node, negcache(dns_message_t *message, fetchctx_t *fctx, const dns_name_t *name,
dns_rdatatype_t covers, isc_stdtime_t now, dns_ttl_t minttl, isc_stdtime_t now, bool optout, bool secure, dns_rdataset_t *added,
dns_ttl_t maxttl, bool optout, bool secure, dns_dbnode_t **nodep, isc_result_t *eresultp);
dns_rdataset_t *ardataset, isc_result_t *eresultp);
static void static void
validated(void *arg); validated(void *arg);
static void static void
@ -5006,15 +5005,14 @@ static void
clone_results(fetchctx_t *fctx) { clone_results(fetchctx_t *fctx) {
dns_fetchresponse_t *hresp = NULL; dns_fetchresponse_t *hresp = NULL;
FCTXTRACE("clone_results"); REQUIRE(!ISC_LIST_EMPTY(fctx->resps));
/* /*
* Set up any other resps to have the same data as the first. * Set up any other resps to have the same data as the first.
*
* Caller must be holding the appropriate lock. * Caller must be holding the appropriate lock.
*/ */
fctx->cloned = true; FCTXTRACE("clone_results");
ISC_LIST_FOREACH (fctx->resps, resp, link) { ISC_LIST_FOREACH (fctx->resps, resp, link) {
/* This is the head resp; keep a pointer and move on */ /* This is the head resp; keep a pointer and move on */
@ -5030,22 +5028,21 @@ clone_results(fetchctx_t *fctx) {
dns_db_attach(hresp->db, &resp->db); dns_db_attach(hresp->db, &resp->db);
dns_db_attachnode(hresp->db, hresp->node, &resp->node); dns_db_attachnode(hresp->db, hresp->node, &resp->node);
INSIST(hresp->rdataset != NULL); INSIST(hresp->rdataset != NULL && resp->rdataset != NULL);
INSIST(resp->rdataset != NULL);
if (dns_rdataset_isassociated(hresp->rdataset)) { if (dns_rdataset_isassociated(hresp->rdataset)) {
dns_rdataset_clone(hresp->rdataset, resp->rdataset); dns_rdataset_clone(hresp->rdataset, resp->rdataset);
} }
INSIST(!(hresp->sigrdataset == NULL && INSIST(hresp->sigrdataset != NULL || resp->sigrdataset == NULL);
resp->sigrdataset != NULL)); if (resp->sigrdataset != NULL && hresp->sigrdataset != NULL &&
if (hresp->sigrdataset != NULL && dns_rdataset_isassociated(hresp->sigrdataset))
dns_rdataset_isassociated(hresp->sigrdataset) &&
resp->sigrdataset != NULL)
{ {
dns_rdataset_clone(hresp->sigrdataset, dns_rdataset_clone(hresp->sigrdataset,
resp->sigrdataset); resp->sigrdataset);
} }
} }
fctx->cloned = true;
} }
#define CACHE(r) (((r)->attributes.cache)) #define CACHE(r) (((r)->attributes.cache))
@ -5187,7 +5184,6 @@ validated(void *arg) {
isc_result_t eresult = ISC_R_SUCCESS; isc_result_t eresult = ISC_R_SUCCESS;
isc_result_t result = ISC_R_SUCCESS; isc_result_t result = ISC_R_SUCCESS;
isc_stdtime_t now; isc_stdtime_t now;
uint32_t ttl;
unsigned int options; unsigned int options;
dns_fixedname_t fwild; dns_fixedname_t fwild;
dns_name_t *wild = NULL; dns_name_t *wild = NULL;
@ -5355,57 +5351,12 @@ validated(void *arg) {
} }
if (negative) { if (negative) {
dns_rdatatype_t covers;
FCTXTRACE("nonexistence validation OK"); FCTXTRACE("nonexistence validation OK");
inc_stats(res, dns_resstatscounter_valnegsuccess); inc_stats(res, dns_resstatscounter_valnegsuccess);
/* result = negcache(message, fctx, val->name, now, val->optout,
* Cache DS NXDOMAIN separately to other types. val->secure, ardataset, &node, &eresult);
*/
if (message->rcode == dns_rcode_nxdomain &&
fctx->type != dns_rdatatype_ds)
{
covers = dns_rdatatype_any;
} else {
covers = fctx->type;
}
/*
* Don't report qname minimisation NXDOMAIN errors
* when the result is NXDOMAIN except we have already
* confirmed a higher error.
*/
if (!fctx->force_qmin_warning &&
message->rcode == dns_rcode_nxdomain &&
(fctx->qmin_warning == DNS_R_NXDOMAIN ||
fctx->qmin_warning == DNS_R_NCACHENXDOMAIN))
{
fctx->qmin_warning = ISC_R_SUCCESS;
}
result = dns_db_findnode(fctx->cache, val->name, true, &node);
if (result != ISC_R_SUCCESS) {
/* fctx->lock unlocked in noanswer_response */
goto noanswer_response;
}
/*
* If we are asking for a SOA record set the cache time
* to zero to facilitate locating the containing zone of
* a arbitrary zone.
*/
ttl = res->view->maxncachettl;
if (fctx->type == dns_rdatatype_soa &&
covers == dns_rdatatype_any && res->zero_no_soa_ttl)
{
ttl = 0;
}
result = ncache_adderesult(message, fctx->cache, node, covers,
now, fctx->res->view->minncachettl,
ttl, val->optout, val->secure,
ardataset, &eresult);
if (result != ISC_R_SUCCESS) { if (result != ISC_R_SUCCESS) {
goto noanswer_response; goto noanswer_response;
} }
@ -5818,8 +5769,7 @@ cache_name(fetchctx_t *fctx, dns_name_t *name, dns_message_t *message,
dns_rdataset_t *addedrdataset = NULL; dns_rdataset_t *addedrdataset = NULL;
dns_rdataset_t *ardataset = NULL, *asigrdataset = NULL; dns_rdataset_t *ardataset = NULL, *asigrdataset = NULL;
dns_rdataset_t *valrdataset = NULL, *valsigrdataset = NULL; dns_rdataset_t *valrdataset = NULL, *valsigrdataset = NULL;
dns_dbnode_t *node = NULL, **anodep = NULL; dns_dbnode_t *node = NULL;
dns_db_t **adbp = NULL;
dns_resolver_t *res = fctx->res; dns_resolver_t *res = fctx->res;
bool need_validation = false; bool need_validation = false;
bool secure_domain = false; bool secure_domain = false;
@ -5861,12 +5811,7 @@ cache_name(fetchctx_t *fctx, dns_name_t *name, dns_message_t *message,
if (name->attributes.answer && !need_validation) { if (name->attributes.answer && !need_validation) {
have_answer = true; have_answer = true;
resp = ISC_LIST_HEAD(fctx->resps); resp = ISC_LIST_HEAD(fctx->resps);
if (resp != NULL) { if (resp != NULL) {
adbp = &resp->db;
dns_name_copy(name, resp->foundname);
anodep = &resp->node;
/* /*
* If this is an ANY, SIG or RRSIG query, we're * If this is an ANY, SIG or RRSIG query, we're
* not going to return any rdatasets, unless we * not going to return any rdatasets, unless we
@ -6286,14 +6231,9 @@ cache_name(fetchctx_t *fctx, dns_name_t *name, dns_message_t *message,
} }
} }
resp->result = eresult; resp->result = eresult;
if (adbp != NULL && *adbp != NULL) { dns_name_copy(name, resp->foundname);
if (anodep != NULL && *anodep != NULL) { dns_db_attach(fctx->cache, &resp->db);
dns_db_detachnode(*adbp, anodep); dns_db_transfernode(fctx->cache, &node, &resp->node);
}
dns_db_detach(adbp);
}
dns_db_attach(fctx->cache, adbp);
dns_db_transfernode(fctx->cache, &node, anodep);
clone_results(fctx); clone_results(fctx);
} }
} }
@ -6338,77 +6278,104 @@ cleanup:
* Call dns_ncache_add() and then compute an appropriate eresult. * Call dns_ncache_add() and then compute an appropriate eresult.
*/ */
static isc_result_t static isc_result_t
ncache_adderesult(dns_message_t *message, dns_db_t *cache, dns_dbnode_t *node, negcache(dns_message_t *message, fetchctx_t *fctx, const dns_name_t *name,
dns_rdatatype_t covers, isc_stdtime_t now, dns_ttl_t minttl, isc_stdtime_t now, bool optout, bool secure, dns_rdataset_t *added,
dns_ttl_t maxttl, bool optout, bool secure, dns_dbnode_t **nodep, isc_result_t *eresultp) {
dns_rdataset_t *ardataset, isc_result_t *eresultp) {
isc_result_t result; isc_result_t result;
dns_rdataset_t rdataset; dns_ttl_t minttl = fctx->res->view->minncachettl;
dns_ttl_t maxttl = fctx->res->view->maxncachettl;
dns_rdatatype_t covers = fctx->type;
dns_db_t *cache = fctx->cache;
dns_dbnode_t *node = NULL;
dns_rdataset_t rdataset = DNS_RDATASET_INIT;
if (ardataset == NULL) { /* Set up a placeholder in case added was NULL */
dns_rdataset_init(&rdataset); if (added == NULL) {
ardataset = &rdataset; added = &rdataset;
}
/*
* Cache DS NXDOMAIN separately to other types.
*/
if (message->rcode == dns_rcode_nxdomain &&
fctx->type != dns_rdatatype_ds)
{
covers = dns_rdatatype_any;
}
/*
* If the request was for an SOA record, set the cache time
* to zero to facilitate locating the containing zone of
* an arbitrary zone.
*/
if (fctx->type == dns_rdatatype_soa && covers == dns_rdatatype_any &&
fctx->res->zero_no_soa_ttl)
{
maxttl = 0;
}
/*
* Don't warn about QNAME minimization NXDOMAIN errors
* if the final result is NXDOMAIN anyway.
*/
if (!fctx->force_qmin_warning && message->rcode == dns_rcode_nxdomain &&
(fctx->qmin_warning == DNS_R_NXDOMAIN ||
fctx->qmin_warning == DNS_R_NCACHENXDOMAIN))
{
fctx->qmin_warning = ISC_R_SUCCESS;
}
/*
* Cache the negative entry.
*/
result = dns_db_findnode(fctx->cache, name, true, &node);
if (result != ISC_R_SUCCESS) {
return result;
} }
result = dns_ncache_add(message, cache, node, covers, now, minttl, result = dns_ncache_add(message, cache, node, covers, now, minttl,
maxttl, optout, secure, ardataset); maxttl, optout, secure, added);
if (result == DNS_R_UNCHANGED || result == ISC_R_SUCCESS) { if (result == DNS_R_UNCHANGED || result == ISC_R_SUCCESS) {
/* /*
* If the cache now contains a negative entry and we * The cache now either contains the negative entry we
* care about whether it is DNS_R_NCACHENXDOMAIN or * were adding, or a pre-existing entry (positive or
* DNS_R_NCACHENXRRSET then extract it. * negative) that was left alone. Set the event result
* accordingly.
*/ */
if (NEGATIVE(ardataset)) { if (NXDOMAIN(added)) {
/* *eresultp = DNS_R_NCACHENXDOMAIN;
* The cache data is a negative cache entry. } else if (NEGATIVE(added)) {
*/ *eresultp = DNS_R_NCACHENXRRSET;
if (NXDOMAIN(ardataset)) { } else if (added->type == dns_rdatatype_cname) {
*eresultp = DNS_R_NCACHENXDOMAIN; *eresultp = DNS_R_CNAME;
} else { } else if (added->type == dns_rdatatype_dname) {
*eresultp = DNS_R_NCACHENXRRSET; *eresultp = DNS_R_DNAME;
}
} else { } else {
/* *eresultp = ISC_R_SUCCESS;
* The attempt to add a negative cache entry
* was rejected. Set *eresultp to reflect
* the type of the dataset being returned.
*/
switch (ardataset->type) {
case dns_rdatatype_cname:
*eresultp = DNS_R_CNAME;
break;
case dns_rdatatype_dname:
*eresultp = DNS_R_DNAME;
break;
default:
*eresultp = ISC_R_SUCCESS;
break;
}
} }
result = ISC_R_SUCCESS; result = ISC_R_SUCCESS;
} }
if (ardataset == &rdataset && dns_rdataset_isassociated(ardataset)) {
dns_rdataset_disassociate(ardataset); if (added == &rdataset && dns_rdataset_isassociated(added)) {
dns_rdataset_disassociate(added);
} }
*nodep = node;
return result; return result;
} }
static isc_result_t static isc_result_t
ncache_message(fetchctx_t *fctx, dns_message_t *message, ncache_message(fetchctx_t *fctx, dns_message_t *message,
dns_adbaddrinfo_t *addrinfo, dns_rdatatype_t covers, dns_adbaddrinfo_t *addrinfo, isc_stdtime_t now) {
isc_stdtime_t now) {
isc_result_t result, eresult = ISC_R_SUCCESS; isc_result_t result, eresult = ISC_R_SUCCESS;
dns_name_t *name = fctx->name; dns_name_t *name = fctx->name;
dns_resolver_t *res = fctx->res; dns_resolver_t *res = fctx->res;
dns_db_t **adbp = NULL; dns_dbnode_t *node = NULL;
dns_dbnode_t *node = NULL, **anodep = NULL;
dns_rdataset_t *ardataset = NULL;
bool need_validation = false, secure_domain = false; bool need_validation = false, secure_domain = false;
dns_fetchresponse_t *resp = NULL; dns_fetchresponse_t *resp = NULL;
uint32_t ttl;
unsigned int valoptions = 0; unsigned int valoptions = 0;
bool checknta = true; bool checknta = true;
dns_rdataset_t *added = NULL;
FCTXTRACE("ncache_message"); FCTXTRACE("ncache_message");
@ -6473,63 +6440,26 @@ ncache_message(fetchctx_t *fctx, dns_message_t *message,
if (!HAVE_ANSWER(fctx)) { if (!HAVE_ANSWER(fctx)) {
resp = ISC_LIST_HEAD(fctx->resps); resp = ISC_LIST_HEAD(fctx->resps);
if (resp != NULL) { if (resp != NULL) {
adbp = &resp->db; added = resp->rdataset;
dns_name_copy(name, resp->foundname);
anodep = &resp->node;
ardataset = resp->rdataset;
} }
} }
result = dns_db_findnode(fctx->cache, name, true, &node); result = negcache(message, fctx, name, now, false, false, added, &node,
if (result != ISC_R_SUCCESS) { &eresult);
goto unlock;
}
/*
* Don't report qname minimisation NXDOMAIN errors
* when the result is NXDOMAIN except we have already
* confirmed a higher error.
*/
if (!fctx->force_qmin_warning && message->rcode == dns_rcode_nxdomain &&
(fctx->qmin_warning == DNS_R_NXDOMAIN ||
fctx->qmin_warning == DNS_R_NCACHENXDOMAIN))
{
fctx->qmin_warning = ISC_R_SUCCESS;
}
/*
* If we are asking for a SOA record set the cache time
* to zero to facilitate locating the containing zone of
* a arbitrary zone.
*/
ttl = fctx->res->view->maxncachettl;
if (fctx->type == dns_rdatatype_soa && covers == dns_rdatatype_any &&
fctx->res->zero_no_soa_ttl)
{
ttl = 0;
}
result = ncache_adderesult(message, fctx->cache, node, covers, now,
fctx->res->view->minncachettl, ttl, false,
false, ardataset, &eresult);
if (result != ISC_R_SUCCESS) { if (result != ISC_R_SUCCESS) {
goto unlock; goto unlock;
} }
if (!HAVE_ANSWER(fctx)) { if (!HAVE_ANSWER(fctx)) {
FCTX_ATTR_SET(fctx, FCTX_ATTR_HAVEANSWER); FCTX_ATTR_SET(fctx, FCTX_ATTR_HAVEANSWER);
if (resp != NULL) { }
resp->result = eresult;
if (adbp != NULL && *adbp != NULL) { if (resp != NULL) {
if (anodep != NULL && *anodep != NULL) { resp->result = eresult;
dns_db_detachnode(*adbp, anodep); dns_name_copy(name, resp->foundname);
} dns_db_attach(fctx->cache, &resp->db);
dns_db_detach(adbp); dns_db_transfernode(fctx->cache, &node, &resp->node);
} clone_results(fctx);
dns_db_attach(fctx->cache, adbp);
dns_db_transfernode(fctx->cache, &node, anodep);
clone_results(fctx);
}
} }
unlock: unlock:
@ -8982,29 +8912,17 @@ rctx_authority_negative(respctx_t *rctx) {
static void static void
rctx_ncache(respctx_t *rctx) { rctx_ncache(respctx_t *rctx) {
isc_result_t result; isc_result_t result;
dns_rdatatype_t covers;
fetchctx_t *fctx = rctx->fctx; fetchctx_t *fctx = rctx->fctx;
if (!WANTNCACHE(fctx)) { if (!WANTNCACHE(fctx)) {
return; return;
} }
/*
* Cache DS NXDOMAIN separately to other types.
*/
if (rctx->query->rmessage->rcode == dns_rcode_nxdomain &&
fctx->type != dns_rdatatype_ds)
{
covers = dns_rdatatype_any;
} else {
covers = fctx->type;
}
/* /*
* Cache any negative cache entries in the message. * Cache any negative cache entries in the message.
*/ */
result = ncache_message(fctx, rctx->query->rmessage, result = ncache_message(fctx, rctx->query->rmessage,
rctx->query->addrinfo, covers, rctx->now); rctx->query->addrinfo, rctx->now);
if (result != ISC_R_SUCCESS) { if (result != ISC_R_SUCCESS) {
FCTXTRACE3("ncache_message complete", result); FCTXTRACE3("ncache_message complete", result);
} }