From: Remi Gacogne Date: Fri, 4 Apr 2025 10:08:45 +0000 (+0200) Subject: dnsdist: Refactor the packet cache settings X-Git-Tag: dnsdist-2.0.0-alpha2~86^2~1 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=f92f2466bb8655092dc56abc22f4b842286ff609;p=thirdparty%2Fpdns.git dnsdist: Refactor the packet cache settings --- diff --git a/pdns/dnsdistdist/dnsdist-cache.cc b/pdns/dnsdistdist/dnsdist-cache.cc index 020825306b..79d8d118fe 100644 --- a/pdns/dnsdistdist/dnsdist-cache.cc +++ b/pdns/dnsdistdist/dnsdist-cache.cc @@ -31,19 +31,23 @@ #include "base64.hh" // NOLINTNEXTLINE(bugprone-easily-swappable-parameters): too cumbersome to change at this point -DNSDistPacketCache::DNSDistPacketCache(size_t maxEntries, uint32_t maxTTL, uint32_t minTTL, uint32_t tempFailureTTL, uint32_t maxNegativeTTL, uint32_t staleTTL, bool dontAge, uint32_t shards, bool deferrableInsertLock, bool parseECS) : - d_maxEntries(maxEntries), d_shardCount(shards), d_maxTTL(maxTTL), d_tempFailureTTL(tempFailureTTL), d_maxNegativeTTL(maxNegativeTTL), d_minTTL(minTTL), d_staleTTL(staleTTL), d_dontAge(dontAge), d_deferrableInsertLock(deferrableInsertLock), d_parseECS(parseECS) +DNSDistPacketCache::DNSDistPacketCache(const CacheSettings& settings) : + d_settings(settings) { - if (d_maxEntries == 0) { + if (d_settings.d_maxEntries == 0) { throw std::runtime_error("Trying to create a 0-sized packet-cache"); } - d_shards.resize(d_shardCount); + if (d_settings.d_shardCount == 0) { + d_settings.d_shardCount = 1; + } + + d_shards.resize(d_settings.d_shardCount); /* we reserve maxEntries + 1 to avoid rehashing from occurring when we get to maxEntries, as it means a load factor of 1 */ for (auto& shard : d_shards) { - shard.setSize((maxEntries / d_shardCount) + 1); + shard.setSize((d_settings.d_maxEntries / d_settings.d_shardCount) + 1); } } @@ -81,7 +85,7 @@ bool DNSDistPacketCache::cachedValueMatches(const CacheValue& cachedValue, uint1 return false; } - if (d_parseECS && cachedValue.subnet != subnet) { + if (d_settings.d_parseECS && cachedValue.subnet != subnet) { return false; } @@ -91,7 +95,7 @@ bool DNSDistPacketCache::cachedValueMatches(const CacheValue& cachedValue, uint1 void DNSDistPacketCache::insertLocked(CacheShard& shard, std::unordered_map& map, uint32_t key, CacheValue& newValue) { /* check again now that we hold the lock to prevent a race */ - if (map.size() >= (d_maxEntries / d_shardCount)) { + if (map.size() >= (d_settings.d_maxEntries / d_settings.d_shardCount)) { return; } @@ -135,7 +139,7 @@ void DNSDistPacketCache::insert(uint32_t key, const boost::optional& su uint32_t minTTL{0}; if (rcode == RCode::ServFail || rcode == RCode::Refused) { - minTTL = tempFailureTTL == boost::none ? d_tempFailureTTL : *tempFailureTTL; + minTTL = tempFailureTTL == boost::none ? d_settings.d_tempFailureTTL : *tempFailureTTL; if (minTTL == 0) { return; } @@ -151,13 +155,13 @@ void DNSDistPacketCache::insert(uint32_t key, const boost::optional& su } if (rcode == RCode::NXDomain || (rcode == RCode::NoError && seenAuthSOA)) { - minTTL = std::min(minTTL, d_maxNegativeTTL); + minTTL = std::min(minTTL, d_settings.d_maxNegativeTTL); } - else if (minTTL > d_maxTTL) { - minTTL = d_maxTTL; + else if (minTTL > d_settings.d_maxTTL) { + minTTL = d_settings.d_maxTTL; } - if (minTTL < d_minTTL) { + if (minTTL < d_settings.d_minTTL) { ++d_ttlTooShorts; return; } @@ -165,7 +169,7 @@ void DNSDistPacketCache::insert(uint32_t key, const boost::optional& su uint32_t shardIndex = getShardIndex(key); - if (d_shards.at(shardIndex).d_entriesCount >= (d_maxEntries / d_shardCount)) { + if (d_shards.at(shardIndex).d_entriesCount >= (d_settings.d_maxEntries / d_settings.d_shardCount)) { return; } @@ -186,7 +190,7 @@ void DNSDistPacketCache::insert(uint32_t key, const boost::optional& su auto& shard = d_shards.at(shardIndex); - if (d_deferrableInsertLock) { + if (d_settings.d_deferrableInsertLock) { auto lock = shard.d_map.try_write_lock(); if (!lock.owns_lock()) { @@ -216,7 +220,7 @@ bool DNSDistPacketCache::get(DNSQuestion& dnsQuestion, uint16_t queryId, uint32_ *keyOut = key; } - if (d_parseECS) { + if (d_settings.d_parseECS) { getClientSubnet(dnsQuestion.getData(), dnsQuestion.ids.qname.wirelength(), subnet); } @@ -294,11 +298,11 @@ bool DNSDistPacketCache::get(DNSQuestion& dnsQuestion, uint16_t queryId, uint32_ age = now - value.added; } else { - age = (value.validity - value.added) - d_staleTTL; + age = (value.validity - value.added) - d_settings.d_staleTTL; } } - if (!d_dontAge && !skipAging) { + if (!d_settings.d_dontAge && !skipAging) { if (!stale) { // coverity[store_truncates_time_t] dnsheader_aligned dh_aligned(response.data()); @@ -308,7 +312,7 @@ bool DNSDistPacketCache::get(DNSQuestion& dnsQuestion, uint16_t queryId, uint32_ else { // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) editDNSPacketTTL(reinterpret_cast(response.data()), response.size(), - [staleTTL = d_staleTTL](uint8_t /* section */, uint16_t /* class_ */, uint16_t /* type */, uint32_t /* ttl */) { return staleTTL; }); + [staleTTL = d_settings.d_staleTTL](uint8_t /* section */, uint16_t /* class_ */, uint16_t /* type */, uint32_t /* ttl */) { return staleTTL; }); } } @@ -323,7 +327,7 @@ bool DNSDistPacketCache::get(DNSQuestion& dnsQuestion, uint16_t queryId, uint32_ */ size_t DNSDistPacketCache::purgeExpired(size_t upTo, const time_t now) { - const size_t maxPerShard = upTo / d_shardCount; + const size_t maxPerShard = upTo / d_settings.d_shardCount; size_t removed = 0; @@ -361,7 +365,7 @@ size_t DNSDistPacketCache::purgeExpired(size_t upTo, const time_t now) */ size_t DNSDistPacketCache::expunge(size_t upTo) { - const size_t maxPerShard = upTo / d_shardCount; + const size_t maxPerShard = upTo / d_settings.d_shardCount; size_t removed = 0; @@ -419,7 +423,7 @@ size_t DNSDistPacketCache::expungeByName(const DNSName& name, uint16_t qtype, bo bool DNSDistPacketCache::isFull() { - return (getSize() >= d_maxEntries); + return (getSize() >= d_settings.d_maxEntries); } uint64_t DNSDistPacketCache::getSize() @@ -453,10 +457,10 @@ uint32_t DNSDistPacketCache::getKey(const DNSName::string_t& qname, size_t qname throw std::range_error("Computing packet cache key for an invalid packet (" + std::to_string(packet.size()) + " < " + std::to_string(sizeof(dnsheader) + qnameWireLength) + ")"); } if (packet.size() > ((sizeof(dnsheader) + qnameWireLength))) { - if (!d_optionsToSkip.empty()) { + if (!d_settings.d_optionsToSkip.empty()) { /* skip EDNS options if any */ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) - result = PacketCache::hashAfterQname(std::string_view(reinterpret_cast(packet.data()), packet.size()), result, sizeof(dnsheader) + qnameWireLength, d_optionsToSkip); + result = PacketCache::hashAfterQname(std::string_view(reinterpret_cast(packet.data()), packet.size()), result, sizeof(dnsheader) + qnameWireLength, d_settings.d_optionsToSkip); } else { result = burtle(&packet.at(sizeof(dnsheader) + qnameWireLength), packet.size() - (sizeof(dnsheader) + qnameWireLength), result); @@ -469,12 +473,12 @@ uint32_t DNSDistPacketCache::getKey(const DNSName::string_t& qname, size_t qname uint32_t DNSDistPacketCache::getShardIndex(uint32_t key) const { - return key % d_shardCount; + return key % d_settings.d_shardCount; } string DNSDistPacketCache::toString() { - return std::to_string(getSize()) + "/" + std::to_string(d_maxEntries); + return std::to_string(getSize()) + "/" + std::to_string(d_settings.d_maxEntries); } uint64_t DNSDistPacketCache::getEntriesCount() @@ -529,11 +533,6 @@ uint64_t DNSDistPacketCache::dump(int fileDesc, bool rawResponse) return count; } -void DNSDistPacketCache::setSkippedOptions(const std::unordered_set& optionsToSkip) -{ - d_optionsToSkip = optionsToSkip; -} - std::set DNSDistPacketCache::getDomainsContainingRecords(const ComboAddress& addr) { std::set domains; @@ -642,8 +641,3 @@ std::set DNSDistPacketCache::getRecordsForDomain(const DNSName& do return addresses; } - -void DNSDistPacketCache::setMaximumEntrySize(size_t maxSize) -{ - d_maximumEntrySize = maxSize; -} diff --git a/pdns/dnsdistdist/dnsdist-cache.hh b/pdns/dnsdistdist/dnsdist-cache.hh index a3ef35023e..c6e249508a 100644 --- a/pdns/dnsdistdist/dnsdist-cache.hh +++ b/pdns/dnsdistdist/dnsdist-cache.hh @@ -35,7 +35,24 @@ 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 maxNegativeTTL = 3600, uint32_t staleTTL = 60, bool dontAge = false, uint32_t shards = 1, bool deferrableInsertLock = true, bool parseECS = false); + struct CacheSettings + { + std::unordered_set d_optionsToSkip{EDNSOptionCode::COOKIE}; + size_t d_maxEntries{0}; + size_t d_maximumEntrySize{4096}; + uint32_t d_maxTTL{86400}; + uint32_t d_minTTL{0}; + uint32_t d_tempFailureTTL{60}; + uint32_t d_maxNegativeTTL{3600}; + uint32_t d_staleTTL{60}; + uint32_t d_shardCount{1}; + bool d_dontAge{false}; + bool d_deferrableInsertLock{true}; + bool d_parseECS{false}; + bool d_keepStaleData{false}; + }; + + DNSDistPacketCache(const CacheSettings& settings); void insert(uint32_t key, const boost::optional& subnet, uint16_t queryFlags, bool dnssecOK, const DNSName& qname, uint16_t qtype, uint16_t qclass, const PacketBuffer& response, bool receivedOverUDP, uint8_t rcode, boost::optional tempFailureTTL); bool get(DNSQuestion& dnsQuestion, uint16_t queryId, uint32_t* keyOut, boost::optional& subnet, bool dnssecOK, bool receivedOverUDP, uint32_t allowExpired = 0, bool skipAging = false, bool truncatedOK = true, bool recordMiss = true); @@ -51,7 +68,7 @@ public: uint64_t getDeferredInserts() const { return d_deferredInserts.load(); } uint64_t getLookupCollisions() const { return d_lookupCollisions.load(); } uint64_t getInsertCollisions() const { return d_insertCollisions.load(); } - uint64_t getMaxEntries() const { return d_maxEntries; } + uint64_t getMaxEntries() const { return d_settings.d_maxEntries; } uint64_t getTTLTooShorts() const { return d_ttlTooShorts.load(); } uint64_t getCleanupCount() const { return d_cleanupCount.load(); } uint64_t getEntriesCount(); @@ -62,26 +79,14 @@ public: /* get the list of IP addresses contained in A or AAAA for a given domains (qname) */ std::set getRecordsForDomain(const DNSName& domain); - void setSkippedOptions(const std::unordered_set& optionsToSkip); - - bool isECSParsingEnabled() const { return d_parseECS; } + bool isECSParsingEnabled() const { return d_settings.d_parseECS; } bool keepStaleData() const { - return d_keepStaleData; - } - void setKeepStaleData(bool keep) - { - d_keepStaleData = keep; - } - - void setECSParsingEnabled(bool enabled) - { - d_parseECS = enabled; + return d_settings.d_keepStaleData; } - void setMaximumEntrySize(size_t maxSize); - size_t getMaximumEntrySize() const { return d_maximumEntrySize; } + size_t getMaximumEntrySize() const { return d_settings.d_maximumEntrySize; } uint32_t getKey(const DNSName::string_t& qname, size_t qnameWireLength, const PacketBuffer& packet, bool receivedOverUDP); @@ -129,7 +134,6 @@ private: void insertLocked(CacheShard& shard, std::unordered_map& map, uint32_t key, CacheValue& newValue); std::vector d_shards; - std::unordered_set d_optionsToSkip{EDNSOptionCode::COOKIE}; pdns::stat_t d_deferredLookups{0}; pdns::stat_t d_deferredInserts{0}; @@ -140,16 +144,5 @@ private: pdns::stat_t d_ttlTooShorts{0}; pdns::stat_t d_cleanupCount{0}; - const size_t d_maxEntries; - size_t d_maximumEntrySize{4096}; - const uint32_t d_shardCount; - const uint32_t d_maxTTL; - const uint32_t d_tempFailureTTL; - const uint32_t d_maxNegativeTTL; - const uint32_t d_minTTL; - const uint32_t d_staleTTL; - const bool d_dontAge; - const bool d_deferrableInsertLock; - bool d_parseECS; - bool d_keepStaleData{false}; + CacheSettings d_settings; }; diff --git a/pdns/dnsdistdist/dnsdist-configuration-yaml.cc b/pdns/dnsdistdist/dnsdist-configuration-yaml.cc index 55ddc0eb57..9fc2557c7a 100644 --- a/pdns/dnsdistdist/dnsdist-configuration-yaml.cc +++ b/pdns/dnsdistdist/dnsdist-configuration-yaml.cc @@ -1062,23 +1062,29 @@ bool loadConfigurationFromFile(const std::string& fileName, [[maybe_unused]] boo } for (const auto& cache : globalConfig.packet_caches) { - auto packetCacheObj = std::make_shared(cache.size, cache.max_ttl, cache.min_ttl, cache.temporary_failure_ttl, cache.max_negative_ttl, cache.stale_ttl, cache.dont_age, cache.shards, cache.deferrable_insert_lock, cache.parse_ecs); - - packetCacheObj->setKeepStaleData(cache.keep_stale_data); - std::unordered_set optionsToSkip{EDNSOptionCode::COOKIE}; - + DNSDistPacketCache::CacheSettings settings{ + .d_maxEntries = cache.size, + .d_maxTTL = cache.max_ttl, + .d_minTTL = cache.min_ttl, + .d_tempFailureTTL = cache.temporary_failure_ttl, + .d_maxNegativeTTL = cache.max_negative_ttl, + .d_staleTTL = cache.stale_ttl, + .d_shardCount = cache.shards, + .d_dontAge = cache.dont_age, + .d_deferrableInsertLock = cache.deferrable_insert_lock, + .d_parseECS = cache.parse_ecs, + .d_keepStaleData = cache.keep_stale_data, + }; for (const auto& option : cache.options_to_skip) { - optionsToSkip.insert(pdns::checked_stoi(std::string(option))); + settings.d_optionsToSkip.insert(pdns::checked_stoi(std::string(option))); } - if (cache.cookie_hashing) { - optionsToSkip.erase(EDNSOptionCode::COOKIE); + settings.d_optionsToSkip.erase(EDNSOptionCode::COOKIE); } - - packetCacheObj->setSkippedOptions(optionsToSkip); if (cache.maximum_entry_size >= sizeof(dnsheader)) { - packetCacheObj->setMaximumEntrySize(cache.maximum_entry_size); + settings.d_maximumEntrySize = cache.maximum_entry_size; } + auto packetCacheObj = std::make_shared(settings); registerType(packetCacheObj, cache.name); } diff --git a/pdns/dnsdistdist/dnsdist-lua-bindings-packetcache.cc b/pdns/dnsdistdist/dnsdist-lua-bindings-packetcache.cc index 6ca827af2a..6f47577d9a 100644 --- a/pdns/dnsdistdist/dnsdist-lua-bindings-packetcache.cc +++ b/pdns/dnsdistdist/dnsdist-lua-bindings-packetcache.cc @@ -33,66 +33,55 @@ void setupLuaBindingsPacketCache(LuaContext& luaCtx, bool client) /* PacketCache */ luaCtx.writeFunction("newPacketCache", [client](size_t maxEntries, boost::optional>>> vars) { - bool keepStaleData = false; - size_t maxTTL = 86400; - size_t minTTL = 0; - size_t tempFailTTL = 60; - size_t maxNegativeTTL = 3600; - size_t staleTTL = 60; - size_t numberOfShards = 20; - size_t maxEntrySize{0}; - bool dontAge = false; - bool deferrableInsertLock = true; - bool ecsParsing = false; + DNSDistPacketCache::CacheSettings settings { + .d_maxEntries = maxEntries, + .d_shardCount = 20, + }; bool cookieHashing = false; LuaArray skipOptions; - std::unordered_set optionsToSkip{EDNSOptionCode::COOKIE}; - - getOptionalValue(vars, "deferrableInsertLock", deferrableInsertLock); - getOptionalValue(vars, "dontAge", dontAge); - getOptionalValue(vars, "keepStaleData", keepStaleData); - getOptionalValue(vars, "maxNegativeTTL", maxNegativeTTL); - getOptionalValue(vars, "maxTTL", maxTTL); - getOptionalValue(vars, "minTTL", minTTL); - getOptionalValue(vars, "numberOfShards", numberOfShards); - getOptionalValue(vars, "parseECS", ecsParsing); - getOptionalValue(vars, "staleTTL", staleTTL); - getOptionalValue(vars, "temporaryFailureTTL", tempFailTTL); + size_t maximumEntrySize{4096}; + + getOptionalValue(vars, "deferrableInsertLock", settings.d_deferrableInsertLock); + getOptionalValue(vars, "dontAge", settings.d_dontAge); + getOptionalValue(vars, "keepStaleData", settings.d_keepStaleData); + getOptionalValue(vars, "maxNegativeTTL", settings.d_maxNegativeTTL); + getOptionalValue(vars, "maxTTL", settings.d_maxTTL); + getOptionalValue(vars, "minTTL", settings.d_minTTL); + getOptionalValue(vars, "numberOfShards", settings.d_shardCount); + getOptionalValue(vars, "parseECS", settings.d_parseECS); + getOptionalValue(vars, "staleTTL", settings.d_staleTTL); + getOptionalValue(vars, "temporaryFailureTTL", settings.d_tempFailureTTL); getOptionalValue(vars, "cookieHashing", cookieHashing); - getOptionalValue(vars, "maximumEntrySize", maxEntrySize); + getOptionalValue(vars, "maximumEntrySize", maximumEntrySize); + + if (maximumEntrySize >= sizeof(dnsheader)) { + settings.d_maximumEntrySize = maximumEntrySize; + } if (getOptionalValue(vars, "skipOptions", skipOptions) > 0) { for (const auto& option : skipOptions) { - optionsToSkip.insert(option.second); + settings.d_optionsToSkip.insert(option.second); } } if (cookieHashing) { - optionsToSkip.erase(EDNSOptionCode::COOKIE); + settings.d_optionsToSkip.erase(EDNSOptionCode::COOKIE); } checkAllParametersConsumed("newPacketCache", vars); - if (maxEntries < numberOfShards) { - warnlog("The number of entries (%d) in the packet cache is smaller than the number of shards (%d), decreasing the number of shards to %d", maxEntries, numberOfShards, maxEntries); - g_outputBuffer += "The number of entries (" + std::to_string(maxEntries) + " in the packet cache is smaller than the number of shards (" + std::to_string(numberOfShards) + "), decreasing the number of shards to " + std::to_string(maxEntries); - numberOfShards = maxEntries; + if (maxEntries < settings.d_shardCount) { + warnlog("The number of entries (%d) in the packet cache is smaller than the number of shards (%d), decreasing the number of shards to %d", maxEntries, settings.d_shardCount, maxEntries); + g_outputBuffer += "The number of entries (" + std::to_string(maxEntries) + " in the packet cache is smaller than the number of shards (" + std::to_string(settings.d_shardCount) + "), decreasing the number of shards to " + std::to_string(maxEntries); + settings.d_shardCount = maxEntries; } if (client) { - maxEntries = 1; - numberOfShards = 1; - } - - auto res = std::make_shared(maxEntries, maxTTL, minTTL, tempFailTTL, maxNegativeTTL, staleTTL, dontAge, numberOfShards, deferrableInsertLock, ecsParsing); - - res->setKeepStaleData(keepStaleData); - res->setSkippedOptions(optionsToSkip); - if (maxEntrySize >= sizeof(dnsheader)) { - res->setMaximumEntrySize(maxEntrySize); + settings.d_maxEntries = 1; + settings.d_shardCount = 1; } - return res; + return std::make_shared(settings); }); #ifndef DISABLE_PACKETCACHE_BINDINGS diff --git a/pdns/dnsdistdist/fuzz_dnsdistcache.cc b/pdns/dnsdistdist/fuzz_dnsdistcache.cc index 6c10920d4a..75c419c42f 100644 --- a/pdns/dnsdistdist/fuzz_dnsdistcache.cc +++ b/pdns/dnsdistdist/fuzz_dnsdistcache.cc @@ -32,14 +32,21 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) } /* dnsdist's version */ - DNSDistPacketCache pcSkipCookies(10000); // By default, cookies are not hashed - pcSkipCookies.setECSParsingEnabled(true); + DNSDistPacketCache::CacheSettings skipCookieSettings{ + .d_maxEntries = 10000, + .d_parseECS = true, + }; + DNSDistPacketCache pcSkipCookies(skipCookieSettings); - DNSDistPacketCache pcHashCookies(10000); - pcHashCookies.setECSParsingEnabled(true); // Do not skip cookies - pcHashCookies.setSkippedOptions({}); + DNSDistPacketCache::CacheSettings parseCookieSettings{ + .d_optionsToSkip = {}, + .d_maxEntries = 10000, + .d_parseECS = true, + + }; + DNSDistPacketCache pcHashCookies(parseCookieSettings); try { uint16_t qtype; diff --git a/pdns/dnsdistdist/test-dnsdist-lua-ffi.cc b/pdns/dnsdistdist/test-dnsdist-lua-ffi.cc index f1145625f6..2559a0589d 100644 --- a/pdns/dnsdistdist/test-dnsdist-lua-ffi.cc +++ b/pdns/dnsdistdist/test-dnsdist-lua-ffi.cc @@ -440,7 +440,10 @@ BOOST_AUTO_TEST_CASE(test_Server) BOOST_AUTO_TEST_CASE(test_PacketCache) { - auto packetCache = std::make_shared(10); + DNSDistPacketCache::CacheSettings settings{ + .d_maxEntries = 10, + }; + auto packetCache = std::make_shared(settings); ComboAddress ipv4("192.0.2.1"); InternalQueryState ids; diff --git a/pdns/dnsdistdist/test-dnsdistpacketcache_cc.cc b/pdns/dnsdistdist/test-dnsdistpacketcache_cc.cc index 6915233cae..73754fc506 100644 --- a/pdns/dnsdistdist/test-dnsdistpacketcache_cc.cc +++ b/pdns/dnsdistdist/test-dnsdistpacketcache_cc.cc @@ -22,8 +22,12 @@ static bool receivedOverUDP = true; BOOST_AUTO_TEST_CASE(test_PacketCacheSimple) { - const size_t maxEntries = 150000; - DNSDistPacketCache localCache(maxEntries, 86400, 1); + const DNSDistPacketCache::CacheSettings settings{ + .d_maxEntries = 150000, + .d_maxTTL = 86400, + .d_minTTL = 1, + }; + DNSDistPacketCache localCache(settings); BOOST_CHECK_EQUAL(localCache.getSize(), 0U); size_t counter = 0; @@ -131,9 +135,17 @@ BOOST_AUTO_TEST_CASE(test_PacketCacheSimple) BOOST_AUTO_TEST_CASE(test_PacketCacheSharded) { - const size_t maxEntries = 150000; - const size_t numberOfShards = 10; - DNSDistPacketCache localCache(maxEntries, 86400, 1, 60, 3600, 60, false, numberOfShards); + const DNSDistPacketCache::CacheSettings settings{ + .d_maxEntries = 150000, + .d_maxTTL = 86400, + .d_minTTL = 1, + .d_tempFailureTTL = 60, + .d_maxNegativeTTL = 3600, + .d_staleTTL = 60, + .d_shardCount = 10, + .d_dontAge = false, + }; + DNSDistPacketCache localCache(settings); BOOST_CHECK_EQUAL(localCache.getSize(), 0U); size_t counter = 0; @@ -233,8 +245,12 @@ BOOST_AUTO_TEST_CASE(test_PacketCacheSharded) BOOST_AUTO_TEST_CASE(test_PacketCacheTCP) { - const size_t maxEntries = 150000; - DNSDistPacketCache localCache(maxEntries, 86400, 1); + const DNSDistPacketCache::CacheSettings settings{ + .d_maxEntries = 150000, + .d_maxTTL = 86400, + .d_minTTL = 1, + }; + DNSDistPacketCache localCache(settings); InternalQueryState ids; ids.qtype = QType::A; ids.qclass = QClass::IN; @@ -299,8 +315,12 @@ BOOST_AUTO_TEST_CASE(test_PacketCacheTCP) BOOST_AUTO_TEST_CASE(test_PacketCacheServFailTTL) { - const size_t maxEntries = 150000; - DNSDistPacketCache localCache(maxEntries, 86400, 1); + const DNSDistPacketCache::CacheSettings settings{ + .d_maxEntries = 150000, + .d_maxTTL = 86400, + .d_minTTL = 1, + }; + DNSDistPacketCache localCache(settings); InternalQueryState ids; ids.qtype = QType::A; ids.qclass = QClass::IN; @@ -351,8 +371,14 @@ BOOST_AUTO_TEST_CASE(test_PacketCacheServFailTTL) BOOST_AUTO_TEST_CASE(test_PacketCacheNoDataTTL) { - const size_t maxEntries = 150000; - DNSDistPacketCache localCache(maxEntries, /* maxTTL */ 86400, /* minTTL */ 1, /* tempFailureTTL */ 60, /* maxNegativeTTL */ 1); + const DNSDistPacketCache::CacheSettings settings{ + .d_maxEntries = 150000, + .d_maxTTL = 86400, + .d_minTTL = 1, + .d_tempFailureTTL = 60, + .d_maxNegativeTTL = 1, + }; + DNSDistPacketCache localCache(settings); ComboAddress remote; bool dnssecOK = false; @@ -407,8 +433,14 @@ BOOST_AUTO_TEST_CASE(test_PacketCacheNoDataTTL) BOOST_AUTO_TEST_CASE(test_PacketCacheNXDomainTTL) { - const size_t maxEntries = 150000; - DNSDistPacketCache localCache(maxEntries, /* maxTTL */ 86400, /* minTTL */ 1, /* tempFailureTTL */ 60, /* maxNegativeTTL */ 1); + const DNSDistPacketCache::CacheSettings settings{ + .d_maxEntries = 150000, + .d_maxTTL = 86400, + .d_minTTL = 1, + .d_tempFailureTTL = 60, + .d_maxNegativeTTL = 1, + }; + DNSDistPacketCache localCache(settings); InternalQueryState ids; ids.qtype = QType::A; @@ -463,8 +495,14 @@ BOOST_AUTO_TEST_CASE(test_PacketCacheNXDomainTTL) BOOST_AUTO_TEST_CASE(test_PacketCacheTruncated) { - const size_t maxEntries = 150000; - DNSDistPacketCache localCache(maxEntries, /* maxTTL */ 86400, /* minTTL */ 1, /* tempFailureTTL */ 60, /* maxNegativeTTL */ 1); + const DNSDistPacketCache::CacheSettings settings{ + .d_maxEntries = 150000, + .d_maxTTL = 86400, + .d_minTTL = 1, + .d_tempFailureTTL = 60, + .d_maxNegativeTTL = 1, + }; + DNSDistPacketCache localCache(settings); InternalQueryState ids; ids.qtype = QType::A; @@ -518,8 +556,6 @@ BOOST_AUTO_TEST_CASE(test_PacketCacheTruncated) BOOST_AUTO_TEST_CASE(test_PacketCacheMaximumSize) { - const size_t maxEntries = 150000; - DNSDistPacketCache packetCache(maxEntries, 86400, 1); InternalQueryState ids; ids.qtype = QType::A; ids.qclass = QClass::IN; @@ -550,74 +586,89 @@ BOOST_AUTO_TEST_CASE(test_PacketCacheMaximumSize) pwR.commit(); } - /* first, we set the maximum entry size to the response packet size */ - packetCache.setMaximumEntrySize(response.size()); - { - /* UDP */ - uint32_t key = 0; - boost::optional subnet; - DNSQuestion dnsQuestion(ids, query); - bool found = packetCache.get(dnsQuestion, 0, &key, subnet, dnssecOK, receivedOverUDP); - BOOST_CHECK_EQUAL(found, false); - BOOST_CHECK(!subnet); + /* first, we set the maximum entry size to the response packet size */ + const DNSDistPacketCache::CacheSettings settings{ + .d_maxEntries = 150000, + .d_maximumEntrySize = response.size(), + .d_maxTTL = 86400, + .d_minTTL = 1, + }; + DNSDistPacketCache packetCache(settings); - packetCache.insert(key, subnet, *(getFlagsFromDNSHeader(dnsQuestion.getHeader().get())), dnssecOK, ids.qname, QType::A, QClass::IN, response, receivedOverUDP, RCode::NoError, boost::none); - found = packetCache.get(dnsQuestion, queryID, &key, subnet, dnssecOK, receivedOverUDP, 0, true); - BOOST_CHECK_EQUAL(found, true); - BOOST_CHECK(!subnet); - } + { + /* UDP */ + uint32_t key = 0; + boost::optional subnet; + DNSQuestion dnsQuestion(ids, query); + bool found = packetCache.get(dnsQuestion, 0, &key, subnet, dnssecOK, receivedOverUDP); + BOOST_CHECK_EQUAL(found, false); + BOOST_CHECK(!subnet); - { - /* same but over TCP */ - uint32_t key = 0; - boost::optional subnet; - ids.protocol = dnsdist::Protocol::DoTCP; - DNSQuestion dnsQuestion(ids, query); - bool found = packetCache.get(dnsQuestion, 0, &key, subnet, dnssecOK, !receivedOverUDP); - BOOST_CHECK_EQUAL(found, false); - BOOST_CHECK(!subnet); + packetCache.insert(key, subnet, *(getFlagsFromDNSHeader(dnsQuestion.getHeader().get())), dnssecOK, ids.qname, QType::A, QClass::IN, response, receivedOverUDP, RCode::NoError, boost::none); + found = packetCache.get(dnsQuestion, queryID, &key, subnet, dnssecOK, receivedOverUDP, 0, true); + BOOST_CHECK_EQUAL(found, true); + BOOST_CHECK(!subnet); + } - packetCache.insert(key, subnet, *(getFlagsFromDNSHeader(dnsQuestion.getHeader().get())), dnssecOK, ids.qname, QType::A, QClass::IN, response, !receivedOverUDP, RCode::NoError, boost::none); - found = packetCache.get(dnsQuestion, queryID, &key, subnet, dnssecOK, !receivedOverUDP, 0, true); - BOOST_CHECK_EQUAL(found, true); - BOOST_CHECK(!subnet); + { + /* same but over TCP */ + uint32_t key = 0; + boost::optional subnet; + ids.protocol = dnsdist::Protocol::DoTCP; + DNSQuestion dnsQuestion(ids, query); + bool found = packetCache.get(dnsQuestion, 0, &key, subnet, dnssecOK, !receivedOverUDP); + BOOST_CHECK_EQUAL(found, false); + BOOST_CHECK(!subnet); + + packetCache.insert(key, subnet, *(getFlagsFromDNSHeader(dnsQuestion.getHeader().get())), dnssecOK, ids.qname, QType::A, QClass::IN, response, !receivedOverUDP, RCode::NoError, boost::none); + found = packetCache.get(dnsQuestion, queryID, &key, subnet, dnssecOK, !receivedOverUDP, 0, true); + BOOST_CHECK_EQUAL(found, true); + BOOST_CHECK(!subnet); + } } - /* then we set it slightly below response packet size */ - packetCache.expunge(0); - packetCache.setMaximumEntrySize(response.size() - 1); { - /* UDP */ - uint32_t key = 0; - boost::optional subnet; - DNSQuestion dnsQuestion(ids, query); - bool found = packetCache.get(dnsQuestion, 0, &key, subnet, dnssecOK, receivedOverUDP); - BOOST_CHECK_EQUAL(found, false); - BOOST_CHECK(!subnet); + /* then we set it slightly below response packet size */ + const DNSDistPacketCache::CacheSettings settings{ + .d_maxEntries = 150000, + .d_maximumEntrySize = response.size() - 1, + .d_maxTTL = 86400, + .d_minTTL = 1, + }; + DNSDistPacketCache packetCache(settings); - packetCache.insert(key, subnet, *(getFlagsFromDNSHeader(dnsQuestion.getHeader().get())), dnssecOK, ids.qname, QType::A, QClass::IN, response, receivedOverUDP, RCode::NoError, boost::none); - found = packetCache.get(dnsQuestion, queryID, &key, subnet, dnssecOK, receivedOverUDP, 0, true); - BOOST_CHECK_EQUAL(found, false); - } + { + /* UDP */ + uint32_t key = 0; + boost::optional subnet; + DNSQuestion dnsQuestion(ids, query); + bool found = packetCache.get(dnsQuestion, 0, &key, subnet, dnssecOK, receivedOverUDP); + BOOST_CHECK_EQUAL(found, false); + BOOST_CHECK(!subnet); - { - /* same but over TCP */ - uint32_t key = 0; - boost::optional subnet; - ids.protocol = dnsdist::Protocol::DoTCP; - DNSQuestion dnsQuestion(ids, query); - bool found = packetCache.get(dnsQuestion, 0, &key, subnet, dnssecOK, !receivedOverUDP); - BOOST_CHECK_EQUAL(found, false); - BOOST_CHECK(!subnet); + packetCache.insert(key, subnet, *(getFlagsFromDNSHeader(dnsQuestion.getHeader().get())), dnssecOK, ids.qname, QType::A, QClass::IN, response, receivedOverUDP, RCode::NoError, boost::none); + found = packetCache.get(dnsQuestion, queryID, &key, subnet, dnssecOK, receivedOverUDP, 0, true); + BOOST_CHECK_EQUAL(found, false); + } - packetCache.insert(key, subnet, *(getFlagsFromDNSHeader(dnsQuestion.getHeader().get())), dnssecOK, ids.qname, QType::A, QClass::IN, response, !receivedOverUDP, RCode::NoError, boost::none); - found = packetCache.get(dnsQuestion, queryID, &key, subnet, dnssecOK, !receivedOverUDP, 0, true); - BOOST_CHECK_EQUAL(found, false); + { + /* same but over TCP */ + uint32_t key = 0; + boost::optional subnet; + ids.protocol = dnsdist::Protocol::DoTCP; + DNSQuestion dnsQuestion(ids, query); + bool found = packetCache.get(dnsQuestion, 0, &key, subnet, dnssecOK, !receivedOverUDP); + BOOST_CHECK_EQUAL(found, false); + BOOST_CHECK(!subnet); + + packetCache.insert(key, subnet, *(getFlagsFromDNSHeader(dnsQuestion.getHeader().get())), dnssecOK, ids.qname, QType::A, QClass::IN, response, !receivedOverUDP, RCode::NoError, boost::none); + found = packetCache.get(dnsQuestion, queryID, &key, subnet, dnssecOK, !receivedOverUDP, 0, true); + BOOST_CHECK_EQUAL(found, false); + } } /* now we generate a very big response packet, it should be cached over TCP and UDP (although in practice dnsdist will refuse to cache it for the UDP case) */ - packetCache.expunge(0); response.clear(); { GenericDNSPacketWriter pwR(response, ids.qname, QType::AAAA, QClass::IN, 0); @@ -634,39 +685,52 @@ BOOST_AUTO_TEST_CASE(test_PacketCacheMaximumSize) } BOOST_REQUIRE_GT(response.size(), 4096U); - packetCache.setMaximumEntrySize(response.size()); { - /* UDP */ - uint32_t key = 0; - boost::optional subnet; - DNSQuestion dnsQuestion(ids, query); - bool found = packetCache.get(dnsQuestion, 0, &key, subnet, dnssecOK, receivedOverUDP); - BOOST_CHECK_EQUAL(found, false); - BOOST_CHECK(!subnet); + /* then we set it slightly below response packet size */ + const DNSDistPacketCache::CacheSettings settings{ + .d_maxEntries = 150000, + .d_maximumEntrySize = response.size(), + .d_maxTTL = 86400, + .d_minTTL = 1, + }; + DNSDistPacketCache packetCache(settings); - packetCache.insert(key, subnet, *(getFlagsFromDNSHeader(dnsQuestion.getHeader().get())), dnssecOK, ids.qname, QType::A, QClass::IN, response, receivedOverUDP, RCode::NoError, boost::none); - found = packetCache.get(dnsQuestion, queryID, &key, subnet, dnssecOK, receivedOverUDP, 0, true); - BOOST_CHECK_EQUAL(found, true); - } + { + /* UDP */ + uint32_t key = 0; + boost::optional subnet; + DNSQuestion dnsQuestion(ids, query); + bool found = packetCache.get(dnsQuestion, 0, &key, subnet, dnssecOK, receivedOverUDP); + BOOST_CHECK_EQUAL(found, false); + BOOST_CHECK(!subnet); - { - /* same but over TCP */ - uint32_t key = 0; - boost::optional subnet; - ids.protocol = dnsdist::Protocol::DoTCP; - DNSQuestion dnsQuestion(ids, query); - bool found = packetCache.get(dnsQuestion, 0, &key, subnet, dnssecOK, !receivedOverUDP); - BOOST_CHECK_EQUAL(found, false); - BOOST_CHECK(!subnet); + packetCache.insert(key, subnet, *(getFlagsFromDNSHeader(dnsQuestion.getHeader().get())), dnssecOK, ids.qname, QType::A, QClass::IN, response, receivedOverUDP, RCode::NoError, boost::none); + found = packetCache.get(dnsQuestion, queryID, &key, subnet, dnssecOK, receivedOverUDP, 0, true); + BOOST_CHECK_EQUAL(found, true); + } - packetCache.insert(key, subnet, *(getFlagsFromDNSHeader(dnsQuestion.getHeader().get())), dnssecOK, ids.qname, QType::A, QClass::IN, response, !receivedOverUDP, RCode::NoError, boost::none); - found = packetCache.get(dnsQuestion, queryID, &key, subnet, dnssecOK, !receivedOverUDP, 0, true); - BOOST_CHECK_EQUAL(found, true); + { + /* same but over TCP */ + uint32_t key = 0; + boost::optional subnet; + ids.protocol = dnsdist::Protocol::DoTCP; + DNSQuestion dnsQuestion(ids, query); + bool found = packetCache.get(dnsQuestion, 0, &key, subnet, dnssecOK, !receivedOverUDP); + BOOST_CHECK_EQUAL(found, false); + BOOST_CHECK(!subnet); + + packetCache.insert(key, subnet, *(getFlagsFromDNSHeader(dnsQuestion.getHeader().get())), dnssecOK, ids.qname, QType::A, QClass::IN, response, !receivedOverUDP, RCode::NoError, boost::none); + found = packetCache.get(dnsQuestion, queryID, &key, subnet, dnssecOK, !receivedOverUDP, 0, true); + BOOST_CHECK_EQUAL(found, true); + } } } -static DNSDistPacketCache s_localCache(500000); +const DNSDistPacketCache::CacheSettings s_localCacheSettings{ + .d_maxEntries = 500000, +}; +static DNSDistPacketCache s_localCache(s_localCacheSettings); static void threadMangler(unsigned int offset) { @@ -777,8 +841,19 @@ BOOST_AUTO_TEST_CASE(test_PacketCacheThreaded) BOOST_AUTO_TEST_CASE(test_PCCollision) { - const size_t maxEntries = 150000; - DNSDistPacketCache localCache(maxEntries, 86400, 1, 60, 3600, 60, false, 1, true, true); + const DNSDistPacketCache::CacheSettings settings{ + .d_maxEntries = 150000, + .d_maxTTL = 86400, + .d_minTTL = 1, + .d_tempFailureTTL = 60, + .d_maxNegativeTTL = 3600, + .d_staleTTL = 60, + .d_shardCount = 1, + .d_dontAge = false, + .d_deferrableInsertLock = true, + .d_parseECS = true, + }; + DNSDistPacketCache localCache(settings); BOOST_CHECK_EQUAL(localCache.getSize(), 0U); InternalQueryState ids; @@ -862,7 +937,10 @@ BOOST_AUTO_TEST_CASE(test_PCCollision) #if 0 /* to be able to compute a new collision if the packet cache hashing code is updated */ { - DNSDistPacketCache pc(10000); + const DNSDistPacketCache::CacheSettings settings{ + .d_maxEntries = 10000, + }; + DNSDistPacketCache pc(settings); GenericDNSPacketWriter::optvect_t ednsOptions; EDNSSubnetOpts opt; std::map colMap; @@ -903,8 +981,19 @@ BOOST_AUTO_TEST_CASE(test_PCCollision) BOOST_AUTO_TEST_CASE(test_PCDNSSECCollision) { - const size_t maxEntries = 150000; - DNSDistPacketCache localCache(maxEntries, 86400, 1, 60, 3600, 60, false, 1, true, true); + const DNSDistPacketCache::CacheSettings settings{ + .d_maxEntries = 150000, + .d_maxTTL = 86400, + .d_minTTL = 1, + .d_tempFailureTTL = 60, + .d_maxNegativeTTL = 3600, + .d_staleTTL = 60, + .d_shardCount = 1, + .d_dontAge = false, + .d_deferrableInsertLock = true, + .d_parseECS = true, + }; + DNSDistPacketCache localCache(settings); BOOST_CHECK_EQUAL(localCache.getSize(), 0U); InternalQueryState ids; @@ -958,8 +1047,12 @@ BOOST_AUTO_TEST_CASE(test_PCDNSSECCollision) BOOST_AUTO_TEST_CASE(test_PacketCacheInspection) { - const size_t maxEntries = 100; - DNSDistPacketCache localCache(maxEntries, 86400, 1); + const DNSDistPacketCache::CacheSettings settings{ + .d_maxEntries = 150000, + .d_maxTTL = 86400, + .d_minTTL = 1, + }; + DNSDistPacketCache localCache(settings); BOOST_CHECK_EQUAL(localCache.getSize(), 0U); ComboAddress remote; @@ -1200,8 +1293,12 @@ BOOST_AUTO_TEST_CASE(test_PacketCacheInspection) BOOST_AUTO_TEST_CASE(test_PacketCacheXFR) { - const size_t maxEntries = 150000; - DNSDistPacketCache localCache(maxEntries, 86400, 1); + const DNSDistPacketCache::CacheSettings settings{ + .d_maxEntries = 150000, + .d_maxTTL = 86400, + .d_minTTL = 1, + }; + DNSDistPacketCache localCache(settings); BOOST_CHECK_EQUAL(localCache.getSize(), 0U); const std::set xfrTypes = {QType::AXFR, QType::IXFR};