]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
[MINOR] tcp: add support for dynamic MSS setting
authorWilly Tarreau <w@1wt.eu>
Fri, 24 Dec 2010 14:26:39 +0000 (15:26 +0100)
committerWilly Tarreau <w@1wt.eu>
Thu, 30 Dec 2010 08:50:23 +0000 (09:50 +0100)
By passing a negative value to the "mss" argument of "bind" lines, it
becomes possible to subtract this value to the MSS advertised by the
client, which results in segments smaller than advertised. The effect
is useful with some TCP stacks which ACK less often when segments are
not full, because they only ACK every other full segment as suggested
by RFC1122.

NOTE: currently this has no effect on Linux kernel 2.6, a kernel patch
is still required to change the MSS of established connections.

doc/configuration.txt
src/cfgparse.c
src/frontend.c
src/proto_tcp.c

index f20b8b2ea09e3821ac25abab8bc812b8d58c3554..daec87958bbde976234f348578270598da908055 100644 (file)
@@ -1463,9 +1463,14 @@ bind /<path> [, ...] [ group <user> | gid <gid> ]
                   connections passing through a VPN. Note that this relies on a
                   kernel feature which is theorically supported under Linux but
                   was buggy in all versions prior to 2.6.28. It may or may not
-                  work on other operating systems. The commonly advertised
-                  value on Ethernet networks is 1460 = 1500(MTU) - 40(IP+TCP).
-                  This parameter is only compatible with TCP sockets.
+                  work on other operating systems. It may also not change the
+                  advertised value but change the effective size of outgoing
+                  segments. The commonly advertised value on Ethernet networks
+                  is 1460 = 1500(MTU) - 40(IP+TCP). If this value is positive,
+                  it will be used as the advertised MSS. If it is negative, it
+                  will indicate by how much to reduce the incoming connection's
+                  advertised MSS for outgoing segments. This parameter is only
+                  compatible with TCP sockets.
 
     <id>          is a persistent value for socket ID. Must be positive and
                   unique in the proxy. An unused value will automatically be
index ddfbe42536884acecbc7f8faacad1b1ce80fc0c5..a67b348384bd1ad83aa4a336da415d17a173648b 100644 (file)
@@ -1683,9 +1683,9 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm)
                                        goto out;
                                }
 
-                               mss = str2uic(args[cur_arg + 1]);
-                               if (mss < 1 || mss > 65535) {
-                                       Alert("parsing [%s:%d]: %s expects an MSS value between 1 and 65535.\n",
+                               mss = atoi(args[cur_arg + 1]);
+                               if (!mss || abs(mss) > 65535) {
+                                       Alert("parsing [%s:%d]: %s expects an MSS with and absolute value between 1 and 65535.\n",
                                              file, linenum, args[0]);
                                        err_code |= ERR_ALERT | ERR_FATAL;
                                        goto out;
index 4fc4460f0c37fc5bd03a2b958db60d821d87ef61..8842e28ca6267ff7b46456f2e68745751f6a1769 100644 (file)
@@ -20,6 +20,8 @@
 #include <sys/stat.h>
 #include <sys/types.h>
 
+#include <netinet/tcp.h>
+
 #include <common/compat.h>
 #include <common/config.h>
 #include <common/debug.h>
@@ -100,6 +102,17 @@ int frontend_accept(struct session *s)
                if (s->fe->options & PR_O_TCP_NOLING)
                        setsockopt(cfd, SOL_SOCKET, SO_LINGER,
                                   (struct linger *) &nolinger, sizeof(struct linger));
+#if defined(TCP_MAXSEG)
+               if (s->listener->maxseg < 0) {
+                       /* we just want to reduce the current MSS by that value */
+                       int mss;
+                       int mss_len = sizeof(mss);
+                       if (getsockopt(cfd, IPPROTO_TCP, TCP_MAXSEG, &mss, &mss_len) == 0) {
+                               mss += s->listener->maxseg; /* remember, it's < 0 */
+                               setsockopt(cfd, IPPROTO_TCP, TCP_MAXSEG, &mss, sizeof(mss));
+                       }
+               }
+#endif
        }
 
        if (global.tune.client_sndbuf)
index 5039db8be8dd421af6ace7c0c57929bff1778337..6328d0a5ac350e4ca69aafc9d28e28aa38f978e6 100644 (file)
@@ -509,7 +509,7 @@ int tcp_bind_listener(struct listener *listener, char *errmsg, int errlen)
        }
 #endif
 #if defined(TCP_MAXSEG)
-       if (listener->maxseg) {
+       if (listener->maxseg > 0) {
                if (setsockopt(fd, IPPROTO_TCP, TCP_MAXSEG,
                               &listener->maxseg, sizeof(listener->maxseg)) == -1) {
                        msg = "cannot set MSS";