From 48a7e72c5d19df8ebe260248796e01aade8bea44 Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Fri, 24 Dec 2010 15:26:39 +0100 Subject: [PATCH] [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. --- doc/configuration.txt | 11 ++++++++--- src/cfgparse.c | 6 +++--- src/frontend.c | 13 +++++++++++++ src/proto_tcp.c | 2 +- 4 files changed, 25 insertions(+), 7 deletions(-) diff --git a/doc/configuration.txt b/doc/configuration.txt index f20b8b2ea..daec87958 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 ddfbe4253..a67b34838 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 4fc4460f0..8842e28ca 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 5039db8be..6328d0a5a 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";