]> git.ipfire.org Git - thirdparty/unbound.git/commitdiff
flush data from cache.
authorWouter Wijngaards <wouter@nlnetlabs.nl>
Tue, 23 Sep 2008 14:07:02 +0000 (14:07 +0000)
committerWouter Wijngaards <wouter@nlnetlabs.nl>
Tue, 23 Sep 2008 14:07:02 +0000 (14:07 +0000)
git-svn-id: file:///svn/unbound/trunk@1268 be551aaa-1e26-0410-a405-d3ace91eadb9

daemon/remote.c
doc/Changelog
doc/control_proto_spec.txt
doc/plan
doc/unbound-control.8.in
services/cache/rrset.c
services/cache/rrset.h
smallapp/unbound-control.c

index 16ca5c2c13812947be9b6334e20c9b42de41067b..cc7082a202d8454dc337dbeaef25c79e7d79b7d7 100644 (file)
@@ -59,6 +59,9 @@
 #include "util/storage/slabhash.h"
 #include "util/fptr_wlist.h"
 #include "util/data/dname.h"
+#include "validator/validator.h"
+#include "validator/val_kcache.h"
+#include "validator/val_kentry.h"
 
 #ifdef HAVE_SYS_TYPES_H
 #  include <sys/types.h>
@@ -982,6 +985,182 @@ do_lookup(SSL* ssl, struct worker* worker, char* arg)
        free(nm);
 }
 
+/** flush a type */
+static void
+do_flush_type(SSL* ssl, struct worker* worker, char* arg)
+{
+       uint8_t* nm;
+       int nmlabs;
+       size_t nmlen;
+       char* arg2;
+       uint16_t t;
+       if(!find_arg2(ssl, arg, &arg2))
+               return;
+       if(!parse_arg_name(ssl, arg, &nm, &nmlen, &nmlabs))
+               return;
+       t = ldns_get_rr_type_by_name(arg2);
+       rrset_cache_remove(worker->env.rrset_cache, nm, nmlen, 
+               t, LDNS_RR_CLASS_IN, 0);
+       
+       free(nm);
+       send_ok(ssl);
+}
+
+/**
+ * Local info for deletion functions
+ */
+struct del_info {
+       /** worker */
+       struct worker* worker;
+       /** name to delete */
+       uint8_t* name;
+       /** length */
+       size_t len;
+       /** labels */
+       int labs;
+       /** time to invalidate to */
+       uint32_t expired;
+       /** number of rrsets removed */
+       size_t num_rrsets;
+       /** number of key entries removed */
+       size_t num_keys;
+};
+
+/** callback to delete rrsets in a zone */
+static void
+zone_del_rrset(struct lruhash_entry* e, void* arg)
+{
+       /* entry is locked */
+       struct del_info* inf = (struct del_info*)arg;
+       struct ub_packed_rrset_key* k = (struct ub_packed_rrset_key*)e->key;
+       if(dname_subdomain_c(k->rk.dname, inf->name)) {
+               struct packed_rrset_data* d = 
+                       (struct packed_rrset_data*)e->data;
+               d->ttl = inf->expired;
+               inf->num_rrsets++;
+       }
+}
+
+/** callback to delete keys in zone */
+static void
+zone_del_kcache(struct lruhash_entry* e, void* arg)
+{
+       /* entry is locked */
+       struct del_info* inf = (struct del_info*)arg;
+       struct key_entry_key* k = (struct key_entry_key*)e->key;
+       if(dname_subdomain_c(k->name, inf->name)) {
+               struct key_entry_data* d = (struct key_entry_data*)e->data;
+               d->ttl = inf->expired;
+               inf->num_keys++;
+       }
+}
+
+/** traverse a lruhash */
+static void 
+lruhash_traverse(struct lruhash* h, int wr, 
+       void (*func)(struct lruhash_entry*, void*), void* arg)
+{
+       size_t i;
+       struct lruhash_entry* e;
+
+       lock_quick_lock(&h->lock);
+       for(i=0; i<h->size; i++) {
+               lock_quick_lock(&h->array[i].lock);
+               for(e = h->array[i].overflow_list; e; e = e->overflow_next) {
+                       if(wr) {
+                               lock_rw_wrlock(&e->lock);
+                       } else {
+                               lock_rw_rdlock(&e->lock);
+                       }
+                       (*func)(e, arg);
+                       lock_rw_unlock(&e->lock);
+               }
+               lock_quick_unlock(&h->array[i].lock);
+       }
+       lock_quick_unlock(&h->lock);
+}
+
+/** traverse a slabhash */
+static void 
+slabhash_traverse(struct slabhash* sh, int wr, 
+       void (*func)(struct lruhash_entry*, void*), void* arg)
+{
+       size_t i;
+       for(i=0; i<sh->size; i++)
+               lruhash_traverse(sh->array[i], wr, func, arg);
+}
+
+/** remove all rrsets and keys from zone from cache */
+static void
+do_flush_zone(SSL* ssl, struct worker* worker, char* arg)
+{
+       uint8_t* nm;
+       int nmlabs;
+       size_t nmlen;
+       struct del_info inf;
+       int idx;
+       if(!parse_arg_name(ssl, arg, &nm, &nmlen, &nmlabs))
+               return;
+       /* delete all RRs and key entries from zone */
+       /* what we do is to set them all expired */
+       inf.worker = worker;
+       inf.name = nm;
+       inf.len = nmlen;
+       inf.labs = nmlabs;
+       inf.expired = *worker->env.now;
+       inf.expired -= 3; /* handle 3 seconds skew between threads */
+       inf.num_rrsets = 0;
+       inf.num_keys = 0;
+       slabhash_traverse(&worker->env.rrset_cache->table, 1, 
+               &zone_del_rrset, &inf);
+
+       /* and validator cache */
+       idx = modstack_find(&worker->daemon->mods, "validator");
+       if(idx != -1) {
+               struct val_env* ve = (struct val_env*)worker->env.modinfo[idx];
+               slabhash_traverse(ve->kcache->slab, 1, &zone_del_kcache, &inf);
+       }
+
+       free(nm);
+
+       (void)ssl_printf(ssl, "ok removed %u rrsets and %u key entries\n",
+               (unsigned)inf.num_rrsets, (unsigned)inf.num_keys);
+}
+
+/** remove name rrset from cache */
+static void
+do_flush_name(SSL* ssl, struct worker* worker, char* arg)
+{
+       uint8_t* nm;
+       int nmlabs;
+       size_t nmlen;
+       if(!parse_arg_name(ssl, arg, &nm, &nmlen, &nmlabs))
+               return;
+       rrset_cache_remove(worker->env.rrset_cache, nm, nmlen, 
+               LDNS_RR_TYPE_A, LDNS_RR_CLASS_IN, 0);
+       rrset_cache_remove(worker->env.rrset_cache, nm, nmlen, 
+               LDNS_RR_TYPE_AAAA, LDNS_RR_CLASS_IN, 0);
+       rrset_cache_remove(worker->env.rrset_cache, nm, nmlen, 
+               LDNS_RR_TYPE_NS, LDNS_RR_CLASS_IN, 0);
+       rrset_cache_remove(worker->env.rrset_cache, nm, nmlen, 
+               LDNS_RR_TYPE_SOA, LDNS_RR_CLASS_IN, 0);
+       rrset_cache_remove(worker->env.rrset_cache, nm, nmlen, 
+               LDNS_RR_TYPE_CNAME, LDNS_RR_CLASS_IN, 0);
+       rrset_cache_remove(worker->env.rrset_cache, nm, nmlen, 
+               LDNS_RR_TYPE_DNAME, LDNS_RR_CLASS_IN, 0);
+       rrset_cache_remove(worker->env.rrset_cache, nm, nmlen, 
+               LDNS_RR_TYPE_MX, LDNS_RR_CLASS_IN, 0);
+       rrset_cache_remove(worker->env.rrset_cache, nm, nmlen, 
+               LDNS_RR_TYPE_PTR, LDNS_RR_CLASS_IN, 0);
+       rrset_cache_remove(worker->env.rrset_cache, nm, nmlen, 
+               LDNS_RR_TYPE_SRV, LDNS_RR_CLASS_IN, 0);
+       rrset_cache_remove(worker->env.rrset_cache, nm, nmlen, 
+               LDNS_RR_TYPE_NAPTR, LDNS_RR_CLASS_IN, 0);
+       
+       free(nm);
+       send_ok(ssl);
+}
+
 /** execute a remote control command */
 static void
 execute_cmd(struct daemon_remote* rc, SSL* ssl, char* cmd)
@@ -1010,6 +1189,12 @@ execute_cmd(struct daemon_remote* rc, SSL* ssl, char* cmd)
                if(load_cache(ssl, rc->worker)) send_ok(ssl);
        } else if(strncmp(p, "lookup", 6) == 0) {
                do_lookup(ssl, rc->worker, skipwhite(p+6));
+       } else if(strncmp(p, "flush_zone", 10) == 0) {
+               do_flush_zone(ssl, rc->worker, skipwhite(p+10));
+       } else if(strncmp(p, "flush_type", 10) == 0) {
+               do_flush_type(ssl, rc->worker, skipwhite(p+10));
+       } else if(strncmp(p, "flush", 5) == 0) {
+               do_flush_name(ssl, rc->worker, skipwhite(p+5));
        } else {
                (void)ssl_printf(ssl, "error unknown command '%s'\n", p);
        }
index 0bf4454abb27486f1d544757105d7b64e5df36e9..bf2791dc4d9631d7886d8aa6b8e3f1602ae12e6c 100644 (file)
@@ -1,5 +1,6 @@
 23 September 2008: Wouter
        - Msg cache is loaded. A cache load enables cache responses.
+       - unbound-control flush [name], flush_type and flush_zone.
 
 22 September 2008: Wouter
        - dump_cache and load_cache statements in unbound-control.
index 9b3012326f4352aba44bc65b63174c05efc68d83..f6d330e1ab572924236306080ede8534639f498f 100644 (file)
@@ -37,10 +37,10 @@ load_cache
        client sends cache contents (like from dump_cache), which is stored 
        in the cache. end of data indicated with a line with 'EOF' on it.
        The data is sent after the query line.
-flush_name <name>
+flush <name>
        flushes some information regarding the name from the cache.
-       removes the A, AAAA, NS, SOA, CNAME, DNAME, MX, PTR types.
-       Does not remote other types.
+       removes the A, AAAA, NS, SOA, CNAME, DNAME, MX, PTR, SRV, NAPTR types.
+       Does not remove other types.
 flush_type <name> <RR type>
        removes rrtype entry from the cache.
 flush_zone <name>
index bde157128d0e2fccb663cc241210da7d9dfda54f..2a7f3b18051408207e50fa614a9d1a122323a017 100644 (file)
--- a/doc/plan
+++ b/doc/plan
@@ -56,7 +56,7 @@ not   stats on SIGUSR1. perhaps also see which slow auth servers cause >1sec value
 + remote control to add/remove localinfo, redirects.
 + remote control to load/store cache contents
 + remote control to start, stop, reload.
-* remote control to flush names or domains (all under a name) from the 
++ remote control to flush names or domains (all under a name) from the 
    cache. Include NSes. And the A, AAAA for its NSes.
 + remote control to see delegation; what servers would be used to get 
   data for a name.
index aa92b2792edf03e3840e6472fa007b9493a70d40..ffe017b31b4a4e82b9aa839420f24f2cb3ed3b21 100644 (file)
@@ -95,6 +95,22 @@ in old or wrong data returned to clients.
 .B lookup \fIname
 Print to stdout the name servers that would be used to look up the 
 name specified.
+.TP
+.B flush \fIname
+Remove the name from the cache. Removes the types
+A, AAAA, NS, SOA, CNAME, DNAME, MX, PTR, SRV and NAPTR.
+Because that is fast to do. Other record types can be removed using 
+.B flush_type 
+or 
+.B flush_zone\fR.
+.TP
+.B flush_type \fIname\fR \fItype
+Remove the name, type information from the cache.
+.TP
+.B flush_zone \fIname
+Remove all information at or below the name from the cache. 
+The rrsets and key entries are removed so that new lookups will be performed.
+This needs to walk and inspect the entire cache, and is a slow operation.
 .SH "EXIT CODE"
 The unbound-control program exits with status code 1 on error, 0 on success.
 .SH "SET UP"
index e9270551abd2207dc2eb76f891074775eb260b41..c9856c96c4638a948a68001696fbdfe681bd1bd0 100644 (file)
@@ -371,3 +371,17 @@ rrset_check_sec_status(struct rrset_cache* r,
        }
        lock_rw_unlock(&e->lock);
 }
+
+void rrset_cache_remove(struct rrset_cache* r, uint8_t* nm, size_t nmlen,
+       uint16_t type, uint16_t dclass, uint32_t flags)
+{
+       struct ub_packed_rrset_key key;
+       key.entry.key = &key;
+       key.rk.dname = nm;
+       key.rk.dname_len = nmlen;
+       key.rk.rrset_class = htons(dclass);
+       key.rk.type = htons(type);
+       key.rk.flags = flags;
+       key.entry.hash = rrset_key_hash(&key.rk);
+       slabhash_remove(&r->table, key.entry.hash, &key);
+}
index 02241d4bddbd00483253c23921c93a4ad8444bfe..e414107d258a65ed67eba5a0ff60afe3475f04d9 100644 (file)
@@ -209,6 +209,18 @@ void rrset_update_sec_status(struct rrset_cache* r,
 void rrset_check_sec_status(struct rrset_cache* r, 
        struct ub_packed_rrset_key* rrset, uint32_t now);
 
+/**
+ * Remove an rrset from the cache, by name and type and flags
+ * @param r: rrset cache
+ * @param nm: name of rrset
+ * @param nmlen: length of name
+ * @param type: type of rrset
+ * @param dclass: class of rrset, host order
+ * @param flags: flags of rrset, host order
+ */
+void rrset_cache_remove(struct rrset_cache* r, uint8_t* nm, size_t nmlen,
+       uint16_t type, uint16_t dclass, uint32_t flags);
+
 /** mark rrset to be deleted, set id=0 */
 void rrset_markdel(void* key);
 
index a513db0c65d16d911ce0766a7e54e337c6f11366..050a6d5b5e11f525b1a6e9be61ffee0d51add648 100644 (file)
@@ -71,6 +71,12 @@ usage()
        printf("  dump_cache                    print cache to stdout\n");
        printf("  load_cache                    load cache from stdin\n");
        printf("  lookup [name]                 print nameservers for name\n");
+       printf("  flush [name]                  flushes common types for name from cache\n");
+       printf("                                types:  A, AAAA, MX, PTR, NS,\n");
+       printf("                                        SOA, CNAME, DNAME, SRV, NAPTR\n");
+       printf("  flush_type [name] [type]      flush name, type from cache\n");
+       printf("  flush_zone [name]             flush everything at or under name\n");
+       printf("                                from rr and dnssec caches\n");
        printf("Version %s\n", PACKAGE_VERSION);
        printf("BSD licensed, see LICENSE in source package for details.\n");
        printf("Report bugs to %s\n", PACKAGE_BUGREPORT);