mirror of
https://git.haproxy.org/git/haproxy.git/
synced 2025-08-05 14:47:07 +02:00
MINOR: mux-quic: support glitches
Implement basic support for glitches on QUIC multiplexer. This is mostly identical too glitches for HTTP/2. A new configuration option named tune.quic.frontend.glitches-threshold is defined to limit the number of glitches on a connection before closing it. Glitches counter is incremented via qcc_report_glitch(). A new qcc_app_ops callback <report_susp> is defined. On threshold reaching, it allows to set an application error code to close the connection. For HTTP/3, value H3_EXCESSIVE_LOAD is returned. If not defined, default code INTERNAL_ERROR is used. For the moment, no glitch are reported for QUIC or HTTP/3 usage. This will be added in future patches as needed.
This commit is contained in:
parent
a6993a669b
commit
216f70f989
@ -1406,6 +1406,7 @@ The following keywords are supported in the "global" section :
|
||||
- tune.pt.zero-copy-forwarding
|
||||
- tune.quic.cc-hystart
|
||||
- tune.quic.frontend.conn-tx-buffers.limit
|
||||
- tune.quic.frontend.glitches-threshold
|
||||
- tune.quic.frontend.max-idle-timeout
|
||||
- tune.quic.frontend.max-streams-bidi
|
||||
- tune.quic.max-frame-loss
|
||||
@ -3696,6 +3697,18 @@ tune.quic.frontend.conn-tx-buffers.limit <number>
|
||||
and memory consumption and can be adjusted according to an estimated round
|
||||
time-trip. Each buffer is tune.bufsize.
|
||||
|
||||
tune.quic.frontend.glitches-threshold <number>
|
||||
Sets the threshold for the number of glitches on a frontend connection, where
|
||||
that connection will automatically be killed. This allows to automatically
|
||||
kill misbehaving connections without having to write explicit rules for them.
|
||||
The default value is zero, indicating that no threshold is set so that no
|
||||
event will cause a connection to be closed. Beware that some QUIC clients may
|
||||
occasionally cause a few glitches over long lasting connection, so any non-
|
||||
zero value here should probably be in the hundreds or thousands to be
|
||||
effective without affecting slightly bogus clients.
|
||||
|
||||
See also: fc_glitches
|
||||
|
||||
tune.quic.frontend.max-idle-timeout <timeout>
|
||||
Sets the QUIC max_idle_timeout transport parameters in milliseconds for
|
||||
frontends which determines the period of time after which a connection silently
|
||||
|
@ -196,6 +196,7 @@ struct global {
|
||||
#ifdef USE_QUIC
|
||||
unsigned int quic_backend_max_idle_timeout;
|
||||
unsigned int quic_frontend_max_idle_timeout;
|
||||
unsigned int quic_frontend_glitches_threshold;
|
||||
unsigned int quic_frontend_max_streams_bidi;
|
||||
unsigned int quic_retry_threshold;
|
||||
unsigned int quic_reorder_ratio;
|
||||
|
@ -41,6 +41,7 @@ struct qcc {
|
||||
uint64_t nb_sc; /* number of attached stream connectors */
|
||||
uint64_t nb_hreq; /* number of in-progress http requests */
|
||||
uint32_t flags; /* QC_CF_* */
|
||||
int glitches; /* total number of glitches on this connection */
|
||||
|
||||
/* flow-control fields set by us enforced on our side. */
|
||||
struct {
|
||||
@ -216,6 +217,8 @@ struct qcc_app_ops {
|
||||
|
||||
/* Increment app counters on CONNECTION_CLOSE_APP reception. */
|
||||
void (*inc_err_cnt)(void *ctx, int err_code);
|
||||
/* Set QCC error code as suspicious activity has been detected. */
|
||||
void (*report_susp)(void *ctx);
|
||||
};
|
||||
|
||||
#endif /* USE_QUIC */
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include <haproxy/stconn.h>
|
||||
|
||||
void qcc_set_error(struct qcc *qcc, int err, int app);
|
||||
int qcc_report_glitch(struct qcc *qcc, int inc);
|
||||
struct qcs *qcc_init_stream_local(struct qcc *qcc, int bidi);
|
||||
struct stconn *qcs_attach_sc(struct qcs *qcs, struct buffer *buf, char fin);
|
||||
int qcs_is_close_local(struct qcs *qcs);
|
||||
|
@ -235,6 +235,8 @@ static int cfg_parse_quic_tune_setting(char **args, int section_type,
|
||||
suffix = args[0] + prefix_len;
|
||||
if (strcmp(suffix, "frontend.conn-tx-buffers.limit") == 0)
|
||||
global.tune.quic_streams_buf = arg;
|
||||
else if (strcmp(suffix, "frontend.glitches-threshold") == 0)
|
||||
global.tune.quic_frontend_glitches_threshold = arg;
|
||||
else if (strcmp(suffix, "frontend.max-streams-bidi") == 0)
|
||||
global.tune.quic_frontend_max_streams_bidi = arg;
|
||||
else if (strcmp(suffix, "max-frame-loss") == 0)
|
||||
@ -300,6 +302,7 @@ static struct cfg_kw_list cfg_kws = {ILH, {
|
||||
{ CFG_GLOBAL, "tune.quic.backend.max-idle-timeou", cfg_parse_quic_time },
|
||||
{ CFG_GLOBAL, "tune.quic.cc-hystart", cfg_parse_quic_tune_on_off },
|
||||
{ CFG_GLOBAL, "tune.quic.frontend.conn-tx-buffers.limit", cfg_parse_quic_tune_setting },
|
||||
{ CFG_GLOBAL, "tune.quic.frontend.glitches-threshold", cfg_parse_quic_tune_setting },
|
||||
{ CFG_GLOBAL, "tune.quic.frontend.max-streams-bidi", cfg_parse_quic_tune_setting },
|
||||
{ CFG_GLOBAL, "tune.quic.frontend.max-idle-timeout", cfg_parse_quic_time },
|
||||
{ CFG_GLOBAL, "tune.quic.max-frame-loss", cfg_parse_quic_tune_setting },
|
||||
|
7
src/h3.c
7
src/h3.c
@ -2399,6 +2399,12 @@ static void h3_stats_inc_err_cnt(void *ctx, int err_code)
|
||||
h3_inc_err_cnt(h3c->prx_counters, err_code);
|
||||
}
|
||||
|
||||
static void h3_report_susp(void *ctx)
|
||||
{
|
||||
struct h3c *h3c = ctx;
|
||||
h3c->qcc->err = quic_err_app(H3_ERR_EXCESSIVE_LOAD);
|
||||
}
|
||||
|
||||
static inline const char *h3_ft_str(uint64_t type)
|
||||
{
|
||||
switch (type) {
|
||||
@ -2455,5 +2461,6 @@ const struct qcc_app_ops h3_ops = {
|
||||
.detach = h3_detach,
|
||||
.shutdown = h3_shutdown,
|
||||
.inc_err_cnt = h3_stats_inc_err_cnt,
|
||||
.report_susp = h3_report_susp,
|
||||
.release = h3_release,
|
||||
};
|
||||
|
@ -556,6 +556,28 @@ void qcc_set_error(struct qcc *qcc, int err, int app)
|
||||
tasklet_wakeup(qcc->wait_event.tasklet);
|
||||
}
|
||||
|
||||
/* Increment glitch counter for <qcc> connection by <inc> steps. If configured
|
||||
* threshold reached, close the connection with an error code.
|
||||
*/
|
||||
int qcc_report_glitch(struct qcc *qcc, int inc)
|
||||
{
|
||||
const int max = global.tune.quic_frontend_glitches_threshold;
|
||||
|
||||
qcc->glitches += inc;
|
||||
if (max && qcc->glitches >= max && !(qcc->flags & QC_CF_ERRL)) {
|
||||
if (qcc->app_ops->report_susp) {
|
||||
qcc->app_ops->report_susp(qcc->ctx);
|
||||
qcc_set_error(qcc, qcc->err.code, 1);
|
||||
}
|
||||
else {
|
||||
qcc_set_error(qcc, QC_ERR_INTERNAL_ERROR, 0);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Open a locally initiated stream for the connection <qcc>. Set <bidi> for a
|
||||
* bidirectional stream, else an unidirectional stream is opened. The next
|
||||
* available ID on the connection will be used according to the stream type.
|
||||
@ -2622,6 +2644,7 @@ static int qmux_init(struct connection *conn, struct proxy *prx,
|
||||
conn->ctx = qcc;
|
||||
qcc->nb_hreq = qcc->nb_sc = 0;
|
||||
qcc->flags = 0;
|
||||
qcc->glitches = 0;
|
||||
qcc->err = quic_err_transport(QC_ERR_NO_ERROR);
|
||||
|
||||
/* Server parameters, params used for RX flow control. */
|
||||
@ -3144,6 +3167,9 @@ static int qmux_ctl(struct connection *conn, enum mux_ctl_type mux_ctl, void *ou
|
||||
case MUX_CTL_EXIT_STATUS:
|
||||
return MUX_ES_UNKNOWN;
|
||||
|
||||
case MUX_CTL_GET_GLITCHES:
|
||||
return qcc->glitches;
|
||||
|
||||
case MUX_CTL_GET_NBSTRM: {
|
||||
struct qcs *qcs;
|
||||
unsigned int nb_strm = qcc->nb_sc;
|
||||
|
Loading…
Reference in New Issue
Block a user