diff --git a/doc/configuration.txt b/doc/configuration.txt index 7bcf22cc0..b1f471c6a 100644 --- a/doc/configuration.txt +++ b/doc/configuration.txt @@ -17621,6 +17621,18 @@ id must be strictly positive and unique within the listener/frontend. This option can only be used when defining only a single socket. +idle-ping + May be used in the following contexts: tcp, http, log + + Define an interval for periodic liveliness on idle frontend connections. If + the peer is unable to respond before the next scheduled test, the connection + is closed. Else, the client timeout is refreshed and the connection is kept. + Note that http-request/http-keep-alive timers run in parallel and are not + refreshed by idle-ping. + + This feature relies on specific underlying protocol support. For now, only H2 + mux implements it. Idle-ping is simply ignored by other protocols. + interface Restricts the socket to a specific interface. When specified, only packets received from that particular interface are processed by the socket. This is diff --git a/include/haproxy/connection.h b/include/haproxy/connection.h index 981c94803..2e79a129f 100644 --- a/include/haproxy/connection.h +++ b/include/haproxy/connection.h @@ -716,8 +716,8 @@ static inline int conn_idle_ping(const struct connection *conn) return srv ? srv->idle_ping : TICK_ETERNITY; } else { - /* TODO */ - return TICK_ETERNITY; + struct session *sess = conn->owner; + return sess->listener->bind_conf->idle_ping; } } diff --git a/include/haproxy/listener-t.h b/include/haproxy/listener-t.h index becc83b01..7518aa6ec 100644 --- a/include/haproxy/listener-t.h +++ b/include/haproxy/listener-t.h @@ -193,6 +193,7 @@ struct bind_conf { unsigned int analysers; /* bitmap of required protocol analysers */ int maxseg; /* for TCP, advertised MSS */ int tcp_ut; /* for TCP, user timeout */ + int idle_ping; /* MUX idle-ping interval in ms */ int maxaccept; /* if set, max number of connections accepted at once (-1 when disabled) */ unsigned int backlog; /* if set, listen backlog */ int maxconn; /* maximum connections allowed on this listener */ diff --git a/src/listener.c b/src/listener.c index 95a5fef70..c161c885b 100644 --- a/src/listener.c +++ b/src/listener.c @@ -2216,6 +2216,44 @@ static int bind_parse_id(char **args, int cur_arg, struct proxy *px, struct bind return 0; } +/* Parse the "idle-ping" bind keyword */ +static int bind_parse_idle_ping(char **args, int cur_arg, + struct proxy *px, struct bind_conf *conf, + char **err) +{ + const char *res; + unsigned int value; + + if (!*(args[cur_arg+1])) { + memprintf(err, "'%s' expects an argument.", args[cur_arg]); + goto error; + } + + res = parse_time_err(args[cur_arg+1], &value, TIME_UNIT_MS); + if (res == PARSE_TIME_OVER) { + memprintf(err, "timer overflow in argument <%s> to <%s> on bind line, maximum value is 2147483647 ms (~24.8 days).", + args[cur_arg+1], args[cur_arg]); + goto error; + } + else if (res == PARSE_TIME_UNDER) { + memprintf(err, "timer underflow in argument <%s> to <%s> on bind line, minimum non-null value is 1 ms.", + args[cur_arg+1], args[cur_arg]); + goto error; + } + else if (res) { + memprintf(err, "unexpected character '%c' in '%s' argument on bind line.", + *res, args[cur_arg]); + goto error; + } + + conf->idle_ping = value; + + return 0; + + error: + return ERR_ALERT | ERR_FATAL; +} + /* Complete a bind_conf by parsing the args after the address. is the * arguments array, is the first one to be considered.
is * the section name to report in error messages, and and are @@ -2584,6 +2622,7 @@ static struct bind_kw_list bind_kws = { "ALL", { }, { { "backlog", bind_parse_backlog, 1, 0 }, /* set backlog of listening socket */ { "guid-prefix", bind_parse_guid_prefix, 1, 1 }, /* set guid of listening socket */ { "id", bind_parse_id, 1, 1 }, /* set id of listening socket */ + { "idle-ping", bind_parse_idle_ping, 1, 1 }, /* activate idle ping if mux support it */ { "maxconn", bind_parse_maxconn, 1, 0 }, /* set maxconn of listening socket */ { "name", bind_parse_name, 1, 1 }, /* set name of listening socket */ { "nbconn", bind_parse_nbconn, 1, 1 }, /* set number of connection on active preconnect */ diff --git a/src/mux_h2.c b/src/mux_h2.c index 7f99ffd54..86e39e5e2 100644 --- a/src/mux_h2.c +++ b/src/mux_h2.c @@ -863,6 +863,7 @@ static void h2c_update_timeout(struct h2c *h2c) else { int dft = TICK_ETERNITY; int exp = TICK_ETERNITY; + int ping = TICK_ETERNITY; /* idle connection : no stream, no output data */ if (h2c->flags & (H2_CF_GOAWAY_SENT|H2_CF_GOAWAY_FAILED)) { @@ -904,13 +905,19 @@ static void h2c_update_timeout(struct h2c *h2c) is_idle_conn = 1; } - else if (!(h2c->proxy->flags & (PR_FL_DISABLED|PR_FL_STOPPED))) { + else { /* Only idle-ping is relevant for backend idle conn. */ - exp = tick_add_ifset(now_ms, conn_idle_ping(h2c->conn)); - if (tick_isset(exp) && !(h2c->flags & H2_CF_IDL_PING_SENT)) { - /* If PING timer selected, set flag to trigger its emission rather than conn deletion on next timeout. */ - h2c->flags |= H2_CF_IDL_PING; - } + exp = TICK_ETERNITY; + } + + if (!(h2c->proxy->flags & (PR_FL_DISABLED|PR_FL_STOPPED))) + ping = tick_add_ifset(now_ms, conn_idle_ping(h2c->conn)); + + exp = tick_first(exp, ping); + /* If PING timer selected, set flag to trigger its emission rather than conn deletion on next timeout. */ + if (tick_isset(exp) && exp == ping && ping != dft && + !(h2c->flags & H2_CF_IDL_PING_SENT)) { + h2c->flags |= H2_CF_IDL_PING; } }