]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
[MINOR] add support for the "backlog" parameter
authorWilly Tarreau <w@1wt.eu>
Sun, 6 Jan 2008 09:55:10 +0000 (10:55 +0100)
committerWilly Tarreau <w@1wt.eu>
Sun, 6 Jan 2008 09:55:10 +0000 (10:55 +0100)
Add the "backlog" parameter to frontends, to give hints to
the system about the approximate listen backlog desired size.

In order to protect against SYN flood attacks, one solution is
to increase the system's SYN backlog size. Depending on the
system, sometimes it is just tunable via a system parameter,
sometimes it is not adjustable at all, and sometimes the system
relies on hints given by the application at the time of the
listen() syscall. By default, HAProxy passes the frontend's
maxconn value to the listen() syscall. On systems which can
make use of this value, it can sometimes be useful to be able
to specify a different value, hence this backlog parameter.

doc/configuration.txt
include/types/protocols.h
include/types/proxy.h
src/cfgparse.c
src/proto_tcp.c
src/proxy.c
tests/test-backlog.cfg [new file with mode: 0644]

index 3f0be93a22f9a89aa2bc5bcdaa6e471e6b16e655..1c7a058d24f9e5cb269870bd6837a8fc3d94e37e 100644 (file)
@@ -4,7 +4,7 @@
                          ----------------------
                             version 1.3.14.2
                              willy tarreau
-                               2007/12/27
+                               2008/01/05
 
 
 This document covers the configuration language as implemented in the version
@@ -502,6 +502,7 @@ keyword                 defaults   frontend   listen    backend
 ----------------------+----------+----------+---------+---------
 acl                         -          X         X         X   
 appsession                  -          -         X         X   
+backlog                     X          X         X         -
 balance                     X          -         X         X   
 bind                        -          X         X         -   
 block                       -          X         X         X
@@ -653,6 +654,31 @@ appsession <cookie> len <length> timeout <holdtime>
   See also : "cookie", "capture cookie" and "balance".
 
 
+backlog <conns>
+  Give hints to the system about the approximate listen backlog desired size
+  May be used in sections :   defaults | frontend | listen | backend
+                                 yes   |    yes   |   yes  |   no
+  Arguments :
+    <conns>   is the number of pending connections. Depending on the operating
+              system, it may represent the number of already acknowledged
+             connections, of non-acknowledged ones, or both.
+
+  In order to protect against SYN flood attacks, one solution is to increase
+  the system's SYN backlog size. Depending on the system, sometimes it is just
+  tunable via a system parameter, sometimes it is not adjustable at all, and
+  sometimes the system relies on hints given by the application at the time of
+  the listen() syscall. By default, HAProxy passes the frontend's maxconn value
+  to the listen() syscall. On systems which can make use of this value, it can
+  sometimes be useful to be able to specify a different value, hence this
+  backlog parameter.
+
+  On Linux 2.4, the parameter is ignored by the system. On Linux 2.6, it is
+  used as a hint and the system accepts up to the smallest greater power of
+  two, and never more than some limits (usually 32768).
+
+  See also : "maxconn" and the target operating system's tuning guide.
+
+
 balance <algorithm> [ <arguments> ]
   Define the load balancing algorithm to be used in a backend.
   May be used in sections :   defaults | frontend | listen | backend
index 6c59ce10af9647697fa27fedc2a212ca8a8a87ce..f360746591956713f86dca9ac3e9c6807b113d1d 100644 (file)
@@ -78,6 +78,7 @@ struct listener {
        struct protocol *proto;         /* protocol this listener belongs to */
        int nbconn;                     /* current number of connections on this listener */
        int maxconn;                    /* maximum connections allowed on this listener */
+       unsigned int backlog;           /* if set, listen backlog */
        struct listener *next;          /* next address for the same proxy, or NULL */
        struct list proto_list;         /* list in the protocol header */
        int (*accept)(int fd);          /* accept() function passed to fdtab[] */
index ef748936de7c683c2eb5608ffc45c73552e65e68..8a72d82d564e761c18498d70d2f23510f4b13857 100644 (file)
@@ -228,6 +228,7 @@ struct proxy {
        struct chunk errmsg[HTTP_ERR_SIZE];     /* default or customized error messages for known errors */
        int uuid;                               /* universally unique proxy ID, used for SNMP */
        int next_svid;                          /* next server-id, used for SNMP */
+       unsigned int backlog;                   /* force the frontend's listen backlog */
 };
 
 struct switching_rule {
index ae05da0aa4db44721c90e5dea7b83ed9500fbd79..7b43b7e68d4e346338a7d45c501bc2af72558c79 100644 (file)
@@ -614,6 +614,7 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int inv)
 
                if (curproxy->cap & PR_CAP_FE) {
                        curproxy->maxconn = defproxy.maxconn;
+                       curproxy->backlog = defproxy.backlog;
 
                        /* initialize error relocations */
                        for (rc = 0; rc < HTTP_ERR_SIZE; rc++) {
@@ -1365,6 +1366,16 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int inv)
                }
                curproxy->maxconn = atol(args[1]);
        }
+       else if (!strcmp(args[0], "backlog")) {  /* backlog */
+               if (warnifnotcap(curproxy, PR_CAP_FE, file, linenum, args[0], NULL))
+                       return 0;
+
+               if (*(args[1]) == 0) {
+                       Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
+                       return -1;
+               }
+               curproxy->backlog = atol(args[1]);
+       }
        else if (!strcmp(args[0], "fullconn")) {  /* fullconn */
                if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], " Maybe you want 'maxconn' instead ?"))
                        return 0;
@@ -2865,6 +2876,7 @@ int readcfgfile(const char *file)
                        if (curproxy->options & PR_O_TCP_NOLING)
                                listener->options |= LI_O_NOLINGER;
                        listener->maxconn = curproxy->maxconn;
+                       listener->backlog = curproxy->backlog;
                        listener->timeout = &curproxy->timeout.client;
                        listener->accept = event_accept;
                        listener->private = curproxy;
index 593096d7f387f1bf137e6129f29ba0e02dfaa79f..2da34db38fdd0d1e3534d7f6f089256964bfe737 100644 (file)
@@ -160,7 +160,7 @@ int tcp_bind_listener(struct listener *listener, char *errmsg, int errlen)
                goto tcp_close_return;
        }
        
-       if (listen(fd, listener->maxconn) == -1) {
+       if (listen(fd, listener->backlog ? listener->backlog : listener->maxconn) == -1) {
                err |= ERR_RETRYABLE | ERR_ALERT;
                msg = "cannot listen to socket";
                goto tcp_close_return;
index 1b12844ea25416d53d8c288af7432e3cbd261fcc..82bb2ae14e0f7a0f0571344ee373a512209ce0bb 100644 (file)
@@ -369,7 +369,7 @@ void pause_proxy(struct proxy *p)
        struct listener *l;
        for (l = p->listen; l != NULL; l = l->next) {
                if (shutdown(l->fd, SHUT_WR) == 0 &&
-                   listen(l->fd, p->maxconn) == 0 &&
+                   listen(l->fd, p->backlog ? p->backlog : p->maxconn) == 0 &&
                    shutdown(l->fd, SHUT_RD) == 0) {
                        EV_FD_CLR(l->fd, DIR_RD);
                        if (p->state != PR_STERROR)
@@ -435,7 +435,7 @@ void listen_proxies(void)
                        send_log(p, LOG_WARNING, "Enabling proxy %s.\n", p->id);
 
                        for (l = p->listen; l != NULL; l = l->next) {
-                               if (listen(l->fd, p->maxconn) == 0) {
+                               if (listen(l->fd, p->backlog ? p->backlog : p->maxconn) == 0) {
                                        if (actconn < global.maxconn && p->feconn < p->maxconn) {
                                                EV_FD_SET(l->fd, DIR_RD);
                                                p->state = PR_STRUN;
diff --git a/tests/test-backlog.cfg b/tests/test-backlog.cfg
new file mode 100644 (file)
index 0000000..bc4a71e
--- /dev/null
@@ -0,0 +1,22 @@
+# This is a test configuration.
+# It is used to check that the backlog queue works as expected.
+
+global
+       maxconn    200
+        stats timeout 3s
+
+frontend backlog_def
+        mode       http
+        timeout    client  15s
+        maxconn    100
+        bind       :8000
+        option     httpclose
+
+frontend backlog_max
+        mode       http
+        timeout    client  15s
+        maxconn    100
+       backlog    100000
+        bind       :8001
+        option     httpclose
+