diff --git a/include/haproxy/proxy.h b/include/haproxy/proxy.h index afa6297c3..089ab9e22 100644 --- a/include/haproxy/proxy.h +++ b/include/haproxy/proxy.h @@ -74,8 +74,7 @@ void defaults_px_destroy_all_unref(void); void defaults_px_detach(struct proxy *px); void defaults_px_ref_all(void); void defaults_px_unref_all(void); - -void proxy_ref_defaults(struct proxy *px, struct proxy *defpx); +int proxy_ref_defaults(struct proxy *px, struct proxy *defpx, char **errmsg); void proxy_unref_defaults(struct proxy *px); int setup_new_proxy(struct proxy *px, const char *name, unsigned int cap, char **errmsg); struct proxy *alloc_new_proxy(const char *name, unsigned int cap, diff --git a/src/cfgparse-listen.c b/src/cfgparse-listen.c index bcb085936..68b2eba88 100644 --- a/src/cfgparse-listen.c +++ b/src/cfgparse-listen.c @@ -501,84 +501,10 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm) curproxy->conf.file_prev = file_prev; curproxy->conf.line_prev = line_prev; - if (curr_defproxy && (!LIST_ISEMPTY(&curr_defproxy->http_req_rules) || - !LIST_ISEMPTY(&curr_defproxy->http_res_rules) || - !LIST_ISEMPTY(&curr_defproxy->http_after_res_rules) || - !LIST_ISEMPTY(&curr_defproxy->tcp_req.l4_rules) || - !LIST_ISEMPTY(&curr_defproxy->tcp_req.l5_rules) || - !LIST_ISEMPTY(&curr_defproxy->tcp_req.inspect_rules) || - !LIST_ISEMPTY(&curr_defproxy->tcp_rep.inspect_rules))) { - /* If the current default proxy defines TCP/HTTP rules, the - * current proxy will keep a reference on it. But some sanity - * checks are performed first: - * - * - It cannot be used to init a defaults section - * - It cannot be used to init a listen section - * - It cannot be used to init backend and frontend sections at - * same time. It can be used to init several sections of the - * same type only. - * - It cannot define L4/L5 TCP rules if it is used to init - * backend sections. - * - It cannot define 'tcp-response content' rules if it - * is used to init frontend sections. - * - * If no error is found, refcount of the default proxy is incremented. - */ - - /* Note: Add tcpcheck_rules too if unresolve args become allowed in defaults section */ - if (rc & PR_CAP_DEF) { - ha_alert("parsing [%s:%d]: a defaults section cannot inherit from a defaults section defining TCP/HTTP rules (defaults section at %s:%d).\n", - file, linenum, curr_defproxy->conf.file, curr_defproxy->conf.line); - err_code |= ERR_ALERT | ERR_ABORT; - } - else if ((rc & PR_CAP_LISTEN) == PR_CAP_LISTEN) { - ha_alert("parsing [%s:%d]: a listen section cannot inherit from a defaults section defining TCP/HTTP rules.\n", - file, linenum); - err_code |= ERR_ALERT | ERR_ABORT; - } - else { - char defcap = (curr_defproxy->cap & PR_CAP_LISTEN); - - if ((defcap == PR_CAP_BE || defcap == PR_CAP_FE) && (rc & PR_CAP_LISTEN) != defcap) { - ha_alert("parsing [%s:%d]: frontends and backends cannot inherit from the same defaults section" - " if it defines TCP/HTTP rules (defaults section at %s:%d).\n", - file, linenum, curr_defproxy->conf.file, curr_defproxy->conf.line); - err_code |= ERR_ALERT | ERR_ABORT; - } - else if (!(rc & PR_CAP_FE) && (!LIST_ISEMPTY(&curr_defproxy->tcp_req.l4_rules) || - !LIST_ISEMPTY(&curr_defproxy->tcp_req.l5_rules))) { - ha_alert("parsing [%s:%d]: a backend section cannot inherit from a defaults section defining" - " 'tcp-request connection' or 'tcp-request session' rules (defaults section at %s:%d).\n", - file, linenum, curr_defproxy->conf.file, curr_defproxy->conf.line); - err_code |= ERR_ALERT | ERR_ABORT; - } - else if (!(rc & PR_CAP_BE) && !LIST_ISEMPTY(&curr_defproxy->tcp_rep.inspect_rules)) { - ha_alert("parsing [%s:%d]: a frontend section cannot inherit from a defaults section defining" - " 'tcp-response content' rules (defaults section at %s:%d).\n", - file, linenum, curr_defproxy->conf.file, curr_defproxy->conf.line); - err_code |= ERR_ALERT | ERR_ABORT; - } - else { - curr_defproxy->cap = (curr_defproxy->cap & ~PR_CAP_LISTEN) | (rc & PR_CAP_LISTEN); - proxy_ref_defaults(curproxy, curr_defproxy); - } - } - } - - if (curr_defproxy && (curr_defproxy->tcpcheck_rules.flags & TCPCHK_RULES_PROTO_CHK) && - (curproxy->cap & PR_CAP_LISTEN) == PR_CAP_BE) { - /* If the current default proxy defines tcpcheck rules, the - * current proxy will keep a reference on it. but only if the - * current proxy has the backend capability. - */ - proxy_ref_defaults(curproxy, curr_defproxy); - } - - if ((rc & PR_CAP_BE) && curr_defproxy && (curr_defproxy->nb_req_cap || curr_defproxy->nb_rsp_cap)) { - ha_alert("parsing [%s:%d]: backend or defaults sections cannot inherit from a defaults section defining" - " capptures (defaults section at %s:%d).\n", - file, linenum, curr_defproxy->conf.file, curr_defproxy->conf.line); - err_code |= ERR_ALERT | ERR_ABORT; + if (curr_defproxy) { + err_code = proxy_ref_defaults(curproxy, curr_defproxy, &errmsg); + if (err_code) + ha_alert("parsing [%s:%d]: %s.\n", file, linenum, errmsg); } if (rc & PR_CAP_DEF) { diff --git a/src/proxy.c b/src/proxy.c index 7f573659e..fc65f3c06 100644 --- a/src/proxy.c +++ b/src/proxy.c @@ -3010,15 +3010,113 @@ void defaults_px_unref_all(void) * refcount is incremented by one. For now, this operation is not thread safe * and is perform during init stage only. */ -void proxy_ref_defaults(struct proxy *px, struct proxy *defpx) +static inline void defaults_px_ref(struct proxy *defpx, struct proxy *px) { if (px->defpx == defpx) return; - BUG_ON(px->defpx != NULL); + /* is already referencing another defaults. */ + BUG_ON(px->defpx); + px->defpx = defpx; defpx->conf.refcount++; } +/* Check that can inherits from default proxy. If some settings + * cannot be copied, refcount of the defaults instance is incremented. + * Inheritance may be impossible due to incompatibility issues. In this case, + * will be allocated to point to a textual description of the error. + * + * Returns ERR_NONE on success and a combination of ERR_CODE on failure + */ +int proxy_ref_defaults(struct proxy *px, struct proxy *defpx, char **errmsg) +{ + char defcap = defpx->cap & PR_CAP_LISTEN; + int err_code = ERR_NONE; + + if ((px->cap & PR_CAP_BE) && (defpx->nb_req_cap || defpx->nb_rsp_cap)) { + memprintf(errmsg, "backend or defaults sections cannot inherit from a defaults section defining" + " captures (defaults section at %s:%d)", + defpx->conf.file, defpx->conf.line); + err_code |= ERR_ALERT | ERR_ABORT; + goto out; + } + + /* If the current default proxy defines TCP/HTTP rules, the + * current proxy will keep a reference on it. But some sanity + * checks are performed first: + * + * - It cannot be used to init a defaults section + * - It cannot be used to init a listen section + * - It cannot be used to init backend and frontend sections at + * same time. It can be used to init several sections of the + * same type only. + * - It cannot define L4/L5 TCP rules if it is used to init + * backend sections. + * - It cannot define 'tcp-response content' rules if it + * is used to init frontend sections. + * + * If no error is found, refcount of the default proxy is incremented. + */ + if ((!LIST_ISEMPTY(&defpx->http_req_rules) || + !LIST_ISEMPTY(&defpx->http_res_rules) || + !LIST_ISEMPTY(&defpx->http_after_res_rules) || + !LIST_ISEMPTY(&defpx->tcp_req.l4_rules) || + !LIST_ISEMPTY(&defpx->tcp_req.l5_rules) || + !LIST_ISEMPTY(&defpx->tcp_req.inspect_rules) || + !LIST_ISEMPTY(&defpx->tcp_rep.inspect_rules))) { + + /* Note: Add tcpcheck_rules too if unresolve args become allowed in defaults section */ + if (px->cap & PR_CAP_DEF) { + memprintf(errmsg, "a defaults section cannot inherit from a defaults section defining TCP/HTTP rules (defaults section at %s:%d)", + defpx->conf.file, defpx->conf.line); + err_code |= ERR_ALERT | ERR_ABORT; + goto out; + } + else if ((px->cap & PR_CAP_LISTEN) == PR_CAP_LISTEN) { + memprintf(errmsg, "a listen section cannot inherit from a defaults section defining TCP/HTTP rules"); + err_code |= ERR_ALERT | ERR_ABORT; + goto out; + } + else if ((defcap == PR_CAP_BE || defcap == PR_CAP_FE) && (px->cap & PR_CAP_LISTEN) != defcap) { + memprintf(errmsg, "frontends and backends cannot inherit from the same defaults section" + " if it defines TCP/HTTP rules (defaults section at %s:%d)", + defpx->conf.file, defpx->conf.line); + err_code |= ERR_ALERT | ERR_ABORT; + goto out; + } + else if (!(px->cap & PR_CAP_FE) && (!LIST_ISEMPTY(&defpx->tcp_req.l4_rules) || + !LIST_ISEMPTY(&defpx->tcp_req.l5_rules))) { + memprintf(errmsg, "a backend section cannot inherit from a defaults section defining" + " 'tcp-request connection' or 'tcp-request session' rules (defaults section at %s:%d)", + defpx->conf.file, defpx->conf.line); + err_code |= ERR_ALERT | ERR_ABORT; + goto out; + } + else if (!(px->cap & PR_CAP_BE) && !LIST_ISEMPTY(&defpx->tcp_rep.inspect_rules)) { + memprintf(errmsg, "a frontend section cannot inherit from a defaults section defining" + " 'tcp-response content' rules (defaults section at %s:%d)", + defpx->conf.file, defpx->conf.line); + err_code |= ERR_ALERT | ERR_ABORT; + goto out; + } + + defpx->cap = (defpx->cap & ~PR_CAP_LISTEN) | (px->cap & PR_CAP_LISTEN); + defaults_px_ref(defpx, px); + } + + if ((defpx->tcpcheck_rules.flags & TCPCHK_RULES_PROTO_CHK) && + (px->cap & PR_CAP_LISTEN) == PR_CAP_BE) { + /* If the current default proxy defines tcpcheck rules, the + * current proxy will keep a reference on it. but only if the + * current proxy has the backend capability. + */ + defaults_px_ref(defpx, px); + } + + out: + return err_code; +} + /* proxy removes its reference on its default proxy. The default proxy * refcount is decremented by one. If it was the last reference, the * corresponding default proxy is destroyed. For now this operation is not