]> git.ipfire.org Git - thirdparty/pdns.git/commitdiff
dnsdist: Refactor the packet cache settings
authorRemi Gacogne <remi.gacogne@powerdns.com>
Fri, 4 Apr 2025 10:08:45 +0000 (12:08 +0200)
committerRemi Gacogne <remi.gacogne@powerdns.com>
Fri, 11 Apr 2025 10:07:47 +0000 (12:07 +0200)
pdns/dnsdistdist/dnsdist-cache.cc
pdns/dnsdistdist/dnsdist-cache.hh
pdns/dnsdistdist/dnsdist-configuration-yaml.cc
pdns/dnsdistdist/dnsdist-lua-bindings-packetcache.cc
pdns/dnsdistdist/fuzz_dnsdistcache.cc
pdns/dnsdistdist/test-dnsdist-lua-ffi.cc
pdns/dnsdistdist/test-dnsdistpacketcache_cc.cc

index 020825306be5303e6609c79cb117f699fdec57b3..79d8d118fe984f350f193b3b6e86c041d18dbaba 100644 (file)
 #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<uint32_t, CacheValue>& 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<Netmask>& 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<Netmask>& 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<Netmask>& 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<Netmask>& 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<char*>(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<const char*>(packet.data()), packet.size()), result, sizeof(dnsheader) + qnameWireLength, d_optionsToSkip);
+      result = PacketCache::hashAfterQname(std::string_view(reinterpret_cast<const char*>(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<uint16_t>& optionsToSkip)
-{
-  d_optionsToSkip = optionsToSkip;
-}
-
 std::set<DNSName> DNSDistPacketCache::getDomainsContainingRecords(const ComboAddress& addr)
 {
   std::set<DNSName> domains;
@@ -642,8 +641,3 @@ std::set<ComboAddress> DNSDistPacketCache::getRecordsForDomain(const DNSName& do
 
   return addresses;
 }
-
-void DNSDistPacketCache::setMaximumEntrySize(size_t maxSize)
-{
-  d_maximumEntrySize = maxSize;
-}
index a3ef35023e4cf1d1bf7e08f6f3c5c3ff175004f9..c6e249508acb8d062f2e3d5452c1342c69a4f7d7 100644 (file)
@@ -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<uint16_t> 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<Netmask>& 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<uint32_t> tempFailureTTL);
   bool get(DNSQuestion& dnsQuestion, uint16_t queryId, uint32_t* keyOut, boost::optional<Netmask>& 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<ComboAddress> getRecordsForDomain(const DNSName& domain);
 
-  void setSkippedOptions(const std::unordered_set<uint16_t>& 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<uint32_t, CacheValue>& map, uint32_t key, CacheValue& newValue);
 
   std::vector<CacheShard> d_shards;
-  std::unordered_set<uint16_t> 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;
 };
index 55ddc0eb57415054e59eed3b311388369e0c1ebf..9fc2557c7a5e47245e28710564df05ebd657d53c 100644 (file)
@@ -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<DNSDistPacketCache>(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<uint16_t> 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<uint16_t>(std::string(option)));
+        settings.d_optionsToSkip.insert(pdns::checked_stoi<uint16_t>(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<DNSDistPacketCache>(settings);
 
       registerType<DNSDistPacketCache>(packetCacheObj, cache.name);
     }
index 6ca827af2ad07d20066f12c79dd5e4ad68d81553..6f47577d9a82e288a8feaaa47641adb568054811 100644 (file)
@@ -33,66 +33,55 @@ void setupLuaBindingsPacketCache(LuaContext& luaCtx, bool client)
   /* PacketCache */
   luaCtx.writeFunction("newPacketCache", [client](size_t maxEntries, boost::optional<LuaAssociativeTable<boost::variant<bool, size_t, LuaArray<uint16_t>>>> 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<uint16_t> skipOptions;
-    std::unordered_set<uint16_t> optionsToSkip{EDNSOptionCode::COOKIE};
-
-    getOptionalValue<bool>(vars, "deferrableInsertLock", deferrableInsertLock);
-    getOptionalValue<bool>(vars, "dontAge", dontAge);
-    getOptionalValue<bool>(vars, "keepStaleData", keepStaleData);
-    getOptionalValue<size_t>(vars, "maxNegativeTTL", maxNegativeTTL);
-    getOptionalValue<size_t>(vars, "maxTTL", maxTTL);
-    getOptionalValue<size_t>(vars, "minTTL", minTTL);
-    getOptionalValue<size_t>(vars, "numberOfShards", numberOfShards);
-    getOptionalValue<bool>(vars, "parseECS", ecsParsing);
-    getOptionalValue<size_t>(vars, "staleTTL", staleTTL);
-    getOptionalValue<size_t>(vars, "temporaryFailureTTL", tempFailTTL);
+    size_t maximumEntrySize{4096};
+
+    getOptionalValue<bool>(vars, "deferrableInsertLock", settings.d_deferrableInsertLock);
+    getOptionalValue<bool>(vars, "dontAge", settings.d_dontAge);
+    getOptionalValue<bool>(vars, "keepStaleData", settings.d_keepStaleData);
+    getOptionalValue<size_t>(vars, "maxNegativeTTL", settings.d_maxNegativeTTL);
+    getOptionalValue<size_t>(vars, "maxTTL", settings.d_maxTTL);
+    getOptionalValue<size_t>(vars, "minTTL", settings.d_minTTL);
+    getOptionalValue<size_t>(vars, "numberOfShards", settings.d_shardCount);
+    getOptionalValue<bool>(vars, "parseECS", settings.d_parseECS);
+    getOptionalValue<size_t>(vars, "staleTTL", settings.d_staleTTL);
+    getOptionalValue<size_t>(vars, "temporaryFailureTTL", settings.d_tempFailureTTL);
     getOptionalValue<bool>(vars, "cookieHashing", cookieHashing);
-    getOptionalValue<size_t>(vars, "maximumEntrySize", maxEntrySize);
+    getOptionalValue<size_t>(vars, "maximumEntrySize", maximumEntrySize);
+
+    if (maximumEntrySize >= sizeof(dnsheader)) {
+      settings.d_maximumEntrySize = maximumEntrySize;
+    }
 
     if (getOptionalValue<decltype(skipOptions)>(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<DNSDistPacketCache>(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<DNSDistPacketCache>(settings);
   });
 
 #ifndef DISABLE_PACKETCACHE_BINDINGS
index 6c10920d4a9a697976351db9dd835e86b0e37b87..75c419c42fd2e5f37882d0724cd6819c77218a40 100644 (file)
@@ -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;
index f1145625f6e1cd0a7b3ad6d54748df23e11bbb68..2559a0589da0a0d7544672f7ea45f1e7d458208a 100644 (file)
@@ -440,7 +440,10 @@ BOOST_AUTO_TEST_CASE(test_Server)
 
 BOOST_AUTO_TEST_CASE(test_PacketCache)
 {
-  auto packetCache = std::make_shared<DNSDistPacketCache>(10);
+  DNSDistPacketCache::CacheSettings settings{
+    .d_maxEntries = 10,
+  };
+  auto packetCache = std::make_shared<DNSDistPacketCache>(settings);
 
   ComboAddress ipv4("192.0.2.1");
   InternalQueryState ids;
index 6915233caecb823d606c34e661c1664f5faa4086..73754fc50684bf5fba09b3213d7f7d8c02c6e11e 100644 (file)
@@ -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<Netmask> 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<Netmask> 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<Netmask> 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<Netmask> 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<Netmask> 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<Netmask> 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<Netmask> 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<Netmask> 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<PacketBuffer> 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<Netmask> 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<Netmask> 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<Netmask> 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<Netmask> 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<PacketBuffer>::optvect_t ednsOptions;
     EDNSSubnetOpts opt;
     std::map<uint32_t, Netmask> 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<QType> xfrTypes = {QType::AXFR, QType::IXFR};