25702 Commits

Author SHA1 Message Date
Christopher Faulet
949199a2f4 DEBUG: stream: Add bytes_in/bytes_out value for both SC in session dump
It could be handy to have these infos in the full session dump. So let's
dump it now.
2025-11-06 15:01:29 +01:00
Christopher Faulet
a1b5325a7a MINOR: channel: Remove total field from channels
The <total> field in the channel structure is now useless, so it can be
removed. The <bytes_in> field from the SC is used instead.

This patch is related to issue #1617.
2025-11-06 15:01:29 +01:00
Christopher Faulet
1effe0fc0a MINOR: applet: Add function to get amount of data in the output buffer
The helper function applet_output_data() returns the amount of data in the
output buffer of an applet. For applets using the new API, it is based on
data present in the outbuf buffer. For legacy applets, it is based on input
data present in the input channel's buffer. The HTX version,
applet_htx_output_data(), is also available

This patch is related to issue #1617.
2025-11-06 15:01:29 +01:00
Christopher Faulet
4991a51208 MINOR: stats: Add stats about request and response bytes received and sent
In previous patches, these counters were added per frontend, backend, server
and listener. With this patch, these counters are reported on stats,
including promex.

Note that the stats file minor version was incremented by one because the
shm_stats_file_object struct size has changed.

This patch is related to issue #1617.
2025-11-06 15:01:29 +01:00
Christopher Faulet
0084baa6ba MINOR: counters: Remove bytes_in and bytes_out counter from fe/be/srv/li
bytes_in and bytes_out counters per frontend, backend, listener and server
were removed and we now rely on, respectively on, req_in and res_in
counters.

This patch is related to issue #1617.
2025-11-06 15:01:29 +01:00
Christopher Faulet
567df50d91 MINOR: stream: Remove bytes_in and bytes_out counters from stream
per-stream bytes_in and bytes_out counters was removed and replaced by
req.in and res.in. Coorresponding samples still exists but replies on new
counters.

This patch is related to issue #1617.
2025-11-06 15:01:29 +01:00
Christopher Faulet
1c62a6f501 MINOR: counters: Add req_in/req_out/res_in/res_out counters for fe/be/srv/li
Thanks to the previous patch, and based on info available on the stream, it
is now possible to have counters for frontends, backends, servers and
listeners to report number of bytes received and sent on both sides.

This patch is related to issue #1617.
2025-11-06 15:01:29 +01:00
Christopher Faulet
ac9201f929 MINOR: stream: Add samples to get number of bytes received or sent on each side
req.in and req.out samples can now be used to get the number of bytes
received by a client and send to the server. And res.in and res.out samples
can be used to get the number of bytes received by a server and send to the
client. These info are stored in the logs structure inside a stream.

This patch is related to issue #1617.
2025-11-06 15:01:28 +01:00
Christopher Faulet
629fbbce19 MINOR: stconn: Add counters to SC to know number of bytes received and sent
<bytes_in> and <bytes_out> counters were added to SC to count, respectively,
the number of bytes received from an endpoint or sent to an endpoint. These
counters are updated for connections and applets.

This patch is related to issue #1617.
2025-11-06 15:01:28 +01:00
William Lallemand
094baa1cc0 BUG/MINOR: acme: allow 'key' when generating cert
Allow to use the 'key' keyword when 'crt' was generated with both a crt
and a key.

No backport needed.
2025-11-06 14:11:43 +01:00
William Lallemand
05036180d9 DOC: acme: crt-store allows you to start without a certificate
If your acme certificate is declared in a crt-store, and the certificate
file does not exist on the disk, HAProxy will start with a temporary key
pair.
2025-11-06 13:40:42 +01:00
Willy Tarreau
5fe4677231 MINOR: server: move the lock inside srv_add_idle()
Almost all callers of _srv_add_idle() lock the list then call the
function. It's not the most efficient and it requires some care from
the caller to take care of that lock. Let's change this a little bit by
having srv_add_idle() that takes the lock and calls _srv_add_idle() that
is now inlined. This way callers don't have to handle the lock themselves
anymore, and the lock is only taken around the sensitive parts, not the
function call+return.

Interestingly, perf tests show a small perf increase from 2.28-2.32M RPS
to 2.32-2.37M RPS on a 128-thread system.
2025-11-06 13:16:24 +01:00
William Lallemand
a8498cde74 BUILD: ssl/ckch: fix ckch_conf_kws parsing without ACME
Without ACME, the tmp_pkey and tmp_x509 functions are not available, the
patch checks HAVE_ACME to use them.
2025-11-06 12:27:27 +01:00
William Lallemand
22f92804d6 BUG/MINOR: acme: fix initialization issue in acme_gen_tmp_x509()
src/acme.c: In function ‘acme_gen_tmp_x509’:
src/acme.c:2685:15: error: ‘digest’ may be used uninitialized [-Werror=maybe-uninitialized]
 2685 |         if (!(X509_sign(newcrt, pkey, digest)))
      |              ~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/acme.c:2628:23: note: ‘digest’ was declared here
 2628 |         const EVP_MD *digest;
      |                       ^~~~~~
2025-11-06 12:12:18 +01:00
William Lallemand
0524af034f BUILD: acme: acme_gen_tmp_x509() signedness and unused variables
Fix compilation issues in acme_gen_tmp_x509().

src/acme.c:2665:66: warning: pointer targets in passing argument 4 of ‘X509_NAME_add_entry_by_txt’ differ in signedness [-Wpointer-sign]
 2665 |         if (X509_NAME_add_entry_by_txt(name, "CN", MBSTRING_ASC, "expired",
      |                                                                  ^~~~~~~~~
      |                                                                  |
      |                                                                  char *
In file included from /usr/include/openssl/ssl.h:32,
                 from include/haproxy/openssl-compat.h:19,
                 from include/haproxy/acme-t.h:6,
                 from src/acme.c:16:
/usr/include/openssl/x509.h:1074:53: note: expected ‘const unsigned char *’ but argument is of type ‘char *’
 1074 |                                const unsigned char *bytes, int len, int loc,
      |                                ~~~~~~~~~~~~~~~~~~~~~^~~~~
src/acme.c:2630:23: warning: unused variable ‘i’ [-Wunused-variable]
 2630 |         unsigned int  i;
      |                       ^
src/acme.c:2629:23: warning: unused variable ‘ctx’ [-Wunused-variable]
 2629 |         X509V3_CTX    ctx;
      |                       ^~~
2025-11-06 12:08:04 +01:00
William Lallemand
a15d4f5b19 BUILD: ssl/ckch: wrong function name in ckch_conf_kws
ckch_conf_load_pem does not exist anymore and
ckch_conf_load_pem_or_generate must be used instead
2025-11-06 12:03:29 +01:00
William Lallemand
582a1430b2 MEDIUM: acme: generate a key pair when no file are available
When an acme keyword is associated to a crt and key, and the corresponding
files does not exist, HAProxy would not start.

This patch allows to configure acme without pre-generating a keypair before
starting HAProxy. If the files does not exist, it tries to generate a unique
keypair in memory, that will be used for every ACME certificates that don't
have a file on the disk yet.
2025-11-06 11:56:27 +01:00
William Lallemand
546c67d137 MINOR: acme: generate a temporary key pair
This patch provides two functions acme_gen_tmp_pkey() and
acme_gen_tmp_x509().

These functions generates a unique keypair and X509 certificate that
will be stored in tmp_x509 and tmp_pkey. If the key pair or certificate
was already generated they will return the existing one.

The key is an RSA2048 and the X509 is generated with a expiration in the
past. The CN is "expired".

These are just placeholders to be used if we don't have files.
2025-11-06 11:56:27 +01:00
William Lallemand
1df55b441b MEDIUM: ssl/ckch: use ckch_store instead of ckch_data for ckch_conf_kws
This is an API change, instead of passing a ckch_data alone, the
ckch_conf_kws.func() is called with a ckch_store.

This allows the callback to access the whole ckch_store, with the
ckch_conf and the ckch_data. But it requires the ckch_conf to be
actually put in the ckch_store before.
2025-11-06 11:56:27 +01:00
Olivier Houchard
201971ec5f MEDIUM: stick-tables: Optimize the expiration process a bit.
In process_tables_expire(), if the table we're analyzing still has
entries, and thus should be put back into the tree, do not put it in the
mt_list, to have it put back into the tree the next time the task runs.
There is no problem with putting it in the tree right away, as either
the next expiration is in the future, or we handled the maximum number
of expirations per task call and we're about to stop, anyway.

This does not need to be backported.
2025-11-05 19:22:11 +01:00
Olivier Houchard
93f994e8b1 BUG/MEDIUM: stick-tables: Make sure we handle expiration on all tables
In process_tables_expire(), when parsing all the tables with expiration
set, to check if the any entry expired, make sure we start from the
oldest one, we can't just rely on eb32_first(), because of sign issues
on the timestamp.
Not doing that may mean some tables are not considered for expiration.

This does not need to be backported.
2025-11-05 19:22:11 +01:00
Amaury Denoyelle
b9809fe0d0 MINOR: quic: remove <mux_state> field
This patch removes <mux_state> field from quic_conn structure. The
purpose of this field was to indicate if MUX layer above quic_conn is
not yet initialized, active, or already released.

It became tedious to properly set it as initialization order of the
various quic_conn/conn/MUX layers now differ between the frontend and
backend sides, and also depending if 0-RTT is used or not. Recently, a
new change introduced in connect_server() will allow to initialize QUIC
MUX earlier if ALPN is cached on the server structure. This had another
level of complexity.

Thus, this patch removes <mux_state> field completely. Instead, a new
flag QUIC_FL_CONN_XPRT_CLOSED is defined. It is set at a single place
only on close XPRT callback invokation. It can be mixed with the new
utility functions qc_wait_for_conn()/qc_is_conn_ready() to determine the
status of conn/MUX layers now without an extra quic_conn field.
2025-11-05 14:03:34 +01:00
William Lallemand
99a2454e9d DOC: configuration: deprecate the master-worker keyword
Deprecate the 'master-worker' keyword in the global section.

Split the configuration of the 'no-exit-on-failure' subkeyword in
another section which is not deprecated yet and explains that its only
meant for debugging purpose.
2025-11-05 12:27:11 +01:00
William Lallemand
4f978325ac MEDIUM: cfgparse: 'daemon' not compatible with -Ws
Emit a warning when the 'daemon' keyword is used in master-worker mode
for systemd (-Ws). This never worked and was always ignored by setting
MODE_FOREGROUND during cmdline parsing.
2025-11-05 11:49:11 +01:00
William Lallemand
631233e9ec MEDIUM: cfgparse: deprecate 'master-worker' keyword alone
Warn when the 'master-worker' keyword is used without
'no-exit-on-failure'.

Warn when the 'master-worker' keyword is used and -W and -Ws already set
the mode.
2025-11-05 11:49:11 +01:00
Willy Tarreau
096999ee20 BUG/MEDIUM: connections: permit to permanently remove an idle conn
There's currently a function conn_delete_from_tree() which is used to
detach an idle connection from the tree it's currently attached to so
that it is no longer found. This function is used in three circumstances:
  - when picking a new connection that no longer has any avail stream
  - when temporarily working on the connection from an I/O handler,
    in which case it's re-added at the end
  - when killing a connection

The 2nd case above is quite specific, as it requires to preserve the
CO_FL_LIST_MASK flags so that the connection can be re-inserted into
the proper tree when leaving the handler. However, there's a catch.
When killing a connection, we want to be certain it will not be
reinserted into the tree. The flags preservation is causing a tiny
race if an I/O happens while the connection is in the kill list,
because in this case the I/O handler will note the connection flags,
do its work, then reinsert the connection where it believed it was,
then the connection gets purged, and another user can find it in the
tree.

The issue is very difficult to reproduce. On a 128-thread machine it
happens in H2 around 500k req/s after around 50M requests. In H1 it
happens after around 1 billion requests.

The fix here consists in passing an extra argument to the function to
indicate if the removal is permanent or not. When it's permanent, the
function will clear the associated flags. The callers were adjusted
so that all those dequeuing a connection in order to kill it do it
permanently and all other ones do it only temporarily.

A slightly different approach could have worked: the function could
always remove all flags, and the callers would need to restore them.
But this would require trickier modifications of the various call
places, compared to only passing 0/1 to indicate the permanent status.

This will need to be backported to all stable versions. The issue was
at least reproduced since 3.1 (not tested before). The patch will need
to be adjusted for 3.2 and older, because a 2nd argument "thr" was
added in 3.3, so the patch will not apply to older versions as-is.
2025-11-05 11:08:25 +01:00
Willy Tarreau
59c599f3f0 BUG/MEDIUM: mux-h2: make sure not to move a dead connection to idle
In h2_detach(), it looks possible to place a dead connection back to
the idle list, and to later call h2_release() on it once detected as
dead. It's not certain that it happens but nothing in the code shows
it is not possible, so better make sure it cannot happen.

This should be preventively backported to all versions.
2025-11-05 11:08:25 +01:00
Maximilian Moehl
0799fd1072 BUG/MEDIUM: mux-h1: fix 414 / 431 status code reporting
The more detailed status code reporting introduced with bc967758a2 is
checking against the error state to determine whether it is a too long
URL or too large headers. The check used always returns true which
results in a 414 as the error state is only set at a later point.

This commit adjusts the check to use the current state instead to return
the intended status code.

This patch must be backported as far as 3.1.
2025-11-05 10:55:18 +01:00
Olivier Houchard
06821dc189 BUG/MEDIUM: server: Also call srv_reset_path_parameters() on srv up
Also call srv_reset_path_parameters() when the server changed states,
and got up. It is not enough to do it when the server goes down, because
there's a small race condition, and a connection could get established
just after we did it, and could have set the path parameters.

This does not need to be backported.
2025-11-04 18:47:34 +01:00
Olivier Houchard
7d4aa7b22b BUG/MEDIUM: server: Add a rwlock to path parameter
Add a rwlock to control the server's path_parameter, to make sure
multiple threads don't set it at the same time, and it can't be seen in
an inconsistent state.
Also don't set the parameter every time, only set them if they have
changed, to prevent needless writes.

This does not need to be backported.
2025-11-04 18:47:34 +01:00
Amaury Denoyelle
efe60745b3 MINOR: quic: remove connection arg from qc_new_conn()
This patch is similar to the previous one, this time dealing with
qc_new_conn(). This function was asymetric on frontend and backend side,
as connection argument was set only in the latter case.

This was required prior due to qc_alloc_ssl_sock_ctx() signature. This
has changed with the previous patch, thus qc_new_conn() can also be
realigned on both FE and BE sides. <conn> member of quic_conn instance
is always set outside it, in qc_xprt_start() on the backend case.
2025-11-04 17:47:42 +01:00
Amaury Denoyelle
5a17cade4f MINOR: quic: do not set conn member if ssl_sock_ctx
ssl_sock_ctx is a generic object used both on TCP/SSL and QUIC stacks.
Most notably it contains a <conn> member which is a pointer to struct
connection.

On QUIC frontend side, this member is always set to NULL. Indeed,
connection is only created after handshake completion. However, this has
changed for backend side, where the connection is instantiated prior to
its quic_conn counterpart. Thus, ssl_sock_ctx member would be set in
this case as a convenience for use later in qc_ssl_do_hanshake().

However, this method was unsafe as the connection can be released,
without resetting ssl_sock_ctx member. Thus, the previous patch fixes
this by using on <conn> member through the quic_conn instance which is
the proper way.

Thus, this patch resets ssl_sock_ctx <conn> member to NULL. This is
deemed the cleanest method as it ensures that both frontend and backend
sides must not use it anymore.
2025-11-04 17:38:09 +01:00
Amaury Denoyelle
69de7ec14e BUG/MINOR: quic: fix crash on client handshake abort
On backend side, a connection can be aborted and released prior to
handshake completion. This causes a crash in qc_ssl_do_hanshake() as
<conn> member of ssl_sock_ctx is not reset in this case.

To fix this, use <conn> member of quic_conn instead. This is safe as it
is properly set to NULL when a connection is released.

No impact on the frontend side as <conn> member is not accessed. Indeed,
in this case connection is most of the times allocated after handshake
completion.

No need to be backported.
2025-11-04 17:33:42 +01:00
William Lallemand
3c578ca31c CI: github: update to macos-26
macOS-15 images seems to have difficulties to run the reg-tests since a
few days for an unknown reason. Doing a rollback of both VTest2 and
haporxy doesn't seem to fix the problem so this is probably related to a
change in github actions.

This patch switches the image to the new macos-26 images which seems to
fix the problem.
2025-11-03 16:17:36 +01:00
William Lallemand
0c34502c6d SCRIPTS: build-ssl: fix rpath in AWS-LC install for openssl and bssl bin
AWS-LC binaries were not linked correctly with an rpath, preventing the
binaries to be useful without setting an LD_LIBRARY_PATH manually.
2025-11-03 15:04:57 +01:00
Willy Tarreau
fd012b6c59 OPTIM: proxy: move atomically access fields out of the read-only ones
Perf top showed that h1_snd_buf() was having great difficulties accessing
the proxy's server_id_hdr_name field in the middle of the headers loop.
Moving the assignment out of the loop to a local variable moved the
problem there as well:

       |      if (!(h1m->flags & H1_MF_RESP) && isttest(h1c->px->server_id_hdr_n
  0.10 |20b0:   mov        -0x120(%rbp),%rdi
  1.33 |        mov        0x60(%rdi),%r10
  0.01 |        test       %eax,%eax
  0.18 |        jne        2118
 12.87 |        mov        0x350(%r10),%rdi
  0.01 |        test       %rdi,%rdi
  0.05 |        je         2118
       |        mov        0x358(%r10),%r11

It turns out that there are several atomically accessed fields in its
vicinity, causing the cache line to bounce all the time. Let's collect
the few frequently changed fields and place them together at the end
of the structure, and plug the 32-bit hole with another isolated field.
Doing so also reduced a little bit the cost of decrementing be->be_conn
in process_stream(), and overall the HTTP/1 performance increased by
about 1% both on ARM and x86_64.
2025-11-03 13:54:49 +01:00
William Lallemand
12aca978a8 SCRIPTS: build-ssl: allow to build a FIPS version without FIPS
build-ssl.sh is always prepending a "v" to the version, preventing to
build a FIPS version without FIPS enabled.

This patch checks if FIPS is in the version string to chose to add the
"v" or not.

Example:

AWS_LC_VERSION=AWS-LC-FIPS-3.0.0 BUILDSSL_DESTDIR=/opt/awslc-3.0.0 ./scripts/build-ssl.sh
2025-11-03 12:03:05 +01:00
Amaury Denoyelle
6bfabfdc77 OPTIM: backend: skip conn reuse for incompatible proxies
When trying to reuse a backend connection, a connection hash is
calculated to match an entry with similar parameters. Previously, this
operation was skipped if the stream content wasn't based on HTTP, as it
would have been incompatible with http-reuse.

With the introduction of SPOP backends, this condition was removed, so
that it can also benefit from connection reuse. However, this means that
now hash calcul is always performed when connecting to a server, even
for TCP or log backends. This is unnecessary as these proxies cannot
perform connection reuse.

Note also that reuse mode is resetted on postparsing for incompatible
backends. This at least guarantees that no tree lookup will be performed
via be_reuse_connection(). However, connection lookup is still performed
in the session via session_get_conn() which is another unnecessary
operation.

Thus, this patch restores the condition so that reuse operations are now
entirely skipped if a backend mode is incompatible. This is implemented
via a new utility function named be_supports_conn_reuse().

This could be backported up to 3.1, as this commit could be considered
as a performance regression for tcp/log backend modes.
2025-11-03 10:43:50 +01:00
Willy Tarreau
ad1bdc3364 BUG/MAJOR: stats-file: fix crash on non-x86 platform caused by unaligned cast
Since commit d655ed5f14 ("BUG/MAJOR: stats-file: ensure
shm_stats_file_object struct mapping consistency (2nd attempt)"), the
last_state_change field in the counters is a uint (to match how it's
reported). However, it happens that there are explicit casts in function
me_generate_field() to retrieve the value, and which cause crashes on
aarch64 and likely other non-x86 64-bit platforms due to atomically
reading an unaligned 64-bit value, and may even randomly crash other
64-bit platforms when reading past the end of the structure.

The fix for now adapts the cast to match the one used by the accessed
type (i.e. unsigned int), but the approach must change, as there's
nothing there which allows to figure whether or not the type is correct
by just reading the code. At minima a typeof() on a named field is
needed, but this requires more invasive changes, hence this temporary
fix.

No backport is needed, as stats-file is only in 3.3.
2025-11-03 07:33:11 +01:00
Damien Claisse
561dc127bd BUG/MINOR: resolvers: ensure fair round robin iteration
Previous fixes restored round robin iteration, but an imbalance remains
when the response tree contains record types other than A or AAAA. Let's
take the following example: the DNS answers two A records and a CNAME.
The response "tree" (which is actually flat, more like a list) may look
as follows, ordered by hash:
- 1st item: first A record with IP 1
- 2nd item: second A record with IP 2
- 3rd item: CNAME record
As a consequence, resolv_get_ip_from_response will iterate as follows,
while the TTL is still valid:
- 1st call: DNS request is done, response tree is created, iteration
  starts at the first item, IP 1 is returned.
- 2nd call: cached response tree is used, iteration starts at the second
  item, IP 2 is returned.
- 3rd call: cached response tree is used, iteration starts at the third
  item, but it's a CNAME, so we continue to the next item, which restarts
  iteration at the first item, and IP 1 is returned.
- 4th call: cached response tree is used and iteration restarts at the
  beginning, returning IP 1 again.
The 1-2-1-1-2-1-1-2 sequence will repeat, so IP 1 will be used twice as
often as IP 2, creating a strong imbalance. Even with more IP addresses,
the first one by hashing order in the tree will always receive twice the
traffic of the others.
To fix this, set the next iteration item to the one following the selected
IP record, if any. This ensures we never use the same IP twice in a row.

This commit should be backported where 3023e9819 ("BUG/MINOR: resolvers:
Restore round-robin selection on records in DNS answers") is, so as far
as 2.6.
2025-11-02 17:28:32 +01:00
William Lallemand
d1d2461197 REGTESTS: converters: check USE_OPENSSL in aes_gcm.vtc
Check USE_OPENSSL as well as the haproxy version for the aes_gcm
reg-test.
2025-10-31 12:43:00 +01:00
William Lallemand
1d859bdaa2 MINOR: sample: optional AAD parameter support to aes_gcm_enc/dec
The aes_gcm_enc() and aes_gcm_dec() sample converters now accept an
optional fifth argument for Additional Authenticated Data (AAD). When
provided, the AAD value is base64-decoded and used during AES-GCM
encryption or decryption. Both string and variable forms are supported.

This enables use cases that require authentication of additional data.
2025-10-31 12:27:38 +01:00
Amaury Denoyelle
73b5d331cc OPTIM: quic: adjust automatic ALPN setting for QUIC servers
If a QUIC server is declared without ALPN, "h3" value is automatically
set during _srv_parse_finalize().

This patch adjusts this operation. Instead of relying on
ssl_sock_parse_alpn(), a plain strdup() is used. This is considered more
efficient as the ALPN string is constant in this case. This method is
already used for listeners on the frontend side.
2025-10-31 11:32:20 +01:00
Amaury Denoyelle
14a6468df5 MINOR: quic: reject conf with QUIC servers if not compiled
Ensure that QUIC support is compiled into haproxy when a QUIC server is
configured. This check is performed during _srv_parse_finalize() so that
it is detected both on configuration parsing and when adding a dynamic
server via the CLI.

Note that this changes the behavior of srv_is_quic() utility function.
Previously, it always returned false when QUIC support wasn't compiled.
With this new check introduced, it is now guaranteed that a QUIC server
won't exist if compilation support is not active. Hence srv_is_quic()
does not rely anymore on USE_QUIC define.
2025-10-31 11:32:20 +01:00
Amaury Denoyelle
1af3caae7d MINOR: quic: enable SSL on QUIC servers automatically
Previously, QUIC servers were rejected if SSL was not explicitely
activated using 'ssl' configuration keyword.

Change this behavior : now SSL is automatically activated for QUIC
servers when the keyword is missing. A warning is displayed as it is
considered better to explicitely note that SSL is in use.
2025-10-31 11:32:14 +01:00
Willy Tarreau
0a14ad11be [RELEASE] Released version 3.3-dev11
Released version 3.3-dev11 with the following main changes :
    - BUG/MEDIUM: mt_list: Make sure not to unlock the element twice
    - BUG/MINOR: quic-be: unchecked connections during handshakes
    - BUG/MEDIUM: cli: also free the trash chunk on the error path
    - MINOR: initcalls: Add a new initcall stage, STG_INIT_2
    - MEDIUM: stick-tables: Use a per-shard expiration task
    - MEDIUM: stick-tables: Remove the table lock
    - MEDIUM: stick-tables: Stop if stktable_trash_oldest() fails.
    - MEDIUM: stick-tables: Stop as soon as stktable_trash_oldest succeeds.
    - BUG/MEDIUM: h1-htx: Don't set HTX_FL_EOM flag on 1xx informational messages
    - BUG/MEDIUM: h3: properly encode response after interim one in same buf
    - BUG/MAJOR: pools: fix default pool alignment
    - MINOR: ncbuf: extract common types
    - MINOR: ncbmbuf: define new ncbmbuf type
    - MINOR: ncbmbuf: implement add
    - MINOR: ncbmbuf: implement iterator bitmap utilities functions
    - MINOR: ncbmbuf: implement ncbmb_data()
    - MINOR: ncbmbuf: implement advance operation
    - MINOR: ncbmbuf: add tests as standalone mode
    - BUG/MAJOR: quic: use ncbmbuf for CRYPTO handling
    - MINOR: quic: remove received CRYPTO temporary tree storage
    - MINOR: stats-file: fix typo in shm-stats-file object struct size detection
    - MINOR: compiler: add FIXED_SIZE(size, type, name) macro
    - MEDIUM: freq-ctr: use explicit-size types for freq-ctr struct
    - BUG/MAJOR: stats-file: ensure shm_stats_file_object struct mapping consistency
    - BUG/MEDIUM: build: limit excessive and counter-productive gcc-15 vectorization
    - BUG/MEDIUM: stick-tables: Don't loop if there's nothing left
    - MINOR: acme: add the dns-01-record field to the sink
    - MINOR: acme: display the complete challenge_ready command in the logs
    - BUG/MEDIUM: mt_lists: Avoid el->prev = el->next = el
    - MINOR: quic: remove unused conn-tx-buffers limit keyword
    - MINOR: quic: prepare support for options on FE/BE side
    - MINOR: quic: rename "no-quic" to "tune.quic.listen"
    - MINOR: quic: duplicate glitches FE option on BE side
    - MINOR: quic: split congestion controler options for FE/BE usage
    - MINOR: quic: split Tx options for FE/BE usage
    - MINOR: quic: rename max Tx mem setting
    - MINOR: quic: rename retry-threshold setting
    - MINOR: quic: rename frontend sock-per-conn setting
    - BUG/MINOR: quic: split max-idle-timeout option for FE/BE usage
    - BUG/MINOR: quic: split option for congestion max window size
    - BUG/MINOR: quic: rename and duplicate stream settings
    - BUG/MEDIUM: applet: Improve again spinning loops detection with the new API
    - Revert "BUG/MAJOR: stats-file: ensure shm_stats_file_object struct mapping consistency"
    - Revert "MEDIUM: freq-ctr: use explicit-size types for freq-ctr struct"
    - Revert "MINOR: compiler: add FIXED_SIZE(size, type, name) macro"
    - BUG/MAJOR: stats-file: ensure shm_stats_file_object struct mapping consistency (2nd attempt)
    - BUG/MINOR: stick-tables: properly index string-type keys
    - BUILD: openssl-compat: fix build failure with OPENSSL=0 and KTLS=1
    - BUG/MEDIUM: mt_list: Use atomic operations to prevent compiler optims
    - MEDIUM: quic: Fix build with openssl-compat
    - MINOR: applet: do not put SE_FL_WANT_ROOM on rcv_buf() if the channel is empty
    - MINOR: cli: create cli_raw_rcv_buf() from the generic applet_raw_rcv_buf()
    - BUG/MEDIUM: cli: do not return ACKs one char at a time
    - BUG/MEDIUM: ssl: Crash because of dangling ckch_store reference in a ckch instance
    - BUG/MINOR: ssl: Remove unreachable code in CLI function
    - BUG/MINOR: acl: warn if "_sub" derivative used with an explicit match
    - DOC: config: fix confusing typo about ACL -m ("now" vs "not")
    - DOC: config: slightly clarify the ssl_fc_has_early() behavior
    - MINOR: ssl-sample: add ssl_fc_early_rcvd() to detect use of early data
    - CI: disable fail-fast on fedora rawhide builds
    - MINOR: http: fix 405,431,501 default errorfile
    - BUG/MINOR: init: Do not close previously created fd in stdio_quiet
    - MINOR: init: Make devnullfd global and create it earlier in init
    - MINOR: init: Use devnullfd in stdio_quiet calls instead of recreating a fd everytime
    - MEDIUM: ssl: Add certificate password callback that calls external command
    - MEDIUM: ssl: Add local passphrase cache
    - MINOR: ssl: Do not dump decrypted privkeys in 'dump ssl cert'
    - BUG/MINOR: resolvers: Apply dns-accept-family setting on additional records
    - MEDIUM: h1: Immediately try to read data for frontend
    - REGTEST: quic: add ssl_reuse.vtc new QUIC test
    - BUG/MINOR: ssl: returns when SSL_CTX_new failed during init
    - MEDIUM: ssl/ech: config and load keys
    - MINOR: ssl/ech: add logging and sample fetches for ECH status and outer SNI
    - MINOR: listener: implement bind_conf_find_by_name()
    - MINOR: ssl/ech: key management via stats socket
    - CI: github: add USE_ECH=1 to haproxy for openssl-ech job
    - DOC: configuration: "ech" for bind lines
    - BUG/MINOR: ech: non destructive parsing in cli_find_ech_specific_ctx()
    - DOC: management: document ECH CLI commands
    - MEDIUM: mux-h2: do not needlessly refrain from sending data early
    - MINOR: mux-h2: extract the code to send preface+settings into its own function
    - BUG/MINOR: mux-h2: send the preface along with the first request if needed
v3.3-dev11
2025-10-31 10:09:57 +01:00
Willy Tarreau
a1f26ca307 BUG/MINOR: mux-h2: send the preface along with the first request if needed
Tests involving 0-RTT and H2 on the backend show that 0-RTT is being
partially used but does not work. The analysis shows that only the
preface and settings are sent using early-data and the request is sent
separately. As explained in the previous patch, this is caused by the
fact that a wakeup of the iocb is needed just to send the preface, then
a new call to process_stream is needed to try sending again.

Here with this patch, we're making h2_snd_buf() able to send the preface
if it was not yet sent. Thanks to this, the preface, settings and first
request can now leave as a single TCP segment. In case of TLS with 0-RTT,
it now allows all the block to leave in early data.

Even in clear-text H2, we're now seeing a 15% lower context-switch count,
and the number of calls to process_stream() per connection dropped from 3
to 2. The connection rate increased by an extra 9.5%. Compared to without
the last 3 patches, this is a 22% reduction of context-switches, 33%
reduction of process_stream() calls, and 15.7% increase in connection
rate. And more importantly, 0-RTT now really works with H2 on the
backend, saving one full RTT on the first request.

This fix is only for a missed optimization and a non-functional 0-RTT
on the backend. It's worth backporting it, but it doesn't cause enough
harm to hurry a backport. Better wait for it to live a little bit in
3.3 (till at least a week or two after the final release) before
backporting it. It's not sure that it's worth going beyond 3.2 in any
case. It depends on the these two previous commits:

  MEDIUM: mux-h2: do not needlessly refrain from sending data early
  MINOR: mux-h2: extract the code to send preface+settings into its own function
2025-10-30 18:16:54 +01:00
Willy Tarreau
d5aa3e19cc MINOR: mux-h2: extract the code to send preface+settings into its own function
The code that deals with sending preface + settings and changing the
state currently is in h2_process_mux(), but we'll want to do it as
well from h2_snd_buf(), so let's move it to a dedicate function first.
At this point there is no functional change.
2025-10-30 18:16:54 +01:00
Willy Tarreau
b0e8edaef2 MEDIUM: mux-h2: do not needlessly refrain from sending data early
The mux currently refrains from sending data before H2_CS_FRAME_H, i.e.
before the peer's SETTINGS frame was received. While it makes sense on
the frontend, it's causing harm on the backend because it forces the
first request to be sent in two halves over an extra RTT: first the
preface and settings, second the request once the settings are received.
This is totally contrary to the philosophy of the H2 protocol, consisting
in permitting the client to send as soon as possible.

Actually what happens is the following:
  - process_stream() calls connect_server()
  - connect_server() creates a connection, and if the proto/alpn is guessed
    or known, the mux is instantiated for the current request.
  - the H2 init code wakes the h2 tasklet up and returns
  - process_stream() tries to send the request using h2_snd_buf(), but that
    one sees that we're before H2_CS_FRAME_H, refrains from doing so and
    returns.
  - process_stream() subscribes and quits
  - the h2 tasklet can now execute to send the preface and settings, which
    leave as a first TCP segment. The connection is ready.
  - the iocb is woken again once the server's SETTINGS frame is received,
    turning the connection to the H2_CS_FRAME_H state, and the iocb wake
    up process_stream().
  - process_stream() executes again and can try to send again.
  - h2_snd_buf() is called and finally sends the request as a second TCP
    segment.

Not only this is inefficient, but it also renders 0-RTT and TFO impossible
on H2 connections. When 0-RTT is used, only the preface and settings leave
as early data (the very first data of that connection), which is totally
pointless.

In order to fix this, we have to go through a few steps:
  - first we need to let data be sent to a server immediately after the
    SETTINGS frame was sent (i.e. in H2_CS_SETTINGS1 state instead of
    H2_CS_FRAME_H). However, some protocol extensions are advertised by
    the server using SETTINGS (e.g. RFC8441) and some requests might need
    to know the existence of such extensions. For this reason we're adding
    a new h2c flag, H2_CF_SETTINGS_NEEDED, which indicates that some
    operations were not done because a server's SETTINGS frame is needed.
    This is set when trying to send a protocol upgrade or extended CONNECT
    during H2_CS_SETTINGS1, indicating that it's needed to wait for
    H2_CS_FRAME_H in this case. The flag is always set on frontend
    connections. This is what is being done in this patch.

  - second, we need to be able to push the preface opportunistically with
    the first h2_snd_buf() so that it's not needed to wake the tasklet up
    just to send that and wake process_stream() again. This will be in a
    separate patch.

By doing the first step, we're at least saving one needless tasklet
wakeup per connection (~9%), which results in ~5% backend connection
rate increase.
2025-10-30 18:16:54 +01:00
William Lallemand
0436062f48 DOC: management: document ECH CLI commands
Document "show ssl ech", "add ssl ech", "set ssl ech" and "del ssl ech"
2025-10-30 11:59:39 +01:00