BUG/MINOR: quic: split option for congestion max window size

This commit is contained in:
Amaury Denoyelle 2025-09-10 10:48:12 +02:00
parent 33afba0dda
commit d5142706f8
8 changed files with 72 additions and 36 deletions

View File

@ -1891,6 +1891,7 @@ The following keywords are supported in the "global" section :
- tune.quic.be.cc.cubic-min-losses
- tune.quic.be.cc.hystart
- tune.quic.be.cc.max-frame-loss
- tune.quic.be.cc.max-win-size
- tune.quic.be.cc.reorder-ratio
- tune.quic.be.max-idle-timeout
- tune.quic.be.sec.glitches-threshold
@ -1903,6 +1904,7 @@ The following keywords are supported in the "global" section :
- tune.quic.fe.cc.cubic-min-losses
- tune.quic.fe.cc.hystart
- tune.quic.fe.cc.max-frame-loss
- tune.quic.fe.cc.max-win-size
- tune.quic.fe.cc.reorder-ratio
- tune.quic.fe.max-idle-timeout
- tune.quic.fe.sec.glitches-threshold
@ -1915,7 +1917,7 @@ The following keywords are supported in the "global" section :
- tune.quic.frontend.max-streams-bidi
- tune.quic.frontend.max-tx-mem (deprecated)
- tune.quic.frontend.stream-data-ratio
- tune.quic.frontend.default-max-window-size
- tune.quic.frontend.default-max-window-size (deprecated)
- tune.quic.listen
- tune.quic.max-frame-loss (deprecated)
- tune.quic.mem.tx-max
@ -4753,6 +4755,26 @@ tune.quic.max-frame-loss <number> (deprecated)
part of the streamlining process apply on QUIC configuration. If used, this
setting will only be applied on frontend connections.
tune.quic.be.cc.max-win-size <size>
tune.quic.fe.cc.max-win-size <size>
Sets the default maximum window size for the congestion controller of a
single QUIC connection either on frontend or backend side. The value must be
written as an integer with an optional suffix 'k', 'm' or 'g'. It must be
between 10k and 4g.
QUIC multiplexer also uses the current congestion window size to determine if
it can allocate new stream buffers on data emission. As such, the maximum
congestion window size also serves as a limit on this allocator.
The default value is 480k.
See also the "quic-cc-algo" bind option.
tune.quic.frontend.default-max-window-size <size> (deprecated)
This keyword has been deprecated in 3.3 and will be removed in 3.5. It is
part of the streamlining process apply on QUIC configuration. If used, this
setting will only be applied on frontend connections.
tune.quic.be.cc.reorder-ratio <0..100, in percent>
tune.quic.fe.cc.reorder-ratio <0..100, in percent>
The ratio applied to the packet reordering threshold calculated. It may
@ -4934,19 +4956,6 @@ tune.quic.frontend.stream-data-ratio <0..100, in percent>
See also: "tune.quic.frontend.max-data-size",
"tune.quic.frontend.max-streams-bidi"
tune.quic.frontend.default-max-window-size <size>
Sets the default maximum window size for the congestion controller of a
single QUIC connection. The value must be written as an integer with an
optional suffix 'k', 'm' or 'g'. It must be between 10k and 4g.
QUIC multiplexer also uses the current congestion window size to determine if
it can allocate new stream buffers on data emission. As such, the maximum
congestion window size also serves as a limit on this allocator.
The default value is 480k.
See also the "quic-cc-algo" bind option.
tune.quic.listen { on | off }
Disable QUIC transport protocol on the frontend side. All the QUIC listeners
will still be created, but they won't listen for incoming datagrams. Hence,
@ -17166,7 +17175,7 @@ quic-cc-algo { cubic | newreno | bbr | nocc }[(<args,...>)]
comma. Each argument is optional and can be empty if needed. Here is the
mandatory order of each parameters :
- maximum window size in bytes. It must be greater than 10k and smaller than
4g. By default "tune.quic.frontend.default-max-window-size" value is used.
4g. By default "tune.quic.fe.cc.max-win-size" value is used.
Example:
# newreno congestion control algorithm

View File

@ -217,7 +217,6 @@ struct global {
#ifdef USE_QUIC
unsigned int quic_frontend_max_data;
unsigned int quic_frontend_max_streams_bidi;
size_t quic_frontend_max_window_size;
unsigned int quic_frontend_stream_data_ratio;
#endif /* USE_QUIC */
} tune;

View File

@ -91,8 +91,6 @@ typedef unsigned long long ull;
#define QUIC_TOKEN_FMT_NEW 0xb7
/* Retry token duration */
#define QUIC_RETRY_DURATION_SEC 10
/* Default congestion window size. 480 kB, equivalent to the legacy value which was 30*bufsize */
#define QUIC_DFLT_MAX_WINDOW_SIZE 491520
/* Default ratio applied for max-stream-data-bidi-remote derived from max-data */
#define QUIC_DFLT_FRONT_STREAM_DATA_RATIO 90

View File

@ -9,6 +9,8 @@
/* Default limit of loss detection on a single frame. If exceeded, connection is closed. */
#define QUIC_DFLT_CC_MAX_FRAME_LOSS 10
/* Default congestion window size. 480 kB, equivalent to the legacy value which was 30*bufsize */
#define QUIC_DFLT_CC_MAX_WIN_SIZE 491520
/* Default ratio value applied to a dynamic Packet reorder threshold. */
#define QUIC_DFLT_CC_REORDER_RATIO 50 /* in percent */
/* Default max-idle-timeout advertised via TP */
@ -29,6 +31,7 @@ struct quic_tune {
struct {
uint cc_cubic_min_losses;
uint cc_max_frame_loss;
size_t cc_max_win_size;
uint cc_reorder_ratio;
uint max_idle_timeout;
uint sec_glitches_threshold;
@ -40,6 +43,7 @@ struct quic_tune {
struct {
uint cc_cubic_min_losses;
uint cc_max_frame_loss;
size_t cc_max_win_size;
uint cc_reorder_ratio;
uint max_idle_timeout;
uint sec_glitches_threshold;

View File

@ -26,6 +26,7 @@
struct quic_tune quic_tune = {
.fe = {
.cc_max_frame_loss = QUIC_DFLT_CC_MAX_FRAME_LOSS,
.cc_max_win_size = QUIC_DFLT_CC_MAX_WIN_SIZE,
.cc_reorder_ratio = QUIC_DFLT_CC_REORDER_RATIO,
.max_idle_timeout = QUIC_DFLT_FE_MAX_IDLE_TIMEOUT,
.sec_retry_threshold = QUIC_DFLT_SEC_RETRY_THRESHOLD,
@ -34,6 +35,7 @@ struct quic_tune quic_tune = {
},
.be = {
.cc_max_frame_loss = QUIC_DFLT_CC_MAX_FRAME_LOSS,
.cc_max_win_size = QUIC_DFLT_CC_MAX_WIN_SIZE,
.cc_reorder_ratio = QUIC_DFLT_CC_REORDER_RATIO,
.max_idle_timeout = QUIC_DFLT_BE_MAX_IDLE_TIMEOUT,
.fb_opts = QUIC_TUNE_FB_TX_PACING|QUIC_TUNE_FB_TX_UDP_GSO,
@ -376,6 +378,23 @@ static int cfg_parse_quic_tune_setting(char **args, int section_type,
&quic_tune.fe.cc_max_frame_loss;
*ptr = arg;
}
else if (strcmp(suffix, "be.cc.max-win-size") == 0 ||
strcmp(suffix, "fe.cc.max-win-size") == 0) {
size_t *ptr = (suffix[0] == 'b') ? &quic_tune.be.cc_max_win_size :
&quic_tune.fe.cc_max_win_size;
unsigned long cwnd;
char *end_opt;
cwnd = parse_window_size(args[0], args[1], &end_opt, err);
if (!cwnd)
return -1;
if (*end_opt != '\0') {
memprintf(err, "'%s' : expects an integer value with an optional suffix 'k', 'm' or 'g'", args[0]);
return -1;
}
*ptr = cwnd;
}
else if (strcmp(suffix, "be.cc.reorder-ratio") == 0 ||
strcmp(suffix, "fe.cc.reorder-ratio") == 0) {
uint *ptr = (suffix[0] == 'b') ? &quic_tune.be.cc_reorder_ratio :
@ -402,20 +421,6 @@ static int cfg_parse_quic_tune_setting(char **args, int section_type,
}
else if (strcmp(suffix, "frontend.max-streams-bidi") == 0)
global.tune.quic_frontend_max_streams_bidi = arg;
else if (strcmp(suffix, "frontend.default-max-window-size") == 0) {
unsigned long cwnd;
char *end_opt;
cwnd = parse_window_size(args[0], args[1], &end_opt, err);
if (!cwnd)
return -1;
if (*end_opt != '\0') {
memprintf(err, "'%s' : expects an integer value with an optional suffix 'k', 'm' or 'g'", args[0]);
return -1;
}
global.tune.quic_frontend_max_window_size = cwnd;
}
else if (strcmp(suffix, "frontend.stream-data-ratio") == 0) {
if (arg < 1 || arg > 100) {
memprintf(err, "'%s' expects an integer argument between 1 and 100.", args[0]);
@ -431,6 +436,24 @@ static int cfg_parse_quic_tune_setting(char **args, int section_type,
quic_tune.fe.cc_cubic_min_losses = arg - 1;
ret = 1;
}
else if (strcmp(suffix, "frontend.default-max-window-size") == 0) {
unsigned long cwnd;
char *end_opt;
memprintf(err, "'%s' is deprecated in 3.3 and will be removed in 3.5. "
"Please use the newer keyword syntax 'tune.quic.fe.cc.max-win-size'.", args[0]);
cwnd = parse_window_size(args[0], args[1], &end_opt, err);
if (!cwnd)
return -1;
if (*end_opt != '\0') {
memprintf(err, "'%s' : expects an integer value with an optional suffix 'k', 'm' or 'g'", args[0]);
return -1;
}
quic_tune.fe.cc_max_win_size = cwnd;
ret = 1;
}
else if (strcmp(suffix, "frontend.glitches-threshold") == 0) {
memprintf(err, "'%s' is deprecated in 3.3 and will be removed in 3.5. "
"Please use the newer keyword syntax 'tune.quic.fe.sec.glitches-threshold'.", args[0]);
@ -596,13 +619,13 @@ static struct cfg_kw_list cfg_kws = {ILH, {
{ CFG_GLOBAL, "tune.quic.mem.tx-max", cfg_parse_quic_tune_setting },
{ CFG_GLOBAL, "tune.quic.frontend.max-data-size", cfg_parse_quic_tune_setting },
{ CFG_GLOBAL, "tune.quic.frontend.max-streams-bidi", cfg_parse_quic_tune_setting },
{ CFG_GLOBAL, "tune.quic.frontend.default-max-window-size", cfg_parse_quic_tune_setting },
{ CFG_GLOBAL, "tune.quic.frontend.stream-data-ratio", cfg_parse_quic_tune_setting },
{ CFG_GLOBAL, "tune.quic.zero-copy-fwd-send", cfg_parse_quic_tune_on_off },
{ CFG_GLOBAL, "tune.quic.fe.cc.cubic-min-losses", cfg_parse_quic_tune_setting },
{ CFG_GLOBAL, "tune.quic.fe.cc.hystart", cfg_parse_quic_tune_on_off },
{ CFG_GLOBAL, "tune.quic.fe.cc.max-frame-loss", cfg_parse_quic_tune_setting },
{ CFG_GLOBAL, "tune.quic.fe.cc.max-win-size", cfg_parse_quic_tune_setting },
{ CFG_GLOBAL, "tune.quic.fe.cc.reorder-ratio", cfg_parse_quic_tune_setting },
{ CFG_GLOBAL, "tune.quic.fe.max-idle-timeout", cfg_parse_quic_time },
{ CFG_GLOBAL, "tune.quic.fe.sec.glitches-threshold", cfg_parse_quic_tune_setting },
@ -614,6 +637,7 @@ static struct cfg_kw_list cfg_kws = {ILH, {
{ CFG_GLOBAL, "tune.quic.be.cc.cubic-min-losses", cfg_parse_quic_tune_setting },
{ CFG_GLOBAL, "tune.quic.be.cc.hystart", cfg_parse_quic_tune_on_off },
{ CFG_GLOBAL, "tune.quic.be.cc.max-frame-loss", cfg_parse_quic_tune_setting },
{ CFG_GLOBAL, "tune.quic.be.cc.max-win-size", cfg_parse_quic_tune_setting },
{ CFG_GLOBAL, "tune.quic.be.cc.reorder-ratio", cfg_parse_quic_tune_setting },
{ CFG_GLOBAL, "tune.quic.be.max-idle-timeout", cfg_parse_quic_time },
{ CFG_GLOBAL, "tune.quic.be.sec.glitches-threshold", cfg_parse_quic_tune_setting },
@ -625,6 +649,7 @@ static struct cfg_kw_list cfg_kws = {ILH, {
{ CFG_GLOBAL, "tune.quic.cc.cubic.min-losses", cfg_parse_quic_tune_setting },
{ CFG_GLOBAL, "tune.quic.disable-tx-pacing", cfg_parse_quic_tune_setting0 },
{ CFG_GLOBAL, "tune.quic.disable-udp-gso", cfg_parse_quic_tune_setting0 },
{ CFG_GLOBAL, "tune.quic.frontend.default-max-window-size", cfg_parse_quic_tune_setting },
{ CFG_GLOBAL, "tune.quic.frontend.glitches-threshold", cfg_parse_quic_tune_setting },
{ CFG_GLOBAL, "tune.quic.frontend.max-idle-timeout", cfg_parse_quic_time },
{ CFG_GLOBAL, "tune.quic.frontend.max-tx-mem", cfg_parse_quic_tune_setting },

View File

@ -201,7 +201,6 @@ struct global global = {
#ifdef USE_QUIC
.quic_frontend_max_data = 0,
.quic_frontend_max_streams_bidi = QUIC_TP_DFLT_FRONT_MAX_STREAMS_BIDI,
.quic_frontend_max_window_size = QUIC_DFLT_MAX_WINDOW_SIZE,
.quic_frontend_stream_data_ratio = QUIC_DFLT_FRONT_STREAM_DATA_RATIO,
#endif /* USE_QUIC */
},

View File

@ -35,6 +35,7 @@
#include <haproxy/protocol.h>
#include <haproxy/proxy.h>
#include <haproxy/quic_tp.h>
#include <haproxy/quic_tune.h>
#include <haproxy/sample.h>
#include <haproxy/stream.h>
#include <haproxy/task.h>
@ -2081,7 +2082,7 @@ struct bind_conf *bind_conf_alloc(struct proxy *fe, const char *file,
#ifdef USE_QUIC
/* Use connection socket for QUIC by default. */
bind_conf->quic_mode = QUIC_SOCK_MODE_CONN;
bind_conf->max_cwnd = global.tune.quic_frontend_max_window_size;
bind_conf->max_cwnd = quic_tune.fe.cc_max_win_size;
#endif
LIST_INIT(&bind_conf->listeners);

View File

@ -1320,7 +1320,8 @@ struct quic_conn *qc_new_conn(const struct quic_version *qv, int ipv4,
qc->max_ack_delay = 0;
/* Only one path at this time (multipath not supported) */
qc->path = &qc->paths[0];
quic_cc_path_init(qc->path, ipv4, l ? l->bind_conf->max_cwnd : 0,
quic_cc_path_init(qc->path, ipv4,
l ? l->bind_conf->max_cwnd : quic_tune.be.cc_max_win_size,
cc_algo ? cc_algo : default_quic_cc_algo, qc);
if (local_addr)