]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
BUG/MINOR: quic: fix rxbuf settings on backend side master
authorAmaury Denoyelle <adenoyelle@haproxy.com>
Fri, 12 Jun 2026 13:40:46 +0000 (15:40 +0200)
committerAmaury Denoyelle <adenoyelle@haproxy.com>
Mon, 15 Jun 2026 07:36:42 +0000 (09:36 +0200)
QUIC flow control on bidirectional streams ensure that the peer cannot
emit more than what haproxy has allowed, which guarantees that buffering
is under controlled on the receiver side.

This limit is first announced on the transport parameter via
initial_max_stream_data_bidi_remote which is derived from configuration
value. QUIC MUX calculation for its streams is then directly based on
the transport parameter.

This mechanism works as expected on the frontend side, as in this case
all exchanges occur on remote streams opened by the opposite side.
However, this is not working as expected on the backend side, as in this
case transfers occur on streams opened locally by haproxy as the client.
Thus, configuration has no impact on backend side rxbuf which remains
set to a single buffer, causing important latency when retrieving large
objects.

This patch removes this limitation on the backend side by adjusting
quic_transport_params_init(). If <server> parameter is false, limitation
is set for initial_max_stream_data_bidi_local TP.

This must be backported up to 3.3.

src/quic_tp.c

index 75243b44d50023840734f3d6e41a6aca43d03854..b38c5318ac7ad0ba7d8261fc4c36735d3211567a 100644 (file)
@@ -58,6 +58,7 @@ void quic_transport_params_init(struct quic_transport_params *p, int server)
          server ? quic_tune.fe.stream_max_concurrent : quic_tune.be.stream_max_concurrent;
        /* TODO value used to conform with HTTP/3, should be derived from app_ops */
        const int max_streams_uni = 3;
          server ? quic_tune.fe.stream_max_concurrent : quic_tune.be.stream_max_concurrent;
        /* TODO value used to conform with HTTP/3, should be derived from app_ops */
        const int max_streams_uni = 3;
+       uint64_t max_stream_data_bidi;
 
        /* Set RFC default values for unspecified parameters. */
        quic_dflt_transport_params_cpy(p);
 
        /* Set RFC default values for unspecified parameters. */
        quic_dflt_transport_params_cpy(p);
@@ -81,21 +82,30 @@ void quic_transport_params_init(struct quic_transport_params *p, int server)
        p->initial_max_data = stream_rxbuf ?
          stream_rxbuf : max_streams_bidi * stream_rx_bufsz;
 
        p->initial_max_data = stream_rxbuf ?
          stream_rxbuf : max_streams_bidi * stream_rx_bufsz;
 
-       /* Set remote streams flow-control data limit. This is calculated as a
-        * ratio from max-data, then rounded up to bufsize.
+       /* Calculate the limit for the Rx capability of bidirectional streams.
+        * This is a ratio from max-data rounded up to bufsize.
         */
         */
-       p->initial_max_stream_data_bidi_remote = server ?
+       max_stream_data_bidi = server ?
          p->initial_max_data * quic_tune.fe.stream_data_ratio / 100 :
          p->initial_max_data * quic_tune.be.stream_data_ratio / 100;
          p->initial_max_data * quic_tune.fe.stream_data_ratio / 100 :
          p->initial_max_data * quic_tune.be.stream_data_ratio / 100;
-       p->initial_max_stream_data_bidi_remote =
-         stream_rx_bufsz * ((p->initial_max_stream_data_bidi_remote + (stream_rx_bufsz - 1)) / stream_rx_bufsz);
+       max_stream_data_bidi =
+         stream_rx_bufsz * ((max_stream_data_bidi + (stream_rx_bufsz - 1)) / stream_rx_bufsz);
 
 
-       /* Set remaining flow-control data limit. Local bidi streams are unused
-        * on server side. Uni streams are only used for control exchange, so
-        * only a single buffer for in flight data should be enough.
+       /* Apply bidirectional streams Rx cap. This depends on the connection
+        * side. On FE side, exchange will occur on remote streams; on BE side,
+        * exchange will occur on local streams.
         */
         */
-       p->initial_max_stream_data_bidi_local  = stream_rx_bufsz;
-       p->initial_max_stream_data_uni         = stream_rx_bufsz;
+       if (server) {
+               p->initial_max_stream_data_bidi_remote = max_stream_data_bidi;
+               p->initial_max_stream_data_bidi_local  = stream_rx_bufsz;
+       }
+       else {
+               p->initial_max_stream_data_bidi_remote = stream_rx_bufsz;
+               p->initial_max_stream_data_bidi_local  = max_stream_data_bidi;
+       }
+
+       /* Unidirectional streams exchange should be minimal. */
+       p->initial_max_stream_data_uni = stream_rx_bufsz;
 
        if (server) {
                p->with_stateless_reset_token  = 1;
 
        if (server) {
                p->with_stateless_reset_token  = 1;