mirror of
https://github.com/isc-projects/bind9.git
synced 2026-05-27 12:13:20 -04:00
[9.18] fix: usr: Limit the outgoing UDP send queue size
If the operating system UDP queue gets full and the outgoing UDP sending starts to be delayed, BIND 9 could exhibit memory spikes as it tries to enqueue all the outgoing UDP messages. Try a bit harder to deliver the outgoing UDP messages synchronously and if that fails, drop the outgoing DNS message that would get queued up and then timeout on the client side. Closes #4930 Backport of MR !9506 Merge branch 'backport-4930-limit-the-UDP-send-queue-9.18' into 'bind-9.18' See merge request isc-projects/bind9!9512
This commit is contained in:
commit
6c1fc4ae54
3 changed files with 48 additions and 4 deletions
|
|
@ -60,6 +60,7 @@
|
|||
*/
|
||||
#define ISC_NETMGR_UDP_RECVBUF_SIZE UINT16_MAX
|
||||
#endif
|
||||
#define ISC_NETMGR_UDP_SENDBUF_SIZE UINT16_MAX
|
||||
|
||||
/*
|
||||
* The TCP send and receive buffers can fit one maximum sized DNS message plus
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@
|
|||
#include <isc/buffer.h>
|
||||
#include <isc/condition.h>
|
||||
#include <isc/errno.h>
|
||||
#include <isc/log.h>
|
||||
#include <isc/magic.h>
|
||||
#include <isc/mem.h>
|
||||
#include <isc/netmgr.h>
|
||||
|
|
@ -27,6 +28,7 @@
|
|||
#include <isc/region.h>
|
||||
#include <isc/result.h>
|
||||
#include <isc/sockaddr.h>
|
||||
#include <isc/stdtime.h>
|
||||
#include <isc/thread.h>
|
||||
#include <isc/util.h>
|
||||
|
||||
|
|
@ -809,6 +811,21 @@ udp_send_cb(uv_udp_send_t *req, int status) {
|
|||
isc__nm_sendcb(sock, uvreq, result, false);
|
||||
}
|
||||
|
||||
static _Atomic(isc_stdtime_t) last_udpsends_log = 0;
|
||||
|
||||
static bool
|
||||
can_log_udp_sends(void) {
|
||||
isc_stdtime_t now;
|
||||
|
||||
isc_stdtime_get(&now);
|
||||
isc_stdtime_t last = atomic_exchange_relaxed(&last_udpsends_log, now);
|
||||
if (now != last) {
|
||||
return (true);
|
||||
}
|
||||
|
||||
return (false);
|
||||
}
|
||||
|
||||
/*
|
||||
* udp_send_direct sends buf to a peer on a socket. Sock has to be in
|
||||
* the same thread as the callee.
|
||||
|
|
@ -840,10 +857,35 @@ udp_send_direct(isc_nmsocket_t *sock, isc__nm_uvreq_t *req,
|
|||
}
|
||||
#endif
|
||||
|
||||
r = uv_udp_send(&req->uv_req.udp_send, &sock->uv_handle.udp,
|
||||
&req->uvbuf, 1, sa, udp_send_cb);
|
||||
if (r < 0) {
|
||||
return (isc__nm_uverr2result(r));
|
||||
if (uv_udp_get_send_queue_size(&sock->uv_handle.udp) >
|
||||
ISC_NETMGR_UDP_SENDBUF_SIZE)
|
||||
{
|
||||
/*
|
||||
* The kernel UDP send queue is full, try sending the UDP
|
||||
* response synchronously instead of just failing.
|
||||
*/
|
||||
r = uv_udp_try_send(&sock->uv_handle.udp, &req->uvbuf, 1, sa);
|
||||
if (r < 0) {
|
||||
if (can_log_udp_sends()) {
|
||||
isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
|
||||
ISC_LOGMODULE_NETMGR,
|
||||
ISC_LOG_ERROR,
|
||||
"Sending UDP messages failed: %s",
|
||||
isc_result_totext(
|
||||
isc__nm_uverr2result(r)));
|
||||
}
|
||||
|
||||
return (isc__nm_uverr2result(r));
|
||||
}
|
||||
|
||||
isc__nm_sendcb(sock, req, ISC_R_SUCCESS, true);
|
||||
} else {
|
||||
/* Send the message asynchronously */
|
||||
r = uv_udp_send(&req->uv_req.udp_send, &sock->uv_handle.udp,
|
||||
&req->uvbuf, 1, sa, udp_send_cb);
|
||||
if (r < 0) {
|
||||
return (isc__nm_uverr2result(r));
|
||||
}
|
||||
}
|
||||
|
||||
return (ISC_R_SUCCESS);
|
||||
|
|
|
|||
|
|
@ -127,4 +127,5 @@ isc_uv_tcp_freebind(uv_tcp_t *handle, const struct sockaddr *addr,
|
|||
|
||||
#if UV_VERSION_HEX < UV_VERSION(1, 19, 0)
|
||||
#define uv_stream_get_write_queue_size(stream) ((stream)->write_queue_size)
|
||||
#define uv_udp_get_send_queue_size(handle) ((handle)->send_queue_size)
|
||||
#endif /* UV_VERSION_HEX < UV_VERSION(1, 19, 0) */
|
||||
|
|
|
|||
Loading…
Reference in a new issue