HAProxy - Load balancer
Find a file
Willy Tarreau a0541f5d21 BUG/MEDIUM: mux-h2: ignore conn->owner when deciding if a connection is dead
Originally, valid backend connections always used to have conn->owner
pointing to the owner session. In 1.9, commit 93c885 enforced this when
implementing backend H2 support by making sure that no orphaned connection
was left on its own with no remaining stream able to handle it.
Later, idle connections were reworked so that they were no longer
necessarily attached to a stream, but could be directly in the server,
accessed via a hash, so it started to become possible to have conn->owner
left to NULL when picking such a connection. It in fact happens for
http-reuse always, when the second stream picks the connection because
its owner is NULL and it's not changed.

More recently, a case was identified where it could be theoretically
possible to reinsert a dead connection into an idle list, and commit
59c599f3f0 ("BUG/MEDIUM: mux-h2: make sure not to move a dead
connection to idle") addressed that possibility in 3.3 by adding the
h2c_is_dead() test in h2_detach() before deciding to reinsert a
connection into the idle list.

Unfortunately, the combination of changes above results in the following
sequence being possible:
  - a stream requires a connection, connect_server() creates one, sets
    conn->owner to the session, then when the session is being set up,
    the SSL stack calls conn_create_mux() which gets the session from
    conn->owner, passes it to mux->init() (h2_init), which in turn
    creates the backend stream and assigns it this session.

  - when the stream ends, it detaches (h2_detach), and the call to
    h2c_is_dead() returns false because h2c->conn->owner is set. The
    connection is thus added into the server's idle list.

  - a new stream comes, it finds the connection in the server's list,
    which doesn't require to set conn->owner, the stream is added via
    h2_attach() which passes the stream's session, and that one is
    properly set on h2s again, but never on conn->owner.

  - the stream finishes, detaches, and this time the call to h2c_is_dead()
    sees the owner is NULL, thus indicates that the connection seems dead
    so it's not added again to the idle list, and it's destroyed.

Note that this most only happens at low loads (at most one active stream
per connection, so typically at most than one active stream per thread),
where the H2 reuse ratio on a server configured with http-reuse always
or http-reuse aggressive is close to 50%. At high loads, this is much more
rare, though looking at the reuse stats for a server, it's visible that a
sustained load still shows around 1% of the connections being periodically
renewed.

Interestingly, for RHTTP the impact is more important because there
was already a work around for this test in h2c_is_dead() but it uses
conn_is_reverse(), which is never correct in this case (it should be
called conn_to_reverse() because it says the conn must be reversed
and has not yet been), so this extra test doesn't protect against the
NULL check, and connections are closed after each stream is terminated
(if there is no other stream left).

After a long analysis with Amaury and Olivier, it was concluded that:
  - the h2c_is_dead() addition is finally not the best solution and
    could be refined, however in the current state it's a bit tricky.
  - the conn->owner test in h2c_is_dead() is no longer relevant,
    probably since 2.4 when connections were stored using hash_nodes
    in the servers and would no longer depend on a session, so that
    test should be removed.
  - the test conn_is_reverse() on the same line, that was added to
    ignore the former for RHTTP, and which doesn't properly work either
    should be removed as well.

Some further cleanups should be performed to clarify this situation.

This patch implements the points above, and it should be backported
wherever commit 59c599f3f0 was backported.
2026-04-16 18:27:15 +02:00
.github CI: Build dev/haring/ as part of contrib.yml 2026-04-14 11:16:17 +02:00
addons MINOR: ot: renamed the variable dbg_indent_level to flt_ot_dbg_indent_level 2026-04-13 09:23:30 +02:00
admin CLEANUP: fix typos and spelling in comments and documentation 2026-03-30 09:24:19 +02:00
dev CLEANUP: fix typos and spelling in comments and documentation 2026-03-30 09:24:19 +02:00
doc MEDIUM: threads: change the default max-threads-per-group value to 16 2026-04-16 10:48:43 +02:00
examples EXAMPLES: ssl: keylog entries are greater than 1024 2026-04-14 16:24:28 +02:00
include MEDIUM: threads: change the default max-threads-per-group value to 16 2026-04-16 10:48:43 +02:00
reg-tests REGTESTS: add QUIC test for max-total streams setting 2026-04-15 15:18:37 +02:00
scripts CI: VTest build with git clone + cache 2026-04-07 18:35:23 +02:00
src BUG/MEDIUM: mux-h2: ignore conn->owner when deciding if a connection is dead 2026-04-16 18:27:15 +02:00
tests TESTS: quic: add unit-tests for QUIC TX part 2025-09-08 14:49:03 +02:00
.cirrus.yml CI: cirrus-ci: bump FreeBSD image to 14-3 2025-10-09 14:06:48 +02:00
.gitattributes MINOR: Configure the cpp userdiff driver for *.[ch] in .gitattributes 2021-02-22 18:17:57 +01:00
.gitignore MINOR: tevt/dev: Add term_events tool 2025-01-31 10:41:50 +01:00
.mailmap DOC: update Tim's address in .mailmap 2021-09-16 09:14:14 +02:00
.travis.yml MEDIUM: mworker: remove USE_SYSTEMD requirement for -Ws 2024-11-20 12:07:38 +01:00
BRANCHES DOC: clarify the experimental status for certain features 2025-10-17 18:41:13 +02:00
BSDmakefile BUILD: makefile: commit the tiny FreeBSD makefile stub 2023-05-24 17:17:36 +02:00
CHANGELOG [RELEASE] Released version 3.4-dev9 2026-04-15 17:59:00 +02:00
CONTRIBUTING CLEANUP: assorted typo fixes in the code and comments 2025-04-02 11:12:20 +02:00
INSTALL MINOR: version: mention that it's development again 2025-11-26 16:11:47 +01:00
LICENSE LICENSE: add licence exception for OpenSSL 2012-09-07 13:52:26 +02:00
MAINTAINERS MAJOR: spoe: Let the SPOE back into the game 2024-05-22 09:04:38 +02:00
Makefile BUILD: Makefile: don't forget to also delete haterm on make clean 2026-04-14 16:48:16 +02:00
README.md DOC: remove the alpine/musl status job image 2026-04-15 11:34:17 +02:00
SUBVERS BUILD: use format tags in VERDATE and SUBVERS files 2013-12-10 11:22:49 +01:00
VERDATE [RELEASE] Released version 3.4-dev9 2026-04-15 17:59:00 +02:00
VERSION [RELEASE] Released version 3.4-dev9 2026-04-15 17:59:00 +02:00

HAProxy

AWS-LC Illumos NetBSD FreeBSD VTest

HAProxy logo

HAProxy is a free, very fast and reliable reverse-proxy offering high availability, load balancing, and proxying for TCP and HTTP-based applications.

Installation

The INSTALL file describes how to build HAProxy. A list of packages is also available on the wiki.

Getting help

The discourse and the mailing-list are available for questions or configuration assistance. You can also use the slack or IRC channel. Please don't use the issue tracker for these.

The issue tracker is only for bug reports or feature requests.

Documentation

The HAProxy documentation has been split into a number of different files for ease of use. It is available in text format as well as HTML. The wiki is also meant to replace the old architecture guide.

Please refer to the following files depending on what you're looking for:

  • INSTALL for instructions on how to build and install HAProxy
  • BRANCHES to understand the project's life cycle and what version to use
  • LICENSE for the project's license
  • CONTRIBUTING for the process to follow to submit contributions

The more detailed documentation is located into the doc/ directory:

License

HAProxy is licensed under GPL 2 or any later version, the headers under LGPL 2.1. See the LICENSE file for a more detailed explanation.