]> git.ipfire.org Git - thirdparty/haproxy.git/log
thirdparty/haproxy.git
6 months agoBUG/MINOR: quic: fix BBB max bandwidth oscillation issue.
Frederic Lecaille [Thu, 12 Dec 2024 10:08:26 +0000 (11:08 +0100)] 
BUG/MINOR: quic: fix BBB max bandwidth oscillation issue.

Remove the code in relation with BBR.ack_phase as per this commit:
https://github.com/ietf-wg-ccwg/draft-ietf-ccwg-bbr/pull/5/commits/ee98c12ad6f0e93153656218a7df1b1ef92618d7

I do now kwow at this time why such a request was pushed on GH for the BBR v3 draft
pseudo-code. That said, the use of such an ack phase seemed confusing, adding much
more information about a BBR flow state than needed. Indeed, the ack phase
state is modified several times in the BBR draft pseudo-code but only used to
decide if the max bandwidth filter virtual clock had to be incremented by
BBRAdvanceMaxBwFilter().

In addition to this, when discussing about haproxy BBR implementation with
Neal Cardwell on the BBR development google group about an oscillation issue
of the max bandwidth (BBR.max_bw), I concluded that this was due to the fact
that its filter virutal clock was too often update, due to the ack phase wich
was stalled in BBR_ACK_PHASE_ACKS_PROBE_STOPPING state for too long. This is
where Neal asked me to test the aforementioned commit. This definitively
makes the max bandwidth (BBR.max_bw) oscillation issue disappear.

Another solution would have been to add a new ack phase enum afer
BBR_ACK_PHASE_ACKS_PROBE_STOPPING. BBR_ACK_PHASE_ACKS_PROBE_STOPPED
would have been a good candidate.

Remove the code in relation with BBR.ack_phase.

Must be backported to 3.1.

6 months agoBUG/MINOR: quic: wrong logical statement in in_recovery_period() (BBR)
Frederic Lecaille [Thu, 12 Dec 2024 09:45:26 +0000 (10:45 +0100)] 
BUG/MINOR: quic: wrong logical statement in in_recovery_period() (BBR)

A && logical operator was badly replaced by a || in this function which decides
if BBR is in a recovery period.

Must be backported to 3.1.

6 months agoMINOR: window_filter: rely on the time to update the filter samples (QUIC/BBR)
Frederic Lecaille [Thu, 12 Dec 2024 08:59:35 +0000 (09:59 +0100)] 
MINOR: window_filter: rely on the time to update the filter samples (QUIC/BBR)

The windowed filters are used only the BBR implementation for QUIC to filter
the maximum bandwidth samples for its estimation over a virtual time interval
tracked by counting the cyclical progression through ProbeBW cycles. ngtcp2
and quiche use such windowed filters in their BBR implementation. But in a
slightly different way. When updating the 2nd or 3rd filter samples, this
is done based on their values in place of the time they have been sampled.
It seems more logical to rely on the sample timestamps even if this has no
implication because when a sample is updated using another sample because it
has the same value, they have both the same timestamps!

This patch modifies two statements which compare two consecutive filter samples
based on their values (smp[]->v) by statements which compare them based on the
virtual time they have been sampled (smp[]->t). This fully complies which the
code used by the Linux kernel in lib/win_minmax.c.

Alo take the opportunity of this patch to shorten some statements using <smp>
local variable value to update smp[2] sample in place of initializing its two
members with the <smp> member values.

This patch SHOULD be easily backported to 3.1 where BBR was first implemented.

7 months agoCI: github: let's add an AWS-LC-FIPS job
William Lallemand [Thu, 12 Dec 2024 15:28:32 +0000 (16:28 +0100)] 
CI: github: let's add an AWS-LC-FIPS job

Add a job which does exactly the same as the aws-lc.yml job, but using
the AWS-LC-FIPS build.

7 months agoMEDIUM: ssl: rename 'OpenSSL' by 'SSL library' in haproxy -vv
William Lallemand [Thu, 12 Dec 2024 14:39:47 +0000 (15:39 +0100)] 
MEDIUM: ssl: rename 'OpenSSL' by 'SSL library' in haproxy -vv

It's been some time since we are compatible with multiple SSL libraries,
let's rename the "OpenSSL library" strings in "SSL library" strings in
haproxy -vv, in order to be more generic.

7 months agoMINOR: ssl: add "FIPS" details in haproxy -vv
William Lallemand [Thu, 12 Dec 2024 10:37:42 +0000 (11:37 +0100)] 
MINOR: ssl: add "FIPS" details in haproxy -vv

Add the FIPS mode in haproxy -vv, it need to be activated on the system
with openssl.cnf or by compiling the SSL library with the right options.

Can't work with OpenSSL >= 3.0 because fips a "provider" to load, works
with AWS-LC, WolfSSL and OpenSSL 1.1.1.

7 months agoCI: scripts: add support for AWS-LC-FIPS in build-ssl.sh
William Lallemand [Tue, 10 Dec 2024 13:25:39 +0000 (14:25 +0100)] 
CI: scripts: add support for AWS-LC-FIPS in build-ssl.sh

Allow the build-ssl.sh script to build AWS-LC-FIPS.

Example:

  sudo AWS_LC_FIPS_VERSION=3.0.0 BUILDSSL_DESTDIR=/opt/awslc-fips-3.0.0/ ./scripts/build-ssl.sh

7 months agoMINOR: stats: use stress mode to force reentrant dumps
Amaury Denoyelle [Thu, 7 Nov 2024 16:15:47 +0000 (17:15 +0100)] 
MINOR: stats: use stress mode to force reentrant dumps

Provide alternative code during stats dump when stress mode is active.
The objective is to force the applet to yield on every output line. This
allows to easily test reentrant code paths, in particular while adding
and removing server instances.

To support this, output is interrupted every time the output buffer (or
its equivalent) is not empty. Use COND_STRESS() macro to provide default
and stress alternative conditions.

7 months agoMINOR: applet: define applet_putchk_stress() alternative
Amaury Denoyelle [Thu, 7 Nov 2024 16:15:15 +0000 (17:15 +0100)] 
MINOR: applet: define applet_putchk_stress() alternative

Previous patch introduced stress mode to be able to easily test
alternative code paths.

The first point would be to force interruption of stats dump on every
line and check reentrant patchs, in particular while adding and removing
servers instances.

The purpose of this patch is to be able to use applet_putchk_stress()
during stats dump while not impacting other applets. To support this,
extract applet_putchk() into an internal _applet_putchk() which have a
new argument stress. Define two helpers applet_putchk() and
applet_putchk_stress(), the latter to set the stress argument to true.

For the moment, applet_putchk_stress() is not used. This will be the
subject of the next patch.

7 months agoMINOR: build: define DEBUG_STRESS
Amaury Denoyelle [Thu, 7 Nov 2024 15:37:10 +0000 (16:37 +0100)] 
MINOR: build: define DEBUG_STRESS

Define a new build mode DEBUG_STRESS. This will be used to stress some
code parts which cannot be reproduce easily with an alternative
suboptimal code.

First, a global <mode_stress> is set either to 1 or 0 depending on
DEBUG_STRESS compilation. A new global keyword "stress-level" is also
defined. It allows to specify a level from 0 to 9, to increase the
stress incurred on the code.

Helper macro STRESS_RUN* are defined for each stress level. This allows
to easily specify an instruction in default execution and a stress
counterpart if running on the corresponding stress level.

7 months ago[RELEASE] Released version 3.2-dev1 v3.2-dev1
Willy Tarreau [Wed, 11 Dec 2024 13:17:46 +0000 (14:17 +0100)] 
[RELEASE] Released version 3.2-dev1

Released version 3.2-dev1 with the following main changes :
    - MINOR: pattern: split pat_ref_set()
    - MINOR: pattern: add pat_ref_gen_set() function
    - MINOR: pattern: add pat_ref_gen_find_elt() function
    - MINOR: pattern: add pat_ref_gen_delete() function
    - MEDIUM: pattern: consider gen_id in pat_ref_set_from_node()
    - MEDIUM: pattern: always consider gen_id for pat_ref lookup operations
    - MINOR: version: this is development again (3.2)
    - DEV: patchbot: prepare for new version 3.2-dev
    - BUG/MEDIUM: sock: Remove FD_POLL_HUP during connect() if FD_POLL_ERR is not set
    - MINOR: proxy: Add support of 421-Misdirected-Request in retry-on status
    - BUG/MINOR: log: fix lf_text() behavior with empty string
    - MINOR: log: always consider "+M" option in lf_text_len()
    - BUG/MINOR: improve BBR throughput on very fast links
    - MINOR: event_hdl: add PAT_REF events
    - MINOR: pattern: publish event_hdl events on pat_ref updates
    - MINOR: hlua: add patref class
    - MINOR: hlua: add core.get_patref method
    - MINOR: hlua_fcn: implement index and pair metamethods for patref class
    - MINOR: hlua_fcn: wrap pat_ref struct for patref class
    - MINOR: pattern: add pat_ref_may_commit() helper function
    - MINOR: hlua_fcn: add Patref:commit() method
    - MINOR: hlua_fcn: add Patref:prepare() method
    - MINOR: hlua_fcn: add Patref:purge() method
    - MINOR: hlua_fcn: add Patref:giveup()
    - MINOR: hlua_fcn: add Patref:add()
    - MINOR: hlua_fcn: add Patref:del()
    - MINOR: hlua_fcn: add Patref:set()
    - MINOR: hlua_fcn: add Patref:add_bulk()
    - MINOR: hlua_fcn: add Patref:event_sub()
    - DOC: lua: prefer Patref:{set,add}() over legacy methods for acl and maps
    - BUG/MINOR: hlua_fcn: fix Patref:set() force parameter
    - BUG/MEDIUM: event_hdl: fix uninitialized value in async mode when no data is provided
    - BUG/MEDIUM: quic: prevent stream freeze on pacing
    - BUG/MEDIUM: http-ana: Reset request flag about data sent to perform a L7 retry
    - BUG/MINOR: h1-htx: Use default reason if not set when formatting the response
    - BUILD: quic: fix a build error about an non initialized timestamp
    - CI: github: allow coredumps on aws-lc and wolfssl jobs
    - BUG/MINOR: listener: fix potential null pointer dereference in listener_release()
    - MINOR: hlua: fix ambiguous hlua usage in hlua_filter_delete()
    - BUG/MINOR: signal: register default handler for SIGINT in signal_init()
    - BUG/MINOR: startup: close pidfd and free global.pidfile in handle_pidfile()
    - BUG/MINOR: startup: fix pidfile creation
    - MINOR: tools: add a new macro DEFVAL() to provide a default argument
    - MINOR: tasklet: set TASK_WOKEN_OTHER on tasklets by default
    - BUG/MINOR: quic: fix bbr_inflight() calls with wrong gain value
    - BUG/MEDIUM: init: make sure only daemonized processes change their session
    - BUG/MINOR: init: do not call fork_poller() for non-forked processes
    - BUG/MEDIUM: mux-quic: remove pacing status when everything is sent
    - BUG/MINOR: quic: remove startup alert if conn socket-owner unsupported
    - BUG/MINOR: quic: remove startup alert if GSO unsupported
    - MINOR: stktable: implement "recv-only" table option
    - CLEANUP: stktable: replace nopurge attribute with flag
    - CLEANUP: stktable: add some stktable flags polishing
    - BUG/MEDIUM: mux-h2: make sure not to touch dummy streams when sending WU
    - MINOR: mux-quic: clean up zero-copy done_ff callback
    - BUG/MINOR: config: Fix parsing of accept-invalid-http-{request,response}
    - BUG/MINOR: mworker: don't save program PIDs in oldpids
    - BUG/MINOR: mworker: fix -D -W -sf/-st modes
    - BUG/MINOR: startup: fix error path for master, if can't open pidfile
    - CLEANUP: startup: make if condition to kill old pids more readable
    - DOC: config: fix confusing init-state examples
    - MINOR: mux-h1: use explicit __objt_server on idle conn reinsert
    - MINOR: mux-h2: use explicit __objt_server on idle conn reinsert
    - MINOR: mux-spop: use explicit __objt_server on idle conn reinsert
    - MINOR: mux-fcgi: use explicit __objt_server on idle conn reinsert
    - MINOR: quic: convert startup check in a freestanding function
    - MINOR: quic: split startup check function
    - MINOR: quic: implement build options report
    - BUG/MINOR: debug: COUNT_IF() should return true/false
    - MINOR: mux-h2/traces: add a missing trace on negative initial window size
    - CLEANUP: mux-h2/traces: reword certain ambiguous traces
    - MINOR: mux-h2/glitches: add a description to the H2 glitches
    - BUG/MINOR: mux-h2: fix expression when detecting excess of CONTINUATION frames
    - BUILD: debug: fix build issues in COUNT_IF() with -Wunused-value
    - MINOR: tools: make fddebug() automatically emit the location
    - MINOR: ssl: add notBefore and notAfter utility functions
    - MEDIUM: ssl/cli: "show ssl sni" list the loaded SNI in frontends
    - BUG/MEDIUM: startup: don't daemonize if started with -c
    - BUG/MEDIUM: startup: report status if daemonized process fails
    - BUG/MEDIUM: mworker: report status, if daemonized master fails
    - BUG/MINOR: mworker: detach from tty when received READY from worker
    - BUG/MINOR: namespace: handle a possible strdup() failure
    - BUG/MINOR: ssl_crtlist: handle a possible strdup() failure
    - BUG/MINOR: resolvers: handle a possible strdup() failure
    - CI: use "/tmp" as default value for TMPDIR when searching logs
    - DOC: management: fix typos and paragraph ordering in 'show ssl sni'
    - CLEANUP: ssl: fix comment in 'show ssl sni'
    - MINOR: ssl/cli: add negative filters to "show ssl sni"
    - BUG/MINOR: stats: decrement srv refcount on stats-file release
    - MINOR: list: define a watcher type
    - BUG/MEDIUM: stats/server: use watcher to track server during stats dump
    - MINOR: server: remove prev_deleted server list
    - BUG/MINOR: http-fetch: Ignore empty argument string for query()
    - BUG/MINOR: server-state: Fix expiration date of srvrq_check tasks
    - BUG/MINOR: hlua_fcn: restore server pairs iterator pointer consistency

7 months agoBUG/MINOR: hlua_fcn: restore server pairs iterator pointer consistency
Aurelien DARRAGON [Wed, 11 Dec 2024 09:42:11 +0000 (10:42 +0100)] 
BUG/MINOR: hlua_fcn: restore server pairs iterator pointer consistency

Since 9c91b30 ("MINOR: server: remove prev_deleted server list"), hlua
server pair iterator may use and return invalid (stale) server pointer
if multiple servers were deleted between two iterations.

Indeed, the server refcount mechanism (using srv_take()) is no longer
sufficient as the prev_deleted mitigation was removed.

To ensure server pointer consistency between two yields, the new watcher
mechanism must be used (as it already the case for stats dumping).

Thus in this patch we slightly change the server iteration logic:
hlua_server_list_iterator_context struct now stores the next valid server
pointer, and a watcher is added to ensure this pointer is never stale.

Then in hlua_listable_servers_pairs_iterator(), this next pointer is used
to create the Lua server object, and the next valid pointer is obtained by
leveraging watcher_next().

No backport needed unless 9c91b30 ("MINOR: server: remove prev_deleted
server list") is. Please note that dynamic servers were not supported in
Lua prior to 2.8, so it doesn't make sense to backport this patch further
than 2.8.

7 months agoBUG/MINOR: server-state: Fix expiration date of srvrq_check tasks
Christopher Faulet [Wed, 11 Dec 2024 08:23:28 +0000 (09:23 +0100)] 
BUG/MINOR: server-state: Fix expiration date of srvrq_check tasks

"hold.timeout" was used as expiration date for srvrq_check tasks. But it is
not accurrate. The expiration date must be based on the resolution timeouts
instead (resolve and retry).

The purpose of srvrq_check task is to clean up the server resolution status
when outdated info are inherited from the state file. Using "hold.timeout"
is not accurrate here because hold timeouts concern the resolution response
items not the resolution status of servers. It may be set to a huge value or
0. The expiration date of these tasks must be based on the resolution
timeouts instead.

So now the ("timeout resolve" + resolve_retries * "timeout retry") value is
used.

This patch should fix the issue #2816. It must be backported to all stable
versions.

7 months agoBUG/MINOR: http-fetch: Ignore empty argument string for query()
Christopher Faulet [Wed, 11 Dec 2024 08:09:26 +0000 (09:09 +0100)] 
BUG/MINOR: http-fetch: Ignore empty argument string for query()

query() sample fetch function takes an optional argument string. During
configuration parsing, empty string must be ignored. It is especially
important when the sample is used with empty parenthesis. The argument is
optional and it is a list of options to configure the behavior of the sample
fetch. So it is logical to ignore empty strings.

This patch should fix the issue #2815. It must be backported to 3.1.

7 months agoMINOR: server: remove prev_deleted server list
Amaury Denoyelle [Wed, 27 Nov 2024 10:11:12 +0000 (11:11 +0100)] 
MINOR: server: remove prev_deleted server list

This patch is a direct follow-up to the previous one. Thanks to watcher
type, it is not safe to assume that servers manipulated via stats dump
were not targetted by a "delete server" CLI command. As such,
prev_deleted list server member is now unneeded. This patch thus removes
any reference to it.

7 months agoBUG/MEDIUM: stats/server: use watcher to track server during stats dump
Amaury Denoyelle [Wed, 23 Oct 2024 09:33:34 +0000 (11:33 +0200)] 
BUG/MEDIUM: stats/server: use watcher to track server during stats dump

If a server A is deleted while a stats dump is currently on it, deletion
is delayed thanks to reference counting. Server A is nonetheless removed
from the proxy list. However, this list is a single linked list. If the
next server B is deleted and freed immediately, server A would still
point to it. This problem has been solved by the prev_deleted list in
servers.

This model seems correct, but it is difficult to ensure completely its
validity. In particular, it implies when stats dump is resumed, server A
elements will be accessed despite the server being in a half-deleted
state.

Thus, it has been decided to completely ditch the refcount mechanism for
stats dump. Instead, use the watcher element to register every stats
dump currently tracking a server instance. Each time a server is deleted
on the CLI, each stats dump element which may points to it are updated
to access the next server instance, or NULL if this is the last server.
This ensures that a server which was deleted via CLI but not completely
freed is never accessed on stats dump resumption.

Currently, no race condition related to dynamic servers and stats dump
is known. However, as described above, the previous model is deemed too
fragile, as such this patch is labelled as bug-fix. It should be
backported up to 2.6, after a reasonable period of observation. It
relies on the following patch :
  MINOR: list: define a watcher type

7 months agoMINOR: list: define a watcher type
Amaury Denoyelle [Wed, 23 Oct 2024 09:31:44 +0000 (11:31 +0200)] 
MINOR: list: define a watcher type

Define a new watcher type into list module. This type is similar to bref
and can be used to register an element which is currently tracking a
dynamic target. Contrary to bref, if the target is freed, every watcher
element are updated to point to a next valid entry or NULL.

This type will simplify handling of dynamic servers deletion, in
particular while stats dump are performed.

This patch is not a bug-fix. However, it is mandatory to fix a race
condition in dynamic servers. Thus, it should be backported along the
next commit up to 2.6.

7 months agoBUG/MINOR: stats: decrement srv refcount on stats-file release
Amaury Denoyelle [Tue, 10 Dec 2024 14:57:17 +0000 (15:57 +0100)] 
BUG/MINOR: stats: decrement srv refcount on stats-file release

Servers instance may be removed at runtime. This can occurs during a
stat dump which currently references this server instance. This case is
protected by server refcount to prevent the server immediate release.

CLI output may be interrupted prior to stats dump completion, for
example if client CLI has been disconnected before the full response
transfer. As such, srv_drop() must be called in every stats dump release
callback.

srv_drop() was missing for stats-file dump release callback. This could
cause a race condition which would prevent a server instance to be fully
removed. Fix this by adding srv_drop() invokation into
cli_io_handler_release_dump_stat_file().

This should be backported up to 3.0.

7 months agoMINOR: ssl/cli: add negative filters to "show ssl sni"
William Lallemand [Tue, 10 Dec 2024 10:19:15 +0000 (11:19 +0100)] 
MINOR: ssl/cli: add negative filters to "show ssl sni"

The 'show ssl sni' output can be confusing when using crt-list, because
the wildcards can be completed with negative filters, and they need to
be associated to the same line.

Having a negative filter on its line alone does not make much sense,
this patch adds a new 'Negative Filter' column that show the exception
applied on a wildcard from a crt-list line.

7 months agoCLEANUP: ssl: fix comment in 'show ssl sni'
William Lallemand [Tue, 10 Dec 2024 10:17:10 +0000 (11:17 +0100)] 
CLEANUP: ssl: fix comment in 'show ssl sni'

Fix a comment in the 'show ssl sni' IO handler.

7 months agoDOC: management: fix typos and paragraph ordering in 'show ssl sni'
William Lallemand [Tue, 10 Dec 2024 09:21:47 +0000 (10:21 +0100)] 
DOC: management: fix typos and paragraph ordering in 'show ssl sni'

Fixes small typos, uppercase and paragraph ordering in the 'show ssl
sni' section.

7 months agoCI: use "/tmp" as default value for TMPDIR when searching logs
Ilia Shipitsin [Sat, 7 Dec 2024 09:01:38 +0000 (10:01 +0100)] 
CI: use "/tmp" as default value for TMPDIR when searching logs

VTest use /tmp already if not defined, let stick the behaviour for
searching logs as well

7 months agoBUG/MINOR: resolvers: handle a possible strdup() failure
Ilia Shipitsin [Tue, 3 Dec 2024 18:54:46 +0000 (19:54 +0100)] 
BUG/MINOR: resolvers: handle a possible strdup() failure

This defect was found by the coccinelle script "unchecked-strdup.cocci".
It can be backported to all supported branches.

7 months agoBUG/MINOR: ssl_crtlist: handle a possible strdup() failure
Ilia Shipitsin [Tue, 3 Dec 2024 16:13:05 +0000 (17:13 +0100)] 
BUG/MINOR: ssl_crtlist: handle a possible strdup() failure

This defect was found by the coccinelle script "unchecked-strdup.cocci".
It can be backported to all supported branches.

7 months agoBUG/MINOR: namespace: handle a possible strdup() failure
Ilia Shipitsin [Tue, 3 Dec 2024 16:10:21 +0000 (17:10 +0100)] 
BUG/MINOR: namespace: handle a possible strdup() failure

This defect was found by the coccinelle script "unchecked-strdup.cocci".
It can be backported to all supported branches.

7 months agoBUG/MINOR: mworker: detach from tty when received READY from worker
Valentine Krasnobaeva [Mon, 9 Dec 2024 19:20:40 +0000 (20:20 +0100)] 
BUG/MINOR: mworker: detach from tty when received READY from worker

Some master process' initialization steps are conditioned by receiving the
READY message from worker (pidfile creation, forwarding READY message to the
launching parent). So, master process can not do these initialization routines
before.

If the master process fails, while creating pid or forwarding the READY to the
parent in daemon mode, he exits with a proper alert message. In daemon mode we
no longer see such message, as process is already detached from the tty.

To fix this, as these alerts could be very useful, let's detach the master
process from the tty after his last initialization steps in _send_status.

7 months agoBUG/MEDIUM: mworker: report status, if daemonized master fails
Valentine Krasnobaeva [Mon, 9 Dec 2024 17:56:01 +0000 (18:56 +0100)] 
BUG/MEDIUM: mworker: report status, if daemonized master fails

As daemonization fork happens now very early and before the master-worker
fork, if master or worker processes fail during the initialization, some
critical errors can't be reported to stdout. The launching (parent) process in
such cases exits with 0. This makes an impression, that master and his worker
have successfully started at background, which really complicates the
operations.

In the previous commit a pipe was added to make daemonized child communicate
with his parent. Let's add the same logic to master-worker mode. Up to
receiving the READY message from the worker, master will "forward" it via the
pipe to the launching process. Launching process can obtain master's exit
status, if the master fails to start and nothing has been written in the pipe.

This fix should be backported only in 3.1.

7 months agoBUG/MEDIUM: startup: report status if daemonized process fails
Valentine Krasnobaeva [Mon, 9 Dec 2024 17:51:34 +0000 (18:51 +0100)] 
BUG/MEDIUM: startup: report status if daemonized process fails

Due to master-worker rework, daemonization fork happens now before parsing
and applying the configuration. This makes impossible to report correctly all
warnings and alerts to shell's stdout. Daemonzied process fails, while being
already in background, exit code reported by shell via '$?' equals to 0, as
it's the exit code of his parent.

To fix this, let's create a pipe between parent and daemonized child. The
child will send into this pipe a "READY" message, when it finishes his
initialization. The parent will wait on the "read" end of the pipe until
receiving something. If read() fails, parent obtains the status of the
exited child with waitpid(). So, the parent can correctly report the error to
the stdout and he can exit with child's exitcode.

This fix should be backported only in 3.1.

7 months agoBUG/MEDIUM: startup: don't daemonize if started with -c
Valentine Krasnobaeva [Mon, 9 Dec 2024 11:00:35 +0000 (12:00 +0100)] 
BUG/MEDIUM: startup: don't daemonize if started with -c

Due to master-worker refactoring, daemonization fork happens now very early,
before parsing and verifying the configuration. For the moment there is no
any specific syntax, which needs for the daemon mode to be really applied in
order to perform the tests.

So, it's better not to do the daemonization fork, if 'daemon' keyword is
presented in the config (or -D option), when we started with -c (MODE_CHECK).
Like this, during the config verification, the process will always stay in
foreground and all warning or errors will be delivered to the stdout.

This fix should be backported only in 3.1.

7 months agoMEDIUM: ssl/cli: "show ssl sni" list the loaded SNI in frontends
William Lallemand [Fri, 6 Dec 2024 16:44:53 +0000 (17:44 +0100)] 
MEDIUM: ssl/cli: "show ssl sni" list the loaded SNI in frontends

The "show ssl sni" command, allows one to dump the list of SNI in an
haproxy process, or a designated frontend.

It lists the SNI with the type, filename, and dates of expiration and
activation

7 months agoMINOR: ssl: add notBefore and notAfter utility functions
William Lallemand [Fri, 6 Dec 2024 16:42:19 +0000 (17:42 +0100)] 
MINOR: ssl: add notBefore and notAfter utility functions

Extracting notBefore and notAfter as a string can be bothersome,
add 2 utility functions that returns the value in a static buffer.

7 months agoMINOR: tools: make fddebug() automatically emit the location
Willy Tarreau [Mon, 9 Dec 2024 16:40:51 +0000 (17:40 +0100)] 
MINOR: tools: make fddebug() automatically emit the location

fddebug() is sometimes quite helpful, but annoying to use when following
a call path because it's a pain to always repeat the function name and
call place. Let's have it automatically prepend the function name, the
file name and the line number, and make its arguments optional, replacing
them by a simple LF when all absent. This way, simply placing:

    fddebug();

is sufficient to emit a location follocing "[%s@%s:%d]\n". This function
must not be used in production (and even call places with it shouldn't be
committed) and it should only be used by developers, so the simplest the
better.

7 months agoBUILD: debug: fix build issues in COUNT_IF() with -Wunused-value
Willy Tarreau [Mon, 9 Dec 2024 16:49:08 +0000 (17:49 +0100)] 
BUILD: debug: fix build issues in COUNT_IF() with -Wunused-value

Commit 7f64bb79fd ("BUG/MINOR: debug: COUNT_IF() should return true/false")
allowed the COUNT_IF() macro to return the evaluated value. This is handy
to place it in "if ()" conditions and count them at the same time. When
glitches are disabled, the condition is just returned as-is, but most call
places do not use the result, making some compilers complain. In addition,
while reviewing this, it was noticed that when DEBUG_STRICT=0, the macro
would still be replaced by a "do { } while (0)" statement, which not only
does not evaluate the expression, but also cannot return anything. Ditto
for COUNT_IF_HOT().

Let's make sure both are always properly evaluated now.

7 months agoBUG/MINOR: mux-h2: fix expression when detecting excess of CONTINUATION frames
Willy Tarreau [Fri, 6 Dec 2024 17:53:19 +0000 (18:53 +0100)] 
BUG/MINOR: mux-h2: fix expression when detecting excess of CONTINUATION frames

Latest commit f0eca8fe7 ("MINOR: mux-h2/glitches: add a description to
the H2 glitches") misplaced the optional glitch description field, with
it appearing at the end of the if () condition and always reporting
an excess of CONTINUATION frames from the first exceeding one.

This needs to be backported along with that commit once it gets backported.

7 months agoMINOR: mux-h2/glitches: add a description to the H2 glitches
Willy Tarreau [Fri, 6 Dec 2024 16:55:05 +0000 (17:55 +0100)] 
MINOR: mux-h2/glitches: add a description to the H2 glitches

Since we can now list them using "debug counters" and now support a
description, better add the description to all glitches. This patch may
be backported to 3.1, but before this the following patches must also
be picked:

    86823c828 MINOR: mux-h2/traces: add a missing trace on negative initial window size
    7c8e9420a CLEANUP: mux-h2/traces: reword certain ambiguous traces

7 months agoCLEANUP: mux-h2/traces: reword certain ambiguous traces
Willy Tarreau [Fri, 6 Dec 2024 17:24:38 +0000 (18:24 +0100)] 
CLEANUP: mux-h2/traces: reword certain ambiguous traces

Some h2 traces were not very clear, let's reword them a bit.

7 months agoMINOR: mux-h2/traces: add a missing trace on negative initial window size
Willy Tarreau [Fri, 6 Dec 2024 16:30:05 +0000 (17:30 +0100)] 
MINOR: mux-h2/traces: add a missing trace on negative initial window size

When a negative initial windows size is reported, we're going to close
the connection, so it's important to report a trace to explain why!
This should be backported at least to 3.1 and possibly 3.0 (adapting the
context since there's no glitches there).

7 months agoBUG/MINOR: debug: COUNT_IF() should return true/false
Willy Tarreau [Wed, 27 Nov 2024 13:24:16 +0000 (14:24 +0100)] 
BUG/MINOR: debug: COUNT_IF() should return true/false

The COUNT_IF() macro was initially meant to return true/false to be used
in if() conditions but had an extra do { } while(0) that prevents it from
doing so. Let's get rid of the do { } while(0) before the code generalizes
to too many places. There's no impact on existing code, but may have to be
backported if future fixes rely on it.

7 months agoMINOR: quic: implement build options report
Amaury Denoyelle [Thu, 5 Dec 2024 15:14:08 +0000 (16:14 +0100)] 
MINOR: quic: implement build options report

Define a new function quic_register_build_options(). Its purpose is to
register a build options string for QUIC features which is reported when
using haproxy -vv.

This will allow to easily determine if connection socket-owner mode and
GSO are supported or not. Here is the new filtered output :

$ ./haproxy -vv|grep '^QUIC:'
QUIC: connection socket-owner mode support : yes
QUIC: GSO emission support : yes

7 months agoMINOR: quic: split startup check function
Amaury Denoyelle [Thu, 5 Dec 2024 14:35:36 +0000 (15:35 +0100)] 
MINOR: quic: split startup check function

Two features are tested on startup via quic_test_socketopts() :
connection socket-owner mode support and GSO. Extract both test in their
separated functions called by quic_test_socketopts().

This patch will allow to reuse easily QUIC features detection for build
options report via haproxy -vv.

7 months agoMINOR: quic: convert startup check in a freestanding function
Amaury Denoyelle [Thu, 5 Dec 2024 14:20:14 +0000 (15:20 +0100)] 
MINOR: quic: convert startup check in a freestanding function

quic_test_socketopts() function is used to detect system support for
QUIC network stack. Previously, it relies on an already bound listener
instance, notably to ensure that two UDP sockets can be bound on the
same source address.

Improve quic_test_socketopts() to run without any listener argument. It
now automatically instantiates and manipulates two dummy sockets FDs to
check for multi-bind support. This brings two advantages :
* the function is now called via an initcall
* it will easily be reusable to implement build option description

7 months agoMINOR: mux-fcgi: use explicit __objt_server on idle conn reinsert
Amaury Denoyelle [Fri, 6 Dec 2024 16:47:12 +0000 (17:47 +0100)] 
MINOR: mux-fcgi: use explicit __objt_server on idle conn reinsert

This commit is the counterpart of the previous one for FCGI mux. It
replaces objt_server() by unsafe __objt_server(), as conn target is
guarantee to point to a valid server instance, which can then be used as
_srv_add_idle() argument.

7 months agoMINOR: mux-spop: use explicit __objt_server on idle conn reinsert
Amaury Denoyelle [Fri, 6 Dec 2024 16:46:35 +0000 (17:46 +0100)] 
MINOR: mux-spop: use explicit __objt_server on idle conn reinsert

This commit is the counterpart of the previous one for SPOP mux. It
replaces objt_server() by unsafe __objt_server(), as conn target is
guarantee to point to a valid server instance, which can then be used as
_srv_add_idle() argument.

This should fix coverity report from github issue #2811.

7 months agoMINOR: mux-h2: use explicit __objt_server on idle conn reinsert
Amaury Denoyelle [Fri, 6 Dec 2024 16:44:26 +0000 (17:44 +0100)] 
MINOR: mux-h2: use explicit __objt_server on idle conn reinsert

This commit is the counterpart of the previous one for H2 mux. It
replaces objt_server() by unsafe __objt_server(), as conn target is
guarantee to point to a valid server instance, which can then be used as
_srv_add_idle() argument.

7 months agoMINOR: mux-h1: use explicit __objt_server on idle conn reinsert
Amaury Denoyelle [Fri, 6 Dec 2024 15:47:53 +0000 (16:47 +0100)] 
MINOR: mux-h1: use explicit __objt_server on idle conn reinsert

When dealing with a backend connection, H1 mux IO handler must reinsert
it in its idle list pool if it was extracted from it at the beginning.
This is the case if conn_in_list is true.

On reinsert, idle list pool is retrieved via the server instance
accessible from <conn.target>. Replace objt_server usage with
__objt_server as an idle connection is always attached to a server. This
ensures that there is no issue when using _srv_add_idle() then.

This should fix coverity report from github issue #2810.

7 months agoDOC: config: fix confusing init-state examples
Aurelien DARRAGON [Fri, 6 Dec 2024 11:04:11 +0000 (12:04 +0100)] 
DOC: config: fix confusing init-state examples

in 50322dff ("MEDIUM: server: add init-state"), some examples on how to
use init-state server keyword were added alongside with the keyword
documentation.

However, as reported by Nick Ramirez, there was an error because the
example that stated that haproxy will pass the traffic to the server after
3 successful health checks used the "init-state down" instead of the
"init-state fully-down". Thus the behavior wouldn't match what the
comment said (only 1 successful health check was required).

Here we fix the example in itself to match with the comment. Also the
following example ("# or") was also affected, but it is kind of
redundant as the main purpose of the examples are to illustrate the
feature in itself and not how to use server-template directive, so we
remove it.

This should be backported in 3.1 with 50322dff

7 months agoCLEANUP: startup: make if condition to kill old pids more readable
Valentine Krasnobaeva [Tue, 3 Dec 2024 20:13:29 +0000 (21:13 +0100)] 
CLEANUP: startup: make if condition to kill old pids more readable

Update comment and condition. nb_oldpids it's not a pointer, but a signed int,
which keeps the max number of elements in oldpids array. So, it's a good
practice to check, if it's strictly positive here.

7 months agoBUG/MINOR: startup: fix error path for master, if can't open pidfile
Valentine Krasnobaeva [Tue, 3 Dec 2024 20:33:55 +0000 (21:33 +0100)] 
BUG/MINOR: startup: fix error path for master, if can't open pidfile

If master process can't open a pidfile, there is no sense to send SIGTTIN to
oldpids, as it will exit. So, old workers will terminate as well. It's better
to send the last alert to the log about unrecoverable error, because master is
already in its polling loop.

For the standalone mode we should keep the previous logic in this case: send
SIGTTIN to old process and unbind listeners for the new one. So, it's better
to put this error path in main(), as it's done when other configuration settings
can't be applied.

This patch should be backported only in 3.1.

7 months agoBUG/MINOR: mworker: fix -D -W -sf/-st modes
Valentine Krasnobaeva [Tue, 3 Dec 2024 20:13:47 +0000 (21:13 +0100)] 
BUG/MINOR: mworker: fix -D -W -sf/-st modes

When a new master process is launched like below:

./haproxy -W -D -p ha.pid -sf $(cat ha.pid)...

The old master process and its workers do not stop. Since the master-worker
refactoring, the code, which sends USR1/TERM to old pids from -sf, is called
only for the standalone mode. In master-worker mode we should receive the READY
message from the newly forked worker at first, in order to be able to terminate
the previous master.

So, to fix this, let's terminate the previous master in _send_status(), where
we parse the READY message from the newly forked worker. And let's continue to
use oldpids array, as it was in 3.0, in order to stop the workers, launched
before the reload.

This patch should be backported only in 3.1.

7 months agoBUG/MINOR: mworker: don't save program PIDs in oldpids
Valentine Krasnobaeva [Thu, 5 Dec 2024 15:00:12 +0000 (16:00 +0100)] 
BUG/MINOR: mworker: don't save program PIDs in oldpids

After reload, previously launched programs are stopped explicitly in
mworker_ext_launch_all(). So, there is no longer need to save their PIDs in
oldpids array before the master reexec().

This also prepares the fix of "-D -W -sf/-st" modes, as we will need to
loop over this array in the master process context, in order to stop the
previous master, when the new one is ready.

This patch should be backported only in 3.1.

7 months agoBUG/MINOR: config: Fix parsing of accept-invalid-http-{request,response}
Christopher Faulet [Wed, 4 Dec 2024 09:47:35 +0000 (10:47 +0100)] 
BUG/MINOR: config: Fix parsing of accept-invalid-http-{request,response}

These options are now deprectated, but the proxy capabilities are not
properly checked during the configuration parsing leading to always ignore
these options. This is now fixed by checking the frontend capability for
"accept-invalid-http-request" option and the backend capability for
"accept-invalid-http-response" option.

In addition, the messages about the deprecation of these options are now
emitted with ha_warning() instead of ha_alert() because they are only
warnings and not errors.

This patch should fix the issue #2806. It must be backported to 3.1.

7 months agoMINOR: mux-quic: clean up zero-copy done_ff callback
Amaury Denoyelle [Mon, 2 Dec 2024 15:24:45 +0000 (16:24 +0100)] 
MINOR: mux-quic: clean up zero-copy done_ff callback

Recently, an issue was found with QUIC zero-copy forwarding on 3.0
version. A desynchronization could occur internally in QCS Tx bytes
counters which would cause a BUG_ON() crash on qcs_destroy() when the
stream is detached.

It was silently fixed in version 3.1 by the following patch. As it was
considered as an optimization, it was not scheduled yet for backport.

  6697e87ae5e1f569dc87cf690b5ecfc049c4aab0
  MINOR: mux-quic: Don't send an emtpy H3 DATA frame during zero-copy forwarding

This mistake has been caused due to some counter-intuitive manipulation
in QUIC zero-copy implementation. Try to streamline this in QUIC MUX
done_ff callback and its application protocol counterpart. Especially
for values exchanged between MUX and application on one side, and MUX
and stconn layer as done_fastfwd return value.

First, application done_ff callback now returns the length of the wholly
encoded frame. For HTTP/3, it means header length + payload length h3
frame. This value can then be reused as qcc_send_stream() argument to
increase QCS Tx soft offset.

As previously, special care has been taken to ensure that QUIC MUX
done_ff only return the transferred data bytes. Thus, any extra offset
for HTTP/3 header is properly excluded. This is mandatory for stconn
layer to consider the transfer has completed.

Secondly, remove duplicated code in application done_ff to reset iobuf
info. This is now factorize in QUIC MUX done_ff itself.

This patch is related to github issue #2678.

7 months agoBUG/MEDIUM: mux-h2: make sure not to touch dummy streams when sending WU
Willy Tarreau [Thu, 5 Dec 2024 14:18:38 +0000 (15:18 +0100)] 
BUG/MEDIUM: mux-h2: make sure not to touch dummy streams when sending WU

Since commit 1cc851d9f2 ("MEDIUM: mux-h2: start to update stream when
sending WU") we started storing stream offsets in the h2s struct. These
offsets are updated at a few points, where it's safe to write to the
stream, and in h2c_send_strm_wu(), where the h2s->h2c was not performed.

Due to this, nothing protects the h2s from being updated when sending a
WU for a closed stream, which might only happen when acknowledging a
frame after resetting that stream, which is quite unlikely. In any case
if this happens, it will crash as in issue #2793 since the closed streams
are purposely read-only to catch such bugs.

The fix is trivial, just check h2s->h2c before deciding to update the
stream.

Thanks to @Wahnes for reporting this, and Christopher for spotting the
cause. This needs to be backported to 3.1 only.

7 months agoCLEANUP: stktable: add some stktable flags polishing
Aurelien DARRAGON [Thu, 5 Dec 2024 12:09:52 +0000 (13:09 +0100)] 
CLEANUP: stktable: add some stktable flags polishing

Better late than never, commit 1f73d35 ("MINOR: stktable: implement
"recv-only" table option") implemented stktable flags and initial
definitions, but it lacks some comments plus the flag is stored as
16bits but the SKT_FL_ definition width allows for only 8bits so
it is a bit confusing, let's fix that

7 months agoCLEANUP: stktable: replace nopurge attribute with flag
Aurelien DARRAGON [Thu, 5 Dec 2024 11:02:38 +0000 (12:02 +0100)] 
CLEANUP: stktable: replace nopurge attribute with flag

Thanks to previous commit stktable struct now have a "flags" struct member

Let's take this opportunity to remove the isolated "nopurge" attribute in
stktable struct and rely on a flag named STK_FL_NOPURGE instead.

This helps to better organize stktable struct members.

7 months agoMINOR: stktable: implement "recv-only" table option
Aurelien DARRAGON [Thu, 5 Dec 2024 09:28:50 +0000 (10:28 +0100)] 
MINOR: stktable: implement "recv-only" table option

When "recv-only" keyword is added on a stick table declaration (in peers
or proxy section), haproxy considers that the table is only used for
data retrieval from a remote location and not used to perform local
updates. As such, it enables the retrieval of local-only values such
as conn_cur that are ignored by default. This can be useful in some
contexts where we want to know about local-values such are conn_cur
from a remote peer.

To do this, add stktable struct flags  which default to NONE and enable
the RECV_ONLY flag on the table then "recv-only" keyword is found in the
table declaration. Then, when in peer_treat_updatemsg(), when handling
table updates, don't ignore data updates for local-only values if the flag
is set.

7 months agoBUG/MINOR: quic: remove startup alert if GSO unsupported
Amaury Denoyelle [Wed, 4 Dec 2024 15:25:53 +0000 (16:25 +0100)] 
BUG/MINOR: quic: remove startup alert if GSO unsupported

This patch is similar to the previous one, but for GSO support. Remove
alert level message to a diag report only visible with argument -dD.

This must be backported up to 3.1.

7 months agoBUG/MINOR: quic: remove startup alert if conn socket-owner unsupported
Amaury Denoyelle [Wed, 4 Dec 2024 15:25:03 +0000 (16:25 +0100)] 
BUG/MINOR: quic: remove startup alert if conn socket-owner unsupported

QUIC relies on several advanced network API features from the kernel to
perform optimally. Checks are performed during startup to ensure that
these features are supported. A fallback is automatically performed for
every incompatible feature.

Besides the automatic fallback mechanism, a message is also reported to
the user at the same time. Previously, alert level was used, but it is
incorrect as it is reserved for unrecoverable errors which should
prevent haproxy to start. Warning level could be used, but this can
annoy users running with zero-warning mode.

This patch removes the alert message when 'socket-owner connection' mode
cannot be activated. Convert the message to a diag level. This allows
users to start without forcing configuration modification to hide a
warning. Besides, several feature fallback such as the polling mechanism
does not emit any warning either, so it's better to adopt a similar
behavior for QUIC features.

This must be backported up to 2.8.

7 months agoBUG/MEDIUM: mux-quic: remove pacing status when everything is sent
Amaury Denoyelle [Thu, 28 Nov 2024 10:27:15 +0000 (11:27 +0100)] 
BUG/MEDIUM: mux-quic: remove pacing status when everything is sent

TASK_F_USR1 is used by MUX tasklet when emission has been interrupted
due to pacing. When the tasklet runs again, only qcc_purge_sending()
will be called as an optimization.

Pacing status is only removed via qcc_wakeup(). Until then, TASK_F_USR1
is not cleared. This causes an issue after emission with pacing
completion if the MUX tasklet is woken up for a recv subscribe, as
qcc_wakeup() is not used by quic-conn layer. The tasklet will
incorrectly run only for pacing emission, without handling reception
process. Worst, a crash will occur if QCC tx frames list is empty, due
to a BUG_ON() in qcc_purge_sending().

Recv subscribe is only used for 0-RTT, when QUIC MUX is instantiated
before quic-conn handshake completion. Thus, this bug can only be
reproduced with 0-rtt. Furthermore, MUX must already have emitted at
least a few response bytes with pacing, before QUIC handshake
completion. It cannot easily be reproduced, at least with CLI clients
where the handshake is always already completed before MUX exchanges.

To fix this, remove TASK_F_USR1 when pacing emission has been completed.
At least, this prevents BUG_ON() on qcc_purge_sending() as it won't be
called with an empty QCC Tx frame list anymore. However, this bug has
revealed that MUX tasklet architecture is not suitable when both
handling reception and emission part. This will be improved in a future
serie of patches.

This should fix github issue #2796.

This must be backported up to 3.1.

7 months agoBUG/MINOR: init: do not call fork_poller() for non-forked processes
Willy Tarreau [Wed, 4 Dec 2024 14:58:49 +0000 (15:58 +0100)] 
BUG/MINOR: init: do not call fork_poller() for non-forked processes

In 3.1-dev10, commit 8dd4efe42f ("MAJOR: mworker: move master-worker
fork in init()") made the fork_poller() code unconditional, while it
is only desirable for processes that have been forked from a parent
(standalone daemon mode) or from a master (master-worker mode). The
call can be expensive in some cases as it will create a new poller,
scan and try to migrate to it all existing FDs till the highest known
one. With very high numbers of FDs, this can take several seconds to
start.

This should be backported to 3.1.

7 months agoBUG/MEDIUM: init: make sure only daemonized processes change their session
Willy Tarreau [Wed, 4 Dec 2024 07:26:24 +0000 (08:26 +0100)] 
BUG/MEDIUM: init: make sure only daemonized processes change their session

Commit 8dd4efe42f ("MAJOR: mworker: move master-worker fork in init()")
introduced some sensitive changes to the startup code (which was
expected), and one sensitive change is that the second call to setsid()
was accidentally made unconditional. As such it even applies to foreground
processes, resulting in foreground processes being detached from the
terminal and no longer responding to Ctrl-C nor Ctrl-Z. An example of
this simply consists in start haproxy -db under sudo. Then a new shell
is required to stop it.

This patch removes this second setsid(), as it is already done in
apply_daemon_mode().

This must be backported to 3.1.

7 months agoBUG/MINOR: quic: fix bbr_inflight() calls with wrong gain value
Frederic Lecaille [Wed, 4 Dec 2024 17:47:15 +0000 (18:47 +0100)] 
BUG/MINOR: quic: fix bbr_inflight() calls with wrong gain value

This patch fixes two wrong calls to bbr_inflight().

bbr_target_inflight() aim is to compute the number of bytes BBR has to put on
the network as bytes in flight (sent but not acked bytes). It must call
bbr_inflight() with the current window gain value (in place of a wrong fixed 100
gain value here, in percents).

bbr_is_time_to_cruise() also called bbr_inflight() with a wrong gain value
as parameter due to a confusion between the value mentioned by the RFC (1
meaning 100% of the current window) and our implementation which needs value in
percents (so 100 in place of 1 here). Note that bbr_is_time_to_cruise() aim is to
make BBR the decision to leave the probing_bw down state. The bug had as side
effect to make BBR stay in this state during too long periods of time during
which the bottleneck bandwidth is decreasing, leading to big oscillations
between the mininum and maximum bottleneck bandwidth estimations.

This patch must be backported to 3.1 where BBR was first implemented.

7 months agoMINOR: tasklet: set TASK_WOKEN_OTHER on tasklets by default
Willy Tarreau [Thu, 28 Nov 2024 18:42:22 +0000 (19:42 +0100)] 
MINOR: tasklet: set TASK_WOKEN_OTHER on tasklets by default

Now when tasklets are woken up via tasklet_wakeup(), tasklet_wakeup_on()
or tasklet_wakeup_after(), either the optional wakeup flags will be used,
or TASK_WOKEN_OTHER will be used.

This allows tasklet handlers waking up for any given cause to notice
whether or not they were also woken for another reason. For example, a
mux handler could skip heavy parts when seeing that TASK_WOKEN_OTHER is
absent, proving that no standard tasklet_wakeup() was done, for example
in response to a subscribe().

The benefit of the TASK_WOKEN_* flags is that they're purged during the
wakeup, and that they're easy to check for using TASK_WOKEN_ANY.
TASK_F_UEVT1 and TASK_F_UEVT2 are also usable for private use (e.g. wakeup
from a stream to a connection inside a mux).

Probably that in the future, code dealing with subscribe events should
start to place TASK_WOKEN_IO like is done for upper layers.

7 months agoMINOR: tools: add a new macro DEFVAL() to provide a default argument
Willy Tarreau [Thu, 28 Nov 2024 14:11:46 +0000 (15:11 +0100)] 
MINOR: tools: add a new macro DEFVAL() to provide a default argument

This is like DEFZERO and DEFNULL, but this one allows to specify the
default value to be used as the first argument.

7 months agoBUG/MINOR: startup: fix pidfile creation
Valentine Krasnobaeva [Mon, 2 Dec 2024 15:05:16 +0000 (16:05 +0100)] 
BUG/MINOR: startup: fix pidfile creation

Pidfile should be created at the latest initialization stage, when we are
sure, that process is able to start successfully, otherwise PID value, written
in this file is no longer valid.

So, for the standalone mode, let's move the block, which opens the pidfile and
let's put it just before applying "chroot". In master-worker mode, master
doesn't perform chroot. So it creates the pidfile, only when the "READY"
message from the newly forked worker is received.

This should be backported only in 3.1

7 months agoBUG/MINOR: startup: close pidfd and free global.pidfile in handle_pidfile()
Valentine Krasnobaeva [Mon, 2 Dec 2024 15:04:56 +0000 (16:04 +0100)] 
BUG/MINOR: startup: close pidfd and free global.pidfile in handle_pidfile()

After master-worker mode refactoring, global.pidfile is only used in
handle_pidfile(), which opens the provided file and writes the PID into it. So,
it's more appropriate to perform the close(pidfd) and ha_free(&global.pidfile)
also in this function.

This commit prepares the fix of the pidfile creation, as it's created now very
early, when we are not sure, that process has successfully started. In
master-worker mode handle_pidfile() can be called in the master process context.
So, let's make it accessible from other compilation units via global.h.

This should be backported only in 3.1.

7 months agoBUG/MINOR: signal: register default handler for SIGINT in signal_init()
Valentine Krasnobaeva [Mon, 2 Dec 2024 13:47:17 +0000 (14:47 +0100)] 
BUG/MINOR: signal: register default handler for SIGINT in signal_init()

When haproxy is launched in a background and in a subshell (see example below),
according to POSIX standard (2.11. Signals and Error Handling), it inherits
from the subshell SIG_IGN signal handler for SIGINT and SIGQUIT.

$ (./haproxy -f env4.cfg &)

So, when haproxy is lanched like this, it doesn't stop upon receiving
the SIGINT. This can be a root cause of some unexpected timeouts, when haproxy
is started under VTest, as VTest sends to the process SIGINT in order to
terminate it. To fix this, let's explicitly register the default signal
handler for the SIGINT in signal_init() initcall.

This should be backported in all stable versions.

7 months agoMINOR: hlua: fix ambiguous hlua usage in hlua_filter_delete()
Aurelien DARRAGON [Mon, 2 Dec 2024 15:44:00 +0000 (16:44 +0100)] 
MINOR: hlua: fix ambiguous hlua usage in hlua_filter_delete()

In GH #2804, @Bbulatov reported that the result of hlua_stream_ctx_get()
was used and de-referenced without checking if it's NULL in
hlua_filter_delete() while other functions used to check for NULL before
de-referencing it.

In fact hlua_stream_ctx_get() can only return NULL if
hlua_stream_ctx_prepare() failed or was not called on the current stream.

Now because of the filter's API, since hlua_filter_delete() is mapped as
detach method and hlua_filter_new() as attach method, and since
hlua_filter_new() is responsible for calling hlua_stream_ctx_prepare(),
there's no reason hlua_filter_delete() should be called if
hlua_filter_new() failed or wasn't called. Thus we can assume that hlua
can never be NULL in hlua_filter_delete(), so we add a BUG_ON() to ensure
it is always the case and remove the ambiguity.

7 months agoBUG/MINOR: listener: fix potential null pointer dereference in listener_release()
Aurelien DARRAGON [Mon, 2 Dec 2024 15:22:28 +0000 (16:22 +0100)] 
BUG/MINOR: listener: fix potential null pointer dereference in listener_release()

As reported by @Bbulatov on GH #2804, fe is found at multiple places in
listener_release(): in some places it is first checked against NULL before
being de-referenced while in some other places it is not, which is
ambiguous and could hide a bug.

In practise, fe cannot be NULL for now, but it might not be the case in
the future as we want to keep the possibility to run isolated listeners
(that is, without proxy attached).

We've already ensured this was the case with a57786e ("BUG/MINOR:
listener: null pointer dereference suspected by coverity"), but
this promise was recently broken by 65ae134 ("BUG/MINOR: listener: Wake
proxy's mngmt task up if necessary on session release").

Let's fix that by conditionning the block with an "else if" statement
instead of a regular "else".

No need for backport except if multi-connection protocols (ie: FTP) were
to be backported as well.

7 months agoCI: github: allow coredumps on aws-lc and wolfssl jobs
William Lallemand [Mon, 2 Dec 2024 14:19:41 +0000 (15:19 +0100)] 
CI: github: allow coredumps on aws-lc and wolfssl jobs

The weekly aws-lc and wolfssl jobs lacks an `ulimit -c` call in order to
allow to get the coredumps.

7 months agoBUILD: quic: fix a build error about an non initialized timestamp
Frederic Lecaille [Fri, 29 Nov 2024 13:39:48 +0000 (14:39 +0100)] 
BUILD: quic: fix a build error about an non initialized timestamp

This is to please a non identified compilers which complains about an hypothetic
<time_ns> variable which would be not initialized even if this is the case only
when it is not used.

This build issue arrived with this commit:
BUG/MINOR: improve BBR throughput on very fast links

Should be backported to 3.1 with this previous commit.

7 months agoBUG/MINOR: h1-htx: Use default reason if not set when formatting the response
Christopher Faulet [Fri, 29 Nov 2024 13:31:21 +0000 (14:31 +0100)] 
BUG/MINOR: h1-htx: Use default reason if not set when formatting the response

When the response status line is formatted before sending it to the client,
if there is no reason set, HAProxy should add one that matches the status
code, as stated in the configuration manual. However it is not performed.

It is possible to hit this bug when the response comes from a H2 server,
because there is no reason field in HTTP/2 and above.

This patch should fix the issue #2798. It should be backported to all stable
versions.

7 months agoBUG/MEDIUM: http-ana: Reset request flag about data sent to perform a L7 retry
Christopher Faulet [Thu, 28 Nov 2024 09:01:41 +0000 (10:01 +0100)] 
BUG/MEDIUM: http-ana: Reset request flag about data sent to perform a L7 retry

It is possible to loose the request after several L7 retries, leading to
crashes, because the request channel flag stating some data were sent is not
properly reset.

When a L7 retry is performed, some flags on different entities must be reset
to be sure a new connection will be properly retried, just like it was the
first one, mainly because there was no connection establishment failure. One
of them, on the request channel, is not reset. The flag stating some data
were already sent. It is annoying because this flag is used during the
connection establishment to know if an error is triggered at the connection
level or at the data level. In the last case, the error must be handled by
the HTTP response analyzer, to eventually perform another L7 retry.

Because CF_WROTE_DATA flag is not removed when a L7 retry is performed, a
subsequent connection establishment error may be handled as a L7 error while
in fact the request was never sent. It also means the request was never
saved in the buffer used to performed L7 retries. Thus, on the next L7
retires, the request is just lost. This forecefully leads to a bunch of
undefined behavior. One of them is a crash, when the request is used to
perform the load-balancing.

This patch should fix issue #2793. It must be backported to all stable
versions.

7 months agoBUG/MEDIUM: quic: prevent stream freeze on pacing
Amaury Denoyelle [Fri, 29 Nov 2024 13:28:09 +0000 (14:28 +0100)] 
BUG/MEDIUM: quic: prevent stream freeze on pacing

On snd_buf completion, QUIC MUX tasklet is scheduled if newly data has
been transferred from the stream layer. Thanks to qcc_wakeup(), pacing
status is removed from tasklet, which ensure next emission will reset Tx
frames and use the new data.

Tasklet is not scheduled if MUX is already subscribed on send due to a
previous blocking condition. This is an optimization to prevent an
unneeded IO handler execution. However, this causes a bug if an emission
is currently delayed due to pacing. As pacing status is not removed on
snd_buf, next emission process will continue emission with older data
without refreshing the newly transferred one.

This causes a transfer freeze. Unless there is some activity on the
connection, the transfer will be eventually aborted due to idle timeout.

To fix this, remove TASK_F_USR1 if tasklet wakeup is not called due to
send subscription. Note that this code is also duplicated in done_ff for
zero-copy transfer.

This must be backported up to 3.1.

7 months agoBUG/MEDIUM: event_hdl: fix uninitialized value in async mode when no data is provided
Aurelien DARRAGON [Fri, 29 Nov 2024 07:42:01 +0000 (08:42 +0100)] 
BUG/MEDIUM: event_hdl: fix uninitialized value in async mode when no data is provided

In _event_hdl_publish(), when we prepare the asynchronous event and no
<data> was provided (set to NULL), we forgot to initialize the _data
event_hdl_async_event struct member to NULL, which leads to uninitialized
reads in event_hdl_async_free_event() when the event is freed:

==1002331== Conditional jump or move depends on uninitialised value(s)
==1002331==    at 0x35D9D1: event_hdl_async_free_event (event_hdl.c:224)
==1002331==    by 0x1CC8EC: hlua_event_runner (hlua.c:9917)
==1002331==    by 0x39AD3F: run_tasks_from_lists (task.c:641)
==1002331==    by 0x39B7B4: process_runnable_tasks (task.c:883)
==1002331==    by 0x314B48: run_poll_loop (haproxy.c:2976)
==1002331==    by 0x315218: run_thread_poll_loop (haproxy.c:3190)
==1002331==    by 0x18061D: main (haproxy.c:3747)

The bug severity was set to MEDIUM because of its nature, and it's best
if this patch can be backported up to 2.8. But in practise it can only be
triggered with events that don't provide optional data: since PAT_REF
events are the first native events making use of this feature, this bug
shouldn't be an issue before f72a66e ("MINOR: pattern: publish event_hdl
events on pat_ref updates")

7 months agoBUG/MINOR: hlua_fcn: fix Patref:set() force parameter
Aurelien DARRAGON [Fri, 29 Nov 2024 06:33:51 +0000 (07:33 +0100)] 
BUG/MINOR: hlua_fcn: fix Patref:set() force parameter

Patref:set(key, val[, force]) takes optional "force" parameter (defaults
to false) to force the entry to be created if it doesn't already exist

To retrieve the value, lua_tointeger() was used in place of
lua_toboolean(), and because of that force is not enabled if "true"
is passed as parameter (only numbers were recognized) despite the
documentation mentioning that "force" is a boolean.

To fix the issue, we replace lua_tointeger by lua_toboolean.

Also, the doc was updated to rename "bool" to "boolean" for the "force"
parameter to stay consistent with historical naming in the file.

No backport needed unless 9ee37de5c ("MINOR: hlua_fcn: add Patref:set()")
is.

7 months agoDOC: lua: prefer Patref:{set,add}() over legacy methods for acl and maps
Aurelien DARRAGON [Thu, 28 Nov 2024 16:39:00 +0000 (17:39 +0100)] 
DOC: lua: prefer Patref:{set,add}() over legacy methods for acl and maps

Patref:set() can achieve the same thing as core.set_map()
Patref:add() can achieve the same thing as core.add_acl()
Patref:del() can achieve the same thing as core.del_map() and
core.del_acl()

As a bonus, Patref:{set,add} are more efficient than their core
legacy equivalent, because they don't require systematic pattern
reference lookup for each individual operation.

Let's mention that in the doc to encourage Patref methods adoption.

7 months agoMINOR: hlua_fcn: add Patref:event_sub()
Aurelien DARRAGON [Wed, 27 Nov 2024 16:06:58 +0000 (17:06 +0100)] 
MINOR: hlua_fcn: add Patref:event_sub()

Just like we did for server events, in this patch we expose the PAT_REF
event family (see "MINOR: event_hdl: add PAT_REF events") in Lua.

Unlike server events, Patref events don't provide additional event data,
and the registration can only take place from a Patref object (ie: not
globally).

Thanks to this commit it now becomes possible to trigger actions when
updates are performed on a map (or acl list) being monitor, without
the need to loop or use inefficient workarounds.

7 months agoMINOR: hlua_fcn: add Patref:add_bulk()
Aurelien DARRAGON [Tue, 26 Nov 2024 12:03:23 +0000 (13:03 +0100)] 
MINOR: hlua_fcn: add Patref:add_bulk()

There is no cli equivalent for this one. It is similar to Patref:add()
excepts thay it takes a table as parameter (for acl: table of keys, for
maps: table of keys:values). The goal is to add multiple entries at once
to limit locking time to the strict minimum. It is recommended to use this
one over Patref:add() when adding multiple entries at once.

7 months agoMINOR: hlua_fcn: add Patref:set()
Aurelien DARRAGON [Tue, 26 Nov 2024 10:26:27 +0000 (11:26 +0100)] 
MINOR: hlua_fcn: add Patref:set()

Just like "set map" on the cli, the Patref:set() method (only relevant
for maps) can be used to modify an existing entry's value in the pattern
reference pointed to by the Lua Patref object. Lookup is performed on the
key. The update will target the live pattern reference version, unless
Patref:prepare() is ongoing.

7 months agoMINOR: hlua_fcn: add Patref:del()
Aurelien DARRAGON [Tue, 26 Nov 2024 08:20:10 +0000 (09:20 +0100)] 
MINOR: hlua_fcn: add Patref:del()

Just like "del map" and "del acl" on the cli, the Patref:del() method can
be used to delete an existing entry in the pattern reference pointed to
by the Lua Patref object. The update will target the live pattern
reference version, unless Patref:prepare() is ongoing.

7 months agoMINOR: hlua_fcn: add Patref:add()
Aurelien DARRAGON [Tue, 26 Nov 2024 07:38:23 +0000 (08:38 +0100)] 
MINOR: hlua_fcn: add Patref:add()

Just like "add map" and "add acl" on the cli, the Patref:add() method can
be used to add a new entry to the pattern reference pointed to by the
Lua Patref object. The update will target the live pattern reference
version, unless Patref:prepare() is ongoing.

7 months agoMINOR: hlua_fcn: add Patref:giveup()
Aurelien DARRAGON [Mon, 25 Nov 2024 14:29:40 +0000 (15:29 +0100)] 
MINOR: hlua_fcn: add Patref:giveup()

If Patref:commit() was used and the new version (generation) isn't going
to be committed, calling Patref:giveup() will allow allocated resources
to be freed and reused. It is a good habit to call this if commit()
isn't called after a prepare().

7 months agoMINOR: hlua_fcn: add Patref:purge() method
Aurelien DARRAGON [Thu, 21 Nov 2024 15:46:26 +0000 (16:46 +0100)] 
MINOR: hlua_fcn: add Patref:purge() method

It is a special Lua Patref method: it bypasses the commit/prepare logic
and purges the whole pattern reference items pointed to by Patref Lua
object (all versions, not just the current one). It doesn't have a cli
equivalent: it leverages pat_ref_purge_range().

7 months agoMINOR: hlua_fcn: add Patref:prepare() method
Aurelien DARRAGON [Thu, 21 Nov 2024 15:32:05 +0000 (16:32 +0100)] 
MINOR: hlua_fcn: add Patref:prepare() method

Just like the "prepare map" or "prepare acl" on the cli, but for Lua:
it leverages the pattern API to create a subset (ie: a new generation id)
that will automatically be used as target for following Patref operations
(add/set/del...) until the "commit" method is invoked to atomically push
the pending updates.

7 months agoMINOR: hlua_fcn: add Patref:commit() method
Aurelien DARRAGON [Tue, 19 Nov 2024 15:40:20 +0000 (16:40 +0100)] 
MINOR: hlua_fcn: add Patref:commit() method

commit() method may be used to commit pending updates on the local patref
object:

hlua_patref flags were added:
 HLUA_PATREF_FL_GEN means the patref object has been updated
 and it is associated to a new revision (curr_gen) in order to prepare
 and commit the pending updates.

upon commit, the pattern API is leveraged with curr_gen as revision to
commit new object items. Once commit is performed, previous (pending)
revisions that are older than the committed one are cleaned up (similar
to what's done with commit on the cli). Also, Patref function APIs now
take into account curr_gen to perform lookups.

7 months agoMINOR: pattern: add pat_ref_may_commit() helper function
Aurelien DARRAGON [Thu, 21 Nov 2024 10:28:01 +0000 (11:28 +0100)] 
MINOR: pattern: add pat_ref_may_commit() helper function

pat_ref_may_commit() may be used to know if a given generation ID id still
valid, which means it may still be committed at some point. Else it means
that another pending generation ID older than the tested one was already
committed and thus other generations ID below this one are stale and must
be regenerated.

7 months agoMINOR: hlua_fcn: wrap pat_ref struct for patref class
Aurelien DARRAGON [Tue, 19 Nov 2024 14:34:11 +0000 (15:34 +0100)] 
MINOR: hlua_fcn: wrap pat_ref struct for patref class

In order to extend the patref class features, let's wrap the pat_ref struct
into hlua_patref struct. This way we may add additional data alongside the
pat_ref pointer to store additional context required for pat_ref data
manipulation from lua.

Since the wrapper (hlua_patref) is an allocated object, we declare the _gc
metamethod for patref class in order to properly cleanup resources when
they are out of scope.

7 months agoMINOR: hlua_fcn: implement index and pair metamethods for patref class
Aurelien DARRAGON [Tue, 19 Nov 2024 11:01:51 +0000 (12:01 +0100)] 
MINOR: hlua_fcn: implement index and pair metamethods for patref class

patref object may now leverage index and pair methamethods to list and
access patref elements at a specific index (=key)

Also, patref:is_map() method may be used to know if the patref stores acl
(key only) or map-style (key:value) patterns.

7 months agoMINOR: hlua: add core.get_patref method
Aurelien DARRAGON [Thu, 14 Nov 2024 16:37:54 +0000 (17:37 +0100)] 
MINOR: hlua: add core.get_patref method

core.get_patref() method may be used to get a reference to a pattern
object (pat_ref struct which is used for maps and acl storage) from
Lua by providing the reference name (filename for files, or prefix+name
for opt or virtual pattern references).

Lua documentation was updated.

7 months agoMINOR: hlua: add patref class
Aurelien DARRAGON [Thu, 7 Nov 2024 16:26:32 +0000 (17:26 +0100)] 
MINOR: hlua: add patref class

Implement patref class to expose pat_ref struct internal pattern struct
in lua. This is some prerequisite work needed to be able to manipulate
exisiting generic pattern object lists (acl/map) from Lua, because the Map
class can only be used to perform matching ops on Map files.

7 months agoMINOR: pattern: publish event_hdl events on pat_ref updates
Aurelien DARRAGON [Fri, 18 Oct 2024 16:40:41 +0000 (18:40 +0200)] 
MINOR: pattern: publish event_hdl events on pat_ref updates

Now that PAT_REF events were defined in previous commit, let's actually
publish them from pattern API where relevant. Unlike server events,
pattern reference events are only published in the pat_ref subscriber's
list on purpose, because in some setups patref updates (updates performed
on a map for instance from action or cli) are very frequent, and we don't
want to impact pattern API performance just for that.

Moreover, as the main use case is to be able to subscribe to maps updates
from Lua, allowing a per-pattern reference registration is already enough.

No additional data is provided for such events (also for performance reason)

Care was taken not to publish events when the update doesn't affect the
live subset (the one targeted by curr_gen).

7 months agoMINOR: event_hdl: add PAT_REF events
Aurelien DARRAGON [Wed, 6 Nov 2024 16:10:52 +0000 (17:10 +0100)] 
MINOR: event_hdl: add PAT_REF events

This is some prerequisite work for implementing PAT_REF events.

In this commit we define the PAT_REF event_hdl family (which gets family
slot id #2), with the following supported events:

  - EVENT_HDL_SUB_PAT_REF_ADD: element was added to the current version of
    the pattern ref
  - EVENT_HDL_SUB_PAT_REF_DEL: element was deleted from the current
    version of the pattern ref
  - EVENT_HDL_SUB_PAT_REF_SET: element was modified in the current version
    of the pattern ref
  - EVENT_HDL_SUB_PAT_REF_COMMIT: pending element(s) was/were commited in
    the current version of the pattern ref
  - EVENT_HDL_SUB_PAT_REF_CLEAR: all elements were cleared from the
    current version of the pattern ref

The goal is to be able to track a pat_ref struct in order to be notified
when it is updated. For performance reasons, events from this family won't
provide any additional info, and will only be published in the pat_ref
subscription list. Indeed, pat_ref may be updated at a relatively high
frequency (or worse, batch work), so we cannot afford doing expensive
treatment for each update.

7 months agoBUG/MINOR: improve BBR throughput on very fast links
Frederic Lecaille [Wed, 27 Nov 2024 18:39:34 +0000 (19:39 +0100)] 
BUG/MINOR: improve BBR throughput on very fast links

This patch fixes the loss of information when computing the delivery rate
(quic_cc_drs.c) on links with very low latency due to usage of 32bits
variables with the millisecond as precision.

Initialize the quic_conn task with TASK_F_WANTS_TIME flag ask it to ask
the scheduler to update the call date of this task. This allows this task to get
a nanosecond resolution on the call date calling task_mono_time(). This is enabled
only for congestion control algorithms with delivery rate estimation support
(BBR only at this time).

Store the send date with nanosecond precision of each TX packet into
->time_sent_ns new quic_tx_packet struct member to store the date a packet was
sent in nanoseconds thanks to task_mono_time().

Make use of this new timestamp by the delivery rate estimation algorithm (quic_cc_drs.c).

Rename current ->time_sent member from quic_tx_packet struct to ->time_sent_ms to
distinguish the unit used by this variable (millisecond) and update the code which
uses this variable. The logic found in quic_loss.c is not modified at all.

Must be backported to 3.1.

7 months agoMINOR: log: always consider "+M" option in lf_text_len()
Aurelien DARRAGON [Thu, 28 Nov 2024 11:58:37 +0000 (12:58 +0100)] 
MINOR: log: always consider "+M" option in lf_text_len()

Historically, when lf_text_len() or lf_text() were called with a NULL
string and "+M" option was set, "-" would be printed.

However, if the input string was simply an empty one with len > 0, then
nothing would be printed. This can happen if lf_text() is called with
an empty string because in this case len is set to size (indeed, for
performance reasons we don't pre-compute the length, we stop as soon
as we encounter a NULL-byte)

In practise, a lot of call places making use of lf_text() or lf_text_len()
try their best to avoid calling lf_text() with an empty string, and
instead explicitly call lf_text_len() with NULL as parameter to consider
the "+M" option.

But this is not enough, as shown in GH #2797, there could still be places
where lf_text() is called with an empty string. In such case, instead of
ignoring the "+M" option, let's check after _lf_text_len() if the returned
pointer differs from the original one. If both are equal, then it means
that nothing was printed (ie: result of empty string): in that case we
check the "+M" option to print "-" when possible.

While this commit seems harmless, it's probably better to avoid
backporting it since it could break existing applications relying on the
historical behavior.

7 months agoBUG/MINOR: log: fix lf_text() behavior with empty string
Aurelien DARRAGON [Thu, 28 Nov 2024 11:03:17 +0000 (12:03 +0100)] 
BUG/MINOR: log: fix lf_text() behavior with empty string

As reported by Baptiste in GH #2797, if a logformat alias leveraging
lf_text() ends up printing nothing (empty string), the whole logformat
evaluation stops, leading garbage log message.

This bug was introduced during 3.0 cycle in fcb7e4b ("MINOR: log: add
lf_rawtext{_len}() functions"). At that time I genuinely thought that
if strlcpy2() returned 0, it was due to a lack of space, actually
forgetting that the function may simply be called with an empty string.

Because of that, lf_text() would return NULL if called with an empty
string, and since all lf_*() helpers are expected to return NULL on
error, this explains why the logformat evaluation immediately stops in
this case.

To fix the issue, let's simply consider that strlcpy2() returning 0 is
not an error, like it was already the case before.

It should be backported in 3.1 and 3.0 with fcb7e4b.

7 months agoMINOR: proxy: Add support of 421-Misdirected-Request in retry-on status
Christopher Faulet [Thu, 28 Nov 2024 10:45:51 +0000 (11:45 +0100)] 
MINOR: proxy: Add support of 421-Misdirected-Request in retry-on status

The "421" status can now be specified on retry-on directives. PR_RE_* flags
were updated to remains sorted.

This patch should fix the issue #2794. It is quite simple so it may safely
be backported to 3.1 if necessary.

7 months agoBUG/MEDIUM: sock: Remove FD_POLL_HUP during connect() if FD_POLL_ERR is not set
Christopher Faulet [Wed, 27 Nov 2024 09:04:45 +0000 (10:04 +0100)] 
BUG/MEDIUM: sock: Remove FD_POLL_HUP during connect() if FD_POLL_ERR is not set

epoll_wait() may return EPOLLUP and/or EPOLLRDHUP after an asynchronous
connect(), to indicate that the peer accepted the connection then
immediately closed before epoll_wait() returned. When this happens,
sock_conn_check() is called to check whether or not the connection correctly
established, and after that the receive channel of the socket is assumed to
already be closed. This lets haproxy send the request at best (if RDHUP and
not HUP) then immediately close.

Over the last two years, there were a few reports about this spuriously
happening on connections where network captures proved that the server had
not closed at all (and sometimes even received the request and responded to
it after haproxy had closed). The logs show that a successful connection is
immediately reported on error after the request was sent. After
investigations, it appeared that a EPOLLUP, or eventually a EPOLLRDHUP, can
be reported by epool_wait() during the connect() but in sock_conn_check(),
the connect() reports a success. So the connection is validated but the HUP
is handled on the first receive and an error is reported.

The same behavior could be observed on health-checks, leading HAProxy to
consider the server as DOWN while it is not.

The only explanation at this point is that it is a kernel bug, notably
because it does not even match the documentation for connect() nor epoll. In
addition for now it was only observed with Ubuntu kernels 5.4 and 5.15 and
was never reproduced on any other one.

We have no reproducer but here is the typical strace observed:

socket(AF_INET, SOCK_STREAM, IPPROTO_IP) = 114
fcntl(114, F_SETFL, O_RDONLY|O_NONBLOCK) = 0
setsockopt(114, SOL_TCP, TCP_NODELAY, [1], 4) = 0
connect(114, {sa_family=AF_INET, sin_port=htons(11000), sin_addr=inet_addr("A.B.C.D")}, 16) = -1 EINPROGRESS (Operation now in progress)
epoll_ctl(19, EPOLL_CTL_ADD, 114, {events=EPOLLIN|EPOLLOUT|EPOLLRDHUP, data={u32=114, u64=114}}) = 0
epoll_wait(19, [{events=EPOLLIN, data={u32=15, u64=15}}, {events=EPOLLIN, data={u32=151, u64=151}}, {events=EPOLLIN, data={u32=59, u64=59}}, {events=EPOLLIN|EPOLLRDHUP, data={u32=114, u64=114}}], 200, 0) = 4
epoll_ctl(19, EPOLL_CTL_MOD, 114, {events=EPOLLOUT, data={u32=114, u64=114}}) = 0
epoll_wait(19, [{events=EPOLLOUT, data={u32=114, u64=114}}, {events=EPOLLIN, data={u32=15, u64=15}}, {events=EPOLLIN, data={u32=10, u64=10}}, {events=EPOLLIN, data={u32=165, u64=165}}], 200, 0) = 4
connect(114, {sa_family=AF_INET, sin_port=htons(11000), sin_addr=inet_addr("A.B.C.D")}, 16) = 0
sendto(114, "POST "..., 1009, MSG_DONTWAIT|MSG_NOSIGNAL, NULL, 0) = 1009
close(114)                              = 0

Some ressources about this issue:
  - https://www.spinics.net/lists/netdev/msg876470.html
  - https://github.com/haproxy/haproxy/issues/1863
  - https://github.com/haproxy/haproxy/issues/2368

So, to workaround the issue, we have decided to remove FD_POLL_HUP flag on
the FD during the connection establishement if FD_POLL_ERR is not reported
too in sock_conn_check(). This way, the call to connect() is able to
validate or reject the connection. At the end, if the HUP or RDHUP flags
were valid, either connect() would report the error itself, or the next
recv() would return 0 confirming the closure that the poller tried to
report. EPOLL_RDHUP is only an optimization to save a syscall anyway, and
this pattern is so rare that nobody will ever notice the extra call to
recv().

Please note that at least one reporter confirmed that using poll() instead
of epoll() also addressed the problem, so that can also be a temporary
workaround for those discovering the problem without the ability to
immediately upgrade.

The event is accounted via a COUNT_IF(), to be able to spot it in future
issue. Just in case.

This patch should fix the issue #1863 and #2368. It may be related
to #2751. It should be backported as far as 2.4. In 3.0 and below, the
COUNT_IF() must be removed.

7 months agoDEV: patchbot: prepare for new version 3.2-dev
Willy Tarreau [Tue, 26 Nov 2024 16:24:21 +0000 (17:24 +0100)] 
DEV: patchbot: prepare for new version 3.2-dev

The bot will now load the prompt for the upcoming 3.2 version so we have
to rename the files and update their contents to match the current version.

7 months agoMINOR: version: this is development again (3.2)
Willy Tarreau [Tue, 26 Nov 2024 16:20:40 +0000 (17:20 +0100)] 
MINOR: version: this is development again (3.2)

This basically reverts commit b629f366a7 ("MINOR: version: mention that
3.1 is stable now").