From: Otto Moerbeek Date: Fri, 24 Nov 2023 14:29:48 +0000 (+0100) Subject: Introduce a random delay before processing a request that was chained X-Git-Tag: rec-5.1.0-beta1~22^2~5 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=14777fc4d3ce2594fef000ad8a86c02ee8596035;p=thirdparty%2Fpdns.git Introduce a random delay before processing a request that was chained --- diff --git a/pdns/recursordist/lwres.cc b/pdns/recursordist/lwres.cc index 7061b97f49..5a7182d6b5 100644 --- a/pdns/recursordist/lwres.cc +++ b/pdns/recursordist/lwres.cc @@ -538,6 +538,16 @@ static LWResult::Result asyncresolve(const ComboAddress& address, const DNSName& return ret; } + if (*chained) { + auto msec = lwr->d_usec / 1000; + if (msec > g_networkTimeoutMsec * 2 / 3) { + auto jitterMsec = dns_random(msec); + if (jitterMsec > 0) { + mthreadSleep(jitterMsec); + } + } + } + buf.resize(len); #ifdef HAVE_FSTRM diff --git a/pdns/recursordist/mtasker.hh b/pdns/recursordist/mtasker.hh index e9d936676b..72833d787c 100644 --- a/pdns/recursordist/mtasker.hh +++ b/pdns/recursordist/mtasker.hh @@ -81,6 +81,7 @@ public: } using tfunc_t = void(void*); //!< type of the pointer that starts a thread + uint64_t nextWaiterDelayUsec(uint64_t defusecs); int waitEvent(EventKey& key, EventVal* val = nullptr, unsigned int timeoutMsec = 0, const struct timeval* now = nullptr); void yield(); int sendEvent(const EventKey& key, const EventVal* val = nullptr); @@ -216,6 +217,29 @@ private: #include #endif /* PDNS_USE_VALGRIND */ +template +uint64_t MTasker::nextWaiterDelayUsec(uint64_t defusecs) +{ + if (d_waiters.empty()) { + // no waiters + return defusecs; + } + auto& ttdindex = boost::multi_index::get(d_waiters); + auto iter = ttdindex.begin(); + timeval rnow{}; + gettimeofday(&rnow, nullptr); + if (iter->ttd.tv_sec != 0) { + // we have a waiter with a timeout specified + if (rnow < iter->ttd) { + // we should not wait longer than the default timeout + return std::min(defusecs, uSec(iter->ttd - rnow)); + } + // already expired + return 0; + } + return defusecs; +} + //! puts a thread to sleep waiting until a specified event arrives /** Threads can call waitEvent to register that they are waiting on an event with a certain key. If so desired, the event can carry data which is returned in val in case that is non-zero. diff --git a/pdns/recursordist/pdns_recursor.cc b/pdns/recursordist/pdns_recursor.cc index da94b29fa9..605918181c 100644 --- a/pdns/recursordist/pdns_recursor.cc +++ b/pdns/recursordist/pdns_recursor.cc @@ -268,7 +268,7 @@ static void handleUDPServerResponse(int fileDesc, FDMultiplexer::funcparam_t& va thread_local std::unique_ptr t_udpclientsocks; // If we have plenty of mthreads slot left, use default timeout. -// Othwerwise reduce the timeout to be between g_networkTimeoutMsec/10 and g_networkTimeoutMsec +// Otherwise reduce the timeout to be between g_networkTimeoutMsec/10 and g_networkTimeoutMsec unsigned int authWaitTimeMSec(const std::unique_ptr& mtasker) { const auto max = g_maxMThreads; @@ -2872,7 +2872,7 @@ static void doResends(MT_t::waiters_t::iterator& iter, const std::shared_ptrkey->authReqChain) { + for (auto qid : iter->key->authReqChain) { auto packetID = std::make_shared(*resend); packetID->fd = -1; packetID->id = qid; @@ -2881,6 +2881,18 @@ static void doResends(MT_t::waiters_t::iterator& iter, const std::shared_ptr(); + neverHappens->id = dns_random_uint16(); + neverHappens->type = dns_random_uint16(); + neverHappens->remote = ComboAddress("100::"); // discard-only + neverHappens->remote.setPort(dns_random_uint16()); + neverHappens->fd = -1; + assert(g_multiTasker->waitEvent(neverHappens, nullptr, jitterMsec) != -1); // NOLINT +} + + static void handleUDPServerResponse(int fileDesc, FDMultiplexer::funcparam_t& var) { auto pid = boost::any_cast>(var); diff --git a/pdns/recursordist/rec-main.cc b/pdns/recursordist/rec-main.cc index f808b464a5..5784e63db3 100644 --- a/pdns/recursordist/rec-main.cc +++ b/pdns/recursordist/rec-main.cc @@ -2765,7 +2765,8 @@ static void recLoop() } runLuaMaintenance(threadInfo, last_lua_maintenance, luaMaintenanceInterval); - t_fdm->run(&g_now); + auto timeoutUsec = g_multiTasker->nextWaiterDelayUsec(500000); + t_fdm->run(&g_now, static_cast(timeoutUsec / 1000)); // 'run' updates g_now for us runTCPMaintenance(threadInfo, listenOnTCP, maxTcpClients); diff --git a/pdns/recursordist/syncres.hh b/pdns/recursordist/syncres.hh index bf9fab1b38..82bd31ad08 100644 --- a/pdns/recursordist/syncres.hh +++ b/pdns/recursordist/syncres.hh @@ -741,6 +741,7 @@ private: /* external functions, opaque to us */ LWResult::Result asendtcp(const PacketBuffer& data, shared_ptr&); LWResult::Result arecvtcp(PacketBuffer& data, size_t len, shared_ptr&, bool incompleteOkay); +void mthreadSleep(unsigned int jitterMsec); enum TCPAction : uint8_t {