mirror of
https://github.com/NLnetLabs/unbound.git
synced 2025-12-28 02:29:51 -05:00
Host cache code.
git-svn-id: file:///svn/unbound/trunk@319 be551aaa-1e26-0410-a405-d3ace91eadb9
This commit is contained in:
parent
62461e23be
commit
e6dccd8565
5 changed files with 426 additions and 9 deletions
|
|
@ -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.
|
||||
|
|
|
|||
389
services/cache/infra.c
vendored
389
services/cache/infra.c
vendored
|
|
@ -40,4 +40,393 @@
|
|||
*/
|
||||
#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;
|
||||
}
|
||||
|
|
|
|||
23
services/cache/infra.h
vendored
23
services/cache/infra.h
vendored
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
Loading…
Reference in a new issue