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 <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.
This commit is contained in:
Amaury Denoyelle 2024-04-02 10:44:08 +02:00
parent 8259456981
commit 0489d85263
7 changed files with 102 additions and 0 deletions

View File

@ -15908,6 +15908,12 @@ group <group>
"gid" setting except that the group name is used instead of its gid. This "gid" setting except that the group name is used instead of its gid. This
setting is ignored by non UNIX sockets. 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> id <id>
Fixes the socket ID. By default, socket IDs are automatically assigned, but 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 sometimes it is more convenient to fix them to ease monitoring. This value

View File

@ -28,6 +28,7 @@
#include <import/ebtree-t.h> #include <import/ebtree-t.h>
#include <haproxy/api-t.h> #include <haproxy/api-t.h>
#include <haproxy/guid-t.h>
#include <haproxy/obj_type-t.h> #include <haproxy/obj_type-t.h>
#include <haproxy/quic_cc-t.h> #include <haproxy/quic_cc-t.h>
#include <haproxy/quic_sock-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 *arg; /* argument passed to "bind" for better error reporting */
char *file; /* file where the section appears */ char *file; /* file where the section appears */
int line; /* line 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 */ char *rhttp_srvname; /* name of server when using "rhttp@" address */
int rhttp_nbconn; /* count of connections to initiate in parallel */ 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 */ __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 */ struct eb32_node id; /* place in the tree of used IDs */
} conf; /* config information */ } 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) */ struct li_per_thread *per_thr; /* per-thread fields (one per thread in the group) */
EXTRA_COUNTERS(extra_counters); EXTRA_COUNTERS(extra_counters);

View 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); 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 * Registers the bind keyword list <kwl> as a list of valid keywords for next
* parsing sessions. * parsing sessions.

View File

@ -2920,6 +2920,12 @@ int check_config_validity()
if (err_code & ERR_FATAL) if (err_code & ERR_FATAL)
goto out; goto out;
} }
if (bind_generate_guid(bind_conf)) {
cfgerr++;
err_code |= ERR_FATAL | ERR_ALERT;
goto out;
}
} }
switch (curproxy->mode) { switch (curproxy->mode) {

View File

@ -1,6 +1,7 @@
#include <haproxy/guid.h> #include <haproxy/guid.h>
#include <import/ebistree.h> #include <import/ebistree.h>
#include <haproxy/listener-t.h>
#include <haproxy/obj_type.h> #include <haproxy/obj_type.h>
#include <haproxy/proxy.h> #include <haproxy/proxy.h>
#include <haproxy/server-t.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; guid = &__objt_proxy(objt)->guid;
break; break;
case OBJ_TYPE_LISTENER:
guid = &__objt_listener(objt)->guid;
break;
case OBJ_TYPE_SERVER: case OBJ_TYPE_SERVER:
guid = &__objt_server(objt)->guid; guid = &__objt_server(objt)->guid;
break; break;
@ -115,6 +120,7 @@ char *guid_name(const struct guid_node *guid)
{ {
char *msg = NULL; char *msg = NULL;
struct proxy *px; struct proxy *px;
struct listener *l;
struct server *srv; struct server *srv;
switch (obj_type(guid->obj_type)) { switch (obj_type(guid->obj_type)) {
@ -122,6 +128,12 @@ char *guid_name(const struct guid_node *guid)
px = __objt_proxy(guid->obj_type); px = __objt_proxy(guid->obj_type);
return memprintf(&msg, "%s %s", proxy_cap_str(px->cap), px->id); 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: case OBJ_TYPE_SERVER:
srv = __objt_server(guid->obj_type); srv = __objt_server(guid->obj_type);
return memprintf(&msg, "server %s/%s", srv->proxy->id, srv->id); return memprintf(&msg, "server %s/%s", srv->proxy->id, srv->id);

View File

@ -27,6 +27,7 @@
#include <haproxy/freq_ctr.h> #include <haproxy/freq_ctr.h>
#include <haproxy/frontend.h> #include <haproxy/frontend.h>
#include <haproxy/global.h> #include <haproxy/global.h>
#include <haproxy/guid.h>
#include <haproxy/list.h> #include <haproxy/list.h>
#include <haproxy/listener.h> #include <haproxy/listener.h>
#include <haproxy/log.h> #include <haproxy/log.h>
@ -816,6 +817,8 @@ int create_listeners(struct bind_conf *bc, const struct sockaddr_storage *ss,
if (fd != -1) if (fd != -1)
l->rx.flags |= RX_F_INHERITED; l->rx.flags |= RX_F_INHERITED;
guid_init(&l->guid);
l->extra_counters = NULL; l->extra_counters = NULL;
HA_RWLOCK_INIT(&l->lock); HA_RWLOCK_INIT(&l->lock);
@ -1832,6 +1835,43 @@ int bind_complete_thread_setup(struct bind_conf *bind_conf, int *err_code)
return cfgerr; 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 * Registers the bind keyword list <kwl> as a list of valid keywords for next
* parsing sessions. * parsing sessions.
@ -1975,6 +2015,9 @@ struct bind_conf *bind_conf_alloc(struct proxy *fe, const char *file,
#endif #endif
LIST_INIT(&bind_conf->listeners); LIST_INIT(&bind_conf->listeners);
bind_conf->guid_prefix = NULL;
bind_conf->guid_idx = 0;
bind_conf->rhttp_srvname = NULL; bind_conf->rhttp_srvname = NULL;
return bind_conf; return bind_conf;
@ -2082,6 +2125,26 @@ static int bind_parse_backlog(char **args, int cur_arg, struct proxy *px, struct
return 0; 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 */ /* parse the "id" bind keyword */
static int bind_parse_id(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err) 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-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 */ { "accept-proxy", bind_parse_accept_proxy, 0, 0 }, /* enable PROXY protocol */
{ "backlog", bind_parse_backlog, 1, 0 }, /* set backlog of listening socket */ { "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 */ { "id", bind_parse_id, 1, 1 }, /* set id of listening socket */
{ "maxconn", bind_parse_maxconn, 1, 0 }, /* set maxconn 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 */ { "name", bind_parse_name, 1, 1 }, /* set name of listening socket */

View File

@ -316,6 +316,7 @@ void free_proxy(struct proxy *p)
srv_free_params(&p->defsrv); srv_free_params(&p->defsrv);
list_for_each_entry_safe(l, l_next, &p->conf.listeners, by_fe) { 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_fe);
LIST_DELETE(&l->by_bind); LIST_DELETE(&l->by_bind);
free(l->name); free(l->name);
@ -335,6 +336,7 @@ void free_proxy(struct proxy *p)
free(bind_conf->arg); free(bind_conf->arg);
free(bind_conf->settings.interface); free(bind_conf->settings.interface);
LIST_DELETE(&bind_conf->by_fe); LIST_DELETE(&bind_conf->by_fe);
free(bind_conf->guid_prefix);
free(bind_conf->rhttp_srvname); free(bind_conf->rhttp_srvname);
free(bind_conf); free(bind_conf);
} }