diff --git a/include/types/protocols.h b/include/types/protocols.h index 80c1a6e02..212ecef95 100644 --- a/include/types/protocols.h +++ b/include/types/protocols.h @@ -84,6 +84,11 @@ enum { #define LI_O_TCP_RULES 0x0010 /* run TCP rules checks on the incoming connection */ #define LI_O_CHK_MONNET 0x0020 /* check the source against a monitor-net rule */ #define LI_O_ACC_PROXY 0x0040 /* find the proxied address in the first request line */ +#define LI_O_UNLIMITED 0x0080 /* listener not subject to global limits (peers & stats socket) */ + +/* Note: if a listener uses LI_O_UNLIMITED, it is highly recommended that it adds its own + * maxconn setting to the global.maxsock value so that its resources are reserved. + */ /* The listener will be directly referenced by the fdtab[] which holds its * socket. The listener provides the protocol-specific accept() function to diff --git a/src/cfgparse.c b/src/cfgparse.c index f098a3158..45d9677d8 100644 --- a/src/cfgparse.c +++ b/src/cfgparse.c @@ -1278,6 +1278,8 @@ int cfg_parse_peers(const char *file, int linenum, char **args, int kwm) curpeers->peers_fe->listen->frontend = ((struct proxy *)curpeers->peers_fe); curpeers->peers_fe->listen->handler = process_session; curpeers->peers_fe->listen->analysers |= ((struct proxy *)curpeers->peers_fe)->fe_req_ana; + curpeers->peers_fe->listen->options |= LI_O_UNLIMITED; /* don't make the peers subject to global limits */ + global.maxsock += curpeers->peers_fe->listen->maxconn; } } } /* neither "peer" nor "peers" */ diff --git a/src/dumpstats.c b/src/dumpstats.c index 6d97f5da5..964ba83b3 100644 --- a/src/dumpstats.c +++ b/src/dumpstats.c @@ -206,7 +206,7 @@ static int stats_parse_global(char **args, int section_type, struct proxy *curpx } global.stats_sock.state = LI_INIT; - global.stats_sock.options = LI_O_NONE; + global.stats_sock.options = LI_O_UNLIMITED; global.stats_sock.accept = session_accept; global.stats_fe->accept = stats_accept; global.stats_sock.handler = process_session; diff --git a/src/haproxy.c b/src/haproxy.c index 7aa9fd451..f783c3d90 100644 --- a/src/haproxy.c +++ b/src/haproxy.c @@ -68,6 +68,7 @@ #include #include #include +#include #include #include @@ -603,6 +604,18 @@ void init(int argc, char **argv) global.maxsock += global.maxconn * 2; /* each connection needs two sockets */ global.maxsock += global.maxpipes * 2; /* each pipe needs two FDs */ + if (global.stats_fe) + global.maxsock += global.stats_fe->maxconn; + + if (peers) { + /* peers also need to bypass global maxconn */ + struct peers *p = peers; + + for (p = peers; p; p = p->next) + if (p->peers_fe) + global.maxsock += p->peers_fe->maxconn; + } + if (global.tune.maxpollevents <= 0) global.tune.maxpollevents = MAX_POLL_EVENTS; diff --git a/src/peers.c b/src/peers.c index 26a3154b7..bbe99d493 100644 --- a/src/peers.c +++ b/src/peers.c @@ -1271,7 +1271,8 @@ static struct session *peer_session_create(struct peer *peer, struct peer_sessio l->nbconn++; /* warning! right now, it's up to the handler to decrease this */ p->feconn++;/* beconn will be increased later */ jobs++; - actconn++; + if (!(s->listener->options & LI_O_UNLIMITED)) + actconn++; totalconn++; return s; diff --git a/src/session.c b/src/session.c index a9dfef8e9..5032d889b 100644 --- a/src/session.c +++ b/src/session.c @@ -2086,7 +2086,8 @@ struct task *process_session(struct task *t) s->fe->feconn--; if (s->flags & SN_BE_ASSIGNED) s->be->beconn--; - actconn--; + if (!(s->listener->options & LI_O_UNLIMITED)) + actconn--; jobs--; s->listener->nbconn--; if (s->listener->state == LI_FULL) diff --git a/src/stream_sock.c b/src/stream_sock.c index 365f52b97..d673aba7d 100644 --- a/src/stream_sock.c +++ b/src/stream_sock.c @@ -1156,7 +1156,7 @@ int stream_sock_accept(int fd) return 0; } - if (global.cps_lim) { + if (global.cps_lim && !(l->options & LI_O_UNLIMITED)) { int max = freq_ctr_remain(&global.conn_per_sec, global.cps_lim, 0); if (unlikely(!max)) { @@ -1193,7 +1193,7 @@ int stream_sock_accept(int fd) struct sockaddr_storage addr; socklen_t laddr = sizeof(addr); - if (unlikely(actconn >= global.maxconn)) { + if (unlikely(actconn >= global.maxconn) && !(l->options & LI_O_UNLIMITED)) { limit_listener(l, &global_listener_queue); task_schedule(global_listener_queue_task, tick_add(now_ms, 1000)); /* try again in 1 second */ return 0; @@ -1252,12 +1252,14 @@ int stream_sock_accept(int fd) } /* increase the per-process number of cumulated connections */ - update_freq_ctr(&global.conn_per_sec, 1); - if (global.conn_per_sec.curr_ctr > global.cps_max) - global.cps_max = global.conn_per_sec.curr_ctr; + if (!(l->options & LI_O_UNLIMITED)) { + update_freq_ctr(&global.conn_per_sec, 1); + if (global.conn_per_sec.curr_ctr > global.cps_max) + global.cps_max = global.conn_per_sec.curr_ctr; + actconn++; + } jobs++; - actconn++; totalconn++; l->nbconn++; @@ -1273,8 +1275,9 @@ int stream_sock_accept(int fd) * error due to a resource shortage, and we must stop the * listener (ret < 0). */ + if (!(l->options & LI_O_UNLIMITED)) + actconn--; jobs--; - actconn--; l->nbconn--; if (ret == 0) /* successful termination */ continue;