From 1c862c59204557dec1ab160dd9f1827618b425f2 Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Fri, 5 Oct 2012 16:21:00 +0200 Subject: [PATCH] MEDIUM: tcp: enable TCP Fast Open on systems which support it If TCP_FASTOPEN is defined, then the "tfo" option is supported on "bind" lines to enable TCP Fast Open (linux >= 3.6). --- doc/configuration.txt | 11 +++++++++++ include/types/listener.h | 1 + src/proto_tcp.c | 28 ++++++++++++++++++++++++++++ 3 files changed, 40 insertions(+) diff --git a/doc/configuration.txt b/doc/configuration.txt index 8c3132b3a..3d8bbfdb6 100644 --- a/doc/configuration.txt +++ b/doc/configuration.txt @@ -6937,6 +6937,17 @@ ssl appear in clear text, so that ACLs and HTTP processing will only have access to deciphered contents. +tfo + Is an optional keyword which is supported only on Linux kernels >= 3.6. It + enables TCP Fast Open on the listening socket, which means that clients which + support this feature will be able to send a request and receive a response + during the 3-way handshake starting from second connection, thus saving one + round-trip after the first connection. This only makes sense with protocols + that use high connection rates and where each round trip matters. This can + possibly cause issues with many firewalls which do not accept data on SYN + packets, so this option should only be enabled once well tested. This option + is only supported on TCPv4/TCPv6 sockets and ignored by other ones. + transparent Is an optional keyword which is supported only on certain Linux kernels. It indicates that the addresses will be bound even if they do not belong to the diff --git a/include/types/listener.h b/include/types/listener.h index 935a00370..6fe21ab88 100644 --- a/include/types/listener.h +++ b/include/types/listener.h @@ -88,6 +88,7 @@ enum { #define LI_O_CHK_MONNET 0x0020 /* check the source against a monitor-net rule */ #define LI_O_ACC_PROXY 0x0040 /* find the proxied address in the first request line */ #define LI_O_UNLIMITED 0x0080 /* listener not subject to global limits (peers & stats socket) */ +#define LI_O_TCP_FO 0x0100 /* enable TCP Fast Open (linux >= 3.6) */ /* Note: if a listener uses LI_O_UNLIMITED, it is highly recommended that it adds its own * maxconn setting to the global.maxsock value so that its resources are reserved. diff --git a/src/proto_tcp.c b/src/proto_tcp.c index ea6f94326..8b0792baa 100644 --- a/src/proto_tcp.c +++ b/src/proto_tcp.c @@ -674,6 +674,16 @@ int tcp_bind_listener(struct listener *listener, char *errmsg, int errlen) err |= ERR_WARN; } } +#endif +#if defined(TCP_FASTOPEN) + if (listener->options & LI_O_TCP_FO) { + /* TFO needs a queue length, let's use the configured backlog */ + int qlen = listener->backlog ? listener->backlog : listener->maxconn; + if (setsockopt(fd, IPPROTO_TCP, TCP_FASTOPEN, &qlen, sizeof(qlen)) == -1) { + msg = "cannot enable TCP_FASTOPEN"; + err |= ERR_WARN; + } + } #endif if (bind(fd, (struct sockaddr *)&listener->addr, listener->proto->sock_addrlen) == -1) { err |= ERR_RETRYABLE | ERR_ALERT; @@ -1726,6 +1736,21 @@ static int bind_parse_defer_accept(char **args, int cur_arg, struct proxy *px, s } #endif +#ifdef TCP_FASTOPEN +/* parse the "defer-accept" bind keyword */ +static int bind_parse_tfo(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err) +{ + struct listener *l; + + list_for_each_entry(l, &conf->listeners, by_bind) { + if (l->addr.ss_family == AF_INET || l->addr.ss_family == AF_INET6) + l->options |= LI_O_TCP_FO; + } + + return 0; +} +#endif + #ifdef TCP_MAXSEG /* parse the "mss" bind keyword */ static int bind_parse_mss(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err) @@ -1832,6 +1857,9 @@ static struct bind_kw_list bind_kws = { "TCP", { }, { #ifdef TCP_MAXSEG { "mss", bind_parse_mss, 1 }, /* set MSS of listening socket */ #endif +#ifdef TCP_FASTOPEN + { "tfo", bind_parse_tfo, 0 }, /* enable TCP_FASTOPEN of listening socket */ +#endif #ifdef CONFIG_HAP_LINUX_TPROXY { "transparent", bind_parse_transparent, 0 }, /* transparently bind to the specified addresses */ #endif