From: Amaury Denoyelle Date: Thu, 9 Jul 2026 08:41:59 +0000 (+0200) Subject: MEDIUM: proxy: implement named default-server X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=507f790af73903cd1f5f448bc78fb60038bc7cb3;p=thirdparty%2Fhaproxy.git MEDIUM: proxy: implement named default-server Implement the support for named default-server. In a single backend, it is now possible to define different default-server instances identified by a name. Along to them, it's still possible to use the anonymous default-server. To define a named default-server, a new "name" argument can be used just after the "default-server" token. It is positional to ensure extra server settings are always set after it. This is necessary to continue to allow to define a default-server on multiple lines, concatenating the settings with the previous line. Named default-server are stored in a new dedicated compact tree in proxy struct. Name must not conflict with server instances already defined in the same backend. This is necessary for the future implementation of name addressing on both servers and default-servers without having to specify the lookup list. --- diff --git a/doc/configuration.txt b/doc/configuration.txt index 36b565d18..ac4b3de9b 100644 --- a/doc/configuration.txt +++ b/doc/configuration.txt @@ -7370,8 +7370,8 @@ declare capture [ request | response ] len "http-request capture" and "http-response capture". -default-server [from ] [param*] - Change default options for a server in a backend +default-server [name ] [from ] [param*] + Changes a set of options reusable for future server declarations. May be used in the following contexts: tcp, http @@ -7379,6 +7379,9 @@ default-server [from ] [param*] yes | no | yes | yes Arguments: + specifies a named default-instance instead of the default + anonymous one. + instructs to reinitialize first the set of options to their default values and then reusing the settings from the designated server or default-server instance. See section 5.2 about server @@ -7392,12 +7395,18 @@ default-server [from ] [param*] Example : default-server inter 1000 weight 13 - Multiple default-server lines can be specified in the same backend with each - new line completing the previous one. This set of options can be reset by - using the "from none" keyword value. + Several sets of options can be defined per backend instance. A backend always + contains an unnamed default-server which is selected when argument is + not present. A named default-server can be created by specifying the + argument with a value. This name must not collide with servers in the same + backend. + + The same default-server can be defined over multiple lines, with each line + completing the previous one. This set of options can be reset by using the + "from none" keyword value. - A default-server with no parameter set will automatically be purged after - parsing. As such, a final "default-server from none" statement will be + An unnamed default-server with no parameter set will automatically be purged + after parsing. As such, a final "default-server from none" statement will be sufficient to release this unused memory, regardless of the global setting "tune.defaults.purge" value. @@ -18212,7 +18221,7 @@ address if they are used. Before any of those settings, the extra keyword its settings. server
[:port] [from ] [settings ...] - default-server [from ] [settings ...] + default-server [name ] [from ] [settings ...] from Preinitialize the server settings by copying values from another server or diff --git a/include/haproxy/proxy-t.h b/include/haproxy/proxy-t.h index dd6b18674..be3fd3a7c 100644 --- a/include/haproxy/proxy-t.h +++ b/include/haproxy/proxy-t.h @@ -369,6 +369,7 @@ struct proxy { #endif struct list servers; /* servers present in current backend */ struct server *defsrv; /* default server configuration */ + struct ceb_root *defsrv_by_name; /* named default servers */ struct lbprm lbprm; /* load-balancing parameters */ int srv_act, srv_bck; /* # of servers eligible for LB (UP|!checked) AND (enabled+weight!=0) */ int load_server_state_from_file; /* location of the file containing server state. diff --git a/src/cfgparse.c b/src/cfgparse.c index 78d298ec9..48edfae62 100644 --- a/src/cfgparse.c +++ b/src/cfgparse.c @@ -2273,7 +2273,7 @@ int check_config_validity() struct proxy *defpx; struct list *init_proxies_list = NULL; struct stktable *t; - struct server *newsrv = NULL; + struct server *newsrv = NULL, *defsrv; struct mt_list back; int err_code = 0; /* Value forced to skip '1' due to an historical bug, see below for more details. */ @@ -2429,12 +2429,20 @@ init_proxies_list_stage1: cfgerr++; } - /* Remove default-server if tune.defaults.purge is set for it. */ + /* Remove default-server instances if tune.defaults.purge is set for it. */ if (curproxy->cap & PR_CAP_BE && (global.tune.options & GTUNE_PURGE_DEF_SRV)) { + /* remove unnamed default server */ if (curproxy->defsrv) { srv_free_params(curproxy->defsrv); srv_free(&curproxy->defsrv); } + + /* also removed named default servers */ + while ((defsrv = cebuis_item_first(&curproxy->defsrv_by_name, conf.name_node, id, struct server))) { + cebuis_item_delete(&curproxy->defsrv_by_name, conf.name_node, id, defsrv); + srv_free_params(defsrv); + srv_free(&defsrv); + } } if (curproxy->flags & PR_FL_DISABLED) { diff --git a/src/proxy.c b/src/proxy.c index ce4f7032d..f9a9f5149 100644 --- a/src/proxy.c +++ b/src/proxy.c @@ -327,6 +327,7 @@ static inline void proxy_free_common(struct proxy *px) void deinit_proxy(struct proxy *p) { struct server *s, *s_back; + struct server *defsrv; struct cap_hdr *h,*h_next; struct listener *l,*l_next; struct bind_conf *bind_conf, *bind_back; @@ -424,6 +425,12 @@ void deinit_proxy(struct proxy *p) srv_free(&p->defsrv); } + while ((defsrv = cebuis_item_first(&p->defsrv_by_name, conf.name_node, id, struct server))) { + cebuis_item_delete(&p->defsrv_by_name, conf.name_node, id, defsrv); + srv_free_params(defsrv); + srv_free(&defsrv); + } + if (p->lbprm.ops && p->lbprm.ops->proxy_deinit) p->lbprm.ops->proxy_deinit(p); @@ -4326,7 +4333,7 @@ static int post_section_px_cleanup() * executed for defaults section as this may still be useful. */ if ((curproxy->cap & PR_CAP_LISTEN) && !(curproxy->cap & PR_CAP_DEF)) { - /* Default-server is removed if it does not define specific setting. */ + /* Unnamed default-server is removed if it does not define specific setting. */ if (curproxy->defsrv && !(curproxy->defsrv->flags & SRV_F_UMODIFIED)) { srv_free_params(curproxy->defsrv); srv_free(&curproxy->defsrv); diff --git a/src/server.c b/src/server.c index bea64e74b..6a15801d4 100644 --- a/src/server.c +++ b/src/server.c @@ -3893,24 +3893,65 @@ static int _srv_parse_init(struct server **srv, char **args, int *cur_arg, HA_SPIN_INIT(&newsrv->lock); } else { - /* This is a "default-server" line. Let's make certain the - * current proxy's default server exists, otherwise it's - * time to allocate it now. - */ - newsrv = curproxy->defsrv; + char *name; + + /* Parse optional "name" default-server keyword. */ + if (*args[1] && strcmp(args[1], "name") == 0) { + if (!*args[2]) { + ha_alert("default-server name: missing value.\n"); + err_code |= ERR_ALERT | ERR_FATAL; + goto out; + } + + *cur_arg = 3; + name = strdup(args[2]); + if (!name) { + ha_alert("out of memory.\n"); + err_code |= ERR_ALERT | ERR_FATAL; + goto out; + } + + /* Retrieve default-server by its name. */ + newsrv = cebuis_item_lookup(&curproxy->defsrv_by_name, + conf.name_node, id, name, + struct server); + } + else { + /* unnamed default-server instance */ + *cur_arg = 1; + name = NULL; + newsrv = curproxy->defsrv; + } + if (!newsrv) { + /* Allocate non-existing yet default-server instance. */ + struct server *srv_other; + + if (name && (srv_other = server_find_by_name(curproxy, name))) { + ha_alert("default-server name '%s' conflicts with server defined at line %d.\n", + name, srv_other->conf.line); + err_code |= ERR_ALERT | ERR_ABORT; + goto out; + } + newsrv = srv_alloc(); if (!newsrv) { ha_alert("out of memory.\n"); err_code |= ERR_ALERT | ERR_ABORT; goto out; } - newsrv->id = NULL; + newsrv->id = name; srv_settings_init(newsrv); - curproxy->defsrv = newsrv; + + if (newsrv->id) { + cebuis_item_insert(&curproxy->defsrv_by_name, + conf.name_node, id, newsrv); + } + else { + curproxy->defsrv = newsrv; + } } *srv = newsrv; - *cur_arg = 1; } free(fqdn); @@ -3987,7 +4028,9 @@ static int _srv_parse_from(struct server *srv, char **args, int *cur_arg, *from = srv; } else if (!(parse_flags & SRV_PARSE_DYNAMIC)) { - /* Reuses the default-server in the current proxy when parsing configuration files. */ + /* Reuses the unnamed default-server in the same proxy + * for servers declared in the configuration files. + */ *from = curproxy->defsrv; } else {