*/
#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;
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;
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;
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,
* 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;
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.
*/
/** 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;
};
/**
/**
* 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.