Thierry FOURNIER [Tue, 10 Mar 2015 01:40:29 +0000 (02:40 +0100)]
MEDIUM: lua: make the functions hlua_gethlua() and hlua_sethlua() faster
Lua 5.3 provides an opaque space associated with each
coroutine stack. This patch uses this lot of memory to
store the "struct hlua *" associated pointer.
This patch makes the retrieval of the "struct hlua *"
associated struct faster because it replace a lookup in
a tree by an immediate access to the data.
This commit introduced a regression making it impossible to leave
process_session() during a forced yield because the analyser was always
set on the response even if not needed. The result was a busy loop
making haproxy spin at 100% without even polling anymore in case a
forced yield was performed.
The problem it tried to address (intercept response data from a request
analyser before forwarding) is not a trivial issue to address since
wakeups based on reads will not necessarily happen unless there's write
activity.
Anyway, if functions are attached specifically to a request or to a
response, it's for a reason. So for now let's be clear about the fact
that it's unreliable to try to process data from the opposite channel
until a better solution is found.
Willy Tarreau [Tue, 10 Mar 2015 14:25:54 +0000 (15:25 +0100)]
BUG/MAJOR: http: fix stats regression consecutive to HTTP_RULE_RES_YIELD
Commit bc4c1ac ("MEDIUM: http/tcp: permit to resume http and tcp custom actions")
unfortunately broke the stats applet by moving the clearing of the analyser bit
after processing the applet headers. It used to work only in HTTP/1.1 and not
in HTTP/1.0. This is 1.6-specific, no backport is needed.
Thierry FOURNIER [Tue, 10 Mar 2015 00:55:01 +0000 (01:55 +0100)]
BUG/MEDIUM: buffer: one byte miss in buffer free space check
Space is not avalaible only if the end of the data inserted
is strictly greater than the end of buffer. If these two value
are equal, the space is avamaible.
BUG/MINOR: lua: sockets receive behavior doesn't follows the specs
Specs says that the receive() function with an argument "*l"
must return a line without the final "\n" ( or without "\r\n").
This patch removes these two final bytes.
BUG/MEDIUM: lua: sockets don't have buffer to write data
When we try to write data in a session from another session, the "req"
buffer is not allowed. This patch try to allocate the buffer. The session
wait if the buffer is not yet avalaible.
BUG/MINOR: log: segfault if there are no proxy reference
The HAProxy API allow to send log without defined proxy (it
set to the NULL value). An incomplete test if done to choose
the log tag and an invalid pointer is dereferenced.
BUG/MINOR: lua: check buffers before initializing socket
When a socket is initilized in the body context, a segfaut is generated
because the memory pools are not initilized. This atch check if these
memory pool are initialized.
The function buffer_contig_space() returns the contiguous space avalaible
to add data (at the end of the input side) while the function
hlua_channel_send_yield() needs to insert data starting at p. Here we
introduce a new function bi_space_for_replace() which returns the amount
of space that can be inserted at the head of the input side with one of
the buffer_replace* functions.
This patch proposes a function that returns the space avalaible after buf->p.
The request action can't handle the reponse trafic because its
automatically forwarded. The forard with CHN_INFINITE_FORWARD
is set because any anamizers are registered on the response
channel.
This patch automatically register the request analyzer on the
reponse channel when its yield. This prevent the automatic
tranfer of the response bytes.
BUG/MAJOR: lua: some function are not yieldable, the forced yield causes errors
The hook function called each nth Lua instructions just
do a yield. Sometimes this yield is not allowed, because
some functions are not compatible.
The Lua-5.3 permits to known if the yield is avalaible with
the function lua_isyieldable().
If the processing is interrupted in non yieldable state,
we try to execute a yield asap. The yield will be may
available at the end of the non-yieldable currently
executed function. So, we require interrupt at the end
of the current function.
But, Lua cannot yield when its returning from a function,
so, we can fix the interrupt hook to 1 instruction,
expecting that the function is finnished.
During this time, the execution timeout is always checked.
MEDIUM: lua: use the Lua-5.3 version of the library
The Lua-5.3 version of the library adds a required function to fix
a bug with the forced-yield system.
This patch permits to build with the Lua-5.3 library. Main changes
are:
- "unsigned" type disappear to be replaced by signed type,
- prototype of the yield function callback changes.
BUG/MEDIUM: lua: many errors when we try to send data with the channel API
First we allow to use the reserved size to write the data that
will be sent. The reserved size remain guaranty because the
writed data will be sent quickly and the reserved room we be
again avalaible.
This permits to guaranty that the function send always have
avalaible space to send data (except if it cannot connect to
the server).
The function buffer_replace2 works only on contiguous buffer.
This patch also detects if the required size is contiguous.
If it not the case we realign the buffer.
BUG/MEDIUM: lua: the Lua process is not waked up after sending data on requests side
If we are writing in the request buffer, we are not waked up
when the data are forwarded because it is useles. The request
analyzers are waked up only when data is incoming. So, if the
request buffer is full, we set the WAKE_ON_WRITE flag.
Before this patch, each yield in a Lua action set a flags to be
waked up when some activity were detected on the response channel.
This behavior causes loop in the analyzer process.
This patch set the wake up on response buffer activity only if we
really want to be waked up on this activity.
BUG/MEDIUM: lua: reset flags before resuming execution
This patch reset the flags except th run flag before resuming
the Lua execution. If this initialisation is not done, some
flags can remain at the end of the Lua execution and give bad
informations.
BUG/MINOR: lua: set buffer if it is nnot avalaible.
Check if the buffer is avalaible because HAProxy doesn't allocate
the request buffer if its not required. Sometimes, the Lua need to
write some data to the server before that the client send his data.
BUG/MEDIUM: lua: the execution timeout is ignored in yield case
This patch check the expiration of the execution timeout for each
yield source, and test also the execution timeout before resuming
the execution of the Lua code.
Commit 501260b ("MEDIUM: task: always ensure that the run queue is
consistent") introduced a skew in the scheduler : if a negatively niced
task is woken up, it can be inserted prior to the current index and will
be skipped as long as there is some activity with less prioritary tasks.
The immediate effect is that it's not possible to get access to the stats
under full load until the load goes down.
This is because the rq_next constantly evolves within more recent
positions. The fix is simple, __task_wakeup() must empty rq_next. The
sad thing is that this issue was fixed during development and missed
during the commit. No backport is needed, this is purely 1.6 stuff.
MEDIUM: lua: interrupt the Lua execution for running other process
This patch permits to interrupt the Lua execution each n# of
instructions. It is useful for controling the execution time
of an Lua code, and permits at the HAProxy schedule to process
some others tasks waiting execution.
This flag indicate that the current yield is returned by the Lua
execution task control. If this flag is set, the current task may
quit but will be set in the run queue to be re-executed immediatly.
This patch modify the "hlua_yieldk()" function, it adds an argument
that contain a field containing yield options.
MEDIUM: lua: each yielding function returns a wake up time.
This is used to ensure that the task doesn't become a zombie
when the Lua returns a yield. The yield wrapper ensure that an
timer used for waking up the task will be set.
The timer is reseted to TICK_ETERNITY if the Lua execution is
done.
MINOR: lua: set skeleton for Lua execution expiration
This first patch permits to cofigure the Lua execution exipiration.
This expiration is configured but it is not yet avalaible, it will
be add in a future patch.
MINOR: lua: use bitfield and macro in place of integer and enum
In the future, the lua execution must return scheduling informations.
We want more than one flag, so I convert an integer used with an
enum into an interer used as bitfield.
BUG/MAJOR: lua: send function fails and return bad bytes
In some cases the Lua "send" function fails. This is caused by the
return of "buffer_replace2()" is not tested. I checked avalaible space
in the buffer and I supposed than "buffer_replace2()" took all the
data. In some cases, "buffer_replace2()" cannot take the incoming
data, it returns the amount of data copied.
This patch check the amount of data really copied by "buffer_replace2()"
and advance the buffer with taking this value in account.
Cyril Bonté [Tue, 3 Mar 2015 22:26:14 +0000 (23:26 +0100)]
BUILD/CLEANUP: systemd: avoid a warning due to mixed code and declaration
Gcc complains because the systemd wrapper mixed code and declaration :
"warning: ISO C90 forbids mixed declarations and code
[-Wdeclaration-after-statement]".
Cyril Bonté [Tue, 3 Mar 2015 22:13:03 +0000 (23:13 +0100)]
BUILD: try to automatically detect the Lua library name
Depending on the distribution, the Lua library can have different names.
Some distributions will require -llua5.2, others -llua52, and other systems may
require -llua.
Now, the Makefile will try to guess the library name, in order of priority :
"lua5.2", "lua52", or "lua".
Cyril Bonté [Sun, 1 Mar 2015 23:08:41 +0000 (00:08 +0100)]
BUG/MEDIUM: lua: segfault when calling haproxy sample fetches from lua
When a Lua script calls an internal haproxy sample fetch, it may segfault in
some conditions :
- when a fetch has no argument,
- when there is no room left to store the special type ARGT_STOP in the argument
list (this one shouldn't happen currently as there isn't any sample fetch with
enough arguments to fill the allocated buffer).
Example of Lua code which reproduces a segfault :
core.register_fetches("segfault", function(txn, ...)
return txn.req_ver(txn)
end)
Cyril Bonté [Sun, 1 Mar 2015 23:08:40 +0000 (00:08 +0100)]
MINOR: lua: add a compilation error message when compiled with an incompatible version
haproxy Lua support begins with Lua 5.2. In order to ease the diagnostic on
compilation error, a preprocessor error is added when an incompatible version
is used.
The compatibility is determined by the presence of LUA_VERSION_NUM and its
magic value (502 for Lua 5.2.x).
Cyril Bonté [Sun, 1 Mar 2015 23:08:39 +0000 (00:08 +0100)]
MINOR: report the Lua version in -vv
As of the other libraries used by haproxy, it can be useful to display the Lua
version used at compilation time.
A new line is added to "haproxy -vv", which shows if Lua is supported by the
binary, and with which version it was compiled.
Willy Tarreau [Fri, 27 Feb 2015 15:38:20 +0000 (16:38 +0100)]
BUILD: lua: cleanup many mixed occurrences declarations & code
The code was a bit of a pain to follow because of this, especially
when some of it heavily relies on longjmp... This refreshing makes
it slightly easier to read.
Thierry FOURNIER [Tue, 17 Feb 2015 14:01:59 +0000 (15:01 +0100)]
MINOR: lua: core: can yield an execution stack
This patch provides a yield function. This function permits to
give back the hand at the HAProxy scheduler. It is used when the
lua processing consumes a lot of time.
The channel class permits manipulation of channels. A channel is
an FIFO buffer between the client and the server. This class provides
function to read, write, forward, destroy and alter data between
the input and the ouput of the buffer.
Thierry FOURNIER [Mon, 16 Feb 2015 18:27:16 +0000 (19:27 +0100)]
MEDIUM: lua: socket: add "socket" class for TCP I/O
This patch adds the TCP I/O functionnality. The class implemented
provides the same functions than the "lua socket" project. This
make network compatibility with another LUA project. The documentation
is located here:
Thierry FOURNIER [Mon, 16 Feb 2015 18:43:25 +0000 (19:43 +0100)]
MINOR: lua: core: add sleep functions
This version of sleep is based on a coroutine. A sleeping
task is started and a signal is registered. This sleep version
must disapear to be replaced by a version using the internal
timers.
Thierry FOURNIER [Mon, 16 Feb 2015 19:21:12 +0000 (20:21 +0100)]
MINOR: lua: register and execute converters in LUA
This patch permits to write LUA converters. Note that
all the converters declared trough LUA are automatically
prefixed by "lua.".
The Lua converters needs the current session to be executed,
but the writed and executed Lua code must be static and
contextless. The TXN object is not created for the converters.
Thierry FOURNIER [Mon, 16 Feb 2015 19:14:51 +0000 (20:14 +0100)]
MINOR: lua: txn: import existing sample-fetches in the class TXN
This patch adds the browsing of all the HAProxy fetches and
create associated LUA functions. The HAProxy internal fetches
can be used in LUA trough the class "TXN".
Note that the symbols "-", "+" and "." in the name of current
sample fetch are rewrited as "_" in LUA because ".", "-" and "+"
are operators.
Thierry FOURNIER [Wed, 25 Feb 2015 10:43:21 +0000 (11:43 +0100)]
MINOR: lua: add shared context in the lua stack
The shared context is a global reference dedicated to one Lua stack.
Even if the TXN is not required, the shared context it is associated
with a TXN object. In fact, the shared has no sense outside a TXN
context
Thierry FOURNIER [Fri, 23 Jan 2015 11:08:30 +0000 (12:08 +0100)]
MINOR: lua: post initialisation bindings
This system permits to execute some lua function after than HAProxy
complete his initialisation. These functions are executed between
the end of the configuration parsing and check and the begin of the
scheduler.
Thierry FOURNIER [Fri, 23 Jan 2015 10:08:20 +0000 (11:08 +0100)]
MEDIUM: lua: "com" signals
This system permits to send signals between lua tasks. A main lua stack can
register the signal in a coprocess. When the coprocess finish his job, it
send a signal, and the associated task is wakes. If the main lua execution
stack stop (with or without errors), the list or pending signals is purged.
Thierry FOURNIER [Fri, 23 Jan 2015 13:06:13 +0000 (14:06 +0100)]
MEDIUM: lua: lua integration in the build and init system.
This is the first step of the lua integration. We add the useful
files in the HAProxy project. These files contains the main
includes, the Makefile options and empty initialisation function.
Is is the LUA skeleton.
Thierry FOURNIER [Mon, 16 Feb 2015 18:26:48 +0000 (19:26 +0100)]
MINOR: channel: functions to get data from a buffer without copy
We now have functions to retrieve one block and one line from
either the input or the output part of a buffer. They return
up to two (pointer,length) values in case the buffer wraps.
Thierry FOURNIER [Wed, 25 Feb 2015 12:36:14 +0000 (13:36 +0100)]
MEDIUM: http/tcp: permit to resume http and tcp custom actions
Later, the processing of some actions needs to be interrupted and resumed
later. This patch permit to resume the actions. The actions that needs
to run with the resume mode are not yet avalaible. It will be soon with
Lua patches. So the code added by this patch is untestable for the moment.
The list of "tcp_exec_req_rules" cannot resme because is called by the
unresumable function "accept_session".
Thierry FOURNIER [Wed, 25 Feb 2015 12:51:19 +0000 (13:51 +0100)]
MEDIUM: http: change the code returned by the response processing rule functions
Actually, this function returns a pointer on the rule that stop
the evaluation of the rule list. Later we integrate the possibility
of interrupt and resue the processsing of some actions. The current
response mode is not sufficient to returns the "interrupt" information.
The pointer returned is never used, so I change the return type of
this function by an enum. With this enum, the function is ready to
return the "interupt" value.
Thierry FOURNIER [Fri, 12 Dec 2014 18:41:33 +0000 (19:41 +0100)]
MEDIUM: tcp: add register keyword system.
This patch introduces an action keyword registration system for TCP
rulesets similar to what is available for HTTP rulesets. This sytem
will be useful with lua.
Thierry FOURNIER [Mon, 23 Feb 2015 14:11:11 +0000 (15:11 +0100)]
MINOR: converters: give the session pointer as converter argument
Some usages of the converters need to know the attached session. The Lua
needs the session for retrieving his running context. This patch adds
the "session" as an argument of the converters prototype.
Thierry FOURNIER [Thu, 26 Feb 2015 09:40:09 +0000 (10:40 +0100)]
MEDIUM: channel: wake up any request analyzer on response activity
This behavior is already existing for the "WAIT_HTTP" analyzer,
this patch just extends the system to any analyzer that would
be waked up on response activity.
Thierry FOURNIER [Wed, 14 Jan 2015 10:31:49 +0000 (11:31 +0100)]
MEDIUM: protocol: automatically pick the proto associated to the connection.
When the destination IP is dynamically set, we can't use the "target"
to define the proto. This patch ensures that we always use the protocol
associated with the address family. The proto field was removed from
the server and check structs.
Thierry FOURNIER [Mon, 15 Dec 2014 12:26:01 +0000 (13:26 +0100)]
MAJOR: poll: only rely on wake_expired_tasks() to compute the wait delay
Actually, HAProxy uses the function "process_runnable_tasks" and
"wake_expired_tasks" to get the next task which can expires.
If a task is added with "task_schedule" or other method during
the execution of an other task, the expiration of this new task
is not taken into account, and the execution of this task can be
too late.
Actualy, HAProxy seems to be no sensitive to this bug.
This fix moves the call to process_runnable_tasks() before the timeout
calculation and ensures that all wakeups are processed together. Only
wake_expired_tasks() needs to return a timeout now.
Nenad Merdanovic [Fri, 27 Feb 2015 18:56:49 +0000 (19:56 +0100)]
MEDIUM: Add support for configurable TLS ticket keys
Until now, the TLS ticket keys couldn't have been configured and
shared between multiple instances or multiple servers running HAproxy.
The result was that if a request got a TLS ticket from one instance/server
and it hits another one afterwards, it will have to go through the full
SSL handshake and negotation.
This patch enables adding a ticket file to the bind line, which will be
used for all SSL contexts created from that bind line. We can use the
same file on all instances or servers to mitigate this issue and have
consistent TLS tickets assigned. Clients will no longer have to negotiate
every time they change the handling process.
Simon Horman [Thu, 26 Feb 2015 02:26:17 +0000 (11:26 +0900)]
BUG/MEDIUM: Do not consider an agent check as failed on L7 error
As failure to connect to the agent check is not sufficient to mark it as
failed it stands to reason that an L7 error shouldn't either.
Without this fix if an L7 error occurs, for example of connectivity to the
agent is lost immediately after establishing a connection to it, then the
agent check will be considered to have failed and thus may end up with zero
health. Once this has occurred if the primary health check also reaches
zero health, which is likely if connectivity to the server is lost, then
the server will be marked as down and not be marked as up again until a
successful agent check occurs regardless of the success of any primary
health checks.
This behaviour is not correct as a failed agent check should never cause a
server to be marked as down or by extension continue to be marked as down.
Willy Tarreau [Mon, 23 Feb 2015 15:07:01 +0000 (16:07 +0100)]
MEDIUM: task: always ensure that the run queue is consistent
As found by Thierry Fournier, if a task manages to kill another one and
if this other task is the next one in the run queue, we can do whatever
including crashing, because the scheduler restarts from the saved next
task. For now, there is no such concept of a task killing another one,
but with Lua it will come.
A solution consists in always performing the lookup of the first task in
the scheduler's loop, but it's expensive and costs around 2% of the
performance.
Another solution consists in keeping a global next run queue node and
ensuring that when this task gets removed, it updates this pointer to
the next one. This allows to simplify the code a bit and in the end to
slightly increase the performance (0.3-0.5%). The mechanism might still
be usable if we later migrate to a multi-threaded scheduler.
Thierry FOURNIER [Tue, 17 Feb 2015 15:09:00 +0000 (16:09 +0100)]
BUG/MINOR: ARG6 and ARG7 don't fit in a 32 bits word
The patch "MEDIUM: args: increase arg type to 5 bits and limit arg count
to 5" (dbc79d0a) increased the number of types supported, but forgot to
remove the ARG6/ARG7 macros.
Willy Tarreau [Fri, 20 Feb 2015 12:55:29 +0000 (13:55 +0100)]
MINOR: http: add the new sample fetches req.hdr_names and res.hdr_names
These new sample fetches retrieve the list of header names as they appear
in the request or response. This can be used for debugging, for statistics
as well as an aid to better detect the presence of proxies or plugins on
some browsers, which alter the request compared to a regular browser by
adding or reordering headers.
Willy Tarreau [Sat, 14 Feb 2015 13:14:57 +0000 (14:14 +0100)]
BUG/MAJOR: peers: initialize s->buffer_wait when creating the session
Commit bf883e0 ("MAJOR: session: implement a wait-queue for sessions who
need a buffer") introduced in 1.6 forgot to initialize the buffer_wait
list when the session is initiated by an applet for a peer, resulting in
a crash. Thanks to Chris Kopp for reporting the issue.