From: Remi Gacogne Date: Tue, 16 Aug 2022 15:07:14 +0000 (+0200) Subject: dnsdist: Make recording queries/responses in the ringbuffers optional X-Git-Tag: rec-4.8.0-alpha1~38^2~1 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=0619a17f2429d8fb111bea305893f67b0f41d067;p=thirdparty%2Fpdns.git dnsdist: Make recording queries/responses in the ringbuffers optional --- diff --git a/pdns/dnsdist-console.cc b/pdns/dnsdist-console.cc index 40415a4ae3..0f9998e050 100644 --- a/pdns/dnsdist-console.cc +++ b/pdns/dnsdist-console.cc @@ -686,6 +686,7 @@ const std::vector g_consoleKeywords{ { "setQueryCount", true, "bool", "set whether queries should be counted" }, { "setQueryCountFilter", true, "func", "filter queries that would be counted, where `func` is a function with parameter `dq` which decides whether a query should and how it should be counted" }, { "setRingBuffersLockRetries", true, "n", "set the number of attempts to get a non-blocking lock to a ringbuffer shard before blocking" }, + { "setRingBuffersOptions", true, "{ lockRetries=int, recordQueries=true, recordResponses=true }", "set ringbuffer options" }, { "setRingBuffersSize", true, "n [, numberOfShards]", "set the capacity of the ringbuffers used for live traffic inspection to `n`, and optionally the number of shards to use to `numberOfShards`" }, { "setRoundRobinFailOnNoServer", true, "value", "By default the roundrobin load-balancing policy will still try to select a backend even if all backends are currently down. Setting this to true will make the policy fail and return that no server is available instead" }, { "setRules", true, "list of rules", "replace the current rules with the supplied list of pairs of DNS Rules and DNS Actions (see `newRuleAction()`)" }, diff --git a/pdns/dnsdist-lua.cc b/pdns/dnsdist-lua.cc index d77ddf51cb..c81cb6cbde 100644 --- a/pdns/dnsdist-lua.cc +++ b/pdns/dnsdist-lua.cc @@ -2017,6 +2017,27 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck) g_rings.setNumberOfLockRetries(retries); }); + luaCtx.writeFunction("setRingBuffersOptions", [](const LuaAssociativeTable>& options) { + setLuaSideEffect(); + if (g_configurationDone) { + errlog("setRingBuffersOptions() cannot be used at runtime!"); + g_outputBuffer = "setRingBuffersOptions() cannot be used at runtime!\n"; + return; + } + if (options.count("lockRetries") > 0) { + auto retries = boost::get(options.at("lockRetries")); + g_rings.setNumberOfLockRetries(retries); + } + if (options.count("recordQueries") > 0) { + auto record = boost::get(options.at("recordQueries")); + g_rings.setRecordQueries(record); + } + if (options.count("recordResponses") > 0) { + auto record = boost::get(options.at("recordResponses")); + g_rings.setRecordResponses(record); + } + }); + luaCtx.writeFunction("setWHashedPertubation", [](uint64_t perturb) { setLuaSideEffect(); checkParameterBound("setWHashedPertubation", perturb, std::numeric_limits::max()); diff --git a/pdns/dnsdist-rings.cc b/pdns/dnsdist-rings.cc index fabbd4d043..5485b33869 100644 --- a/pdns/dnsdist-rings.cc +++ b/pdns/dnsdist-rings.cc @@ -48,8 +48,12 @@ void Rings::init() /* resize all the rings */ for (auto& shard : d_shards) { shard = std::make_unique(); - shard->queryRing.lock()->set_capacity(d_capacity / d_numberOfShards); - shard->respRing.lock()->set_capacity(d_capacity / d_numberOfShards); + if (shouldRecordQueries()) { + shard->queryRing.lock()->set_capacity(d_capacity / d_numberOfShards); + } + if (shouldRecordResponses()) { + shard->respRing.lock()->set_capacity(d_capacity / d_numberOfShards); + } } /* we just recreated the shards so they are now empty */ @@ -66,6 +70,16 @@ void Rings::setNumberOfLockRetries(size_t retries) } } +void Rings::setRecordQueries(bool record) +{ + d_recordQueries = record; +} + +void Rings::setRecordResponses(bool record) +{ + d_recordResponses = record; +} + size_t Rings::numDistinctRequestors() { std::set s; diff --git a/pdns/dnsdist-rings.hh b/pdns/dnsdist-rings.hh index 2f66e5689d..c8b0d32dd0 100644 --- a/pdns/dnsdist-rings.hh +++ b/pdns/dnsdist-rings.hh @@ -82,6 +82,8 @@ struct Rings { void init(); void setNumberOfLockRetries(size_t retries); + void setRecordQueries(bool); + void setRecordResponses(bool); size_t getNumberOfShards() const { @@ -186,6 +188,16 @@ struct Rings { only useful for debugging purposes */ size_t loadFromFile(const std::string& filepath, const struct timespec& now); + bool shouldRecordQueries() const + { + return d_recordQueries; + } + + bool shouldRecordResponses() const + { + return d_recordResponses; + } + std::vector > d_shards; pdns::stat_t d_blockingQueryInserts; pdns::stat_t d_blockingResponseInserts; @@ -240,6 +252,8 @@ private: size_t d_numberOfShards; size_t d_nbLockTries = 5; bool d_keepLockingStats{false}; + bool d_recordQueries{true}; + bool d_recordResponses{true}; }; extern Rings g_rings; diff --git a/pdns/dnsdist.cc b/pdns/dnsdist.cc index d82a205eb7..dcbfc9e1c6 100644 --- a/pdns/dnsdist.cc +++ b/pdns/dnsdist.cc @@ -606,9 +606,11 @@ void handleResponseSent(const IDState& ids, double udiff, const ComboAddress& cl void handleResponseSent(const DNSName& qname, const QType& qtype, double udiff, const ComboAddress& client, const ComboAddress& backend, unsigned int size, const dnsheader& cleartextDH, dnsdist::Protocol outgoingProtocol, dnsdist::Protocol incomingProtocol) { - struct timespec ts; - gettime(&ts); - g_rings.insertResponse(ts, client, qname, qtype, static_cast(udiff), size, cleartextDH, backend, outgoingProtocol); + if (g_rings.shouldRecordResponses()) { + struct timespec ts; + gettime(&ts); + g_rings.insertResponse(ts, client, qname, qtype, static_cast(udiff), size, cleartextDH, backend, outgoingProtocol); + } switch (cleartextDH.rcode) { case RCode::NXDomain: @@ -914,7 +916,9 @@ bool processRulesResult(const DNSAction::Action& action, DNSQuestion& dq, std::s static bool applyRulesToQuery(LocalHolders& holders, DNSQuestion& dq, const struct timespec& now) { - g_rings.insertQuery(now, *dq.remote, *dq.qname, dq.qtype, dq.getData().size(), *dq.getHeader(), dq.getProtocol()); + if (g_rings.shouldRecordQueries()) { + g_rings.insertQuery(now, *dq.remote, *dq.qname, dq.qtype, dq.getData().size(), *dq.getHeader(), dq.getProtocol()); + } if (g_qcount.enabled) { string qname = (*dq.qname).toLogString(); diff --git a/pdns/dnsdistdist/dnsdist-backend.cc b/pdns/dnsdistdist/dnsdist-backend.cc index 005eaa3b81..dfebb8efca 100644 --- a/pdns/dnsdistdist/dnsdist-backend.cc +++ b/pdns/dnsdistdist/dnsdist-backend.cc @@ -339,14 +339,16 @@ void DownstreamState::handleTimeout(IDState& ids) d_config.remote.toStringWithPort(), getName(), ids.qname.toLogString(), QType(ids.qtype).toString(), ids.origRemote.toStringWithPort()); - struct timespec ts; - gettime(&ts); + if (g_rings.shouldRecordResponses()) { + struct timespec ts; + gettime(&ts); - struct dnsheader fake; - memset(&fake, 0, sizeof(fake)); - fake.id = ids.origID; + struct dnsheader fake; + memset(&fake, 0, sizeof(fake)); + fake.id = ids.origID; - g_rings.insertResponse(ts, ids.origRemote, ids.qname, ids.qtype, std::numeric_limits::max(), 0, fake, d_config.remote, getProtocol()); + g_rings.insertResponse(ts, ids.origRemote, ids.qname, ids.qtype, std::numeric_limits::max(), 0, fake, d_config.remote, getProtocol()); + } } void DownstreamState::handleTimeouts() diff --git a/pdns/dnsdistdist/docs/reference/config.rst b/pdns/dnsdistdist/docs/reference/config.rst index c7e11ee224..eb9117b8a5 100644 --- a/pdns/dnsdistdist/docs/reference/config.rst +++ b/pdns/dnsdistdist/docs/reference/config.rst @@ -507,6 +507,20 @@ Ringbuffers :param int num: The maximum number of attempts. Defaults to 5 if there is more than one shard, 0 otherwise. +.. function:: setRingBuffersOptions(options) + + .. versionadded:: 1.8.0 + + Set the rings buffers configuration + + :param table options: A table with key: value pairs with options. + + Options: + + * ``lockRetries``: int - Set the number of shards to attempt to lock without blocking before giving up and simply blocking while waiting for the next shard to be available. Default to 5 if there is more than one shard, 0 otherwise + * ``recordQueries``: boolean - Whether to record queries in the ring buffers. Default is true. Note that :func:`grepq`, several top* commands (:func:`topClients`, :func:`topQueries`, ...) and the :doc:`Dynamic Blocks <../guides/dynblocks>` require this to be enabled. + * ``recordResponses``: boolean - Whether to record responses in the ring buffers. Default is true. Note that :func:`grepq`, several top* commands (:func:`topResponses`, :func:`topSlow`, ...) and the :doc:`Dynamic Blocks <../guides/dynblocks>` require this to be enabled. + .. function:: setRingBuffersSize(num [, numberOfShards]) .. versionchanged:: 1.6.0