From 27c8d20451e800a03ad639887fd0feee25a44a9d Mon Sep 17 00:00:00 2001 From: Christopher Faulet Date: Wed, 13 Oct 2021 09:50:53 +0200 Subject: [PATCH] MINOR: proxy: Be able to reference the defaults section used by a proxy A proxy may now references the defaults section it is used. To do so, a pointer on the default proxy was added in the proxy structure. And a refcount must be used to track proxies using a default proxy. A default proxy is destroyed iff its refcount is equal to zero and when it drops to zero. All this stuff must be performed during init/deinit staged for now. All unreferenced default proxies are removed after the configuration parsing. This patch is mandatory to support TCP/HTTP rules in defaults sections. --- include/haproxy/proxy-t.h | 2 ++ include/haproxy/proxy.h | 4 +++- src/haproxy.c | 8 ++++++-- src/proxy.c | 42 ++++++++++++++++++++++++++++++++++++--- 4 files changed, 50 insertions(+), 6 deletions(-) diff --git a/include/haproxy/proxy-t.h b/include/haproxy/proxy-t.h index b2285bbeb..20c97dab9 100644 --- a/include/haproxy/proxy-t.h +++ b/include/haproxy/proxy-t.h @@ -275,6 +275,7 @@ struct proxy { struct proxy *be; /* default backend, or NULL if none set */ char *name; /* default backend name during config parse */ } defbe; + struct proxy *defpx; /* default proxy used to init this one (may be NULL) */ struct list acl; /* ACL declared on this proxy */ struct list http_req_rules; /* HTTP request rules: allow/deny/... */ struct list http_res_rules; /* HTTP response rules: allow/deny/... */ @@ -421,6 +422,7 @@ struct proxy { struct list listeners; /* list of listeners belonging to this frontend */ struct list errors; /* list of all custom error files */ struct arg_list args; /* sample arg list that need to be resolved */ + unsigned int refcount; /* refcount on this proxy (only used for default proxy for now) */ struct ebpt_node by_name; /* proxies are stored sorted by name here */ char *logformat_string; /* log format string */ char *lfs_file; /* file name where the logformat string appears (strdup) */ diff --git a/include/haproxy/proxy.h b/include/haproxy/proxy.h index e47a577fe..1fc7a0982 100644 --- a/include/haproxy/proxy.h +++ b/include/haproxy/proxy.h @@ -61,7 +61,9 @@ void init_new_proxy(struct proxy *p); void proxy_preset_defaults(struct proxy *defproxy); void proxy_free_defaults(struct proxy *defproxy); void proxy_destroy_defaults(struct proxy *px); -void proxy_destroy_all_defaults(void); +void proxy_destroy_all_unref_defaults(void); +void proxy_ref_defaults(struct proxy *px, struct proxy *defpx); +void proxy_unref_defaults(struct proxy *px); struct proxy *alloc_new_proxy(const char *name, unsigned int cap, char **errmsg); struct proxy *parse_new_proxy(const char *name, unsigned int cap, diff --git a/src/haproxy.c b/src/haproxy.c index 3c41c86fb..e3ccea77e 100644 --- a/src/haproxy.c +++ b/src/haproxy.c @@ -1990,8 +1990,9 @@ static void init(int argc, char **argv) ha_warning("a master CLI socket was defined, but master-worker mode (-W) is not enabled.\n"); } - /* defaults sections are not needed anymore */ - proxy_destroy_all_defaults(); + /* destroy unreferenced defaults proxies */ + proxy_destroy_all_unref_defaults(); + err_code |= check_config_validity(); for (px = proxies_list; px; px = px->next) { @@ -2483,6 +2484,9 @@ void deinit(void) free_proxy(p0); }/* end while(p) */ + /* destroy all referenced defaults proxies */ + proxy_destroy_all_unref_defaults(); + while (ua) { struct stat_scope *scope, *scopep; diff --git a/src/proxy.c b/src/proxy.c index c99f3a53a..36e278321 100644 --- a/src/proxy.c +++ b/src/proxy.c @@ -146,6 +146,7 @@ void free_proxy(struct proxy *p) if (!p) return; + proxy_unref_defaults(p); free(p->conf.file); free(p->id); free(p->cookie_name); @@ -1471,22 +1472,57 @@ void proxy_destroy_defaults(struct proxy *px) return; if (!(px->cap & PR_CAP_DEF)) return; + BUG_ON(px->conf.refcount != 0); ebpt_delete(&px->conf.by_name); proxy_free_defaults(px); free(px); } -void proxy_destroy_all_defaults() +/* delete all unreferenced default proxies. A default proxy is unreferenced if + * its refcount is equal to zero. + */ +void proxy_destroy_all_unref_defaults() { struct ebpt_node *n; - while ((n = ebpt_first(&defproxy_by_name))) { + n = ebpt_first(&defproxy_by_name); + while (n) { struct proxy *px = container_of(n, struct proxy, conf.by_name); BUG_ON(!(px->cap & PR_CAP_DEF)); - proxy_destroy_defaults(px); + n = ebpt_next(n); + if (!px->conf.refcount) + proxy_destroy_defaults(px); } } +/* Add a reference on the default proxy for the proxy Nothing is + * done if already references . Otherwise, the default proxy + * 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) +{ + if (px->defpx == defpx) + return; + BUG_ON(px->defpx != NULL); + px->defpx = defpx; + defpx->conf.refcount++; +} + +/* 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 + * thread safe and is performed during deinit staged only. +*/ +void proxy_unref_defaults(struct proxy *px) +{ + if (px->defpx == NULL) + return; + if (!--px->defpx->conf.refcount) + proxy_destroy_defaults(px->defpx); + px->defpx = NULL; +} + /* Allocates a new proxy of type . * Returns the proxy instance on success. On error, NULL is returned. */