mirror of
https://github.com/NLnetLabs/unbound.git
synced 2025-12-20 23:00:56 -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);
|
||||
if(daemon->cfg->port != daemon->listening_port) {
|
||||
size_t i;
|
||||
#if defined(__linux__) && defined(SO_REUSEPORT)
|
||||
if(daemon->cfg->so_reuseport && daemon->cfg->num_threads > 0)
|
||||
daemon->num_ports = daemon->cfg->num_threads;
|
||||
else
|
||||
daemon->num_ports = 1;
|
||||
#else
|
||||
daemon->num_ports = 1;
|
||||
#endif
|
||||
int reuseport = 0;
|
||||
struct listen_port* p0;
|
||||
/* free and close old ports */
|
||||
if(daemon->ports != NULL) {
|
||||
for(i=0; i<daemon->num_ports; i++)
|
||||
listening_ports_free(daemon->ports[i]);
|
||||
free(daemon->ports);
|
||||
daemon->ports = NULL;
|
||||
}
|
||||
if(!(daemon->ports = (struct listen_port**)calloc(
|
||||
daemon->num_ports, sizeof(*daemon->ports)))) {
|
||||
/* see if we want to reuseport */
|
||||
#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;
|
||||
}
|
||||
for(i=0; i<daemon->num_ports; i++) {
|
||||
if(!(daemon->ports[i]=
|
||||
listening_ports_open(daemon->cfg))) {
|
||||
for(i=0; i<daemon->num_ports; i++)
|
||||
listening_ports_free(daemon->ports[i]);
|
||||
free(daemon->ports);
|
||||
daemon->ports = NULL;
|
||||
return 0;
|
||||
if(reuseport) {
|
||||
/* reuseport was successful, allocate for it */
|
||||
daemon->num_ports = daemon->cfg->num_threads;
|
||||
} else {
|
||||
/* do the normal, singleportslist thing,
|
||||
* reuseport not enabled or did not work */
|
||||
daemon->num_ports = 1;
|
||||
}
|
||||
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;
|
||||
|
|
|
|||
|
|
@ -1,3 +1,6 @@
|
|||
27 January 2014: Wouter
|
||||
- reuseport is attempted, then fallback to without on failure.
|
||||
|
||||
24 January 2014: Wouter
|
||||
- Change unbound-event.h to use void* buffer, length idiom.
|
||||
- iana portlist updated.
|
||||
|
|
|
|||
|
|
@ -254,7 +254,10 @@ to so\-rcvbuf.
|
|||
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
|
||||
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
|
||||
.B rrset\-cache\-size: \fI<number>
|
||||
Number of bytes size of the RRset cache. Default is 4 megabytes.
|
||||
|
|
|
|||
|
|
@ -92,7 +92,7 @@ verbose_print_addr(struct addrinfo *addr)
|
|||
int
|
||||
create_udp_sock(int family, int socktype, struct sockaddr* addr,
|
||||
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;
|
||||
#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,
|
||||
* with SO_REUSEPORT set on each socket.
|
||||
*/
|
||||
if (reuseport &&
|
||||
if (reuseport && *reuseport &&
|
||||
setsockopt(s, SOL_SOCKET, SO_REUSEPORT, (void*)&on,
|
||||
(socklen_t)sizeof(on)) < 0) {
|
||||
log_err("setsockopt(.. SO_REUSEPORT ..) failed: %s",
|
||||
strerror(errno));
|
||||
close(s);
|
||||
*noproto = 0;
|
||||
*inuse = 0;
|
||||
return -1;
|
||||
#ifdef ENOPROTOOPT
|
||||
if(errno != ENOPROTOOPT || verbosity >= 3)
|
||||
log_warn("setsockopt(.. SO_REUSEPORT ..) failed: %s",
|
||||
strerror(errno));
|
||||
#endif
|
||||
/* this option is not essential, we can continue */
|
||||
*reuseport = 0;
|
||||
}
|
||||
#else
|
||||
(void)reuseport;
|
||||
|
|
@ -431,7 +432,7 @@ create_udp_sock(int family, int socktype, struct sockaddr* addr,
|
|||
|
||||
int
|
||||
create_tcp_accept_sock(struct addrinfo *addr, int v6only, int* noproto,
|
||||
int reuseport)
|
||||
int* reuseport)
|
||||
{
|
||||
int s;
|
||||
#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,
|
||||
* 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) {
|
||||
log_err("setsockopt(.. SO_REUSEPORT ..) failed: %s",
|
||||
strerror(errno));
|
||||
close(s);
|
||||
return -1;
|
||||
#ifdef ENOPROTOOPT
|
||||
if(errno != ENOPROTOOPT || verbosity >= 3)
|
||||
log_warn("setsockopt(.. SO_REUSEPORT ..) failed: %s",
|
||||
strerror(errno));
|
||||
#endif
|
||||
/* this option is not essential, we can continue */
|
||||
*reuseport = 0;
|
||||
}
|
||||
#else
|
||||
(void)reuseport;
|
||||
|
|
@ -556,7 +561,7 @@ create_tcp_accept_sock(struct addrinfo *addr, int v6only, int* noproto,
|
|||
static int
|
||||
make_sock(int stype, const char* ifname, const char* port,
|
||||
struct addrinfo *hints, int v6only, int* noip6, size_t rcv, size_t snd,
|
||||
int reuseport)
|
||||
int* reuseport)
|
||||
{
|
||||
struct addrinfo *res = NULL;
|
||||
int r, s, inuse, noproto;
|
||||
|
|
@ -604,7 +609,7 @@ make_sock(int stype, const char* ifname, const char* port,
|
|||
static int
|
||||
make_sock_port(int stype, const char* ifname, const char* port,
|
||||
struct addrinfo *hints, int v6only, int* noip6, size_t rcv, size_t snd,
|
||||
int reuseport)
|
||||
int* reuseport)
|
||||
{
|
||||
char* s = strchr(ifname, '@');
|
||||
if(s) {
|
||||
|
|
@ -721,13 +726,14 @@ set_recvpktinfo(int s, int family)
|
|||
* @param rcv: receive buffer size for UDP
|
||||
* @param snd: send buffer size for UDP
|
||||
* @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.
|
||||
*/
|
||||
static int
|
||||
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,
|
||||
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;
|
||||
if(!do_udp && !do_tcp)
|
||||
|
|
@ -901,7 +907,7 @@ listen_delete(struct listen_dnsport* front)
|
|||
}
|
||||
|
||||
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 addrinfo hints;
|
||||
|
|
@ -937,7 +943,7 @@ listening_ports_open(struct config_file* cfg)
|
|||
do_auto, cfg->do_udp, do_tcp,
|
||||
&hints, portbuf, &list,
|
||||
cfg->so_rcvbuf, cfg->so_sndbuf,
|
||||
cfg->ssl_port, cfg->so_reuseport)) {
|
||||
cfg->ssl_port, reuseport)) {
|
||||
listening_ports_free(list);
|
||||
return NULL;
|
||||
}
|
||||
|
|
@ -948,7 +954,7 @@ listening_ports_open(struct config_file* cfg)
|
|||
do_auto, cfg->do_udp, do_tcp,
|
||||
&hints, portbuf, &list,
|
||||
cfg->so_rcvbuf, cfg->so_sndbuf,
|
||||
cfg->ssl_port, cfg->so_reuseport)) {
|
||||
cfg->ssl_port, reuseport)) {
|
||||
listening_ports_free(list);
|
||||
return NULL;
|
||||
}
|
||||
|
|
@ -961,7 +967,7 @@ listening_ports_open(struct config_file* cfg)
|
|||
if(!ports_create_if(cfg->ifs[i], 0, cfg->do_udp,
|
||||
do_tcp, &hints, portbuf, &list,
|
||||
cfg->so_rcvbuf, cfg->so_sndbuf,
|
||||
cfg->ssl_port, cfg->so_reuseport)) {
|
||||
cfg->ssl_port, reuseport)) {
|
||||
listening_ports_free(list);
|
||||
return NULL;
|
||||
}
|
||||
|
|
@ -972,7 +978,7 @@ listening_ports_open(struct config_file* cfg)
|
|||
if(!ports_create_if(cfg->ifs[i], 0, cfg->do_udp,
|
||||
do_tcp, &hints, portbuf, &list,
|
||||
cfg->so_rcvbuf, cfg->so_sndbuf,
|
||||
cfg->ssl_port, cfg->so_reuseport)) {
|
||||
cfg->ssl_port, reuseport)) {
|
||||
listening_ports_free(list);
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -107,9 +107,13 @@ struct listen_port {
|
|||
* interfaces for IP4 and/or IP6, for UDP and/or TCP.
|
||||
* On the given port number. It creates the sockets.
|
||||
* @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.
|
||||
*/
|
||||
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.
|
||||
|
|
@ -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 listen: if true, this is a listening UDP port, eg port 53, and
|
||||
* 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.
|
||||
*/
|
||||
int create_udp_sock(int family, int socktype, struct sockaddr* addr,
|
||||
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
|
||||
* @param addr: address info ready to make socket.
|
||||
* @param v6only: enable ip6 only flag on ip6 sockets.
|
||||
* @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.
|
||||
*/
|
||||
int create_tcp_accept_sock(struct addrinfo *addr, int v6only, int* noproto,
|
||||
int reuseport);
|
||||
int* reuseport);
|
||||
|
||||
#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);
|
||||
fd = create_udp_sock(AF_INET6, SOCK_DGRAM,
|
||||
(struct sockaddr*)addr, addrlen, 1, inuse, &noproto,
|
||||
0, 0, 0, 0);
|
||||
0, 0, 0, NULL);
|
||||
} else {
|
||||
struct sockaddr_in* sa = (struct sockaddr_in*)addr;
|
||||
sa->sin_port = (in_port_t)htons((uint16_t)port);
|
||||
fd = create_udp_sock(AF_INET, SOCK_DGRAM,
|
||||
(struct sockaddr*)addr, addrlen, 1, inuse, &noproto,
|
||||
0, 0, 0, 0);
|
||||
0, 0, 0, NULL);
|
||||
}
|
||||
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");
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue