1 /* 2 * services/cache/rrset.c - Resource record set cache. 3 * 4 * Copyright (c) 2007, NLnet Labs. All rights reserved. 5 * 6 * This software is open source. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 12 * Redistributions of source code must retain the above copyright notice, 13 * this list of conditions and the following disclaimer. 14 * 15 * Redistributions in binary form must reproduce the above copyright notice, 16 * this list of conditions and the following disclaimer in the documentation 17 * and/or other materials provided with the distribution. 18 * 19 * Neither the name of the NLNET LABS nor the names of its contributors may 20 * be used to endorse or promote products derived from this software without 21 * specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 24 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 25 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 26 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 27 * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 28 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 29 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 30 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 31 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 32 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 33 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34 */ 35 36 /** 37 * \file 38 * 39 * This file contains the rrset cache. 40 */ 41 #include "config.h" 42 #include "services/cache/rrset.h" 43 #include "sldns/rrdef.h" 44 #include "util/storage/slabhash.h" 45 #include "util/config_file.h" 46 #include "util/data/packed_rrset.h" 47 #include "util/data/msgreply.h" 48 #include "util/data/msgparse.h" 49 #include "util/data/dname.h" 50 #include "util/regional.h" 51 #include "util/alloc.h" 52 #include "util/net_help.h" 53 #include "validator/val_utils.h" 54 55 void 56 rrset_markdel(void* key) 57 { 58 struct ub_packed_rrset_key* r = (struct ub_packed_rrset_key*)key; 59 r->id = 0; 60 } 61 62 struct rrset_cache* rrset_cache_create(struct config_file* cfg, 63 struct alloc_cache* alloc) 64 { 65 size_t slabs = (cfg?cfg->rrset_cache_slabs:HASH_DEFAULT_SLABS); 66 size_t startarray = HASH_DEFAULT_STARTARRAY; 67 size_t maxmem = (cfg?cfg->rrset_cache_size:HASH_DEFAULT_MAXMEM); 68 69 struct rrset_cache *r = (struct rrset_cache*)slabhash_create(slabs, 70 startarray, maxmem, ub_rrset_sizefunc, ub_rrset_compare, 71 ub_rrset_key_delete, rrset_data_delete, alloc); 72 if(!r) 73 return NULL; 74 slabhash_setmarkdel(&r->table, &rrset_markdel); 75 return r; 76 } 77 78 void rrset_cache_delete(struct rrset_cache* r) 79 { 80 if(!r) 81 return; 82 slabhash_delete(&r->table); 83 /* slabhash delete also does free(r), since table is first in struct*/ 84 } 85 86 struct rrset_cache* rrset_cache_adjust(struct rrset_cache *r, 87 struct config_file* cfg, struct alloc_cache* alloc) 88 { 89 if(!r || !cfg || !slabhash_is_size(&r->table, cfg->rrset_cache_size, 90 cfg->rrset_cache_slabs)) 91 { 92 rrset_cache_delete(r); 93 r = rrset_cache_create(cfg, alloc); 94 } 95 return r; 96 } 97 98 void 99 rrset_cache_touch(struct rrset_cache* r, struct ub_packed_rrset_key* key, 100 hashvalue_type hash, rrset_id_type id) 101 { 102 struct lruhash* table = slabhash_gettable(&r->table, hash); 103 /* 104 * This leads to locking problems, deadlocks, if the caller is 105 * holding any other rrset lock. 106 * Because a lookup through the hashtable does: 107 * tablelock -> entrylock (for that entry caller holds) 108 * And this would do 109 * entrylock(already held) -> tablelock 110 * And if two threads do this, it results in deadlock. 111 * So, the caller must not hold entrylock. 112 */ 113 lock_quick_lock(&table->lock); 114 /* we have locked the hash table, the item can still be deleted. 115 * because it could already have been reclaimed, but not yet set id=0. 116 * This is because some lruhash routines have lazy deletion. 117 * so, we must acquire a lock on the item to verify the id != 0. 118 * also, with hash not changed, we are using the right slab. 119 */ 120 lock_rw_rdlock(&key->entry.lock); 121 if(key->id == id && key->entry.hash == hash) { 122 lru_touch(table, &key->entry); 123 } 124 lock_rw_unlock(&key->entry.lock); 125 lock_quick_unlock(&table->lock); 126 } 127 128 /** see if rrset needs to be updated in the cache */ 129 static int 130 need_to_update_rrset(void* nd, void* cd, time_t timenow, int equal, int ns, 131 int a_aaaa) 132 { 133 struct packed_rrset_data* newd = (struct packed_rrset_data*)nd; 134 struct packed_rrset_data* cached = (struct packed_rrset_data*)cd; 135 /* o if new data is expired, cached data is better */ 136 if( TTL_IS_EXPIRED(newd->ttl, timenow) && !TTL_IS_EXPIRED(cached->ttl, timenow)) 137 return 0; 138 /* o store if rrset has been validated 139 * everything better than bogus data 140 * secure is preferred */ 141 if( newd->security == sec_status_secure && 142 cached->security != sec_status_secure) 143 return 1; 144 if( cached->security == sec_status_bogus && 145 newd->security != sec_status_bogus && !equal) 146 return 1; 147 /* o if new RRset is more trustworthy - insert it */ 148 if( newd->trust > cached->trust ) { 149 /* if the cached rrset is bogus, and new is equal, 150 * do not update the TTL - let it expire. */ 151 if(equal && !TTL_IS_EXPIRED(cached->ttl, timenow) && 152 cached->security == sec_status_bogus) 153 return 0; 154 /* ghost-domain: never let an NS overwrite extend lifetime 155 * past the entry it replaces, regardless of trust. */ 156 /* Also for A/AAAA and it is glue. */ 157 if((ns || 158 (a_aaaa && cached->trust==rrset_trust_add_noAA)) 159 && !TTL_IS_EXPIRED(cached->ttl, timenow) && 160 newd->ttl > cached->ttl) { 161 size_t i; 162 if(a_aaaa) newd->trust=rrset_trust_add_noAA; 163 newd->ttl = cached->ttl; 164 for(i=0; i<(newd->count+newd->rrsig_count); i++) 165 if(newd->rr_ttl[i] > newd->ttl) 166 newd->rr_ttl[i] = newd->ttl; 167 } 168 return 1; 169 } 170 /* o item in cache has expired */ 171 if( TTL_IS_EXPIRED(cached->ttl, timenow) ) 172 return 1; 173 /* o same trust, but different in data - insert it */ 174 if( newd->trust == cached->trust && !equal ) { 175 /* if this is type NS, do not 'stick' to owner that changes 176 * the NS RRset, but use the cached TTL for the new data, and 177 * update to fetch the latest data. ttl is not expired, because 178 * that check was before this one. */ 179 if(ns) { 180 size_t i; 181 newd->ttl = cached->ttl; 182 for(i=0; i<(newd->count+newd->rrsig_count); i++) 183 if(newd->rr_ttl[i] > newd->ttl) 184 newd->rr_ttl[i] = newd->ttl; 185 } 186 return 1; 187 } 188 return 0; 189 } 190 191 /** Update RRSet special key ID */ 192 static void 193 rrset_update_id(struct rrset_ref* ref, struct alloc_cache* alloc) 194 { 195 /* this may clear the cache and invalidate lock below */ 196 uint64_t newid = alloc_get_id(alloc); 197 /* obtain writelock */ 198 lock_rw_wrlock(&ref->key->entry.lock); 199 /* check if it was deleted in the meantime, if so, skip update */ 200 if(ref->key->id == ref->id) { 201 ref->key->id = newid; 202 ref->id = newid; 203 } 204 lock_rw_unlock(&ref->key->entry.lock); 205 } 206 207 int 208 rrset_cache_update(struct rrset_cache* r, struct rrset_ref* ref, 209 struct alloc_cache* alloc, time_t timenow) 210 { 211 struct lruhash_entry* e; 212 struct ub_packed_rrset_key* k = ref->key; 213 hashvalue_type h = k->entry.hash; 214 uint16_t rrset_type = ntohs(k->rk.type); 215 int equal = 0; 216 log_assert(ref->id != 0 && k->id != 0); 217 log_assert(k->rk.dname != NULL); 218 if((k->rk.flags&PACKED_RRSET_0TTL_GRACE) !=0) { 219 log_nametypeclass(VERB_ALGO, "rrset store of PACKED_RRSET_0TTL_GRACE rrset skipped", k->rk.dname, rrset_type, ntohs(k->rk.rrset_class)); 220 ub_packed_rrset_parsedelete(k, alloc); 221 return 0; /* Do not store 0TTL items after apply of 222 the grace ttl amount. 223 This means the ref was not changed by the call. */ 224 } 225 /* looks up item with a readlock - no editing! */ 226 if((e=slabhash_lookup(&r->table, h, k, 0)) != 0) { 227 /* return id and key as they will be used in the cache 228 * since the lruhash_insert, if item already exists, deallocs 229 * the passed key in favor of the already stored key. 230 * because of the small gap (see below) this key ptr and id 231 * may prove later to be already deleted, which is no problem 232 * as it only makes a cache miss. 233 */ 234 ref->key = (struct ub_packed_rrset_key*)e->key; 235 ref->id = ref->key->id; 236 equal = rrsetdata_equal((struct packed_rrset_data*)k->entry. 237 data, (struct packed_rrset_data*)e->data); 238 if(!need_to_update_rrset(k->entry.data, e->data, timenow, 239 equal, (rrset_type==LDNS_RR_TYPE_NS), 240 (rrset_type==LDNS_RR_TYPE_A || rrset_type==LDNS_RR_TYPE_AAAA))) { 241 /* cache is superior, return that value */ 242 lock_rw_unlock(&e->lock); 243 ub_packed_rrset_parsedelete(k, alloc); 244 if(equal) return 2; 245 return 1; 246 } 247 lock_rw_unlock(&e->lock); 248 /* Go on and insert the passed item. 249 * small gap here, where entry is not locked. 250 * possibly entry is updated with something else. 251 * we then overwrite that with our data. 252 * this is just too bad, its cache anyway. */ 253 /* use insert to update entry to manage lruhash 254 * cache size values nicely. */ 255 } 256 log_assert(ref->key->id != 0); 257 slabhash_insert(&r->table, h, &k->entry, k->entry.data, alloc); 258 if(e) { 259 /* For NSEC, NSEC3, DNAME, when rdata is updated, update 260 * the ID number so that proofs in message cache are 261 * invalidated */ 262 if((rrset_type == LDNS_RR_TYPE_NSEC 263 || rrset_type == LDNS_RR_TYPE_NSEC3 264 || rrset_type == LDNS_RR_TYPE_DNAME) && !equal) { 265 rrset_update_id(ref, alloc); 266 } 267 return 1; 268 } 269 return 0; 270 } 271 272 /** See if the name is a within signer authority */ 273 static int 274 dname_subdomain_rrsig_signers(uint8_t* dname, 275 struct ub_packed_rrset_key* rrset) 276 { 277 struct packed_rrset_data* d = (struct packed_rrset_data*) 278 rrset->entry.data; 279 size_t i; 280 if(!d || !d->rrsig_count) 281 return 0; 282 for(i=0; i<d->rrsig_count; i++) { 283 uint8_t* sname = NULL; 284 size_t slen = 0; 285 rrsig_get_signer(d->rr_data[d->count+i], d->rr_len[d->count+i], 286 &sname, &slen); 287 if(!sname || !slen) 288 return 0; /* malformed */ 289 if(!dname_subdomain_c(dname, sname)) 290 return 0; /* not a subdomain */ 291 } 292 return 1; 293 } 294 295 void rrset_cache_update_wildcard(struct rrset_cache* rrset_cache, 296 struct ub_packed_rrset_key* rrset, uint8_t* ce, size_t ce_len, 297 struct alloc_cache* alloc, time_t timenow) 298 { 299 struct rrset_ref ref; 300 uint8_t wc_dname[LDNS_MAX_DOMAINLEN+3]; 301 uint8_t* new_dname; 302 size_t new_dname_len; 303 304 /* See if the RRSIG signer name allows this wildcard, 305 * the new rrset should fall within the zone of the RRSIG signer(s). */ 306 if(!dname_subdomain_rrsig_signers(ce, rrset)) { 307 verbose(VERB_ALGO, "wildcard canonical parent outside signer authority"); 308 return; 309 } 310 311 rrset = packed_rrset_copy_alloc(rrset, alloc, timenow); 312 if(!rrset) { 313 log_err("malloc failure in rrset_cache_update_wildcard"); 314 return; 315 } 316 /* ce has at least one label less then qname, we can therefore safely 317 * add the wildcard label. */ 318 wc_dname[0] = 1; 319 wc_dname[1] = (uint8_t)'*'; 320 memmove(wc_dname+2, ce, ce_len); 321 322 new_dname_len = ce_len + 2; 323 new_dname = (uint8_t*)memdup(wc_dname, new_dname_len); 324 if(!new_dname) { 325 ub_packed_rrset_parsedelete(rrset, alloc); 326 log_err("memdup failure in rrset_cache_update_wildcard"); 327 return; 328 } 329 free(rrset->rk.dname); 330 rrset->rk.dname = new_dname; 331 rrset->rk.dname_len = new_dname_len; 332 333 rrset->entry.hash = rrset_key_hash(&rrset->rk); 334 ref.key = rrset; 335 ref.id = rrset->id; 336 /* ignore ret: if it was in the cache, ref updated */ 337 (void)rrset_cache_update(rrset_cache, &ref, alloc, timenow); 338 } 339 340 /** Grace period in seconds for TTL=0 DNAME rrsets (RFC 2308: do not cache). 341 * Allows synthesis from cache within this window to reduce recursion load. */ 342 #define DNAME_TTL0_GRACE_SECONDS 1 343 344 struct ub_packed_rrset_key* 345 rrset_cache_lookup(struct rrset_cache* r, uint8_t* qname, size_t qnamelen, 346 uint16_t qtype, uint16_t qclass, uint32_t flags, time_t timenow, 347 int wr) 348 { 349 struct lruhash_entry* e; 350 struct ub_packed_rrset_key key; 351 352 key.entry.key = &key; 353 key.entry.data = NULL; 354 key.rk.dname = qname; 355 key.rk.dname_len = qnamelen; 356 key.rk.type = htons(qtype); 357 key.rk.rrset_class = htons(qclass); 358 key.rk.flags = flags; 359 360 key.entry.hash = rrset_key_hash(&key.rk); 361 362 if((e = slabhash_lookup(&r->table, key.entry.hash, &key, wr))) { 363 /* check TTL */ 364 struct packed_rrset_data* data = 365 (struct packed_rrset_data*)e->data; 366 struct ub_packed_rrset_key* k = (struct ub_packed_rrset_key*)e->key; 367 if(TTL_IS_EXPIRED(data->ttl, timenow)) { 368 /* Allow TTL=0 DNAME within grace period for synthesis */ 369 if(qtype == LDNS_RR_TYPE_DNAME && 370 (k->rk.flags & PACKED_RRSET_UPSTREAM_0TTL) && 371 (timenow - data->ttl_add) <= DNAME_TTL0_GRACE_SECONDS) { 372 /* within grace: allow for synthesis */ 373 } else { 374 lock_rw_unlock(&e->lock); 375 return NULL; 376 } 377 } 378 /* we're done */ 379 return k; 380 } 381 return NULL; 382 } 383 384 int 385 rrset_array_lock(struct rrset_ref* ref, size_t count, time_t timenow) 386 { 387 size_t i; 388 struct packed_rrset_data* d; 389 for(i=0; i<count; i++) { 390 if(i>0 && ref[i].key == ref[i-1].key) 391 continue; /* only lock items once */ 392 lock_rw_rdlock(&ref[i].key->entry.lock); 393 d = ref[i].key->entry.data; 394 if(ref[i].id != ref[i].key->id || 395 TTL_IS_EXPIRED(d->ttl, timenow)) { 396 /* failure! rollback our readlocks */ 397 rrset_array_unlock(ref, i+1); 398 return 0; 399 } 400 } 401 return 1; 402 } 403 404 void 405 rrset_array_unlock(struct rrset_ref* ref, size_t count) 406 { 407 size_t i; 408 for(i=0; i<count; i++) { 409 if(i>0 && ref[i].key == ref[i-1].key) 410 continue; /* only unlock items once */ 411 lock_rw_unlock(&ref[i].key->entry.lock); 412 } 413 } 414 415 void 416 rrset_array_unlock_touch(struct rrset_cache* r, struct regional* scratch, 417 struct rrset_ref* ref, size_t count) 418 { 419 hashvalue_type* h; 420 size_t i; 421 if(count > RR_COUNT_MAX || !(h = (hashvalue_type*)regional_alloc( 422 scratch, sizeof(hashvalue_type)*count))) { 423 log_warn("rrset LRU: memory allocation failed"); 424 h = NULL; 425 } else /* store hash values */ 426 for(i=0; i<count; i++) 427 h[i] = ref[i].key->entry.hash; 428 /* unlock */ 429 for(i=0; i<count; i++) { 430 if(i>0 && ref[i].key == ref[i-1].key) 431 continue; /* only unlock items once */ 432 lock_rw_unlock(&ref[i].key->entry.lock); 433 } 434 if(h) { 435 /* LRU touch, with no rrset locks held */ 436 for(i=0; i<count; i++) { 437 if(i>0 && ref[i].key == ref[i-1].key) 438 continue; /* only touch items once */ 439 rrset_cache_touch(r, ref[i].key, h[i], ref[i].id); 440 } 441 } 442 } 443 444 void 445 rrset_update_sec_status(struct rrset_cache* r, 446 struct ub_packed_rrset_key* rrset, time_t now) 447 { 448 struct packed_rrset_data* updata = 449 (struct packed_rrset_data*)rrset->entry.data; 450 struct lruhash_entry* e; 451 struct packed_rrset_data* cachedata; 452 453 /* hash it again to make sure it has a hash */ 454 rrset->entry.hash = rrset_key_hash(&rrset->rk); 455 456 e = slabhash_lookup(&r->table, rrset->entry.hash, rrset, 1); 457 if(!e) 458 return; /* not in the cache anymore */ 459 cachedata = (struct packed_rrset_data*)e->data; 460 if(!rrsetdata_equal(updata, cachedata)) { 461 lock_rw_unlock(&e->lock); 462 return; /* rrset has changed in the meantime */ 463 } 464 /* update the cached rrset */ 465 if(updata->security > cachedata->security) { 466 size_t i; 467 if(updata->trust > cachedata->trust) 468 cachedata->trust = updata->trust; 469 cachedata->security = updata->security; 470 /* for NS records only shorter TTLs, other types: update it */ 471 if(ntohs(rrset->rk.type) != LDNS_RR_TYPE_NS || 472 updata->ttl+now < cachedata->ttl || 473 cachedata->ttl < now || 474 updata->security == sec_status_bogus) { 475 cachedata->ttl = updata->ttl + now; 476 for(i=0; i<cachedata->count+cachedata->rrsig_count; i++) 477 cachedata->rr_ttl[i] = updata->rr_ttl[i]+now; 478 cachedata->ttl_add = now; 479 } 480 } 481 lock_rw_unlock(&e->lock); 482 } 483 484 void 485 rrset_check_sec_status(struct rrset_cache* r, 486 struct ub_packed_rrset_key* rrset, time_t now) 487 { 488 struct packed_rrset_data* updata = 489 (struct packed_rrset_data*)rrset->entry.data; 490 struct lruhash_entry* e; 491 struct packed_rrset_data* cachedata; 492 493 /* hash it again to make sure it has a hash */ 494 rrset->entry.hash = rrset_key_hash(&rrset->rk); 495 496 e = slabhash_lookup(&r->table, rrset->entry.hash, rrset, 0); 497 if(!e) 498 return; /* not in the cache anymore */ 499 cachedata = (struct packed_rrset_data*)e->data; 500 if(now > cachedata->ttl || !rrsetdata_equal(updata, cachedata)) { 501 lock_rw_unlock(&e->lock); 502 return; /* expired, or rrset has changed in the meantime */ 503 } 504 if(cachedata->security > updata->security) { 505 updata->security = cachedata->security; 506 if(cachedata->security == sec_status_bogus) { 507 size_t i; 508 updata->ttl = cachedata->ttl - now; 509 for(i=0; i<cachedata->count+cachedata->rrsig_count; i++) 510 if(cachedata->rr_ttl[i] < now) 511 updata->rr_ttl[i] = 0; 512 else updata->rr_ttl[i] = 513 cachedata->rr_ttl[i]-now; 514 } 515 if(cachedata->trust > updata->trust) 516 updata->trust = cachedata->trust; 517 } 518 lock_rw_unlock(&e->lock); 519 } 520 521 void 522 rrset_cache_remove_above(struct rrset_cache* r, uint8_t** qname, size_t* 523 qnamelen, uint16_t searchtype, uint16_t qclass, time_t now, uint8_t* 524 qnametop, size_t qnametoplen) 525 { 526 struct ub_packed_rrset_key *rrset; 527 uint8_t lablen; 528 529 while(*qnamelen > 0) { 530 /* look one label higher */ 531 lablen = **qname; 532 *qname += lablen + 1; 533 *qnamelen -= lablen + 1; 534 if(*qnamelen <= 0) 535 return; 536 537 /* stop at qnametop */ 538 if(qnametop && *qnamelen == qnametoplen && 539 query_dname_compare(*qname, qnametop)==0) 540 return; 541 542 if(verbosity >= VERB_ALGO) { 543 /* looks up with a time of 0, to see expired entries */ 544 if((rrset = rrset_cache_lookup(r, *qname, 545 *qnamelen, searchtype, qclass, 0, 0, 0))) { 546 struct packed_rrset_data* data = 547 (struct packed_rrset_data*)rrset->entry.data; 548 int expired = (now > data->ttl); 549 lock_rw_unlock(&rrset->entry.lock); 550 if(expired) 551 log_nametypeclass(verbosity, "this " 552 "(grand)parent rrset will be " 553 "removed (expired)", 554 *qname, searchtype, qclass); 555 else log_nametypeclass(verbosity, "this " 556 "(grand)parent rrset will be " 557 "removed", 558 *qname, searchtype, qclass); 559 } 560 } 561 rrset_cache_remove(r, *qname, *qnamelen, searchtype, qclass, 0); 562 } 563 } 564 565 int 566 rrset_cache_expired_above(struct rrset_cache* r, uint8_t** qname, size_t* 567 qnamelen, uint16_t searchtype, uint16_t qclass, time_t now, uint8_t* 568 qnametop, size_t qnametoplen) 569 { 570 struct ub_packed_rrset_key *rrset; 571 uint8_t lablen; 572 573 while(*qnamelen > 0) { 574 /* look one label higher */ 575 lablen = **qname; 576 *qname += lablen + 1; 577 *qnamelen -= lablen + 1; 578 if(*qnamelen <= 0) 579 break; 580 581 /* looks up with a time of 0, to see expired entries */ 582 if((rrset = rrset_cache_lookup(r, *qname, 583 *qnamelen, searchtype, qclass, 0, 0, 0))) { 584 struct packed_rrset_data* data = 585 (struct packed_rrset_data*)rrset->entry.data; 586 if(TTL_IS_EXPIRED(data->ttl, now)) { 587 /* it is expired, this is not wanted */ 588 lock_rw_unlock(&rrset->entry.lock); 589 log_nametypeclass(VERB_ALGO, "this rrset is expired", *qname, searchtype, qclass); 590 return 1; 591 } 592 /* it is not expired, continue looking */ 593 lock_rw_unlock(&rrset->entry.lock); 594 } 595 596 /* do not look above the qnametop. */ 597 if(qnametop && *qnamelen == qnametoplen && 598 query_dname_compare(*qname, qnametop)==0) 599 break; 600 } 601 return 0; 602 } 603 604 void rrset_cache_remove(struct rrset_cache* r, uint8_t* nm, size_t nmlen, 605 uint16_t type, uint16_t dclass, uint32_t flags) 606 { 607 struct ub_packed_rrset_key key; 608 key.entry.key = &key; 609 key.rk.dname = nm; 610 key.rk.dname_len = nmlen; 611 key.rk.rrset_class = htons(dclass); 612 key.rk.type = htons(type); 613 key.rk.flags = flags; 614 key.entry.hash = rrset_key_hash(&key.rk); 615 slabhash_remove(&r->table, key.entry.hash, &key); 616 } 617