From: Remi Gacogne Date: Sun, 12 Mar 2017 16:04:30 +0000 (+0100) Subject: dnsdist: Add an option so the packet cache entries don't age X-Git-Tag: rec-4.1.0-alpha1~178^2 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=refs%2Fpull%2F5136%2Fhead;p=thirdparty%2Fpdns.git dnsdist: Add an option so the packet cache entries don't age --- diff --git a/pdns/README-dnsdist.md b/pdns/README-dnsdist.md index feb433f868..e5f179e081 100644 --- a/pdns/README-dnsdist.md +++ b/pdns/README-dnsdist.md @@ -870,16 +870,18 @@ The first step is to define a cache, then to assign that cache to the chosen poo the default one being represented by the empty string: ``` -pc = newPacketCache(10000, 86400, 0, 60, 60) +pc = newPacketCache(10000, 86400, 0, 60, 60, false) getPool(""):setCache(pc) ``` The first parameter (10000) is the maximum number of entries stored in the cache, and is the -only one required. All the other parameter are optional and in seconds. +only one required. The second, third, fourth and fifth parameters are optional and in seconds. The second one (86400) is the maximum lifetime of an entry in the cache, the third one (0) is the minimum TTL an entry should have to be considered for insertion in the cache, -the fourth one (60) is the TTL used for a Server Failure or a Refused response. The last -one (60) is the TTL that will be used when a stale cache entry is returned. +the fourth one (60) is the TTL used for a Server Failure or a Refused response. The fifth +one (60) is the TTL that will be used when a stale cache entry is returned. The last one +is a boolean that indicates whether the TTL of reponses should be reduced by the number of +seconds the response has been in the cache. For performance reasons the cache will pre-allocate buckets based on the maximum number of entries, so be careful to set the first parameter to a reasonable value. Something along the lines of a dozen bytes per pre-allocated entry can be expected on 64-bit. @@ -1537,7 +1539,7 @@ instantiate a server with additional parameters * `expunge(n)`: remove entries from the cache, leaving at most `n` entries * `expungeByName(DNSName [, qtype=ANY])`: remove entries matching the supplied DNSName and type from the cache * `isFull()`: return true if the cache has reached the maximum number of entries - * `newPacketCache(maxEntries[, maxTTL=86400, minTTL=0, temporaryFailureTTL=60, staleTTL=60])`: return a new PacketCache + * `newPacketCache(maxEntries[, maxTTL=86400, minTTL=0, temporaryFailureTTL=60, staleTTL=60, dontAge=false])`: return a new PacketCache * `printStats()`: print the cache stats (hits, misses, deferred lookups and deferred inserts) * `purgeExpired(n)`: remove expired entries from the cache until there is at most `n` entries remaining in the cache * `toString()`: return the number of entries in the Packet Cache, and the maximum number of entries diff --git a/pdns/dnsdist-cache.cc b/pdns/dnsdist-cache.cc index 9b5b48ce20..a6181f0504 100644 --- a/pdns/dnsdist-cache.cc +++ b/pdns/dnsdist-cache.cc @@ -24,7 +24,7 @@ #include "dnsparser.hh" #include "dnsdist-cache.hh" -DNSDistPacketCache::DNSDistPacketCache(size_t maxEntries, uint32_t maxTTL, uint32_t minTTL, uint32_t tempFailureTTL, uint32_t staleTTL): d_maxEntries(maxEntries), d_maxTTL(maxTTL), d_tempFailureTTL(tempFailureTTL), d_minTTL(minTTL), d_staleTTL(staleTTL) +DNSDistPacketCache::DNSDistPacketCache(size_t maxEntries, uint32_t maxTTL, uint32_t minTTL, uint32_t tempFailureTTL, uint32_t staleTTL, bool dontAge): d_maxEntries(maxEntries), d_maxTTL(maxTTL), d_tempFailureTTL(tempFailureTTL), d_minTTL(minTTL), d_staleTTL(staleTTL), d_dontAge(dontAge) { pthread_rwlock_init(&d_lock, 0); /* we reserve maxEntries + 1 to avoid rehashing from occurring @@ -209,7 +209,7 @@ bool DNSDistPacketCache::get(const DNSQuestion& dq, uint16_t consumed, uint16_t } } - if (!skipAging) { + if (!d_dontAge && !skipAging) { ageDNSPacket(response, *responseLen, age); } diff --git a/pdns/dnsdist-cache.hh b/pdns/dnsdist-cache.hh index 10164c7c64..aacd8614e2 100644 --- a/pdns/dnsdist-cache.hh +++ b/pdns/dnsdist-cache.hh @@ -30,7 +30,7 @@ struct DNSQuestion; class DNSDistPacketCache : boost::noncopyable { public: - DNSDistPacketCache(size_t maxEntries, uint32_t maxTTL=86400, uint32_t minTTL=0, uint32_t tempFailureTTL=60, uint32_t staleTTL=60); + DNSDistPacketCache(size_t maxEntries, uint32_t maxTTL=86400, uint32_t minTTL=0, uint32_t tempFailureTTL=60, uint32_t staleTTL=60, bool dontAge=false); ~DNSDistPacketCache(); void insert(uint32_t key, const DNSName& qname, uint16_t qtype, uint16_t qclass, const char* response, uint16_t responseLen, bool tcp, uint8_t rcode); @@ -85,4 +85,5 @@ private: uint32_t d_tempFailureTTL; uint32_t d_minTTL; uint32_t d_staleTTL; + bool d_dontAge; }; diff --git a/pdns/dnsdist-console.cc b/pdns/dnsdist-console.cc index e73b9541c6..1feff43212 100644 --- a/pdns/dnsdist-console.cc +++ b/pdns/dnsdist-console.cc @@ -329,6 +329,7 @@ const std::vector g_consoleKeywords{ { "mvResponseRule", true, "from, to", "move response rule 'from' to a position where it is in front of 'to'. 'to' can be one larger than the largest rule" }, { "mvRule", true, "from, to", "move rule 'from' to a position where it is in front of 'to'. 'to' can be one larger than the largest rule, in which case the rule will be moved to the last position" }, { "newDNSName", true, "name", "make a DNSName based on this .-terminated name" }, + { "newPacketCache", true, "maxEntries[, maxTTL=86400, minTTL=0, temporaryFailureTTL=60, staleTTL=60, dontAge=false]", "return a new Packet Cache" }, { "newQPSLimiter", true, "rate, burst", "configure a QPS limiter with that rate and that burst capacity" }, { "newRemoteLogger", true, "address:port [, timeout=2, maxQueuedEntries=100, reconnectWaitTime=1]", "create a Remote Logger object, to use with `RemoteLogAction()` and `RemoteLogResponseAction()`" }, { "newRuleAction", true, "DNS rule, DNS action", "return a pair of DNS Rule and DNS Action, to be used with `setRules()`" }, diff --git a/pdns/dnsdist-lua2.cc b/pdns/dnsdist-lua2.cc index abf3deec55..6fccad4363 100644 --- a/pdns/dnsdist-lua2.cc +++ b/pdns/dnsdist-lua2.cc @@ -687,8 +687,8 @@ void moreLua(bool client) } }); - g_lua.writeFunction("newPacketCache", [client](size_t maxEntries, boost::optional maxTTL, boost::optional minTTL, boost::optional tempFailTTL, boost::optional staleTTL) { - return std::make_shared(maxEntries, maxTTL ? *maxTTL : 86400, minTTL ? *minTTL : 0, tempFailTTL ? *tempFailTTL : 60, staleTTL ? *staleTTL : 60); + g_lua.writeFunction("newPacketCache", [client](size_t maxEntries, boost::optional maxTTL, boost::optional minTTL, boost::optional tempFailTTL, boost::optional staleTTL, boost::optional dontAge) { + return std::make_shared(maxEntries, maxTTL ? *maxTTL : 86400, minTTL ? *minTTL : 0, tempFailTTL ? *tempFailTTL : 60, staleTTL ? *staleTTL : 60, dontAge ? *dontAge : false); }); g_lua.registerFunction("toString", &DNSDistPacketCache::toString); g_lua.registerFunction("isFull", &DNSDistPacketCache::isFull); diff --git a/regression-tests.dnsdist/test_Caching.py b/regression-tests.dnsdist/test_Caching.py index 832ca80af2..537c065da5 100644 --- a/regression-tests.dnsdist/test_Caching.py +++ b/regression-tests.dnsdist/test_Caching.py @@ -1107,3 +1107,60 @@ class TestCachingFailureTTL(DNSDistTest): total += self._responsesCounter[key] self.assertEquals(total, misses) + +class TestCachingDontAge(DNSDistTest): + + _config_template = """ + pc = newPacketCache(100, 86400, 0, 60, 60, true) + getPool(""):setCache(pc) + newServer{address="127.0.0.1:%s"} + """ + def testCacheDoesntDecreaseTTL(self): + """ + Cache: Cache doesn't decrease TTL with 'don't age' set + + dnsdist is configured to cache entries but without aging the TTL, + we are sending one request (cache miss) and verify that the cache + hits don't have a decreasing TTL. + """ + ttl = 600 + misses = 0 + name = 'cachedoesntdecreasettl.cache-dont-age.tests.powerdns.com.' + query = dns.message.make_query(name, 'AAAA', 'IN') + response = dns.message.make_response(query) + rrset = dns.rrset.from_text(name, + ttl, + dns.rdataclass.IN, + dns.rdatatype.AAAA, + '::1') + response.answer.append(rrset) + + # first query to fill the cache + (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response) + self.assertTrue(receivedQuery) + self.assertTrue(receivedResponse) + receivedQuery.id = query.id + self.assertEquals(query, receivedQuery) + self.assertEquals(receivedResponse, response) + misses += 1 + + # next queries should hit the cache + (_, receivedResponse) = self.sendUDPQuery(query, response=None, useQueue=False) + self.assertEquals(receivedResponse, response) + for an in receivedResponse.answer: + self.assertTrue(an.ttl == ttl) + + # now we wait a bit for the TTL to decrease + time.sleep(1) + + # next queries should hit the cache + (_, receivedResponse) = self.sendUDPQuery(query, response=None, useQueue=False) + self.assertEquals(receivedResponse, response) + for an in receivedResponse.answer: + self.assertTrue(an.ttl == ttl) + + total = 0 + for key in self._responsesCounter: + total += self._responsesCounter[key] + + self.assertEquals(total, misses)