]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: listener: implement GUID support
authorAmaury Denoyelle <adenoyelle@haproxy.com>
Tue, 2 Apr 2024 08:44:08 +0000 (10:44 +0200)
committerAmaury Denoyelle <adenoyelle@haproxy.com>
Fri, 5 Apr 2024 13:40:42 +0000 (15:40 +0200)
This commit is similar with the two previous ones. Its purpose is to add
GUID support on listeners. Due to bind_conf and listeners configuration,
some specifities were required.

Its possible to define several listeners on a single bind line, for
example by specifying multiple addresses. As such, it's impossible to
support a "guid" keyword on a bind line. The problem is exacerbated by
the cloning of listeners when sharding is used.

To resolve this, a new keyword "guid-prefix" is defined for bind lines.
It allows to specify a string which will be used as a prefix for
automatically generated GUID for each listeners attached to a bind_conf.

Automatic GUID listeners generation is implemented via a new function
bind_generate_guid(). It is called on post-parsing, after
bind_complete_thread_setup(). For each listeners on a bind_conf, a new
GUID is generated with bind_conf prefix and the index of the listener
relative to other listeners in the bind_conf. This last value is stored
in a new bind_conf field named <guid_idx>. If a GUID cannot be inserted,
for example due to a non-unique value, an error is returned, startup is
interrupted with configuration rejected.

doc/configuration.txt
include/haproxy/listener-t.h
include/haproxy/listener.h
src/cfgparse.c
src/guid.c
src/listener.c
src/proxy.c

index c42f9ea59459f702d511b31dcebe3c026c1ea4fe..085bbe1734a6e27d938314710d1ce9487f1cdf36 100644 (file)
@@ -15908,6 +15908,12 @@ group <group>
   "gid" setting except that the group name is used instead of its gid. This
   setting is ignored by non UNIX sockets.
 
+guid-prefix <string>
+  Generate case-sensitive global unique IDs for each listening sockets
+  allocated on this bind line. Prefix will be concatenated to listeners
+  position index on the current bind line, with character '-' as separator. See
+  "guid" proxy keyword description for more information on its format.
+
 id <id>
   Fixes the socket ID. By default, socket IDs are automatically assigned, but
   sometimes it is more convenient to fix them to ease monitoring. This value
index 22f4bf0b5d269e647cf64324d9301ee85605b73a..5b41fbd529fb3ddc2413a6a5e05ed522126f261d 100644 (file)
@@ -28,6 +28,7 @@
 #include <import/ebtree-t.h>
 
 #include <haproxy/api-t.h>
+#include <haproxy/guid-t.h>
 #include <haproxy/obj_type-t.h>
 #include <haproxy/quic_cc-t.h>
 #include <haproxy/quic_sock-t.h>
@@ -207,6 +208,8 @@ struct bind_conf {
        char *arg;                 /* argument passed to "bind" for better error reporting */
        char *file;                /* file where the section appears */
        int line;                  /* line where the section appears */
+       char *guid_prefix;         /* prefix for listeners GUID */
+       size_t guid_idx;           /* next index for listeners GUID generation */
        char *rhttp_srvname;       /* name of server when using "rhttp@" address */
        int rhttp_nbconn;          /* count of connections to initiate in parallel */
        __decl_thread(HA_RWLOCK_T sni_lock); /* lock the SNI trees during add/del operations */
@@ -252,6 +255,8 @@ struct listener {
                struct eb32_node id;    /* place in the tree of used IDs */
        } conf;                         /* config information */
 
+       struct guid_node guid;          /* GUID global tree node */
+
        struct li_per_thread *per_thr;  /* per-thread fields (one per thread in the group) */
 
        EXTRA_COUNTERS(extra_counters);
index 5b3dc189efff84a13dca5ad32d51bfc4290edcd3..3627a791e85eacfdfb34c4ed1ed740901bb66262 100644 (file)
@@ -192,6 +192,13 @@ int default_resume_listener(struct listener *l);
  */
 int bind_complete_thread_setup(struct bind_conf *bind_conf, int *err_code);
 
+/* Generate and insert unique GUID for each listeners of <bind_conf> instance
+ * if GUID prefix is defined.
+ *
+ * Returns 0 on success else non-zero.
+ */
+int bind_generate_guid(struct bind_conf *bind_conf);
+
 /*
  * Registers the bind keyword list <kwl> as a list of valid keywords for next
  * parsing sessions.
index 15fca551bc33e95bd9611db7da53e8d31ecbf742..cdddfc2ed1098926a27732906f9067b1be1daac7 100644 (file)
@@ -2920,6 +2920,12 @@ init_proxies_list_stage1:
                                if (err_code & ERR_FATAL)
                                        goto out;
                        }
+
+                       if (bind_generate_guid(bind_conf)) {
+                               cfgerr++;
+                               err_code |= ERR_FATAL | ERR_ALERT;
+                               goto out;
+                       }
                }
 
                switch (curproxy->mode) {
index af04f1a816e34abf1056a7c1616e3dbc510f5663..1f56ec9ba8ff1ae1873f899eb2d08f973828ed26 100644 (file)
@@ -1,6 +1,7 @@
 #include <haproxy/guid.h>
 
 #include <import/ebistree.h>
+#include <haproxy/listener-t.h>
 #include <haproxy/obj_type.h>
 #include <haproxy/proxy.h>
 #include <haproxy/server-t.h>
@@ -46,6 +47,10 @@ int guid_insert(enum obj_type *objt, const char *uid, char **errmsg)
                guid = &__objt_proxy(objt)->guid;
                break;
 
+       case OBJ_TYPE_LISTENER:
+               guid = &__objt_listener(objt)->guid;
+               break;
+
        case OBJ_TYPE_SERVER:
                guid = &__objt_server(objt)->guid;
                break;
@@ -115,6 +120,7 @@ char *guid_name(const struct guid_node *guid)
 {
        char *msg = NULL;
        struct proxy *px;
+       struct listener *l;
        struct server *srv;
 
        switch (obj_type(guid->obj_type)) {
@@ -122,6 +128,12 @@ char *guid_name(const struct guid_node *guid)
                px = __objt_proxy(guid->obj_type);
                return memprintf(&msg, "%s %s", proxy_cap_str(px->cap), px->id);
 
+       case OBJ_TYPE_LISTENER:
+               l = __objt_listener(guid->obj_type);
+               return memprintf(&msg, "listener %s (%s:%d)",
+                                l->bind_conf->frontend->id,
+                                l->bind_conf->file, l->bind_conf->line);
+
        case OBJ_TYPE_SERVER:
                srv = __objt_server(guid->obj_type);
                return memprintf(&msg, "server %s/%s", srv->proxy->id, srv->id);
index 6e37984a85ae02a872ad9f91d58d0f698f836e83..07113ff6ec4cb01f06b98044c60f26a4a56efe38 100644 (file)
@@ -27,6 +27,7 @@
 #include <haproxy/freq_ctr.h>
 #include <haproxy/frontend.h>
 #include <haproxy/global.h>
+#include <haproxy/guid.h>
 #include <haproxy/list.h>
 #include <haproxy/listener.h>
 #include <haproxy/log.h>
@@ -816,6 +817,8 @@ int create_listeners(struct bind_conf *bc, const struct sockaddr_storage *ss,
                if (fd != -1)
                        l->rx.flags |= RX_F_INHERITED;
 
+               guid_init(&l->guid);
+
                l->extra_counters = NULL;
 
                HA_RWLOCK_INIT(&l->lock);
@@ -1832,6 +1835,43 @@ int bind_complete_thread_setup(struct bind_conf *bind_conf, int *err_code)
        return cfgerr;
 }
 
+/* Generate and insert unique GUID for each listeners of <bind_conf> instance
+ * if GUID prefix is defined.
+ *
+ * Returns 0 on success else non-zero.
+ */
+int bind_generate_guid(struct bind_conf *bind_conf)
+{
+       struct listener *l;
+       char *guid_err = NULL;
+
+       if (!bind_conf->guid_prefix)
+               return 0;
+
+       list_for_each_entry(l, &bind_conf->listeners, by_bind) {
+               if (bind_conf->guid_idx == (size_t)-1) {
+                       ha_alert("[%s:%d] : error on GUID generation : Too many listeners.\n",
+                                bind_conf->file, bind_conf->line);
+                       return 1;
+               }
+
+               chunk_printf(&trash, "%s-%lld", bind_conf->guid_prefix,
+                            (ullong)bind_conf->guid_idx);
+
+               if (guid_insert(&l->obj_type, b_head(&trash), &guid_err)) {
+                       ha_alert("[%s:%d] : error on GUID generation : %s. "
+                                "You may fix it by adjusting guid-prefix.\n",
+                                bind_conf->file, bind_conf->line, guid_err);
+                       ha_free(&guid_err);
+                       return 1;
+               }
+
+               ++bind_conf->guid_idx;
+       }
+
+       return 0;
+}
+
 /*
  * Registers the bind keyword list <kwl> as a list of valid keywords for next
  * parsing sessions.
@@ -1975,6 +2015,9 @@ struct bind_conf *bind_conf_alloc(struct proxy *fe, const char *file,
 #endif
        LIST_INIT(&bind_conf->listeners);
 
+       bind_conf->guid_prefix = NULL;
+       bind_conf->guid_idx = 0;
+
        bind_conf->rhttp_srvname = NULL;
 
        return bind_conf;
@@ -2082,6 +2125,26 @@ static int bind_parse_backlog(char **args, int cur_arg, struct proxy *px, struct
        return 0;
 }
 
+/* parse the "guid-prefix" bind keyword */
+static int bind_parse_guid_prefix(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
+{
+       char *prefix = NULL;
+
+       if (!*args[cur_arg + 1]) {
+               memprintf(err, "'%s' : expects an argument", args[cur_arg]);
+               return ERR_ALERT | ERR_FATAL;
+       }
+
+       prefix = strdup(args[cur_arg + 1]);
+       if (!prefix) {
+               memprintf(err, "'%s' : out of memory", args[cur_arg]);
+               return ERR_ALERT | ERR_FATAL;
+       }
+
+       conf->guid_prefix = prefix;
+       return 0;
+}
+
 /* parse the "id" bind keyword */
 static int bind_parse_id(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
 {
@@ -2486,6 +2549,7 @@ static struct bind_kw_list bind_kws = { "ALL", { }, {
        { "accept-netscaler-cip", bind_parse_accept_netscaler_cip, 1, 0 }, /* enable NetScaler Client IP insertion protocol */
        { "accept-proxy", bind_parse_accept_proxy, 0, 0 }, /* enable PROXY protocol */
        { "backlog",      bind_parse_backlog,      1, 0 }, /* set backlog of listening socket */
+       { "guid-prefix",  bind_parse_guid_prefix,  1, 1 }, /* set guid of listening socket */
        { "id",           bind_parse_id,           1, 1 }, /* set id of listening socket */
        { "maxconn",      bind_parse_maxconn,      1, 0 }, /* set maxconn of listening socket */
        { "name",         bind_parse_name,         1, 1 }, /* set name of listening socket */
index 34067b04b129823a7eda111cb8f52f7ee511523d..92c5df143af4d10b33b884223ad0cfd01d396e9d 100644 (file)
@@ -316,6 +316,7 @@ void free_proxy(struct proxy *p)
        srv_free_params(&p->defsrv);
 
        list_for_each_entry_safe(l, l_next, &p->conf.listeners, by_fe) {
+               guid_remove(&l->guid);
                LIST_DELETE(&l->by_fe);
                LIST_DELETE(&l->by_bind);
                free(l->name);
@@ -335,6 +336,7 @@ void free_proxy(struct proxy *p)
                free(bind_conf->arg);
                free(bind_conf->settings.interface);
                LIST_DELETE(&bind_conf->by_fe);
+               free(bind_conf->guid_prefix);
                free(bind_conf->rhttp_srvname);
                free(bind_conf);
        }