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
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

View 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);

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);
/* 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.

View File

@ -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) {

View 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);

View 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 */

View 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);
}