Commit Graph

13506 Commits

Author SHA1 Message Date
Christopher Faulet
ae635766f6 MEDIUM: mux-h1: Use a h1c flag to block reads when splicing is in-progress
Instead of using 2 flags on the H1 stream (H1S_F_BUF_FLUSH and
H1S_F_SPLICED_DATA), we now only use one flag on the H1 connection
(H1C_F_WANT_SPLICE) to notify we want to use splicing or we are using
splicing. This flag blocks the calls to rcv_buf() connection callback.

It is a bit easier to set the H1 connection capability to receive data in
its input buffer instead of relying on the H1 stream.
2020-12-04 14:41:48 +01:00
Christopher Faulet
089acd5b0d MINOR: mux-h1: Add a flag to disable reads to wait opposite side
H1C_F_WAIT_OPPOSITE must be set on the H1 conenction to don't read more data
because we must be sync with the opposite side. This flag replaces the
H1C_F_IN_BUSY flag. Its name is a bit explicit. It is automatically set on
the backend side when the mux is created. It is safe to do so because at
this stage, the request has not yet been sent to the server. This way, in
h1_recv_allowed(), a test on this flag is enough to block the reads instead
of testing the H1 stream state on the backend side.
2020-12-04 14:41:48 +01:00
Christopher Faulet
26256f86e1 MINOR: stream: Pass an optional input buffer when a stream is created
It is now possible to set the buffer used by the channel request buffer when
a stream is created. It may be useful if input data are already received,
instead of waiting the first call to the mux rcv_buf() callback. This change
is mandatory to support H1 connection with no stream attached.

For now, the multiplexers don't pass any buffer. BUF_NULL is thus used to
call stream_create_from_cs().
2020-12-04 14:41:48 +01:00
Christopher Faulet
afc02a4436 MINOR: muxes: Remove get_cs_info callback function now useless
This callback function was only defined by the mux-h1. But it has been
removed in the previous commit because it is unused now. So, we can do a
step forward removing the callback function from the mux definition and the
cs_info structure.
2020-12-04 14:41:48 +01:00
Christopher Faulet
3b536a3131 MINOR: mux-h1: Don't provide anymore timing info using cs_info structure
The cs_info are now unused. The stream uses the session to get these
info. So we can safely remove it from the mux-h1.
2020-12-04 14:41:48 +01:00
Christopher Faulet
15e525f495 MINOR: stream: Don't retrieve anymore timing info from the mux csinfo
These info are only provided by the mux-h1. But, thanks to previous patches,
we can get them from the session directly. There is no need to retrieve them
from the mux anymore.
2020-12-04 14:41:48 +01:00
Christopher Faulet
7a6c513246 MINOR: stream: Always get idle duration from the session
Since the idle duration provided by the session is always up-to-date, there
is no more reason to rely on the multiplexer cs_info to set it to the
stream.
2020-12-04 14:41:48 +01:00
Christopher Faulet
dd78921c66 MINOR: logs: Use session idle duration when no stream is provided
When a log message is emitted from the session, using sess_log() function,
there is no stream available. In this case, instead of deducing the idle
duration from the accept date, we use the one provided by the session. 0 is
used if it is undefined (i.e set to -1).
2020-12-04 14:41:48 +01:00
Christopher Faulet
42849b047a MINOR: mux-h1: Reset session dates and durations info when the CS is detached
These info are reset for the next transaction, if the connection is kept
alive. From the stream point of view, it should be the same a new
connection, except there is no handshake. Thus the handshake duration is set
to 0.
2020-12-04 14:41:48 +01:00
Christopher Faulet
4e74155466 MINOR: mux-h1: Update session idle duration when data are received
The session idle duration is set if not already done when data are
received. For now, this value is still unused.
2020-12-04 14:41:48 +01:00
Christopher Faulet
d517396f8e MINOR: session: Add the idle duration field into the session
The idle duration between two streams is added to the session structure. It
is not necessarily pertinent on all protocols. In fact, it is only defined
for H1 connections. It is the duration between two H1 transactions. But the
.get_cs_info() callback function on the multiplexers only exists because
this duration is missing at the session level. So it is a simplification
opportunity for a really low cost.

To reduce the cost, a hole in the session structure is filled by moving
.srv_list field at the end of the structure.
2020-12-04 14:41:48 +01:00
Christopher Faulet
268c92e2f8 BUG/MINOR: mux-h1: Handle keep-alive timeout for idle frontend connections
IDLE frontend connections have no stream attached. The stream is only
created when new data are received, when the parsing of the next request
starts. Thus the keep-alive timeout, handled into the HTTP analysers, is not
considered while nothing is received. But this is especially when this
timeout must be considered. Concretely the http-keep-alive is ignored while
no data are received. Only the client timeout is used. It will only be
considered on incomplete requests, if the http-request timeout is not set.

To fix the bug, the http-keep-alive timeout must be handled at the mux
level, for IDLE frontend connection only.

This patch should fix the issue #984. It must be backported as far as
2.2. On prior versions, the stream is created earlier. So, it is not a
problem, except if this behavior changes of course (it was an optim of the
2.2, but don't remember the commit).
2020-12-04 14:41:48 +01:00
Willy Tarreau
7da02dd308 BUG/MINOR: listener: use sockaddr_in6 for IPv6
A copy-paste bug between {tcp,udp}{4,6}_add_listener() resulted in
using a struct sockaddr_in to set the TCP/UDP port while it ought to
be a struct sockaddr_in6. Fortunately, the port has the same offset
(2) in both so it was harmless. A cleaner way to proceed would be
to have a set_port function exported by the address family layer.

This needs to be backported to 2.3.
2020-12-04 14:28:23 +01:00
Willy Tarreau
186f37674c BUG/MINOR: lua-thread: close all states on deinit
It seems to me that lua_close() must be called on all states at deinit
time, not just the first two ones. This is likely a remnant of commit
59f11be43 ("MEDIUM: lua-thread: Add the lua-load-per-thread directive").
There should likely be some memory leak reports when using Lua without
this fix, though none were observed for now.

No backport is needed as this was merged into 2.4-dev.
2020-12-04 12:00:11 +01:00
Thierry Fournier
aafc777854 BUG/MEDIUM: lua-thread: some parts must be initialized once
Lua dedicated TCP, HTTP and SSL socket and proxies must be initialized
once. Right now, they are initialized from the Lua init state, but since
commit 59f11be43 ("MEDIUM: lua-thread: Add the lua-load-per-thread
directive") this function is called one time per lua context. This
caused some fields to be cleared and overwritten, and pre-allocated
object to be lost. This is why the address sanitizer detected memory
leaks from the socket_ssl server initialization.

Let's move all the state-independent part of the function to the
hlua_init() function to avoid this.

No backport is needed, this is only 2.4-dev.
2020-12-04 11:55:05 +01:00
Remi Tricot-Le Breton
51058d64a6 MINOR: cache: Consider invalid Age values as stale
Do not store responses that have an invalid age header (non numerical,
negative ...).
2020-12-04 10:21:56 +01:00
Remi Tricot-Le Breton
72cffaf440 MEDIUM: cache: Remove cache entry in case of POST on the same resource
In case of successful unsafe method on a stored resource, the cached entry
must be invalidated (see RFC7234#4.4).
A "non-error response" is one with a 2xx (Successful) or 3xx (Redirection)
status code.
This implies that the primary hash must now be calculated on requests
that have an unsafe method (POST or PUT for instance) so that we can
disable the corresponding entries when we process the response.
2020-12-04 10:21:56 +01:00
Remi Tricot-Le Breton
fcea374fdf MINOR: cache: Add extra "cache-control" value checks
The Cache-Control max-age and s-maxage directives should be followed by
a positive numerical value (see RFC 7234#5.2.1.1). According to the
specs, a sender "should not" generate a quoted-string value but we will
still accept this format.
2020-12-04 10:21:56 +01:00
Remi Tricot-Le Breton
795e1412b0 MINOR: cache: Do not store stale entry
When a response has an Age header (filled in by another cache on the
message's path) that is greater than its defined maximum age (extracted
either from cache-control directives or an expires header), it is
already stale and should not be cached.
2020-12-04 10:21:56 +01:00
Phil Scherer
b931f964e1 DOC/MINOR: Fix formatting in Management Guide
section numbering used '9.2)' instead of '9.2.'.
2020-12-03 06:40:51 +01:00
David Carlier
2d0493af49 BUILD/MINOR: haproxy DragonFlyBSD affinity build update.
sched_setaffinity supported by this platform.
2020-12-02 22:43:57 +01:00
Willy Tarreau
cc794b91f6 REGTESTS: add a test for the threaded Lua code
This is simply txn_get_priv.vtc with the loading made using
lua-load-per-thread, allowing all threads to run independently.
There's nothing global nor thread-specific in this test, which makes
an excellent example of something that should work out of the box.
Four concurrent clients are initialized with 4 loops each so as to
give a little chance to various threads to run concurrently.
2020-12-02 21:53:16 +01:00
Thierry Fournier
46278ff828 MINOR: lua-thread: Add verbosity in errors
Because lua-load-per-thread could not load the same code for each thread,
this patch displays the state-id associated with the error.
2020-12-02 21:53:16 +01:00
Thierry Fournier
59f11be436 MEDIUM: lua-thread: Add the lua-load-per-thread directive
The goal is to allow execution of one main lua state per thread.

This patch contains the main job. The lua init is done using these
steps:
 - "lua-load-per-thread" loads the lua code in the first thread
 - it creates the structs
 - it stores loaded files
 - the 1st step load is completed (execution of hlua_post_init)
   and now, we known the number of threads
 - we initilize lua states for all remaining threads
 - for each one, we load the lua file
 - for each one, we execute post-init

Once all is loaded, we control consistency of functions references.
The rules are:
 - a function reference cannot be in the shared lua state and in
   a per-thread lua state at the same time.
 - if a function reference is declared in a per-thread lua state, it
   must be declared in all per-thread lua states
2020-12-02 21:53:16 +01:00
Thierry Fournier
c749259dff MINOR: lua-thread: Store each function reference and init reference in array
The goal is to allow execution of one main lua state per thread.

The array introduces storage of one reference per thread, because each
lua state can have different reference id for a same function. A function
returns the preferred state id according to configuration and current
thread id.
2020-12-02 21:53:16 +01:00
Thierry Fournier
021d986ecc MINOR: lua-thread: Replace state_from by state_id
The goal is to allow execution of one main lua state per thread.

"state_from" is a pointer to the parent lua state. "state_id"
is the index of the parent state id in the reference lua states
array. "state_id" is better because the lock is a "== 0" test
which is quick than pointer comparison. In other way, the state_id
index could index other things the the Lua state concerned. I
think to the function references.
2020-12-02 21:53:16 +01:00
Thierry Fournier
62a22aa23f MINOR: lua-thread: Replace "struct hlua_function" allocation by dedicated function
The goal is to allow execution of one main lua state per thread.

This function will initialize the struct with other things than 0.
With this function helper, the initialization is centralized and
it prevents mistakes. This patch also keeps a reference to each
declared function in a list. It will be useful in next patches to
control consistency of declared references.
2020-12-02 21:53:16 +01:00
Thierry Fournier
afc63e2cb1 MINOR: lua-thread: Replace global gL var with an array of states
The goal is to allow execution of one main lua state per thread.

The array of states is initialized at the max number of thread +1.
We define the index 0 is the common state shared by all threads
and should be locked. Other index index are dedicated to each
one thread. The old gL now becomes hlua_states[0].
2020-12-02 21:53:16 +01:00
Thierry Fournier
7cbe5046e8 MEDIUM: lua-thread: Apply lock only if the parent state is the main thread
The goal is to allow execution of one main lua state per thread.

This patch opens the way to addition of a per-thread dedicated lua state.
By passing the hlua we can figure the original state that's been used
and decide to lock or not.
2020-12-02 21:53:16 +01:00
Thierry Fournier
3c539327f4 MEDIUM: lua-thread: No longer use locked context in initialization parts
The goal is to allow execution of one main lua state per thread.

Stop using locks in init part, we will use only in parts where
the parent lua state is known, so we could take decision about lock
according with the lua parent state.
2020-12-02 21:53:16 +01:00
Thierry Fournier
ecb83c24c4 MINOR: lua-thread: Add the "thread" core variable
The goal is to allow execution of one main lua state per thread.

This commit introduces this variable in the core. Lua state initialized
by thread will have access to this variable, which reports the executing
thread. 0 indicates the shared thread. Programs which must be executed
only once can check for core.thread <= 1.
2020-12-02 21:53:16 +01:00
Thierry Fournier
b8cef175bd MINOR: lua-thread: Split hlua_post_init() function in two parts
The goal is to allow execution of one main lua state per thread.

This function will be called for each initialized lua state, so
one per thread. The split transforms the lua state variable from
global to local.
2020-12-02 21:53:16 +01:00
Thierry Fournier
c93c15cf8c MINOR: lua-thread: Split hlua_load function in two parts
The goal is to allow execution of one main lua state per thread.

This function will be called once per thread, using different Lua
states. This patch prepares the work.
2020-12-02 21:53:16 +01:00
Thierry Fournier
75fc02956b MINOR: lua-thread: make hlua_ctx_init() get L from its caller
The goal is to allow execution of one main lua state per thread.

The function hlua_ctx_init() now gets the original lua state from
its caller. This allows the initialisation of lua_thread (coroutines)
from any master lua state.

The parent lua state is stored in the hlua struct.

This patch is a temporary transition, it will be modified later.
2020-12-02 21:53:16 +01:00
Thierry Fournier
1eac28f5fc MINOR: lua-thread: Split hlua_init() function in two parts
The goal is to allow execution of one main lua state per thread.

This is a preparative work in order to init more than one stack
in the lua-thread objective.
2020-12-02 21:53:16 +01:00
Thierry Fournier
ad5345fed7 MINOR: lua-thread: Replace embedded struct hlua_function by a pointer
The goal is to allow execution of one main lua state per thread.

Because this struct will be filled after the configuration parser, we
cannot copy the content. The actual state of the Haproxy code doesn't
justify this change, it is an update preparing next steps.
2020-12-02 21:53:16 +01:00
Thierry Fournier
92689e651e MINOR: lua-thread: Stop usage of struct hlua for the global lua state
The goal is to no longer use "struct hlua" with global main lua_state.

The usage of the "struct hlua" is no longer required. This patch replaces
this struct by another one.

Now, the usage of runtime Lua phase is separated from the start lua phase.
2020-12-02 21:53:16 +01:00
Thierry Fournier
4234dbd03b MINOR: lua-thread: Use NULL context for main lua state
The goal is to no longer use "struct hlua" with global main lua_state.

This patch returns NULL value when some code tries go get the hlua struct
associated with a task through hlua_gethlua(). This functions is useful
only during runtime because the struct hlua contains only runtime states.

Some Lua functions allowed to yield are called from init environment.
I'm not sure this is a good practice. Maybe it will be clever to
disallow calling this kind of functions.
2020-12-02 21:53:16 +01:00
Thierry Fournier
9eb3230b7c MINOR: lua-thread: hlua_ctx_renew() is never called with main gL lua state
The goal is no longer using "struct hlua" with global main lua_state.

if somewhere in the code, hlua_ctx_renew() is called with a global Lua
context, we have a serious bug. A crash is better than working with
this bug, so this patch remove a useless control.

In other way, this control were used during hlua_post_init() function.
The function hlua_post_init() used a call to the runtime hlua_ctx_resume()
function. This call no longer exists.
2020-12-02 21:53:16 +01:00
Thierry Fournier
670db24329 MEDIUM: lua-thread: make hlua_post_init() no longer use the runtime execution function
The goal is to no longer use "struct hlua" with global main lua_state.

The hlua_post_init() is executed during start phase, it does not require
yielding nor any advanced runtime error processing. Let's simplify this
by re-implementing the code using lower-level functions which directly
take a state and not an hlua anymore.
2020-12-02 21:53:16 +01:00
Thierry Fournier
3fb9e5133a MINOR: lua-thread: remove struct hlua from function hlua_prepend_path()
The goal is to no longer use "struct hlua" with global main lua_state
and directly take the state instead.

This patch removes the implicit dependency to this struct with
the function hlua_prepend_path()
2020-12-02 21:53:16 +01:00
Willy Tarreau
cdb53465f4 MEDIUM: lua-thread: use atomics for memory accounting
Let's switch memory accounting to atomics so that the allocator function
may safely be used from concurrent Lua states.

Given that this function is extremely hot on the call path, we try to
optimize it for the most common case, which is:
  - no limit
  - there's enough memory

The accounting is what is particuarly expensive in threads since all
CPUs compete for a cache line, so when the limit is not used, we don't
want to use accounting. However we need to preserve it during the boot
phase until we may parse a "tune.lua.maxmem" value. For this, we turn
the unlimited "0" value to ~0 at the end of the boot phase to mark the
definite end of accounting. The function then detects this value and
directly jumps to realloc() in this case.

When the limit is enforced however, we use a CAS to check and reserve
our share of memory, and we roll back on failure. The CAS is used both
for increments and decrements so that a single operation is enough to
update the counters.
2020-12-02 21:53:16 +01:00
Willy Tarreau
d36c7fa5ec MINOR: lua: simplify hlua_alloc() to only rely on realloc()
The function really has the semantics of a realloc() except that it
also passes the old size to help with accounting. No need to special
case the free or malloc, realloc does everything we need.
2020-12-02 21:53:16 +01:00
Emeric Brun
fdabf49548 BUG/MAJOR: ring: tcp forward on ring can break the reader counter.
If the session is not established, the applet handler could leave
with the applet detached from the ring. At next call, the attach
counter will be decreased again causing unpredectable behavior.

This patch should be backported on branches >=2.2
2020-12-02 20:17:19 +01:00
Frédéric Lécaille
fd1831499e BUG/MINOR: trace: Wrong displayed trace level
With commit a1f12746b ("MINOR: traces: add a new level "error" below
the "user" level") a new trace level was inserted, resulting in
shifting all exiting ones by one. But the levels reported in the
__trace() function were not updated accordingly, resulting in the
TRACE_LEVEL_DEVELOPER not to be properly reported anymore. This
patch fixes it by extending the number of levels to 6.

No backport is needed.
2020-12-02 17:44:40 +01:00
Remi Tricot-Le Breton
3243447f83 MINOR: cache: Add entry to the tree as soon as possible
When many concurrent requests targeting the same resource were seen, the
cache could sometimes be filled by too many partial responses resulting
in the impossibility to cache a single one of them. This happened
because the actual tree insertion happened only after all the payload of
every response was seen. So until then, every response was added to the
cache because none of the streams knew that a similar request/response
was already being treated.
This patch consists in adding the cache_entry as soon as possible in the
tree (right after the first packet) so that the other responses do not
get cached as well (if they have the same primary key).
A "complete" flag is also added to the cache_entry so that we know if
all the payload is already stored in the entry or if it is still being
processed.
2020-12-02 16:38:42 +01:00
Remi Tricot-Le Breton
8bb72aa82f MINOR: cache: Improve accept_encoding_normalizer
Turn the "Accept-Encoding" value to lower case before processing it.
Calculate the CRC on every token instead of a sorted concatenation of
them all (in order to avoir copying them) then XOR all the CRCs into a
single hash (while ignoring duplicates).
2020-12-02 16:32:54 +01:00
Thierry Fournier
f67442efdb BUG/MINOR: lua: warn when registering action, conv, sf, cli or applet multiple times
Lua allows registering multiple sample-fetches, converters, action, cli,
applet/services with the same name. This is absolutely useless since only
the first registration will be used. This patch sends a warning if the case
is encountered.

This pach could be backported until 1.8, with the 3 associated patches:
 - MINOR: actions: Export actions lookup functions
 - MINOR: actions: add a function returning a service pointer from its name
 - MINOR: cli: add a function to look up a CLI service description
2020-12-02 09:45:18 +01:00
Thierry Fournier
a51a1fd174 MINOR: cli: add a function to look up a CLI service description
This function will be useful to check if the keyword is already registered.
Also add a define for the max number of args.

This will be needed by a next patch to fix a bug and will have to be
backported.
2020-12-02 09:45:18 +01:00
Thierry Fournier
87e539906b MINOR: actions: add a function returning a service pointer from its name
This function simply calls action_lookup() on the private service_keywords,
to look up a service name. This will be used to detect double registration
of a same service from Lua.

This will be needed by a next patch to fix a bug and will have to be
backported.
2020-12-02 09:45:18 +01:00