]> git.ipfire.org Git - thirdparty/pdns.git/commitdiff
Dump ns speed map in protobuf format
authorOtto Moerbeek <otto.moerbeek@open-xchange.com>
Wed, 2 Jul 2025 14:19:10 +0000 (16:19 +0200)
committerOtto Moerbeek <otto.moerbeek@open-xchange.com>
Wed, 9 Jul 2025 09:17:18 +0000 (11:17 +0200)
Signed-off-by: Otto Moerbeek <otto.moerbeek@open-xchange.com>
pdns/recursordist/protozero-helpers.hh [new file with mode: 0644]
pdns/recursordist/recursor_cache.cc
pdns/recursordist/syncres.cc

diff --git a/pdns/recursordist/protozero-helpers.hh b/pdns/recursordist/protozero-helpers.hh
new file mode 100644 (file)
index 0000000..e88c888
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#pragma once
+
+#include <protozero/pbf_builder.hpp>
+#include <protozero/pbf_message.hpp>
+
+#include "iputils.hh"
+
+enum class PBComboAddress : protozero::pbf_tag_type
+{
+  required_uint32_port = 1,
+  required_bytes_address = 2, // family implicit
+};
+
+template <typename T>
+void encodeComboAddress(protozero::pbf_builder<T>& writer, T type, const ComboAddress& address)
+{
+  protozero::pbf_builder<PBComboAddress> message(writer, type);
+
+  // Skip all parts except address and port
+  message.add_uint32(PBComboAddress::required_uint32_port, address.getPort());
+  if (address.sin4.sin_family == AF_INET) {
+    message.add_bytes(PBComboAddress::required_bytes_address, reinterpret_cast<const char*>(&address.sin4.sin_addr.s_addr), sizeof(address.sin4.sin_addr.s_addr)); // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast): it's the API
+  }
+  else if (address.sin4.sin_family == AF_INET6) {
+    message.add_bytes(PBComboAddress::required_bytes_address, reinterpret_cast<const char*>(&address.sin6.sin6_addr.s6_addr), sizeof(address.sin6.sin6_addr)); // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast): it's the API
+  }
+}
+
+template <typename T>
+void decodeComboAddress(protozero::pbf_message<T>& reader, ComboAddress& address)
+{
+  address.reset();
+  protozero::pbf_message<PBComboAddress> message(reader.get_message());
+
+  // Skip all parts except address and port
+  if (message.next(PBComboAddress::required_uint32_port)) {
+    address.setPort(message.get_uint32());
+  }
+  else {
+    throw std::runtime_error("expected port in protobuf data");
+  }
+  constexpr auto inet4size = sizeof(address.sin4.sin_addr);
+  constexpr auto inet6size = sizeof(address.sin6.sin6_addr);
+  if (message.next(PBComboAddress::required_bytes_address)) {
+    auto data = message.get_bytes();
+    address.sin4.sin_family = data.size() == inet4size ? AF_INET : AF_INET6;
+    if (data.size() == inet4size) {
+      address.sin4.sin_family = AF_INET;
+      memcpy(&address.sin4.sin_addr, data.data(), data.size());
+    }
+    else if (data.size() == inet6size) {
+      address.sin6.sin6_family = AF_INET6;
+      memcpy(&address.sin6.sin6_addr, data.data(), data.size());
+    }
+    else {
+      throw std::runtime_error("unexpected address family in protobuf data");
+    }
+  }
+  else {
+    throw std::runtime_error("expected address bytes in protobuf data");
+  }
+}
+
+template <typename T>
+void encodeNetmask(protozero::pbf_builder<T>& writer, T type, const Netmask& subnet)
+{
+  if (!subnet.empty()) {
+    writer.add_bytes(type, reinterpret_cast<const char*>(&subnet), sizeof(Netmask)); // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast): it's the API
+  }
+}
+
+template <typename T>
+void decodeNetmask(protozero::pbf_message<T>& message, Netmask& subnet)
+{
+  auto data = message.get_bytes();
+  memcpy(&subnet, data.data(), data.size());
+}
+
index df29606e46b350dfaf58941e866a64ec5885e132..0287b209c8b1325e7907efc53181dea2f3a64eee 100644 (file)
@@ -34,6 +34,7 @@
 #include "cachecleaner.hh"
 #include "rec-taskqueue.hh"
 #include "version.hh"
+#include "protozero-helpers.hh"
 
 /*
  * SERVE-STALE: the general approach
@@ -985,12 +986,6 @@ enum class PBCacheEntry : protozero::pbf_tag_type
   required_bool_tooBig = 16,
 };
 
-enum class PBComboAddress : protozero::pbf_tag_type
-{
-  required_uint32_port = 1,
-  required_bytes_address = 2, // family implicit
-};
-
 enum class PBAuthRecord : protozero::pbf_tag_type
 {
   required_bytes_name = 1,
@@ -1002,70 +997,6 @@ enum class PBAuthRecord : protozero::pbf_tag_type
   required_uint32_clen = 7,
 };
 
-template <typename T>
-static void encodeComboAddress(protozero::pbf_builder<T>& writer, T type, const ComboAddress& address)
-{
-  protozero::pbf_builder<PBComboAddress> message(writer, type);
-
-  // Skip all parts except address and port
-  message.add_uint32(PBComboAddress::required_uint32_port, address.getPort());
-  if (address.sin4.sin_family == AF_INET) {
-    message.add_bytes(PBComboAddress::required_bytes_address, reinterpret_cast<const char*>(&address.sin4.sin_addr.s_addr), sizeof(address.sin4.sin_addr.s_addr)); // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast): it's the API
-  }
-  else if (address.sin4.sin_family == AF_INET6) {
-    message.add_bytes(PBComboAddress::required_bytes_address, reinterpret_cast<const char*>(&address.sin6.sin6_addr.s6_addr), sizeof(address.sin6.sin6_addr)); // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast): it's the API
-  }
-}
-
-template <typename T>
-static void decodeComboAddress(protozero::pbf_message<T>& reader, ComboAddress& address)
-{
-  address.reset();
-  protozero::pbf_message<PBComboAddress> message(reader.get_message());
-
-  // Skip all parts except address and port
-  if (message.next(PBComboAddress::required_uint32_port)) {
-    address.setPort(message.get_uint32());
-  }
-  else {
-    throw std::runtime_error("expected port in protobuf data");
-  }
-  constexpr auto inet4size = sizeof(address.sin4.sin_addr);
-  constexpr auto inet6size = sizeof(address.sin6.sin6_addr);
-  if (message.next(PBComboAddress::required_bytes_address)) {
-    auto data = message.get_bytes();
-    address.sin4.sin_family = data.size() == inet4size ? AF_INET : AF_INET6;
-    if (data.size() == inet4size) {
-      address.sin4.sin_family = AF_INET;
-      memcpy(&address.sin4.sin_addr, data.data(), data.size());
-    }
-    else if (data.size() == inet6size) {
-      address.sin6.sin6_family = AF_INET6;
-      memcpy(&address.sin6.sin6_addr, data.data(), data.size());
-    }
-    else {
-      throw std::runtime_error("unexpected address family in protobuf data");
-    }
-  }
-  else {
-    throw std::runtime_error("expected address bytes in protobuf data");
-  }
-}
-
-template <typename T>
-static void encodeNetmask(protozero::pbf_builder<T>& writer, T type, const Netmask& subnet)
-{
-  if (!subnet.empty()) {
-    writer.add_bytes(type, reinterpret_cast<const char*>(&subnet), sizeof(Netmask)); // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast): it's the API
-  }
-}
-
-template <typename T>
-static void decodeNetmask(protozero::pbf_message<T>& message, Netmask& subnet)
-{
-  auto data = message.get_bytes();
-  memcpy(&subnet, data.data(), data.size());
-}
 
 template <typename T, typename U>
 void MemRecursorCache::getRecordSet(T& message, U recordSet)
index 27fa159b5b9f6e4959b495b9d51c838109bfee2f..6a0c103e25ce330ac835727a84f2632662388732 100644 (file)
 #include "rec-taskqueue.hh"
 #include "shuffle.hh"
 
+#include "version.hh"
+#include <protozero/pbf_builder.hpp>
+#include <protozero/pbf_message.hpp>
+#include "protozero-helpers.hh"
+
 rec::GlobalCounters g_Counters;
 thread_local rec::TCounters t_Counters(g_Counters);
 
@@ -242,6 +247,64 @@ public:
     ind.modify(iter, [&](DecayingEwmaCollection& dec) { dec.d_lastget = now; });
     return ret;
   }
+
+  enum class PBNSSpeedDump : protozero::pbf_tag_type
+  {
+    required_string_version = 1,
+    required_string_identity = 2,
+    required_uint64_protocolVersion = 3,
+    required_int64_time = 4,
+    required_string_type = 5,
+    repeated_message_nsspeedEntry = 6,
+  };
+
+  enum class PBNSSpeedEntry : protozero::pbf_tag_type
+  {
+    required_bytes_name = 1,
+    required_int64_lastgets = 2,
+    required_int64_lastgetus = 3,
+    repeated_message_map = 4,
+  };
+
+  enum class PBNSSpeedMap : protozero::pbf_tag_type
+  {
+    required_bytes_address = 1,
+    required_float_val = 2,
+    required_int32_last = 3,
+  };
+
+  template <typename T, typename U>
+  void getEntry(T& message, U entry)
+  {
+    message.add_bytes(PBNSSpeedEntry::required_bytes_name, entry->d_name.toString());
+    message.add_int64(PBNSSpeedEntry::required_int64_lastgets, entry->d_lastget.tv_sec);
+    message.add_int64(PBNSSpeedEntry::required_int64_lastgetus, entry->d_lastget.tv_usec);
+    for (const auto& [address, collection] : entry->d_collection) {
+      protozero::pbf_builder<PBNSSpeedMap> map(message, PBNSSpeedEntry::repeated_message_map);
+      encodeComboAddress(map, PBNSSpeedMap::required_bytes_address, address);
+      map.add_float(PBNSSpeedMap::required_float_val, collection.d_val);
+      map.add_int32(PBNSSpeedMap::required_int32_last, collection.d_last);
+    }
+  }
+
+  size_t getPB(std::string& ret)
+  {
+    protozero::pbf_builder<PBNSSpeedDump> full(ret);
+    full.add_string(PBNSSpeedDump::required_string_version, getPDNSVersion());
+    full.add_string(PBNSSpeedDump::required_string_identity, SyncRes::s_serverID);
+    full.add_uint64(PBNSSpeedDump::required_uint64_protocolVersion, 1);
+    full.add_int64(PBNSSpeedDump::required_int64_time, time(nullptr));
+    full.add_string(PBNSSpeedDump::required_string_type, "PBNSSpeedDump");
+
+    size_t count = 0;
+    for (const auto& entry : *this) {
+      protozero::pbf_builder<PBNSSpeedEntry> message(full, PBNSSpeedDump::repeated_message_nsspeedEntry);
+      getEntry(message, &entry);
+      ++count;
+    }
+    return count;
+  }
+
 };
 
 static LockGuarded<nsspeeds_t> s_nsSpeeds;