diff --git a/lib/isc/netmgr/netmgr-int.h b/lib/isc/netmgr/netmgr-int.h index c13b6fae99..f4cb5dd8fc 100644 --- a/lib/isc/netmgr/netmgr-int.h +++ b/lib/isc/netmgr/netmgr-int.h @@ -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 diff --git a/lib/isc/netmgr/udp.c b/lib/isc/netmgr/udp.c index 1956a185ef..f9f528ffb1 100644 --- a/lib/isc/netmgr/udp.c +++ b/lib/isc/netmgr/udp.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -27,6 +28,7 @@ #include #include #include +#include #include #include @@ -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); diff --git a/lib/isc/netmgr/uv-compat.h b/lib/isc/netmgr/uv-compat.h index f0a0d2de00..ec99208830 100644 --- a/lib/isc/netmgr/uv-compat.h +++ b/lib/isc/netmgr/uv-compat.h @@ -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) */