]> git.ipfire.org Git - thirdparty/haproxy.git/log
thirdparty/haproxy.git
6 years agoMEDIUM: htx: 1xx messages are now part of the final reponses
Christopher Faulet [Fri, 17 May 2019 06:37:28 +0000 (08:37 +0200)] 
MEDIUM: htx: 1xx messages are now part of the final reponses

1xx informational messages (all except 101) are now part of the HTTP reponse,
semantically speaking. These messages are not followed by an EOM anymore,
because a final reponse is always expected. All these parts can also be
transferred to the channel in same time, if possible. The HTX response analyzer
has been update to forward them in loop, as the legacy one.

6 years agoMINOR: htx: Be sure to xfer all headers in one time in htx_xfer_blks()
Christopher Faulet [Thu, 16 May 2019 09:30:31 +0000 (11:30 +0200)] 
MINOR: htx: Be sure to xfer all headers in one time in htx_xfer_blks()

In the function htx_xfer_blks(), we take care to transfer all headers in one
time. When the current block is a start-line, we check if there is enough space
to transfer all headers too. If not, and if the destination is empty, a parsing
error is reported on the source.

The H2 multiplexer is the only one to use this function. When a parsing error is
reported during the transfer, the flag CS_FL_EOI is also set on the conn_stream.

6 years agoMINOR: mux-h1: Set hdrs_bytes on the SL when an HTX message is produced
Christopher Faulet [Wed, 15 May 2019 13:54:39 +0000 (15:54 +0200)] 
MINOR: mux-h1: Set hdrs_bytes on the SL when an HTX message is produced

6 years agoMINOR: h2/htx: Set hdrs_bytes on the SL when an HTX message is produced
Christopher Faulet [Wed, 15 May 2019 13:53:20 +0000 (15:53 +0200)] 
MINOR: h2/htx: Set hdrs_bytes on the SL when an HTX message is produced

6 years agoMINOR: htx: Add a field to set the memory used by headers in the HTX start-line
Christopher Faulet [Wed, 15 May 2019 12:56:47 +0000 (14:56 +0200)] 
MINOR: htx: Add a field to set the memory used by headers in the HTX start-line

The field hdrs_bytes has been added in the structure htx_sl. It should be used
to set how many bytes are help by all headers, from the start-line to the
corresponding EOH block. it must be set to -1 if it is unknown.

6 years agoMINOR: mux-h2/htx: Support zero-copy when possible in h2_rcv_buf()
Christopher Faulet [Wed, 15 May 2019 08:07:59 +0000 (10:07 +0200)] 
MINOR: mux-h2/htx: Support zero-copy when possible in h2_rcv_buf()

If the channel's buffer is empty and the message is small enough, we can swap
the H2S buffer with the channel one.

6 years agoMINOR: connection: Remove the unused flag CO_RFL_KEEP_RSV
Christopher Faulet [Tue, 14 May 2019 20:47:37 +0000 (22:47 +0200)] 
MINOR: connection: Remove the unused flag CO_RFL_KEEP_RSV

6 years agoMINOR: stream-int: Don't use the flag CO_RFL_KEEP_RSV anymore in si_cs_recv()
Christopher Faulet [Tue, 14 May 2019 20:46:41 +0000 (22:46 +0200)] 
MINOR: stream-int: Don't use the flag CO_RFL_KEEP_RSV anymore in si_cs_recv()

Because the channel_recv_max() always return the right value, for HTX and legacy
streams, we don't need to set this flag. The multiplexer don't use it anymore.

6 years agoMINOR: mux-h2: Use the count value received from the SI in h2_rcv_buf()
Christopher Faulet [Tue, 14 May 2019 20:44:43 +0000 (22:44 +0200)] 
MINOR: mux-h2: Use the count value received from the SI in h2_rcv_buf()

Now, the SI calls h2_rcv_buf() with the right count value. So we can rely on
it. Unlike the H1 multiplexer, it is fairly easier for the H2 multiplexer
because the HTX message already exists, we only transfer blocks from the H2S to
the channel. And this part is handled by htx_xfer_blks().

6 years agoMEDIUM: mux-h1: Use the count value received from the SI in h1_rcv_buf()
Christopher Faulet [Fri, 17 May 2019 13:35:33 +0000 (15:35 +0200)] 
MEDIUM: mux-h1: Use the count value received from the SI in h1_rcv_buf()

Now, the SI calls h1_rcv_buf() with the right count value. So we can rely on
it. During the parsing, we now really respect this value to be sure to never
exceed it. To do so, once headers are parsed, we should estimate the size of the
HTX message before copying data.

6 years agoBUG/MINOR: htx: Change htx_xfer_blk() to also count metadata
Christopher Faulet [Thu, 16 May 2019 09:29:13 +0000 (11:29 +0200)] 
BUG/MINOR: htx: Change htx_xfer_blk() to also count metadata

This patch makes the function more accurate. Thanks to the function
htx_get_max_blksz(), the transfer of data has been simplified. Note that now the
total number of bytes copied (metadata + payload) is returned. This slighly
change how the function is used in the H2 multiplexer.

6 years agoMINOR: htx: Add function htx_get_max_blksz()
Christopher Faulet [Thu, 16 May 2019 09:16:39 +0000 (11:16 +0200)] 
MINOR: htx: Add function htx_get_max_blksz()

This functions should be used to get the maximum size for a block, not exceeding
the max amount of bytes passed in argument. Thus max may be set to -1 to have no
limit.

6 years agoMINOR: channel/htx: Call channel_htx_recv_max() from channel_recv_max()
Christopher Faulet [Tue, 14 May 2019 20:14:03 +0000 (22:14 +0200)] 
MINOR: channel/htx: Call channel_htx_recv_max() from channel_recv_max()

When channel_recv_max() is called for an HTX stream, we fall back on the HTX
version. This function is called from si_cs_recv(). This will let us pass the
max amount of bytes to read to HTX multiplexers.

6 years agoMEDIUM: http/htx: Perform analysis relatively to the first block
Christopher Faulet [Mon, 13 May 2019 13:27:23 +0000 (15:27 +0200)] 
MEDIUM: http/htx: Perform analysis relatively to the first block

The first block is the start-line, if defined. Otherwise it the head of the HTX
message. So now, during HTTP analysis, lookup are all done using the first block
instead of the head. Concretely, for now, it is the same because only one HTTP
message is stored at a time in an HTX message. 1xx informational messages are
handled separatly from the final reponse and from each other. But it will make
sense when the 1xx informational messages and the associated final reponse will
be stored in the same HTX message.

6 years agoMINOR: http/htx: Use sl_pos directly to replace the start-line
Christopher Faulet [Mon, 13 May 2019 13:22:59 +0000 (15:22 +0200)] 
MINOR: http/htx: Use sl_pos directly to replace the start-line

Since the HTX start-line is now referenced by position instead of by its payload
address, it is fairly easier to replace it. No need to search the rigth block to
find the start-line comparing the payloads address. It just enough to get the
block at the position sl_pos.

6 years agoCLEANUP: htx: Remove unused function htx_get_stline()
Christopher Faulet [Mon, 13 May 2019 12:55:59 +0000 (14:55 +0200)] 
CLEANUP: htx: Remove unused function htx_get_stline()

6 years agoMINOR: htx: Replace the function http_find_stline() by http_get_stline()
Christopher Faulet [Mon, 13 May 2019 12:41:27 +0000 (14:41 +0200)] 
MINOR: htx: Replace the function http_find_stline() by http_get_stline()

Now, we only return the start-line. If not found, NULL is returned. No lookup is
performed and the HTX message is no more updated. It is now the caller
responsibility to update the position of the start-line to the right value. So
when it is not found, i.e sl_pos is set to -1, it means the last start-line has
been already processed and the next one has not been inserted yet.

It is mandatory to rely on this kind of warranty to store 1xx informational
responses and final reponse in the same HTX message.

6 years agoMINOR: mux-h2/htx: Get the start-line from the head when HEADERS frame is built
Christopher Faulet [Mon, 13 May 2019 09:55:10 +0000 (11:55 +0200)] 
MINOR: mux-h2/htx: Get the start-line from the head when HEADERS frame is built

in the H2 multiplexer, when a HEADERS frame is built before sending it, we have
the warranty the start-line is the head of the HTX message. It is safer to rely
on this fact than on the sl_pos value. For now, it's safe to use sl_pos in muxes
because HTTP 1xx messages are considered as full messages in HTX and only one
HTTP message can be stored at a time in HTX. But we are trying to handle 1xx
messages as a part of the reponse message. In this way, an HTTP reponse will be
the sum of all 1xx informational messages followed by the final response. So it
will be possible to have several start-line in the same HTX message. And the
sl_pos will point to the first unprocessed start-line from the analyzers point
of view.

6 years agoMINOR: htx: Add functions to get the first block of an HTX message
Christopher Faulet [Mon, 13 May 2019 09:36:27 +0000 (11:36 +0200)] 
MINOR: htx: Add functions to get the first block of an HTX message

It is the first block relatively to the start-line. So it is the start-line if
its position is set (sl_pos != -1), otherwise it is the head. The functions
htx_get_first() and htx_get_first_blk() can be used to get it.  This change is
mandatory to consider 1xx informational messages as part of a response.

6 years agoMINOR: htx: Store start-line block's position instead of address of its payload
Christopher Faulet [Tue, 30 Apr 2019 16:08:26 +0000 (18:08 +0200)] 
MINOR: htx: Store start-line block's position instead of address of its payload

Nothing much to say. This change is just mandatory to consider 1xx informational
messages as part of a response.

6 years agoMINOR: htx: Store the head position instead of the wrap one
Christopher Faulet [Tue, 30 Apr 2019 15:55:45 +0000 (17:55 +0200)] 
MINOR: htx: Store the head position instead of the wrap one

The head of an HTX message is heavily used whereas the wrap position is only
used when a block is added or removed. So it is more logical to store the head
position in the HTX message instead of the wrap one. The wrap position can be
easily deduced. To get it, the new function htx_get_wrap() may be used.

6 years agoMINOR: htx: Move the macro IS_HTX_STRM() in proto/stream.h
Christopher Faulet [Tue, 14 May 2019 20:05:28 +0000 (22:05 +0200)] 
MINOR: htx: Move the macro IS_HTX_STRM() in proto/stream.h

The macro IS_HTX_STRM() only relies on stream flags. So move it in
proto/stream.h.

6 years agoMINOR: htx: Remove the macro IS_HTX_SMP() and always use IS_HTX_STRM() instead
Christopher Faulet [Tue, 14 May 2019 20:04:36 +0000 (22:04 +0200)] 
MINOR: htx: Remove the macro IS_HTX_SMP() and always use IS_HTX_STRM() instead

The macro IS_HTX_SMP() is only used at a place, in a context where the stream
always exists. So, we can remove it to use IS_HTX_STRM() instead.

6 years agoMEDIUM: config: now alert when two servers have the same name
Willy Tarreau [Mon, 27 May 2019 17:31:06 +0000 (19:31 +0200)] 
MEDIUM: config: now alert when two servers have the same name

We've been emitting warnings for over 5 years (since 1.5-dev22) about
configs accidently carrying multiple servers with the same name in the
same backend, and this starts to cause some real trouble in dynamic
environments since it's still very difficult to accurately process
a state-file and we still can't transport a server's name over the
peers protocol because of this.

It's about time to force users to fix their configs if they still
hadn't given that there is zero technical justification for doing this,
beyond the "yyp" (or copy-paste accident) when editing the config.

The message remains as clear as before, indicating the file and lines
of the conflict so that the user can easily fix it.

6 years agoBUG/MEDIUM: threads: fix double-word CAS on non-optimized 32-bit platforms
Willy Tarreau [Mon, 27 May 2019 15:37:20 +0000 (17:37 +0200)] 
BUG/MEDIUM: threads: fix double-word CAS on non-optimized 32-bit platforms

On armv7 haproxy doesn't work because of the fixes on the double-word
CAS. There are two issues. The first one is that the last argument in
case of dwcas is a pointer to the set of value and not a value ; the
second is that it's not enough to cast the data as (void*) since it will
be a single word. Let's fix this by using the pointers as an array of
long. This was tested on i386, armv7, x86_64 and aarch64 and it is now
fine. An alternate approach using a struct was attempted as well but it
used to produce less optimal code.

This fix must be backported to 1.9. This fixes github issue #105.

Cc: Olivier Houchard <ohouchard@haproxy.com>
6 years agoBUG/MEDIUM: queue: fix the tree walk in pendconn_redistribute.
Willy Tarreau [Mon, 27 May 2019 06:10:11 +0000 (08:10 +0200)] 
BUG/MEDIUM: queue: fix the tree walk in pendconn_redistribute.

In pendconn_redistribute() we scan the queue using eb32_next() on the
node we've just deleted, which is wrong since the node is not in the
tree anymore, and it could dereference one node that has already been
released by another thread. Note that we cannot use eb32_first() in the
loop here instead because we need to skip pendconns having SF_FORCE_PRST.
Instead, let's keep a copy of the next node before deleting it.

In addition, the pendconn retrieved there is wrong, it uses &node as
the pointer instead of node, resulting in very quick crashes when the
server list is scanned.

Fortunately this only happens when "option redispatch" is used in
conjunction with "maxconn" on server lines, "cookie" for the stickiness,
and when a server goes down with entries in its queue.

This bug was introduced by commit 0355dabd7 ("MINOR: queue: replace
the linked list with a tree") so the fix must be backported to 1.9.

6 years agoBUG/MAJOR: lb/threads: make sure the avoided server is not full on second pass
Willy Tarreau [Mon, 27 May 2019 08:17:05 +0000 (10:17 +0200)] 
BUG/MAJOR: lb/threads: make sure the avoided server is not full on second pass

In fwrr_get_next_server(), we optionally pass a server to avoid. It
usually points to the current server during a redispatch operation. If
this server is usable, an "avoided" pointer is set and we continue to
look for another server. If in the end no other server is found, then
we fall back to this avoided one, which is still better than nothing.

The problem that may arise with threads is that in the mean time, this
avoided server might have received extra connections and might not be
usable anymore. This causes it to be queued a second time in the "full"
list and the loop to search for a server again, ending up on this one
again and so on.

This patch makes sure that we break out of the loop when we have to
pick the avoided server. It's probably what the code intended to do
as the current break statement causes fwrr_update_position() and
fwrr_dequeue_srv() to be called again on the avoided server.

It must be backported to 1.9 and 1.8, and seems appropriate for older
versions though it's unclear what the impact of this bug might be
there since the race doesn't exist and we're left with the double
update of the server's position.

6 years agoMINOR: cli/activity: add 3 general purpose counters in development mode
Willy Tarreau [Mon, 27 May 2019 05:03:38 +0000 (07:03 +0200)] 
MINOR: cli/activity: add 3 general purpose counters in development mode

The unused fd_del and fd_skip were being abused during debugging sessions
as general purpose event counters. With their removal, let's officially
have dedicated counters for such use cases. These counters are called
"ctr0".."ctr2" and are listed at the end when DEBUG_DEV is set.

6 years agoMINOR: cli/activity: remove "fd_del" and "fd_skip" from show activity
Willy Tarreau [Mon, 27 May 2019 04:59:14 +0000 (06:59 +0200)] 
MINOR: cli/activity: remove "fd_del" and "fd_skip" from show activity

These variables are never set anymore and were always reported as zero.

6 years agoBUILD: ssl: fix latest LibreSSL reg-test error
Ilya Shipitsin [Sat, 25 May 2019 14:30:50 +0000 (19:30 +0500)] 
BUILD: ssl: fix latest LibreSSL reg-test error

starting with OpenSSL 1.0.0 recommended way to disable compression is
using SSL_OP_NO_COMPRESSION when creating context.

manipulations with SSL_COMP_get_compression_methods, sk_SSL_COMP_num
are only required for OpenSSL < 1.0.0

6 years agoBUILD: connections: shut up gcc about impossible out-of-bounds warning
Willy Tarreau [Sun, 26 May 2019 09:50:08 +0000 (11:50 +0200)] 
BUILD: connections: shut up gcc about impossible out-of-bounds warning

Since commit 88698d9 ("MEDIUM: connections: Add a way to control the
number of idling connections.") when building without threads, gcc
complains that the operations made on the idle_orphan_conns[] list is
out of bounds, which is always false since 1) <i> can only equal zero,
and 2) given it's equal to <tid> we never even enter the loop. But as
usual it thinks it knows better, so let's mask the origin of this <i>
value to shut it up. Another solution consists in making <i> unsigned
and adding an explicit range check.

6 years agoMAJOR: mux-h2: switch to next mux buffer on buffer full condition.
Willy Tarreau [Sun, 26 May 2019 08:08:28 +0000 (10:08 +0200)] 
MAJOR: mux-h2: switch to next mux buffer on buffer full condition.

Now when we fail to send because the mux buffer is full, before giving
up and marking MFULL, we try to allocate another buffer in the mux's
ring to try again. Thanks to this (and provided there are enough buffers
allocated to the mux's ring), a single stream picked in the send_list
cannot steal all the mux's room at once. For this, we expand the ring
size to 31 buffers as it seems to be optimal on benchmarks since it
divides the number of context switches by 3. It will inflate each H2
conn's memory by 1 kB.

The bandwidth is now much more stable. Prior to this, it a test on
h2->h1 with very large objects (1 GB), a few tens of connections and
a few tens of streams per connection would show a varying performance
between 34 and 95 Gbps on 2 cores/4 threads, with h2_snd_buf() stopped
on a buffer full condition between 300000 and 600000 times per second.
Now the performance is constantly between 88 and 96 Gbps. Measures show
that buffer full conditions are met around only 159 times per second
in this case, or rougly 2000 to 4000 times less often.

6 years agoMINOR: mux-h2: report the mbuf's head and tail in "show fd"
Willy Tarreau [Sun, 26 May 2019 09:32:27 +0000 (11:32 +0200)] 
MINOR: mux-h2: report the mbuf's head and tail in "show fd"

It's useful to know how the mbuf spans over the whole area and to have
access to the first and last ones, so let's dump just this.

6 years agoCLEANUP: mux-h2: consistently use a local variable for the mbuf
Willy Tarreau [Sun, 26 May 2019 08:05:50 +0000 (10:05 +0200)] 
CLEANUP: mux-h2: consistently use a local variable for the mbuf

This makes the code more readable and reduces the calls to br_tail().
In addition, all calls to h2_get_buf() are now made via this local
variable, which should significantly help for retries.

6 years agoMEDIUM: mux-h2: make the send() function iterate over all mux buffers
Willy Tarreau [Sun, 26 May 2019 07:49:17 +0000 (09:49 +0200)] 
MEDIUM: mux-h2: make the send() function iterate over all mux buffers

Now send() uses a loop to iterate over all buffers to be sent. These
buffers are released and deleted from the vector once completely sent.
If any buffer gets released, offer_buffers() is called to wake up some
waiters.

6 years agoMINOR: mux-h2: introduce h2_release_mbuf() to release all buffers in the mbuf ring
Willy Tarreau [Sun, 26 May 2019 07:45:23 +0000 (09:45 +0200)] 
MINOR: mux-h2: introduce h2_release_mbuf() to release all buffers in the mbuf ring

This function iterates over all buffers in the mbuf ring to release all
of them from the head to the tail.

6 years agoMEDIUM: mux-h2: make the conditions to send based on mbuf, not just its tail
Willy Tarreau [Sun, 26 May 2019 07:43:07 +0000 (09:43 +0200)] 
MEDIUM: mux-h2: make the conditions to send based on mbuf, not just its tail

This is in preparation for iterating over lists. First we need to always
check the buffer's head and not its tail.

6 years agoMEDIUM: mux-h2: replace all occurrences of mbuf with a buffer ring
Willy Tarreau [Sun, 26 May 2019 07:38:07 +0000 (09:38 +0200)] 
MEDIUM: mux-h2: replace all occurrences of mbuf with a buffer ring

For now it's only one buffer long so the head and tails are always the
same, thus it doesn't change what used to work. In short, br_tail(h2c->mbuf)
was inserted everywhere we used to have h2c->mbuf.

6 years agoMINOR: buffer: add a new buffer ring API to manipulate rings of buffers
Willy Tarreau [Fri, 24 May 2019 12:55:06 +0000 (14:55 +0200)] 
MINOR: buffer: add a new buffer ring API to manipulate rings of buffers

The purpose is to manipulate rings made of series of buffers so that
it is possible to continue to work on a next buffer once one is full.
This will be used by muxes to deal with contention between multiple
streams and a single output buffer. No data is expected to span over
multiple buffers, all of them will be used like a regular buffer. This
will significantly limit the amount of changes and the code complexity
while still supporting larger output buffering.

The ring is made of a head and a tail indexes both of which point to a
buffer descriptor. At least one descriptor is always valid, so it could
be seen as a form of pagination always presenting one buffer. The root
of the ring is itself stored into a buffer descriptor so that the user
only has to declare a buffer array and to call br_init() on it in order
to use it.

6 years agoMINOR: buffer: introduce b_make() to make a buffer from its parameters
Willy Tarreau [Fri, 24 May 2019 12:52:56 +0000 (14:52 +0200)] 
MINOR: buffer: introduce b_make() to make a buffer from its parameters

This is convenient to assign a buffer from parts of another one.

6 years agoCLEANUP: debug: remove the TRACE() macro
Willy Tarreau [Sun, 26 May 2019 07:25:59 +0000 (09:25 +0200)] 
CLEANUP: debug: remove the TRACE() macro

It has not been used for many years, is unlikely to be reused and
conflicts with the similarly named macro in flt_trace, causing warnings
at build time when including debug.h in low-level files. Let's simply
remove it.

6 years agoMEDIUM: mux-h2: avoid doing expensive buffer realigns when not absolutely needed
Willy Tarreau [Fri, 24 May 2019 17:42:18 +0000 (19:42 +0200)] 
MEDIUM: mux-h2: avoid doing expensive buffer realigns when not absolutely needed

Transferring large objects over H2 sometimes shows unexplained performance
variations. A long analysis resulted in the following discovery. Often the
mux buffer looks like this :

    [ empty_head |    data     | empty_tail ]

Typical numbers are (very common) :
  - empty_head = 31
  - empty_tail = 16  (total free=47)
  - data = 16337
  - size = 16384
  - data to copy: 43

The reason for these holes are the blocking factors that are not always
the same in and out (due to keeping 9 bytes for the frame size, or the
56 bytes corresponding to the HTX header). This can easily happen 10000
times a second if the network bandwidth permits it!

In this case, while copying a DATA frame we find that the buffer has its
free space wrapped so we decide to realign it to optimize the copy. It's
possible that this practice stems from the code used to emit headers,
which do not support fragmentation and which had no other option left.
But it comes with two problems :
  - we don't check if the data fits, which results in a memcpy for nothing
  - we can move huge amounts of data to just copy a small block.

This patch addresses this two ways :
  - first, by not forcing a data realignment if what we have to copy does
    not fit, as this is totally pointless ;

  - second, by refusing to move too large data blocks. The threshold was
    set to 1 kB, because it may make sense to move 1 kB of data to copy
    a 15 kB one at once, which will leave as a single 16 kB block, but
    it doesn't make sense to mvoe 15 kB to copy just 1 kB. In all cases
    the data would fit and would just be split into two blocks, which is
    not very expensive, hence the low limit to 1 kB

With such changes, realignments are very rare, they show up around once
every 15 seconds at 60 Gbps, and look like this, resulting in a much more
stable bit rate :

  buf=0x7fe6ec0c3510,h=16333,d=35,s=16384 room=16349 in=16337

This patch should be safe for backporting to 1.9 if some performance
issues are reported there.

6 years agoOPTIM: freq-ctr: don't take the date lock for most updates
Willy Tarreau [Sat, 25 May 2019 17:54:40 +0000 (19:54 +0200)] 
OPTIM: freq-ctr: don't take the date lock for most updates

It's amazing that the value was still incremented under the date lock,
let's first use an atomic increment for the counter and move it out of
the date lock to reduce contention. These are just counters, we don't
need to take locks if we're not rotating, atomic ops are enough. This
patch does this, and leaves the lock for when the period is over. It's
important to note that some values might be added just before or just
after a rotation but this is not a problem since we don't care if a
value is counted in the previous or next period when it's exactly on
the edge. Great care was taken to ensure that the current counter is
always atomically updated.

Other minor cleanups were performed, such as avoiding to reload the
value from memory after a CAS, or using &~1 instead of two shifts to
remove the lowest bit.

6 years agoBUG/MINOR: ssl_sock: Fix memory leak when disabling compression
Ilya Shipitsin [Fri, 24 May 2019 22:38:14 +0000 (03:38 +0500)] 
BUG/MINOR: ssl_sock: Fix memory leak when disabling compression

according to manpage:

       sk_TYPE_zero() sets the number of elements in sk to zero. It
       does not free sk so after this call sk is still valid.

so we need to free all elements

[wt: seems like it has been there forever and should be backported
 to all stable branches]

6 years agoDOC: fix typos
Michael Prokop [Fri, 24 May 2019 08:25:45 +0000 (10:25 +0200)] 
DOC: fix typos

s/accidently/accidentally/
s/any ot these messages/any of theses messages/
s/catched/caught/
s/completly/completely/
s/convertor/converter/
s/desribing/describing/
s/developper/developer/
s/eventhough/even though/
s/exectution/execution/
s/functionnality/functionality/
s/If it receive a/If it receives a/
s/In can even/It can even/
s/informations/information/
s/it will be remove /it will be removed /
s/langage/language/
s/mentionned/mentioned/
s/negociated/negotiated/
s/Optionnaly/Optionally/
s/ouputs/outputs/
s/outweights/outweighs/
s/ressources/resources/

6 years agoBUG/MINOR: htx: Remove a forgotten while loop in htx_defrag()
Christopher Faulet [Mon, 20 May 2019 07:32:25 +0000 (09:32 +0200)] 
BUG/MINOR: htx: Remove a forgotten while loop in htx_defrag()

Fortunately, this loop does nothing. Otherwise it would have led to an infinite
loop. It was probably forgotten during a refactoring, in the early stage of the
HTX.

This patch must be backported to 1.9.

6 years agoBUG/MEDIUM: proto-htx: Not forward too much data when 1xx reponses are handled
Christopher Faulet [Fri, 17 May 2019 07:58:45 +0000 (09:58 +0200)] 
BUG/MEDIUM: proto-htx: Not forward too much data when 1xx reponses are handled

When an 1xx reponse is processed, we forward it immediatly. But another message
may already be in the channel's buffer, waiting to be processed. This may be
another 1xx reponse or the final one. So instead of forwarding everything, we
must take care to only forward the processed 1xx response.

This patch must be backported to 1.9.

6 years agoBUG/MINOR: mux-h1: Report EOI instead EOS on parsing error or H2 upgrade
Christopher Faulet [Fri, 17 May 2019 07:14:10 +0000 (09:14 +0200)] 
BUG/MINOR: mux-h1: Report EOI instead EOS on parsing error or H2 upgrade

When a parsing error occurrs in the H1 multiplexer, we stop to copy HTX
blocks. So the error may be reported with an emtpy HTX message. For instance, if
the headers parsing failed. When it happens, the flag CS_FL_EOS is also set on
the conn_stream. But it is an error. Most of time, it is set on established
connections, so it is not really an issue. But if it happens when the server
connection is not fully established, the connection is shut down immediatly and
the stream-interface is switched from SI_ST_CON to SI_ST_DIS/CLO. So HTX
analyzers have no chance to catch the error.

Instead of setting CS_FL_EOS, it is fairly better to set CS_FL_EOI, which is the
right flag to use. The same is also done on H2 upgrade. As a side effet of this
fix, in the stream-interface code, we must now set the flag CF_READ_PARTIAL on
the channel when the flag CF_EOI is set. It is a warranty to wakeup the stream
when EOI is reported to the channel while no data are received.

This patch must be backported to 1.9.

6 years agoBUG/MINOR: mux-h2: Count EOM in bytes sent when a HEADERS frame is formatted
Christopher Faulet [Wed, 15 May 2019 12:22:48 +0000 (14:22 +0200)] 
BUG/MINOR: mux-h2: Count EOM in bytes sent when a HEADERS frame is formatted

In HTX, when a HEADERS frame is formatted before sending it to the client or the
server, If an EOM is found because there is no body, we must count it in the
number bytes sent.

This patch must be backported to 1.9.

6 years agoBUG/MINOR: lua: Set right direction and flags on new HTTP objects
Christopher Faulet [Thu, 23 May 2019 09:14:21 +0000 (11:14 +0200)] 
BUG/MINOR: lua: Set right direction and flags on new HTTP objects

When a LUA HTTP object is created using the current TXN object, it is important
to also set the right direction and flags, using ones from the TXN object.

This patch may be backported to all supported branches with the lua
support. But, it seems to have no impact for now.

6 years agoBUG/MEDIUM: spoe: Don't use the SPOE applet after releasing it
Christopher Faulet [Thu, 23 May 2019 20:47:48 +0000 (22:47 +0200)] 
BUG/MEDIUM: spoe: Don't use the SPOE applet after releasing it

In spoe_release_appctx(), the SPOE applet may be used after it was released to
get its exit status code. Of course, HAProxy crashes when this happens.

This patch must be backported to 1.9 and 1.8.

6 years agoBUG/MINOR: proto-htx: Try to keep connections alive on redirect
Christopher Faulet [Thu, 23 May 2019 14:44:59 +0000 (16:44 +0200)] 
BUG/MINOR: proto-htx: Try to keep connections alive on redirect

As fat as possible, we try to keep the connections alive on redirect. It's
possible when the request has no body or when the request parsing is finished.

No backport is needed.

6 years agoMINOR: stats: report the global output bit rate in human readable form
Willy Tarreau [Thu, 23 May 2019 10:23:55 +0000 (12:23 +0200)] 
MINOR: stats: report the global output bit rate in human readable form

The stats page now reports the per-process output bit rate and applies
the usual conversions needed to turn the TCP payload rate to an Ethernet
bit rate in order to give a reasonably accurate estimate of how far from
interface saturation we are.

6 years agoMINOR: raw_sock: report global traffic statistics
Willy Tarreau [Thu, 23 May 2019 09:39:14 +0000 (11:39 +0200)] 
MINOR: raw_sock: report global traffic statistics

Many times we've been missing per-process traffic statistics. While it
didn't make sense in multi-process mode, with threads it does. Thus we
now have a counter of bytes emitted by raw_sock, and a freq counter for
these as well. However, freq_ctr are limited to 32 bits, and given that
loads of 300 Gbps have already been reached over a loopback using
splicing, we need to downscale this a bit. Here we're storing 1/32 of
the byte rate, which gives a theorical limit of 128 GB/s or ~1 Tbps,
which is more than enough. Let's have fun re-reading this sentence in
2029 :-)  The values can be read in "show info" output on the CLI.

6 years agoBUILD: watchdog: condition it to USE_RT
Willy Tarreau [Thu, 23 May 2019 08:20:55 +0000 (10:20 +0200)] 
BUILD: watchdog: condition it to USE_RT

It's needed on Linux to have access to timerfd_*, and on FreeBSD this
lib is needed as well, though not enabled in our default build. We can
see later if it's OK to enable it, for now let's fix the build issues.

6 years agoBUILD: signals: FreeBSD has SI_LWP instead of SI_TKILL
Willy Tarreau [Thu, 23 May 2019 06:40:50 +0000 (08:40 +0200)] 
BUILD: signals: FreeBSD has SI_LWP instead of SI_TKILL

SI_TKILL is for Linux. We're again in the non-portable area. Both OSes
use macros to define these values so we can #ifdef them. Let's make
SI_TKILL defined based on SI_LWP when only the latter is defined.

6 years agoBUILD: watchdog: use si_value.sival_int, not si_int for the timer's value
Willy Tarreau [Thu, 23 May 2019 06:36:29 +0000 (08:36 +0200)] 
BUILD: watchdog: use si_value.sival_int, not si_int for the timer's value

Bah, the linux manpage suggests to use si_int but it's a fake, it's only
a define on sigval.sival_int where sigval is defined as si_value. Let's
use si_value.sival_int, at least it builds on both Linux and FreeBSD. It's
likely that this code will have to be limited to a small subset of OSes
if it causes difficulties like this.

6 years ago[RELEASE] Released version 2.0-dev4 v2.0-dev4
Willy Tarreau [Wed, 22 May 2019 18:48:33 +0000 (20:48 +0200)] 
[RELEASE] Released version 2.0-dev4

Released version 2.0-dev4 with the following main changes :
    - BUILD: enable freebsd builds on cirrus-ci
    - BUG/MINOR: http_fetch: Rely on the smp direction for "cookie()" and "hdr()"
    - MEDIUM: Make 'option forceclose' actually warn
    - MEDIUM: Make 'resolution_pool_size' directive fatal
    - DOC: management: place "show activity" at the right place
    - MINOR: cli/activity: show the dumping thread ID starting at 1
    - MINOR: task: export global_task_mask
    - MINOR: cli/debug: add a thread dump function
    - BUG/MEDIUM: streams: Don't use CF_EOI to decide if the request is complete.
    - BUG/MEDIUM: streams: Try to L7 retry before aborting the connection.
    - BUG/MINOR: debug: make ha_task_dump() always check the task before dumping it
    - BUG/MINOR: debug: make ha_task_dump() actually dump the requested task
    - MINOR: debug: make ha_thread_dump() and ha_task_dump() take a buffer
    - BUG/MINOR: debug: don't check the call date on tasklets
    - MINOR: thread: implement ha_thread_relax()
    - MINOR: task: put barriers after each write to curr_task
    - MINOR: task: always reset curr_task when freeing a task or tasklet
    - MINOR: stream: detach the stream from its own task on stream_free()
    - MEDIUM: debug/threads: implement an advanced thread dump system
    - REGTEST: extend the check duration on tls_health_checks and mark it slow
    - DOC: fix "successful" typo
    - MINOR: init: setenv HAPROXY_CFGFILES
    - MINOR: threads/init: synchronize the threads startup
    - MEDIUM: init/mworker: make the pipe register function a regular initcall
    - CLEANUP: memory: make the fault injection code use the OTHER_LOCK label
    - CLEANUP: threads: remove the now unused START_LOCK label
    - MINOR: init/threads: make the global threads an array of structs
    - MINOR: threads: add each thread's clockid into the global thread_info
    - CLEANUP: stream: remove an obsolete debugging test
    - MINOR: tools: add dump_hex()
    - MINOR: debug: implement ha_panic()
    - MINOR: debug/cli: add some debugging commands for developers
    - MINOR: tools: provide a may_access() function and make dump_hex() use it
    - MINOR: debug: make ha_panic() report threads starting at 1
    - REORG: compat: move some integer limit definitions from standard.h to compat.h
    - REORG: threads: move the struct thread_info from global.h to hathreads.h
    - MINOR: compat: make sure to always define clockid_t
    - MINOR: threads: always place the clockid in the struct thread_info
    - MINOR: threads: add a thread-local thread_info pointer "ti"
    - MINOR: time: move the cpu, mono, and idle time to thread_info
    - MINOR: time: add a function to retrieve another thread's cputime
    - MINOR: debug: report each thread's cpu usage in "show thread"
    - BUILD: threads: only assign the clock_id when supported
    - BUILD: makefile: use USE_OBSOLETE_LINKER for solaris
    - BUILD: makefile: remove -fomit-frame-pointer optimisation (solaris)
    - MAJOR: polling: add event ports support (Solaris)
    - BUG/MEDIUM: streams: Don't switch from SI_ST_CON to SI_ST_DIS on read0.
    - CLEANUP: time: refine the test on _POSIX_TIMERS
    - MINOR: compat: define a new empty type empty_t for non-implemented fields
    - CLEANUP: time: switch clockid_t to empty_t when not available
    - BUG/MINOR: mworker: Fix memory leak of mworker_proc members
    - CLEANUP: objtype: make obj_type() and obj_type_name() take consts
    - MINOR: debug: switch to SIGURG for thread dumps
    - CLEANUP: threads: really move thread_info to hathreads.c
    - MINOR: threads: make threads_{harmless|want_rdv}_mask constant 0 without threads
    - CLEANUP: debug: always report harmless/want_rdv even without threads
    - MINOR: threads: implement ha_tkill() and ha_tkillall()
    - CLEANUP: debug: make use of ha_tkill() and remove ifdefs
    - MINOR: stream: introduce a stream_dump() function and use it in stream_dump_and_crash()
    - MINOR: debug: dump streams when an applet, iocb or stream is known
    - MINOR: threads: add a "stuck" flag to the thread_info struct
    - MINOR: threads: add a timer_t per thread in thread_info
    - MAJOR: watchdog: implement a thread lockup detection mechanism
    - MINOR: stream: remove the cpu time detection from process_stream()
    - MINOR: connection: report the mux names in "haproxy -vv"
    - CLEANUP: mux-h1: use "H1" and not "h1" as the mux's name
    - BUG/MEDIUM: WURFL: segfault in wurfl-get() with missing info.
    - MINOR: WURFL: call header_retireve_callback() in dummy library
    - MINOR: WURFL: fixed Engine load failed error when wurfl-information-list contains wurfl_root_id
    - MINOR: WURFL: shows log messages during module initialization
    - MINOR: WURFL: removes heading wurfl-information-separator from wurfl-get-all() and wurfl-get() results
    - MINOR: WURFL: wurfl_get() and wurfl_get_all() now return an empty string if device detection fails
    - MEDIUM: WURFL: HTX awareness.
    - MINOR: WURFL: module version bump to 2.0
    - MINOR: WURFL: do not emit warnings when not configured
    - CONTRIB: wurfl: address 3 build issues in the wurfl dummy library
    - BUG/MEDIUM: init/threads: provide per-thread alloc/free function callbacks
    - BUILD: travis: add sanitizers to travis-ci builds
    - BUILD: time: remove the test on _POSIX_C_SOURCE
    - CLEANUP: build: rename some build macros to use the USE_* ones
    - CLEANUP: raw_sock: remove support for very old linux splice bug workaround
    - BUG/MEDIUM: dns: make the port numbers unsigned
    - MEDIUM: config: deprecate the antique req* and rsp* commands

6 years agoMEDIUM: config: deprecate the antique req* and rsp* commands
Willy Tarreau [Wed, 22 May 2019 18:34:35 +0000 (20:34 +0200)] 
MEDIUM: config: deprecate the antique req* and rsp* commands

These commands don't follow the same flow as the rest of the commands,
each of them iterates over all header lines before switching to the
next directive. In addition they make no distinction between start
line and headers and can lead to unparsable rewrites which are very
difficult to deal with internally.

Most of them are still occasionally found in configurations, mainly
because of the usual "we've always done this way". By marking them
deprecated and emitting a warning and recommendation on first use of
each of them, we will raise users' awareness of users regarding the
cleaner, faster and more reliable alternatives.

Some use cases of "reqrep" still appear from time to time for URL
rewriting that is not so convenient with other rules. But at least
users facing this requirement will explain their use case so that we
can best serve them. Some discussion started on this subject in a
thread linked to from github issue #100.

The goal is to remove them in 2.1 since they require to reparse the
result before indexing it and we don't want this hack to live long.
The following directives were marked deprecated :

  -reqadd
  -reqallow
  -reqdel
  -reqdeny
  -reqiallow
  -reqidel
  -reqideny
  -reqipass
  -reqirep
  -reqitarpit
  -reqpass
  -reqrep
  -reqtarpit
  -rspadd
  -rspdel
  -rspdeny
  -rspidel
  -rspideny
  -rspirep
  -rsprep

6 years agoBUG/MEDIUM: dns: make the port numbers unsigned
Willy Tarreau [Wed, 22 May 2019 18:07:45 +0000 (20:07 +0200)] 
BUG/MEDIUM: dns: make the port numbers unsigned

Mustafa Yildirim reported in Discourse that ports >32767 advertised
in SRV records are wrong. Given the high value they definitely
correspond to a sign extension of a negative number. The cause was
indeed that the port is declared as a signed int in the dns_answer_item
structure, and Lukas confirmed in github issue #103 that turning it to
unsigned addresses the issue.

It is worth noting that there are other such fields in this structure
that don't look right (ttl, priority, class, type) and that someone
should audit this part to be certain they are properly typed.

This fix must be backported to 1.9 and likely to 1.8 as well.

6 years agoCLEANUP: raw_sock: remove support for very old linux splice bug workaround
Willy Tarreau [Wed, 22 May 2019 17:55:24 +0000 (19:55 +0200)] 
CLEANUP: raw_sock: remove support for very old linux splice bug workaround

We've been dealing with a workaround for a bug in splice that used to
affect version 2.6.25 to 2.6.27.12 and which was fixed 10 years ago
in kernel versions which are not supported anymore. Given that people
who would use a kernel in such a range would face much more serious
stability and security issues, it's about time to get rid of this
workaround and of the ASSUME_SPLICE_WORKS build option used to disable
it.

6 years agoCLEANUP: build: rename some build macros to use the USE_* ones
Willy Tarreau [Wed, 22 May 2019 17:24:06 +0000 (19:24 +0200)] 
CLEANUP: build: rename some build macros to use the USE_* ones

We still have quite a number of build macros which are mapped 1:1 to a
USE_something setting in the makefile but which have a different name.
This patch cleans this up by renaming them to use the USE_something
one, allowing to clean up the makefile and make it more obvious when
reading the code what build option needs to be added.

The following renames were done :

 ENABLE_POLL -> USE_POLL
 ENABLE_EPOLL -> USE_EPOLL
 ENABLE_KQUEUE -> USE_KQUEUE
 ENABLE_EVPORTS -> USE_EVPORTS
 TPROXY -> USE_TPROXY
 NETFILTER -> USE_NETFILTER
 NEED_CRYPT_H -> USE_CRYPT_H
 CONFIG_HAP_CRYPT -> USE_LIBCRYPT
 CONFIG_HAP_NS -> DUSE_NS
 CONFIG_HAP_LINUX_SPLICE -> USE_LINUX_SPLICE
 CONFIG_HAP_LINUX_TPROXY -> USE_LINUX_TPROXY
 CONFIG_HAP_LINUX_VSYSCALL -> USE_LINUX_VSYSCALL

6 years agoBUILD: time: remove the test on _POSIX_C_SOURCE
Willy Tarreau [Wed, 22 May 2019 17:12:54 +0000 (19:12 +0200)] 
BUILD: time: remove the test on _POSIX_C_SOURCE

It seems it's not defined on FreeBSD while it's mentioned on Linux that
clock_gettime() can be detected using this. Given that we also have the
test for _POSIX_TIMERS>0 that should cover it well enough. If it breaks
on other systems, we'll see.

Report was here :
    https://github.com/haproxy/haproxy/runs/133866993

6 years agoBUILD: travis: add sanitizers to travis-ci builds
Ilya Shipitsin [Wed, 22 May 2019 15:12:15 +0000 (20:12 +0500)] 
BUILD: travis: add sanitizers to travis-ci builds

full list of changes:

use TARGET=osx instead of generic for osx builds,
add USE_PCRE_JIT=1, USE_GETADDRINFO=1 to build matrix,
enable address sanitizer for clang
enable device detection: WURFL, DEVICEATLAS

6 years agoBUG/MEDIUM: init/threads: provide per-thread alloc/free function callbacks
Willy Tarreau [Wed, 22 May 2019 12:42:12 +0000 (14:42 +0200)] 
BUG/MEDIUM: init/threads: provide per-thread alloc/free function callbacks

We currently have the ability to register functions to be called early
on thread creation and at thread deinitialization. It turns out this is
not sufficient because certain such functions may use resources that are
being allocated by the other ones, thus creating a race condition depending
only on the linking order. For example the mworker needs to register a
file descriptor while the pollers will reallocate the fd_updt[] array.
Similarly logs and trashes may be used by some init functions while it's
unclear whether they have been deduplicated.

The same issue happens on deinit, if the fd_updt[] or trash is released
before some functions finish to use them, we'll get into trouble.

This patch creates a couple of early and late callbacks for per-thread
allocation/freeing of resources. A few init functions were moved there,
and the fd init code was split between the two (since it used to both
allocate and initialize at once). This way the init/deinit sequence is
expected to be safe now.

This patch should be backported to 1.9 as at least the trash/log issue
seems to be present. The run_thread_poll_loop() code is a bit different
there as the mworker is not a callback, but it will have no effect and
it's enough to drop the mworker changes.

This bug was reported by Ilya Shipitsin in github issue #104.

6 years agoCONTRIB: wurfl: address 3 build issues in the wurfl dummy library
Willy Tarreau [Wed, 22 May 2019 12:54:27 +0000 (14:54 +0200)] 
CONTRIB: wurfl: address 3 build issues in the wurfl dummy library

Two of them were functions returning an string missing the return
statement and one is just the usual "set but not used".

6 years agoMINOR: WURFL: do not emit warnings when not configured
Willy Tarreau [Wed, 22 May 2019 12:01:22 +0000 (14:01 +0200)] 
MINOR: WURFL: do not emit warnings when not configured

At the moment the WURFL module emits 3 lines of warnings upon startup
when it is not referenced in the configuration file, which is quite
confusing. Let's make sure to keep it silent when not configured, as
detected by the absence of the wurfl-data-file statement.

6 years agoMINOR: WURFL: module version bump to 2.0
mbellomi [Tue, 21 May 2019 15:15:59 +0000 (17:15 +0200)] 
MINOR: WURFL: module version bump to 2.0

Make it version 2.0.

6 years agoMEDIUM: WURFL: HTX awareness.
mbellomi [Tue, 21 May 2019 15:15:07 +0000 (17:15 +0200)] 
MEDIUM: WURFL: HTX awareness.

Now wurfl fetch process is fully  HTX aware.

6 years agoMINOR: WURFL: wurfl_get() and wurfl_get_all() now return an empty string if device...
mbellomi [Tue, 21 May 2019 14:41:24 +0000 (16:41 +0200)] 
MINOR: WURFL: wurfl_get() and wurfl_get_all() now return an empty string if device detection fails

6 years agoMINOR: WURFL: removes heading wurfl-information-separator from wurfl-get-all() and...
mbellomi [Tue, 21 May 2019 14:29:22 +0000 (16:29 +0200)] 
MINOR: WURFL: removes heading wurfl-information-separator from wurfl-get-all() and wurfl-get() results

6 years agoMINOR: WURFL: shows log messages during module initialization
mbellomi [Tue, 21 May 2019 14:11:42 +0000 (16:11 +0200)] 
MINOR: WURFL: shows log messages during module initialization

Now some useful startup information is logged to stderr. Previously they
were lost because logs were not yet enabled.

6 years agoMINOR: WURFL: fixed Engine load failed error when wurfl-information-list contains...
mbellomi [Tue, 21 May 2019 13:51:46 +0000 (15:51 +0200)] 
MINOR: WURFL: fixed Engine load failed error when wurfl-information-list contains wurfl_root_id

6 years agoMINOR: WURFL: call header_retireve_callback() in dummy library
mbellomi [Tue, 21 May 2019 13:44:53 +0000 (15:44 +0200)] 
MINOR: WURFL: call header_retireve_callback() in dummy library

The current coverage of the dummy library was limited because the callbacks
passed to wurfl_lookup() were not called. Now we do call them with one existing
and one non-existing headers to make sure that ha_wurfl_retrieve_header() is
covered by the tests as well.

6 years agoBUG/MEDIUM: WURFL: segfault in wurfl-get() with missing info.
mbellomi [Tue, 21 May 2019 13:32:48 +0000 (15:32 +0200)] 
BUG/MEDIUM: WURFL: segfault in wurfl-get() with missing info.

A segfault may happen in ha_wurfl_get() when dereferencing information not
present in wurfl-information-list. Check the node retrieved from the tree,
not its container.

This fix must be backported to 1.9.

6 years agoCLEANUP: mux-h1: use "H1" and not "h1" as the mux's name
Willy Tarreau [Wed, 22 May 2019 09:36:54 +0000 (11:36 +0200)] 
CLEANUP: mux-h1: use "H1" and not "h1" as the mux's name

The mux's name is the only one reported in lower case in "show sess"
or "haproxy -vv" while the other ones are upper case, so it loses and
the other ones win :-)

6 years agoMINOR: connection: report the mux names in "haproxy -vv"
Willy Tarreau [Wed, 22 May 2019 09:44:03 +0000 (11:44 +0200)] 
MINOR: connection: report the mux names in "haproxy -vv"

Since the mux names appear at a few places (dumps etc), let's list
them in front of supported mux protocols in "haproxy -vv".

6 years agoMINOR: stream: remove the cpu time detection from process_stream()
Willy Tarreau [Wed, 22 May 2019 06:57:01 +0000 (08:57 +0200)] 
MINOR: stream: remove the cpu time detection from process_stream()

It was not as efficient as the watchdog in that it would only trigger
after the problem resolved by itself, and still required a huge margin
to make sure we didn't trigger for an invalid reason. This used to leave
little indication about the cause. Better use the watchdog now and
improve it if needed.

The detector of unkillable tasks remains active though.

6 years agoMAJOR: watchdog: implement a thread lockup detection mechanism
Willy Tarreau [Fri, 3 May 2019 11:52:18 +0000 (13:52 +0200)] 
MAJOR: watchdog: implement a thread lockup detection mechanism

Since threads were introduced, we've naturally had a number of bugs
related to locking issues. In addition we've also got some issues
with corrupted lists in certain rare cases not necessarily involving
threads. Not only these events cause a lot of trouble to the production
as it is very hard to detect that the process is stuck in a loop and
doesn't deliver the service anymore, but it's often difficult (or too
late) to collect more debugging information.

The patch presented here implements a lockup detection mechanism, also
known as "watchdog". The principle is that (on systems supporting it),
each thread will have its own CPU timer which progresses as the thread
consumes CPU cycles, and when a deadline is met, a signal is delivered
(SIGALRM here since it doesn't interrupt gdb by default).

The thread handling this signal (which is not necessarily the one which
triggered the timer) figures the thread ID from the signal arguments and
checks if it's really stuck by looking at the time spent since last exit
from poll() and by checking that the thread's scheduler is still alive
(so that even when dealing with configuration issues resulting in insane
amount of tasks being called in turn, it is not possible to accidently
trigger it). Checking the scheduler's activity will usually result in a
second chance, thus doubling the detecting time.

In order not to incorrectly flag a thread as being the cause of the
lockup, the thread_harmless_mask is checked : a thread could very well
be spinning on itself waiting for all other threads to join (typically
what happens when issuing "show sess"). In this case, once all threads
but one (or two) have joined, all the innocent ones are marked harmless
and will not trigger the timer. Only the ones not reacting will.

The deadline is set to one second, which already appears impossible to
reach, especially since it's 1 second of CPU usage, not elapsed time
with the CPU being preempted by other threads/processes/hypervisor. In
practice due to the scheduler's health verification it takes up to two
seconds to decide to panic.

Once all conditions are met, the goal is to crash from the offending
thread. So if it's the current one, we call ha_panic() otherwise the
signal is bounced to the offending thread which deals with it. This
will result in all threads being woken up in turn to dump their context,
the whole state is emitted on stderr in hope that it can be logged, and
the process aborts, leaving a chance for a core to be dumped and for a
service manager to restart it.

An alternative mechanism could be implemented for systems unable to
wake up a thread once its CPU clock reaches a deadline (e.g. FreeBSD).
Instead of waking the timer each and every deadline, it is possible to
use a standard timer which is reset each time we leave poll(). Since
the signal handler rechecks the CPU consumption this will also work.
However a totally idle process may trigger it from time to time which
may or may not confuse some debugging sessions. The same is true for
alarm() which could be another option for systems not having such a
broad choice of timers (but it seems that in this case they will not
have per-thread CPU measurements available either).

The feature is currently implemented only when threads are enabled in
order to keep the code clean, since the main purpose is to detect and
address inter-thread deadlocks. But if it proves useful for other
situations this condition might be relaxed.

6 years agoMINOR: threads: add a timer_t per thread in thread_info
Willy Tarreau [Tue, 21 May 2019 18:01:26 +0000 (20:01 +0200)] 
MINOR: threads: add a timer_t per thread in thread_info

This will be used by the watchdog to detect that a thread locked up.
It's only defined on platforms supporting it. This patch only reserves
the room for the timer in the struct. A special value was reserved for
the uninitialized timer. The problem is that the POSIX API was horribly
designed, defining no invalid value, thus for each timer it is required
to keep a second variable to indicate whether it's valid. A quick check
shows that defining a 32-bit invalid value is not something uncommon
across other implementations, with ~0 being common. Let's try with this
and if it causes issues we can revisit this decision.

6 years agoMINOR: threads: add a "stuck" flag to the thread_info struct
Willy Tarreau [Wed, 22 May 2019 05:06:44 +0000 (07:06 +0200)] 
MINOR: threads: add a "stuck" flag to the thread_info struct

This flag is constantly cleared by the scheduler and will be set by the
watchdog timer to detect stuck threads. It is also set by the "show
threads" command so that it is easy to spot if the situation has evolved
between two subsequent calls : if the first "show threads" shows no stuck
thread and the second one shows such a stuck thread, it indicates that
this thread didn't manage to make any forward progress since the previous
call, which is extremely suspicious.

6 years agoMINOR: debug: dump streams when an applet, iocb or stream is known
Willy Tarreau [Wed, 22 May 2019 07:43:09 +0000 (09:43 +0200)] 
MINOR: debug: dump streams when an applet, iocb or stream is known

Whenever we can retrieve a valid stream pointer, we now call stream_dump()
to get a detailed dump of the stream currently running on the processor.
This is used by "show threads" and by ha_panic().

6 years agoMINOR: stream: introduce a stream_dump() function and use it in stream_dump_and_crash()
Willy Tarreau [Wed, 22 May 2019 07:33:03 +0000 (09:33 +0200)] 
MINOR: stream: introduce a stream_dump() function and use it in stream_dump_and_crash()

This function dumps a lot of information about a stream into the provided
buffer. It is now used by stream_dump_and_crash() and will be used by the
debugger as well.

6 years agoCLEANUP: debug: make use of ha_tkill() and remove ifdefs
Willy Tarreau [Wed, 22 May 2019 06:46:59 +0000 (08:46 +0200)] 
CLEANUP: debug: make use of ha_tkill() and remove ifdefs

This way we always signal the threads the same way.

6 years agoMINOR: threads: implement ha_tkill() and ha_tkillall()
Willy Tarreau [Wed, 22 May 2019 06:43:34 +0000 (08:43 +0200)] 
MINOR: threads: implement ha_tkill() and ha_tkillall()

These functions are used respectively to signal one thread or all threads.
When multithreading is disabled, it's always the current thread which is
signaled.

6 years agoCLEANUP: debug: always report harmless/want_rdv even without threads
Willy Tarreau [Wed, 22 May 2019 06:52:58 +0000 (08:52 +0200)] 
CLEANUP: debug: always report harmless/want_rdv even without threads

This way we have a more consistent output and we can remove annoying
ifdefs.

6 years agoMINOR: threads: make threads_{harmless|want_rdv}_mask constant 0 without threads
Willy Tarreau [Wed, 22 May 2019 05:48:18 +0000 (07:48 +0200)] 
MINOR: threads: make threads_{harmless|want_rdv}_mask constant 0 without threads

Some code starts to add ifdefs everywhere to work around the lack of
threads_harmless_mask when threads are not compiled in. This one is
often used to indicate a thread having joined the rendez-vous point or
a thread sleeping in the poller. By setting it to zero we translate
what usually is required in debugging code (i.e. the only thread is
currently working) and for signal handlers we can use a combination of
threads_harmless_mask and sleeping_threads_mask to detect the polling
cases as well. Similarly do the same with threads_want_rdv_mask which
is less often used though.

6 years agoCLEANUP: threads: really move thread_info to hathreads.c
Willy Tarreau [Wed, 22 May 2019 04:42:27 +0000 (06:42 +0200)] 
CLEANUP: threads: really move thread_info to hathreads.c

Commit 5a6e2245f ("REORG: threads: move the struct thread_info from
global.h to hathreads.h") didn't hold its promise well, as the thread_info
struct was still declared and initialized in haproxy.c in addition to being
in hathreads.c. Let's move it for real now.

6 years agoMINOR: debug: switch to SIGURG for thread dumps
Willy Tarreau [Wed, 22 May 2019 04:28:54 +0000 (06:28 +0200)] 
MINOR: debug: switch to SIGURG for thread dumps

The current choice of SIGPWR has the adverse effect of stopping gdb each
time it is triggered using "show threads" or example, which is not really
convenient. Let's switch to SIGURG instead, which we don't use either.

6 years agoCLEANUP: objtype: make obj_type() and obj_type_name() take consts
Willy Tarreau [Wed, 22 May 2019 07:30:09 +0000 (09:30 +0200)] 
CLEANUP: objtype: make obj_type() and obj_type_name() take consts

There is no reason for them to require a writable area.

6 years agoBUG/MINOR: mworker: Fix memory leak of mworker_proc members
Tim Duesterhus [Thu, 16 May 2019 18:23:22 +0000 (20:23 +0200)] 
BUG/MINOR: mworker: Fix memory leak of mworker_proc members

The struct mworker_proc is not uniformly freed everywhere, sometimes leading
to leaks of the `id` string (and possibly the other strings).

Introduce a mworker_free_child function instead of duplicating the freeing
logic everywhere to prevent this kind of issues.

This leak was reported in issue #96.

It looks like the leaks have been introduced in commit 9a1ee7ac31c56fd7d881adf2ef4659f336e50c9f,
which is specific to 2.0-dev. Backporting `mworker_free_child` might be
helpful to ease backporting other fixes, though.

6 years agoCLEANUP: time: switch clockid_t to empty_t when not available
Willy Tarreau [Tue, 21 May 2019 17:58:16 +0000 (19:58 +0200)] 
CLEANUP: time: switch clockid_t to empty_t when not available

This is cleaner than using an int. We also get rid of the constants
that we don't need nor use.

6 years agoMINOR: compat: define a new empty type empty_t for non-implemented fields
Willy Tarreau [Tue, 21 May 2019 17:48:44 +0000 (19:48 +0200)] 
MINOR: compat: define a new empty type empty_t for non-implemented fields

Some structures have optional fields which depend on availability of
certain features on certain platforms, and having to stuff lots of
ifdefs in these structs makes them unreadable. Using real values like
ints requires some initialization and adds even more confusion.

Here we take a different approach : we create an empty type called
empty_t to use as a substitute for the real type that is not implemented
and which doesn't contain any value (it's an empty struct). Thus it has
a size of zero but an address, thus a pointer may point to it. It will
not have to be initialized though. Some initialization code might even
continue to work and do nothing like initializing it using memset with
its sizeof which is zero.

6 years agoCLEANUP: time: refine the test on _POSIX_TIMERS
Willy Tarreau [Tue, 21 May 2019 17:46:58 +0000 (19:46 +0200)] 
CLEANUP: time: refine the test on _POSIX_TIMERS

The clock_gettime() man page says we must check that _POSIX_TIMERS is
defined to a value greater than zero, not just that it's simply defined
so let's fix this right now.

6 years agoBUG/MEDIUM: streams: Don't switch from SI_ST_CON to SI_ST_DIS on read0.
Olivier Houchard [Tue, 21 May 2019 15:43:50 +0000 (17:43 +0200)] 
BUG/MEDIUM: streams: Don't switch from SI_ST_CON to SI_ST_DIS on read0.

When we receive a read0, and we're still in SI_ST_CON state (so on an
outgoing conneciton), don't immediately switch to SI_ST_DIS, or, we would
never call sess_establish(), and so the analysers will never run.
Instead, let sess_establish() handle that case, and switch to SI_ST_DIS if
we already have CF_SHUTR on the channel.

This should be backported to 1.9.

6 years agoMAJOR: polling: add event ports support (Solaris)
Emmanuel Hocdet [Mon, 8 Apr 2019 16:53:32 +0000 (16:53 +0000)] 
MAJOR: polling: add event ports support (Solaris)

Event ports are kqueue/epoll polling class for Solaris. Code is based
on https://github.com/joyent/haproxy-1.8/tree/joyent/dev-v1.8.8.
Event ports are available only on SunOS systems derived from
Solaris 10 and later (including illumos systems).

6 years agoBUILD: makefile: remove -fomit-frame-pointer optimisation (solaris)
Emmanuel Hocdet [Fri, 17 May 2019 15:32:21 +0000 (15:32 +0000)] 
BUILD: makefile: remove -fomit-frame-pointer optimisation (solaris)

-fomit-frame-pointer is commonly avoided because tools like dtrace
needs frame-pointer. Remove it from Makefile and let builder's env
do the job.

This patch could be backported to 1.9.

6 years agoBUILD: makefile: use USE_OBSOLETE_LINKER for solaris
Emmanuel Hocdet [Tue, 21 May 2019 09:12:03 +0000 (09:12 +0000)] 
BUILD: makefile: use USE_OBSOLETE_LINKER for solaris

USE_OBSOLETE_LINKER is needed to build on SunOS systems.

This patch must be backported to 1.9.

6 years agoBUILD: threads: only assign the clock_id when supported
Willy Tarreau [Tue, 21 May 2019 13:14:08 +0000 (15:14 +0200)] 
BUILD: threads: only assign the clock_id when supported

I took extreme care to always check for _POSIX_THREAD_CPUTIME before
manipulating clock_id, except at one place (run_thread_poll_loop) as
found by Manu, breaking Solaris. Now fixed, no backport needed.

6 years agoMINOR: debug: report each thread's cpu usage in "show thread"
Willy Tarreau [Mon, 20 May 2019 18:52:20 +0000 (20:52 +0200)] 
MINOR: debug: report each thread's cpu usage in "show thread"

Now we can report each thread's CPU time, both at wake up (poll) and
retrieved while dumping (now), then the difference, which directly
indicates how long the thread has been running uninterrupted. A very
high value for the diff could indicate a deadlock, especially if it
happens between two threads. Note that it may occasionally happen
that a wrong value is displayed since nothing guarantees that the
date is read atomically.