2 * services/cache/infra.c - infrastructure cache, server rtt and capabilities
4 * Copyright (c) 2007, NLnet Labs. All rights reserved.
6 * This software is open source.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
12 * Redistributions of source code must retain the above copyright notice,
13 * this list of conditions and the following disclaimer.
15 * Redistributions in binary form must reproduce the above copyright notice,
16 * this list of conditions and the following disclaimer in the documentation
17 * and/or other materials provided with the distribution.
19 * Neither the name of the NLNET LABS nor the names of its contributors may
20 * be used to endorse or promote products derived from this software without
21 * specific prior written permission.
23 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
26 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
27 * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
29 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
30 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
31 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
32 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
33 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39 * This file contains the infrastructure cache.
42 #include "sldns/rrdef.h"
43 #include "sldns/str2wire.h"
44 #include "services/cache/infra.h"
45 #include "util/storage/slabhash.h"
46 #include "util/storage/lookup3.h"
47 #include "util/data/dname.h"
49 #include "util/net_help.h"
50 #include "util/config_file.h"
51 #include "iterator/iterator.h"
53 /** Timeout when only a single probe query per IP is allowed. */
54 #define PROBE_MAXRTO 12000 /* in msec */
56 /** number of timeouts for a type when the domain can be blocked ;
57 * even if another type has completely rtt maxed it, the different type
58 * can do this number of packets (until those all timeout too) */
59 #define TIMEOUT_COUNT_MAX 3
61 /** ratelimit value for delegation point */
62 int infra_dp_ratelimit = 0;
65 infra_sizefunc(void* k, void* ATTR_UNUSED(d))
67 struct infra_key* key = (struct infra_key*)k;
68 return sizeof(*key) + sizeof(struct infra_data) + key->namelen
69 + lock_get_mem(&key->entry.lock);
73 infra_compfunc(void* key1, void* key2)
75 struct infra_key* k1 = (struct infra_key*)key1;
76 struct infra_key* k2 = (struct infra_key*)key2;
77 int r = sockaddr_cmp(&k1->addr, k1->addrlen, &k2->addr, k2->addrlen);
80 if(k1->namelen != k2->namelen) {
81 if(k1->namelen < k2->namelen)
85 return query_dname_compare(k1->zonename, k2->zonename);
89 infra_delkeyfunc(void* k, void* ATTR_UNUSED(arg))
91 struct infra_key* key = (struct infra_key*)k;
94 lock_rw_destroy(&key->entry.lock);
100 infra_deldatafunc(void* d, void* ATTR_UNUSED(arg))
102 struct infra_data* data = (struct infra_data*)d;
107 rate_sizefunc(void* k, void* ATTR_UNUSED(d))
109 struct rate_key* key = (struct rate_key*)k;
110 return sizeof(*key) + sizeof(struct rate_data) + key->namelen
111 + lock_get_mem(&key->entry.lock);
115 rate_compfunc(void* key1, void* key2)
117 struct rate_key* k1 = (struct rate_key*)key1;
118 struct rate_key* k2 = (struct rate_key*)key2;
119 if(k1->namelen != k2->namelen) {
120 if(k1->namelen < k2->namelen)
124 return query_dname_compare(k1->name, k2->name);
128 rate_delkeyfunc(void* k, void* ATTR_UNUSED(arg))
130 struct rate_key* key = (struct rate_key*)k;
133 lock_rw_destroy(&key->entry.lock);
139 rate_deldatafunc(void* d, void* ATTR_UNUSED(arg))
141 struct rate_data* data = (struct rate_data*)d;
145 /** find or create element in domainlimit tree */
146 static struct domain_limit_data* domain_limit_findcreate(
147 struct infra_cache* infra, char* name)
152 struct domain_limit_data* d;
155 nm = sldns_str2wire_dname(name, &nmlen);
157 log_err("could not parse %s", name);
160 labs = dname_count_labels(nm);
162 /* can we find it? */
163 d = (struct domain_limit_data*)name_tree_find(&infra->domain_limits,
164 nm, nmlen, labs, LDNS_RR_CLASS_IN);
171 d = (struct domain_limit_data*)calloc(1, sizeof(*d));
176 d->node.node.key = &d->node;
180 d->node.dclass = LDNS_RR_CLASS_IN;
183 if(!name_tree_insert(&infra->domain_limits, &d->node, nm, nmlen,
184 labs, LDNS_RR_CLASS_IN)) {
185 log_err("duplicate element in domainlimit tree");
193 /** insert rate limit configuration into lookup tree */
194 static int infra_ratelimit_cfg_insert(struct infra_cache* infra,
195 struct config_file* cfg)
197 struct config_str2list* p;
198 struct domain_limit_data* d;
199 for(p = cfg->ratelimit_for_domain; p; p = p->next) {
200 d = domain_limit_findcreate(infra, p->str);
203 d->lim = atoi(p->str2);
205 for(p = cfg->ratelimit_below_domain; p; p = p->next) {
206 d = domain_limit_findcreate(infra, p->str);
209 d->below = atoi(p->str2);
215 infra_create(struct config_file* cfg)
217 struct infra_cache* infra = (struct infra_cache*)calloc(1,
218 sizeof(struct infra_cache));
219 size_t maxmem = cfg->infra_cache_numhosts * (sizeof(struct infra_key)+
220 sizeof(struct infra_data)+INFRA_BYTES_NAME);
221 infra->hosts = slabhash_create(cfg->infra_cache_slabs,
222 INFRA_HOST_STARTSIZE, maxmem, &infra_sizefunc, &infra_compfunc,
223 &infra_delkeyfunc, &infra_deldatafunc, NULL);
228 infra->host_ttl = cfg->host_ttl;
229 name_tree_init(&infra->domain_limits);
230 infra_dp_ratelimit = cfg->ratelimit;
231 if(cfg->ratelimit != 0) {
232 infra->domain_rates = slabhash_create(cfg->ratelimit_slabs,
233 INFRA_HOST_STARTSIZE, cfg->ratelimit_size,
234 &rate_sizefunc, &rate_compfunc, &rate_delkeyfunc,
235 &rate_deldatafunc, NULL);
236 if(!infra->domain_rates) {
240 /* insert config data into ratelimits */
241 if(!infra_ratelimit_cfg_insert(infra, cfg)) {
245 name_tree_init_parents(&infra->domain_limits);
250 /** delete domain_limit entries */
251 static void domain_limit_free(rbnode_t* n, void* ATTR_UNUSED(arg))
254 free(((struct domain_limit_data*)n)->node.name);
260 infra_delete(struct infra_cache* infra)
264 slabhash_delete(infra->hosts);
265 slabhash_delete(infra->domain_rates);
266 traverse_postorder(&infra->domain_limits, domain_limit_free, NULL);
271 infra_adjust(struct infra_cache* infra, struct config_file* cfg)
275 return infra_create(cfg);
276 infra->host_ttl = cfg->host_ttl;
277 maxmem = cfg->infra_cache_numhosts * (sizeof(struct infra_key)+
278 sizeof(struct infra_data)+INFRA_BYTES_NAME);
279 if(maxmem != slabhash_get_size(infra->hosts) ||
280 cfg->infra_cache_slabs != infra->hosts->size) {
282 infra = infra_create(cfg);
287 /** calculate the hash value for a host key */
289 hash_addr(struct sockaddr_storage* addr, socklen_t addrlen)
291 hashvalue_t h = 0xab;
292 /* select the pieces to hash, some OS have changing data inside */
293 if(addr_is_ip6(addr, addrlen)) {
294 struct sockaddr_in6* in6 = (struct sockaddr_in6*)addr;
295 h = hashlittle(&in6->sin6_family, sizeof(in6->sin6_family), h);
296 h = hashlittle(&in6->sin6_port, sizeof(in6->sin6_port), h);
297 h = hashlittle(&in6->sin6_addr, INET6_SIZE, h);
299 struct sockaddr_in* in = (struct sockaddr_in*)addr;
300 h = hashlittle(&in->sin_family, sizeof(in->sin_family), h);
301 h = hashlittle(&in->sin_port, sizeof(in->sin_port), h);
302 h = hashlittle(&in->sin_addr, INET_SIZE, h);
307 /** calculate infra hash for a key */
309 hash_infra(struct sockaddr_storage* addr, socklen_t addrlen, uint8_t* name)
311 return dname_query_hash(name, hash_addr(addr, addrlen));
314 /** lookup version that does not check host ttl (you check it) */
315 struct lruhash_entry*
316 infra_lookup_nottl(struct infra_cache* infra, struct sockaddr_storage* addr,
317 socklen_t addrlen, uint8_t* name, size_t namelen, int wr)
321 memcpy(&k.addr, addr, addrlen);
324 k.entry.hash = hash_infra(addr, addrlen, name);
325 k.entry.key = (void*)&k;
327 return slabhash_lookup(infra->hosts, k.entry.hash, &k, wr);
330 /** init the data elements */
332 data_entry_init(struct infra_cache* infra, struct lruhash_entry* e,
335 struct infra_data* data = (struct infra_data*)e->data;
336 data->ttl = timenow + infra->host_ttl;
337 rtt_init(&data->rtt);
338 data->edns_version = 0;
339 data->edns_lame_known = 0;
340 data->probedelay = 0;
341 data->isdnsseclame = 0;
343 data->lame_type_A = 0;
344 data->lame_other = 0;
346 data->timeout_AAAA = 0;
347 data->timeout_other = 0;
351 * Create and init a new entry for a host
352 * @param infra: infra structure with config parameters.
353 * @param addr: host address.
354 * @param addrlen: length of addr.
355 * @param name: name of zone
356 * @param namelen: length of name.
357 * @param tm: time now.
358 * @return: the new entry or NULL on malloc failure.
360 static struct lruhash_entry*
361 new_entry(struct infra_cache* infra, struct sockaddr_storage* addr,
362 socklen_t addrlen, uint8_t* name, size_t namelen, time_t tm)
364 struct infra_data* data;
365 struct infra_key* key = (struct infra_key*)malloc(sizeof(*key));
368 data = (struct infra_data*)malloc(sizeof(struct infra_data));
373 key->zonename = memdup(name, namelen);
379 key->namelen = namelen;
380 lock_rw_init(&key->entry.lock);
381 key->entry.hash = hash_infra(addr, addrlen, name);
382 key->entry.key = (void*)key;
383 key->entry.data = (void*)data;
384 key->addrlen = addrlen;
385 memcpy(&key->addr, addr, addrlen);
386 data_entry_init(infra, &key->entry, tm);
391 infra_host(struct infra_cache* infra, struct sockaddr_storage* addr,
392 socklen_t addrlen, uint8_t* nm, size_t nmlen, time_t timenow,
393 int* edns_vs, uint8_t* edns_lame_known, int* to)
395 struct lruhash_entry* e = infra_lookup_nottl(infra, addr, addrlen,
397 struct infra_data* data;
399 if(e && ((struct infra_data*)e->data)->ttl < timenow) {
400 /* it expired, try to reuse existing entry */
401 int old = ((struct infra_data*)e->data)->rtt.rto;
402 uint8_t tA = ((struct infra_data*)e->data)->timeout_A;
403 uint8_t tAAAA = ((struct infra_data*)e->data)->timeout_AAAA;
404 uint8_t tother = ((struct infra_data*)e->data)->timeout_other;
405 lock_rw_unlock(&e->lock);
406 e = infra_lookup_nottl(infra, addr, addrlen, nm, nmlen, 1);
408 /* if its still there we have a writelock, init */
410 /* do not touch lameness, it may be valid still */
411 data_entry_init(infra, e, timenow);
413 /* TOP_TIMEOUT remains on reuse */
414 if(old >= USEFUL_SERVER_TOP_TIMEOUT) {
415 ((struct infra_data*)e->data)->rtt.rto
416 = USEFUL_SERVER_TOP_TIMEOUT;
417 ((struct infra_data*)e->data)->timeout_A = tA;
418 ((struct infra_data*)e->data)->timeout_AAAA = tAAAA;
419 ((struct infra_data*)e->data)->timeout_other = tother;
424 /* insert new entry */
425 if(!(e = new_entry(infra, addr, addrlen, nm, nmlen, timenow)))
427 data = (struct infra_data*)e->data;
428 *edns_vs = data->edns_version;
429 *edns_lame_known = data->edns_lame_known;
430 *to = rtt_timeout(&data->rtt);
431 slabhash_insert(infra->hosts, e->hash, e, data, NULL);
434 /* use existing entry */
435 data = (struct infra_data*)e->data;
436 *edns_vs = data->edns_version;
437 *edns_lame_known = data->edns_lame_known;
438 *to = rtt_timeout(&data->rtt);
439 if(*to >= PROBE_MAXRTO && rtt_notimeout(&data->rtt)*4 <= *to) {
440 /* delay other queries, this is the probe query */
442 lock_rw_unlock(&e->lock);
443 e = infra_lookup_nottl(infra, addr,addrlen,nm,nmlen, 1);
444 if(!e) { /* flushed from cache real fast, no use to
445 allocate just for the probedelay */
448 data = (struct infra_data*)e->data;
450 /* add 999 to round up the timeout value from msec to sec,
451 * then add a whole second so it is certain that this probe
452 * has timed out before the next is allowed */
453 data->probedelay = timenow + ((*to)+1999)/1000;
455 lock_rw_unlock(&e->lock);
460 infra_set_lame(struct infra_cache* infra, struct sockaddr_storage* addr,
461 socklen_t addrlen, uint8_t* nm, size_t nmlen, time_t timenow,
462 int dnsseclame, int reclame, uint16_t qtype)
464 struct infra_data* data;
465 struct lruhash_entry* e;
466 int needtoinsert = 0;
467 e = infra_lookup_nottl(infra, addr, addrlen, nm, nmlen, 1);
470 if(!(e = new_entry(infra, addr, addrlen, nm, nmlen, timenow))) {
471 log_err("set_lame: malloc failure");
475 } else if( ((struct infra_data*)e->data)->ttl < timenow) {
476 /* expired, reuse existing entry */
477 data_entry_init(infra, e, timenow);
479 /* got an entry, now set the zone lame */
480 data = (struct infra_data*)e->data;
481 /* merge data (if any) */
483 data->isdnsseclame = 1;
486 if(!dnsseclame && !reclame && qtype == LDNS_RR_TYPE_A)
487 data->lame_type_A = 1;
488 if(!dnsseclame && !reclame && qtype != LDNS_RR_TYPE_A)
489 data->lame_other = 1;
492 slabhash_insert(infra->hosts, e->hash, e, e->data, NULL);
493 else { lock_rw_unlock(&e->lock); }
498 infra_update_tcp_works(struct infra_cache* infra,
499 struct sockaddr_storage* addr, socklen_t addrlen, uint8_t* nm,
502 struct lruhash_entry* e = infra_lookup_nottl(infra, addr, addrlen,
504 struct infra_data* data;
506 return; /* doesn't exist */
507 data = (struct infra_data*)e->data;
508 if(data->rtt.rto >= RTT_MAX_TIMEOUT)
509 /* do not disqualify this server altogether, it is better
511 data->rtt.rto = RTT_MAX_TIMEOUT-1000;
512 lock_rw_unlock(&e->lock);
516 infra_rtt_update(struct infra_cache* infra, struct sockaddr_storage* addr,
517 socklen_t addrlen, uint8_t* nm, size_t nmlen, int qtype,
518 int roundtrip, int orig_rtt, time_t timenow)
520 struct lruhash_entry* e = infra_lookup_nottl(infra, addr, addrlen,
522 struct infra_data* data;
523 int needtoinsert = 0;
526 if(!(e = new_entry(infra, addr, addrlen, nm, nmlen, timenow)))
529 } else if(((struct infra_data*)e->data)->ttl < timenow) {
530 data_entry_init(infra, e, timenow);
532 /* have an entry, update the rtt */
533 data = (struct infra_data*)e->data;
534 if(roundtrip == -1) {
535 rtt_lost(&data->rtt, orig_rtt);
536 if(qtype == LDNS_RR_TYPE_A) {
537 if(data->timeout_A < TIMEOUT_COUNT_MAX)
539 } else if(qtype == LDNS_RR_TYPE_AAAA) {
540 if(data->timeout_AAAA < TIMEOUT_COUNT_MAX)
541 data->timeout_AAAA++;
543 if(data->timeout_other < TIMEOUT_COUNT_MAX)
544 data->timeout_other++;
547 /* if we got a reply, but the old timeout was above server
548 * selection height, delete the timeout so the server is
549 * fully available again */
550 if(rtt_unclamped(&data->rtt) >= USEFUL_SERVER_TOP_TIMEOUT)
551 rtt_init(&data->rtt);
552 rtt_update(&data->rtt, roundtrip);
553 data->probedelay = 0;
554 if(qtype == LDNS_RR_TYPE_A)
556 else if(qtype == LDNS_RR_TYPE_AAAA)
557 data->timeout_AAAA = 0;
558 else data->timeout_other = 0;
560 if(data->rtt.rto > 0)
564 slabhash_insert(infra->hosts, e->hash, e, e->data, NULL);
565 else { lock_rw_unlock(&e->lock); }
569 long long infra_get_host_rto(struct infra_cache* infra,
570 struct sockaddr_storage* addr, socklen_t addrlen, uint8_t* nm,
571 size_t nmlen, struct rtt_info* rtt, int* delay, time_t timenow,
572 int* tA, int* tAAAA, int* tother)
574 struct lruhash_entry* e = infra_lookup_nottl(infra, addr, addrlen,
576 struct infra_data* data;
579 data = (struct infra_data*)e->data;
580 if(data->ttl >= timenow) {
581 ttl = (long long)(data->ttl - timenow);
582 memmove(rtt, &data->rtt, sizeof(*rtt));
583 if(timenow < data->probedelay)
584 *delay = (int)(data->probedelay - timenow);
587 *tA = (int)data->timeout_A;
588 *tAAAA = (int)data->timeout_AAAA;
589 *tother = (int)data->timeout_other;
590 lock_rw_unlock(&e->lock);
595 infra_edns_update(struct infra_cache* infra, struct sockaddr_storage* addr,
596 socklen_t addrlen, uint8_t* nm, size_t nmlen, int edns_version,
599 struct lruhash_entry* e = infra_lookup_nottl(infra, addr, addrlen,
601 struct infra_data* data;
602 int needtoinsert = 0;
604 if(!(e = new_entry(infra, addr, addrlen, nm, nmlen, timenow)))
607 } else if(((struct infra_data*)e->data)->ttl < timenow) {
608 data_entry_init(infra, e, timenow);
610 /* have an entry, update the rtt, and the ttl */
611 data = (struct infra_data*)e->data;
612 /* do not update if noEDNS and stored is yesEDNS */
613 if(!(edns_version == -1 && (data->edns_version != -1 &&
614 data->edns_lame_known))) {
615 data->edns_version = edns_version;
616 data->edns_lame_known = 1;
620 slabhash_insert(infra->hosts, e->hash, e, e->data, NULL);
621 else { lock_rw_unlock(&e->lock); }
626 infra_get_lame_rtt(struct infra_cache* infra,
627 struct sockaddr_storage* addr, socklen_t addrlen,
628 uint8_t* name, size_t namelen, uint16_t qtype,
629 int* lame, int* dnsseclame, int* reclame, int* rtt, time_t timenow)
631 struct infra_data* host;
632 struct lruhash_entry* e = infra_lookup_nottl(infra, addr, addrlen,
636 host = (struct infra_data*)e->data;
637 *rtt = rtt_unclamped(&host->rtt);
638 if(host->rtt.rto >= PROBE_MAXRTO && timenow < host->probedelay
639 && rtt_notimeout(&host->rtt)*4 <= host->rtt.rto) {
640 /* single probe for this domain, and we are not probing */
641 /* unless the query type allows a probe to happen */
642 if(qtype == LDNS_RR_TYPE_A) {
643 if(host->timeout_A >= TIMEOUT_COUNT_MAX)
644 *rtt = USEFUL_SERVER_TOP_TIMEOUT;
645 else *rtt = USEFUL_SERVER_TOP_TIMEOUT-1000;
646 } else if(qtype == LDNS_RR_TYPE_AAAA) {
647 if(host->timeout_AAAA >= TIMEOUT_COUNT_MAX)
648 *rtt = USEFUL_SERVER_TOP_TIMEOUT;
649 else *rtt = USEFUL_SERVER_TOP_TIMEOUT-1000;
651 if(host->timeout_other >= TIMEOUT_COUNT_MAX)
652 *rtt = USEFUL_SERVER_TOP_TIMEOUT;
653 else *rtt = USEFUL_SERVER_TOP_TIMEOUT-1000;
656 if(timenow > host->ttl) {
658 /* see if this can be a re-probe of an unresponsive server */
659 /* minus 1000 because that is outside of the RTTBAND, so
660 * blacklisted servers stay blacklisted if this is chosen */
661 if(host->rtt.rto >= USEFUL_SERVER_TOP_TIMEOUT) {
662 lock_rw_unlock(&e->lock);
663 *rtt = USEFUL_SERVER_TOP_TIMEOUT-1000;
669 lock_rw_unlock(&e->lock);
672 /* check lameness first */
673 if(host->lame_type_A && qtype == LDNS_RR_TYPE_A) {
674 lock_rw_unlock(&e->lock);
679 } else if(host->lame_other && qtype != LDNS_RR_TYPE_A) {
680 lock_rw_unlock(&e->lock);
685 } else if(host->isdnsseclame) {
686 lock_rw_unlock(&e->lock);
691 } else if(host->rec_lame) {
692 lock_rw_unlock(&e->lock);
698 /* no lameness for this type of query */
699 lock_rw_unlock(&e->lock);
706 int infra_find_ratelimit(struct infra_cache* infra, uint8_t* name,
709 int labs = dname_count_labels(name);
710 struct domain_limit_data* d = (struct domain_limit_data*)
711 name_tree_lookup(&infra->domain_limits, name, namelen, labs,
713 if(!d) return infra_dp_ratelimit;
715 if(d->node.labs == labs && d->lim != -1)
716 return d->lim; /* exact match */
718 /* find 'below match' */
719 if(d->node.labs == labs)
720 d = (struct domain_limit_data*)d->node.parent;
724 d = (struct domain_limit_data*)d->node.parent;
726 return infra_dp_ratelimit;
729 /** find data item in array, for write access, caller unlocks */
730 static struct lruhash_entry* infra_find_ratedata(struct infra_cache* infra,
731 uint8_t* name, size_t namelen, int wr)
734 hashvalue_t h = dname_query_hash(name, 0xab);
735 memset(&key, 0, sizeof(key));
737 key.namelen = namelen;
739 return slabhash_lookup(infra->domain_rates, h, &key, wr);
742 /** create rate data item for name, number 1 in now */
743 static void infra_create_ratedata(struct infra_cache* infra,
744 uint8_t* name, size_t namelen, time_t timenow)
746 hashvalue_t h = dname_query_hash(name, 0xab);
747 struct rate_key* k = (struct rate_key*)calloc(1, sizeof(*k));
748 struct rate_data* d = (struct rate_data*)calloc(1, sizeof(*d));
752 return; /* alloc failure */
754 k->namelen = namelen;
755 k->name = memdup(name, namelen);
759 return; /* alloc failure */
761 lock_rw_init(&k->entry.lock);
766 d->timestamp[0] = timenow;
767 slabhash_insert(infra->domain_rates, h, &k->entry, d, NULL);
770 /** find the second and return its rate counter, if none, remove oldest */
771 static int* infra_rate_find_second(void* data, time_t t)
773 struct rate_data* d = (struct rate_data*)data;
775 for(i=0; i<RATE_WINDOW; i++) {
776 if(d->timestamp[i] == t)
779 /* remove oldest timestamp, and insert it at t with 0 qps */
781 for(i=0; i<RATE_WINDOW; i++) {
782 if(d->timestamp[i] < d->timestamp[oldest])
785 d->timestamp[oldest] = t;
787 return &(d->qps[oldest]);
790 int infra_rate_max(void* data, time_t now)
792 struct rate_data* d = (struct rate_data*)data;
794 for(i=0; i<RATE_WINDOW; i++) {
795 if(now-d->timestamp[i] <= RATE_WINDOW) {
803 int infra_ratelimit_inc(struct infra_cache* infra, uint8_t* name,
804 size_t namelen, time_t timenow)
807 struct lruhash_entry* entry;
809 if(!infra_dp_ratelimit)
810 return 1; /* not enabled */
813 lim = infra_find_ratelimit(infra, name, namelen);
815 /* find or insert ratedata */
816 entry = infra_find_ratedata(infra, name, namelen, 1);
818 int premax = infra_rate_max(entry->data, timenow);
819 int* cur = infra_rate_find_second(entry->data, timenow);
821 max = infra_rate_max(entry->data, timenow);
822 lock_rw_unlock(&entry->lock);
824 if(premax < lim && max >= lim) {
826 dname_str(name, buf);
827 verbose(VERB_OPS, "ratelimit exceeded %s %d", buf, lim);
833 infra_create_ratedata(infra, name, namelen, timenow);
837 void infra_ratelimit_dec(struct infra_cache* infra, uint8_t* name,
838 size_t namelen, time_t timenow)
840 struct lruhash_entry* entry;
842 if(!infra_dp_ratelimit)
843 return; /* not enabled */
844 entry = infra_find_ratedata(infra, name, namelen, 1);
845 if(!entry) return; /* not cached */
846 cur = infra_rate_find_second(entry->data, timenow);
849 lock_rw_unlock(&entry->lock);
852 int infra_ratelimit_exceeded(struct infra_cache* infra, uint8_t* name,
853 size_t namelen, time_t timenow)
855 struct lruhash_entry* entry;
857 if(!infra_dp_ratelimit)
858 return 0; /* not enabled */
861 lim = infra_find_ratelimit(infra, name, namelen);
863 /* find current rate */
864 entry = infra_find_ratedata(infra, name, namelen, 0);
866 return 0; /* not cached */
867 max = infra_rate_max(entry->data, timenow);
868 lock_rw_unlock(&entry->lock);
874 infra_get_mem(struct infra_cache* infra)
876 size_t s = sizeof(*infra) + slabhash_get_mem(infra->hosts);
877 if(infra->domain_rates) s += slabhash_get_mem(infra->domain_rates);
878 /* ignore domain_limits because walk through tree is big */