From bcec1a7593463c5ca21d4d4da728c6536261ff67 Mon Sep 17 00:00:00 2001 From: Wouter Wijngaards Date: Mon, 18 Aug 2008 15:00:17 +0000 Subject: [PATCH] negative cache design. git-svn-id: file:///svn/unbound/trunk@1197 be551aaa-1e26-0410-a405-d3ace91eadb9 --- util/fptr_wlist.c | 3 +- validator/val_neg.c | 134 ++++++++++++++++++++++++++++++++++++++++++-- validator/val_neg.h | 60 +++++++++++++++----- 3 files changed, 177 insertions(+), 20 deletions(-) diff --git a/util/fptr_wlist.c b/util/fptr_wlist.c index f8e60daff..412236a6e 100644 --- a/util/fptr_wlist.c +++ b/util/fptr_wlist.c @@ -166,7 +166,8 @@ fptr_whitelist_rbtree_cmp(int (*fptr) (const void *, const void *)) else if(fptr == &anchor_cmp) return 1; else if(fptr == &canonical_tree_compare) return 1; else if(fptr == &context_query_cmp) return 1; - else if(fptr == &val_neg_compare) return 1; + else if(fptr == &val_neg_data_compare) return 1; + else if(fptr == &val_neg_zone_compare) return 1; return 0; } diff --git a/validator/val_neg.c b/validator/val_neg.c index 95ac25b70..b7e263cad 100644 --- a/validator/val_neg.c +++ b/validator/val_neg.c @@ -43,14 +43,23 @@ */ #include "config.h" #include "validator/val_neg.h" -#include "util/log.h" #include "util/data/dname.h" +#include "util/log.h" +#include "util/net_help.h" -int val_neg_compare(const void* a, const void* b) +int val_neg_data_compare(const void* a, const void* b) { struct val_neg_data* x = (struct val_neg_data*)a; struct val_neg_data* y = (struct val_neg_data*)b; int m; + return dname_canon_lab_cmp(x->name, x->labs, y->name, y->labs, &m); +} + +int val_neg_zone_compare(const void* a, const void* b) +{ + struct val_neg_zone* x = (struct val_neg_zone*)a; + struct val_neg_zone* y = (struct val_neg_zone*)b; + int m; if(x->dclass != y->dclass) { if(x->dclass < y->dclass) return -1; @@ -67,8 +76,8 @@ struct val_neg_cache* val_neg_create() log_err("Could not create neg cache: out of memory"); return NULL; } - neg->max = 1024*1024; /* 1 M is about 5000(64bit)-10000(32) data */ - rbtree_init(&neg->tree, &val_neg_compare); + neg->max = 1024*1024; /* 1 M is thousands of entries */ + rbtree_init(&neg->tree, &val_neg_zone_compare); lock_basic_init(&neg->lock); lock_protect(&neg->lock, neg, sizeof(*neg)); return neg; @@ -94,7 +103,7 @@ void neg_cache_delete(struct val_neg_cache* neg) struct val_neg_data* p, *np; if(!neg) return; lock_basic_destroy(&neg->lock); - /* delete all the elements */ + /* delete all the zonedata elements */ p = neg->first; while(p) { np = p->next; @@ -102,17 +111,130 @@ void neg_cache_delete(struct val_neg_cache* neg) free(p); p = np; } + /* delete all the zones in the tree */ + /* TODO */ free(neg); } +/** + * Create more space in negative cache + * The oldest elements are deleted until enough space is present. + * Empty zones are deleted. + * @param neg: negative cache. + * @param need: how many bytes are needed. + */ +static void neg_make_space(struct val_neg_cache* neg, size_t need) +{ + /* delete elements until enough space or its empty */ + while(neg->last && (neg->max - neg->use) < need) { + /* Delete data, zone */ + /* update parent ptrs of items beneath it */ + } +} + +/** + * Find the given zone, from the SOA owner name and class + * @param neg: negative cache + * @param soa: what to look for. + * @return zone or NULL if not found. + */ +static struct val_neg_zone* neg_find_zone(struct val_neg_cache* neg, + struct ub_packed_rrset_key* soa) +{ + struct val_neg_zone lookfor; + struct val_neg_zone* result; + lookfor.node.key = &lookfor; + lookfor.name = soa->rk.dname; + lookfor.len = soa->rk.dname_len; + lookfor.labs = dname_count_labels(lookfor.name); + lookfor.dclass = ntohs(soa->rk.rrset_class); + + result = (struct val_neg_zone*) + rbtree_search(&neg->tree, lookfor.node.key); + return result; +} + +/** + * Create a new zone. + * @param neg: negative cache + * @param soa: what to look for. + * @return zone or NULL if out of memory. + * Other data may be deleted to make room for the new zone. + */ +static struct val_neg_zone* neg_create_zone(struct val_neg_cache* neg, + struct ub_packed_rrset_key* soa) +{ + struct val_neg_zone* zone; + size_t need; + + /* make space */ + need = sizeof(struct val_neg_zone) + soa->rk.dname_len; + neg_make_space(neg, need); + + /* create new item */ + zone = (struct val_neg_zone*)calloc(1, sizeof(*zone)); + if(!zone) { + return NULL; + } + zone->node.key = zone; + zone->name = memdup(soa->rk.dname, soa->rk.dname_len); + if(!zone->name) { + return NULL; + } + zone->len = soa->rk.dname_len; + zone->labs = dname_count_labels(zone->name); + zone->dclass = ntohs(soa->rk.rrset_class); + + zone->soa_hash = soa->entry.hash; + rbtree_init(&zone->tree, &val_neg_data_compare); + + /* insert in tree */ + (void)rbtree_insert(&neg->tree, &zone->node); + + /* find zone->parent */ + + + /* set this zone as parent for lower zones */ +} + +/** find zone name of message, returns the SOA record */ +static struct ub_packed_rrset_key* reply_find_soa(struct reply_info* rep) +{ + size_t i; + for(i=rep->an_numrrsets; i< rep->an_numrrsets+rep->ns_numrrsets; i++){ + if(ntohs(rep->rrsets[i]->rk.type) != LDNS_RR_TYPE_SOA) + return rep->rrsets[i]; + } + return NULL; +} + void val_neg_addreply(struct val_neg_cache* neg, struct reply_info* rep) { size_t i; + struct ub_packed_rrset_key* soa; + struct val_neg_zone* zone; + /* find the zone name in message */ + soa = reply_find_soa(rep); + if(!soa) + return; + + /* find or create the zone entry */ + lock_basic_lock(&neg->lock); + zone = neg_find_zone(neg, soa); + if(!zone) { + if(!(zone = neg_create_zone(neg, soa))) { + lock_basic_unlock(&neg->lock); + log_err("out of memory adding negative zone"); + return; + } + } + + /* insert the NSECs */ for(i=rep->an_numrrsets; i< rep->an_numrrsets+rep->ns_numrrsets; i++){ if(ntohs(rep->rrsets[i]->rk.type) != LDNS_RR_TYPE_NSEC) continue; - /* insert the NSEC */ } + lock_basic_unlock(&neg->lock); } int val_neg_dlvlookup(struct val_neg_cache* neg, uint8_t* qname, size_t len, diff --git a/validator/val_neg.h b/validator/val_neg.h index 5eb2753f8..857c6aff4 100644 --- a/validator/val_neg.h +++ b/validator/val_neg.h @@ -62,7 +62,7 @@ struct val_neg_cache { * Because we use a rbtree for the data (quick lookup), we need * a big lock */ lock_basic_t lock; - /** The data rbtree for NSEC. contents of type val_neg_data */ + /** The zone rbtree. contents of type val_neg_zone */ rbtree_t tree; /** the first and last in linked list of LRU of val_neg_data */ struct val_neg_data* first; @@ -74,6 +74,36 @@ struct val_neg_cache { size_t max; }; +/** + * Per Zone aggressive negative caching data. + */ +struct val_neg_zone { + /** rbtree node element, key is this struct: the name */ + rbnode_t node; + /** name; the key */ + uint8_t* name; + /** length of name */ + size_t len; + /** labels in name */ + int labs; + + /** pointer to parent zone in the negative cache */ + struct val_neg_zone* parent; + + /** type of zone ; NSEC */ + + /** hash of zonename, SOA type, class, for lookup of SOA rrset */ + hashvalue_t soa_hash; + + /** tree of NSEC data for this zone, sort by NSEC owner name */ + rbtree_t tree; + /** the children that have NULL as a parent ptr */ + struct val_neg_data* child_first, *child_last; + + /** class of node; host order */ + uint16_t dclass; +}; + /** * Data element for aggressive negative caching. */ @@ -89,23 +119,22 @@ struct val_neg_data { /** pointer to parent node in the negative cache */ struct val_neg_data* parent; + /** linked list of items that have this one as parent, children */ + struct val_neg_data* child_first, *child_last; + /** next and previous siblings in the list of childprent with the + * same value for the parent pointer */ + struct val_neg_data* sibling_next, *sibling_prev; + + /** the zone that this denial is part of */ + struct val_neg_zone* zone; /** previous in LRU */ struct val_neg_data* prev; /** next in LRU (next element was less recently used) */ struct val_neg_data* next; - /** reference to NSEC rrset (parent side of a zone cut) */ - struct rrset_ref nsec_above; - /** reference to SOA record for zone of nsec_above */ - struct rrset_ref soa_above; - /** reference to NSEC rrset (child side of a zone cut - or elsewhere) */ - struct rrset_ref nsec_below; - /** reference to SOA record for zone of nsec_below */ - struct rrset_ref soa_below; - - /** class of node; host order */ - uint16_t dclass; + /** hash of denial rrset: owner name, NSEC, class, for rrset lookup*/ + hashvalue_t nsec_hash; }; /** @@ -138,7 +167,12 @@ void neg_cache_delete(struct val_neg_cache* neg); /** * Comparison function for rbtree val neg data elements */ -int val_neg_compare(const void* a, const void* b); +int val_neg_data_compare(const void* a, const void* b); + +/** + * Comparison function for rbtree val neg zone elements + */ +int val_neg_zone_compare(const void* a, const void* b); /** * Insert NSECs from this message into the negative cache for reference.