haproxy: fixes from upstream

- [PATCH 15/20] BUG/MEDIUM: remove debugging code from systemd-wrapper
 - [PATCH 16/20] BUG/MEDIUM: http: adjust close mode when switching to
 - [PATCH 17/20] BUG/MINOR: config: don't propagate process binding on
 - [PATCH 18/20] BUG/MEDIUM: check: rule-less tcp-check must detect
 - [PATCH 19/20] BUG/MINOR: tcp-check: report the correct failed step in
 - [PATCH 20/20] BUG/MINOR: config: don't propagate process binding for

Signed-off-by: Thomas Heil <heil@terminal-consulting.de>
This commit is contained in:
Thomas Heil 2014-10-06 16:28:36 +02:00
parent 6ab4a265a2
commit a6a3037fbd
7 changed files with 518 additions and 1 deletions

View File

@ -10,7 +10,7 @@ include $(TOPDIR)/rules.mk
PKG_NAME:=haproxy
PKG_VERSION:=1.5.4
PKG_RELEASE:=15
PKG_RELEASE:=20
PKG_SOURCE:=haproxy-$(PKG_VERSION).tar.gz
PKG_SOURCE_URL:=http://haproxy.1wt.eu/download/1.5/src/
PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)-$(BUILD_VARIANT)/$(PKG_NAME)-$(PKG_VERSION)

View File

@ -0,0 +1,36 @@
From 575e299cc07f5f2b314d91dfac8671834cbdd2a7 Mon Sep 17 00:00:00 2001
From: Willy Tarreau <w@1wt.eu>
Date: Wed, 24 Sep 2014 12:59:25 +0200
Subject: [PATCH 15/20] BUG/MEDIUM: remove debugging code from systemd-wrapper
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Kristoffer Grönlund reported that after my recent update to the
systemd-wrapper, I accidentely left the debugging code which
consists in disabling the fork :-(
The fix needs to be backported to 1.5 as well since I pushed it
there as well.
(cherry picked from commit a55bbc64d8272e4066a67b6d190ffebaff2b300a)
---
src/haproxy-systemd-wrapper.c | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/src/haproxy-systemd-wrapper.c b/src/haproxy-systemd-wrapper.c
index 446f28f..8602881 100644
--- a/src/haproxy-systemd-wrapper.c
+++ b/src/haproxy-systemd-wrapper.c
@@ -70,8 +70,7 @@ static void spawn_haproxy(char **pid_strv, int nb_pid)
main_argc = wrapper_argc - 1;
main_argv = wrapper_argv + 1;
- //pid = fork();
- pid=0;
+ pid = fork();
if (!pid) {
/* 3 for "haproxy -Ds -sf" */
char **argv = calloc(4 + main_argc + nb_pid + 1, sizeof(char *));
--
2.0.4

View File

@ -0,0 +1,188 @@
From 2e47a3ab11188239abadb6bba7bd901d764aa4fb Mon Sep 17 00:00:00 2001
From: Willy Tarreau <w@1wt.eu>
Date: Tue, 30 Sep 2014 18:44:22 +0200
Subject: [PATCH 16/20] BUG/MEDIUM: http: adjust close mode when switching to
backend
Commit 179085c ("MEDIUM: http: move Connection header processing earlier")
introduced a regression : the backend's HTTP mode is not considered anymore
when setting the session's HTTP mode, because wait_for_request() is only
called once, when the frontend receives the request (or when the frontend
is in TCP mode, when the backend receives the request).
The net effect is that in some situations when the frontend and the backend
do not work in the same mode (eg: keep-alive vs close), the backend's mode
is ignored.
This patch moves all that processing to a dedicated function, which is
called from the original place, as well as from session_set_backend()
when switching from an HTTP frontend to an HTTP backend in different
modes.
This fix must be backported to 1.5.
(cherry picked from commit 4e21ff9244aefa56bcf0793a9e07edba2c3c1960)
---
include/proto/proto_http.h | 1 +
src/proto_http.c | 107 +++++++++++++++++++++++----------------------
src/proxy.c | 8 ++++
3 files changed, 64 insertions(+), 52 deletions(-)
diff --git a/include/proto/proto_http.h b/include/proto/proto_http.h
index e898ca8..8014310 100644
--- a/include/proto/proto_http.h
+++ b/include/proto/proto_http.h
@@ -112,6 +112,7 @@ unsigned int http_get_hdr(const struct http_msg *msg, const char *hname, int hle
void http_init_txn(struct session *s);
void http_end_txn(struct session *s);
void http_reset_txn(struct session *s);
+void http_adjust_conn_mode(struct session *s, struct http_txn *txn, struct http_msg *msg);
struct http_req_rule *parse_http_req_cond(const char **args, const char *file, int linenum, struct proxy *proxy);
struct http_res_rule *parse_http_res_cond(const char **args, const char *file, int linenum, struct proxy *proxy);
diff --git a/src/proto_http.c b/src/proto_http.c
index 7e35c8b..20e7088 100644
--- a/src/proto_http.c
+++ b/src/proto_http.c
@@ -2393,6 +2393,59 @@ fail:
return 0;
}
+void http_adjust_conn_mode(struct session *s, struct http_txn *txn, struct http_msg *msg)
+{
+ int tmp = TX_CON_WANT_KAL;
+
+ if (!((s->fe->options2|s->be->options2) & PR_O2_FAKE_KA)) {
+ if ((s->fe->options & PR_O_HTTP_MODE) == PR_O_HTTP_TUN ||
+ (s->be->options & PR_O_HTTP_MODE) == PR_O_HTTP_TUN)
+ tmp = TX_CON_WANT_TUN;
+
+ if ((s->fe->options & PR_O_HTTP_MODE) == PR_O_HTTP_PCL ||
+ (s->be->options & PR_O_HTTP_MODE) == PR_O_HTTP_PCL)
+ tmp = TX_CON_WANT_TUN;
+ }
+
+ if ((s->fe->options & PR_O_HTTP_MODE) == PR_O_HTTP_SCL ||
+ (s->be->options & PR_O_HTTP_MODE) == PR_O_HTTP_SCL) {
+ /* option httpclose + server_close => forceclose */
+ if ((s->fe->options & PR_O_HTTP_MODE) == PR_O_HTTP_PCL ||
+ (s->be->options & PR_O_HTTP_MODE) == PR_O_HTTP_PCL)
+ tmp = TX_CON_WANT_CLO;
+ else
+ tmp = TX_CON_WANT_SCL;
+ }
+
+ if ((s->fe->options & PR_O_HTTP_MODE) == PR_O_HTTP_FCL ||
+ (s->be->options & PR_O_HTTP_MODE) == PR_O_HTTP_FCL)
+ tmp = TX_CON_WANT_CLO;
+
+ if ((txn->flags & TX_CON_WANT_MSK) < tmp)
+ txn->flags = (txn->flags & ~TX_CON_WANT_MSK) | tmp;
+
+ if (!(txn->flags & TX_HDR_CONN_PRS) &&
+ (txn->flags & TX_CON_WANT_MSK) != TX_CON_WANT_TUN) {
+ /* parse the Connection header and possibly clean it */
+ int to_del = 0;
+ if ((msg->flags & HTTP_MSGF_VER_11) ||
+ ((txn->flags & TX_CON_WANT_MSK) >= TX_CON_WANT_SCL &&
+ !((s->fe->options2|s->be->options2) & PR_O2_FAKE_KA)))
+ to_del |= 2; /* remove "keep-alive" */
+ if (!(msg->flags & HTTP_MSGF_VER_11))
+ to_del |= 1; /* remove "close" */
+ http_parse_connection_header(txn, msg, to_del);
+ }
+
+ /* check if client or config asks for explicit close in KAL/SCL */
+ if (((txn->flags & TX_CON_WANT_MSK) == TX_CON_WANT_KAL ||
+ (txn->flags & TX_CON_WANT_MSK) == TX_CON_WANT_SCL) &&
+ ((txn->flags & TX_HDR_CONN_CLO) || /* "connection: close" */
+ (!(msg->flags & HTTP_MSGF_VER_11) && !(txn->flags & TX_HDR_CONN_KAL)) || /* no "connection: k-a" in 1.0 */
+ !(msg->flags & HTTP_MSGF_XFER_LEN) || /* no length known => close */
+ s->fe->state == PR_STSTOPPED)) /* frontend is stopping */
+ txn->flags = (txn->flags & ~TX_CON_WANT_MSK) | TX_CON_WANT_CLO;
+}
/* This stream analyser waits for a complete HTTP request. It returns 1 if the
* processing can continue on next analysers, or zero if it either needs more
@@ -2929,58 +2982,8 @@ int http_wait_for_request(struct session *s, struct channel *req, int an_bit)
* time.
*/
if (!(txn->flags & TX_HDR_CONN_PRS) ||
- ((s->fe->options & PR_O_HTTP_MODE) != (s->be->options & PR_O_HTTP_MODE))) {
- int tmp = TX_CON_WANT_KAL;
-
- if (!((s->fe->options2|s->be->options2) & PR_O2_FAKE_KA)) {
- if ((s->fe->options & PR_O_HTTP_MODE) == PR_O_HTTP_TUN ||
- (s->be->options & PR_O_HTTP_MODE) == PR_O_HTTP_TUN)
- tmp = TX_CON_WANT_TUN;
-
- if ((s->fe->options & PR_O_HTTP_MODE) == PR_O_HTTP_PCL ||
- (s->be->options & PR_O_HTTP_MODE) == PR_O_HTTP_PCL)
- tmp = TX_CON_WANT_TUN;
- }
-
- if ((s->fe->options & PR_O_HTTP_MODE) == PR_O_HTTP_SCL ||
- (s->be->options & PR_O_HTTP_MODE) == PR_O_HTTP_SCL) {
- /* option httpclose + server_close => forceclose */
- if ((s->fe->options & PR_O_HTTP_MODE) == PR_O_HTTP_PCL ||
- (s->be->options & PR_O_HTTP_MODE) == PR_O_HTTP_PCL)
- tmp = TX_CON_WANT_CLO;
- else
- tmp = TX_CON_WANT_SCL;
- }
-
- if ((s->fe->options & PR_O_HTTP_MODE) == PR_O_HTTP_FCL ||
- (s->be->options & PR_O_HTTP_MODE) == PR_O_HTTP_FCL)
- tmp = TX_CON_WANT_CLO;
-
- if ((txn->flags & TX_CON_WANT_MSK) < tmp)
- txn->flags = (txn->flags & ~TX_CON_WANT_MSK) | tmp;
-
- if (!(txn->flags & TX_HDR_CONN_PRS) &&
- (txn->flags & TX_CON_WANT_MSK) != TX_CON_WANT_TUN) {
- /* parse the Connection header and possibly clean it */
- int to_del = 0;
- if ((msg->flags & HTTP_MSGF_VER_11) ||
- ((txn->flags & TX_CON_WANT_MSK) >= TX_CON_WANT_SCL &&
- !((s->fe->options2|s->be->options2) & PR_O2_FAKE_KA)))
- to_del |= 2; /* remove "keep-alive" */
- if (!(msg->flags & HTTP_MSGF_VER_11))
- to_del |= 1; /* remove "close" */
- http_parse_connection_header(txn, msg, to_del);
- }
-
- /* check if client or config asks for explicit close in KAL/SCL */
- if (((txn->flags & TX_CON_WANT_MSK) == TX_CON_WANT_KAL ||
- (txn->flags & TX_CON_WANT_MSK) == TX_CON_WANT_SCL) &&
- ((txn->flags & TX_HDR_CONN_CLO) || /* "connection: close" */
- (!(msg->flags & HTTP_MSGF_VER_11) && !(txn->flags & TX_HDR_CONN_KAL)) || /* no "connection: k-a" in 1.0 */
- !(msg->flags & HTTP_MSGF_XFER_LEN) || /* no length known => close */
- s->fe->state == PR_STSTOPPED)) /* frontend is stopping */
- txn->flags = (txn->flags & ~TX_CON_WANT_MSK) | TX_CON_WANT_CLO;
- }
+ ((s->fe->options & PR_O_HTTP_MODE) != (s->be->options & PR_O_HTTP_MODE)))
+ http_adjust_conn_mode(s, txn, msg);
/* end of job, return OK */
req->analysers &= ~an_bit;
diff --git a/src/proxy.c b/src/proxy.c
index 02103ee..405c4c4 100644
--- a/src/proxy.c
+++ b/src/proxy.c
@@ -955,6 +955,14 @@ int session_set_backend(struct session *s, struct proxy *be)
http_init_txn(s);
}
+ /* If we chain to an HTTP backend running a different HTTP mode, we
+ * have to re-adjust the desired keep-alive/close mode to accommodate
+ * both the frontend's and the backend's modes.
+ */
+ if (s->fe->mode == PR_MODE_HTTP && be->mode == PR_MODE_HTTP &&
+ ((s->fe->options & PR_O_HTTP_MODE) != (be->options & PR_O_HTTP_MODE)))
+ http_adjust_conn_mode(s, &s->txn, &s->txn.req);
+
/* If an LB algorithm needs to access some pre-parsed body contents,
* we must not start to forward anything until the connection is
* confirmed otherwise we'll lose the pointer to these data and
--
2.0.4

View File

@ -0,0 +1,46 @@
From b3228c83e320ad168f5b3e6884e771530a68a449 Mon Sep 17 00:00:00 2001
From: Willy Tarreau <w@1wt.eu>
Date: Wed, 1 Oct 2014 20:50:17 +0200
Subject: [PATCH 17/20] BUG/MINOR: config: don't propagate process binding on
fatal errors.
propagate_processes() must not be called with unresolved proxies, but
nothing prevents it from being called in check_config_validity(). The
resulting effect is that an unresolved proxy can cause a recursion
loop if called in such a situation, ending with a segfault after the
fatal error report. There's no side effect beyond this.
This patch refrains from calling the function when any error was met.
This bug also affects 1.5, it should be backported.
(cherry picked from commit acbe8ab38a638a076f8cf9fe2635db0e729d6a1f)
---
src/cfgparse.c | 12 ++++++++----
1 file changed, 8 insertions(+), 4 deletions(-)
diff --git a/src/cfgparse.c b/src/cfgparse.c
index f723a3a..6e962c8 100644
--- a/src/cfgparse.c
+++ b/src/cfgparse.c
@@ -7112,10 +7112,14 @@ out_uri_auth_compat:
global.stats_fe->bind_proc = ~0UL;
}
- /* propagate bindings from frontends to backends */
- for (curproxy = proxy; curproxy; curproxy = curproxy->next) {
- if (curproxy->cap & PR_CAP_FE)
- propagate_processes(curproxy, NULL);
+ /* propagate bindings from frontends to backends. Don't do it if there
+ * are any fatal errors as we must not call it with unresolved proxies.
+ */
+ if (!cfgerr) {
+ for (curproxy = proxy; curproxy; curproxy = curproxy->next) {
+ if (curproxy->cap & PR_CAP_FE)
+ propagate_processes(curproxy, NULL);
+ }
}
/* Bind each unbound backend to all processes when not specified. */
--
2.0.4

View File

@ -0,0 +1,102 @@
From e61737a721c3b91c79484e51fc1789293b269f9f Mon Sep 17 00:00:00 2001
From: Willy Tarreau <w@1wt.eu>
Date: Thu, 2 Oct 2014 14:30:14 +0200
Subject: [PATCH 18/20] BUG/MEDIUM: check: rule-less tcp-check must detect
connect failures
When "option tcp-check" is specified without any tcp-check rules, the
documentation says that it's the same as the default check method. But
the code path is a bit different, and we used to consider that since
the end of rules was reached, the check is always successful regardless
of the connection status.
This patch reorganizes the error detection, and considers the special
case where there's no tcp-check rule as a real L4 check. It also avoids
dereferencing the rule list head as a rule by itself.
While fixing this bug, another one related to the output messages'
accuracy was noticed, it will be fixed in a separate commit and is
much less important.
This bug is also present in 1.5, so this fix must be backported.
(cherry picked from commit ef953953e7f33c6a72c432fce8d47c2d84c69512)
---
src/checks.c | 40 +++++++++++++++++++++++++---------------
1 file changed, 25 insertions(+), 15 deletions(-)
diff --git a/src/checks.c b/src/checks.c
index f3b2b54..9c1a866 100644
--- a/src/checks.c
+++ b/src/checks.c
@@ -1837,20 +1837,34 @@ static int tcpcheck_get_step_id(struct server *s)
static void tcpcheck_main(struct connection *conn)
{
char *contentptr;
- struct list *head = NULL;
struct tcpcheck_rule *cur = NULL;
int done = 0, ret = 0;
-
struct check *check = conn->owner;
struct server *s = check->server;
struct task *t = check->task;
+ struct list *head = &s->proxy->tcpcheck_rules;
- /*
- * don't do anything until the connection is established but if we're running
- * first step which must be a connect
+ /* here, we know that the check is complete or that it failed */
+ if (check->result != CHK_RES_UNKNOWN)
+ goto out_end_tcpcheck;
+
+ /* We have 4 possibilities here :
+ * 1. we've not yet attempted step 1, and step 1 is a connect, so no
+ * connection attempt was made yet ;
+ * 2. we've not yet attempted step 1, and step 1 is a not connect or
+ * does not exist (no rule), so a connection attempt was made
+ * before coming here.
+ * 3. we're coming back after having started with step 1, so we may
+ * be waiting for a connection attempt to complete.
+ * 4. the connection + handshake are complete
+ *
+ * #2 and #3 are quite similar, we want both the connection and the
+ * handshake to complete before going any further. Thus we must always
+ * wait for a connection to complete unless we're before and existing
+ * step 1.
*/
- if (check->current_step && (!(conn->flags & CO_FL_CONNECTED))) {
- /* update expire time, should be done by process_chk */
+ if ((!(conn->flags & CO_FL_CONNECTED) || (conn->flags & CO_FL_HANDSHAKE)) &&
+ (check->current_step || LIST_ISEMPTY(head))) {
/* we allow up to min(inter, timeout.connect) for a connection
* to establish but only when timeout.check is set
* as it may be to short for a full check otherwise
@@ -1867,12 +1881,11 @@ static void tcpcheck_main(struct connection *conn)
return;
}
- /* here, we know that the connection is established */
- if (check->result != CHK_RES_UNKNOWN)
+ /* special case: option tcp-check with no rule, a connect is enough */
+ if (LIST_ISEMPTY(head)) {
+ set_server_check_status(check, HCHK_STATUS_L4OK, NULL);
goto out_end_tcpcheck;
-
- /* head is be the first element of the double chained list */
- head = &s->proxy->tcpcheck_rules;
+ }
/* no step means first step
* initialisation */
@@ -1891,9 +1904,6 @@ static void tcpcheck_main(struct connection *conn)
cur = check->current_step;
}
- if (conn->flags & CO_FL_HANDSHAKE)
- return;
-
/* It's only the rules which will enable send/recv */
__conn_data_stop_both(conn);
--
2.0.4

View File

@ -0,0 +1,111 @@
From 90055f28a7a0c86cfb37ccb23a548a1da7229551 Mon Sep 17 00:00:00 2001
From: Willy Tarreau <w@1wt.eu>
Date: Thu, 2 Oct 2014 14:51:02 +0200
Subject: [PATCH 19/20] BUG/MINOR: tcp-check: report the correct failed step in
the status
The step number was reported by checking only last_started_step, which
was not set in case of error during the initial connection phase, and
caused "step 1" to be returned with an invalid check type (typically
SEND). So now we first verify that a test was started before returning
this.
In addition to this, the indication of the test type was taken from
current_step instead of last_started_step, so the error description
was matching the next action instead of the one reported in the step
ID. Thus we could get the confusing "step 1 (send)" report below :
tcp-check connect
tcp-check send foo
In order to ease debugging, when the port number is known for a connect,
it is indicated in the error report.
Note that this only affects asynchronous error messages, synchronous ones
are correct.
This fix must be backported to 1.5.
(cherry picked from commit 213c6785614d0228d7e96e982e5189e1d0777059)
---
src/checks.c | 43 ++++++++++++++++++++++++++++---------------
1 file changed, 28 insertions(+), 15 deletions(-)
diff --git a/src/checks.c b/src/checks.c
index 9c1a866..5318f35 100644
--- a/src/checks.c
+++ b/src/checks.c
@@ -580,6 +580,7 @@ static void chk_report_conn_err(struct connection *conn, int errno_bck, int expi
struct check *check = conn->owner;
const char *err_msg;
struct chunk *chk;
+ int step;
if (check->result != CHK_RES_UNKNOWN)
return;
@@ -599,19 +600,27 @@ static void chk_report_conn_err(struct connection *conn, int errno_bck, int expi
chk = get_trash_chunk();
if (check->type == PR_O2_TCPCHK_CHK) {
- chunk_printf(chk, " at step %d of tcp-check", tcpcheck_get_step_id(check->server));
- /* we were looking for a string */
- if (check->current_step && check->current_step->action == TCPCHK_ACT_CONNECT) {
- chunk_appendf(chk, " (connect)");
- }
- else if (check->current_step && check->current_step->action == TCPCHK_ACT_EXPECT) {
- if (check->current_step->string)
- chunk_appendf(chk, " (string '%s')", check->current_step->string);
- else if (check->current_step->expect_regex)
- chunk_appendf(chk, " (expect regex)");
- }
- else if (check->current_step && check->current_step->action == TCPCHK_ACT_SEND) {
- chunk_appendf(chk, " (send)");
+ step = tcpcheck_get_step_id(check->server);
+ if (!step)
+ chunk_printf(chk, " at initial connection step of tcp-check");
+ else {
+ chunk_printf(chk, " at step %d of tcp-check", step);
+ /* we were looking for a string */
+ if (check->last_started_step && check->last_started_step->action == TCPCHK_ACT_CONNECT) {
+ if (check->last_started_step->port)
+ chunk_appendf(chk, " (connect port %d)" ,check->last_started_step->port);
+ else
+ chunk_appendf(chk, " (connect)");
+ }
+ else if (check->last_started_step && check->last_started_step->action == TCPCHK_ACT_EXPECT) {
+ if (check->last_started_step->string)
+ chunk_appendf(chk, " (string '%s')", check->last_started_step->string);
+ else if (check->last_started_step->expect_regex)
+ chunk_appendf(chk, " (expect regex)");
+ }
+ else if (check->last_started_step && check->last_started_step->action == TCPCHK_ACT_SEND) {
+ chunk_appendf(chk, " (send)");
+ }
}
}
@@ -1818,6 +1827,10 @@ static int tcpcheck_get_step_id(struct server *s)
struct tcpcheck_rule *cur = NULL, *next = NULL;
int i = 0;
+ /* not even started anything yet => step 0 = initial connect */
+ if (!s->check.current_step)
+ return 0;
+
cur = s->check.last_started_step;
/* no step => first step */
@@ -1887,9 +1900,9 @@ static void tcpcheck_main(struct connection *conn)
goto out_end_tcpcheck;
}
- /* no step means first step
- * initialisation */
+ /* no step means first step initialisation */
if (check->current_step == NULL) {
+ check->last_started_step = NULL;
check->bo->p = check->bo->data;
check->bo->o = 0;
check->bi->p = check->bi->data;
--
2.0.4

View File

@ -0,0 +1,34 @@
From c8d57dec6173430bd5602bb76efff302c51e7803 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Cyril=20Bont=C3=A9?= <cyril.bonte@free.fr>
Date: Thu, 2 Oct 2014 19:56:25 +0200
Subject: [PATCH 20/20] BUG/MINOR: config: don't propagate process binding for
dynamic use_backend
A segfault was reported with the introduction of the propagate_processes()
function. It was caused when a use_backend rule was declared with a dynamic
name, using a log-format string. The backend is not resolved during the
configuration, which lead to the segfault.
The patch prevents the process binding propagation for such dynamic rules, it
should also be backported to 1.5.
(cherry picked from commit 51639696e0a112ea3612e905a5722ad912b3869f)
---
src/cfgparse.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/src/cfgparse.c b/src/cfgparse.c
index 6e962c8..ec6d923 100644
--- a/src/cfgparse.c
+++ b/src/cfgparse.c
@@ -6015,6 +6015,8 @@ void propagate_processes(struct proxy *from, struct proxy *to)
/* use_backend */
list_for_each_entry(rule, &from->switching_rules, list) {
+ if (rule->dynamic)
+ continue;
to = rule->be.backend;
propagate_processes(from, to);
}
--
2.0.4