mirror of
https://git.haproxy.org/git/haproxy.git/
synced 2025-09-22 06:11:32 +02:00
[MINOR] tcp: add support for the defer_accept bind option
This can ensure that data is readily available on a socket when we accept it, but a bug in the kernel ignores the timeout so the socket can remain pending as long as the client does not talk. Use with care.
This commit is contained in:
parent
f2d2b1d128
commit
cb6cd43725
@ -1132,6 +1132,7 @@ bind [<address>]:<port> [, ...] mss <maxseg>
|
|||||||
bind [<address>]:<port> [, ...] transparent
|
bind [<address>]:<port> [, ...] transparent
|
||||||
bind [<address>]:<port> [, ...] id <id>
|
bind [<address>]:<port> [, ...] id <id>
|
||||||
bind [<address>]:<port> [, ...] name <name>
|
bind [<address>]:<port> [, ...] name <name>
|
||||||
|
bind [<address>]:<port> [, ...] defer_accept
|
||||||
Define one or several listening addresses and/or ports in a frontend.
|
Define one or several listening addresses and/or ports in a frontend.
|
||||||
May be used in sections : defaults | frontend | listen | backend
|
May be used in sections : defaults | frontend | listen | backend
|
||||||
no | yes | yes | no
|
no | yes | yes | no
|
||||||
@ -1182,6 +1183,20 @@ bind [<address>]:<port> [, ...] name <name>
|
|||||||
the specified port. This keyword is available only when
|
the specified port. This keyword is available only when
|
||||||
HAProxy is built with USE_LINUX_TPROXY=1.
|
HAProxy is built with USE_LINUX_TPROXY=1.
|
||||||
|
|
||||||
|
defer_accept is an optional keyword which is supported only on certain
|
||||||
|
Linux kernels. It states that a connection will only be
|
||||||
|
accepted once some data arrive on it, or at worst after the
|
||||||
|
first retransmit. This should be used only on protocols for
|
||||||
|
which the client talks first (eg: HTTP). It can slightly
|
||||||
|
improve performance by ensuring that most of the request is
|
||||||
|
already available when the connection is accepted. On the
|
||||||
|
other hand, it will not be able to detect connections which
|
||||||
|
don't talk. It is important to note that this option is
|
||||||
|
broken in all kernels up to 2.6.31, as the connection is
|
||||||
|
never accepted until the client talks. This can cause issues
|
||||||
|
with front firewalls which would see an established
|
||||||
|
connection while the proxy will only see it in SYN_RECV.
|
||||||
|
|
||||||
It is possible to specify a list of address:port combinations delimited by
|
It is possible to specify a list of address:port combinations delimited by
|
||||||
commas. The frontend will then listen on all of these addresses. There is no
|
commas. The frontend will then listen on all of these addresses. There is no
|
||||||
fixed limit to the number of addresses and ports which can be listened on in
|
fixed limit to the number of addresses and ports which can be listened on in
|
||||||
|
@ -71,6 +71,7 @@
|
|||||||
#define LI_O_NOLINGER 0x0001 /* disable linger on this socket */
|
#define LI_O_NOLINGER 0x0001 /* disable linger on this socket */
|
||||||
#define LI_O_FOREIGN 0x0002 /* permit listening on foreing addresses */
|
#define LI_O_FOREIGN 0x0002 /* permit listening on foreing addresses */
|
||||||
#define LI_O_NOQUICKACK 0x0004 /* disable quick ack of immediate data (linux) */
|
#define LI_O_NOQUICKACK 0x0004 /* disable quick ack of immediate data (linux) */
|
||||||
|
#define LI_O_DEF_ACCEPT 0x0008 /* wait up to 1 second for data before accepting */
|
||||||
|
|
||||||
/* The listener will be directly referenced by the fdtab[] which holds its
|
/* The listener will be directly referenced by the fdtab[] which holds its
|
||||||
* socket. The listener provides the protocol-specific accept() function to
|
* socket. The listener provides the protocol-specific accept() function to
|
||||||
|
@ -1143,6 +1143,24 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm)
|
|||||||
goto out;
|
goto out;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!strcmp(args[cur_arg], "defer-accept")) { /* wait for some data for 1 second max before doing accept */
|
||||||
|
#ifdef TCP_DEFER_ACCEPT
|
||||||
|
struct listener *l;
|
||||||
|
|
||||||
|
for (l = curproxy->listen; l != last_listen; l = l->next)
|
||||||
|
l->options |= LI_O_DEF_ACCEPT;
|
||||||
|
|
||||||
|
cur_arg ++;
|
||||||
|
continue;
|
||||||
|
#else
|
||||||
|
Alert("parsing [%s:%d] : '%s' : '%s' option not implemented.\n",
|
||||||
|
file, linenum, args[0], args[cur_arg]);
|
||||||
|
err_code |= ERR_ALERT | ERR_FATAL;
|
||||||
|
goto out;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
if (!strcmp(args[cur_arg], "transparent")) { /* transparently bind to these addresses */
|
if (!strcmp(args[cur_arg], "transparent")) { /* transparently bind to these addresses */
|
||||||
#ifdef CONFIG_HAP_LINUX_TPROXY
|
#ifdef CONFIG_HAP_LINUX_TPROXY
|
||||||
struct listener *l;
|
struct listener *l;
|
||||||
@ -1212,7 +1230,7 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
Alert("parsing [%s:%d] : '%s' only supports the 'transparent', 'name', 'id', 'mss' and 'interface' options.\n",
|
Alert("parsing [%s:%d] : '%s' only supports the 'transparent', 'defer-accept', 'name', 'id', 'mss' and 'interface' options.\n",
|
||||||
file, linenum, args[0]);
|
file, linenum, args[0]);
|
||||||
err_code |= ERR_ALERT | ERR_FATAL;
|
err_code |= ERR_ALERT | ERR_FATAL;
|
||||||
goto out;
|
goto out;
|
||||||
|
@ -519,6 +519,16 @@ int tcp_bind_listener(struct listener *listener, char *errmsg, int errlen)
|
|||||||
err |= ERR_WARN;
|
err |= ERR_WARN;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
#if defined(TCP_DEFER_ACCEPT)
|
||||||
|
if (listener->options & LI_O_DEF_ACCEPT) {
|
||||||
|
/* defer accept by up to one second */
|
||||||
|
int accept_delay = 1;
|
||||||
|
if (setsockopt(fd, IPPROTO_TCP, TCP_DEFER_ACCEPT, &accept_delay, sizeof(accept_delay)) == -1) {
|
||||||
|
msg = "cannot enable DEFER_ACCEPT";
|
||||||
|
err |= ERR_WARN;
|
||||||
|
}
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
if (bind(fd, (struct sockaddr *)&listener->addr, listener->proto->sock_addrlen) == -1) {
|
if (bind(fd, (struct sockaddr *)&listener->addr, listener->proto->sock_addrlen) == -1) {
|
||||||
err |= ERR_RETRYABLE | ERR_ALERT;
|
err |= ERR_RETRYABLE | ERR_ALERT;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user