From 0489d85263853709b1c08a1f2a5da18bcbdbb474 Mon Sep 17 00:00:00 2001 From: Amaury Denoyelle Date: Tue, 2 Apr 2024 10:44:08 +0200 Subject: [PATCH] MINOR: listener: implement GUID support 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 . 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 | 6 ++++ include/haproxy/listener-t.h | 5 +++ include/haproxy/listener.h | 7 ++++ src/cfgparse.c | 6 ++++ src/guid.c | 12 +++++++ src/listener.c | 64 ++++++++++++++++++++++++++++++++++++ src/proxy.c | 2 ++ 7 files changed, 102 insertions(+) diff --git a/doc/configuration.txt b/doc/configuration.txt index c42f9ea59..085bbe173 100644 --- a/doc/configuration.txt +++ b/doc/configuration.txt @@ -15908,6 +15908,12 @@ group "gid" setting except that the group name is used instead of its gid. This setting is ignored by non UNIX sockets. +guid-prefix + 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 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 diff --git a/include/haproxy/listener-t.h b/include/haproxy/listener-t.h index 22f4bf0b5..5b41fbd52 100644 --- a/include/haproxy/listener-t.h +++ b/include/haproxy/listener-t.h @@ -28,6 +28,7 @@ #include #include +#include #include #include #include @@ -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); diff --git a/include/haproxy/listener.h b/include/haproxy/listener.h index 5b3dc189e..3627a791e 100644 --- a/include/haproxy/listener.h +++ b/include/haproxy/listener.h @@ -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 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 as a list of valid keywords for next * parsing sessions. diff --git a/src/cfgparse.c b/src/cfgparse.c index 15fca551b..cdddfc2ed 100644 --- a/src/cfgparse.c +++ b/src/cfgparse.c @@ -2920,6 +2920,12 @@ int check_config_validity() 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) { diff --git a/src/guid.c b/src/guid.c index af04f1a81..1f56ec9ba 100644 --- a/src/guid.c +++ b/src/guid.c @@ -1,6 +1,7 @@ #include #include +#include #include #include #include @@ -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); diff --git a/src/listener.c b/src/listener.c index 6e37984a8..07113ff6e 100644 --- a/src/listener.c +++ b/src/listener.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -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 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 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 */ diff --git a/src/proxy.c b/src/proxy.c index 34067b04b..92c5df143 100644 --- a/src/proxy.c +++ b/src/proxy.c @@ -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); }