]> git.ipfire.org Git - thirdparty/unbound.git/commitdiff
Host cache code.
authorWouter Wijngaards <wouter@nlnetlabs.nl>
Tue, 15 May 2007 10:53:27 +0000 (10:53 +0000)
committerWouter Wijngaards <wouter@nlnetlabs.nl>
Tue, 15 May 2007 10:53:27 +0000 (10:53 +0000)
git-svn-id: file:///svn/unbound/trunk@319 be551aaa-1e26-0410-a405-d3ace91eadb9

doc/Changelog
services/cache/infra.c
services/cache/infra.h
util/net_help.c
util/net_help.h

index 74d58f2818ccaaab85cb9251025427bc2133e8a2..5a7e9a61de9942fee74d33ec00c5990d72b69c31 100644 (file)
@@ -1,3 +1,6 @@
+15 May 2007: Wouter
+       - host cache code.
+
 14 May 2007: Wouter
        - Port to OS/X and Dec Alpha. Printf format and alignment fixes.
        - extensive lock debug report on join timeout.
index 356dc690d68fed9f20b8b7f3e183f1af9b8a3346..da33421b23cb8c8bd2051c661ad5e2aa9c225ca2 100644 (file)
  */
 #include "config.h"
 #include "services/cache/infra.h"
+#include "util/storage/slabhash.h"
+#include "util/storage/lookup3.h"
+#include "util/log.h"
+#include "util/net_help.h"
 
+/** calculate size for the hashtable, does not count size of lameness,
+ * so the hashtable is a fixed number of items */
+static size_t 
+infra_host_sizefunc(void* ATTR_UNUSED(k), void* ATTR_UNUSED(d))
+{
+       return sizeof(struct infra_host_key) + sizeof(struct infra_host_data);
+}
+
+/** compare two addresses, returns -1, 0, or +1 */
+static int 
+infra_host_compfunc(void* key1, void* key2)
+{
+       struct infra_host_key* k1 = (struct infra_host_key*)key1;
+       struct infra_host_key* k2 = (struct infra_host_key*)key2;
+       if(k1->addrlen != k2->addrlen) {
+               if(k1->addrlen < k2->addrlen)
+                       return -1;
+               return 1;
+       }
+       return memcmp(&k1->addr, &k2->addr, k1->addrlen);
+}
+
+/** delete key, and destroy the lock */
+static void 
+infra_host_delkeyfunc(void* k, void* ATTR_UNUSED(arg))
+{
+       struct infra_host_key* key = (struct infra_host_key*)k;
+       if(!key)
+               return;
+       lock_rw_destroy(&key->entry.lock);
+       free(key);
+}
+
+/** delete data and destroy the lameness hashtable */
+static void 
+infra_host_deldatafunc(void* d, void* ATTR_UNUSED(arg))
+{
+       struct infra_host_data* data = (struct infra_host_data*)d;
+       lruhash_delete(data->lameness);
+       free(data);
+}
+
+struct slabhash* 
+infra_create(struct config_file* cfg)
+{
+       /* TODO: use config settings */
+       /* the size of the lameness tables are not counted */
+       size_t maxmem = HOST_DEFAULT_SIZE * (sizeof(struct infra_host_key) + 
+               sizeof(struct infra_host_data));
+       struct slabhash* infra = slabhash_create(HASH_DEFAULT_SLABS,
+               INFRA_HOST_STARTSIZE, maxmem, &infra_host_sizefunc,
+               &infra_host_compfunc, &infra_host_delkeyfunc,
+               &infra_host_deldatafunc, NULL);
+       return infra;
+}
+
+void 
+infra_delete(struct slabhash* infra)
+{
+       if(!infra)
+               return;
+       slabhash_delete(infra);
+}
+
+/** calculate the hash value for a host key */
+static hashvalue_t
+hash_addr(struct sockaddr_storage* addr, socklen_t addrlen)
+{
+       hashvalue_t h = 0xab;
+       h = hashlittle(&addrlen, sizeof(addrlen), h);
+       h = hashlittle(addr, addrlen, h);
+       return h;
+}
+
+/** lookup version that does not check host ttl (you check it) */
+static struct lruhash_entry* 
+infra_lookup_host_nottl(struct slabhash* infra,
+        struct sockaddr_storage* addr, socklen_t addrlen, int wr)
+{
+       struct infra_host_key k;
+       k.addrlen = addrlen;
+       memcpy(&k.addr, addr, addrlen);
+       k.entry.hash = hash_addr(addr, addrlen);
+       k.entry.key = (void*)&k;
+       k.entry.data = NULL;
+       return slabhash_lookup(infra, k.entry.hash, &k, wr);
+}
+
+struct infra_host_data* 
+infra_lookup_host(struct slabhash* infra,
+        struct sockaddr_storage* addr, socklen_t addrlen, int wr,
+        time_t timenow, struct infra_host_key** key)
+{
+       struct infra_host_data* data;
+       struct lruhash_entry* e = infra_lookup_host_nottl(infra, addr, 
+               addrlen, wr);
+       *key = NULL;
+       if(!e)
+               return NULL;
+       /* check TTL */
+       data = (struct infra_host_data*)e->data;
+       if(data->ttl < timenow) {
+               lock_rw_unlock(&e->lock);
+               return NULL;
+       }
+       *key = (struct infra_host_key*)e->key;
+       return data;
+}
+
+/** 
+ * Create and init a new entry for a host 
+ * @param addr: host address.
+ * @param addrlen: length of addr.
+ * @param tm: time now.
+ * @return: the new entry or NULL on malloc failure.
+ */
+static struct lruhash_entry*
+new_host_entry(struct sockaddr_storage* addr, socklen_t addrlen, time_t tm)
+{
+       struct infra_host_data* data;
+       struct infra_host_key* key = (struct infra_host_key*)malloc(
+               sizeof(struct infra_host_key));
+       if(!key)
+               return NULL;
+       data = (struct infra_host_data*)malloc(
+               sizeof(struct infra_host_data));
+       if(!data) {
+               free(key);
+               return NULL;
+       }
+       lock_rw_init(&key->entry.lock);
+       key->entry.hash = hash_addr(addr, addrlen);
+       key->entry.key = (void*)key;
+       key->entry.data = (void*)data;
+       key->addrlen = addrlen;
+       memcpy(&key->addr, addr, addrlen);
+       data->ttl = tm + HOST_TTL;
+       data->lameness = NULL;
+       data->edns_version = 0;
+       rtt_init(&data->rtt);
+       return &key->entry;
+}
+
+int 
+infra_host(struct slabhash* infra, struct sockaddr_storage* addr,
+        socklen_t addrlen, time_t timenow, int* edns_vs, int* to)
+{
+       struct lruhash_entry* e = infra_lookup_host_nottl(infra, addr, 
+               addrlen, 0);
+       struct infra_host_data* data;
+       if(e && ((struct infra_host_data*)e->data)->ttl < timenow) {
+               /* it expired, try to reuse existing entry */
+               lock_rw_unlock(&e->lock);
+               e = infra_lookup_host_nottl(infra, addr, addrlen, 1);
+               if(e) {
+                       /* if its still there we have a writelock, init */
+                       /* re-initialise */
+                       data = (struct infra_host_data*)e->data;
+                       data->ttl = timenow + HOST_TTL;
+                       rtt_init(&data->rtt);
+                       /* do not touch lameness, it may be valid still */
+                       data->edns_version = 0;
+               }
+       }
+       if(!e) {
+               /* insert new entry */
+               if(!(e = new_host_entry(addr, addrlen, timenow)))
+                       return 0;
+               data = (struct infra_host_data*)e->data;
+               *to = rtt_timeout(&data->rtt);
+               *edns_vs = data->edns_version;
+               slabhash_insert(infra, e->hash, e, data, NULL);
+               return 1;
+       }
+       /* use existing entry */
+       data = (struct infra_host_data*)e->data;
+       *to = rtt_timeout(&data->rtt);
+       *edns_vs = data->edns_version;
+       lock_rw_unlock(&e->lock);
+       return 1;
+}
+
+/** hash lameness key */
+static hashvalue_t
+hash_lameness(uint8_t* name, size_t namelen)
+{
+       return hashlittle(name, namelen, 0xab);
+}
+
+int 
+infra_lookup_lame(struct infra_host_data* host,
+        uint8_t* name, size_t namelen, time_t timenow)
+{
+       struct lruhash_entry* e;
+       struct infra_lame_key k;
+       struct infra_lame_data *d;
+       if(!host->lameness)
+               return 0;
+       k.entry.hash = hash_lameness(name, namelen);
+       k.zonename = name;
+       k.namelen = namelen;
+       k.entry.key = (void*)&k;
+       k.entry.data = NULL;
+       e = lruhash_lookup(host->lameness, k.entry.hash, &k, 0);
+       if(!e)
+               return 0;
+       d = (struct infra_lame_data*)e->data;
+       if(d->ttl < timenow) {
+               lock_rw_unlock(&e->lock);
+               return 0;
+       }
+       lock_rw_unlock(&e->lock);
+       return 1;
+}
+
+/** calculate size, which is fixed, zonename does not count so that
+ * a fixed number of items is stored */
+static size_t 
+infra_lame_sizefunc(void* ATTR_UNUSED(k), void* ATTR_UNUSED(d))
+{
+       return sizeof(struct infra_lame_key)+sizeof(struct infra_lame_data);
+}
+
+/** compare zone names, returns -1, 0, +1 */
+static int 
+infra_lame_compfunc(void* key1, void* key2) 
+{
+       struct infra_lame_key* k1 = (struct infra_lame_key*)key1;
+       struct infra_lame_key* k2 = (struct infra_lame_key*)key2;
+       if(k1->namelen != k2->namelen) {
+               if(k1->namelen < k2->namelen)
+                       return -1;
+               return 1;
+       }
+       return memcmp(k1->zonename, k2->zonename, k1->namelen);
+}
+
+/** free key, lock and zonename */
+static void 
+infra_lame_delkeyfunc(void* k, void* ATTR_UNUSED(arg))
+{
+       struct infra_lame_key* key = (struct infra_lame_key*)k;
+       if(!key) 
+               return;
+       lock_rw_destroy(&key->entry.lock);
+       free(key->zonename);
+       free(key);
+}
+
+/** free the lameness data */
+static void 
+infra_lame_deldatafunc(void* d, void* ATTR_UNUSED(arg))
+{
+       if(!d) 
+               return;
+       free(d);
+}
+
+int 
+infra_set_lame(struct slabhash* infra,
+        struct sockaddr_storage* addr, socklen_t addrlen,
+        uint8_t* name, size_t namelen, time_t timenow)
+{
+       struct infra_host_data* data;
+       struct lruhash_entry* e;
+       int needtoinsert = 0;
+       struct infra_lame_key* k;
+       struct infra_lame_data* d;
+       /* allocate at start, easier cleanup (no locks held) */
+       k = (struct infra_lame_key*)malloc(sizeof(*k));
+       if(!k) {
+               log_err("set_lame: malloc failure");
+               return 0;
+       }
+       d = (struct infra_lame_data*)malloc(sizeof(*d));
+       if(!d) {
+               free(k);
+               log_err("set_lame: malloc failure");
+               return 0;
+       }
+       k->zonename = memdup(name, namelen);
+       if(!k->zonename) {
+               free(d);
+               free(k);
+               log_err("set_lame: malloc failure");
+               return 0;
+       }
+       lock_rw_init(&k->entry.lock);
+       k->entry.hash = hash_lameness(name, namelen);
+       k->entry.key = (void*)k;
+       k->entry.data = (void*)d;
+       d->ttl = timenow + HOST_LAME_TTL;
+       k->namelen = namelen;
+       e = infra_lookup_host_nottl(infra, addr, addrlen, 1);
+       if(!e) {
+               /* insert it */
+               if(!(e = new_host_entry(addr, addrlen, timenow))) {
+                       free(k->zonename);
+                       free(k);
+                       free(d);
+                       log_err("set_lame: malloc failure");
+                       return 0;
+               }
+               needtoinsert = 1;
+       }
+       /* got an entry, now set the zone lame */
+       data = (struct infra_host_data*)e->data;
+       if(!data->lameness) {
+               /* create hash table if not there already */
+               data->lameness = lruhash_create(INFRA_LAME_STARTSIZE,
+                       INFRA_LAME_MAXMEM*(sizeof(struct infra_lame_key)+
+                       sizeof(struct infra_lame_data)), infra_lame_sizefunc, 
+                       infra_lame_compfunc, infra_lame_delkeyfunc,
+                       infra_lame_deldatafunc, NULL);
+               if(!data->lameness) {
+                       log_err("set_lame: malloc failure");
+                       if(needtoinsert) slabhash_insert(infra, e->hash, e, 
+                               e->data, NULL);
+                       else    lock_rw_unlock(&e->lock);
+                       free(k->zonename);
+                       free(k);
+                       free(d);
+                       return 0;
+               }
+       }
+       /* inserts new entry, or updates TTL of older entry */
+       lruhash_insert(data->lameness, k->entry.hash, &k->entry, d, NULL);
+       
+       if(needtoinsert)
+               slabhash_insert(infra, e->hash, e, e->data, NULL);
+       else    lock_rw_unlock(&e->lock);
+       return 1;
+}
+
+int 
+infra_rtt_update(struct slabhash* infra,
+        struct sockaddr_storage* addr, socklen_t addrlen,
+        int roundtrip, time_t timenow)
+{
+       struct lruhash_entry* e = infra_lookup_host_nottl(infra, addr, 
+               addrlen, 1);
+       struct infra_host_data* data;
+       int needtoinsert = 0;
+       if(!e) {
+               if(!(e = new_host_entry(addr, addrlen, timenow)))
+                       return 0;
+               needtoinsert = 1;
+       }
+       /* have an entry, update the rtt, and the ttl */
+       data = (struct infra_host_data*)e->data;
+       data->ttl = timenow + HOST_TTL;
+       if(roundtrip == -1)
+               rtt_lost(&data->rtt);
+       else    rtt_update(&data->rtt, roundtrip);
+
+       if(needtoinsert)
+               slabhash_insert(infra, e->hash, e, e->data, NULL);
+       else    lock_rw_unlock(&e->lock);
+       return 1;
+}
+
+int 
+infra_edns_update(struct slabhash* infra,
+        struct sockaddr_storage* addr, socklen_t addrlen,
+        int edns_version, time_t timenow)
+{
+       struct lruhash_entry* e = infra_lookup_host_nottl(infra, addr, 
+               addrlen, 1);
+       struct infra_host_data* data;
+       int needtoinsert = 0;
+       if(!e) {
+               if(!(e = new_host_entry(addr, addrlen, timenow)))
+                       return 0;
+               needtoinsert = 1;
+       }
+       /* have an entry, update the rtt, and the ttl */
+       data = (struct infra_host_data*)e->data;
+       data->ttl = timenow + HOST_TTL;
+       data->edns_version = edns_version;
+
+       if(needtoinsert)
+               slabhash_insert(infra, e->hash, e, e->data, NULL);
+       else    lock_rw_unlock(&e->lock);
+       return 1;
+}
index 486a041e31f638f26369d5239ede137a32171e1c..0271870344448d99e7925f992e27c508b2afded9 100644 (file)
@@ -70,8 +70,6 @@ struct infra_host_data {
        struct lruhash* lameness;
        /** edns version that the host supports, -1 means no EDNS */
        int edns_version;
-       /** edns message size that the host advertizes, 512 by default. */
-       uint16_t edns_size;
 };
 
 /**
@@ -101,6 +99,12 @@ struct infra_lame_data {
 #define HOST_LAME_TTL 900
 /** default size of the host cache, number of entries */
 #define HOST_DEFAULT_SIZE 1000
+/** infra host cache default hash lookup size */
+#define INFRA_HOST_STARTSIZE 32
+/** infra lame cache default hash lookup size */
+#define INFRA_LAME_STARTSIZE 2
+/** infra lame cache max memory per host, for this many entries */
+#define INFRA_LAME_MAXMEM 1000
 
 /**
  * Create infra cache.
@@ -122,15 +126,16 @@ void infra_delete(struct slabhash* infra);
  * @param addrlen: length of addr.
  * @param wr: set to true to get a writelock on the entry.
  * @param timenow: what time it is now.
+ * @param key: the key for the host, returned so caller can unlock when done.
  * @return: host data or NULL if not found or expired.
  */
-struct infra_data* infra_lookup_host(struct slabhash* infra, 
+struct infra_host_data* infra_lookup_host(struct slabhash* infra, 
        struct sockaddr_storage* addr, socklen_t addrlen, int wr, 
-       time_t timenow);
+       time_t timenow, struct infra_host_key** key);
 
 /**
  * Find host information to send a packet. Creates new entry if not found.
- * Lameness is empty. EDNS is 0, size is 512, and rtt is returned for 
+ * Lameness is empty. EDNS is 0 (try with first), and rtt is returned for 
  * the first message to it.
  * @param infra: infrastructure cache.
  * @param addr: host address.
@@ -152,7 +157,7 @@ int infra_host(struct slabhash* infra, struct sockaddr_storage* addr,
  * @param timenow: what time it is now.
  * @return: 0 if not lame or unknown or timed out, true if lame.
  */
-int infra_lookup_lame(struct infra_data* host,
+int infra_lookup_lame(struct infra_host_data* host,
        uint8_t* name, size_t namelen, time_t timenow);
 
 /**
@@ -174,7 +179,8 @@ int infra_set_lame(struct slabhash* infra,
  * @param infra: infrastructure cache.
  * @param addr: host address.
  * @param addrlen: length of addr.
- * @param roundtrip: estimate of roundtrip time or -1 for timeout.
+ * @param roundtrip: estimate of roundtrip time in milliseconds or -1 for 
+ *     timeout.
  * @param timenow: what time it is now.
  * @return: 0 on error.
  */
@@ -188,12 +194,11 @@ int infra_rtt_update(struct slabhash* infra,
  * @param addr: host address.
  * @param addrlen: length of addr.
  * @param edns_version: the version that it publishes.
- * @param udp_size: what udp size it can handle.
  * @param timenow: what time it is now.
  * @return: 0 on error.
  */
 int infra_edns_update(struct slabhash* infra,
         struct sockaddr_storage* addr, socklen_t addrlen,
-       int edns_version, uint16_t udp_size, time_t timenow);
+       int edns_version, time_t timenow);
 
 #endif /* SERVICES_CACHE_INFRA_H */
index 88aecd379c73943fe746dd5545750afc962c135e..3944dc0b788fd2ed05e50d4813a104d5efdfcea1 100644 (file)
@@ -109,3 +109,15 @@ write_iov_buffer(ldns_buffer* buffer, struct iovec* iov, size_t iovlen)
        }
        ldns_buffer_flip(buffer);
 }
+
+void* 
+memdup(void* data, size_t len)
+{
+       void* d;
+       if(!data) return NULL;
+       if(len == 0) return NULL;
+       d = malloc(len);
+       if(!d) return NULL;
+       memcpy(d, data, len);
+       return d;
+}
index e18a24afd23255843c73773c50fa0528f8646cba..a859e312e6b2f9f7780d36c14379234b428a08ab 100644 (file)
@@ -100,4 +100,12 @@ int is_pow2(size_t num);
  */
 void write_iov_buffer(ldns_buffer* buffer, struct iovec* iov, size_t iovlen);
 
+/**
+ * Allocate memory and copy over contents.
+ * @param data: what to copy over.
+ * @param len: length of data.
+ * @return: NULL on malloc failure, or newly malloced data.
+ */
+void* memdup(void* data, size_t len);
+
 #endif /* NET_HELP_H */