From 44560e40ea3c3631d703dc557d39c68e1ca01bfd Mon Sep 17 00:00:00 2001 From: Wouter Wijngaards Date: Mon, 6 Aug 2007 09:34:58 +0000 Subject: [PATCH] key cache. git-svn-id: file:///svn/unbound/trunk@491 be551aaa-1e26-0410-a405-d3ace91eadb9 --- doc/Changelog | 3 + validator/val_kcache.c | 149 +++++++++++++++++++++++++++++++++++++++++ validator/val_kcache.h | 97 +++++++++++++++++++++++++++ validator/val_kentry.c | 87 ++++++++++++++++++++++-- validator/val_kentry.h | 25 +++++-- validator/validator.c | 8 +++ validator/validator.h | 7 +- 7 files changed, 366 insertions(+), 10 deletions(-) create mode 100644 validator/val_kcache.c create mode 100644 validator/val_kcache.h diff --git a/doc/Changelog b/doc/Changelog index 1b96f1539..85c7e2b59 100644 --- a/doc/Changelog +++ b/doc/Changelog @@ -1,3 +1,6 @@ +6 August 2007: Wouter + - key cache for validator. + 3 August 2007: Wouter - replanning. - scrubber check section of lame NS set. diff --git a/validator/val_kcache.c b/validator/val_kcache.c new file mode 100644 index 000000000..663d2b04b --- /dev/null +++ b/validator/val_kcache.c @@ -0,0 +1,149 @@ +/* + * validator/val_kcache.c - validator key shared cache with validated keys + * + * Copyright (c) 2007, NLnet Labs. All rights reserved. + * + * This software is open source. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of the NLNET LABS nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * \file + * + * This file contains functions for dealing with the validator key cache. + */ +#include "config.h" +#include "validator/val_kcache.h" +#include "validator/val_kentry.h" +#include "util/log.h" +#include "util/config_file.h" + +struct key_cache* +key_cache_create(struct config_file* cfg) +{ + struct key_cache* kcache = (struct key_cache*)calloc(1, + sizeof(*kcache)); + size_t numtables, start_size, maxmem; + if(!kcache) { + log_err("malloc failure"); + return NULL; + } + (void)cfg; /* TODO use config for keycache params */ + numtables = HASH_DEFAULT_SLABS; + start_size = HASH_DEFAULT_STARTARRAY; + maxmem = HASH_DEFAULT_MAXMEM; + kcache->slab = slabhash_create(numtables, start_size, maxmem, + &key_entry_sizefunc, &key_entry_compfunc, + &key_entry_delkeyfunc, &key_entry_deldatafunc, NULL); + if(!kcache->slab) { + log_err("malloc failure"); + free(kcache); + return NULL; + } + return kcache; +} + +void +key_cache_delete(struct key_cache* kcache) +{ + if(!kcache) + return; + slabhash_delete(kcache->slab); + free(kcache); +} + +void +key_cache_insert(struct key_cache* kcache, struct key_entry_key* kkey) +{ + struct key_entry_key* k = key_entry_copy(kkey); + if(!k) + return; + key_entry_hash(k); + slabhash_insert(kcache->slab, k->entry.hash, &k->entry, + k->entry.data, NULL); +} + +/** + * Lookup exactly in the key cache. Returns pointer to locked entry. + * Caller must unlock it after use. + * @param kcache: the key cache. + * @param name: for what name to look; uncompressed wireformat + * @param namelen: length of the name. + * @param key_class: class of the key. + * @param wr: set true to get a writelock. + * @return key entry, locked, or NULL if not found. No TTL checking is + * performed. + */ +static struct key_entry_key* +key_cache_search(struct key_cache* kcache, uint8_t* name, size_t namelen, + uint16_t key_class, int wr) +{ + struct lruhash_entry* e; + struct key_entry_key lookfor; + lookfor.entry.key = &lookfor; + lookfor.name = name; + lookfor.namelen = namelen; + lookfor.key_class = key_class; + key_entry_hash(&lookfor); + e = slabhash_lookup(kcache->slab, lookfor.entry.hash, &lookfor, wr); + if(!e) + return NULL; + return (struct key_entry_key*)e->key; +} + +struct key_entry_key* +key_cache_obtain(struct key_cache* kcache, uint8_t* name, size_t namelen, + uint16_t key_class, struct region* region) +{ + uint32_t now = time(NULL); + /* keep looking until we find a nonexpired entry */ + while(1) { + struct key_entry_key* k = key_cache_search(kcache, name, + namelen, key_class, 0); + if(k) { + /* see if TTL is OK */ + struct key_entry_data* d = (struct key_entry_data*) + k->entry.data; + if(now <= d->ttl) { + /* copy and return it */ + struct key_entry_key* retkey = + key_entry_copy_toregion(k, region); + lock_rw_unlock(&k->entry.lock); + return retkey; + } + lock_rw_unlock(&k->entry.lock); + } + /* snip off first label to continue */ + if(name[0] == 0 || namelen <= 1) + break; + namelen -= (size_t)name[0] + 1; + name += (size_t)name[0] + 1; + } + return NULL; +} diff --git a/validator/val_kcache.h b/validator/val_kcache.h new file mode 100644 index 000000000..2f1d3af6a --- /dev/null +++ b/validator/val_kcache.h @@ -0,0 +1,97 @@ +/* + * validator/val_kcache.h - validator key shared cache with validated keys + * + * Copyright (c) 2007, NLnet Labs. All rights reserved. + * + * This software is open source. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of the NLNET LABS nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * \file + * + * This file contains functions for caching validated key entries. + */ + +#ifndef VALIDATOR_VAL_KCACHE_H +#define VALIDATOR_VAL_KCACHE_H +#include "util/storage/slabhash.h" +struct key_entry_key; +struct key_entry_data; +struct config_file; +struct region; + +/** + * Key cache + */ +struct key_cache { + /** uses slabhash for storage, type key_entry_key, key_entry_data */ + struct slabhash* slab; +}; + +/** + * Create the key cache + * @param cfg: config settings for the key cache. + * @return new key cache or NULL on malloc failure. + */ +struct key_cache* key_cache_create(struct config_file* cfg); + +/** + * Delete the key cache + * @param kcache: to delete + */ +void key_cache_delete(struct key_cache* kcache); + +/** + * Insert or update a key cache entry. Note that the insert may silently + * fail if there is not enough memory. + * + * @param kcache: the key cache. + * @param kkey: key entry key, assumed malloced in a region, is copied + * to perform update or insertion. Its data pointer is also copied. + */ +void key_cache_insert(struct key_cache* kcache, struct key_entry_key* kkey); + +/** + * Lookup key entry in the cache. Looks up the closest key entry above the + * given name. + * @param kcache: the key cache. + * @param name: for what name to look; uncompressed wireformat + * @param namelen: length of the name. + * @param key_class: class of the key. + * @param region: a copy of the key_entry is allocated in this region. + * @return pointer to a newly allocated key_entry copy in the region, if + * a key entry could be found, and allocation succeeded and TTL was OK. + * Otherwise, NULL is returned. + */ +struct key_entry_key* key_cache_obtain(struct key_cache* kcache, + uint8_t* name, size_t namelen, uint16_t key_class, + struct region* region); + +#endif /* VALIDATOR_VAL_KCACHE_H */ diff --git a/validator/val_kentry.c b/validator/val_kentry.c index 6137b3a10..7096453aa 100644 --- a/validator/val_kentry.c +++ b/validator/val_kentry.c @@ -43,9 +43,11 @@ #include "util/data/packed_rrset.h" #include "util/data/dname.h" #include "util/storage/lookup3.h" +#include "util/region-allocator.h" +#include "util/net_help.h" size_t -key_entry_sizefunc_t(void* key, void* data) +key_entry_sizefunc(void* key, void* data) { struct key_entry_key* kk = (struct key_entry_key*)key; struct key_entry_data* kd = (struct key_entry_data*)data; @@ -57,7 +59,7 @@ key_entry_sizefunc_t(void* key, void* data) } int -key_entry_compfunc_t(void* k1, void* k2) +key_entry_compfunc(void* k1, void* k2) { struct key_entry_key* n1 = (struct key_entry_key*)k1; struct key_entry_key* n2 = (struct key_entry_key*)k2; @@ -70,7 +72,7 @@ key_entry_compfunc_t(void* k1, void* k2) } void -key_entry_delkeyfunc_t(void* key, void* ATTR_UNUSED(userarg), int islocked) +key_entry_delkeyfunc(void* key, void* ATTR_UNUSED(userarg), int islocked) { struct key_entry_key* kk = (struct key_entry_key*)key; if(!key) @@ -83,7 +85,7 @@ key_entry_delkeyfunc_t(void* key, void* ATTR_UNUSED(userarg), int islocked) } void -key_entry_deldatafunc_t(void* data, void* ATTR_UNUSED(userarg)) +key_entry_deldatafunc(void* data, void* ATTR_UNUSED(userarg)) { struct key_entry_data* kd = (struct key_entry_data*)data; free(kd->rrset_data); @@ -98,3 +100,80 @@ key_entry_hash(struct key_entry_key* kk) kk->entry.hash); kk->entry.hash = dname_query_hash(kk->name, kk->entry.hash); } + +struct key_entry_key* +key_entry_copy_toregion(struct key_entry_key* kkey, struct region* region) +{ + struct key_entry_key* newk; + newk = region_alloc_init(region, kkey, sizeof(*kkey)); + if(!newk) + return NULL; + newk->name = region_alloc_init(region, kkey->name, kkey->namelen); + if(!newk->name) + return NULL; + newk->entry.key = newk; + if(newk->entry.data) { + /* copy data element */ + struct key_entry_data *d = (struct key_entry_data*) + kkey->entry.data; + struct key_entry_data *newd; + newd = region_alloc_init(region, d, sizeof(*d)); + if(!newd) + return NULL; + /* copy rrset */ + if(d->rrset_data) { + newd->rrset_data = region_alloc_init(region, + d->rrset_data, + packed_rrset_sizeof(d->rrset_data)); + if(!newd->rrset_data) + return NULL; + packed_rrset_ptr_fixup(newd->rrset_data); + } + newk->entry.data = newd; + } + return newk; +} + +struct key_entry_key* +key_entry_copy(struct key_entry_key* kkey) +{ + struct key_entry_key* newk; + if(!kkey) + return NULL; + newk = memdup(kkey, sizeof(*kkey)); + if(!newk) + return NULL; + newk->name = memdup(kkey->name, kkey->namelen); + if(!newk->name) { + free(newk); + return NULL; + } + lock_rw_init(&newk->entry.lock); + newk->entry.key = newk; + if(newk->entry.data) { + /* copy data element */ + struct key_entry_data *d = (struct key_entry_data*) + kkey->entry.data; + struct key_entry_data *newd; + newd = memdup(d, sizeof(*d)); + if(!newd) { + free(newk->name); + free(newk); + return NULL; + } + /* copy rrset */ + if(d->rrset_data) { + newd->rrset_data = memdup(d->rrset_data, + packed_rrset_sizeof(d->rrset_data)); + if(!newd->rrset_data) { + free(newd); + free(newk->name); + free(newk); + return NULL; + } + packed_rrset_ptr_fixup(newd->rrset_data); + } + newk->entry.data = newd; + } + return newk; +} diff --git a/validator/val_kentry.h b/validator/val_kentry.h index e0748dda7..9c1fb9a56 100644 --- a/validator/val_kentry.h +++ b/validator/val_kentry.h @@ -42,6 +42,7 @@ #ifndef VALIDATOR_VAL_KENTRY_H #define VALIDATOR_VAL_KENTRY_H struct packed_rrset_data; +struct region; #include "util/storage/lruhash.h" /** @@ -83,20 +84,36 @@ struct key_entry_data { }; /** function for lruhash operation */ -size_t key_entry_sizefunc_t(void* key, void* data); +size_t key_entry_sizefunc(void* key, void* data); /** function for lruhash operation */ -int key_entry_compfunc_t(void* k1, void* k2); +int key_entry_compfunc(void* k1, void* k2); /** function for lruhash operation */ -void key_entry_delkeyfunc_t(void* key, void* userarg, int islocked); +void key_entry_delkeyfunc(void* key, void* userarg, int islocked); /** function for lruhash operation */ -void key_entry_deldatafunc_t(void* data, void* userarg); +void key_entry_deldatafunc(void* data, void* userarg); /** calculate hash for key entry * @param kk: key entry. The lruhash entry.hash value is filled in. */ void key_entry_hash(struct key_entry_key* kk); +/** + * Copy a key entry, to be region-allocated. + * @param kkey: the key entry key (and data pointer) to copy. + * @param region: where to allocate it + * @return newly region-allocated entry or NULL on a failure to allocate. + */ +struct key_entry_key* key_entry_copy_toregion(struct key_entry_key* kkey, + struct region* region); + +/** + * Copy a key entry, malloced. + * @param kkey: the key entry key (and data pointer) to copy. + * @return newly allocated entry or NULL on a failure to allocate memory. + */ +struct key_entry_key* key_entry_copy(struct key_entry_key* kkey); + #endif /* VALIDATOR_VAL_KENTRY_H */ diff --git a/validator/validator.c b/validator/validator.c index d03808b1b..ccaad4eea 100644 --- a/validator/validator.c +++ b/validator/validator.c @@ -42,6 +42,7 @@ #include "config.h" #include "validator/validator.h" #include "validator/val_anchor.h" +#include "validator/val_kcache.h" #include "services/cache/dns.h" #include "util/module.h" #include "util/log.h" @@ -58,6 +59,12 @@ val_apply_cfg(struct val_env* val_env, struct config_file* cfg) log_err("out of memory"); return 0; } + if(!val_env->kcache) + val_env->kcache = key_cache_create(cfg); + if(!val_env->kcache) { + log_err("out of memory"); + return 0; + } if(!anchors_apply_cfg(val_env->anchors, cfg)) { log_err("validator: error in trustanchors config"); return 0; @@ -92,6 +99,7 @@ val_deinit(struct module_env* env, int id) return; val_env = (struct val_env*)env->modinfo[id]; anchors_delete(val_env->anchors); + key_cache_delete(val_env->kcache); free(val_env); } diff --git a/validator/validator.h b/validator/validator.h index a664c6526..e0e3039c9 100644 --- a/validator/validator.h +++ b/validator/validator.h @@ -45,15 +45,18 @@ struct module_func_block; #include "util/data/msgreply.h" struct val_anchors; +struct key_cache; /** * Global state for the validator. */ struct val_env { - /** trusted key storage */ + /** trusted key storage; these are the configured keys */ struct val_anchors* anchors; - /** key cache */ + /** key cache; these are validated keys. trusted keys only + * end up here after being primed. */ + struct key_cache* kcache; }; /** -- 2.47.2