From cc8cefe12deb929ef511c3ab7de65a6439e848a4 Mon Sep 17 00:00:00 2001 From: Remi Gacogne Date: Tue, 29 Mar 2016 11:58:36 +0200 Subject: [PATCH] dnsdist: Count "TTL too short" events, default min TTL to 0 This means that we'll cache response regardless of their TTL value by default. --- pdns/README-dnsdist.md | 4 +- pdns/dnsdist-cache.cc | 5 +- pdns/dnsdist-cache.hh | 4 +- pdns/dnsdist-carbon.cc | 1 + pdns/dnsdist-lua2.cc | 3 +- regression-tests.dnsdist/test_Caching.py | 118 +++++++++++++++++++++++ 6 files changed, 129 insertions(+), 6 deletions(-) diff --git a/pdns/README-dnsdist.md b/pdns/README-dnsdist.md index c797d5350..83e823460 100644 --- a/pdns/README-dnsdist.md +++ b/pdns/README-dnsdist.md @@ -713,7 +713,7 @@ 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, 600, 60, 60) +pc = newPacketCache(10000, 86400, 0, 60, 60) getPool(""):setCache(pc) ``` @@ -1091,7 +1091,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=60, servFailTTL=60, stateTTL=60])`: return a new PacketCache + * `newPacketCache(maxEntries[, maxTTL=86400, minTTL=0, servFailTTL=60, stateTTL=60])`: 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 9e164b338..3c8b1d2eb 100644 --- a/pdns/dnsdist-cache.cc +++ b/pdns/dnsdist-cache.cc @@ -38,8 +38,10 @@ void DNSDistPacketCache::insert(uint32_t key, const DNSName& qname, uint16_t qty if (minTTL > d_maxTTL) minTTL = d_maxTTL; - if (minTTL < d_minTTL) + if (minTTL < d_minTTL) { + d_ttlTooShorts++; return; + } } { @@ -139,7 +141,6 @@ bool DNSDistPacketCache::get(const DNSQuestion& dq, uint16_t consumed, uint16_t /* check for collision */ if (!cachedValueMatches(value, *dq.qname, dq.qtype, dq.qclass, dq.tcp)) { - d_misses++; d_lookupCollisions++; return false; } diff --git a/pdns/dnsdist-cache.hh b/pdns/dnsdist-cache.hh index a154ab86a..dbc59e61b 100644 --- a/pdns/dnsdist-cache.hh +++ b/pdns/dnsdist-cache.hh @@ -9,7 +9,7 @@ struct DNSQuestion; class DNSDistPacketCache : boost::noncopyable { public: - DNSDistPacketCache(size_t maxEntries, uint32_t maxTTL=86400, uint32_t minTTL=60, uint32_t servFailTTL=60, uint32_t staleTTL=60); + DNSDistPacketCache(size_t maxEntries, uint32_t maxTTL=86400, uint32_t minTTL=0, uint32_t servFailTTL=60, uint32_t staleTTL=60); ~DNSDistPacketCache(); void insert(uint32_t key, const DNSName& qname, uint16_t qtype, uint16_t qclass, const char* response, uint16_t responseLen, bool tcp, bool servFail=false); @@ -27,6 +27,7 @@ public: uint64_t getLookupCollisions() const { return d_lookupCollisions; } uint64_t getInsertCollisions() const { return d_insertCollisions; } uint64_t getMaxEntries() const { return d_maxEntries; } + uint64_t getTTLTooShorts() const { return d_ttlTooShorts; } uint64_t getEntriesCount(); static uint32_t getMinTTL(const char* packet, uint16_t length); @@ -57,6 +58,7 @@ private: std::atomic d_misses{0}; std::atomic d_insertCollisions{0}; std::atomic d_lookupCollisions{0}; + std::atomic d_ttlTooShorts{0}; size_t d_maxEntries; uint32_t d_maxTTL; uint32_t d_servFailTTL; diff --git a/pdns/dnsdist-carbon.cc b/pdns/dnsdist-carbon.cc index 29f00d069..bd3c042b4 100644 --- a/pdns/dnsdist-carbon.cc +++ b/pdns/dnsdist-carbon.cc @@ -101,6 +101,7 @@ try str<getDeferredLookups() << " " << now << "\r\n"; str<getLookupCollisions() << " " << now << "\r\n"; str<getInsertCollisions() << " " << now << "\r\n"; + str<getTTLTooShorts() << " " << now << "\r\n"; } } const string msg = str.str(); diff --git a/pdns/dnsdist-lua2.cc b/pdns/dnsdist-lua2.cc index e5a1d21bf..3718223cc 100644 --- a/pdns/dnsdist-lua2.cc +++ b/pdns/dnsdist-lua2.cc @@ -539,7 +539,7 @@ void moreLua(bool client) }); g_lua.writeFunction("newPacketCache", [client](size_t maxEntries, boost::optional maxTTL, boost::optional minTTL, boost::optional servFailTTL, boost::optional staleTTL) { - return std::make_shared(maxEntries, maxTTL ? *maxTTL : 86400, minTTL ? *minTTL : 60, servFailTTL ? *servFailTTL : 60, staleTTL ? *staleTTL : 60); + return std::make_shared(maxEntries, maxTTL ? *maxTTL : 86400, minTTL ? *minTTL : 0, servFailTTL ? *servFailTTL : 60, staleTTL ? *staleTTL : 60); }); g_lua.registerFunction("toString", &DNSDistPacketCache::toString); g_lua.registerFunction("isFull", &DNSDistPacketCache::isFull); @@ -559,6 +559,7 @@ void moreLua(bool client) g_outputBuffer+="Deferred lookups: " + std::to_string(cache->getDeferredLookups()) + "\n"; g_outputBuffer+="Lookup Collisions: " + std::to_string(cache->getLookupCollisions()) + "\n"; g_outputBuffer+="Insert Collisions: " + std::to_string(cache->getInsertCollisions()) + "\n"; + g_outputBuffer+="TTL Too Shorts: " + std::to_string(cache->getTTLTooShorts()) + "\n"; } }); diff --git a/regression-tests.dnsdist/test_Caching.py b/regression-tests.dnsdist/test_Caching.py index be6d9ed99..a016b6cc3 100644 --- a/regression-tests.dnsdist/test_Caching.py +++ b/regression-tests.dnsdist/test_Caching.py @@ -818,3 +818,121 @@ class TestCacheManagement(DNSDistTest): for key in self._responsesCounter: total += self._responsesCounter[key] self.assertEquals(total, misses) + +class TestCachingTTL(DNSDistTest): + + _maxCacheTTL = 86400 + _minCacheTTL = 600 + _config_params = ['_maxCacheTTL', '_minCacheTTL', '_testServerPort'] + _config_template = """ + pc = newPacketCache(1000, %s, %s) + getPool(""):setCache(pc) + newServer{address="127.0.0.1:%s"} + """ + def testCacheShortTTL(self): + """ + Cache: Entries with a TTL shorter than minTTL + + """ + misses = 0 + ttl = 60 + name = 'ttltooshort.cache.tests.powerdns.com.' + query = dns.message.make_query(name, 'A', 'IN') + response = dns.message.make_response(query) + rrset = dns.rrset.from_text(name, + ttl, + dns.rdataclass.IN, + dns.rdatatype.A, + '127.0.0.1') + response.answer.append(rrset) + + # Miss + (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response) + self.assertTrue(receivedQuery) + self.assertTrue(receivedResponse) + receivedQuery.id = query.id + self.assertEquals(query, receivedQuery) + self.assertEquals(response, receivedResponse) + for an in receivedResponse.answer: + self.assertEquals(an.ttl, ttl) + misses += 1 + + # We should not have been cached + (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response) + self.assertTrue(receivedQuery) + self.assertTrue(receivedResponse) + receivedQuery.id = query.id + self.assertEquals(query, receivedQuery) + self.assertEquals(response, receivedResponse) + for an in receivedResponse.answer: + self.assertEquals(an.ttl, ttl) + misses += 1 + + total = 0 + for key in self._responsesCounter: + total += self._responsesCounter[key] + + self.assertEquals(total, misses) + +class TestCachingLongTTL(DNSDistTest): + + _maxCacheTTL = 2 + _config_params = ['_maxCacheTTL', '_testServerPort'] + _config_template = """ + pc = newPacketCache(1000, %s) + getPool(""):setCache(pc) + newServer{address="127.0.0.1:%s"} + """ + def testCacheLongTTL(self): + """ + Cache: Entries with a longer TTL than the maximum + + """ + misses = 0 + ttl = 172800 + name = 'longttl.cache.tests.powerdns.com.' + query = dns.message.make_query(name, 'A', 'IN') + response = dns.message.make_response(query) + rrset = dns.rrset.from_text(name, + ttl, + dns.rdataclass.IN, + dns.rdatatype.A, + '127.0.0.1') + response.answer.append(rrset) + + # Miss + (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response) + self.assertTrue(receivedQuery) + self.assertTrue(receivedResponse) + receivedQuery.id = query.id + self.assertEquals(query, receivedQuery) + self.assertEquals(response, receivedResponse) + for an in receivedResponse.answer: + self.assertEquals(an.ttl, ttl) + 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) + + time.sleep(self._maxCacheTTL + 1) + + # we should not have cached for longer than max cache + # so it should be a miss + (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response) + self.assertTrue(receivedQuery) + self.assertTrue(receivedResponse) + receivedQuery.id = query.id + self.assertEquals(query, receivedQuery) + self.assertEquals(response, receivedResponse) + for an in receivedResponse.answer: + self.assertEquals(an.ttl, ttl) + misses += 1 + + total = 0 + for key in self._responsesCounter: + total += self._responsesCounter[key] + + self.assertEquals(total, misses) -- 2.49.0