MEDIUM: server: implement TCP_USER_TIMEOUT on the server

This is equivalent to commit 2af207a ("MEDIUM: tcp: implement tcp-ut
bind option to set TCP_USER_TIMEOUT") except that this time it works
on the server side. The purpose is to detect dead server connections
even when checks are rare, disabled, or after a soft reload (since
checks are disabled there as well), and to ensure client connections
will get killed faster.
This commit is contained in:
Willy Tarreau 2015-10-13 16:16:41 +02:00
parent 061b5ded28
commit 163d4620c6
3 changed files with 54 additions and 1 deletions

View File

@ -10598,6 +10598,21 @@ ssl
Supported in default-server: No
tcp-ut <delay>
Sets the TCP User Timeout for all outgoing connections to this server. This
option is available on Linux since version 2.6.37. It allows haproxy to
configure a timeout for sockets which contain data not receiving an
acknoledgement for the configured delay. This is especially useful on
long-lived connections experiencing long idle periods such as remote
terminals or database connection pools, where the client and server timeouts
must remain high to allow a long period of idle, but where it is important to
detect that the server has disappeared in order to release all resources
associated with its connection (and the client's session). One typical use
case is also to force dead server connections to die when health checks are
too slow or during a soft reload since health checks are then disabled. The
argument is a delay expressed in milliseconds by default. This only works for
regular TCP connections, and is ignored for other protocols.
track [<proxy>/]<server>
This option enables ability to set the current state of the server by tracking
another one. It is possible to track a server which itself tracks another

View File

@ -216,6 +216,7 @@ struct server {
time_t last_change; /* last time, when the state was changed */
int puid; /* proxy-unique server ID, used for SNMP, and "first" LB algo */
int tcp_ut; /* for TCP, user timeout */
struct check check; /* health-check specific configuration */
struct check agent; /* agent specific configuration */

View File

@ -39,7 +39,6 @@
#include <types/global.h>
#include <types/capture.h>
#include <types/server.h>
#include <types/connection.h>
#include <proto/acl.h>
@ -56,6 +55,7 @@
#include <proto/proto_tcp.h>
#include <proto/proxy.h>
#include <proto/sample.h>
#include <proto/server.h>
#include <proto/stream.h>
#include <proto/stick_table.h>
#include <proto/stream_interface.h>
@ -500,6 +500,11 @@ int tcp_connect_server(struct connection *conn, int data, int delack)
setsockopt(fd, IPPROTO_TCP, TCP_QUICKACK, &zero, sizeof(zero));
#endif
#ifdef TCP_USER_TIMEOUT
/* there is not much more we can do here when it fails, it's still minor */
if (srv && srv->tcp_ut)
setsockopt(fd, IPPROTO_TCP, TCP_USER_TIMEOUT, &srv->tcp_ut, sizeof(srv->tcp_ut));
#endif
if (global.tune.server_sndbuf)
setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &global.tune.server_sndbuf, sizeof(global.tune.server_sndbuf));
@ -2310,6 +2315,31 @@ static int bind_parse_namespace(char **args, int cur_arg, struct proxy *px, stru
}
#endif
#ifdef TCP_USER_TIMEOUT
/* parse the "tcp-ut" server keyword */
static int srv_parse_tcp_ut(char **args, int *cur_arg, struct proxy *px, struct server *newsrv, char **err)
{
const char *ptr = NULL;
unsigned int timeout;
if (!*args[*cur_arg + 1]) {
memprintf(err, "'%s' : missing TCP User Timeout value", args[*cur_arg]);
return ERR_ALERT | ERR_FATAL;
}
ptr = parse_time_err(args[*cur_arg + 1], &timeout, TIME_UNIT_MS);
if (ptr) {
memprintf(err, "'%s' : expects a positive delay in milliseconds", args[*cur_arg]);
return ERR_ALERT | ERR_FATAL;
}
if (newsrv->addr.ss_family == AF_INET || newsrv->addr.ss_family == AF_INET6)
newsrv->tcp_ut = timeout;
return 0;
}
#endif
static struct cfg_kw_list cfg_kws = {ILH, {
{ CFG_LISTEN, "tcp-request", tcp_parse_tcp_req },
{ CFG_LISTEN, "tcp-response", tcp_parse_tcp_rep },
@ -2385,6 +2415,12 @@ static struct bind_kw_list bind_kws = { "TCP", { }, {
{ NULL, NULL, 0 },
}};
static struct srv_kw_list srv_kws = { "TCP", { }, {
#ifdef TCP_USER_TIMEOUT
{ "tcp-ut", srv_parse_tcp_ut, 1, 0 }, /* set TCP user timeout on server */
#endif
{ NULL, NULL, 0 },
}};
static struct action_kw_list tcp_req_conn_actions = {ILH, {
{ "silent-drop", tcp_parse_silent_drop },
@ -2421,6 +2457,7 @@ static void __tcp_protocol_init(void)
cfg_register_keywords(&cfg_kws);
acl_register_keywords(&acl_kws);
bind_register_keywords(&bind_kws);
srv_register_keywords(&srv_kws);
tcp_req_conn_keywords_register(&tcp_req_conn_actions);
tcp_req_cont_keywords_register(&tcp_req_cont_actions);
tcp_res_cont_keywords_register(&tcp_res_cont_actions);