MEDIUM: config: properly propagate process binding between proxies
We now recursively propagate the bind-process values between frontends
and backends instead of doing it during name resolving. This ensures
that we're able to properly propagate all the bind-process directives
even across "listen" instances, which are not perfectly covered at the
moment, depending on the declaration order.
(cherry picked from commit 64ab6077b768ee02b04a36b30ee195639a2fabc1)
diff --git a/src/cfgparse.c b/src/cfgparse.c
index 5288600..b9853ef 100644
--- a/src/cfgparse.c
+++ b/src/cfgparse.c
@@ -5932,6 +5932,64 @@
return err_code;
}
+/* This function propagates processes from frontend <from> to backend <to> so
+ * that it is always guaranteed that a backend pointed to by a frontend is
+ * bound to all of its processes. After that, if the target is a "listen"
+ * instance, the function recursively descends the target's own targets along
+ * default_backend, use_backend rules, and reqsetbe rules. Since the bits are
+ * checked first to ensure that <to> is already bound to all processes of
+ * <from>, there is no risk of looping and we ensure to follow the shortest
+ * path to the destination.
+ *
+ * It is possible to set <to> to NULL for the first call so that the function
+ * takes care of visiting the initial frontend in <from>.
+ *
+ * It is important to note that the function relies on the fact that all names
+ * have already been resolved.
+ */
+void propagate_processes(struct proxy *from, struct proxy *to)
+{
+ struct switching_rule *rule;
+ struct hdr_exp *exp;
+
+ if (to) {
+ /* check whether we need to go down */
+ if (from->bind_proc &&
+ (from->bind_proc & to->bind_proc) == from->bind_proc)
+ return;
+
+ if (!from->bind_proc && !to->bind_proc)
+ return;
+
+ to->bind_proc = from->bind_proc ?
+ (to->bind_proc | from->bind_proc) : 0;
+
+ /* now propagate down */
+ from = to;
+ }
+
+ if (!from->cap & PR_CAP_FE)
+ return;
+
+ /* default_backend */
+ if (from->defbe.be)
+ propagate_processes(from, from->defbe.be);
+
+ /* use_backend */
+ list_for_each_entry(rule, &from->switching_rules, list) {
+ to = rule->be.backend;
+ propagate_processes(from, to);
+ }
+
+ /* reqsetbe */
+ for (exp = from->req_exp; exp != NULL; exp = exp->next) {
+ if (exp->action != ACT_SETBE)
+ continue;
+ to = (struct proxy *)exp->replace;
+ propagate_processes(from, to);
+ }
+}
+
/*
* Returns the error code, 0 if OK, or any combination of :
* - ERR_ABORT: must abort ASAP
@@ -6162,11 +6220,6 @@
} else {
free(curproxy->defbe.name);
curproxy->defbe.be = target;
- /* we force the backend to be present on at least all of
- * the frontend's processes.
- */
- target->bind_proc = curproxy->bind_proc ?
- (target->bind_proc | curproxy->bind_proc) : 0;
/* Emit a warning if this proxy also has some servers */
if (curproxy->srv) {
@@ -6199,11 +6252,6 @@
} else {
free((void *)exp->replace);
exp->replace = (const char *)target;
- /* we force the backend to be present on at least all of
- * the frontend's processes.
- */
- target->bind_proc = curproxy->bind_proc ?
- (target->bind_proc | curproxy->bind_proc) : 0;
}
}
}
@@ -6252,15 +6300,10 @@
} else {
free((void *)rule->be.name);
rule->be.backend = target;
- /* we force the backend to be present on at least all of
- * the frontend's processes.
- */
- target->bind_proc = curproxy->bind_proc ?
- (target->bind_proc | curproxy->bind_proc) : 0;
}
}
- /* find the target proxy for 'use_backend' rules */
+ /* find the target server for 'use_server' rules */
list_for_each_entry(srule, &curproxy->server_rules, list) {
struct server *target = findserver(curproxy, srule->srv.name);
@@ -7131,6 +7174,12 @@
}
}
+ /* At this point, target names have already been resolved */
+ for (curproxy = proxy; curproxy; curproxy = curproxy->next) {
+ if (curproxy->cap & PR_CAP_FE)
+ propagate_processes(curproxy, NULL);
+ }
+
/* automatically compute fullconn if not set. We must not do it in the
* loop above because cross-references are not yet fully resolved.
*/