mirror of
https://github.com/NLnetLabs/unbound.git
synced 2025-12-24 00:29:58 -05:00
- reuseport is attempted, then fallback to without on failure.
git-svn-id: file:///svn/unbound/trunk@3054 be551aaa-1e26-0410-a405-d3ace91eadb9
This commit is contained in:
parent
79dd0f33e0
commit
958b2bcf96
7 changed files with 89 additions and 50 deletions
|
|
@ -256,32 +256,52 @@ daemon_open_shared_ports(struct daemon* daemon)
|
||||||
log_assert(daemon);
|
log_assert(daemon);
|
||||||
if(daemon->cfg->port != daemon->listening_port) {
|
if(daemon->cfg->port != daemon->listening_port) {
|
||||||
size_t i;
|
size_t i;
|
||||||
#if defined(__linux__) && defined(SO_REUSEPORT)
|
int reuseport = 0;
|
||||||
if(daemon->cfg->so_reuseport && daemon->cfg->num_threads > 0)
|
struct listen_port* p0;
|
||||||
daemon->num_ports = daemon->cfg->num_threads;
|
/* free and close old ports */
|
||||||
else
|
|
||||||
daemon->num_ports = 1;
|
|
||||||
#else
|
|
||||||
daemon->num_ports = 1;
|
|
||||||
#endif
|
|
||||||
if(daemon->ports != NULL) {
|
if(daemon->ports != NULL) {
|
||||||
for(i=0; i<daemon->num_ports; i++)
|
for(i=0; i<daemon->num_ports; i++)
|
||||||
listening_ports_free(daemon->ports[i]);
|
listening_ports_free(daemon->ports[i]);
|
||||||
free(daemon->ports);
|
free(daemon->ports);
|
||||||
daemon->ports = NULL;
|
daemon->ports = NULL;
|
||||||
}
|
}
|
||||||
if(!(daemon->ports = (struct listen_port**)calloc(
|
/* see if we want to reuseport */
|
||||||
daemon->num_ports, sizeof(*daemon->ports)))) {
|
#if defined(__linux__) && defined(SO_REUSEPORT)
|
||||||
|
if(daemon->cfg->so_reuseport && daemon->cfg->num_threads > 0)
|
||||||
|
reuseport = 1;
|
||||||
|
#endif
|
||||||
|
/* try to use reuseport */
|
||||||
|
p0 = listening_ports_open(daemon->cfg, &reuseport);
|
||||||
|
if(!p0) {
|
||||||
|
listening_ports_free(p0);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
for(i=0; i<daemon->num_ports; i++) {
|
if(reuseport) {
|
||||||
if(!(daemon->ports[i]=
|
/* reuseport was successful, allocate for it */
|
||||||
listening_ports_open(daemon->cfg))) {
|
daemon->num_ports = daemon->cfg->num_threads;
|
||||||
for(i=0; i<daemon->num_ports; i++)
|
} else {
|
||||||
listening_ports_free(daemon->ports[i]);
|
/* do the normal, singleportslist thing,
|
||||||
free(daemon->ports);
|
* reuseport not enabled or did not work */
|
||||||
daemon->ports = NULL;
|
daemon->num_ports = 1;
|
||||||
return 0;
|
}
|
||||||
|
if(!(daemon->ports = (struct listen_port**)calloc(
|
||||||
|
daemon->num_ports, sizeof(*daemon->ports)))) {
|
||||||
|
listening_ports_free(p0);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
daemon->ports[0] = p0;
|
||||||
|
if(reuseport) {
|
||||||
|
/* continue to use reuseport */
|
||||||
|
for(i=1; i<daemon->num_ports; i++) {
|
||||||
|
if(!(daemon->ports[i]=
|
||||||
|
listening_ports_open(daemon->cfg,
|
||||||
|
&reuseport)) || !reuseport ) {
|
||||||
|
for(i=0; i<daemon->num_ports; i++)
|
||||||
|
listening_ports_free(daemon->ports[i]);
|
||||||
|
free(daemon->ports);
|
||||||
|
daemon->ports = NULL;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
daemon->listening_port = daemon->cfg->port;
|
daemon->listening_port = daemon->cfg->port;
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,6 @@
|
||||||
|
27 January 2014: Wouter
|
||||||
|
- reuseport is attempted, then fallback to without on failure.
|
||||||
|
|
||||||
24 January 2014: Wouter
|
24 January 2014: Wouter
|
||||||
- Change unbound-event.h to use void* buffer, length idiom.
|
- Change unbound-event.h to use void* buffer, length idiom.
|
||||||
- iana portlist updated.
|
- iana portlist updated.
|
||||||
|
|
|
||||||
|
|
@ -254,7 +254,10 @@ to so\-rcvbuf.
|
||||||
If yes, then open dedicated listening sockets for incoming queries for each
|
If yes, then open dedicated listening sockets for incoming queries for each
|
||||||
thread and try to set the SO_REUSEPORT socket option on each socket. May
|
thread and try to set the SO_REUSEPORT socket option on each socket. May
|
||||||
distribute incoming queries to threads more evenly. Default is no. Only
|
distribute incoming queries to threads more evenly. Default is no. Only
|
||||||
supported on Linux >= 3.9.
|
supported on Linux >= 3.9. You can enable it (on any platform and kernel),
|
||||||
|
it then attempts to open the port and passes the option if it was available
|
||||||
|
at compile time, if that works it is used, if it fails, it continues
|
||||||
|
silently (unless verbosity 3) without the option.
|
||||||
.TP
|
.TP
|
||||||
.B rrset\-cache\-size: \fI<number>
|
.B rrset\-cache\-size: \fI<number>
|
||||||
Number of bytes size of the RRset cache. Default is 4 megabytes.
|
Number of bytes size of the RRset cache. Default is 4 megabytes.
|
||||||
|
|
|
||||||
|
|
@ -92,7 +92,7 @@ verbose_print_addr(struct addrinfo *addr)
|
||||||
int
|
int
|
||||||
create_udp_sock(int family, int socktype, struct sockaddr* addr,
|
create_udp_sock(int family, int socktype, struct sockaddr* addr,
|
||||||
socklen_t addrlen, int v6only, int* inuse, int* noproto,
|
socklen_t addrlen, int v6only, int* inuse, int* noproto,
|
||||||
int rcv, int snd, int listen, int reuseport)
|
int rcv, int snd, int listen, int* reuseport)
|
||||||
{
|
{
|
||||||
int s;
|
int s;
|
||||||
#if defined(SO_REUSEADDR) || defined(SO_REUSEPORT) || defined(IPV6_USE_MIN_MTU)
|
#if defined(SO_REUSEADDR) || defined(SO_REUSEPORT) || defined(IPV6_USE_MIN_MTU)
|
||||||
|
|
@ -154,15 +154,16 @@ create_udp_sock(int family, int socktype, struct sockaddr* addr,
|
||||||
* Each thread must have its own socket bound to the same port,
|
* Each thread must have its own socket bound to the same port,
|
||||||
* with SO_REUSEPORT set on each socket.
|
* with SO_REUSEPORT set on each socket.
|
||||||
*/
|
*/
|
||||||
if (reuseport &&
|
if (reuseport && *reuseport &&
|
||||||
setsockopt(s, SOL_SOCKET, SO_REUSEPORT, (void*)&on,
|
setsockopt(s, SOL_SOCKET, SO_REUSEPORT, (void*)&on,
|
||||||
(socklen_t)sizeof(on)) < 0) {
|
(socklen_t)sizeof(on)) < 0) {
|
||||||
log_err("setsockopt(.. SO_REUSEPORT ..) failed: %s",
|
#ifdef ENOPROTOOPT
|
||||||
strerror(errno));
|
if(errno != ENOPROTOOPT || verbosity >= 3)
|
||||||
close(s);
|
log_warn("setsockopt(.. SO_REUSEPORT ..) failed: %s",
|
||||||
*noproto = 0;
|
strerror(errno));
|
||||||
*inuse = 0;
|
#endif
|
||||||
return -1;
|
/* this option is not essential, we can continue */
|
||||||
|
*reuseport = 0;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
(void)reuseport;
|
(void)reuseport;
|
||||||
|
|
@ -431,7 +432,7 @@ create_udp_sock(int family, int socktype, struct sockaddr* addr,
|
||||||
|
|
||||||
int
|
int
|
||||||
create_tcp_accept_sock(struct addrinfo *addr, int v6only, int* noproto,
|
create_tcp_accept_sock(struct addrinfo *addr, int v6only, int* noproto,
|
||||||
int reuseport)
|
int* reuseport)
|
||||||
{
|
{
|
||||||
int s;
|
int s;
|
||||||
#if defined(SO_REUSEADDR) || defined(SO_REUSEPORT) || defined(IPV6_V6ONLY)
|
#if defined(SO_REUSEADDR) || defined(SO_REUSEPORT) || defined(IPV6_V6ONLY)
|
||||||
|
|
@ -478,12 +479,16 @@ create_tcp_accept_sock(struct addrinfo *addr, int v6only, int* noproto,
|
||||||
* Each thread must have its own socket bound to the same port,
|
* Each thread must have its own socket bound to the same port,
|
||||||
* with SO_REUSEPORT set on each socket.
|
* with SO_REUSEPORT set on each socket.
|
||||||
*/
|
*/
|
||||||
if (reuseport && setsockopt(s, SOL_SOCKET, SO_REUSEPORT, (void*)&on,
|
if (reuseport && *reuseport &&
|
||||||
|
setsockopt(s, SOL_SOCKET, SO_REUSEPORT, (void*)&on,
|
||||||
(socklen_t)sizeof(on)) < 0) {
|
(socklen_t)sizeof(on)) < 0) {
|
||||||
log_err("setsockopt(.. SO_REUSEPORT ..) failed: %s",
|
#ifdef ENOPROTOOPT
|
||||||
strerror(errno));
|
if(errno != ENOPROTOOPT || verbosity >= 3)
|
||||||
close(s);
|
log_warn("setsockopt(.. SO_REUSEPORT ..) failed: %s",
|
||||||
return -1;
|
strerror(errno));
|
||||||
|
#endif
|
||||||
|
/* this option is not essential, we can continue */
|
||||||
|
*reuseport = 0;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
(void)reuseport;
|
(void)reuseport;
|
||||||
|
|
@ -556,7 +561,7 @@ create_tcp_accept_sock(struct addrinfo *addr, int v6only, int* noproto,
|
||||||
static int
|
static int
|
||||||
make_sock(int stype, const char* ifname, const char* port,
|
make_sock(int stype, const char* ifname, const char* port,
|
||||||
struct addrinfo *hints, int v6only, int* noip6, size_t rcv, size_t snd,
|
struct addrinfo *hints, int v6only, int* noip6, size_t rcv, size_t snd,
|
||||||
int reuseport)
|
int* reuseport)
|
||||||
{
|
{
|
||||||
struct addrinfo *res = NULL;
|
struct addrinfo *res = NULL;
|
||||||
int r, s, inuse, noproto;
|
int r, s, inuse, noproto;
|
||||||
|
|
@ -604,7 +609,7 @@ make_sock(int stype, const char* ifname, const char* port,
|
||||||
static int
|
static int
|
||||||
make_sock_port(int stype, const char* ifname, const char* port,
|
make_sock_port(int stype, const char* ifname, const char* port,
|
||||||
struct addrinfo *hints, int v6only, int* noip6, size_t rcv, size_t snd,
|
struct addrinfo *hints, int v6only, int* noip6, size_t rcv, size_t snd,
|
||||||
int reuseport)
|
int* reuseport)
|
||||||
{
|
{
|
||||||
char* s = strchr(ifname, '@');
|
char* s = strchr(ifname, '@');
|
||||||
if(s) {
|
if(s) {
|
||||||
|
|
@ -721,13 +726,14 @@ set_recvpktinfo(int s, int family)
|
||||||
* @param rcv: receive buffer size for UDP
|
* @param rcv: receive buffer size for UDP
|
||||||
* @param snd: send buffer size for UDP
|
* @param snd: send buffer size for UDP
|
||||||
* @param ssl_port: ssl service port number
|
* @param ssl_port: ssl service port number
|
||||||
* @param reuseport: try to set SO_REUSEPORT.
|
* @param reuseport: try to set SO_REUSEPORT if nonNULL and true.
|
||||||
|
* set to false on exit if reuseport failed due to no kernel support.
|
||||||
* @return: returns false on error.
|
* @return: returns false on error.
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
ports_create_if(const char* ifname, int do_auto, int do_udp, int do_tcp,
|
ports_create_if(const char* ifname, int do_auto, int do_udp, int do_tcp,
|
||||||
struct addrinfo *hints, const char* port, struct listen_port** list,
|
struct addrinfo *hints, const char* port, struct listen_port** list,
|
||||||
size_t rcv, size_t snd, int ssl_port, int reuseport)
|
size_t rcv, size_t snd, int ssl_port, int* reuseport)
|
||||||
{
|
{
|
||||||
int s, noip6=0;
|
int s, noip6=0;
|
||||||
if(!do_udp && !do_tcp)
|
if(!do_udp && !do_tcp)
|
||||||
|
|
@ -901,7 +907,7 @@ listen_delete(struct listen_dnsport* front)
|
||||||
}
|
}
|
||||||
|
|
||||||
struct listen_port*
|
struct listen_port*
|
||||||
listening_ports_open(struct config_file* cfg)
|
listening_ports_open(struct config_file* cfg, int* reuseport)
|
||||||
{
|
{
|
||||||
struct listen_port* list = NULL;
|
struct listen_port* list = NULL;
|
||||||
struct addrinfo hints;
|
struct addrinfo hints;
|
||||||
|
|
@ -937,7 +943,7 @@ listening_ports_open(struct config_file* cfg)
|
||||||
do_auto, cfg->do_udp, do_tcp,
|
do_auto, cfg->do_udp, do_tcp,
|
||||||
&hints, portbuf, &list,
|
&hints, portbuf, &list,
|
||||||
cfg->so_rcvbuf, cfg->so_sndbuf,
|
cfg->so_rcvbuf, cfg->so_sndbuf,
|
||||||
cfg->ssl_port, cfg->so_reuseport)) {
|
cfg->ssl_port, reuseport)) {
|
||||||
listening_ports_free(list);
|
listening_ports_free(list);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
@ -948,7 +954,7 @@ listening_ports_open(struct config_file* cfg)
|
||||||
do_auto, cfg->do_udp, do_tcp,
|
do_auto, cfg->do_udp, do_tcp,
|
||||||
&hints, portbuf, &list,
|
&hints, portbuf, &list,
|
||||||
cfg->so_rcvbuf, cfg->so_sndbuf,
|
cfg->so_rcvbuf, cfg->so_sndbuf,
|
||||||
cfg->ssl_port, cfg->so_reuseport)) {
|
cfg->ssl_port, reuseport)) {
|
||||||
listening_ports_free(list);
|
listening_ports_free(list);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
@ -961,7 +967,7 @@ listening_ports_open(struct config_file* cfg)
|
||||||
if(!ports_create_if(cfg->ifs[i], 0, cfg->do_udp,
|
if(!ports_create_if(cfg->ifs[i], 0, cfg->do_udp,
|
||||||
do_tcp, &hints, portbuf, &list,
|
do_tcp, &hints, portbuf, &list,
|
||||||
cfg->so_rcvbuf, cfg->so_sndbuf,
|
cfg->so_rcvbuf, cfg->so_sndbuf,
|
||||||
cfg->ssl_port, cfg->so_reuseport)) {
|
cfg->ssl_port, reuseport)) {
|
||||||
listening_ports_free(list);
|
listening_ports_free(list);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
@ -972,7 +978,7 @@ listening_ports_open(struct config_file* cfg)
|
||||||
if(!ports_create_if(cfg->ifs[i], 0, cfg->do_udp,
|
if(!ports_create_if(cfg->ifs[i], 0, cfg->do_udp,
|
||||||
do_tcp, &hints, portbuf, &list,
|
do_tcp, &hints, portbuf, &list,
|
||||||
cfg->so_rcvbuf, cfg->so_sndbuf,
|
cfg->so_rcvbuf, cfg->so_sndbuf,
|
||||||
cfg->ssl_port, cfg->so_reuseport)) {
|
cfg->ssl_port, reuseport)) {
|
||||||
listening_ports_free(list);
|
listening_ports_free(list);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -107,9 +107,13 @@ struct listen_port {
|
||||||
* interfaces for IP4 and/or IP6, for UDP and/or TCP.
|
* interfaces for IP4 and/or IP6, for UDP and/or TCP.
|
||||||
* On the given port number. It creates the sockets.
|
* On the given port number. It creates the sockets.
|
||||||
* @param cfg: settings on what ports to open.
|
* @param cfg: settings on what ports to open.
|
||||||
|
* @param reuseport: set to true if you want reuseport, or NULL to not have it,
|
||||||
|
* set to false on exit if reuseport failed to apply (because of no
|
||||||
|
* kernel support).
|
||||||
* @return: linked list of ports or NULL on error.
|
* @return: linked list of ports or NULL on error.
|
||||||
*/
|
*/
|
||||||
struct listen_port* listening_ports_open(struct config_file* cfg);
|
struct listen_port* listening_ports_open(struct config_file* cfg,
|
||||||
|
int* reuseport);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Close and delete the (list of) listening ports.
|
* Close and delete the (list of) listening ports.
|
||||||
|
|
@ -181,22 +185,24 @@ void listen_start_accept(struct listen_dnsport* listen);
|
||||||
* @param snd: set size on sndbuf with socket option, if 0 it is not set.
|
* @param snd: set size on sndbuf with socket option, if 0 it is not set.
|
||||||
* @param listen: if true, this is a listening UDP port, eg port 53, and
|
* @param listen: if true, this is a listening UDP port, eg port 53, and
|
||||||
* set SO_REUSEADDR on it.
|
* set SO_REUSEADDR on it.
|
||||||
* @param reuseport: if true, try to set SO_REUSEPORT on listening UDP port.
|
* @param reuseport: if nonNULL and true, try to set SO_REUSEPORT on
|
||||||
|
* listening UDP port. Set to false on return if it failed to do so.
|
||||||
* @return: the socket. -1 on error.
|
* @return: the socket. -1 on error.
|
||||||
*/
|
*/
|
||||||
int create_udp_sock(int family, int socktype, struct sockaddr* addr,
|
int create_udp_sock(int family, int socktype, struct sockaddr* addr,
|
||||||
socklen_t addrlen, int v6only, int* inuse, int* noproto, int rcv,
|
socklen_t addrlen, int v6only, int* inuse, int* noproto, int rcv,
|
||||||
int snd, int listen, int reuseport);
|
int snd, int listen, int* reuseport);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create and bind TCP listening socket
|
* Create and bind TCP listening socket
|
||||||
* @param addr: address info ready to make socket.
|
* @param addr: address info ready to make socket.
|
||||||
* @param v6only: enable ip6 only flag on ip6 sockets.
|
* @param v6only: enable ip6 only flag on ip6 sockets.
|
||||||
* @param noproto: if error caused by lack of protocol support.
|
* @param noproto: if error caused by lack of protocol support.
|
||||||
* @param reuseport: if true, try to set SO_REUSEPORT.
|
* @param reuseport: if nonNULL and true, try to set SO_REUSEPORT on
|
||||||
|
* listening UDP port. Set to false on return if it failed to do so.
|
||||||
* @return: the socket. -1 on error.
|
* @return: the socket. -1 on error.
|
||||||
*/
|
*/
|
||||||
int create_tcp_accept_sock(struct addrinfo *addr, int v6only, int* noproto,
|
int create_tcp_accept_sock(struct addrinfo *addr, int v6only, int* noproto,
|
||||||
int reuseport);
|
int* reuseport);
|
||||||
|
|
||||||
#endif /* LISTEN_DNSPORT_H */
|
#endif /* LISTEN_DNSPORT_H */
|
||||||
|
|
|
||||||
|
|
@ -849,13 +849,13 @@ udp_sockport(struct sockaddr_storage* addr, socklen_t addrlen, int port,
|
||||||
sa->sin6_port = (in_port_t)htons((uint16_t)port);
|
sa->sin6_port = (in_port_t)htons((uint16_t)port);
|
||||||
fd = create_udp_sock(AF_INET6, SOCK_DGRAM,
|
fd = create_udp_sock(AF_INET6, SOCK_DGRAM,
|
||||||
(struct sockaddr*)addr, addrlen, 1, inuse, &noproto,
|
(struct sockaddr*)addr, addrlen, 1, inuse, &noproto,
|
||||||
0, 0, 0, 0);
|
0, 0, 0, NULL);
|
||||||
} else {
|
} else {
|
||||||
struct sockaddr_in* sa = (struct sockaddr_in*)addr;
|
struct sockaddr_in* sa = (struct sockaddr_in*)addr;
|
||||||
sa->sin_port = (in_port_t)htons((uint16_t)port);
|
sa->sin_port = (in_port_t)htons((uint16_t)port);
|
||||||
fd = create_udp_sock(AF_INET, SOCK_DGRAM,
|
fd = create_udp_sock(AF_INET, SOCK_DGRAM,
|
||||||
(struct sockaddr*)addr, addrlen, 1, inuse, &noproto,
|
(struct sockaddr*)addr, addrlen, 1, inuse, &noproto,
|
||||||
0, 0, 0, 0);
|
0, 0, 0, NULL);
|
||||||
}
|
}
|
||||||
return fd;
|
return fd;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1142,7 +1142,8 @@ void outnet_serviced_query_stop(struct serviced_query* sq, void* cb_arg)
|
||||||
log_info("double delete of pending serviced query");
|
log_info("double delete of pending serviced query");
|
||||||
}
|
}
|
||||||
|
|
||||||
struct listen_port* listening_ports_open(struct config_file* ATTR_UNUSED(cfg))
|
struct listen_port* listening_ports_open(struct config_file* ATTR_UNUSED(cfg),
|
||||||
|
int* ATTR_UNUSED(reuseport))
|
||||||
{
|
{
|
||||||
return calloc(1, 1);
|
return calloc(1, 1);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue