linux,udp: enable full ICMP error reporting
The Linux kernel suppresses some ICMP error messages by default for UDP sockets. This commit sets IP_RECVERR/IPV6_RECVERR on the socket to enable full ICMP error reporting, hopefully resulting in faster failover to working name servers. PR-URL: https://github.com/libuv/libuv/pull/2872 Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl> Reviewed-By: Santiago Gimeno <santiago.gimeno@gmail.com>
This commit is contained in:
parent
c464d21323
commit
c382d39a85
@ -53,6 +53,14 @@ Data types
|
|||||||
* in uv_udp_recv_cb, nread will always be 0 and addr will always be NULL.
|
* in uv_udp_recv_cb, nread will always be 0 and addr will always be NULL.
|
||||||
*/
|
*/
|
||||||
UV_UDP_MMSG_FREE = 16,
|
UV_UDP_MMSG_FREE = 16,
|
||||||
|
/*
|
||||||
|
* Indicates if IP_RECVERR/IPV6_RECVERR will be set when binding the handle.
|
||||||
|
* This sets IP_RECVERR for IPv4 and IPV6_RECVERR for IPv6 UDP sockets on
|
||||||
|
* Linux. This stops the Linux kernel from supressing some ICMP error messages
|
||||||
|
* and enables full ICMP error reporting for faster failover.
|
||||||
|
* This flag is no-op on platforms other than Linux.
|
||||||
|
*/
|
||||||
|
UV_UDP_LINUX_RECVERR = 32,
|
||||||
/*
|
/*
|
||||||
* Indicates that recvmmsg should be used, if available.
|
* Indicates that recvmmsg should be used, if available.
|
||||||
*/
|
*/
|
||||||
@ -178,7 +186,8 @@ API
|
|||||||
with the address and port to bind to.
|
with the address and port to bind to.
|
||||||
|
|
||||||
:param flags: Indicate how the socket will be bound,
|
:param flags: Indicate how the socket will be bound,
|
||||||
``UV_UDP_IPV6ONLY`` and ``UV_UDP_REUSEADDR`` are supported.
|
``UV_UDP_IPV6ONLY``, ``UV_UDP_REUSEADDR``, and ``UV_UDP_RECVERR``
|
||||||
|
are supported.
|
||||||
|
|
||||||
:returns: 0 on success, or an error code < 0 on failure.
|
:returns: 0 on success, or an error code < 0 on failure.
|
||||||
|
|
||||||
|
|||||||
@ -626,7 +626,14 @@ enum uv_udp_flags {
|
|||||||
* in uv_udp_recv_cb, nread will always be 0 and addr will always be NULL.
|
* in uv_udp_recv_cb, nread will always be 0 and addr will always be NULL.
|
||||||
*/
|
*/
|
||||||
UV_UDP_MMSG_FREE = 16,
|
UV_UDP_MMSG_FREE = 16,
|
||||||
|
/*
|
||||||
|
* Indicates if IP_RECVERR/IPV6_RECVERR will be set when binding the handle.
|
||||||
|
* This sets IP_RECVERR for IPv4 and IPV6_RECVERR for IPv6 UDP sockets on
|
||||||
|
* Linux. This stops the Linux kernel from supressing some ICMP error messages
|
||||||
|
* and enables full ICMP error reporting for faster failover.
|
||||||
|
* This flag is no-op on platforms other than Linux.
|
||||||
|
*/
|
||||||
|
UV_UDP_LINUX_RECVERR = 32,
|
||||||
/*
|
/*
|
||||||
* Indicates that recvmmsg should be used, if available.
|
* Indicates that recvmmsg should be used, if available.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -504,6 +504,28 @@ static int uv__set_reuse(int fd) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The Linux kernel suppresses some ICMP error messages by default for UDP
|
||||||
|
* sockets. Setting IP_RECVERR/IPV6_RECVERR on the socket enables full ICMP
|
||||||
|
* error reporting, hopefully resulting in faster failover to working name
|
||||||
|
* servers.
|
||||||
|
*/
|
||||||
|
static int uv__set_recverr(int fd, sa_family_t ss_family) {
|
||||||
|
#if defined(__linux__)
|
||||||
|
int yes;
|
||||||
|
|
||||||
|
yes = 1;
|
||||||
|
if (ss_family == AF_INET) {
|
||||||
|
if (setsockopt(fd, IPPROTO_IP, IP_RECVERR, &yes, sizeof(yes)))
|
||||||
|
return UV__ERR(errno);
|
||||||
|
} else if (ss_family == AF_INET6) {
|
||||||
|
if (setsockopt(fd, IPPROTO_IPV6, IPV6_RECVERR, &yes, sizeof(yes)))
|
||||||
|
return UV__ERR(errno);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int uv__udp_bind(uv_udp_t* handle,
|
int uv__udp_bind(uv_udp_t* handle,
|
||||||
const struct sockaddr* addr,
|
const struct sockaddr* addr,
|
||||||
@ -514,7 +536,7 @@ int uv__udp_bind(uv_udp_t* handle,
|
|||||||
int fd;
|
int fd;
|
||||||
|
|
||||||
/* Check for bad flags. */
|
/* Check for bad flags. */
|
||||||
if (flags & ~(UV_UDP_IPV6ONLY | UV_UDP_REUSEADDR))
|
if (flags & ~(UV_UDP_IPV6ONLY | UV_UDP_REUSEADDR | UV_UDP_LINUX_RECVERR))
|
||||||
return UV_EINVAL;
|
return UV_EINVAL;
|
||||||
|
|
||||||
/* Cannot set IPv6-only mode on non-IPv6 socket. */
|
/* Cannot set IPv6-only mode on non-IPv6 socket. */
|
||||||
@ -530,6 +552,12 @@ int uv__udp_bind(uv_udp_t* handle,
|
|||||||
handle->io_watcher.fd = fd;
|
handle->io_watcher.fd = fd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (flags & UV_UDP_LINUX_RECVERR) {
|
||||||
|
err = uv__set_recverr(fd, addr->sa_family);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
if (flags & UV_UDP_REUSEADDR) {
|
if (flags & UV_UDP_REUSEADDR) {
|
||||||
err = uv__set_reuse(fd);
|
err = uv__set_reuse(fd);
|
||||||
if (err)
|
if (err)
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user