- unbound tries to set the ulimit fds when started as server.

if that does not work, it will scale back its requirements.


git-svn-id: file:///svn/unbound/trunk@1022 be551aaa-1e26-0410-a405-d3ace91eadb9
This commit is contained in:
Wouter Wijngaards 2008-04-08 15:02:52 +00:00
parent ff8c2ed1bc
commit d26b183ba6
8 changed files with 78 additions and 29 deletions

View file

@ -91,17 +91,22 @@ checkrlimits(struct config_file* cfg)
(int)cfg->incoming_num_tcp:0));
size_t ifs = (size_t)(cfg->num_ifs==0?1:cfg->num_ifs);
size_t listen_num = list*ifs;
size_t out_ifs = (size_t)(cfg->num_out_ifs==0?1:cfg->num_out_ifs);
size_t outnum = cfg->outgoing_num_ports*out_ifs + cfg->outgoing_num_tcp;
size_t out_ifs = (size_t)(cfg->num_out_ifs==0?
( (cfg->do_ip4?1:0) + (cfg->do_ip6?1:0) ) :cfg->num_out_ifs);
size_t outudpnum = cfg->outgoing_num_ports*out_ifs;
size_t outtcpnum = cfg->outgoing_num_tcp;
size_t misc = 4; /* logfile, pidfile, stdout... */
size_t perthread = listen_num + outnum + 2/*cmdpipe*/ + 2/*libevent*/
+ misc;
size_t perthread_noudp = listen_num + outtcpnum +
2/*cmdpipe*/ + 2/*libevent*/ + misc;
size_t perthread = perthread_noudp + outudpnum;
#if !defined(HAVE_PTHREAD) && !defined(HAVE_SOLARIS_THREADS)
int numthread = 1; /* it forks */
#else
int numthread = cfg->num_threads;
#endif
size_t total = numthread * perthread + misc;
size_t avail;
struct rlimit rlim;
if(getrlimit(RLIMIT_NOFILE, &rlim) < 0) {
log_warn("getrlimit: %s", strerror(errno));
@ -110,13 +115,24 @@ checkrlimits(struct config_file* cfg)
if(rlim.rlim_cur == (rlim_t)RLIM_INFINITY)
return;
if((size_t)rlim.rlim_cur < total) {
log_err("Not enough sockets available. Increase "
"ulimit(open files).");
log_err("or decrease number of threads, outgoing num ports, "
"outgoing num tcp or number of interfaces");
log_err("estimate %u fds high mark, %u available",
(unsigned)total, (unsigned)rlim.rlim_cur);
fatal_exit("Not enough file descriptors available");
avail = (size_t)rlim.rlim_cur;
rlim.rlim_cur = (rlim_t)(total + 10);
rlim.rlim_max = (rlim_t)(total + 10);
if(setrlimit(RLIMIT_NOFILE, &rlim) < 0) {
log_warn("setrlimit: %s", strerror(errno));
log_warn("cannot increase max open fds from %u to %u",
(unsigned)avail, (unsigned)total+10);
cfg->outgoing_num_ports = (int)((avail
- numthread*perthread_noudp
- 10 /* safety margin */)
/(numthread*out_ifs));
log_warn("continuing with less udp ports: %u",
cfg->outgoing_num_ports);
log_warn("increase ulimit or decrease threads, ports in config to remove this warning");
return;
}
log_warn("increased limit(open files) from %u to %u",
(unsigned)avail, (unsigned)total+10);
}
}

View file

@ -1,3 +1,7 @@
8 April 2008: Wouter
- unbound tries to set the ulimit fds when started as server.
if that does not work, it will scale back its requirements.
27 March 2008: Wouter
- documented /dev/random symlink from chrootdir as FAQ entry.

View file

@ -54,7 +54,7 @@ server:
# port range. A larger port range gives more resistance to certain
# spoof attacks, as it gets harder to guess which port is used.
# But also takes more system resources (for open sockets).
# outgoing-range: 16
# outgoing-range: 256
# number of outgoing simultaneous tcp buffers to hold per thread.
# outgoing-num-tcp: 10

View file

@ -124,7 +124,7 @@ Default is 1053.
.TP
.B outgoing\-range: \fI<number>
Number of ports to open. This number is opened per thread for every outgoing
query interface. Must be at least 1. Default is 16.
query interface. Must be at least 1. Default is 256.
Larger numbers give more protection against spoofing attempts, but need
extra resources from the operating system.
.TP

View file

@ -86,7 +86,7 @@ verbose_print_addr(struct addrinfo *addr)
}
int
create_udp_sock(struct addrinfo *addr, int v6only)
create_udp_sock(struct addrinfo *addr, int v6only, int* inuse)
{
int s;
# if defined(IPV6_USE_MIN_MTU)
@ -97,6 +97,7 @@ create_udp_sock(struct addrinfo *addr, int v6only)
verbose_print_addr(addr);
if((s = socket(addr->ai_family, addr->ai_socktype, 0)) == -1) {
log_err("can't create socket: %s", strerror(errno));
*inuse = 0;
return -1;
}
if(addr->ai_family == AF_INET6) {
@ -107,6 +108,7 @@ create_udp_sock(struct addrinfo *addr, int v6only)
&val, (socklen_t)sizeof(val)) < 0) {
log_err("setsockopt(..., IPV6_V6ONLY"
", ...) failed: %s", strerror(errno));
*inuse = 0;
return -1;
}
}
@ -124,16 +126,23 @@ create_udp_sock(struct addrinfo *addr, int v6only)
&on, (socklen_t)sizeof(on)) < 0) {
log_err("setsockopt(..., IPV6_USE_MIN_MTU, "
"...) failed: %s", strerror(errno));
*inuse = 0;
return -1;
}
# endif
}
if(bind(s, (struct sockaddr*)addr->ai_addr, addr->ai_addrlen) != 0) {
log_err("can't bind socket: %s", strerror(errno));
#ifdef EADDRINUSE
*inuse = (errno == EADDRINUSE);
if(errno != EADDRINUSE)
#endif
log_err("can't bind socket: %s", strerror(errno));
return -1;
}
if(!fd_set_nonblock(s))
if(!fd_set_nonblock(s)) {
*inuse = 0;
return -1;
}
return s;
}
@ -203,7 +212,7 @@ make_sock(int stype, const char* ifname, const char* port,
struct addrinfo *hints, int v6only)
{
struct addrinfo *res = NULL;
int r, s;
int r, s, inuse;
hints->ai_socktype = stype;
if((r=getaddrinfo(ifname, port, hints, &res)) != 0 || !res) {
log_err("node %s:%s getaddrinfo: %s %s",
@ -211,9 +220,12 @@ make_sock(int stype, const char* ifname, const char* port,
r==EAI_SYSTEM?(char*)strerror(errno):"");
return -1;
}
if(stype == SOCK_DGRAM)
s = create_udp_sock(res, v6only);
else s = create_tcp_accept_sock(res, v6only);
if(stype == SOCK_DGRAM) {
s = create_udp_sock(res, v6only, &inuse);
if(s == -1 && inuse) {
log_err("bind: address already in use");
}
} else s = create_tcp_accept_sock(res, v6only);
freeaddrinfo(res);
return s;
}

View file

@ -168,8 +168,9 @@ size_t listen_get_mem(struct listen_dnsport* listen);
* @param addr: address info ready to make socket.
* @param v6only: if enabled, IP6 sockets get IP6ONLY option set.
* if enabled with value 2 IP6ONLY option is disabled.
* @param inuse: on error, this is set true if the port was in use.
* @return: the socket. -1 on error.
*/
int create_udp_sock(struct addrinfo* addr, int v6only);
int create_udp_sock(struct addrinfo* addr, int v6only, int* inuse);
#endif /* LISTEN_DNSPORT_H */

View file

@ -284,10 +284,12 @@ outnet_udp_cb(struct comm_point* c, void* arg, int error,
* @param ifname: on which interface to open the port.
* @param hints: hints on family and passiveness preset.
* @param porthint: if not -1, it gives the port to base range on.
* @param inuse: on error, true if the port was in use.
* @return: file descriptor
*/
static int
open_udp_port_range(const char* ifname, struct addrinfo* hints, int porthint)
open_udp_port_range(const char* ifname, struct addrinfo* hints, int porthint,
int* inuse)
{
struct addrinfo *res = NULL;
int r, s;
@ -308,7 +310,7 @@ open_udp_port_range(const char* ifname, struct addrinfo* hints, int porthint)
r==EAI_SYSTEM?(char*)strerror(errno):"");
return -1;
}
s = create_udp_sock(res, 1);
s = create_udp_sock(res, 1, inuse);
freeaddrinfo(res);
return s;
}
@ -346,11 +348,23 @@ make_udp_range(struct comm_point** coms, const char* ifname,
hints.ai_family = AF_INET6;
hints.ai_socktype = SOCK_DGRAM;
for(i=0; i<num_ports; i++) {
int fd = open_udp_port_range(ifname, &hints, porthint);
if(porthint != -1)
porthint++;
if(fd == -1)
continue;
int fd = -1;
int inuse = 1;
while(fd == -1 && inuse) {
inuse = 0;
fd = open_udp_port_range(ifname, &hints,
porthint, &inuse);
if(fd == -1 && porthint != -1 && inuse)
verbose(VERB_DETAIL, "%sport %d already in use, skipped",
(do_ip6?"IP6 ":""), porthint);
if(porthint != -1) {
porthint++;
if(porthint > 65535) {
log_err("ports maxed. cannot open ports");
return done;
}
}
}
coms[done] = comm_point_create_udp(outnet->base, fd,
outnet->udp_buff, outnet_udp_cb, outnet);
if(coms[done])

View file

@ -79,7 +79,7 @@ config_create()
cfg->do_tcp = 1;
cfg->use_syslog = 1;
cfg->outgoing_base_port = cfg->port + 2000;
cfg->outgoing_num_ports = 16;
cfg->outgoing_num_ports = 256;
cfg->outgoing_num_tcp = 10;
cfg->incoming_num_tcp = 10;
cfg->msg_buffer_size = 65552; /* 64 k + a small margin */
@ -150,6 +150,8 @@ struct config_file* config_create_forlib()
free(cfg->chrootdir);
cfg->chrootdir = NULL;
cfg->verbosity = 0;
cfg->outgoing_num_ports = 16; /* in library use, this is 'reasonable'
and probably within the ulimit(maxfds) of the user */
cfg->outgoing_num_tcp = 2;
cfg->msg_cache_size = 1024*1024;
cfg->msg_cache_slabs = 1;