]> git.ipfire.org Git - thirdparty/haproxy.git/log
thirdparty/haproxy.git
14 months agoMINOR: stats: prepare stats-file support for values other than FN_COUNTER
Amaury Denoyelle [Mon, 29 Apr 2024 15:06:27 +0000 (17:06 +0200)] 
MINOR: stats: prepare stats-file support for values other than FN_COUNTER

Currently, only FN_COUNTER are dumped and preloaded via a stats-file.
Thus in several places we relied on the assumption that only FN_COUNTER
are valid in stats-file context.

New stats types will soon be implemented as they are also eligilible to
statistics reloading on process startup. Thus, prepare stats-file
functions to remove any FN_COUNTER restriction.

As one of this change, generate_stat_tree() now uses stcol_is_generic()
for stats name tree indexing before stats-file parsing.

Also related to stats-file parsing, individual counter preloading step
as been extracted from line parsing in a dedicated new function
load_ctr(). This will allow to extend it to support multiple mechanism
of counter preloading depending on the stats type.

14 months agoMINOR: stats: convert req_tot as generic column
Amaury Denoyelle [Mon, 29 Apr 2024 13:35:17 +0000 (15:35 +0200)] 
MINOR: stats: convert req_tot as generic column

req_tot counter is a special case as it is not managed identically
between frontend and backend side.

For the backend side, this metric is available directly into
be_counters, which allows to use a generic stat column definition.

On the frontend side however, the metric value is an aggredate of
multiple fe_counters value. This is the case since the splitting between
HTTP version introduced in the following patch :

  9969adbcdc1a79a6e8bb0a6283191d8d330a04f1
  MINOR: stats: add by HTTP version cumulated number of sessions and requests

This difference cannot be handled automatically by me_generate_field().
Add a special case in the function to produce it on frontend side
reusing the aggregated value. This not done however for stats-file as
there is no counter to preload.

14 months agoMINOR: stats: fix visual alignment for stat_cols_px definition
Amaury Denoyelle [Tue, 30 Apr 2024 09:35:47 +0000 (11:35 +0200)] 
MINOR: stats: fix visual alignment for stat_cols_px definition

Simply adjust visual alignment in definition of proxy stats columns
definition for ST_I_PX_HANAFAIL column.

14 months agoCLEANUP: ssl: move the global ocsp-update options parsing to ssl_ocsp.c
William Lallemand [Tue, 30 Apr 2024 20:20:08 +0000 (22:20 +0200)] 
CLEANUP: ssl: move the global ocsp-update options parsing to ssl_ocsp.c

Move the global tunel.ssl.ocsp-update option parsing to ssl_ocsp.c.

14 months agoCLEANUP: ssl: clean the includes in ssl_ocsp.c
William Lallemand [Thu, 2 May 2024 08:22:23 +0000 (10:22 +0200)] 
CLEANUP: ssl: clean the includes in ssl_ocsp.c

Clean the includes in ssl_ocsp.c which were copied from ssl_sock.c and
are not relevant anymore.

Also move the include in the right order.

14 months agoMINOR: capabilities: add cap_sys_admin support
Valentine Krasnobaeva [Fri, 26 Apr 2024 19:47:54 +0000 (21:47 +0200)] 
MINOR: capabilities: add cap_sys_admin support

If 'namespace' keyword is used in the backend server settings or/and in the
bind string, it means that haproxy process will call setns() to change its
default namespace to the configured one and then, it will create a
socket in this new namespace. setns() syscall requires CAP_SYS_ADMIN
capability in the process Effective set (see man 2 setns). Otherwise, the
process must be run as root.

To avoid to run haproxy as root, let's add cap_sys_admin capability in the
same way as we already added the support for some other network capabilities.

As CAP_SYS_ADMIN belongs to CAP_SYS_* capabilities type, let's add a separate
flag LSTCHK_SYSADM for it. This flag is set, if the 'namespace' keyword was
found during configuration parsing. The flag may be unset only in
prepare_caps_for_setuid() or in prepare_caps_from_permitted_set(), which
inspect process EUID/RUID and Effective and Permitted capabilities sets.

If system doesn't support Linux capabilities or 'cap_sys_admin' was not set
in 'setcap', but 'namespace' keyword is presented in the configuration, we
keep the previous strict behaviour. Process, that has changed uid to the
non-priviledged user, will terminate with alert. This alert invites the user
to recheck its configuration.

In the case, when haproxy will start and run under a non-root user and
'cap_sys_admin' is not set, but 'namespace' keyword is presented, this patch
does not change previous behaviour as well. We'll still let the user to try
its configuration, but we inform via warning, that unexpected things, like
socket creation errors, may occur.

14 months agoMINOR: sock: add EPERM case in sock_handle_system_err
Valentine Krasnobaeva [Tue, 23 Apr 2024 21:42:47 +0000 (23:42 +0200)] 
MINOR: sock: add EPERM case in sock_handle_system_err

setns() may return EPERM if thread, that tries to move into different
namespace, do not have CAP_SYS_ADMIN capability in its Effective set.
So, extending sock_handle_system_err() with this error allows to send
appropriate log message and set SF_ERR_PRXCOND (SC termination
flag in log) as stream termination error code. This error code can be
simply checked with SF_ERR_MASK at protocol layer.

14 months agoMEDIUM: proto: make common fd checks in sock_create_server_socket
Valentine Krasnobaeva [Tue, 23 Apr 2024 21:37:43 +0000 (23:37 +0200)] 
MEDIUM: proto: make common fd checks in sock_create_server_socket

quic_connect_server(), tcp_connect_server(), uxst_connect_server() duplicate
same code to check different ERRNOs, that socket() and setns() may return.
They also duplicate some runtime condition checks, applied to the obtained
server socket fd.

So, in order to remove these duplications and to improve code readability,
let's encapsulate socket() and setns() ERRNOs handling in
sock_handle_system_err(). It must be called just before fd's runtime condition
checks, which we also move in sock_create_server_socket by the same reason.

14 months agoMINOR: sock_set_mark: take sock family in account
Valentine Krasnobaeva [Thu, 25 Apr 2024 16:57:27 +0000 (18:57 +0200)] 
MINOR: sock_set_mark: take sock family in account

SO_MARK, SO_USER_COOKIE, SO_RTABLE socket options (used to set the special
mark/ID on socket, in order to perform mark-based routing) are only supported
by AF_INET sockets. So, let's check socket address family, when we enter into
this function.

14 months agoMEIDUM: unix sock: use my_socketat to create bind socket
Valentine Krasnobaeva [Mon, 29 Apr 2024 08:38:46 +0000 (10:38 +0200)] 
MEIDUM: unix sock: use my_socketat to create bind socket

As UNIX Domain sockets could be attached to Linux namespaces (see more details
about it from the Linux kernel patch set below:

https://lore.kernel.org/netdev/m1hbl7hxo3.fsf@fess.ebiederm.org),

it is better to use my_socket_at() in order to create UNIX listener's socket.
my_socket_at() takes in account a network namespace, that may be configured
for a frontend in the bind line:

frontend fe_foo
...
bind uxst@frontend.sock user haproxy group haproxy mode 660 namespace frontend

Like this, namespace aware applications as netstat for example, will see this
listening socket in its 'frontend' namespace and not in the root namespace as
it was before.

It is important to mention, that fixes in Linux kernel referenced above allow
to connect to this listener's socket from the root and from any other
namespace. UNIX Domain socket is protected by its permission set, which must
be set with caution on its inode.

14 months agoMEDIUM: proto_uxst: take in account server namespace
Valentine Krasnobaeva [Tue, 23 Apr 2024 21:11:15 +0000 (23:11 +0200)] 
MEDIUM: proto_uxst: take in account server namespace

As UNIX Domain sockets could be attached to Linux namespaces (see more details
about it from the Linux kernel patch set below:

https://lore.kernel.org/netdev/m1hbl7hxo3.fsf@fess.ebiederm.org),

it is better to use sock_create_server_socket() in UNIX stream protocol
implementation, as this function calls my_socket_at() and the latter takes
in account server network namespace, which could be configured as in example
below:

       backend be_bar
                ...
                server rpicam0 /run/ustreamer.sock namespace foonet

So, for UNIX Domain socket, used as an address of some backend server, this
patch makes possible to perform connect() to this backend server from the same
network namespace, where the server is running, or where its listening socket
was created.

Using sock_create_server_socket() in UNIX stream protocol implementation also
makes the code of uxst_connect_server() more uniform with tcp_connect_server()
and quic_connect_server().

14 months agoMINOR: sock: rename sock to sock_fd in sock_create_server_socket
Valentine Krasnobaeva [Tue, 23 Apr 2024 20:46:55 +0000 (22:46 +0200)] 
MINOR: sock: rename sock to sock_fd in sock_create_server_socket

Renaming sock to sock_fd makes it more clear, that sock_create_server_socket
returns the fd of newly created server socket and then we check this fd.
As we heavily use "fd" variable name in all protocol implementations, let's
prefix this one with the name of its object file: sock.o.

14 months agoBUG/MINOR: stconn: don't wake up an applet waiting on buffer allocation
Willy Tarreau [Tue, 30 Apr 2024 06:38:18 +0000 (08:38 +0200)] 
BUG/MINOR: stconn: don't wake up an applet waiting on buffer allocation

Since the extension of the buffers API to applets in 3.0-dev, an applet
may find itself unable to allocate a buffer, and will block respectively
on APPCTX_FL_OUTBLK_ALLOC or APPCTX_FL_INBLK_ALLOC depending on the
direction. However the code in sc_applet_process() doesn't consider this
situation when deciding to wake up an applet, so when the condition
arises, the applet keeps ringing and is killed by the loop detector.

The fix is trivial and simply consists in checking for the flags above.
No backport is needed since this is new in 3.0.

14 months agoBUG/MEDIUM: log: don't ignore disabled node's options
Aurelien DARRAGON [Tue, 30 Apr 2024 15:52:44 +0000 (17:52 +0200)] 
BUG/MEDIUM: log: don't ignore disabled node's options

In 3f2e8d0ed ("MEDIUM: log: lf_* build helpers now take a ctx argument")
I made a mistake, because starting with this commit it is no longer
possible from a node to disable global logformat options.
The result is that when an option is set globally, it cannot be disabled
anymore.

For instance, it is not possible to do this anymore:
  log-format "%{+X}o %{-X}Ts"

The original intent was to prevent encoding options from being
disabled once enabled globally, because when encoding is enabled globally
we start the object enumeration right away (ie: in CBOR and JSON we
announce dynamic map, and for each node we announce the key..), thus it
doesn't make sense to mix encoding types there, unless encoding is only
used per-node, in which case only the value gets encoded, thus it remains
possible to print a value in JSON/CBOR-compatible format while the next
one shouldn't be printed as-is.

Thus, to restore the original behavior, slightly change the logic in
lf_buildctx_prepare() so that only global encoding options take the
precedence over node's options (instead of all options).

No backport needed.

14 months agoMINOR: log/cbor: _lf_cbor_encode_byte() explicitly requires non-NULL ctx (again)
Aurelien DARRAGON [Tue, 30 Apr 2024 06:55:13 +0000 (08:55 +0200)] 
MINOR: log/cbor: _lf_cbor_encode_byte() explicitly requires non-NULL ctx (again)

The BUG_ON() statement that was added in 9bdea51 ("MINOR: log/cbor:
_lf_cbor_encode_byte() explicitly requires non-NULL ctx") isn't
sufficient as Coverity still thinks the lf_buildctx itself may be NULL
as shown in GH #2554. In fact the original reports complains about the
lf_buildctx itself and I didn't understand it properly, let's add another
check in the BUG_ON() to ensure both cbor_ctx and cbor_ctx->ctx are not
NULL since it is not expected if used properly.

14 months agoBUG/MINOR: log: fix global lf_expr node options behavior (2nd try)
Aurelien DARRAGON [Mon, 29 Apr 2024 13:58:36 +0000 (15:58 +0200)] 
BUG/MINOR: log: fix global lf_expr node options behavior (2nd try)

In 98b44e8 ("BUG/MINOR: log: fix global lf_expr node options behavior"),
I properly restored global node options behavior for when encoding is
not used, however the fix is not optimal when encoding is involved:

Indeed, encoding logic in sess_build_logline() relies on global node
options to know if encoding must be handled expression-wide or
individually. However, because of the above fix, if an expression is
made of 1 or multiple nodes that all set an encoding option manually
(without '%o'), we consider that the option was set globally, but
that's probably not what the user intended. Instead we should only
evaluate global options from '%o', so that it remains possible to
skip global encoding when needed.

No backport needed.

14 months agoBUG/MINOR: log/encode: fix potential NULL-dereference in LOGCHAR()
Aurelien DARRAGON [Mon, 29 Apr 2024 18:19:05 +0000 (20:19 +0200)] 
BUG/MINOR: log/encode: fix potential NULL-dereference in LOGCHAR()

When CBOR encoding was added in c614fd3b9 ("MINOR: log: add +cbor encoding
option"), in LOGCHAR(), we forgot to check that we don't assign the NULL
value to tmplog (as we assume that tmplog cannot be NULL at the end of
sess_build_logline())

No backport needed.

14 months agoBUG/MINOR: log/encode: consider global options for key encoding
Aurelien DARRAGON [Mon, 29 Apr 2024 13:31:17 +0000 (15:31 +0200)] 
BUG/MINOR: log/encode: consider global options for key encoding

In sess_build_logline(), contrary to what's stated in the comment
"only consider global ctx for key encoding", we check for
LOG_OPT_ENCODE flag on the current ctx options instead of global
ones. Because of this, we could end up doing the wrong thing if the
previous node had encoding enabled but it isn't set globally for
instance.

To fix the issue, let's simply check the presence of the flag on
g_options before entering the "key encoding" block.

This bug was introduced with 3f7c8387 ("MINOR: log: add +json encoding
option"), no backport needed.

14 months agoMINOR: ssl: introduce ocsp_update.http_proxy for ocsp-update keyword
William Lallemand [Mon, 29 Apr 2024 15:23:02 +0000 (17:23 +0200)] 
MINOR: ssl: introduce ocsp_update.http_proxy for ocsp-update keyword

The ocsp_update.http_proxy global option allows to set an HTTP proxy
address which will be used to send the OCSP update request with an
absolute form URI.

14 months agoMINOR: httpclient: allow to use absolute URI with new flag HC_F_HTTPROXY
William Lallemand [Mon, 29 Apr 2024 15:10:47 +0000 (17:10 +0200)] 
MINOR: httpclient: allow to use absolute URI with new flag HC_F_HTTPROXY

The new HC_F_HTTPPROXY flag allows to use an absolute URI within a
request that won't be modified in order to use an http proxy.

14 months agoCLEANUP: log: add a macro to know if a lf_node is configurable
Aurelien DARRAGON [Mon, 29 Apr 2024 10:22:56 +0000 (12:22 +0200)] 
CLEANUP: log: add a macro to know if a lf_node is configurable

LF_NODE_WITH_OPT(node) returns true if the node's option may be set and
thus should be considered. Logic is based on logformat node's type:
for now only TAG and FMT nodes can be configured.

14 months agoBUG/MINOR: log: fix global lf_expr node options behavior
Aurelien DARRAGON [Mon, 29 Apr 2024 09:55:27 +0000 (11:55 +0200)] 
BUG/MINOR: log: fix global lf_expr node options behavior

In 507223d5 ("MINOR: log: global lf_expr node options"), a mistake was
made because it was assumed that only the last occurence of %o
(LOG_FMT_GLOBAL) should be kept as global node options.

However, although not documented, it is possible to have multiple %o
within a single logformat expression to change the global settings on the
fly.

For instance, consider this example:

  log-format "%{+X}o test1=%ms %{-X}o test2=%ms %{+X}o test3=%ms"

Prior to 3f2e8d0ed ("MEDIUM: log: lf_* build helpers now take a ctx
argument"), this would output something like this:

  test1=18B test2=395 test3=18B

This is because global options is properly updated as the lf_expr string
is parsed. But now due to 507223d5 and 3f2e8d0ed, only the last %o
occurence is considered. With the above example, this gives:

  test1=18B test2=18B test3=18B

To restore historical behavior, let's partially revert 507223d5: to
compute global node options, we now start with all options enabled and
then for each configurable node in lf_expr_postcheck(), we keep options
common to the current node and previous nodes using AND masking, this way
we really end up with options common to all nodes.

No backport needed.

14 months agoMINOR: log/cbor: _lf_cbor_encode_byte() explicitly requires non-NULL ctx
Aurelien DARRAGON [Mon, 29 Apr 2024 07:46:24 +0000 (09:46 +0200)] 
MINOR: log/cbor: _lf_cbor_encode_byte() explicitly requires non-NULL ctx

As shown in GH #2550, Coverity is tempted to think that NULL-dereference
can occur in _lf_cbor_encode_byte() due to user-ctx being dereferenced
from cbor_ctx, while coverity thinks that cbor_ctx may be NULL.

In practise this cannot happen, because _lf_cbor_encode_byte() is
only leveraged through a function pointer that is set in conjunction with
the function pointer ctx (which ain't NULL). All this logic is done inside
lf_buildctx_prepare() when LOG_OPT_ENCODE_CBOR is set.

Since coverity doesn't seem to understand the logic properly, then it
might as well confuse humans, so let's make it clear in
_lf_cbor_encode_byte() that we expect non-NULL ctx by adding a BUG_ON()

14 months agoCLEANUP: tools/cbor: rename cbor_encode_ctx struct members
Aurelien DARRAGON [Mon, 29 Apr 2024 07:20:46 +0000 (09:20 +0200)] 
CLEANUP: tools/cbor: rename cbor_encode_ctx struct members

Rename e_byte_fct to e_fct_byte and e_fct_byte_ctx to e_fct_ctx, and
adjust some comments to make it clear that e_fct_ctx is here to provide
additional user-ctx to the custom cbor encode function pointers.

For now, only e_fct_byte function may be provided, but we could imagine
having e_fct_int{16,32,64}() one day to speed up the encoding when we
know we can encode multiple bytes at a time, but for now it's not worth
the hassle.

14 months agoBUG/MINOR: stats: replace objt_* by __objt_* macros
Amaury Denoyelle [Mon, 29 Apr 2024 12:16:19 +0000 (14:16 +0200)] 
BUG/MINOR: stats: replace objt_* by __objt_* macros

Update parse_stat_line() used during stats-file parsing. For each line,
GUID is extracted first to access to the object instance. obj_type()
is then invoked to retrieve the correct object type.

Replace objt_* by __objt_* macros to mark its result as safe and non
NULL.

This should fix coverity report from github issue #2550.

No need to backport.

14 months agoREGTESTS: cache: Add test on 'vary' other than accept-encoding
Remi Tricot-Le Breton [Wed, 24 Apr 2024 13:22:50 +0000 (15:22 +0200)] 
REGTESTS: cache: Add test on 'vary' other than accept-encoding

A bug related to vary and the 'accept-encoding' header was fixed in
"BUG/MEDIUM: cache: Vary not working properly on anything other than
accept-encoding". This patch adds tests specific to this bug.

14 months agoBUG/MEDIUM: cache: Vary not working properly on anything other than accept-encoding
Remi Tricot-Le Breton [Wed, 24 Apr 2024 12:32:19 +0000 (14:32 +0200)] 
BUG/MEDIUM: cache: Vary not working properly on anything other than accept-encoding

If a response varies on anything other than accept-encoding (origin or
referer) but still contains an 'Encoding' header, the cached responses
were never sent back.
This is because of the 'set_secondary_key_encoding' call that always
filled the accept-encoding part of the secondary signature with the
response's actual encoding, regardless of whether the response varies on
this or not. This meant that the accept-encoding part of the signature
could be non-null in the cached entry which made the
'get_secondary_entry' calls in 'http_action_req_cache_use' always fail
because in those cases the request's secondary signature always had a
null accept-encoding part.

This patch can be backported up to branch 2.4.

14 months ago[RELEASE] Released version 3.0-dev9 v3.0-dev9
Willy Tarreau [Sat, 27 Apr 2024 07:37:03 +0000 (09:37 +0200)] 
[RELEASE] Released version 3.0-dev9

Released version 3.0-dev9 with the following main changes :
    - BUILD: ssl: use %zd for sizeof() in ssl_ckch.c
    - MINOR: backend: use be_counters for health down accounting
    - BUG/MINOR: backend: use cum_sess counters instead of cum_conn
    - BUG/MINOR: stats: fix stot metric for listeners
    - REGTESTS: use -dI for insecure fork by default in the regtest scripts
    - MINOR: stats: rename proxy stats
    - MINOR: stats: rename ambiguous stat_l and stat_count
    - MINOR: stats: rename info stats
    - MINOR: stats: use stricter naming stats/field/line
    - MINOR: stats: use STAT_F_* prefix for flags
    - BUG/MEDIUM: applet: Let's applets decide if they have more data to deliver
    - BUILD: stick-tables: silence build warnings when threads are disabled
    - MINOR: tools: Rename `ha_generate_uuid` to `ha_generate_uuid_v4`
    - MINOR: Add `ha_generate_uuid_v7`
    - MINOR: Add support for UUIDv7 to the `uuid` sample fetch
    - MEDIUM: shctx: Naming shared memory context
    - BUG/MINOR: h1: fix detection of upper bytes in the URI
    - MINOR: intops: add a pair of functions to check multi-byte ranges
    - TESTS: add a unit test for the multi-byte range checks
    - CLEANUP: h1: make use of the multi-byte matching functions
    - REGTESTS: ssl: Remove "sleep" calls from ocsp auto update test
    - BUG/MEDIUM: peers: Automatically start to learn on local peer
    - BUG/MEDIUM: peers: Reprocess peer state after all session shutdowns
    - MINOR: peers: Remove unused PEERS_F_RESYNC_REQUESTED flag
    - MINOR: peers: Don't set TEACH flags on a peer from the sync task
    - MINOR: peers: Use a peer flag to block the applet waiting ack of the sync task
    - BUG/MEDIUM: peers: Wait for sync task ack when a resynchro is finished
    - MINOR: peers: Remove unused PEERS_F_RESYNC_PROCESS flag
    - MINOR: applet: Add a function to know the side where an applet was created
    - MEDIUM: peers: Simplify the peer flags dealing with the connection state
    - MEDIUM: peers: Use true states for the peer applets as seen from outside
    - MEDIUM: peers: Use true states for the learn state of a peer
    - MINOR: peers: Start learning for local peer before receiving messages
    - MINOR: peers: Rename PEERS_F_TEACH_COMPLETE to PEERS_F_LOCAL_TEACH_COMPLETE
    - MINOR: peers: Reorder and slightly rename PEER flags
    - MINOR: peers: Reorder and rename PEERS flags
    - REORG: peers: Move peer and peers flags in the corresponding header file
    - DEV: flags/peers: Decode PEER and PEERS flags
    - MINOR: peers: Add comment on processing functions of the sync task
    - MINOR: peers: Use a static variable to wait a resync on reload
    - BUG/MEDIUM: peers: Use atomic operations on peers flags when necessary
    - REORG: peers: Rename all occurrences to 'ps' variable
    - BUG/MINOR: peers: Don't wait for a remote resync if there no remote peer
    - MINOR: stats: update ambiguous "metrics" naming to "stat_cols"
    - MINOR: stats: introduce a more expressive stat definition method
    - MINOR: stats: implement automatic metric generation from stat_col
    - MINOR: stats: hide some columns in output
    - MEDIUM: stats: convert counters to new column definition
    - MINOR: stats: define stats-file output format support
    - MEDIUM: stats: implement dump stats-file CLI
    - MINOR: ist: define iststrip() new function
    - MINOR: guid: define guid_is_valid_fmt()
    - MINOR: stats: apply stats-file on process startup
    - MINOR: stats: parse header lines from stats-file
    - MINOR: stats: parse values from stats-file
    - MEDIUM: stats: define stats-file keyword
    - BUG/MINOR: mworker: reintroduce way to disable seamless reload with -x /dev/null
    - CLEANUP: log: remove unused checks for encode_{chunk,string}
    - MINOR: log: store lf_expr nodes inside substruct
    - MINOR: log: global lf_expr node options
    - CLEANUP: log: simplify complex values usages in sess_build_logline()
    - MINOR: log: skip custom logformat_node name if empty
    - MINOR: log: add lf_int() wrapper to print integers
    - MINOR: log: add lf_rawtext{_len}() functions
    - MEDIUM: log: pass date strings to lf_rawtext()
    - MEDIUM: log: write raw strings using lf_rawtext()
    - MEDIUM: log: use lf_rawtext for lf_ip() and lf_port() hex strings
    - MINOR: log: explicitly handle %ts and %tsc as text strings
    - MINOR: log: use LOG_VARTEXT_{START,END} to enclose text strings
    - MINOR: log: make all lf_* sess build helper static
    - MINOR: log: merge lf_encode_string() and lf_encode_chunk() logic
    - MEDIUM: log: lf_* build helpers now take a ctx argument
    - MINOR: log: expose node typecast in lf_buildctx struct
    - MINOR: log: postpone conversion for sample expressions in sess_build_logline()
    - MINOR: log: add LOG_OPT_NONE flag
    - MINOR: log: add no_escape_map to bypass escape with _lf_encode_bytes()
    - MINOR: log: add +bin logformat node option
    - MINOR: log: add +json encoding option
    - MINOR: tools: add cbor encode helpers
    - MINOR: log: add +cbor encoding option
    - MINOR: log: support true cbor binary encoding
    - CLEANUP: dynbuf: move the reserve and limit parsers to dynbuf.c
    - MINOR: list: add a macro to detect that a list contains at most one element
    - MINOR: cli/wait: rename the condition "srv-unused" to "srv-removable"

14 months agoMINOR: cli/wait: rename the condition "srv-unused" to "srv-removable"
Willy Tarreau [Sat, 27 Apr 2024 07:12:34 +0000 (09:12 +0200)] 
MINOR: cli/wait: rename the condition "srv-unused" to "srv-removable"

As previously discussed, "srv-unused" is sufficiently ambiguous to cause
some trouble over the long term. Better use "srv-removable" to indicate
that the server is removable, and if the conditions to delete a server
change over time, the wait condition will be adjusted without renaming
it.

14 months agoMINOR: list: add a macro to detect that a list contains at most one element
Willy Tarreau [Wed, 24 Apr 2024 16:21:50 +0000 (18:21 +0200)] 
MINOR: list: add a macro to detect that a list contains at most one element

The new LIST_ATMOST1() test verifies that the designated element is either
alone or points on both sides to the same element. This is used to detect
that a list has at most a single element, or that an element about to be
deleted was the last one of a list.

14 months agoCLEANUP: dynbuf: move the reserve and limit parsers to dynbuf.c
Willy Tarreau [Thu, 18 Apr 2024 14:11:52 +0000 (16:11 +0200)] 
CLEANUP: dynbuf: move the reserve and limit parsers to dynbuf.c

I just added a new setting to set the number of reserved buffer, to
discover we already had one... Let's move the parsing of this keyword
(tune.buffers.reserve) and tune.buffers.limit to dynbuf.c where they
should be.

14 months agoMINOR: log: support true cbor binary encoding
Aurelien DARRAGON [Tue, 23 Apr 2024 17:13:40 +0000 (19:13 +0200)] 
MINOR: log: support true cbor binary encoding

CBOR in hex format as implemented in previous commit is convenient because
the produced output is portable and can easily be embedded in regular
syslog payloads.

However, one of the goal of CBOR implementation is to be able to produce
"Concise Binary" object representation. Here is an excerpt from cbor.io
website:

  "Some applications also benefit from CBOR itself being encoded in
   binary. This saves bulk and allows faster processing."

Currently we don't offer that with '+cbor', quite the opposite actually
since a text string encoded with '+cbor' option will be larger than a
text string encoded with '+json' or without encoding at all, because for
each CBOR binary byte, 2 characters will be emitted.

Hopefully, the sink/log API allows for binary data to be passed as
parameter, this is because all relevant functions in the chain don't rely
on the terminating NULL byte and take a string pointer + string length as
parameter. We can actually rely on this property to support the '+bin'
option when combined with '+cbor' to produce RAW binary CBOR output.
Be careful though, as this is only intended for use with set-var-fmt or to
send binary data to capable UDP/ring endpoints.

Example:
  log-format "%{+cbor,+bin}o %(test)[bin(00AABB)]"

Will produce:
  bf64746573745f4300aabbffff

(output was piped to `hexdump  -ve '1/1 "%.2x"'` to dump raw bytes as HEX
characters)

With cbor.me pretty printer, it gives us:
  BF              # map(*)
     64           # text(4)
        74657374  # "test"
     5F           # bytes(*)
        43        # bytes(3)
           00AABB # "\u0000\xAA\xBB"
        FF        # primitive(*)
     FF           # primitive(*)

14 months agoMINOR: log: add +cbor encoding option
Aurelien DARRAGON [Tue, 23 Apr 2024 08:12:46 +0000 (10:12 +0200)] 
MINOR: log: add +cbor encoding option

In this patch, we make use of the CBOR (RFC8949) encode helper functions
from the previous commit to implement '+cbor' encoding option for log-
formats. The logic behind it is pretty similar to '+json' encoding option,
except that the produced output is a CBOR payload written in HEX format so
that it remains compatible to use this with regular syslog endpoints.

Example:
  log-format "%{+cbor}o %[int(4)] test %(named_field)[str(ok)]"

Will produce:
  BF6B6E616D65645F6669656C64626F6BFF

  Detailed view (from cbor.me):
    BF                           # map(*)
       6B                        # text(11)
          6E616D65645F6669656C64 # "named_field"
       62                        # text(2)
          6F6B                   # "ok"
       FF                        # primitive(*)

If the option isn't set globally, but on a specific node instead, then
only the value will be encoded according to CBOR specification.

Example:
  log-format "test cbor bool: %{+cbor}[bool(true)]"

Will produce:
  test cbor bool: F5

14 months agoMINOR: tools: add cbor encode helpers
Aurelien DARRAGON [Mon, 22 Apr 2024 15:38:44 +0000 (17:38 +0200)] 
MINOR: tools: add cbor encode helpers

Add cbor helpers to encode strings (bytes/text) and integers according to
RFC8949, also add cbor_encode_ctx struct to pass encoding options such as
how to encode a single byte.

14 months agoMINOR: log: add +json encoding option
Aurelien DARRAGON [Mon, 22 Apr 2024 12:40:04 +0000 (14:40 +0200)] 
MINOR: log: add +json encoding option

In this patch, we add the "+json" log format option that can be set
globally or per log format node.

What it does, it that it sets the LOG_OPT_ENCODE_JSON flag for the
current context which is provided to all lf_* log building function.

This way, all lf_* are now aware of this option and try to comply with
JSON specification when the option is set.

If the option is set globally, then sess_build_logline() will produce a
map-like object with key=val pairs for named logformat nodes.
(logformat nodes that don't have a name are simply ignored).

Example:
  log-format "%{+json}o %[int(4)] test %(named_field)[str(ok)]"

Will produce:
  {"named_field": "ok"}

If the option isn't set globally, but on a specific node instead, then
only the value will be encoded according to JSON specification.

Example:
  log-format "{ \"manual_key\": %(named_field){+json}[bool(true)] }"

Will produce:
  {"manual_key": true}

When the option is set, +E option will be ignored, and partial numerical
values (ie: because of logasap) will be encoded as-is.

14 months agoMINOR: log: add +bin logformat node option
Aurelien DARRAGON [Thu, 25 Apr 2024 14:29:01 +0000 (16:29 +0200)] 
MINOR: log: add +bin logformat node option

Support '+bin' option argument on logformat nodes to try to preserve
binary output type with binary sample expressions.

For this, we rely on the log/sink API which is capable of conveying binary
data since all related functions don't search for a terminating NULL byte
in provided log payload as they take a string pointer and a string length
as argument.

Example:
  log-format "%{+bin}o %[bin(00AABB)]"

Will produce:
  00aabb

(output was piped to `hexdump  -ve '1/1 "%.2x"'` to dump raw bytes as HEX
characters)

This should be used carefully, because many syslog endpoints don't expect
binary data (especially NULL bytes). This is mainly intended for use with
set-var-fmt actions or with ring/udp log endpoints that know how to deal
with such binary payloads.

Also, this option is only supported globally (for use with '%o'), it will
not have any effect when set on an individual node. (it makes no sense to
have binary data in the middle of log payload that was started without
binary data option)

14 months agoMINOR: log: add no_escape_map to bypass escape with _lf_encode_bytes()
Aurelien DARRAGON [Fri, 26 Apr 2024 12:23:43 +0000 (14:23 +0200)] 
MINOR: log: add no_escape_map to bypass escape with _lf_encode_bytes()

Providing no_escape_map as <map> argument to _lf_encode_bytes() function
will make the function skip escaping since the map is empty.

This is for convenience, as it might be useful to call lf_encode_chunk()
to encoding binary data without escaping it.

14 months agoMINOR: log: add LOG_OPT_NONE flag
Aurelien DARRAGON [Thu, 25 Apr 2024 14:24:56 +0000 (16:24 +0200)] 
MINOR: log: add LOG_OPT_NONE flag

Add LOG_OPT_NONE flag for default value. Flag is not explicitly used yet
but with way we make it official that 0 value means NONE.

14 months agoMINOR: log: postpone conversion for sample expressions in sess_build_logline()
Aurelien DARRAGON [Thu, 25 Apr 2024 14:20:11 +0000 (16:20 +0200)] 
MINOR: log: postpone conversion for sample expressions in sess_build_logline()

In sess_build_logline(), for sample expression nodes, instead of directly
calling sample_fetch_as_type(... SMP_T_STR), let's first process the
sample using sample_process(), and then proceed with the conversion to
str if required.

Doing so will allow us to implement type casting and preserving logic.

14 months agoMINOR: log: expose node typecast in lf_buildctx struct
Aurelien DARRAGON [Thu, 25 Apr 2024 16:52:57 +0000 (18:52 +0200)] 
MINOR: log: expose node typecast in lf_buildctx struct

Store node->typecast setting inside lf_buildctx struct so that encoding
functions may benefit from it.

14 months agoMEDIUM: log: lf_* build helpers now take a ctx argument
Aurelien DARRAGON [Mon, 22 Apr 2024 08:12:42 +0000 (10:12 +0200)] 
MEDIUM: log: lf_* build helpers now take a ctx argument

Add internal lf_buildctx struct that is only used inside
sess_build_logline() scope and is passed to lf_* log building helpers
to expose current building context. For now, node options and the in_text
counter are stored in the ctx struct. Thanks to this change, lf_* building
functions don't depend on a logformat_node struct pointer, and may be used
in a standalone manner as long as a build context is provided.

Also, global options are now handled explictly in sess_build_logline() to
make sure that global options are always considered even if they were not
duplicated on every nodes.

No functional change should be expected.

14 months agoMINOR: log: merge lf_encode_string() and lf_encode_chunk() logic
Aurelien DARRAGON [Fri, 26 Apr 2024 11:53:15 +0000 (13:53 +0200)] 
MINOR: log: merge lf_encode_string() and lf_encode_chunk() logic

lf_encode_string() and lf_encode_chunk() function are pretty similar. The
only difference is the stopping behavior, encode_chunk stops at a given
position while encode_string stops when encountering '\0'. Moreover,
both functions leverage tools.c encode helpers, but because of the
LOG_OPT_ESC option, they reimplement those helpers with added logic.

Instead of having to deal with code duplication which makes both functions
harder to maintain, let's define a _lf_encode_bytes() helper function
which satisfies lf_encode_string() and lf_encode_chunk() needs while
keeping the function as simple as possible.

_lf_encode_bytes() itself is made of multiple static inline helper
functions, in the attempt to keep checks outside of core loop for
better performance.

14 months agoMINOR: log: make all lf_* sess build helper static
Aurelien DARRAGON [Mon, 22 Apr 2024 08:18:18 +0000 (10:18 +0200)] 
MINOR: log: make all lf_* sess build helper static

There is no need to expose such functions since they are only involved in
the log building process that occurs inside sess_build_logline().

Making functions static and removing their public prototype to ease code
maintenance.

14 months agoMINOR: log: use LOG_VARTEXT_{START,END} to enclose text strings
Aurelien DARRAGON [Tue, 16 Apr 2024 09:17:55 +0000 (11:17 +0200)] 
MINOR: log: use LOG_VARTEXT_{START,END} to enclose text strings

Rename LOGQUOTE_{START,END} macros to more generic LOG_VARTEXT_{START,END}
in order to prepare for new encoding types that rely on specific treatment
for variable-length texts. No functional change should be expected.

14 months agoMINOR: log: explicitly handle %ts and %tsc as text strings
Aurelien DARRAGON [Tue, 23 Apr 2024 16:25:32 +0000 (18:25 +0200)] 
MINOR: log: explicitly handle %ts and %tsc as text strings

Build fixed-length strings for %ts and %tsc to be able to print them
using lf_rawtext_len(), this way it will be easier to encode them
when new encoding options will be added.

No functional change should be expected.

14 months agoMEDIUM: log: use lf_rawtext for lf_ip() and lf_port() hex strings
Aurelien DARRAGON [Wed, 3 Apr 2024 13:42:35 +0000 (15:42 +0200)] 
MEDIUM: log: use lf_rawtext for lf_ip() and lf_port() hex strings

Same as the previous commit, but for ip and port oriented values when
+X option is provided.

No functional change should be expected.

Because of this patch, we add a little overhead because we first generate
the text into a temporary variable and then use lf_rawtext() to print it.
Thus we have a double-copy, and this could have some performance
implications that were not yet evaluated. Due to the small number of bytes
that can end up being copied twice, we could be lucky and have no visible
performance impact, but if we happen to see a significant impact, it could
be useful to add a passthrough mechanism (to keep historical behavior)
when no encoding is involved.

14 months agoMEDIUM: log: write raw strings using lf_rawtext()
Aurelien DARRAGON [Wed, 27 Mar 2024 09:28:59 +0000 (10:28 +0100)] 
MEDIUM: log: write raw strings using lf_rawtext()

Make use of the previous commit to print strings that should not be
modified.

For instance, when +X option is provided, we have to print numerical
values in ASCII HEX form. For that, we used snprintf() to output the
result to the log output buffer directly, but now we build the string in
a temporary buffer of fixed-size and then print it using lf_rawtext()
which will take care of encoding options.

Because of this patch, we add a little overhead because we first generate
the text into a temporary variable and then use lf_rawtext() to print it.
Thus we have a double-copy, and this could have some performance
implications that were not yet evaluated. Due to the small number of bytes
that can end up being copied twice, we could be lucky and have no visible
performance impact, but if we happen to see a significant impact, it could
be useful to add a passthrough mechanism (to keep historical behavior)
when no encoding is involved.

14 months agoMEDIUM: log: pass date strings to lf_rawtext()
Aurelien DARRAGON [Wed, 3 Apr 2024 09:08:15 +0000 (11:08 +0200)] 
MEDIUM: log: pass date strings to lf_rawtext()

Don't directly call functions that take date as argument and output the
string representation to the log output buffer under sess_build_logline(),
and instead build the strings in temporary buffers of fixed size
(hopefully such functions, such as date2str_log() and gmt2str_log()
procuce strings of known size), and then print the result using
lf_rawtext() helper function. This way, we will be able to encode them
automatically as regular string/text when new encoding methods are added.

Because of this patch, we add a little overhead because we first generate
the text into a temporary variable and then use lf_rawtext() to print it.
Thus we have a double-copy, and this could have some performance
implications that were not yet evaluated. Due to the small number of bytes
that can end up being copied twice (< 30), we could be lucky and have no
visible performance impact, but if we happen to see a significant impact,
it could be useful to add a passthrough mechanism (to keep historical
behavior) when no encoding is involved.

14 months agoMINOR: log: add lf_rawtext{_len}() functions
Aurelien DARRAGON [Wed, 10 Apr 2024 10:07:26 +0000 (12:07 +0200)] 
MINOR: log: add lf_rawtext{_len}() functions

similar to lf_text_{len}, except that quoting and mandatory options are
ignored. Use this to print the input string without any modification (
except for encoding logic).

14 months agoMINOR: log: add lf_int() wrapper to print integers
Aurelien DARRAGON [Wed, 27 Mar 2024 09:17:11 +0000 (10:17 +0100)] 
MINOR: log: add lf_int() wrapper to print integers

Wrap ltoa(), lltoa(), ultoa() and utoa_pad() functions that are used by
sess_build_logline() to print numerical values by implementing a dedicated
helper named lf_int() that takes <dft_hld> as argument to know how to
write the integer by default (when no encoding is specified).

LF_INT_UTOA_PAD_4 is used to emulate utoa_pad(x, 4) since it's found only
once under sess_build_logline(), thus there is no need to pass an extra
parameter to lf_int() function.

14 months agoMINOR: log: skip custom logformat_node name if empty
Aurelien DARRAGON [Thu, 25 Apr 2024 07:50:14 +0000 (09:50 +0200)] 
MINOR: log: skip custom logformat_node name if empty

Reminder:

Since 3.0-dev4, we can optionally give a name to logformat nodes:

  log-format "%(custom_name1)B %(custom_name2)[str(value)]"

But we may also optionally set the expected node type by appending
':type' after the name, type being either sint,str or bool, like this:

  log-format "%(string_as_int:sint)[str(14)]"

However, it is currently not possible to provide a type without providing
a name that is a least 1 char long. But it could be useful to provide a
type without setting a name, like this, for typecasting purposes only:

  log-format "%(:sint)[bool(true)]"

Thus in order to allow this usage, don't set node->name if node name is
not at least 1 character long. By doing so, node->name will remain NULL
and will not be considered, but the typecast setting will.

14 months agoCLEANUP: log: simplify complex values usages in sess_build_logline()
Aurelien DARRAGON [Tue, 26 Mar 2024 10:50:50 +0000 (11:50 +0100)] 
CLEANUP: log: simplify complex values usages in sess_build_logline()

make sess_build_logline() switch case more readable by performing some
simplifications: complex values are first extracted in a temporary
variable so that it's easier to refer to them and at a single place.

14 months agoMINOR: log: global lf_expr node options
Aurelien DARRAGON [Mon, 25 Mar 2024 16:08:17 +0000 (17:08 +0100)] 
MINOR: log: global lf_expr node options

Add options to lf_expr->nodes to store global options (those that are
common to all node) for easier access.

No functional change should be expected.

14 months agoMINOR: log: store lf_expr nodes inside substruct
Aurelien DARRAGON [Mon, 25 Mar 2024 10:29:58 +0000 (11:29 +0100)] 
MINOR: log: store lf_expr nodes inside substruct

Add another struct level inside lf_expr struct to allow new information
to be stored alongside lf_expr nodes.

14 months agoCLEANUP: log: remove unused checks for encode_{chunk,string}
Aurelien DARRAGON [Tue, 9 Apr 2024 15:54:41 +0000 (17:54 +0200)] 
CLEANUP: log: remove unused checks for encode_{chunk,string}

Thanks to 8226e92eb ("BUG/MINOR: tools/log: invalid
encode_{chunk,string} usage"), we only need to check for NULL return
value from encode_{chunk,string}() and escape_string() to know if the
call failed.

14 months agoBUG/MINOR: mworker: reintroduce way to disable seamless reload with -x /dev/null
William Lallemand [Fri, 26 Apr 2024 13:08:31 +0000 (15:08 +0200)] 
BUG/MINOR: mworker: reintroduce way to disable seamless reload with -x /dev/null

Since the introduction of the automatic seamless reload using the
internal socketpair, there is no way of disabling the seamless reload.

Previously we just needed to remove -x from the startup command line,
and remove any "expose-fd" keyword on stats socket lines.

This was introduced in 2be557f7c ("MEDIUM: mworker: seamless reload use
the internal sockpairs").

The patch copy /dev/null again and pass it to the next exec so we never
try to get socket from the -x.

Must be backported as far as 2.6.

14 months agoMEDIUM: stats: define stats-file keyword
Amaury Denoyelle [Wed, 24 Apr 2024 09:10:07 +0000 (11:10 +0200)] 
MEDIUM: stats: define stats-file keyword

This commit is the final to implement preloading of haproxy internal
counters via stats-file parsing.

Define a global keyword "stats-file". It allows to specify the path to
the stats-file which will be parsed on process startup.

14 months agoMINOR: stats: parse values from stats-file
Amaury Denoyelle [Wed, 24 Apr 2024 09:15:18 +0000 (11:15 +0200)] 
MINOR: stats: parse values from stats-file

This patch implement parsing of counter values line from stats-file. It
reuses domain context previously set by the last header line. Each
value is separated by ',' character, relative to the list of column
names describe by the header line.

This is implemented via static function parse_stat_line(). It first
extract a GUID and retrieve the object instance. Then each numerical
value is parsed and object counters updated. For the moment, only U64
counters metrics is supported. parse_stat_line() is called on each line
until a new header line is found.

14 months agoMINOR: stats: parse header lines from stats-file
Amaury Denoyelle [Wed, 24 Apr 2024 09:14:48 +0000 (11:14 +0200)] 
MINOR: stats: parse header lines from stats-file

This patch implements parsing of headers line from stats-file.

A header line is defined as starting with '#' character. It is directly
followed by a domain name. For the moment, either 'fe' or 'be' is
allowed. The following lines will contain counters values relatives to
the domain context until the next header line.

This is implemented via static function parse_header_line(). It first
sets the domain context used during apply_stats_file(). A stats column
array is generated to contains the order on which column are stored.
This will be reused to parse following lines values.

If an invalid line is found and no header was parsed, considered the
stats-file as ill formatted and stop parsing. This allows to immediately
interrupt parsing if a garbage file was used without emitting a ton of
warnings to the user.

14 months agoMINOR: stats: apply stats-file on process startup
Amaury Denoyelle [Wed, 24 Apr 2024 09:09:06 +0000 (11:09 +0200)] 
MINOR: stats: apply stats-file on process startup

This commit is the first one of a serie to implement preloading of
haproxy counters via stats-file parsing.

This patch defines a basic apply_stats_file() function. It implements
reading line by line of a stats-file without any parsing for the moment.
It is called automatically on process startup via init().

14 months agoMINOR: guid: define guid_is_valid_fmt()
Amaury Denoyelle [Thu, 11 Apr 2024 09:10:13 +0000 (11:10 +0200)] 
MINOR: guid: define guid_is_valid_fmt()

Extract GUID format validation in a dedicated function named
guid_is_valid_fmt(). For the moment, it is only used on guid_insert().

This will be reused when parsing stats-file, to ensure GUID has a valid
format before tree lookup.

14 months agoMINOR: ist: define iststrip() new function
Amaury Denoyelle [Fri, 26 Apr 2024 08:16:25 +0000 (10:16 +0200)] 
MINOR: ist: define iststrip() new function

Implement iststrip(). This function removes any trailing newline
sequence if present from an ist.

14 months agoMEDIUM: stats: implement dump stats-file CLI
Amaury Denoyelle [Thu, 28 Mar 2024 13:53:52 +0000 (14:53 +0100)] 
MEDIUM: stats: implement dump stats-file CLI

Define a new CLI command "dump stats-file" with its handler
cli_parse_dump_stat_file(). It will loop twice on proxies_list to dump
first frontend and then backend side. It reuses the common function
stats_dump_stat_to_buffer(), using STAT_F_BOUND to restrict on the
correct side.

A new module stats-file.c is added to regroup function specifics to
stats-file. It defines two main functions :
* stats_dump_file_header() to generate the list of column list prefixed
  by the line context, either "#fe" or "#be"
* stats_dump_fields_file() to generate each stat lines. Object without
  GUID are skipped. Each stat entry is separated by a comma.

For the moment, stats-file does not support statistics modules. As such,
stats_dump_*_line() functions are updated to prevent looping over stats
module on stats-file output.

14 months agoMINOR: stats: define stats-file output format support
Amaury Denoyelle [Tue, 16 Apr 2024 16:17:48 +0000 (18:17 +0200)] 
MINOR: stats: define stats-file output format support

Prepare stats function to handle a new format labelled "stats-file". Its
purpose is to generate a statistics dump with a format closed from the
CSV output. Such output will be then used to preload haproxy internal
counters on process startup.

stats-file output differs from a standard CSV on several points. First,
only an excerpt of all statistics is outputted. All values that does not
make sense to preload are excluded. For the moment, stats-file only list
stats fully defined via "struct stat_col" method. Contrary to a CSV, sll
columns of a stats-file will be filled. As such, empty field value is
used to mark stats which should not be outputted.

Some adaptation specifics to stats-file are necessary into
me_generate_field(). First, stats-file will output separatedly values
from frontend and backend sides with their own respective set of
columns. As such, an empty field value is returned if stat is not
defined for either frontend/listener, or backend/server when outputting
the other side. Also, as stats-file does not support empty column,
stcol_hide() is not used for it.

A minor adjustement was necessary for stats_fill_fe_line() to pass
context flags. This is necessary to detect stat output format. All other
listener/server/backend corresponding functions already have it.

14 months agoMEDIUM: stats: convert counters to new column definition
Amaury Denoyelle [Wed, 3 Apr 2024 15:20:50 +0000 (17:20 +0200)] 
MEDIUM: stats: convert counters to new column definition

Convert most of proxy counters statistics to new "struct stat_col"
definition. Remove their corresponding switch..case entries in
stats_fill_*_line() functions. Their value are automatically calculate
via me_generate_field() invocation.

Along with this, also complete stcol_hide() when some stats should be
hidden.

Only a few counters where not converted. This is because they rely on
values stored outside of fe/be_counters structure, which
me_generate_field() cannot use for now.

14 months agoMINOR: stats: hide some columns in output
Amaury Denoyelle [Wed, 17 Apr 2024 09:12:27 +0000 (11:12 +0200)] 
MINOR: stats: hide some columns in output

Metric style stats can be automatically calculate since the introduction
of metric_generate() when using "struct stat_col" as input. This would
allow to centralize statistics generation. However, some stats are not
outputted under specific condition. For example, health check failures
on a server are only reported if checks are active.

To support this, define a new function metric_hide(). It is called by
metric_generate(). If true, it will skip metric calcuation and return an
empty field value instead. This allows to define "stat_col" metrics and
calculate them with metric_generate() but hiding them under certain
circumstances.

14 months agoMINOR: stats: implement automatic metric generation from stat_col
Amaury Denoyelle [Thu, 11 Apr 2024 11:56:19 +0000 (13:56 +0200)] 
MINOR: stats: implement automatic metric generation from stat_col

This commit is a direct follow-up of the previous one which define a new
type "struct stat_col" to fully define a statistic entry.

Define a new function metric_generate(). For metrics statistics, it is
able to automatically calculate a stat value field for "offsets" from
"struct stat_col". Use it in stats_fill_*_stats() functions. Maintain a
fallback to previously used switch-case for old-style statistics.

This commit does not introduce functional change as currently no
statistic is defined as "struct stat_col". This will be the subject of a
future commit.

14 months agoMINOR: stats: introduce a more expressive stat definition method
Amaury Denoyelle [Thu, 28 Mar 2024 13:53:39 +0000 (14:53 +0100)] 
MINOR: stats: introduce a more expressive stat definition method

Previously, statistics were simply defined as a list of name_desc, as
for example "stat_cols_px" for proxy stats. No notion of type was fixed
for each stat definition. This correspondance was done individually
inside stats_fill_*_line() functions. This renders the process to
define new statistics tedious.

Implement a more expressive stat definition method via a new API. A new
type "struct stat_col" for stat column to replace name_desc usage is
defined. It contains a field to store the stat nature and format. A
<cap> field is also defined to be able to define a proxy stat only for
certain type of objects.

This new type is also further extended to include counter offsets. This
allows to define a method to automatically generate a stat value field
from a "struct stat_col". This will be the subject of a future commit.

New type "struct stat_col" is fully compatible full name_desc. This
allows to gradually convert stats definition. The focus will be first
for proxies counters to implement statistics preservation on reload.

14 months agoMINOR: stats: update ambiguous "metrics" naming to "stat_cols"
Amaury Denoyelle [Tue, 23 Apr 2024 09:06:00 +0000 (11:06 +0200)] 
MINOR: stats: update ambiguous "metrics" naming to "stat_cols"

The name "metrics" was chosen to represent the various list of haproxy
exposed statistics. However, it is deemed as ambiguous as some stats are
indeed metric in the true sense, but some are not, as highlighted by
various "enum field_origin" values.

Replace it by the new name "stat_cols" for statistic columns. Along with
the already existing notion of stat lines it should better reflect its
purpose.

14 months agoBUG/MINOR: peers: Don't wait for a remote resync if there no remote peer
Christopher Faulet [Thu, 25 Apr 2024 19:47:01 +0000 (21:47 +0200)] 
BUG/MINOR: peers: Don't wait for a remote resync if there no remote peer

When a resync is needed, a local resync is first tried and if it does not
work, a remote resync is tried. It happens when the worker is started for
instance. There is a timeout to wait for the local resync, except for the
first start. And if the local resync fails or times out, the same timeout
is applied to the remote resync. This one is always applied, even if there
is no remote peer.

On the other hand, on reload, if the old worker has never performed its
resync, it does not try to resync the new worker. And here there is an
issue. On the first reload, when there is no remote peer, we must wait for
the resync timeout expiration to have a chance to resync the new worker. If
the reload happens too early, there is no resync at all. Concretly, after a
fresh start, if a reload happens in the first 5 seconds, there is no resync
with the new worker. The issue only concerns the first reload and affects
the second worker.

To fix the issue, we must only skip the remote resync if there is no remote
peer. This way, on a fresh start, the worker is immediately considered as
resync. The local reynsc is skipped because it is the first worker and the
remote resync is skipped because there is no remote peer.

This patch must be backported to all stable versions.

14 months agoREORG: peers: Rename all occurrences to 'ps' variable
Christopher Faulet [Thu, 25 Apr 2024 08:57:44 +0000 (10:57 +0200)] 
REORG: peers: Rename all occurrences to 'ps' variable

In loops on the peer list in the code, the 'ps' variable was used as a
shortcut for the peer session. However, if mays be confusing with the peers
section too. So, all occurrences to 'ps' variable were renamed to 'peer'.

14 months agoBUG/MEDIUM: peers: Use atomic operations on peers flags when necessary
Christopher Faulet [Thu, 25 Apr 2024 08:51:18 +0000 (10:51 +0200)] 
BUG/MEDIUM: peers: Use atomic operations on peers flags when necessary

Peers flags are mainly used from the sync task. At least, it is only updated
by the sync task. However, there is one place where a peer may read these
flags, when the message marking the end of a synchro is sent.

So to be sure the value retrieved at this place is consistent, we must use
an atomic operation to read it. And of course, from the sync task, atomic
operations must be used to update peers flags. However, from the sync task,
there is no reason to use atomic operations to read flags because they
cannot be update from somewhere eles.

14 months agoMINOR: peers: Use a static variable to wait a resync on reload
Christopher Faulet [Thu, 25 Apr 2024 08:29:32 +0000 (10:29 +0200)] 
MINOR: peers: Use a static variable to wait a resync on reload

When a process is reloaded, the old process must performed a synchronisation
with the new process. To do so, the sync task notify the local peer to
proceed and waits. Internally, the sync task used PEERS_F_DONOTSTOP flag to
know it should wait. However, this flag was only set/unset in a single
function. There is no real reason to set a flag to do so. A static variable
set to 1 when the resync starts and to 0 when it is finished is enough.

14 months agoMINOR: peers: Add comment on processing functions of the sync task
Christopher Faulet [Thu, 25 Apr 2024 07:49:00 +0000 (09:49 +0200)] 
MINOR: peers: Add comment on processing functions of the sync task

Just add a comment on __process_running_peer_sync() and
__process_stopping_peer_sync() functions.

14 months agoDEV: flags/peers: Decode PEER and PEERS flags
Christopher Faulet [Thu, 25 Apr 2024 07:43:16 +0000 (09:43 +0200)] 
DEV: flags/peers: Decode PEER and PEERS flags

Decode peer and peers flags via peer_show_flags() and peers_show_flags()
functions.

14 months agoREORG: peers: Move peer and peers flags in the corresponding header file
Christopher Faulet [Thu, 25 Apr 2024 07:42:05 +0000 (09:42 +0200)] 
REORG: peers: Move peer and peers flags in the corresponding header file

PEER_F_* and PEERS_F_ * flags were moved to <peer-t.h> header file. It is
mandatory to decode them from "flags" dev tool.

14 months agoMINOR: peers: Reorder and rename PEERS flags
Christopher Faulet [Thu, 25 Apr 2024 07:17:38 +0000 (09:17 +0200)] 
MINOR: peers: Reorder and rename PEERS flags

Peers flags were renamed and reordered, mainly to move flags used for
debugging purpose at the end.

PEERS_F_RESYNC_LOCAL and PEERS_F_RESYNC_REMOTE were also renamed to
PEERS_F_RESYNC_LOCAL_FINISHED and PEERS_F_RESYNC_REMOTE_FINISHED to be clear
on the fact the operation is finished when the flag is set.

14 months agoMINOR: peers: Reorder and slightly rename PEER flags
Christopher Faulet [Thu, 25 Apr 2024 06:43:21 +0000 (08:43 +0200)] 
MINOR: peers: Reorder and slightly rename PEER flags

There are too many holes in peer flags. So let's reorder them. In addition,
PEER_F_RESYNC_REQUESTED flag was renamed to PEER_F_DBG_RESYNC_REQUESTED to
clearly state it is a flag set for debugging purpose.

Finally, PEER_TEACH_RESET was replaced by PEER_TEACH_FLAGS and the bitwise
complement operator is now used on lines updating the peer flags. It is a
far more common way to do (in HAProxy code at least) and less surprising.

14 months agoMINOR: peers: Rename PEERS_F_TEACH_COMPLETE to PEERS_F_LOCAL_TEACH_COMPLETE
Christopher Faulet [Thu, 25 Apr 2024 06:27:20 +0000 (08:27 +0200)] 
MINOR: peers: Rename PEERS_F_TEACH_COMPLETE to PEERS_F_LOCAL_TEACH_COMPLETE

PEERS_F_TEACH_COMPLETE flag is only used for the old local peer to let the
sync task know it can stop waiting during a soft-stop. So it is less
confusing to rename this flag to clearly state it concerns local peer only.

14 months agoMINOR: peers: Start learning for local peer before receiving messages
Christopher Faulet [Wed, 24 Apr 2024 18:55:23 +0000 (20:55 +0200)] 
MINOR: peers: Start learning for local peer before receiving messages

A local peer assigned for leaning can immediately start to learn, without
sending any request. So we can do that first, before receiving
messages. This way, only PEER_LR_ST_PROCESSING state is evaluating when
received messages are processed.

In addition, when the resync request is sent, we are sure it is for a remote
peer.

14 months agoMEDIUM: peers: Use true states for the learn state of a peer
Christopher Faulet [Wed, 24 Apr 2024 18:46:55 +0000 (20:46 +0200)] 
MEDIUM: peers: Use true states for the learn state of a peer

Some flags were used to define the learn state of a peer. It was a bit
confusing, especially because the learn state of a peer is manipulated from
the peer applet but also from the sync task. It is harder to understand the
transitions if it is based on flags than if it is based a dedicated state
based on an enum. It is the purpose of this patch.

Now, we can define the following rules regarding this learn state:

  * A peer is assigned to learn by the sync task
  * The learn state is then changed by the peer itself to notify the
    learning is in progress and when it is finished.
  * Finally, when the peer finished to learn, the sync task must acknowledge
    it by unassigning the peer.

14 months agoMEDIUM: peers: Use true states for the peer applets as seen from outside
Christopher Faulet [Wed, 24 Apr 2024 15:57:29 +0000 (17:57 +0200)] 
MEDIUM: peers: Use true states for the peer applets as seen from outside

This patch is a cleanup of the recent change about the relation between a
peer and the applet used to deal with I/O. Three flags was introduced to
reflect the peer applet state as seen from outside (from the sync task in
fact). Using flags instead of true states was in fact a bad idea. This work
but it is confusing. Especially because it was mixed with LEARN and TEACH
peer flags.

So, now, to make it clearer, we are now using a dedicated state for this
purpose. From the outside, the peer may be in one of the following state
with respects of its applet:

 * the peer has no applet, it is stopped (PEER_APP_ST_STOPPED).

 * the peer applet was created with a validated connection from the protocol
   perspective. But the sync task must synchronized it with the peers
   section. It is in starting state (PEER_APP_ST_STARTING).

 * The starting starting was acknowledged by the sync task, the peer applet
   can start to process messages. It is in running state
   (PEER_APP_ST_RUNNING).

 * The last peer applet was released and the associated connection
   closed. But the sync task must synchronized it with the peers section. It
   is in stopping state (PEER_APP_ST_STOPPING).

Functionnaly speaking, there is no true change here. But it should be easier
to understand now.

In addition to these changes, __process_peer_state() function was renamed
sync_peer_app_state().

14 months agoMEDIUM: peers: Simplify the peer flags dealing with the connection state
Christopher Faulet [Wed, 24 Apr 2024 13:42:55 +0000 (15:42 +0200)] 
MEDIUM: peers: Simplify the peer flags dealing with the connection state

Recently, some peer flags were added to deal with the connection state
(PEER_F_ST_*). 3 states were added:

  * RELEASED: Set when we forced to shutdown the peer session and no new
    session was created yet.

  * CONNECTED: Set when the peer has established connection and validated it
    from the peer protocol point of view

  * ACCEPTED: Set when the peer has accepted a connection and validated it
    from the peer protocol point of view

However, management of these pseudo states is a bit confusing. And it
appears there is no reason to have 2 flags to express there is a validated
peer session. CONNECTED state was used for a peer session on the frontend
side while ACCEPTED state was used for a peer session on the backend side.

So, there is now only one "connected" state and we test if the applet was
created on the frontend or the backend side to decide what to do, in
addition to the fact the peer is local or remote.

It is a transitionnal patch. True states will be created to deal with all
this stuff and corresponding flags will be removed.

This patch depends on the commit "MINOR: applet: Add a function to know the
sidde where an applet was created".

14 months agoMINOR: applet: Add a function to know the side where an applet was created
Christopher Faulet [Wed, 24 Apr 2024 12:36:17 +0000 (14:36 +0200)] 
MINOR: applet: Add a function to know the side where an applet was created

appctx_is_back() function may be used to know if an applet was create on
frontend side or on backend side. It may be handy for some applets that may
exist on both sides, like peer applets.

14 months agoMINOR: peers: Remove unused PEERS_F_RESYNC_PROCESS flag
Christopher Faulet [Wed, 24 Apr 2024 09:42:16 +0000 (11:42 +0200)] 
MINOR: peers: Remove unused PEERS_F_RESYNC_PROCESS flag

This flag is now set or unset but never tested. So we can safely remove it.

14 months agoBUG/MEDIUM: peers: Wait for sync task ack when a resynchro is finished
Christopher Faulet [Wed, 24 Apr 2024 08:53:46 +0000 (10:53 +0200)] 
BUG/MEDIUM: peers: Wait for sync task ack when a resynchro is finished

When a learning process is finished, partially or not, the event must be
processed by the sync task. It is important for the peer applet to wait in
this case, especially if the same peer is teaching to another peer, to be
sure to send the right resync finished message (full or partial).

Thanks to the previous patch, we can set PEER_F_WAIT_SYNCTASK_ACK flag on
the peer when a PEER_MSG_CTRL_RESYNCPARTIAL or PEER_MSG_CTRL_RESYNCFINISHED
message is received to be sure to stop the processing. Of course, we must
also take care to wake the peer up after having acknowledged the learn
status from the sync task.

This patch depends on the commit "BUG/MEDIUM: peers: Wait for sync task ack
when a resynchro is finished". Both must be backported if commit 9425aeaffb
("BUG/MAJOR: peers: Update peers section state from a thread-safe manner")
is backported.

14 months agoMINOR: peers: Use a peer flag to block the applet waiting ack of the sync task
Christopher Faulet [Wed, 24 Apr 2024 08:41:07 +0000 (10:41 +0200)] 
MINOR: peers: Use a peer flag to block the applet waiting ack of the sync task

Since recent fixes on peers, some changes on a peer must be acknowledged
by the sync task before letting the peer applet processing messages.
Blocking conditions was based on a combination of flags. It was
errorprone. So, this patch introduces PEER_F_WAIT_SYNCTASK_ACK peer flag for
this purpose. This flag is set by the peer when it must wait for an ack from
the sync task. This sync task, on its side, must remove it and wake the peer
up.

14 months agoMINOR: peers: Don't set TEACH flags on a peer from the sync task
Christopher Faulet [Wed, 24 Apr 2024 07:32:55 +0000 (09:32 +0200)] 
MINOR: peers: Don't set TEACH flags on a peer from the sync task

The TEACH flags only concerns the peer applet. There is no reason to set it
from the sync task. It is confusing. And at the end, after some
refactoring/fixes, setting these flags directly from the peer applet will
allow us to immediatly performing the corresponding teach processing, while
for now we must wait the sync task acknowledges the changes.

14 months agoMINOR: peers: Remove unused PEERS_F_RESYNC_REQUESTED flag
Christopher Faulet [Tue, 23 Apr 2024 16:58:14 +0000 (18:58 +0200)] 
MINOR: peers: Remove unused PEERS_F_RESYNC_REQUESTED flag

This flag was used for debugging purpose to know a resync was requested at
least once in the process life. Since the last bunch of fixes about the
peers locking mechanism, this info is now set per-peer. There is no reason
to still have it on peers too. So, just remove it.

14 months agoBUG/MEDIUM: peers: Reprocess peer state after all session shutdowns
Christopher Faulet [Wed, 24 Apr 2024 14:38:13 +0000 (16:38 +0200)] 
BUG/MEDIUM: peers: Reprocess peer state after all session shutdowns

When a session is shut down, the peer is switched in released state
(PEER_F_ST_RELEASED) and the sync task must process it to eventually
perform some clean up, in case the peer was assigned to learn.

However, this was only true when the session was shut down from the peer
applet itself. This was not performed when it was shut down from the sync
task. It is now fixed.

14 months agoBUG/MEDIUM: peers: Automatically start to learn on local peer
Christopher Faulet [Wed, 24 Apr 2024 08:18:07 +0000 (10:18 +0200)] 
BUG/MEDIUM: peers: Automatically start to learn on local peer

The previous fix (c0b2015aae "BUG/MEDIUM: peers: Don't set
PEERS_F_RESYNC_PROCESS flag on a peer") was made due to lack of knowledge on
the peers. A local peer, when assigned to learn, must start to learn
immediately without sending any request. This happens on reload.

Thus, in this case, the PEER_F_LEARN_PROCESS flag must be set with
PEER_F_LEARN_ASSIGN flag from the sync task.

This patch must only be backported if the above commit is backported.

14 months agoREGTESTS: ssl: Remove "sleep" calls from ocsp auto update test
Remi Tricot-Le Breton [Mon, 22 Apr 2024 15:09:13 +0000 (17:09 +0200)] 
REGTESTS: ssl: Remove "sleep" calls from ocsp auto update test

Instead of relying on the http client logs for synchronization, use the
specific OCSP logs that are emitted after the newly updated response is
inserted in the tree. This removes the need to wait between the syslog
reception and the insertion that was managed thanks to "sleep" calls.
This regtest can now be switched back to "devel" type instead of "slow".

14 months agoCLEANUP: h1: make use of the multi-byte matching functions
Willy Tarreau [Wed, 24 Apr 2024 13:57:15 +0000 (15:57 +0200)] 
CLEANUP: h1: make use of the multi-byte matching functions

Instead of leaving the hard-coded non-trivial operations in the H1
parsing code, let's just rely on the new intops functions that do the
same and that are less prone to being accidentally touched. It was
verified that the resulting code is exactly the same.

14 months agoTESTS: add a unit test for the multi-byte range checks
Willy Tarreau [Wed, 24 Apr 2024 14:02:46 +0000 (16:02 +0200)] 
TESTS: add a unit test for the multi-byte range checks

The test scans the whole number space in 32 bits and compares the different
functions with the reference that does one byte at a time. In 64-bit mode,
it picks 2^32 64-bit random numbers and tests that they the 64-bit functions
all produce the expected results when submitted such numbers.

It optionally takes an initial offset and step so that it can run on
multiple cores (or even machines), though the test is reasonably fast
on modern machines, around 10s per core.

14 months agoMINOR: intops: add a pair of functions to check multi-byte ranges
Willy Tarreau [Wed, 24 Apr 2024 13:23:28 +0000 (15:23 +0200)] 
MINOR: intops: add a pair of functions to check multi-byte ranges

These new functions is_char4_outside() and is_char8_outside() are meant
to be used to verify if any of the 4 or 8 chars represented respectively
by a uint32_t or a uint64_t is outside of the min,max byte range passed
in argument. This is the simplified, fast version of the function so it
is restricted to less than 0x80 distance between min and max (sufficient
to validate chars). Extra functions are also provided to check for min
or max alone as well, with the same restriction.

The use case typically is to check that the output of read_u32() or
read_u64() contains exclusively certain bytes.

14 months agoBUG/MINOR: h1: fix detection of upper bytes in the URI
Willy Tarreau [Wed, 24 Apr 2024 09:37:06 +0000 (11:37 +0200)] 
BUG/MINOR: h1: fix detection of upper bytes in the URI

In 1.7 with commit 5f10ea30f4 ("OPTIM: http: improve parsing performance
of long URIs") we improved the URI parser's performance on platforms
supporting unaligned accesses by reading 4 chars at a time in a 32-bit
word. However, as reported in GH issue #2545, there's a bug in the way
the top bytes are checked, as the parser will stop when all 4 of them
are above 7e instead of when one of them is, so certain patterns can be
accepted through if the last ones are all valid. The fix requires to
negate the value but on the other hand it allows to parallelize some of
the tests and fuse the masks, which could even end up slightly faster.

This needs to be backported to all stable versions, but be careful, this
code moved a lot over time, from proto_http.c to h1.c, to http_msg.c, to
h1.c again. Better just grep for "24242424" or "21212121" in each version
to find it.

Big kudos to Martijn van Oosterhout (@kleptog) for spotting this problem
while analyzing that piece of code, and reporting it.

14 months agoMEDIUM: shctx: Naming shared memory context
David Carlier [Sat, 20 Apr 2024 06:18:48 +0000 (07:18 +0100)] 
MEDIUM: shctx: Naming shared memory context

From Linux 5.17, anonymous regions can be name via prctl/PR_SET_VMA
so caches can be identified when looking at HAProxy process memory
mapping.
The most possible error is lack of kernel support, as a result
we ignore it, if the naming fails the mapping of memory context
ought to still occur.

14 months agoMINOR: Add support for UUIDv7 to the `uuid` sample fetch
Tim Duesterhus [Fri, 19 Apr 2024 19:01:27 +0000 (21:01 +0200)] 
MINOR: Add support for UUIDv7 to the `uuid` sample fetch

This adds support for UUIDv7 to the existing `uuid` sample fetch that was added
in 8a694b859cf98f8b0855b4aa5a50ebf64b501215.

14 months agoMINOR: Add `ha_generate_uuid_v7`
Tim Duesterhus [Fri, 19 Apr 2024 19:01:26 +0000 (21:01 +0200)] 
MINOR: Add `ha_generate_uuid_v7`

This function generates a version 7 UUID as per
draft-ietf-uuidrev-rfc4122bis-14.

14 months agoMINOR: tools: Rename `ha_generate_uuid` to `ha_generate_uuid_v4`
Tim Duesterhus [Fri, 19 Apr 2024 19:01:25 +0000 (21:01 +0200)] 
MINOR: tools: Rename `ha_generate_uuid` to `ha_generate_uuid_v4`

This is in preparation of adding support for other UUID versions.