]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
[MEDIUM] implement option tcp-smart-accept at the frontend
authorWilly Tarreau <w@1wt.eu>
Sun, 14 Jun 2009 10:07:01 +0000 (12:07 +0200)
committerWilly Tarreau <w@1wt.eu>
Sun, 14 Jun 2009 10:07:01 +0000 (12:07 +0200)
This option disables TCP quick ack upon accept. It is also
automatically enabled in HTTP mode, unless the option is
explicitly disabled with "no option tcp-smart-accept".

This saves one packet per connection which can bring reasonable
amounts of bandwidth for servers processing small requests.

doc/configuration.txt
include/types/protocols.h
include/types/proxy.h
src/cfgparse.c
src/proto_tcp.c

index 94d7861bb29cc0409717023e15d2d1f6c292bc10..3266a4448132e9ca6324fdf19d76398c9738b240 100644 (file)
@@ -706,6 +706,8 @@ option smtpchk              X          -         X         X
 [no] option splice-response X          X         X         X
 [no] option srvtcpka        X          -         X         X
 option ssl-hello-chk        X          -         X         X
+[no] option tcp-smart-
+            accept          X          X         X         -
 option tcpka                X          X         X         X
 option tcplog               X          X         X         X
 [no] option tcpsplice       X          X         X         X
@@ -2755,6 +2757,39 @@ option ssl-hello-chk
   See also: "option httpchk"
 
 
+option tcp-smart-accept
+no option tcp-smart-accept
+  Enable or disable the saving of one ACK packet during the accept sequence
+  May be used in sections :   defaults | frontend | listen | backend
+                                 yes   |    yes   |   yes  |    no
+  Arguments : none
+
+  When an HTTP connection request comes in, the system acknowledges it on
+  behalf of HAProxy, then the client immediately sends its request, and the
+  system acknowledges it too while it is notifying HAProxy about the new
+  connection. HAProxy then reads the request and responds. This means that we
+  have one TCP ACK sent by the system for nothing, because the request could
+  very well be acknowledged by HAProxy when it sends its response.
+
+  For this reason, in HTTP mode, HAProxy automatically asks the system to avoid
+  sending this useless ACK on platforms which support it (currently at least
+  Linux). It must not cause any problem, because the system will send it anyway
+  after 40 ms if the response takes more time than expected to come.
+
+  During complex network debugging sessions, it may be desirable to disable
+  this optimization because delayed ACKs can make troubleshooting more complex
+  when trying to identify where packets are delayed. It is then possible to
+  fall back to normal behaviour by specifying "no option tcp-smart-accept".
+
+  It is also possible to force it for non-HTTP proxies by simply specifying
+  "option tcp-smart-accept". For instance, it can make sense with some services
+  such as SMTP where the server speaks first.
+
+  It is recommended to avoid forcing this option in a defaults section. In case
+  of doubt, consider setting it back to automatic values by prepending the
+  "default" keyword before it, or disabling it using the "no" keyword.
+
+
 option tcpka
   Enable or disable the sending of TCP keepalive packets on both sides
   May be used in sections :   defaults | frontend | listen | backend
index e91fdb3adeb4b062e2a5b495f96078ca78201c2d..8d0ac9f1ff78ac31fd9dcc67babf80af8a45a176 100644 (file)
@@ -68,6 +68,7 @@
 #define LI_O_NONE      0x0000
 #define LI_O_NOLINGER  0x0001  /* disable linger on this socket */
 #define LI_O_FOREIGN   0x0002  /* permit listening on foreing addresses */
+#define LI_O_NOQUICKACK        0x0004  /* disable quick ack of immediate data (linux) */
 
 /* The listener will be directly referenced by the fdtab[] which holds its
  * socket. The listener provides the protocol-specific accept() function to
index b1b90e887d3d52f2faf1792764ea430c02957c9d..7664618f047ecaf3bed9d8f0df5fbbb2f70fe637 100644 (file)
 #define PR_O2_RSPBUG_OK        0x00000010      /* let buggy responses pass through */
 #define PR_O2_NOLOGNORM        0x00000020      /* don't log normal traffic, only errors and retries */
 #define PR_O2_LOGERRORS        0x00000040      /* log errors and retries at level LOG_ERR */
+#define PR_O2_SMARTACC         0x00000080      /* don't immediately ACK request after accept */
 
 /* This structure is used to apply fast weighted round robin on a server group */
 struct fwrr_group {
index af9af07584ee156e8dd5b968f9057092dce51308..03a5303f5106ac419491100bd2eb9e70b0bb034f 100644 (file)
@@ -135,6 +135,7 @@ static const struct cfg_opt cfg_opts2[] =
        { "accept-invalid-http-response", PR_O2_RSPBUG_OK, PR_CAP_BE, 0 },
        { "dontlog-normal",               PR_O2_NOLOGNORM, PR_CAP_FE, 0 },
        { "log-separate-errors",          PR_O2_LOGERRORS, PR_CAP_FE, 0 },
+       { "tcp-smart-accept",             PR_O2_SMARTACC,  PR_CAP_FE, 0 },
        { NULL, 0, 0, 0 }
 };
 
@@ -3741,6 +3742,12 @@ int readcfgfile(const char *file)
                        if (curproxy->mode == PR_MODE_HTTP)
                                listener->analysers |= AN_REQ_HTTP_HDR;
 
+                       /* smart accept mode is automatic in HTTP mode */
+                       if ((curproxy->options2 & PR_O2_SMARTACC) ||
+                           (curproxy->mode == PR_MODE_HTTP &&
+                            !(curproxy->no_options2 & PR_O2_SMARTACC)))
+                               listener->options |= LI_O_NOQUICKACK;
+
                        if (curproxy->tcp_req.inspect_delay ||
                            !LIST_ISEMPTY(&curproxy->tcp_req.inspect_rules))
                                listener->analysers |= AN_REQ_INSPECT;
index 4d0ae35596d875b25cd81b2d06db06fb87607b02..ed0812c20d69e0c7bb30577b04f0be6d2ea1510d 100644 (file)
@@ -18,6 +18,8 @@
 #include <string.h>
 #include <time.h>
 
+#include <netinet/tcp.h>
+
 #include <sys/param.h>
 #include <sys/socket.h>
 #include <sys/stat.h>
@@ -263,6 +265,11 @@ int tcp_bind_listener(struct listener *listener, char *errmsg, int errlen)
                goto tcp_close_return;
        }
 
+#ifdef TCP_QUICKACK
+       if (listener->options & LI_O_NOQUICKACK)
+               setsockopt(fd, SOL_TCP, TCP_QUICKACK, (char *) &zero, sizeof(zero));
+#endif
+
        /* the socket is ready */
        listener->fd = fd;
        listener->state = LI_LISTEN;