diff --git a/Makefile b/Makefile index b5d160251..1f1de6d46 100644 --- a/Makefile +++ b/Makefile @@ -607,7 +607,7 @@ OPTIONS_OBJS += src/quic_conn.o src/mux_quic.o src/h3.o src/xprt_quic.o \ src/quic_cc_newreno.o src/quic_cc_cubic.o src/qpack-tbl.o \ src/qpack-dec.o src/hq_interop.o src/quic_stream.o \ src/h3_stats.o src/qmux_http.o src/cfgparse-quic.o \ - src/cbuf.o src/quic_cc.o + src/cbuf.o src/quic_cc.o src/quic_cc_nocc.o endif ifneq ($(USE_LUA),) diff --git a/include/haproxy/quic_cc-t.h b/include/haproxy/quic_cc-t.h index f646c73d8..35996d721 100644 --- a/include/haproxy/quic_cc-t.h +++ b/include/haproxy/quic_cc-t.h @@ -37,6 +37,10 @@ extern struct quic_cc_algo quic_cc_algo_nr; extern struct quic_cc_algo quic_cc_algo_cubic; extern struct quic_cc_algo *default_quic_cc_algo; +/* Fake algorithm with its fixed window */ +extern struct quic_cc_algo quic_cc_algo_nocc; +extern unsigned int quic_cc_nocc_fixed_cwnd; + extern unsigned long long last_ts; enum quic_cc_algo_state_type { @@ -73,6 +77,7 @@ struct quic_cc_event { enum quic_cc_algo_type { QUIC_CC_ALGO_TP_NEWRENO, QUIC_CC_ALGO_TP_CUBIC, + QUIC_CC_ALGO_TP_NOCC, }; struct quic_cc { diff --git a/src/cfgparse-quic.c b/src/cfgparse-quic.c index 35548d36b..c8cb7d963 100644 --- a/src/cfgparse-quic.c +++ b/src/cfgparse-quic.c @@ -20,16 +20,27 @@ static int bind_parse_quic_cc_algo(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err) { struct quic_cc_algo *cc_algo; + char *arg; if (!*args[cur_arg + 1]) { memprintf(err, "'%s' : missing control congestion algorithm", args[cur_arg]); return ERR_ALERT | ERR_FATAL; } - if (strcmp(args[cur_arg + 1], "newreno") == 0) + arg = args[cur_arg + 1]; + if (strcmp(arg, "newreno") == 0) cc_algo = &quic_cc_algo_nr; - else if (strcmp(args[cur_arg + 1], "cubic") == 0) + else if (strcmp(arg, "cubic") == 0) cc_algo = &quic_cc_algo_cubic; + else if (strlen(arg) >= 6 && strncmp(arg, "nocc-", 5) == 0) { + if (!experimental_directives_allowed) { + ha_alert("'%s' algo is experimental, must be allowed via a global 'expose-experimental-directives'\n", arg); + return ERR_ALERT | ERR_FATAL; + } + + cc_algo = &quic_cc_algo_nocc; + quic_cc_nocc_fixed_cwnd = atoi(arg + 5); + } else { memprintf(err, "'%s' : unknown control congestion algorithm", args[cur_arg]); return ERR_ALERT | ERR_FATAL; diff --git a/src/quic_cc_nocc.c b/src/quic_cc_nocc.c new file mode 100644 index 000000000..27db35024 --- /dev/null +++ b/src/quic_cc_nocc.c @@ -0,0 +1,79 @@ +/* + * Fake congestion control algorithm which does nothing except initializing + * the congestion control window to a fixed value. + * + */ + +#include +#include +#include + +#define TRACE_SOURCE &trace_quic + +unsigned int quic_cc_nocc_fixed_cwnd; + +static int quic_cc_nocc_init(struct quic_cc *cc) +{ + struct quic_path *path; + + path = container_of(cc, struct quic_path, cc); + path->cwnd = quic_cc_nocc_fixed_cwnd << 10; + return 1; +} + +static void quic_cc_nocc_slow_start(struct quic_cc *cc) +{ +} + +/* Slow start callback. */ +static void quic_cc_nocc_ss_cb(struct quic_cc *cc, struct quic_cc_event *ev) +{ + TRACE_ENTER(QUIC_EV_CONN_CC, cc->qc); + TRACE_PROTO("CC nocc", QUIC_EV_CONN_CC, cc->qc, ev, cc); + TRACE_LEAVE(QUIC_EV_CONN_CC, cc->qc); +} + +/* Congestion avoidance callback. */ +static void quic_cc_nocc_ca_cb(struct quic_cc *cc, struct quic_cc_event *ev) +{ + TRACE_ENTER(QUIC_EV_CONN_CC, cc->qc); + TRACE_PROTO("CC nocc", QUIC_EV_CONN_CC, cc->qc, ev, cc); + TRACE_LEAVE(QUIC_EV_CONN_CC, cc->qc); +} + +/* Recovery period callback. */ +static void quic_cc_nocc_rp_cb(struct quic_cc *cc, struct quic_cc_event *ev) +{ + TRACE_ENTER(QUIC_EV_CONN_CC, cc->qc); + TRACE_PROTO("CC nocc", QUIC_EV_CONN_CC, cc->qc, ev, cc); + TRACE_LEAVE(QUIC_EV_CONN_CC, cc->qc); +} + +static void quic_cc_nocc_state_trace(struct buffer *buf, const struct quic_cc *cc) +{ + struct quic_path *path; + + path = container_of(cc, struct quic_path, cc); + chunk_appendf(buf, " cwnd=%llu", (unsigned long long)path->cwnd); +} + +static void (*quic_cc_nocc_state_cbs[])(struct quic_cc *cc, + struct quic_cc_event *ev) = { + [QUIC_CC_ST_SS] = quic_cc_nocc_ss_cb, + [QUIC_CC_ST_CA] = quic_cc_nocc_ca_cb, + [QUIC_CC_ST_RP] = quic_cc_nocc_rp_cb, +}; + +static void quic_cc_nocc_event(struct quic_cc *cc, struct quic_cc_event *ev) +{ + return quic_cc_nocc_state_cbs[cc->algo->state](cc, ev); +} + +struct quic_cc_algo quic_cc_algo_nocc = { + .type = QUIC_CC_ALGO_TP_NOCC, + .init = quic_cc_nocc_init, + .event = quic_cc_nocc_event, + .slow_start = quic_cc_nocc_slow_start, + .state_trace = quic_cc_nocc_state_trace, +}; +