From: Willy Tarreau Date: Sun, 14 Jun 2009 10:07:01 +0000 (+0200) Subject: [MEDIUM] implement option tcp-smart-accept at the frontend X-Git-Tag: v1.4-dev1~52 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=9ea05a790f705620f442ba92889269582ffe8dbd;p=thirdparty%2Fhaproxy.git [MEDIUM] implement option tcp-smart-accept at the frontend 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. --- diff --git a/doc/configuration.txt b/doc/configuration.txt index 94d7861bb2..3266a44481 100644 --- a/doc/configuration.txt +++ b/doc/configuration.txt @@ -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 diff --git a/include/types/protocols.h b/include/types/protocols.h index e91fdb3ade..8d0ac9f1ff 100644 --- a/include/types/protocols.h +++ b/include/types/protocols.h @@ -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 diff --git a/include/types/proxy.h b/include/types/proxy.h index b1b90e887d..7664618f04 100644 --- a/include/types/proxy.h +++ b/include/types/proxy.h @@ -117,6 +117,7 @@ #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 { diff --git a/src/cfgparse.c b/src/cfgparse.c index af9af07584..03a5303f51 100644 --- a/src/cfgparse.c +++ b/src/cfgparse.c @@ -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; diff --git a/src/proto_tcp.c b/src/proto_tcp.c index 4d0ae35596..ed0812c20d 100644 --- a/src/proto_tcp.c +++ b/src/proto_tcp.c @@ -18,6 +18,8 @@ #include #include +#include + #include #include #include @@ -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;