From: Otto Moerbeek Date: Wed, 2 Jul 2025 14:19:10 +0000 (+0200) Subject: Dump ns speed map in protobuf format X-Git-Tag: rec-5.4.0-alpha0~41^2~10 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=d729b9c71158dba21744cf87e2aa3dcd4ec9c518;p=thirdparty%2Fpdns.git Dump ns speed map in protobuf format Signed-off-by: Otto Moerbeek --- diff --git a/pdns/recursordist/protozero-helpers.hh b/pdns/recursordist/protozero-helpers.hh new file mode 100644 index 0000000000..e88c888a4c --- /dev/null +++ b/pdns/recursordist/protozero-helpers.hh @@ -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 +#include + +#include "iputils.hh" + +enum class PBComboAddress : protozero::pbf_tag_type +{ + required_uint32_port = 1, + required_bytes_address = 2, // family implicit +}; + +template +void encodeComboAddress(protozero::pbf_builder& writer, T type, const ComboAddress& address) +{ + protozero::pbf_builder 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(&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(&address.sin6.sin6_addr.s6_addr), sizeof(address.sin6.sin6_addr)); // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast): it's the API + } +} + +template +void decodeComboAddress(protozero::pbf_message& reader, ComboAddress& address) +{ + address.reset(); + protozero::pbf_message 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 +void encodeNetmask(protozero::pbf_builder& writer, T type, const Netmask& subnet) +{ + if (!subnet.empty()) { + writer.add_bytes(type, reinterpret_cast(&subnet), sizeof(Netmask)); // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast): it's the API + } +} + +template +void decodeNetmask(protozero::pbf_message& message, Netmask& subnet) +{ + auto data = message.get_bytes(); + memcpy(&subnet, data.data(), data.size()); +} + diff --git a/pdns/recursordist/recursor_cache.cc b/pdns/recursordist/recursor_cache.cc index df29606e46..0287b209c8 100644 --- a/pdns/recursordist/recursor_cache.cc +++ b/pdns/recursordist/recursor_cache.cc @@ -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 -static void encodeComboAddress(protozero::pbf_builder& writer, T type, const ComboAddress& address) -{ - protozero::pbf_builder 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(&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(&address.sin6.sin6_addr.s6_addr), sizeof(address.sin6.sin6_addr)); // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast): it's the API - } -} - -template -static void decodeComboAddress(protozero::pbf_message& reader, ComboAddress& address) -{ - address.reset(); - protozero::pbf_message 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 -static void encodeNetmask(protozero::pbf_builder& writer, T type, const Netmask& subnet) -{ - if (!subnet.empty()) { - writer.add_bytes(type, reinterpret_cast(&subnet), sizeof(Netmask)); // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast): it's the API - } -} - -template -static void decodeNetmask(protozero::pbf_message& message, Netmask& subnet) -{ - auto data = message.get_bytes(); - memcpy(&subnet, data.data(), data.size()); -} template void MemRecursorCache::getRecordSet(T& message, U recordSet) diff --git a/pdns/recursordist/syncres.cc b/pdns/recursordist/syncres.cc index 27fa159b5b..6a0c103e25 100644 --- a/pdns/recursordist/syncres.cc +++ b/pdns/recursordist/syncres.cc @@ -41,6 +41,11 @@ #include "rec-taskqueue.hh" #include "shuffle.hh" +#include "version.hh" +#include +#include +#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 + 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 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 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 message(full, PBNSSpeedDump::repeated_message_nsspeedEntry); + getEntry(message, &entry); + ++count; + } + return count; + } + }; static LockGuarded s_nsSpeeds;