]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
BUG/MINOR: quic: split option for congestion max window size
authorAmaury Denoyelle <adenoyelle@haproxy.com>
Wed, 10 Sep 2025 08:48:12 +0000 (10:48 +0200)
committerAmaury Denoyelle <adenoyelle@haproxy.com>
Thu, 23 Oct 2025 14:49:20 +0000 (16:49 +0200)
doc/configuration.txt
include/haproxy/global-t.h
include/haproxy/quic_conn-t.h
include/haproxy/quic_tune-t.h
src/cfgparse-quic.c
src/haproxy.c
src/listener.c
src/quic_conn.c

index 2dfbf902e04aa880fc1589fa448a32ea254d8711..866c47e8bc3e8a921b8d0be280f0db3324b2cecc 100644 (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
index 2b0bbae213de1967e8974bbb32000510390b6be2..cc46cd0c1c25bc148d2cd5dbb27ccacee8de65eb 100644 (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;
index 3dad90434d3c9abbb9754d3d3c94fe4eda7ccb8a..2123bbf9fa2a45f557d3504ea071642063432d10 100644 (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
index 42f239f944f0486ed21c27e31f68b921ca253014..e44020e89fc124a20e4fb12770c0069401cc9891 100644 (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;
index 757f5ce368447b899a959d2158f79a0ad8e04c24..3dad2b17ed4eb25f27deea6ee279fe7642dd4eff 100644 (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 },
index 87a62d9decd16e1e28cec1b68bc74541f5468bc8..d0bf36f0d196420b37c6732d0a5135c83970a6e7 100644 (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 */
        },
index 98deba6dfc8afdb0b1e28c7231fcf39c1a2fb447..3bb4cf86216060c0e1387c0d81868e8fc2509d22 100644 (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);
 
index 7389368928e2430d404059e25ef526f0eeb461fd..00a84d606f00c705d64565838a47b17eb6e610af 100644 (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)