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.
* `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
#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
}
}
- if (!skipAging) {
+ if (!d_dontAge && !skipAging) {
ageDNSPacket(response, *responseLen, age);
}
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);
uint32_t d_tempFailureTTL;
uint32_t d_minTTL;
uint32_t d_staleTTL;
+ bool d_dontAge;
};
{ "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()`" },
}
});
- g_lua.writeFunction("newPacketCache", [client](size_t maxEntries, boost::optional<uint32_t> maxTTL, boost::optional<uint32_t> minTTL, boost::optional<uint32_t> tempFailTTL, boost::optional<uint32_t> staleTTL) {
- return std::make_shared<DNSDistPacketCache>(maxEntries, maxTTL ? *maxTTL : 86400, minTTL ? *minTTL : 0, tempFailTTL ? *tempFailTTL : 60, staleTTL ? *staleTTL : 60);
+ g_lua.writeFunction("newPacketCache", [client](size_t maxEntries, boost::optional<uint32_t> maxTTL, boost::optional<uint32_t> minTTL, boost::optional<uint32_t> tempFailTTL, boost::optional<uint32_t> staleTTL, boost::optional<bool> dontAge) {
+ return std::make_shared<DNSDistPacketCache>(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);
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)