REVISION "202306080000Z"
DESCRIPTION "Added metrics for NOD and UDR events"
+ REVISION "202311060000Z"
+ DESCRIPTION "Added metrics for maximum chain length and weight"
+
::= { powerdns 2 }
powerdns OBJECT IDENTIFIER ::= { enterprises 43315 }
"Count of UDR events"
::= { stats 148 }
+maxChainLength OBJECT-TYPE
+ SYNTAX Counter64
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "Maximum chain length"
+ ::= { stats 149 }
+
+maxChainWeight OBJECT-TYPE
+ SYNTAX Counter64
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "Maximum chain weight"
+ ::= { stats 150 }
+
---
--- Traps / Notifications
---
packetCacheContended,
packetCacheAcquired,
nodEvents,
- udrEvents
+ udrEvents,
+ maxChainLength,
+ macChainWeight
}
STATUS current
DESCRIPTION "Objects conformance group for PowerDNS Recursor"
^^^^^^^^^^^^^^^^^
currently configured maximum number of cache entries
+max-chain-length
+^^^^^^^^^^^^^^^^
+maximum chain length
+
+max-chain-weight
+^^^^^^^^^^^^^^^^
+maximum chain weight. The weight of a chain of outgoing queries is the product of the number of chained queries by the size of the response received from the external authoritative server.
+
max-packetcache-entries
^^^^^^^^^^^^^^^^^^^^^^^
currently configured maximum number of packet cache entries
assert(chain.first->key->domain == pident->domain); // NOLINT
// don't chain onto existing chained waiter or a chain already processed
if (chain.first->key->fd > -1 && !chain.first->key->closed) {
- chain.first->key->chain.insert(qid); // we can chain
+ if (g_maxChainLength > 0 && chain.first->key->authReqChain.size() >= g_maxChainLength) {
+ return LWResult::Result::OSLimitError;
+ }
+ chain.first->key->authReqChain.insert(qid); // we can chain
*fileDesc = -1; // gets used in waitEvent / sendEvent later on
+ auto maxLength = t_Counters.at(rec::Counter::maxChainLength);
+ if (chain.first->key->authReqChain.size() > maxLength) {
+ t_Counters.at(rec::Counter::maxChainLength) = chain.first->key->authReqChain.size();
+ }
return LWResult::Result::Success;
}
}
// We close the chain for new entries, since they won't be processed anyway
iter->key->closed = true;
- if (iter->key->chain.empty()) {
+ if (iter->key->authReqChain.empty()) {
return;
}
- for (auto i = iter->key->chain.begin(); i != iter->key->chain.end(); ++i) {
+
+ auto maxWeight = t_Counters.at(rec::Counter::maxChainWeight);
+ auto weight = iter->key->authReqChain.size() * content.size();
+ if (weight > maxWeight) {
+ t_Counters.at(rec::Counter::maxChainWeight) = weight;
+ }
+
+ for (auto qid: iter->key->authReqChain) {
auto packetID = std::make_shared<PacketID>(*resend);
packetID->fd = -1;
- packetID->id = *i;
+ packetID->id = qid;
g_multiTasker->sendEvent(packetID, &content);
t_Counters.at(rec::Counter::chainResends)++;
}
std::set<ComboAddress> g_proxyProtocolExceptions;
boost::optional<ComboAddress> g_dns64Prefix{boost::none};
DNSName g_dns64PrefixReverse;
+unsigned int g_maxChainLength;
std::shared_ptr<SyncRes::domainmap_t> g_initialDomainMap; // new threads needs this to be setup
std::shared_ptr<NetmaskGroup> g_initialAllowFrom; // new thread needs to be setup with this
std::shared_ptr<NetmaskGroup> g_initialAllowNotifyFrom; // new threads need this to be setup
g_maxUDPQueriesPerRound = ::arg().asNum("max-udp-queries-per-round");
g_useKernelTimestamp = ::arg().mustDo("protobuf-use-kernel-timestamp");
+ g_maxChainLength = ::arg().asNum("max-chain-length");
disableStats(StatComponent::API, ::arg()["stats-api-blacklist"]);
disableStats(StatComponent::Carbon, ::arg()["stats-carbon-blacklist"]);
extern size_t g_maxUDPQueriesPerRound;
extern bool g_useKernelTimestamp;
extern bool g_allowNoRD;
+extern unsigned int g_maxChainLength;
extern thread_local std::shared_ptr<NetmaskGroup> t_allowFrom;
extern thread_local std::shared_ptr<NetmaskGroup> t_allowNotifyFrom;
extern thread_local std::shared_ptr<notifyset_t> t_allowNotifyFor;
static const oid10 packetCacheAcquiredOID = {RECURSOR_STATS_OID, 146};
static const oid10 nodEventsOID = {RECURSOR_STATS_OID, 147};
static const oid10 udrEventsOID = {RECURSOR_STATS_OID, 148};
+static const oid10 maxChainLengthOID = {RECURSOR_STATS_OID, 149};
+static const oid10 maxChainWeightOID = {RECURSOR_STATS_OID, 150};
static std::unordered_map<oid, std::string> s_statsMap;
registerCounter64Stat("packetcache-acquired", packetCacheAcquiredOID);
registerCounter64Stat("nod-events", nodEventsOID);
registerCounter64Stat("udr-events", udrEventsOID);
+ registerCounter64Stat("max-chain-length", maxChainLengthOID);
+ registerCounter64Stat("max-chain-weight", maxChainWeightOID);
#endif /* HAVE_NET_SNMP */
}
maintenanceCalls,
nodCount,
udrCount,
+ maxChainLength,
+ maxChainWeight,
numberOfCounters
};
addGetStat("nod-events", [] { return g_Counters.sum(rec::Counter::nodCount); });
addGetStat("udr-events", [] { return g_Counters.sum(rec::Counter::udrCount); });
+ addGetStat("max-chain-length", [] { return g_Counters.max(rec::Counter::maxChainLength); });
+ addGetStat("max-chain-weight", [] { return g_Counters.max(rec::Counter::maxChainWeight); });
+
/* make sure that the ECS stats are properly initialized */
SyncRes::clearECSStats();
for (size_t idx = 0; idx < SyncRes::s_ecsResponsesBySubnetSize4.size(); idx++) {
''',
'versionadded': '4.3.0'
},
+ {
+ 'name': 'max_chain_length',
+ 'section': 'recursor',
+ 'type': LType.Uint64,
+ 'default': '0',
+ 'help': 'maximum number of queries that can be chained to an outgoing request, 0 is no limit',
+ 'doc': '''
+The maximum number of queries that can be attached to an outgoing request chain. Attaching requests to a chain
+saves on outgoing queries, but the processing of a chain when the reply to the outgoing query comes in
+might result in a large outgoing traffic spikes. Reducing the maximum chain length mitigate this.
+If this value is zero, no maximum is enforced, though the maximum number of mthreads (:ref:`setting-max-mthreads`)
+also limits the chain length.
+''',
+ 'versionadded': ['4.8.7', '4.9.4', '5.0.3']
+ },
{
'name' : 'max_include_depth',
'section' : 'recursor',
PacketBuffer outMSG; // the outgoing message that needs to be sent
using chain_t = set<uint16_t>;
- mutable chain_t chain;
+ mutable chain_t authReqChain;
shared_ptr<TCPIOHandler> tcphandler{nullptr};
string::size_type inPos{0}; // how far are we along in the inMSG
size_t inWanted{0}; // if this is set, we'll read until inWanted bytes are read
{"udr-events",
MetricDefinition(PrometheusMetricType::counter,
"Count of UDR events")},
+
+ {"max-chain-length",
+ MetricDefinition(PrometheusMetricType::counter,
+ "Maximum chain length")},
+
+ {"max-chain-weight",
+ MetricDefinition(PrometheusMetricType::counter,
+ "Maximum chain weight")},
};
constexpr bool CHECK_PROMETHEUS_METRICS = false;
"""
def _checkStatsValues(self, results):
- count = 148
+ count = 150
for i in list(range(1, count)):
oid = self._snmpOID + '.1.' + str(i) + '.0'
self.assertTrue(oid in results)