1b7579f77SDag-Erling Smørgrav /* 2b7579f77SDag-Erling Smørgrav * services/cache/rrset.c - Resource record set cache. 3b7579f77SDag-Erling Smørgrav * 4b7579f77SDag-Erling Smørgrav * Copyright (c) 2007, NLnet Labs. All rights reserved. 5b7579f77SDag-Erling Smørgrav * 6b7579f77SDag-Erling Smørgrav * This software is open source. 7b7579f77SDag-Erling Smørgrav * 8b7579f77SDag-Erling Smørgrav * Redistribution and use in source and binary forms, with or without 9b7579f77SDag-Erling Smørgrav * modification, are permitted provided that the following conditions 10b7579f77SDag-Erling Smørgrav * are met: 11b7579f77SDag-Erling Smørgrav * 12b7579f77SDag-Erling Smørgrav * Redistributions of source code must retain the above copyright notice, 13b7579f77SDag-Erling Smørgrav * this list of conditions and the following disclaimer. 14b7579f77SDag-Erling Smørgrav * 15b7579f77SDag-Erling Smørgrav * Redistributions in binary form must reproduce the above copyright notice, 16b7579f77SDag-Erling Smørgrav * this list of conditions and the following disclaimer in the documentation 17b7579f77SDag-Erling Smørgrav * and/or other materials provided with the distribution. 18b7579f77SDag-Erling Smørgrav * 19b7579f77SDag-Erling Smørgrav * Neither the name of the NLNET LABS nor the names of its contributors may 20b7579f77SDag-Erling Smørgrav * be used to endorse or promote products derived from this software without 21b7579f77SDag-Erling Smørgrav * specific prior written permission. 22b7579f77SDag-Erling Smørgrav * 23b7579f77SDag-Erling Smørgrav * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 24*17d15b25SDag-Erling Smørgrav * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 25*17d15b25SDag-Erling Smørgrav * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 26*17d15b25SDag-Erling Smørgrav * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 27*17d15b25SDag-Erling Smørgrav * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 28*17d15b25SDag-Erling Smørgrav * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 29*17d15b25SDag-Erling Smørgrav * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 30*17d15b25SDag-Erling Smørgrav * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 31*17d15b25SDag-Erling Smørgrav * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 32*17d15b25SDag-Erling Smørgrav * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 33*17d15b25SDag-Erling Smørgrav * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34b7579f77SDag-Erling Smørgrav */ 35b7579f77SDag-Erling Smørgrav 36b7579f77SDag-Erling Smørgrav /** 37b7579f77SDag-Erling Smørgrav * \file 38b7579f77SDag-Erling Smørgrav * 39b7579f77SDag-Erling Smørgrav * This file contains the rrset cache. 40b7579f77SDag-Erling Smørgrav */ 41b7579f77SDag-Erling Smørgrav #include "config.h" 42b7579f77SDag-Erling Smørgrav #include "services/cache/rrset.h" 43*17d15b25SDag-Erling Smørgrav #include "ldns/rrdef.h" 44b7579f77SDag-Erling Smørgrav #include "util/storage/slabhash.h" 45b7579f77SDag-Erling Smørgrav #include "util/config_file.h" 46b7579f77SDag-Erling Smørgrav #include "util/data/packed_rrset.h" 47b7579f77SDag-Erling Smørgrav #include "util/data/msgreply.h" 48b7579f77SDag-Erling Smørgrav #include "util/regional.h" 49b7579f77SDag-Erling Smørgrav #include "util/alloc.h" 50b7579f77SDag-Erling Smørgrav 51b7579f77SDag-Erling Smørgrav void 52b7579f77SDag-Erling Smørgrav rrset_markdel(void* key) 53b7579f77SDag-Erling Smørgrav { 54b7579f77SDag-Erling Smørgrav struct ub_packed_rrset_key* r = (struct ub_packed_rrset_key*)key; 55b7579f77SDag-Erling Smørgrav r->id = 0; 56b7579f77SDag-Erling Smørgrav } 57b7579f77SDag-Erling Smørgrav 58b7579f77SDag-Erling Smørgrav struct rrset_cache* rrset_cache_create(struct config_file* cfg, 59b7579f77SDag-Erling Smørgrav struct alloc_cache* alloc) 60b7579f77SDag-Erling Smørgrav { 61b7579f77SDag-Erling Smørgrav size_t slabs = (cfg?cfg->rrset_cache_slabs:HASH_DEFAULT_SLABS); 62b7579f77SDag-Erling Smørgrav size_t startarray = HASH_DEFAULT_STARTARRAY; 63b7579f77SDag-Erling Smørgrav size_t maxmem = (cfg?cfg->rrset_cache_size:HASH_DEFAULT_MAXMEM); 64b7579f77SDag-Erling Smørgrav 65b7579f77SDag-Erling Smørgrav struct rrset_cache *r = (struct rrset_cache*)slabhash_create(slabs, 66b7579f77SDag-Erling Smørgrav startarray, maxmem, ub_rrset_sizefunc, ub_rrset_compare, 67b7579f77SDag-Erling Smørgrav ub_rrset_key_delete, rrset_data_delete, alloc); 68b7579f77SDag-Erling Smørgrav slabhash_setmarkdel(&r->table, &rrset_markdel); 69b7579f77SDag-Erling Smørgrav return r; 70b7579f77SDag-Erling Smørgrav } 71b7579f77SDag-Erling Smørgrav 72b7579f77SDag-Erling Smørgrav void rrset_cache_delete(struct rrset_cache* r) 73b7579f77SDag-Erling Smørgrav { 74b7579f77SDag-Erling Smørgrav if(!r) 75b7579f77SDag-Erling Smørgrav return; 76b7579f77SDag-Erling Smørgrav slabhash_delete(&r->table); 77b7579f77SDag-Erling Smørgrav /* slabhash delete also does free(r), since table is first in struct*/ 78b7579f77SDag-Erling Smørgrav } 79b7579f77SDag-Erling Smørgrav 80b7579f77SDag-Erling Smørgrav struct rrset_cache* rrset_cache_adjust(struct rrset_cache *r, 81b7579f77SDag-Erling Smørgrav struct config_file* cfg, struct alloc_cache* alloc) 82b7579f77SDag-Erling Smørgrav { 83b7579f77SDag-Erling Smørgrav if(!r || !cfg || cfg->rrset_cache_slabs != r->table.size || 84b7579f77SDag-Erling Smørgrav cfg->rrset_cache_size != slabhash_get_size(&r->table)) 85b7579f77SDag-Erling Smørgrav { 86b7579f77SDag-Erling Smørgrav rrset_cache_delete(r); 87b7579f77SDag-Erling Smørgrav r = rrset_cache_create(cfg, alloc); 88b7579f77SDag-Erling Smørgrav } 89b7579f77SDag-Erling Smørgrav return r; 90b7579f77SDag-Erling Smørgrav } 91b7579f77SDag-Erling Smørgrav 92b7579f77SDag-Erling Smørgrav void 93b7579f77SDag-Erling Smørgrav rrset_cache_touch(struct rrset_cache* r, struct ub_packed_rrset_key* key, 94b7579f77SDag-Erling Smørgrav hashvalue_t hash, rrset_id_t id) 95b7579f77SDag-Erling Smørgrav { 96b7579f77SDag-Erling Smørgrav struct lruhash* table = slabhash_gettable(&r->table, hash); 97b7579f77SDag-Erling Smørgrav /* 98b7579f77SDag-Erling Smørgrav * This leads to locking problems, deadlocks, if the caller is 99b7579f77SDag-Erling Smørgrav * holding any other rrset lock. 100b7579f77SDag-Erling Smørgrav * Because a lookup through the hashtable does: 101b7579f77SDag-Erling Smørgrav * tablelock -> entrylock (for that entry caller holds) 102b7579f77SDag-Erling Smørgrav * And this would do 103b7579f77SDag-Erling Smørgrav * entrylock(already held) -> tablelock 104b7579f77SDag-Erling Smørgrav * And if two threads do this, it results in deadlock. 105b7579f77SDag-Erling Smørgrav * So, the caller must not hold entrylock. 106b7579f77SDag-Erling Smørgrav */ 107b7579f77SDag-Erling Smørgrav lock_quick_lock(&table->lock); 108b7579f77SDag-Erling Smørgrav /* we have locked the hash table, the item can still be deleted. 109b7579f77SDag-Erling Smørgrav * because it could already have been reclaimed, but not yet set id=0. 110b7579f77SDag-Erling Smørgrav * This is because some lruhash routines have lazy deletion. 111b7579f77SDag-Erling Smørgrav * so, we must acquire a lock on the item to verify the id != 0. 112b7579f77SDag-Erling Smørgrav * also, with hash not changed, we are using the right slab. 113b7579f77SDag-Erling Smørgrav */ 114b7579f77SDag-Erling Smørgrav lock_rw_rdlock(&key->entry.lock); 115b7579f77SDag-Erling Smørgrav if(key->id == id && key->entry.hash == hash) { 116b7579f77SDag-Erling Smørgrav lru_touch(table, &key->entry); 117b7579f77SDag-Erling Smørgrav } 118b7579f77SDag-Erling Smørgrav lock_rw_unlock(&key->entry.lock); 119b7579f77SDag-Erling Smørgrav lock_quick_unlock(&table->lock); 120b7579f77SDag-Erling Smørgrav } 121b7579f77SDag-Erling Smørgrav 122b7579f77SDag-Erling Smørgrav /** see if rrset needs to be updated in the cache */ 123b7579f77SDag-Erling Smørgrav static int 124*17d15b25SDag-Erling Smørgrav need_to_update_rrset(void* nd, void* cd, time_t timenow, int equal, int ns) 125b7579f77SDag-Erling Smørgrav { 126b7579f77SDag-Erling Smørgrav struct packed_rrset_data* newd = (struct packed_rrset_data*)nd; 127b7579f77SDag-Erling Smørgrav struct packed_rrset_data* cached = (struct packed_rrset_data*)cd; 128b7579f77SDag-Erling Smørgrav /* o store if rrset has been validated 129b7579f77SDag-Erling Smørgrav * everything better than bogus data 130b7579f77SDag-Erling Smørgrav * secure is preferred */ 131b7579f77SDag-Erling Smørgrav if( newd->security == sec_status_secure && 132b7579f77SDag-Erling Smørgrav cached->security != sec_status_secure) 133b7579f77SDag-Erling Smørgrav return 1; 134b7579f77SDag-Erling Smørgrav if( cached->security == sec_status_bogus && 135b7579f77SDag-Erling Smørgrav newd->security != sec_status_bogus && !equal) 136b7579f77SDag-Erling Smørgrav return 1; 137b7579f77SDag-Erling Smørgrav /* o if current RRset is more trustworthy - insert it */ 138b7579f77SDag-Erling Smørgrav if( newd->trust > cached->trust ) { 139b7579f77SDag-Erling Smørgrav /* if the cached rrset is bogus, and this one equal, 140b7579f77SDag-Erling Smørgrav * do not update the TTL - let it expire. */ 141b7579f77SDag-Erling Smørgrav if(equal && cached->ttl >= timenow && 142b7579f77SDag-Erling Smørgrav cached->security == sec_status_bogus) 143b7579f77SDag-Erling Smørgrav return 0; 144b7579f77SDag-Erling Smørgrav return 1; 145b7579f77SDag-Erling Smørgrav } 146b7579f77SDag-Erling Smørgrav /* o item in cache has expired */ 147b7579f77SDag-Erling Smørgrav if( cached->ttl < timenow ) 148b7579f77SDag-Erling Smørgrav return 1; 149b7579f77SDag-Erling Smørgrav /* o same trust, but different in data - insert it */ 150b7579f77SDag-Erling Smørgrav if( newd->trust == cached->trust && !equal ) { 151b7579f77SDag-Erling Smørgrav /* if this is type NS, do not 'stick' to owner that changes 152b7579f77SDag-Erling Smørgrav * the NS RRset, but use the old TTL for the new data, and 153b7579f77SDag-Erling Smørgrav * update to fetch the latest data. ttl is not expired, because 154b7579f77SDag-Erling Smørgrav * that check was before this one. */ 155b7579f77SDag-Erling Smørgrav if(ns) { 156b7579f77SDag-Erling Smørgrav size_t i; 157b7579f77SDag-Erling Smørgrav newd->ttl = cached->ttl; 158b7579f77SDag-Erling Smørgrav for(i=0; i<(newd->count+newd->rrsig_count); i++) 159b7579f77SDag-Erling Smørgrav if(newd->rr_ttl[i] > newd->ttl) 160b7579f77SDag-Erling Smørgrav newd->rr_ttl[i] = newd->ttl; 161b7579f77SDag-Erling Smørgrav } 162b7579f77SDag-Erling Smørgrav return 1; 163b7579f77SDag-Erling Smørgrav } 164b7579f77SDag-Erling Smørgrav return 0; 165b7579f77SDag-Erling Smørgrav } 166b7579f77SDag-Erling Smørgrav 167b7579f77SDag-Erling Smørgrav /** Update RRSet special key ID */ 168b7579f77SDag-Erling Smørgrav static void 169b7579f77SDag-Erling Smørgrav rrset_update_id(struct rrset_ref* ref, struct alloc_cache* alloc) 170b7579f77SDag-Erling Smørgrav { 171b7579f77SDag-Erling Smørgrav /* this may clear the cache and invalidate lock below */ 172b7579f77SDag-Erling Smørgrav uint64_t newid = alloc_get_id(alloc); 173b7579f77SDag-Erling Smørgrav /* obtain writelock */ 174b7579f77SDag-Erling Smørgrav lock_rw_wrlock(&ref->key->entry.lock); 175b7579f77SDag-Erling Smørgrav /* check if it was deleted in the meantime, if so, skip update */ 176b7579f77SDag-Erling Smørgrav if(ref->key->id == ref->id) { 177b7579f77SDag-Erling Smørgrav ref->key->id = newid; 178b7579f77SDag-Erling Smørgrav ref->id = newid; 179b7579f77SDag-Erling Smørgrav } 180b7579f77SDag-Erling Smørgrav lock_rw_unlock(&ref->key->entry.lock); 181b7579f77SDag-Erling Smørgrav } 182b7579f77SDag-Erling Smørgrav 183b7579f77SDag-Erling Smørgrav int 184b7579f77SDag-Erling Smørgrav rrset_cache_update(struct rrset_cache* r, struct rrset_ref* ref, 185*17d15b25SDag-Erling Smørgrav struct alloc_cache* alloc, time_t timenow) 186b7579f77SDag-Erling Smørgrav { 187b7579f77SDag-Erling Smørgrav struct lruhash_entry* e; 188b7579f77SDag-Erling Smørgrav struct ub_packed_rrset_key* k = ref->key; 189b7579f77SDag-Erling Smørgrav hashvalue_t h = k->entry.hash; 190b7579f77SDag-Erling Smørgrav uint16_t rrset_type = ntohs(k->rk.type); 191b7579f77SDag-Erling Smørgrav int equal = 0; 192b7579f77SDag-Erling Smørgrav log_assert(ref->id != 0 && k->id != 0); 193b7579f77SDag-Erling Smørgrav /* looks up item with a readlock - no editing! */ 194b7579f77SDag-Erling Smørgrav if((e=slabhash_lookup(&r->table, h, k, 0)) != 0) { 195b7579f77SDag-Erling Smørgrav /* return id and key as they will be used in the cache 196b7579f77SDag-Erling Smørgrav * since the lruhash_insert, if item already exists, deallocs 197b7579f77SDag-Erling Smørgrav * the passed key in favor of the already stored key. 198b7579f77SDag-Erling Smørgrav * because of the small gap (see below) this key ptr and id 199b7579f77SDag-Erling Smørgrav * may prove later to be already deleted, which is no problem 200b7579f77SDag-Erling Smørgrav * as it only makes a cache miss. 201b7579f77SDag-Erling Smørgrav */ 202b7579f77SDag-Erling Smørgrav ref->key = (struct ub_packed_rrset_key*)e->key; 203b7579f77SDag-Erling Smørgrav ref->id = ref->key->id; 204b7579f77SDag-Erling Smørgrav equal = rrsetdata_equal((struct packed_rrset_data*)k->entry. 205b7579f77SDag-Erling Smørgrav data, (struct packed_rrset_data*)e->data); 206b7579f77SDag-Erling Smørgrav if(!need_to_update_rrset(k->entry.data, e->data, timenow, 207b7579f77SDag-Erling Smørgrav equal, (rrset_type==LDNS_RR_TYPE_NS))) { 208b7579f77SDag-Erling Smørgrav /* cache is superior, return that value */ 209b7579f77SDag-Erling Smørgrav lock_rw_unlock(&e->lock); 210b7579f77SDag-Erling Smørgrav ub_packed_rrset_parsedelete(k, alloc); 211b7579f77SDag-Erling Smørgrav if(equal) return 2; 212b7579f77SDag-Erling Smørgrav return 1; 213b7579f77SDag-Erling Smørgrav } 214b7579f77SDag-Erling Smørgrav lock_rw_unlock(&e->lock); 215b7579f77SDag-Erling Smørgrav /* Go on and insert the passed item. 216b7579f77SDag-Erling Smørgrav * small gap here, where entry is not locked. 217b7579f77SDag-Erling Smørgrav * possibly entry is updated with something else. 218b7579f77SDag-Erling Smørgrav * we then overwrite that with our data. 219b7579f77SDag-Erling Smørgrav * this is just too bad, its cache anyway. */ 220b7579f77SDag-Erling Smørgrav /* use insert to update entry to manage lruhash 221b7579f77SDag-Erling Smørgrav * cache size values nicely. */ 222b7579f77SDag-Erling Smørgrav } 223b7579f77SDag-Erling Smørgrav log_assert(ref->key->id != 0); 224b7579f77SDag-Erling Smørgrav slabhash_insert(&r->table, h, &k->entry, k->entry.data, alloc); 225b7579f77SDag-Erling Smørgrav if(e) { 226b7579f77SDag-Erling Smørgrav /* For NSEC, NSEC3, DNAME, when rdata is updated, update 227b7579f77SDag-Erling Smørgrav * the ID number so that proofs in message cache are 228b7579f77SDag-Erling Smørgrav * invalidated */ 229b7579f77SDag-Erling Smørgrav if((rrset_type == LDNS_RR_TYPE_NSEC 230b7579f77SDag-Erling Smørgrav || rrset_type == LDNS_RR_TYPE_NSEC3 231b7579f77SDag-Erling Smørgrav || rrset_type == LDNS_RR_TYPE_DNAME) && !equal) { 232b7579f77SDag-Erling Smørgrav rrset_update_id(ref, alloc); 233b7579f77SDag-Erling Smørgrav } 234b7579f77SDag-Erling Smørgrav return 1; 235b7579f77SDag-Erling Smørgrav } 236b7579f77SDag-Erling Smørgrav return 0; 237b7579f77SDag-Erling Smørgrav } 238b7579f77SDag-Erling Smørgrav 239b7579f77SDag-Erling Smørgrav struct ub_packed_rrset_key* 240b7579f77SDag-Erling Smørgrav rrset_cache_lookup(struct rrset_cache* r, uint8_t* qname, size_t qnamelen, 241*17d15b25SDag-Erling Smørgrav uint16_t qtype, uint16_t qclass, uint32_t flags, time_t timenow, 242b7579f77SDag-Erling Smørgrav int wr) 243b7579f77SDag-Erling Smørgrav { 244b7579f77SDag-Erling Smørgrav struct lruhash_entry* e; 245b7579f77SDag-Erling Smørgrav struct ub_packed_rrset_key key; 246b7579f77SDag-Erling Smørgrav 247b7579f77SDag-Erling Smørgrav key.entry.key = &key; 248b7579f77SDag-Erling Smørgrav key.entry.data = NULL; 249b7579f77SDag-Erling Smørgrav key.rk.dname = qname; 250b7579f77SDag-Erling Smørgrav key.rk.dname_len = qnamelen; 251b7579f77SDag-Erling Smørgrav key.rk.type = htons(qtype); 252b7579f77SDag-Erling Smørgrav key.rk.rrset_class = htons(qclass); 253b7579f77SDag-Erling Smørgrav key.rk.flags = flags; 254b7579f77SDag-Erling Smørgrav 255b7579f77SDag-Erling Smørgrav key.entry.hash = rrset_key_hash(&key.rk); 256b7579f77SDag-Erling Smørgrav 257b7579f77SDag-Erling Smørgrav if((e = slabhash_lookup(&r->table, key.entry.hash, &key, wr))) { 258b7579f77SDag-Erling Smørgrav /* check TTL */ 259b7579f77SDag-Erling Smørgrav struct packed_rrset_data* data = 260b7579f77SDag-Erling Smørgrav (struct packed_rrset_data*)e->data; 261b7579f77SDag-Erling Smørgrav if(timenow > data->ttl) { 262b7579f77SDag-Erling Smørgrav lock_rw_unlock(&e->lock); 263b7579f77SDag-Erling Smørgrav return NULL; 264b7579f77SDag-Erling Smørgrav } 265b7579f77SDag-Erling Smørgrav /* we're done */ 266b7579f77SDag-Erling Smørgrav return (struct ub_packed_rrset_key*)e->key; 267b7579f77SDag-Erling Smørgrav } 268b7579f77SDag-Erling Smørgrav return NULL; 269b7579f77SDag-Erling Smørgrav } 270b7579f77SDag-Erling Smørgrav 271b7579f77SDag-Erling Smørgrav int 272*17d15b25SDag-Erling Smørgrav rrset_array_lock(struct rrset_ref* ref, size_t count, time_t timenow) 273b7579f77SDag-Erling Smørgrav { 274b7579f77SDag-Erling Smørgrav size_t i; 275b7579f77SDag-Erling Smørgrav for(i=0; i<count; i++) { 276b7579f77SDag-Erling Smørgrav if(i>0 && ref[i].key == ref[i-1].key) 277b7579f77SDag-Erling Smørgrav continue; /* only lock items once */ 278b7579f77SDag-Erling Smørgrav lock_rw_rdlock(&ref[i].key->entry.lock); 279b7579f77SDag-Erling Smørgrav if(ref[i].id != ref[i].key->id || timenow > 280b7579f77SDag-Erling Smørgrav ((struct packed_rrset_data*)(ref[i].key->entry.data)) 281b7579f77SDag-Erling Smørgrav ->ttl) { 282b7579f77SDag-Erling Smørgrav /* failure! rollback our readlocks */ 283b7579f77SDag-Erling Smørgrav rrset_array_unlock(ref, i+1); 284b7579f77SDag-Erling Smørgrav return 0; 285b7579f77SDag-Erling Smørgrav } 286b7579f77SDag-Erling Smørgrav } 287b7579f77SDag-Erling Smørgrav return 1; 288b7579f77SDag-Erling Smørgrav } 289b7579f77SDag-Erling Smørgrav 290b7579f77SDag-Erling Smørgrav void 291b7579f77SDag-Erling Smørgrav rrset_array_unlock(struct rrset_ref* ref, size_t count) 292b7579f77SDag-Erling Smørgrav { 293b7579f77SDag-Erling Smørgrav size_t i; 294b7579f77SDag-Erling Smørgrav for(i=0; i<count; i++) { 295b7579f77SDag-Erling Smørgrav if(i>0 && ref[i].key == ref[i-1].key) 296b7579f77SDag-Erling Smørgrav continue; /* only unlock items once */ 297b7579f77SDag-Erling Smørgrav lock_rw_unlock(&ref[i].key->entry.lock); 298b7579f77SDag-Erling Smørgrav } 299b7579f77SDag-Erling Smørgrav } 300b7579f77SDag-Erling Smørgrav 301b7579f77SDag-Erling Smørgrav void 302b7579f77SDag-Erling Smørgrav rrset_array_unlock_touch(struct rrset_cache* r, struct regional* scratch, 303b7579f77SDag-Erling Smørgrav struct rrset_ref* ref, size_t count) 304b7579f77SDag-Erling Smørgrav { 305b7579f77SDag-Erling Smørgrav hashvalue_t* h; 306b7579f77SDag-Erling Smørgrav size_t i; 307b7579f77SDag-Erling Smørgrav if(!(h = (hashvalue_t*)regional_alloc(scratch, 308b7579f77SDag-Erling Smørgrav sizeof(hashvalue_t)*count))) 309b7579f77SDag-Erling Smørgrav log_warn("rrset LRU: memory allocation failed"); 310b7579f77SDag-Erling Smørgrav else /* store hash values */ 311b7579f77SDag-Erling Smørgrav for(i=0; i<count; i++) 312b7579f77SDag-Erling Smørgrav h[i] = ref[i].key->entry.hash; 313b7579f77SDag-Erling Smørgrav /* unlock */ 314b7579f77SDag-Erling Smørgrav for(i=0; i<count; i++) { 315b7579f77SDag-Erling Smørgrav if(i>0 && ref[i].key == ref[i-1].key) 316b7579f77SDag-Erling Smørgrav continue; /* only unlock items once */ 317b7579f77SDag-Erling Smørgrav lock_rw_unlock(&ref[i].key->entry.lock); 318b7579f77SDag-Erling Smørgrav } 319b7579f77SDag-Erling Smørgrav if(h) { 320b7579f77SDag-Erling Smørgrav /* LRU touch, with no rrset locks held */ 321b7579f77SDag-Erling Smørgrav for(i=0; i<count; i++) { 322b7579f77SDag-Erling Smørgrav if(i>0 && ref[i].key == ref[i-1].key) 323b7579f77SDag-Erling Smørgrav continue; /* only touch items once */ 324b7579f77SDag-Erling Smørgrav rrset_cache_touch(r, ref[i].key, h[i], ref[i].id); 325b7579f77SDag-Erling Smørgrav } 326b7579f77SDag-Erling Smørgrav } 327b7579f77SDag-Erling Smørgrav } 328b7579f77SDag-Erling Smørgrav 329b7579f77SDag-Erling Smørgrav void 330b7579f77SDag-Erling Smørgrav rrset_update_sec_status(struct rrset_cache* r, 331*17d15b25SDag-Erling Smørgrav struct ub_packed_rrset_key* rrset, time_t now) 332b7579f77SDag-Erling Smørgrav { 333b7579f77SDag-Erling Smørgrav struct packed_rrset_data* updata = 334b7579f77SDag-Erling Smørgrav (struct packed_rrset_data*)rrset->entry.data; 335b7579f77SDag-Erling Smørgrav struct lruhash_entry* e; 336b7579f77SDag-Erling Smørgrav struct packed_rrset_data* cachedata; 337b7579f77SDag-Erling Smørgrav 338b7579f77SDag-Erling Smørgrav /* hash it again to make sure it has a hash */ 339b7579f77SDag-Erling Smørgrav rrset->entry.hash = rrset_key_hash(&rrset->rk); 340b7579f77SDag-Erling Smørgrav 341b7579f77SDag-Erling Smørgrav e = slabhash_lookup(&r->table, rrset->entry.hash, rrset, 1); 342b7579f77SDag-Erling Smørgrav if(!e) 343b7579f77SDag-Erling Smørgrav return; /* not in the cache anymore */ 344b7579f77SDag-Erling Smørgrav cachedata = (struct packed_rrset_data*)e->data; 345b7579f77SDag-Erling Smørgrav if(!rrsetdata_equal(updata, cachedata)) { 346b7579f77SDag-Erling Smørgrav lock_rw_unlock(&e->lock); 347b7579f77SDag-Erling Smørgrav return; /* rrset has changed in the meantime */ 348b7579f77SDag-Erling Smørgrav } 349b7579f77SDag-Erling Smørgrav /* update the cached rrset */ 350b7579f77SDag-Erling Smørgrav if(updata->security > cachedata->security) { 351b7579f77SDag-Erling Smørgrav size_t i; 352b7579f77SDag-Erling Smørgrav if(updata->trust > cachedata->trust) 353b7579f77SDag-Erling Smørgrav cachedata->trust = updata->trust; 354b7579f77SDag-Erling Smørgrav cachedata->security = updata->security; 355b7579f77SDag-Erling Smørgrav /* for NS records only shorter TTLs, other types: update it */ 356b7579f77SDag-Erling Smørgrav if(ntohs(rrset->rk.type) != LDNS_RR_TYPE_NS || 357b7579f77SDag-Erling Smørgrav updata->ttl+now < cachedata->ttl || 358b7579f77SDag-Erling Smørgrav cachedata->ttl < now || 359b7579f77SDag-Erling Smørgrav updata->security == sec_status_bogus) { 360b7579f77SDag-Erling Smørgrav cachedata->ttl = updata->ttl + now; 361b7579f77SDag-Erling Smørgrav for(i=0; i<cachedata->count+cachedata->rrsig_count; i++) 362b7579f77SDag-Erling Smørgrav cachedata->rr_ttl[i] = updata->rr_ttl[i]+now; 363b7579f77SDag-Erling Smørgrav } 364b7579f77SDag-Erling Smørgrav } 365b7579f77SDag-Erling Smørgrav lock_rw_unlock(&e->lock); 366b7579f77SDag-Erling Smørgrav } 367b7579f77SDag-Erling Smørgrav 368b7579f77SDag-Erling Smørgrav void 369b7579f77SDag-Erling Smørgrav rrset_check_sec_status(struct rrset_cache* r, 370*17d15b25SDag-Erling Smørgrav struct ub_packed_rrset_key* rrset, time_t now) 371b7579f77SDag-Erling Smørgrav { 372b7579f77SDag-Erling Smørgrav struct packed_rrset_data* updata = 373b7579f77SDag-Erling Smørgrav (struct packed_rrset_data*)rrset->entry.data; 374b7579f77SDag-Erling Smørgrav struct lruhash_entry* e; 375b7579f77SDag-Erling Smørgrav struct packed_rrset_data* cachedata; 376b7579f77SDag-Erling Smørgrav 377b7579f77SDag-Erling Smørgrav /* hash it again to make sure it has a hash */ 378b7579f77SDag-Erling Smørgrav rrset->entry.hash = rrset_key_hash(&rrset->rk); 379b7579f77SDag-Erling Smørgrav 380b7579f77SDag-Erling Smørgrav e = slabhash_lookup(&r->table, rrset->entry.hash, rrset, 0); 381b7579f77SDag-Erling Smørgrav if(!e) 382b7579f77SDag-Erling Smørgrav return; /* not in the cache anymore */ 383b7579f77SDag-Erling Smørgrav cachedata = (struct packed_rrset_data*)e->data; 384b7579f77SDag-Erling Smørgrav if(now > cachedata->ttl || !rrsetdata_equal(updata, cachedata)) { 385b7579f77SDag-Erling Smørgrav lock_rw_unlock(&e->lock); 386b7579f77SDag-Erling Smørgrav return; /* expired, or rrset has changed in the meantime */ 387b7579f77SDag-Erling Smørgrav } 388b7579f77SDag-Erling Smørgrav if(cachedata->security > updata->security) { 389b7579f77SDag-Erling Smørgrav updata->security = cachedata->security; 390b7579f77SDag-Erling Smørgrav if(cachedata->security == sec_status_bogus) { 391b7579f77SDag-Erling Smørgrav size_t i; 392b7579f77SDag-Erling Smørgrav updata->ttl = cachedata->ttl - now; 393b7579f77SDag-Erling Smørgrav for(i=0; i<cachedata->count+cachedata->rrsig_count; i++) 394b7579f77SDag-Erling Smørgrav if(cachedata->rr_ttl[i] < now) 395b7579f77SDag-Erling Smørgrav updata->rr_ttl[i] = 0; 396b7579f77SDag-Erling Smørgrav else updata->rr_ttl[i] = 397b7579f77SDag-Erling Smørgrav cachedata->rr_ttl[i]-now; 398b7579f77SDag-Erling Smørgrav } 399b7579f77SDag-Erling Smørgrav if(cachedata->trust > updata->trust) 400b7579f77SDag-Erling Smørgrav updata->trust = cachedata->trust; 401b7579f77SDag-Erling Smørgrav } 402b7579f77SDag-Erling Smørgrav lock_rw_unlock(&e->lock); 403b7579f77SDag-Erling Smørgrav } 404b7579f77SDag-Erling Smørgrav 405b7579f77SDag-Erling Smørgrav void rrset_cache_remove(struct rrset_cache* r, uint8_t* nm, size_t nmlen, 406b7579f77SDag-Erling Smørgrav uint16_t type, uint16_t dclass, uint32_t flags) 407b7579f77SDag-Erling Smørgrav { 408b7579f77SDag-Erling Smørgrav struct ub_packed_rrset_key key; 409b7579f77SDag-Erling Smørgrav key.entry.key = &key; 410b7579f77SDag-Erling Smørgrav key.rk.dname = nm; 411b7579f77SDag-Erling Smørgrav key.rk.dname_len = nmlen; 412b7579f77SDag-Erling Smørgrav key.rk.rrset_class = htons(dclass); 413b7579f77SDag-Erling Smørgrav key.rk.type = htons(type); 414b7579f77SDag-Erling Smørgrav key.rk.flags = flags; 415b7579f77SDag-Erling Smørgrav key.entry.hash = rrset_key_hash(&key.rk); 416b7579f77SDag-Erling Smørgrav slabhash_remove(&r->table, key.entry.hash, &key); 417b7579f77SDag-Erling Smørgrav } 418