From: Willy Tarreau Date: Fri, 24 Dec 2010 14:26:39 +0000 (+0100) Subject: [MINOR] tcp: add support for dynamic MSS setting X-Git-Tag: v1.5-dev8~336 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=48a7e72c5d19df8ebe260248796e01aade8bea44;p=thirdparty%2Fhaproxy.git [MINOR] tcp: add support for dynamic MSS setting 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. --- diff --git a/doc/configuration.txt b/doc/configuration.txt index f20b8b2ea0..daec87958b 100644 --- a/doc/configuration.txt +++ b/doc/configuration.txt @@ -1463,9 +1463,14 @@ bind / [, ...] [ group | 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. is a persistent value for socket ID. Must be positive and unique in the proxy. An unused value will automatically be diff --git a/src/cfgparse.c b/src/cfgparse.c index ddfbe42536..a67b348384 100644 --- a/src/cfgparse.c +++ b/src/cfgparse.c @@ -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; diff --git a/src/frontend.c b/src/frontend.c index 4fc4460f0c..8842e28ca6 100644 --- a/src/frontend.c +++ b/src/frontend.c @@ -20,6 +20,8 @@ #include #include +#include + #include #include #include @@ -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) diff --git a/src/proto_tcp.c b/src/proto_tcp.c index 5039db8be8..6328d0a5ac 100644 --- a/src/proto_tcp.c +++ b/src/proto_tcp.c @@ -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";