]> git.kaiwu.me - haproxy.git/log
haproxy.git
2 months agoMINOR: check: Remove wake_srv_chk() function
Christopher Faulet [Thu, 5 Mar 2026 16:43:26 +0000 (17:43 +0100)]
MINOR: check: Remove wake_srv_chk() function

wake_srv_chk() function is now only used by srv_chk_io_cb(), the
health-checl I/O callback function. So let's remove it. The code of the
function was moved in srv_chk_io_cb().

2 months agoMEDIUM: stconn: Remove .wake() callback function from app_ops
Christopher Faulet [Thu, 5 Mar 2026 16:41:31 +0000 (17:41 +0100)]
MEDIUM: stconn: Remove .wake() callback function from app_ops

.wake() callback function is no longer used by endpoints. So it can be
removed from the app_ops structure.

2 months agoMINOR: connection: Call sc_conn_process() instead of .wake() callback function
Christopher Faulet [Thu, 5 Mar 2026 16:30:26 +0000 (17:30 +0100)]
MINOR: connection: Call sc_conn_process() instead of .wake() callback function

At we fail to create a mux, in conn_create_mux(), instead of calling the
app_ops .wake() callback function, we can directly call sc_conn_process().
At this stage, we know we are using an connection, so it is safe to do so.

2 months agoMINOR: applet: Call sc_applet_process() instead of .wake() callback function
Christopher Faulet [Thu, 5 Mar 2026 16:28:10 +0000 (17:28 +0100)]
MINOR: applet: Call sc_applet_process() instead of .wake() callback function

At the end of task_run_applet() and task_process_applet(), instead of
calling the app_ops .wake() callback function, we can directly call
sc_applet_process(). At this stage, we know we are using an applet, so it is
safe to do so.

2 months agoMAJOR: muxes: No longer use app_ops .wake() callback function from muxes
Christopher Faulet [Thu, 5 Mar 2026 16:17:49 +0000 (17:17 +0100)]
MAJOR: muxes: No longer use app_ops .wake() callback function from muxes

Thanks to previous commits, it is now possible to wake the data layer up,
via a tasklet_wakeup, instead of using the app_ops .wake() callback
function.

When a data layer must be notified of a mux event (an error for instance),
we now always perform a tasklet_wakeup(). TASK_WOKEN_MSG state is used by
default. TASK_WOKEN_IO is eventually added if the data layer was subscribed
to receives or sends.

Changes are not trivial at all. We replaced a synchronous call to the
sc_conn_process() function by a tasklet_wakeup().

2 months agoMINOR: muxes: Wakup the data layer from a mux stream with TASK_WOKEN_IO state
Christopher Faulet [Thu, 5 Mar 2026 16:13:48 +0000 (17:13 +0100)]
MINOR: muxes: Wakup the data layer from a mux stream with TASK_WOKEN_IO state

Now, when a mux stream is waking its data layer up for receives or sends, it
uses the TASK_WOKEN_IO state. The state is not used by the stconn I/O
callback function for now.

2 months agoMINOR: mux-spop: Rely on spop_strm_notify_send() when resuming streams for sending
Christopher Faulet [Thu, 5 Mar 2026 16:08:13 +0000 (17:08 +0100)]
MINOR: mux-spop: Rely on spop_strm_notify_send() when resuming streams for sending

In spop_resume_each_sending_spop_strm(), there was exactly the same code
than spop_strm_notify_send(). So let's use spop_strm_notify_send() instead
of duplicating code.

2 months agoMINOR: mux-h2: Rely on h2s_notify_send() when resuming h2s for sending
Christopher Faulet [Thu, 5 Mar 2026 16:06:12 +0000 (17:06 +0100)]
MINOR: mux-h2: Rely on h2s_notify_send() when resuming h2s for sending

In h2_resume_each_sending_h2s(), there was exactly the same code than
h2s_notify_send(). So let's use h2s_notify_send() instead of duplicating
code.

2 months agoMINOR: stconn: Call sc_conn_process from the I/O callback if TASK_WOKEN_MSG state...
Christopher Faulet [Thu, 5 Mar 2026 14:22:50 +0000 (15:22 +0100)]
MINOR: stconn: Call sc_conn_process from the I/O callback if TASK_WOKEN_MSG state was set

It is the first commit of a series to refactor the SC app_ops. The first
step is to remove the .wake() callback function from the app_ops to replace
all uses by a wakeup of the SC tasklet.

Here, when the SC is woken up, the state is now tested and if TASK_WOKEN_MSG
is set, sc_conn_process() is called.

2 months agoDOC: jwt: Add ECDH support in jwt_decrypt converters
Remi Tricot-Le Breton [Tue, 10 Mar 2026 13:43:47 +0000 (14:43 +0100)]
DOC: jwt: Add ECDH support in jwt_decrypt converters

The jwt_decrypt_jwk and jwt_decrypt_cert converters now manage
algorithms in the ECDH family.

2 months agoMINOR: jwt: Manage ec certificates in jwt_decrypt_cert
Remi Tricot-Le Breton [Tue, 10 Mar 2026 13:43:46 +0000 (14:43 +0100)]
MINOR: jwt: Manage ec certificates in jwt_decrypt_cert

This patch adds the support of algorithms in the ECDH family in the
jwt_decrypt_cert converter.

2 months agoMINOR: jwt: Add ecdh-es+axxxkw support in jwt_decrypt_jwk converter
Remi Tricot-Le Breton [Tue, 10 Mar 2026 13:43:45 +0000 (14:43 +0100)]
MINOR: jwt: Add ecdh-es+axxxkw support in jwt_decrypt_jwk converter

This builds on the ECDH-ES processing and simply requires an extra AES
Key Wrap operation between the built key and the token's CEK.

2 months agoMINOR: jwt: Manage ECDH-ES algorithm in jwt_decrypt_jwk function
Remi Tricot-Le Breton [Tue, 10 Mar 2026 13:43:44 +0000 (14:43 +0100)]
MINOR: jwt: Manage ECDH-ES algorithm in jwt_decrypt_jwk function

When ECDH-ES algorithm is used in a JWE token, no cek is provided and
one must be built in order to decrypt the contents of the token. The
decrypting key is built by deriving a temporary key out of a public key
provided in the token and the private key provided by the user and
performing a concatKDF operation.

2 months agoMINOR: jwt: Parse ec-specific fields in jose header
Remi Tricot-Le Breton [Tue, 10 Mar 2026 13:43:43 +0000 (14:43 +0100)]
MINOR: jwt: Parse ec-specific fields in jose header

When the encoding is of the ECDH family, the optional "apu" and "apv"
fields of the JOSE header must be parsed, as well as the mandatory "epk"
field that contains an EC public key used to derive a key that allows
either to decrypt the contents of the token (in case of ECDH-ES) or to
decrypt the content encoding key (cek) when using ECDH-ES+AES Key Wrap.

2 months agoMINOR: jwt: Convert EC JWK to EVP_PKEY
Remi Tricot-Le Breton [Tue, 10 Mar 2026 13:43:42 +0000 (14:43 +0100)]
MINOR: jwt: Convert EC JWK to EVP_PKEY

Convert a JWK with the "EC" key type ("kty") into an EVP_PKEY. The JWK
can either represent a public key if it only contains the "x" and "y"
fields, or a private key if it also contains the "d" field.

2 months agoMINOR: jwt: Improve 'jwt_tokenize' function
Remi Tricot-Le Breton [Tue, 10 Mar 2026 13:11:55 +0000 (14:11 +0100)]
MINOR: jwt: Improve 'jwt_tokenize' function

The 'jwt_tokenize' function that can be used to split a JWT token into
its subparts can either fully process the token (from beginning to end)
when we need to check its signature, or only partially when using the
jwt_header_query or jwt_member_query converters. In this case we relied
on the fact that the return value of the 'jwt_tokenize' function was not
checked because a '-1' was returned (which was not actually an error).

In order to make this logic more explicit, the 'jwt_tokenize' function
now has a way to warn the caller that the token was invalid (less
subparts than the specified 'item_num') or that the token was not
processed in full (enough subparts found without parsing the token all
the way).
The function will now only return 0 if we found strictly the same number
of subparts as 'item_num'.

2 months agoRevert "BUG/MINOR: jwt: Missing 'jwt_tokenize' return value check"
William Lallemand [Mon, 9 Mar 2026 15:53:06 +0000 (16:53 +0100)]
Revert "BUG/MINOR: jwt: Missing 'jwt_tokenize' return value check"

This reverts commit 5e14904fef4856372433fc5b7e8d3de9450ec1b5.

The patch is broken, a better implementation is needed.

2 months agoBUG/MINOR: mworker: don't set the PROC_O_LEAVING flag on master process
William Lallemand [Thu, 5 Mar 2026 15:29:37 +0000 (16:29 +0100)]
BUG/MINOR: mworker: don't set the PROC_O_LEAVING flag on master process

The master process in the proc_list mustn't set the PROC_O_LEAVING flag
since the reload doesn't mean the master will leave.

Could be backported as far as 3.1.

2 months agoMINOR: mworker: add a BUG_ON() on mproxy_li in _send_status
William Lallemand [Thu, 5 Mar 2026 14:54:13 +0000 (15:54 +0100)]
MINOR: mworker: add a BUG_ON() on mproxy_li in _send_status

mproxy_li is supposed to be used in _send_status to stop the sockpair FD
between the master and the new worker, being a listener.

This can only work if the listener has been stored in the fdtab owner,
and there's no reason it shouldn't be here.

2 months agoSCRIPTS: git-show-backports: add a restart-from-last option
Willy Tarreau [Mon, 9 Mar 2026 14:20:35 +0000 (15:20 +0100)]
SCRIPTS: git-show-backports: add a restart-from-last option

It's always a bit tricky to avoid already backported patches when they
just got a different ID (e.g. a critical fix in a topic branch). Most
often with stable topic branches we just want to pick all stable commits
since the last backported one. New option -L instead of -m does exactly
this: it enumerates only commits that were added to the reference branch
after its most recent backport.

2 months agoSCRIPTS: git-show-backports: hide the common ancestor warning in quiet mode
Willy Tarreau [Mon, 9 Mar 2026 14:17:52 +0000 (15:17 +0100)]
SCRIPTS: git-show-backports: hide the common ancestor warning in quiet mode

It's annoying to always see that warning in quiet mode when backporting
upstream to topic branches, let's hide it.

2 months agoBUG/MINOR: admin: haproxy-reload rename -vv long option
William Lallemand [Sun, 8 Mar 2026 00:26:04 +0000 (01:26 +0100)]
BUG/MINOR: admin: haproxy-reload rename -vv long option

The -vv option used --verbose as its long form, which was identical to
the long form of -v. Since the case statement matches top-to-bottom,
--verbose would always trigger -v (VERBOSE=2), making -vv unreachable
via its long option. The long form is renamed to --verbose=all to avoid
the conflict, and the usage string is updated accordingly.

Must be backported to 3.3.

2 months agoMEDIUM: admin: haproxy-reload conversion to POSIX sh
William Lallemand [Sun, 8 Mar 2026 00:10:45 +0000 (01:10 +0100)]
MEDIUM: admin: haproxy-reload conversion to POSIX sh

The script relied on a bash-specific process substitution (< <(...)) to
feed socat's output into the read loop. This is replaced with a standard
POSIX pipe into a command group.

The response parsing is also simplified: instead of iterating over each
line with a while loop and echoing them individually, the status line is
read first, the "--" separator consumed, and the remaining output is
streamed to stderr or discarded as a whole depending on the verbosity
level.

Could be backported to 3.3 as it makes it more portable, but introduce a
slight change in the error format.

2 months agoBUG/MINOR: admin: haproxy-reload use explicit socat address type
William Lallemand [Sat, 7 Mar 2026 23:41:36 +0000 (00:41 +0100)]
BUG/MINOR: admin: haproxy-reload use explicit socat address type

socat was used with the ${MASTER_SOCKET} variable directly, letting it
auto-detect the network protocol. However, when given a plain filename
that does not point to a UNIX socket, socat would create a file at that
path instead of reporting an error.

To fix this, the address type is now determined explicitly: if
MASTER_SOCKET points to an existing UNIX socket file (checked with -S),
UNIX-CONNECT: is used; if it matches a <host>:<port> pattern, TCP: is
used; otherwise an error is reported. The socat_addr variable is also
properly scoped as local to the reload() function.

Could be backported in 3.3.

2 months agoCLEANUP: flt_http_comp: comp_state doesn't bother about the direction anymore
Aurelien DARRAGON [Wed, 4 Mar 2026 16:41:35 +0000 (17:41 +0100)]
CLEANUP: flt_http_comp: comp_state doesn't bother about the direction anymore

no need to have duplicated comp_ctx and comp_algo for request vs response
in comp_state struct, because thanks to previous commit compression filter
is either oriented on the request or the response, and 2 distinct filters
are instanciated when we need to handle both requests and responses
compression.

Thus we can save us from duplicated struct members and related operations.

2 months agoMEDIUM: flt_http_comp: split "compression" filter in 2 distinct filters
Aurelien DARRAGON [Wed, 18 Feb 2026 14:53:27 +0000 (15:53 +0100)]
MEDIUM: flt_http_comp: split "compression" filter in 2 distinct filters

Existing "compression" filter is a multi-purpose filter that will try
to compress both requests and responses according to "compression"
settings, such as "compression direction".

One of the pre-requisite work identified to implement decompression
filter is that we needed a way to manually define the sequence of
enabled filters to chain them in the proper order to make
compression and decompression chains work as expected in regard
to the intended use-case.

Due to the current nature of the "compression" filter this was not
possible, because the filter has a combined action as it will try
to compress both requests and responses, and as we are about to
implement "filter-sequence" directive, we will not be able to
change the order of execution of the compression filter between
requests and responses.

A possible solution we identified to solve this issue is to split the
existing "compression" filter into 2 distinct filters, one which is
request-oriented, "comp-req", and another one which is response-oriented
"comp-res". This is what we are doing in this commit. Compression logic
in itself is unchanged, "comp-req" will only aim to compress the request
while "comp-res" will try to compress the response. Both filters will
still be invoked on request and responses hooks, but they only do their
part of the job.

From now on, to compress both requests and responses, both filters have
to be enabled on the proxy. To preserve original behavior, the "compression"
filter is still supported, what it does is that it instantiates both
"comp-req" and "comp-res" filters implicitly, as the compression filter is
now effectively split into 2 separate filters under the hood.

When using "comp-res" and "comp-req" filters explicitly, the use of the
"compression direction" setting is not relevant anymore. Indeed, the
compression direction is assumed as soon as one or both filters are
enabled. Thus "compression direction" is kept as a legacy option in
order to configure the "compression" generic filter.

Documentation was updated.

2 months agoMINOR: flt_http_comp: define and use proxy_get_comp() helper function
Aurelien DARRAGON [Thu, 5 Mar 2026 18:00:09 +0000 (19:00 +0100)]
MINOR: flt_http_comp: define and use proxy_get_comp() helper function

proxy_get_comp() function can be used to retrieve proxy->comp options or
allocate and initialize it if missing

For now, it is solely used by parse_compression_options(), but the goal is
to be able to use this helper from multiple origins.

2 months agoBUG/MINOR: jwt: Missing 'jwt_tokenize' return value check
Remi Tricot-Le Breton [Mon, 23 Feb 2026 13:56:59 +0000 (14:56 +0100)]
BUG/MINOR: jwt: Missing 'jwt_tokenize' return value check

There was a "jwt_tokenize" call whose return value was not checked.

This was found by coverity and raised in GitHub #3277.
This patch can be backported to all stable branches.

2 months agoBUG/MINOR: backend: Don't get proto to use for webscoket if there is no server
Christopher Faulet [Fri, 6 Mar 2026 08:24:29 +0000 (09:24 +0100)]
BUG/MINOR: backend: Don't get proto to use for webscoket if there is no server

In connect_server(), it is possible to have no server defined (dispatch mode
or transparent backend). In that case, we must be carefull to check the srv
variable in all calls involving the server. It was not perform at one place,
when the protocol to use for websocket is retrieved. This must not be done
when there is no server.

This patch should fix the first report in #3144. It must be backported to
all stable version.

2 months agoBUG/MINOR: ssl-sample: Fix sample_conv_sha2() by checking EVP_Digest* failures
Christopher Faulet [Fri, 6 Mar 2026 07:59:01 +0000 (08:59 +0100)]
BUG/MINOR: ssl-sample: Fix sample_conv_sha2() by checking EVP_Digest* failures

In sample_conv_sha2(), calls to EVP_Digest* can fail. So we must check
return value of each call and report a error on failure and release the
digest context.

This patch should fix the issue #3274. It should be backported as far as
2.6.

2 months agoBUG/MINOR: stconn: Increase SC bytes_out value in se_done_ff()
Christopher Faulet [Thu, 5 Mar 2026 15:07:58 +0000 (16:07 +0100)]
BUG/MINOR: stconn: Increase SC bytes_out value in se_done_ff()

When data are sent via the zero-copy data forwarding, we must not forget to
increase the stconn bytes_out value.

This patch must be backport to 3.3.

2 months ago[RELEASE] Released version 3.4-dev6 v3.4-dev6
Willy Tarreau [Thu, 5 Mar 2026 14:55:28 +0000 (15:55 +0100)]
[RELEASE] Released version 3.4-dev6

Released version 3.4-dev6 with the following main changes :
    - CLEANUP: acme: remove duplicate includes
    - BUG/MINOR: proxy: detect strdup error on server auto SNI
    - BUG/MINOR: server: set auto SNI for dynamic servers
    - BUG/MINOR: server: enable no-check-sni-auto for dynamic servers
    - MINOR: haterm: provide -b and -c options (RSA key size, ECDSA curves)
    - MINOR: haterm: add long options for QUIC and TCP "bind" settings
    - BUG/MINOR: haterm: missing allocation check in copy_argv()
    - BUG/MINOR: quic: fix counters used on BE side
    - MINOR: quic: add BUG_ON() on half_open_conn counter access from BE
    - BUG/MINOR: quic/h3: display QUIC/H3 backend module on HTML stats
    - BUG/MINOR: acme: acme_ctx_destroy() leaks auth->dns
    - BUG/MINOR: acme: wrong labels logic always memprintf errmsg
    - MINOR: ssl: clarify error reporting for unsupported keywords
    - BUG/MINOR: acme: fix incorrect number of arguments allowed in config
    - CLEANUP: haterm: remove unreachable labels hstream_add_data()
    - CLEANUP: haterm: avoid static analyzer warnings about rand() use
    - CLEANUP: ssl: Remove a useless variable from ssl_gen_x509()
    - CI: use the latest docker for QUIC Interop
    - CI: remove redundant "halog" compilation
    - CLENAUP: cfgparse: accept-invalid-http-* does not support "no"/"defaults"
    - BUG/MEDIUM: spoe: Acquire context buffer in applet before consuming a frame
    - MINOR: traces: always mark trace_source as thread-aligned
    - MINOR: ncbmbuf: improve itbmap_next() code
    - MINOR: proxy: improve code when checking server name conflicts
    - MINOR: quic: add a new metric for ncbuf failures
    - BUG/MINOR: haterm: cannot reset default "haterm" mode
    - BUG/MEDIUM: cpu-topo: Distribute CPUs fairly across groups
    - BUG/MINOR: quic: missing app ops init during backend 0-RTT sessions
    - CLEANUP: ssl: remove outdated comments
    - MINOR: mux-h2: also count glitches on invalid trailers
    - MINOR: mux-h2: add a new setting, "tune.h2.log-errors" to tweak error logging
    - BUG/MEDIUM: mux-h2: make sure to always report pending errors to the stream
    - BUG/MINOR: server: adjust initialization order for dynamic servers
    - CLEANUP: tree-wide: drop a few useless null-checks before free()
    - CLEANUP: quic-stats: include counters from quic_stats
    - REORG: stats/counters: move extra_counters to counters not stats
    - CLEANUP: stats: drop stats.h / stats-t.h where not needed
    - MEDIUM: counters: change the fill_stats() API to pass the module and extra_counters
    - CLEANUP: counters: only retrieve zeroes for unallocated extra_counters
    - MEDIUM: counters: add a dedicated storage for extra_counters in various structs
    - MINOR: counters: store a tgroup step for extra_counters to access multiple tgroups
    - MEDIUM: counters: store the number of thread groups accessing extra_counters
    - MINOR: counters: add EXTRA_COUNTERS_BASE() to retrieve extra_counters base storage
    - MEDIUM: counters: return aggregate extra counters in ->fill_stats()
    - MEDIUM: counters: make EXTRA_COUNTERS_GET() consider tgid
    - BUG/MINOR: call EXTRA_COUNTERS_FREE() before srv_free_params() in srv_drop()
    - MINOR: promex: test applet resume in stress mode
    - BUG/MINOR: promex: fix server iteration when last server is deleted
    - BUG/MINOR: proxy: add dynamic backend into ID tree
    - MINOR: proxy: convert proxy flags to uint
    - MINOR: server: refactor srv_detach()
    - MINOR: proxy: define a basic "del backend" CLI
    - MINOR: proxy: define proxy watcher member
    - MINOR: stats: protect proxy iteration via watcher
    - MINOR: promex: use watcher to iterate over backend instances
    - MINOR: lua: use watcher for proxies iterator
    - MINOR: proxy: add refcount to proxies
    - MINOR: proxy: rename default refcount to avoid confusion
    - MINOR: server: take proxy refcount when deleting a server
    - MINOR: lua: handle proxy refcount
    - MINOR: proxy: prevent backend removal when unsupported
    - MINOR: proxy: prevent deletion of backend referenced by config elements
    - MINOR: proxy: prevent backend deletion if server still exists in it
    - MINOR: server: mark backend removal as forbidden if QUIC was used
    - MINOR: cli: implement wait on be-removable
    - MINOR: proxy: add comment for defaults_px_ref/unref_all()
    - MEDIUM: proxy: add lock for global accesses during proxy free
    - MEDIUM: proxy: add lock for global accesses during default free
    - MINOR: proxy: use atomic ops for default proxy refcount
    - MEDIUM: proxy: implement backend deletion
    - REGTESTS: add a test on "del backend"
    - REGTESTS: complete "del backend" with unnamed defaults ref free
    - BUG/MINOR: hlua: fix return with push nil on proxy check
    - BUG/MEDIUM: stream: Handle TASK_WOKEN_RES as a stream event
    - MINOR: quic: use signed char type for ALPN manipulation
    - MINOR: quic/h3: reorganize stream reject after MUX closure
    - MINOR: mux-quic: add function for ALPN to app-ops conversion
    - MEDIUM: quic/mux-quic: adjust app-ops install
    - MINOR: quic: use server cache for ALPN on BE side
    - BUG/MEDIUM: hpack: correctly deal with too large decoded numbers
    - BUG/MAJOR: qpack: unchecked length passed to huffman decoder
    - BUG/MINOR: qpack: fix 1-byte OOB read in qpack_decode_fs_pfx()
    - BUG/MINOR: quic: fix OOB read in preferred_address transport parameter
    - BUG/MEDIUM: qpack: correctly deal with too large decoded numbers
    - BUG/MINOR: hlua: Properly enable/disable line receives from HTTP applet
    - BUG/MEDIUM: hlua: Fix end of request detection when retrieving payload
    - BUG/MINOR: hlua: Properly enable/disable receives for TCP applets
    - MINOR: htx: Add a function to retrieve the HTTP version from a start-line
    - MINOR: h1-htx: Reports non-HTTP version via dedicated flags
    - BUG/MINOR: h1-htx: Be sure that H1 response version starts by "HTTP/"
    - MINOR: http-ana: Save the message version in the http_msg structure
    - MEDIUM: http-fetch: Rework how HTTP message version is retrieved
    - MEDIUM: http-ana: Use the version of the opposite side for internal messages
    - DEBUG: stream: Display the currently running rule in stream dump
    - MINOR: filters: Use filter API as far as poissible to break loops on filters
    - MINOR: filters: Set last_entity when a filter fails on stream_start callback
    - MINOR: stream: Display the currently running filter per channel in stream dump
    - DOC: config: Use the right alias for %B
    - BUG/MINOR: channel: Increase the stconn bytes_in value in channel_add_input()
    - BUG/MINOR: sample: Fix sample to retrieve the number of bytes received and sent
    - BUG/MINOR: http-ana: Increment scf bytes_out value if an haproxy error is sent
    - BUG/MAJOR: fcgi: Fix param decoding by properly checking its size
    - BUG/MAJOR: resolvers: Properly lowered the names found in DNS response
    - BUG/MEDIUM: mux-fcgi: Use a safe loop to resume each stream eligible for sending
    - MINOR: mux-fcgi: Use a dedicated function to resume streams eligible for sending
    - CLEANUP: qpack: simplify length checks in qpack_decode_fs()
    - MINOR: counters: Introduce COUNTERS_UPDATE_MAX()
    - MINOR: listeners: Update the frequency counters separately when needed
    - MINOR: proxies: Update beconn separately
    - MINOR: stats: Add an option to disable the calculation of max counters

2 months agoMINOR: stats: Add an option to disable the calculation of max counters
Olivier Houchard [Mon, 2 Mar 2026 16:01:58 +0000 (17:01 +0100)]
MINOR: stats: Add an option to disable the calculation of max counters

Add a new option, "stats calculate-max-counters [on|off]".
It makes it possible to disable the calculation of max counters, as they
can have a performance cost.

2 months agoMINOR: proxies: Update beconn separately
Olivier Houchard [Wed, 4 Mar 2026 16:43:24 +0000 (16:43 +0000)]
MINOR: proxies: Update beconn separately

Update beconn separately from the call to COUNTERS_UPDATE_MAX(), as soon
there will be an option to get COUNTERS_UPDATE_MAX() to do nothing, and
we still want beconn to be properly updated, as it is used for other
purposes.

2 months agoMINOR: listeners: Update the frequency counters separately when needed
Olivier Houchard [Tue, 3 Mar 2026 17:55:17 +0000 (18:55 +0100)]
MINOR: listeners: Update the frequency counters separately when needed

Update the frequency counters that are exported to the stats page
outside of the call to COUNTERS_UPDATE_MAX(), so that they will
happen even if COUNTERS_UPDATE_MAX() ends up doing nothing.

2 months agoMINOR: counters: Introduce COUNTERS_UPDATE_MAX()
Olivier Houchard [Tue, 3 Mar 2026 15:50:18 +0000 (16:50 +0100)]
MINOR: counters: Introduce COUNTERS_UPDATE_MAX()

Introduce COUNTERS_UPDATE_MAX(), and use it instead of using
HA_ATOMIC_UPDATE_MAX() directly.
For now it just calls HA_ATOMIC_UPDATE_MAX(), but will later be modified
so that we can disable max calculation.
This can be backported up to 2.8 if the usage of COUNTERS_UPDATE_MAX()
generates too many conflicts.

2 months agoCLEANUP: qpack: simplify length checks in qpack_decode_fs()
Frederic Lecaille [Thu, 5 Mar 2026 14:29:06 +0000 (15:29 +0100)]
CLEANUP: qpack: simplify length checks in qpack_decode_fs()

This patch simplifies the decoding loop by merging the variable-length
integer truncation check (len == -1) with the subsequent buffer
availability check (len < length).

This removes redundant code blocks and improves readability without
changing the decoding logic.

Note that the second removal is correct, as the check was duplicate and
unnecessary."

2 months agoMINOR: mux-fcgi: Use a dedicated function to resume streams eligible for sending
Christopher Faulet [Thu, 5 Mar 2026 13:29:52 +0000 (14:29 +0100)]
MINOR: mux-fcgi: Use a dedicated function to resume streams eligible for sending

The same code was duplicated in fcgi_process_mux() and fcgi_sedn(). So let's
move it in a dedicated function.

2 months agoBUG/MEDIUM: mux-fcgi: Use a safe loop to resume each stream eligible for sending
Christopher Faulet [Thu, 5 Mar 2026 13:18:41 +0000 (14:18 +0100)]
BUG/MEDIUM: mux-fcgi: Use a safe loop to resume each stream eligible for sending

At the end of fcgi_send(), if the connection is not full anymore, we loop on
the send list to resume FCGI stream for sending. But a streams may be
removed from the this list during the loop. So a safe loop must be used.

This patch should be backported to all stable versions.

2 months agoBUG/MAJOR: resolvers: Properly lowered the names found in DNS response
Christopher Faulet [Wed, 4 Mar 2026 17:29:21 +0000 (18:29 +0100)]
BUG/MAJOR: resolvers: Properly lowered the names found in DNS response

Names found in DNS responses are lowered to be compared. A name is composed
of several labels, strings precedeed by their length on one byte. For
instance:

 3www7haproxy3org

There is an bug when labels are lowered. The label length is not skipped and
tolower() function is called on it. So for label length in the range [65-90]
(uppercase char), 32 is added to the label length due to the conversion of a
uppercase char to lowercase. This bugs can lead to OOB read later in the
resolvers code.

The fix is quite obvious, the label length must be skipped when the label is
lowered.

Thank you to Kamil Frankowicz for having reported this.

This patch must be backported to all stable versions.

2 months agoBUG/MAJOR: fcgi: Fix param decoding by properly checking its size
Christopher Faulet [Wed, 4 Mar 2026 13:53:04 +0000 (14:53 +0100)]
BUG/MAJOR: fcgi: Fix param decoding by properly checking its size

In functions used to decode a FCGI parameter, the test on the data length
before reading the parameter's name and value did not consider the offset
value used to skip already parsed data. So it was possible to read more data
than available (OOB read). To do so, a malicious FCGI server must send a
forged GET_VALUES_RESULT record containing a parameter with wrong name/value
length.

Thank you to Kamil Frankowicz for having reported this.

This patch must be backported to all stable versions.

2 months agoBUG/MINOR: http-ana: Increment scf bytes_out value if an haproxy error is sent
Christopher Faulet [Thu, 5 Mar 2026 09:01:56 +0000 (10:01 +0100)]
BUG/MINOR: http-ana: Increment scf bytes_out value if an haproxy error is sent

When an HAproxy error is sent, we must not forget to increment bytes_out
value on the front stconn.

This patch must be backport to 3.3.

2 months agoBUG/MINOR: sample: Fix sample to retrieve the number of bytes received and sent
Christopher Faulet [Thu, 5 Mar 2026 08:58:59 +0000 (09:58 +0100)]
BUG/MINOR: sample: Fix sample to retrieve the number of bytes received and sent

There was an issue in the if/else statement in smp_fetch_bytes() function.
When req.bytes_in or req.bytes_out was requested, res.bytes_in was always
returned. It is now fixed.

This patch must be backported to 3.3.

2 months agoBUG/MINOR: channel: Increase the stconn bytes_in value in channel_add_input()
Christopher Faulet [Thu, 5 Mar 2026 08:42:25 +0000 (09:42 +0100)]
BUG/MINOR: channel: Increase the stconn bytes_in value in channel_add_input()

This function is no longer used. So it is not really an bug. But it is still
available and could be used by legacy applets. In that case, we must take
care to increment the stconn bytes_in value accordingly when input data are
inserted.

This patch must be backported to 3.3.

2 months agoDOC: config: Use the right alias for %B
Christopher Faulet [Thu, 5 Mar 2026 08:33:13 +0000 (09:33 +0100)]
DOC: config: Use the right alias for %B

In custom log format part, %[req.bytes_in] was erroneously documented as the
alias of %B. The good alias is %[res.bytes_in]. It is now fixed.

This patch must be backported to 3.3.

2 months agoMINOR: stream: Display the currently running filter per channel in stream dump
Christopher Faulet [Wed, 4 Mar 2026 10:03:01 +0000 (11:03 +0100)]
MINOR: stream: Display the currently running filter per channel in stream dump

Since the 3.1, when stream's info are dump, it is possible to print the
yielding filter on each channel, if any. It was useful to detect buggy
filter on spinning loop. But it is not possible to detect a filter consuming
too much CPU per-execution. We can see a filter was executing in the
backtrace reported by the watchdog, but we are unable to spot the specific
one.

Thanks to this patch, it is now possible. When a dump is emitted, the
running or yield filters on each channel are now displayed with their
current state (RUNNING or YIELDING).

This patch could be backported as far as 3.2 because it could be useful to
spot issues. But the filter API was slightly refactored in 3.4, so this
patch should be adapted.

2 months agoMINOR: filters: Set last_entity when a filter fails on stream_start callback
Christopher Faulet [Wed, 4 Mar 2026 09:56:52 +0000 (10:56 +0100)]
MINOR: filters: Set last_entity when a filter fails on stream_start callback

On the stream, the last_entity should reference the last rule or the last
filter evaluated during the stream processing. However, this info was not
saved when a filter failed on strem_start callback function. It is now
fixed.

This patch could be backported as far as 3.1.

2 months agoMINOR: filters: Use filter API as far as poissible to break loops on filters
Christopher Faulet [Wed, 4 Mar 2026 08:05:14 +0000 (09:05 +0100)]
MINOR: filters: Use filter API as far as poissible to break loops on filters

When the filters API was refactored to improve loops on filters, some places
were not updated (or not fully updated). Some loops were not relying on
resume_filter_list_break() while it was possible. So let's do so with this
patch.

2 months agoDEBUG: stream: Display the currently running rule in stream dump
Christopher Faulet [Wed, 4 Mar 2026 07:53:20 +0000 (08:53 +0100)]
DEBUG: stream: Display the currently running rule in stream dump

Since the 2.5, when stream's info are dump, it is possible to print the
yielding rule, if any. It was useful to detect buggy rules on spinning
loop. But it is not possible to detect a rule consuming too much CPU
per-execution. We can see a rule was executing in the backtrace reported by
the watchdog, but we are unable to spot the specific rule.

Thanks to this patch, it is now possible. When a dump is emitted, the
running or yield rule is now displayed with its current state (RUNNING or
YIELDING).

This patch could be backported as far as 3.2 because it could be useful to
spot issues.

2 months agoMEDIUM: http-ana: Use the version of the opposite side for internal messages
Christopher Faulet [Wed, 25 Feb 2026 15:29:26 +0000 (16:29 +0100)]
MEDIUM: http-ana: Use the version of the opposite side for internal messages

When the response is send by HAProxy, from a applet or for the analyzers,
The request version is used for the response. The main reason is that there
is not real version for the response when this happens. "HTTP/1.1" is used,
but it is in fact just an HTX response. So the version of the request is
used.

In the same manner, when the request is sent from an applet (httpclient),
the response version is used, once available.

The purpose of this change is to return the most accurate version from the
user point of view.

2 months agoMEDIUM: http-fetch: Rework how HTTP message version is retrieved
Christopher Faulet [Wed, 25 Feb 2026 15:20:56 +0000 (16:20 +0100)]
MEDIUM: http-fetch: Rework how HTTP message version is retrieved

Thanks to previous patches, we can now rely on the version stored in the
http_msg structure to get the request or the response version.

"req.ver" and "res.ver" sample fetch functions returns the string
representation of the version, without the prefix, so "<major>.<minor>", but
only if the version is valid. For the response, "res.ver" may be added from
a health-check context, in that case, the HTX message is used.

"capture.req.ver" and "capture.res.ver" does the same but the "HTTP/" prefix
is added to the result. And "capture.res.ver" cannot be called from a
health-check.

To ease the version formatting and avoid code duplication, an helper
function was added. So these samples are now relying on "get_msg_version()".

2 months agoMINOR: http-ana: Save the message version in the http_msg structure
Christopher Faulet [Wed, 25 Feb 2026 15:10:28 +0000 (16:10 +0100)]
MINOR: http-ana: Save the message version in the http_msg structure

When the request or the response is received, the numerical value of the
message version is now saved. To do so, the field "vsn" was added in the
http_msg structure. It is an unsigned char. The 4 MSB bits are used for the
major digit and the 4 LSB bits for the minor one.

Of couse, the version must be valid. the HTX_SL_F_NOT_HTTP flag of the
start-line is used to be sure the version is valid. But because this flag is
quite new, we also take care the string representation of the version is 8
bytes length. 0 means the version is not valid.

2 months agoBUG/MINOR: h1-htx: Be sure that H1 response version starts by "HTTP/"
Christopher Faulet [Wed, 25 Feb 2026 15:00:39 +0000 (16:00 +0100)]
BUG/MINOR: h1-htx: Be sure that H1 response version starts by "HTTP/"

When the response is parsed, we test the version to be sure it is
valid. However, the protocol was not tested. Now we take care that the
response version starts by "HTTP/", otherwise an error is returned.

Of course, it is still possible to by-pass this test with
"accept-unsafe-violations-in-http-response" option.

This patch could be backported to all stable versions.

2 months agoMINOR: h1-htx: Reports non-HTTP version via dedicated flags
Christopher Faulet [Wed, 25 Feb 2026 14:37:30 +0000 (15:37 +0100)]
MINOR: h1-htx: Reports non-HTTP version via dedicated flags

Now, when the HTTP version format is not strictly valid, flags are set on
the h1 parser and the HTX start-line. H1_MF_NOT_HTTP is set on the H1 parser
and HTX_SL_F_NOT_HTTP is set on the HTX start-line. These flags were
introduced to avoid parsing again and again the version to know if it is a
valid version or not, escpecially because it is most of time valid.

2 months agoMINOR: htx: Add a function to retrieve the HTTP version from a start-line
Christopher Faulet [Wed, 25 Feb 2026 14:33:37 +0000 (15:33 +0100)]
MINOR: htx: Add a function to retrieve the HTTP version from a start-line

htx_sl_vsn() function can now be used to retrieve the ist string
representing the HTTP version from a start-line passed as parameter. This
function takes care to return the right part of the start-line, depending on
its type (request or response).

2 months agoBUG/MINOR: hlua: Properly enable/disable receives for TCP applets
Christopher Faulet [Wed, 4 Mar 2026 18:15:34 +0000 (19:15 +0100)]
BUG/MINOR: hlua: Properly enable/disable receives for TCP applets

From a lua TCP applet, in functions used to retrieve data (receive,
try_receive and getline), we must take care to disable receives when data
are returned (or on failure) and to restart receives when these functions
are called again. In addition, when an applet execution is finished, we must
restart receives to properly drain the request.

This patch should be backported to 3.3. On older version, no bug was
reported so we can wait a report first.

2 months agoBUG/MEDIUM: hlua: Fix end of request detection when retrieving payload
Christopher Faulet [Tue, 3 Mar 2026 08:30:40 +0000 (09:30 +0100)]
BUG/MEDIUM: hlua: Fix end of request detection when retrieving payload

When the lua HTTP applet was refactored to use its own buffers, a bug was
introduced in receive() and getline() function. We rely on HTX_FL_EOM flag
to detect the end of the request. But there is nothing preventing extra
calls to these function, when the whole request was consumed. If this
happens, the call will yield waiting for more data with no way to stop it.

To fix the issue, APPLET_REQ_RECV flag was added to know the whole request
was received.

This patch should fix #3293. It must be backported to 3.3.

2 months agoBUG/MINOR: hlua: Properly enable/disable line receives from HTTP applet
Christopher Faulet [Mon, 2 Mar 2026 18:07:07 +0000 (19:07 +0100)]
BUG/MINOR: hlua: Properly enable/disable line receives from HTTP applet

From a lua HTTP applet, in the getline() function, we must take care to
disable receives when a line is retrieved and to restart receives when the
function is called again. In addition, when an applet execution is finished,
we must restart receives to properly drain the request.

This patch could help to fix #3293. It must be backported to 3.3. On older
version, no bug was reported so we can wait a report first. But in that
case, hlua_applet_http_recv() should also be fixed (on 3.3 it was fixed
during the applets refactoring).

2 months agoBUG/MEDIUM: qpack: correctly deal with too large decoded numbers
Frederic Lecaille [Thu, 5 Mar 2026 13:46:51 +0000 (14:46 +0100)]
BUG/MEDIUM: qpack: correctly deal with too large decoded numbers

Same fix as this one for hpack:

7315428615 ("BUG/MEDIUM: hpack: correctly deal with too large decoded numbers")

Indeed, the encoding of integers for QPACK is the same as for HPACK but for 64 bits
integers.

Must be backported as far as 2.6.

2 months agoBUG/MINOR: quic: fix OOB read in preferred_address transport parameter
Frederic Lecaille [Wed, 4 Mar 2026 16:30:08 +0000 (17:30 +0100)]
BUG/MINOR: quic: fix OOB read in preferred_address transport parameter

This bug impacts only the QUIC backend. A QUIC server does receive
a server preferred address transport parameter.

In quic_transport_param_dec_pref_addr(), the boundary check for the
connection ID was inverted and incorrect. This could lead to an
out-of-bounds read during the following memcpy.

This patch fixes the comparison to ensure the buffer has enough input data
for both the CID and the mandatory Stateless Reset Token.

Thank you to Kamil Frankowicz for having reported this.

Must be backported to 3.3.

2 months agoBUG/MINOR: qpack: fix 1-byte OOB read in qpack_decode_fs_pfx()
Frederic Lecaille [Wed, 4 Mar 2026 13:10:49 +0000 (14:10 +0100)]
BUG/MINOR: qpack: fix 1-byte OOB read in qpack_decode_fs_pfx()

In qpack_decode_fs_pfx(), if the first qpack_get_varint() call
consumes the entire buffer, the code would perform a 1-byte
out-of-bounds read when accessing the sign bit via **raw.

This patch adds an explicit length check at the beginning of
qpack_get_varint(), which systematically secures all other callers
against empty inputs. It also adds a necessary check before the
second varint call in qpack_decode_fs_pfx() to ensure data is still
available before dereferencing the pointer to extract the sign bit,
returning QPACK_RET_TRUNCATED if the buffer is exhausted.

Thank you to Kamil Frankowicz for having reported this.

Must be backported as far as 2.6.

2 months agoBUG/MAJOR: qpack: unchecked length passed to huffman decoder
Frederic Lecaille [Wed, 4 Mar 2026 13:02:28 +0000 (14:02 +0100)]
BUG/MAJOR: qpack: unchecked length passed to huffman decoder

A call to huffman decoder function (huff_dec()) is made from qpack_decode_fs()
without checking the buffer length passed to this function, leading to OOB read
which can crash the process.

Thank you to Kamil Frankowicz for having reported this.

Must be backport as far as 2.6.

2 months agoBUG/MEDIUM: hpack: correctly deal with too large decoded numbers
Willy Tarreau [Wed, 4 Mar 2026 10:37:12 +0000 (11:37 +0100)]
BUG/MEDIUM: hpack: correctly deal with too large decoded numbers

The varint hpack decoder supports unbounded numbers but returns 32-bit
results. This means that possible truncation my happen on some field
lengths or indexes that would be emitted as quantities that do not fit
in a 32-bit number. The final value will also depend on how the left
shift operation behaves on the target architecture (e.g. whether bits
are lost or used modulo 31). This could lead to a desynchronization of
the HPACK stream decoding compared to what an external observer would
see (e.g. from a network traffic capture). However, there isn't any
impact between streams, HPACK is performed at the connection level,
not at the stream level, so no stream may try to leverage this
limitation to have any effect on another one.

For the fix, instead of adding checks everywhere in the loop and for
the final stage, let's rewrite the decoder to compare the read value
to a max value that is shifted by 7 bits for every 7 bits read. This
allows a sender to continue to emit zeroes for higher bits without
being blocked, while detecting that a received value would overflow.
The loop is now simpler as it deals both with values with the higher
bit set and the final ones, and stops once the final value was recorded.

A test on non-zero before performing the shift was added to please
ubsan, though in practice zero shifted by any quantity remains zero.
But the test is cheap so that's OK.

Thanks to Guillaume Meunier, Head of Vulnerability Operations Center
France at Orange Cyberdefense, for reporting this bug.

This should be backported to all stable versions.

2 months agoMINOR: quic: use server cache for ALPN on BE side
Amaury Denoyelle [Tue, 3 Mar 2026 09:02:39 +0000 (10:02 +0100)]
MINOR: quic: use server cache for ALPN on BE side

On the backend side, QUIC MUX may be started preemptively before the
ALPN negotiation. This is useful notably for 0-RTT implementation.

However, this was a source of crashes. ALPN was expected to be retrieved
from the server cache, however QUIC MUX still used the ALPN from the
transport layer. This could cause a crash, especially when several
connections runs in parallel as the server cache is shared among
threads.

Thanks to the previous patch which reworks QUIC MUX init, this solution
can now be fixed. Indeed, if conn_get_alpn() is not successful, MUX can
look at the server cache again to use the expected value.

Note that this could still prevent the MUX to work as expected if the
server cache is resetted between connect_server() and MUX init. Thus,
the ultimate solution would be to copy the cached ALPN into the
connection. This problem is not specific to QUIC though, and must be
fixed in a separate patch.

2 months agoMEDIUM: quic/mux-quic: adjust app-ops install
Amaury Denoyelle [Tue, 3 Mar 2026 08:47:29 +0000 (09:47 +0100)]
MEDIUM: quic/mux-quic: adjust app-ops install

This patch reworks the installation of app-ops layer by QUIC MUX.
Previously, app_ops field was stored directly into the quic_conn
structure. Then the MUX reused it directly during its qmux_init().

This patch removes app_ops field from quic_conn and replaces it with a
copy of the negotiated ALPN. By using quic_alpn_to_app_ops(), it ensures
it remains compatible with a known application layer.

On the MUX layer, qcc_install_app_ops() now uses the standard
conn_get_alpn() to retrieve the ALPN from the transport layer. This is
done via the newly defined <get_alpn> QUIC xprt callback.

This new architecture should be cleaner as it better highlights the
responsibility of each layers in the ALPN/app negotiation.

2 months agoMINOR: mux-quic: add function for ALPN to app-ops conversion
Amaury Denoyelle [Tue, 3 Mar 2026 08:45:22 +0000 (09:45 +0100)]
MINOR: mux-quic: add function for ALPN to app-ops conversion

Extract the conversion from ALPN to qcc_app_ops type from quic_conn
source file into QUIC MUX. The newly created function is named
quic_alpn_to_app_ops(). This will serve as a central point to identify
which ALPNs are currently supported in our QUIC stack.

This patch is purely a small refactoring. It will be useful for the next
one which rework MUX app-ops layer init. The current cleanup allows
notably to remove H3/hq-interop headers from quic_conn source file.

2 months agoMINOR: quic/h3: reorganize stream reject after MUX closure
Amaury Denoyelle [Tue, 3 Mar 2026 08:41:26 +0000 (09:41 +0100)]
MINOR: quic/h3: reorganize stream reject after MUX closure

The QUIC MUX layer is closed after its transport counterpart. This may
be necessary then to reject any new streams opened by the remote peer.
This operation is dependent however from the application protocol.

Previously, a function qc_h3_request_reject() was directly implemented
in quic_conn source file for use when HTTP/3 was previously negotiated.
However, this solution was not evolutive and broke layering.

This patch introduces a new proper separation with a <strm_reject>
callback defined in quic_conn structure. When set, it will be used to
preemptively close any new stream. QUIC MUX is responsible to set it
just before its closure.

No functional change. This patch is purely a refactoring with a better
architecture design. Especially, H3 specific code from transport layer
is now completely removed.

2 months agoMINOR: quic: use signed char type for ALPN manipulation
Amaury Denoyelle [Tue, 3 Mar 2026 08:02:44 +0000 (09:02 +0100)]
MINOR: quic: use signed char type for ALPN manipulation

In most of haproxy code, ALPN is used as a signed char pointer. In QUIC
code instead, it is manipulated as unsigned.

Unifies this by using signed type in QUIC code. This allows to remove a
bunch of unnecessary casts.

2 months agoBUG/MEDIUM: stream: Handle TASK_WOKEN_RES as a stream event
Christopher Faulet [Tue, 3 Mar 2026 11:50:36 +0000 (12:50 +0100)]
BUG/MEDIUM: stream: Handle TASK_WOKEN_RES as a stream event

The conversion of TASK_WOKEN_RES to a stream event was missing. Among other
things, this wakeup reason is used when a stream is dequeued. So it was
possible to skip the connection establishment if the stream was also woken
up for a timer reason. When this happened, the stream was blocked till the
queue timeout expiration.

Converting TASK_WOKEN_RES to STRM_EVT_RES fixes the issue.

This patch should fix the issue #3290. It must be backported as far as 3.2.

2 months agoBUG/MINOR: hlua: fix return with push nil on proxy check
Amaury Denoyelle [Tue, 3 Mar 2026 07:45:27 +0000 (08:45 +0100)]
BUG/MINOR: hlua: fix return with push nil on proxy check

hlua_check_proxy() may now return NULL if the target proxy instance has
been flagged for deletion. Thus, proxies method have been adjusted and
may push nil to report such case.

This patch fixes these error paths. When nil is pushed, 1 must be
returned instead of 0. This represents the count of pushed values on the
stack which can be retrieved by the caller.

No need to backport.

2 months agoREGTESTS: complete "del backend" with unnamed defaults ref free
Amaury Denoyelle [Mon, 2 Mar 2026 07:51:46 +0000 (08:51 +0100)]
REGTESTS: complete "del backend" with unnamed defaults ref free

Complete delete backend regtests by checking deletion of a proxy with a
reference on an unnamed defaults instance. This operation is sensible as
the defaults refcount is decremented, and when the last backend is
removed, the defaults is also freed.

2 months agoREGTESTS: add a test on "del backend"
Amaury Denoyelle [Fri, 27 Feb 2026 09:45:55 +0000 (10:45 +0100)]
REGTESTS: add a test on "del backend"

Add a reg-tests to test "del backend" CLI command. First, checks are
performed to ensure a backend cannot be deleted if not in the expected
state.

Then, a "del backend" success is tested. Stats are dumped to ensure the
backend instance is indeed removed.

2 months agoMEDIUM: proxy: implement backend deletion
Amaury Denoyelle [Tue, 6 Jan 2026 14:26:13 +0000 (15:26 +0100)]
MEDIUM: proxy: implement backend deletion

This patch finalizes "del backend" handler by implementing the proper
proxy deletion.

After ensuring backend deletion can be performed, several steps are
executed. First, any watcher elements are updated to point on the next
proxy instance. The backend is then removed from ID and name global
trees and is finally detached from proxies_list.

Once the backend instance is removed from proxies_list, the backend
cannot be found by new elements. Thread isolation is lifted and
proxy_drop() is called, which will purge the proxy if its refcount is
null. Thanks to recently introduced PROXIES_DEL_LOCK, proxy_drop() is
thread safe.

2 months agoMINOR: proxy: use atomic ops for default proxy refcount
Amaury Denoyelle [Mon, 2 Mar 2026 10:15:41 +0000 (11:15 +0100)]
MINOR: proxy: use atomic ops for default proxy refcount

Default proxy refcount <def_ref> is used to comptabilize reference on a
default proxy instance by standard proxies. Currently, this is necessary
when a default proxy defines TCP/HTTP rules or a tcpcheck ruleset.

Transform every access on <def_ref> so that atomic operations are now
used. Currently, this is not strictly needed as default proxies
references are only manipulated at init or deinit in single thread mode.
However, when dynamic backends deletion will be implemented, <def_ref>
will be decremented at runtime also.

2 months agoMEDIUM: proxy: add lock for global accesses during default free
Amaury Denoyelle [Mon, 2 Mar 2026 08:05:19 +0000 (09:05 +0100)]
MEDIUM: proxy: add lock for global accesses during default free

This patch is similar to the previous one, but this time it deals with
functions related to defaults proxies instances. Lock PROXIES_DEL_LOCK
is used to protect accesses on global collections.

This patch will be necessary to implement dynamic backend deletion, even
if defaults won't be use as direct target of a "del backend" CLI.
However, a backend may have a reference on a default instance. When the
backend is freed, this references is released, which can in turn cause
the freeing of the default proxy instance. All of this will occur at
runtime, outside of thread isolation.

2 months agoMEDIUM: proxy: add lock for global accesses during proxy free
Amaury Denoyelle [Mon, 2 Mar 2026 07:51:18 +0000 (08:51 +0100)]
MEDIUM: proxy: add lock for global accesses during proxy free

Define a new lock with label PROXIES_DEL_LOCK. Its purpose is to protect
operations performed on global lists or trees while a proxy is freed.

Currently, this lock is unneeded as proxies are only freed on
single-thread init or deinit. However, with the incoming dynamic backend
deletion, this operation will be also performed at runtime, outside of
thread isolation.

2 months agoMINOR: proxy: add comment for defaults_px_ref/unref_all()
Amaury Denoyelle [Mon, 2 Mar 2026 07:52:20 +0000 (08:52 +0100)]
MINOR: proxy: add comment for defaults_px_ref/unref_all()

Write documentation for functions related to default proxies instances.

2 months agoMINOR: cli: implement wait on be-removable
Amaury Denoyelle [Wed, 18 Feb 2026 13:00:08 +0000 (14:00 +0100)]
MINOR: cli: implement wait on be-removable

Implement be-removable argument to CLI wait. This is implemented via
be_check_for_deletion() invokation, also used by "del backend" handler.

The objective is to test whether a backend instance can be removed. If
this is not the case, the command may returns immediately if the target
proxy is incompatible with dynamic removal or if a user action is
required. Else, the command will wait until the temporary restriction is
lifted.

2 months agoMINOR: server: mark backend removal as forbidden if QUIC was used
Amaury Denoyelle [Mon, 23 Feb 2026 11:01:39 +0000 (12:01 +0100)]
MINOR: server: mark backend removal as forbidden if QUIC was used

Currenly, quic_conn on the backend side may access their parent proxy
instance during their lifetime. In particular, this is the case for
counters update, with <prx_counters> field directly referencing a proxy
memory zone.

As such, this prevents safe backend removal. One solution would be to
check if the upper connection instance is still alive, as a proxy cannot
be removed if connection are still active. However, this would
completely prevent proxy counters update via
quic_conn_prx_cntrs_update(), as this is performed on quic_conn release.

Another solution would be to use refcount, or a dedicated counter on the
which account for QUIC connections on a backend instance. However,
refcount is currently only used by short-term references, and it could
also have a negative impact on performance.

Thus, the simplest solution for now is to disable a backend removal if a
QUIC server is/was used in it. This is considered acceptable for now as
QUIC on the backend side is experimental.

2 months agoMINOR: proxy: prevent backend deletion if server still exists in it
Amaury Denoyelle [Mon, 12 Jan 2026 14:26:45 +0000 (15:26 +0100)]
MINOR: proxy: prevent backend deletion if server still exists in it

Ensure a backend instance cannot be removed if there is still server in
it. This is checked via be_check_for_deletion() to ensure "del backend"
cannot be executed. The only solution is to use "del server" to remove
on the servers instances.

This check only covers servers not yet targetted via "del server". For
deleted servers not yet purged (due to their refcount), the proxy
refcount is incremented but this does not block "del backend"
invokation.

2 months agoMINOR: proxy: prevent deletion of backend referenced by config elements
Amaury Denoyelle [Tue, 6 Jan 2026 15:53:03 +0000 (16:53 +0100)]
MINOR: proxy: prevent deletion of backend referenced by config elements

Define a new proxy flag PR_FL_NON_PURGEABLE. This is used to mark every
proxy instance explicitely referenced in the config. Such instances
cannot be deleted at runtime.

Static use_backend/default_backend rules are handled in
proxy_finalize(). Also, sample expression proxy references are protected
via smp_resolve_args().

Note that this last case also incidentally protects any proxies
referenced via a CLI "set var" expression. This should not be the case
as in this case variable value is instantly resolved so the proxy
reference is not needed anymore. This also affects dynamic servers.

2 months agoMINOR: proxy: prevent backend removal when unsupported
Amaury Denoyelle [Tue, 6 Jan 2026 15:38:05 +0000 (16:38 +0100)]
MINOR: proxy: prevent backend removal when unsupported

Prevent removal of a backend which relies on features not compatible
with dynamic backends. This is the case if either dispatch or
transparent option is used, or if a stick-table is declared.

These limitations are similar to the "add backend" ones.

2 months agoMINOR: lua: handle proxy refcount
Amaury Denoyelle [Wed, 18 Feb 2026 08:55:13 +0000 (09:55 +0100)]
MINOR: lua: handle proxy refcount

Implement proxy refcount for Lua proxy class. This is similar to the
server class.

In summary, proxy_take() is used to increment refcount when a Lua proxy
is instantiated. proxy_drop() is called via Lua garbage collector. To
ensure a deleted backend is released asap, hlua_check_proxy() now
returns NULL if PR_FL_DELETED is set.

This approach is directly dependable on Lua GC execution. As such, it
probably suffers from the same limitations as the ones already described
in the previous commit. With the current patch, "del backend" is not
directly impacted though. However, the final proxy deinit may happen
after a long period of time, which could cause memory pressure increase.

One final observations regarding deinit : it is necessary to delay a
BUG_ON() which checks that defaults proxies list is empty. Now this must
be executed after Lua deinit (called via post_deinit_list). This should
guarantee that all proxies and their defaults refcount are null.

2 months agoMINOR: server: take proxy refcount when deleting a server
Amaury Denoyelle [Tue, 6 Jan 2026 15:28:36 +0000 (16:28 +0100)]
MINOR: server: take proxy refcount when deleting a server

When a server is deleted via "del server", increment refcount of its
parent backend. This is necessary as the server is not referenced
anymore in the backend, but can still access it via its own <proxy>
member. Thus, backend removal must not happen until the complete purge
of the server.

The proxy refcount is released in srv_drop() if the flag SRV_F_DELETED
is set, which indicates that "del server" was used. This operation is
performed after the complete release of the server instance to ensure no
access will be performed on the proxy via itself. The refcount must not
be decremented if a server is freed without "del server" invokation.

Another solution could be for servers to always increment the refcount.
However, for now in haproxy refcount usage is limited, so the current
approach is preferred. It should also ensure that if the refcount is
still incremented, it may indicate that some servers are not completely
purged themselves.

Note that this patch may cause issues if "del backend" are used in
parallel with LUA scripts referencing servers. Currently, any servers
referenced by LUA must be released by its garbage collector to ensure it
can be finally freed. However, it appeas that in some case the gc does
not run for several minutes. At least this has been observed with Lua
version 5.4.8. In the end, this will result in indefinitely blocking of
"del backend" commands.

2 months agoMINOR: proxy: rename default refcount to avoid confusion
Amaury Denoyelle [Fri, 27 Feb 2026 08:20:15 +0000 (09:20 +0100)]
MINOR: proxy: rename default refcount to avoid confusion

Rename proxy conf <refcount> to <def_ref>. This field only serves for
defaults proxy instances. The objective is to avoid confusion with the
newly introduced <refcount> field used for dynamic backends.

As an optimization, it could be possible to remove <def_ref> and only
use <refcount> also for defaults proxies usage. However for now the
simplest solution is implemented.

This patch does not bring any functional change.

2 months agoMINOR: proxy: add refcount to proxies
Amaury Denoyelle [Fri, 13 Feb 2026 10:29:00 +0000 (11:29 +0100)]
MINOR: proxy: add refcount to proxies

Implement refcount notion into proxy structure. The objective is to be
able to increment refcount on proxy to prevent its deletion temporarily.
This is similar to the server refcount : "del backend" is not blocked
and will remove the targetted instance from the global proxies_list.
However, the final free operation is delayed until the refcount is null.

As stated above, the API is similar to servers. Proxies are initialized
with a refcount of 1. Refcount can be incremented via proxy_take(). When
no longer useful, refcount is decremented via proxy_drop() which
replaces the older free_proxy(). Deinit is only performed once refcount
is null.

This commit also defines flag PR_FL_DELETED. It is set when a proxy
instance has been removed via a "del backend" CLI command. This should
serve as indication to modules which may still have a refcount on the
target proxy so that they can release it as soon as possible.

Note that this new refcount is completely ignored for a default proxy
instance. For them, proxy_take() is pure noop. Free is immediately
performed on first proxy_drop() invokation.

2 months agoMINOR: lua: use watcher for proxies iterator
Amaury Denoyelle [Tue, 24 Feb 2026 16:47:46 +0000 (17:47 +0100)]
MINOR: lua: use watcher for proxies iterator

Ensures proxies iteration via lua functions is safe via a new watcher
member. The principle is similar to the one already used for servers
iteration.

2 months agoMINOR: promex: use watcher to iterate over backend instances
Amaury Denoyelle [Tue, 24 Feb 2026 15:22:12 +0000 (16:22 +0100)]
MINOR: promex: use watcher to iterate over backend instances

Ensures proxies iteration in promex applet is safe via a new watcher
member. The principle is similar to the one already used for servers
iteration.

Note that ctx.p[0] is not updated anymore at the end of a function, as
this is automatically done via the watcher itself.

2 months agoMINOR: stats: protect proxy iteration via watcher
Amaury Denoyelle [Tue, 10 Feb 2026 10:20:12 +0000 (11:20 +0100)]
MINOR: stats: protect proxy iteration via watcher

Define a new <px_watch> watcher member in stats applet context. It is
used to register the applet on a proxy when iterating over the proxies
list. <obj1> is automatically updated via the watcher interaction.
Watcher is first initialized prior to stats_dump_proxies() invocation.

This guarantees that stats dump is safe even if applet yields and a
backend is removed in parallel.

2 months agoMINOR: proxy: define proxy watcher member
Amaury Denoyelle [Tue, 10 Feb 2026 10:18:11 +0000 (11:18 +0100)]
MINOR: proxy: define proxy watcher member

Define a new member watcher_list in proxy. It will be used to register
modules which iterate over the proxies list. This will ensure that the
operation is safe even if a backend is removed in parallel.

2 months agoMINOR: proxy: define a basic "del backend" CLI
Amaury Denoyelle [Tue, 6 Jan 2026 10:40:05 +0000 (11:40 +0100)]
MINOR: proxy: define a basic "del backend" CLI

Add "del backend" handler which is restricted to admin level. Along with
it, a new function be_check_for_deletion() is used to test if the
backend is removable.

2 months agoMINOR: server: refactor srv_detach()
Amaury Denoyelle [Tue, 6 Jan 2026 15:36:44 +0000 (16:36 +0100)]
MINOR: server: refactor srv_detach()

Correct documentation for srv_detach() which previously stated that this
function could be called for a server even if not stored in its proxy
list. In fact there is a BUG_ON() which detects this case.

2 months agoMINOR: proxy: convert proxy flags to uint
Amaury Denoyelle [Mon, 12 Jan 2026 09:53:57 +0000 (10:53 +0100)]
MINOR: proxy: convert proxy flags to uint

Proxy flags member were of type char. This will soon enough not be
sufficient as new flags will be defined. As such, convert flags member
to unsigned int type.

2 months agoBUG/MINOR: proxy: add dynamic backend into ID tree
Amaury Denoyelle [Wed, 18 Feb 2026 13:00:22 +0000 (14:00 +0100)]
BUG/MINOR: proxy: add dynamic backend into ID tree

Add missing proxy_index_id() call in "add backend" handler. This step is
responsible to store the newly created proxy instance in the
used_proxy_id global tree.

No need to backport.

2 months agoBUG/MINOR: promex: fix server iteration when last server is deleted
Amaury Denoyelle [Thu, 26 Feb 2026 10:18:43 +0000 (11:18 +0100)]
BUG/MINOR: promex: fix server iteration when last server is deleted

Servers iteration via promex is now resilient to server runtime deletion
thanks to the watcher mechanism. However, the watcher was not correctly
initialized which could cause duplicate metrics reporting.

This issue happens when promex dump yielded when manipulating the last
server of a proxy. If this server is removed in parallel, <sv> pointer
will be set to NULL when promex resumes. Instead of switching to another
proxy, the code would reuse the same one and iterate again on the same
server list.

To fix this issue, <sv> pointer must not be reinitialized just after a
resumption point. Instead, this is now performed before
promex_dump_srv_metrics(), or just after switching to another proxy
instance. Thus, on resumption, if promex_dump_srv_metrics() is started
with <sv> as NULL, it means that the server was deleted and the end of
the current proxy list is reached, hence iteration is restarted on the
next proxy instance.

Note that ctx.p[1] does not need to be manually updated at the end of
promex_dump_srv_metrics() as srv_watch already does that.

This patch must be backported up to 3.0.

2 months agoMINOR: promex: test applet resume in stress mode
Amaury Denoyelle [Tue, 24 Feb 2026 16:05:37 +0000 (17:05 +0100)]
MINOR: promex: test applet resume in stress mode

Implement a stress mode with force yield for promex applet each time a
metric is displayed. This is implemented by returning 0 in
promex_dump_ts() each time the output buffer is not empty.

To test this, haproxy must be compiled with DEBUG_STRESS and the
following configuration must be used :

  global
    stress-level 1

2 months agoBUG/MINOR: call EXTRA_COUNTERS_FREE() before srv_free_params() in srv_drop()
Willy Tarreau [Thu, 26 Feb 2026 16:18:41 +0000 (17:18 +0100)]
BUG/MINOR: call EXTRA_COUNTERS_FREE() before srv_free_params() in srv_drop()

As seen with the last changes to counters allocation, the move of the
counters storage to the thread group as operated in commit 04a9f86a85
("MEDIUM: counters: add a dedicated storage for extra_counters in various
structs") causes some random errors when using ASAN, because the extra
counters are freed in srv_drop() after calling srv_free_params(), which
is responsible for freeing the per-thread group storage.

For the proxies however it's OK because free calls are made before the
call to deinit_proxy() which frees the per_tgrp area.

No backport is needed, this is purely 3.4-dev.

2 months agoMEDIUM: counters: make EXTRA_COUNTERS_GET() consider tgid
Willy Tarreau [Wed, 25 Feb 2026 08:58:08 +0000 (09:58 +0100)]
MEDIUM: counters: make EXTRA_COUNTERS_GET() consider tgid

Now we store and retrieve only counters for the current tgid when more
than one is supported. This allows to significantly reduce contention
on shared stats. The haterm utility saw its performance increase from
4.9 to 5.8M req/s in H1, and 6.0 to 7.6M for H2, both with 5 groups of
16 threads, showing that we don't necessarily need insane amounts of
groups.

2 months agoMEDIUM: counters: return aggregate extra counters in ->fill_stats()
Willy Tarreau [Wed, 25 Feb 2026 17:38:55 +0000 (18:38 +0100)]
MEDIUM: counters: return aggregate extra counters in ->fill_stats()

Now thanks to new macro EXTRA_COUNTERS_AGGR() we can iterate over all
thread groups storages when returning the data for a given metric. This
remains convenient and mostly transparent. The caller continues to pass
the pointer to the metric in the first group, and offsets are calculated
for all other groups and data summed. For now all groups except the
first one contain only zeroes but reported values are nevertheless
correct.

2 months agoMINOR: counters: add EXTRA_COUNTERS_BASE() to retrieve extra_counters base storage
Willy Tarreau [Wed, 25 Feb 2026 09:13:21 +0000 (10:13 +0100)]
MINOR: counters: add EXTRA_COUNTERS_BASE() to retrieve extra_counters base storage

The goal is to always retrieve the storage address of the first thread
group for the given module. This will be used to iterate over all thread
groups. For now it returns the same value as EXTRA_COUNTERS_GET().