]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MEDIUM: proxy: implement named default-server
authorAmaury Denoyelle <adenoyelle@haproxy.com>
Thu, 9 Jul 2026 08:41:59 +0000 (10:41 +0200)
committerAmaury Denoyelle <adenoyelle@haproxy.com>
Mon, 3 Aug 2026 14:52:09 +0000 (16:52 +0200)
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
<defsrv_by_name> 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.

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

index 36b565d18191c89a7cfefa33deb6835d749ff23f..ac4b3de9baea052f7d276d01005ccdf510f1158a 100644 (file)
@@ -7370,8 +7370,8 @@ declare capture [ request | response ] len <length>
             "http-request capture" and "http-response capture".
 
 
-default-server [from <origin>] [param*]
-  Change default options for a server in a backend
+default-server [name <name>] [from <origin>] [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 <origin>] [param*]
                                  yes   |    no    |   yes  |   yes
 
   Arguments:
+    <name>    specifies a named default-instance instead of the default
+              anonymous one.
+
     <origin>  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 <origin>] [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 <name> argument is
+  not present. A named default-server can be created by specifying the <name>
+  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 <name> <address>[:port] [from <origin>] [settings ...]
-  default-server [from <origin>] [settings ...]
+  default-server [name <name>] [from <origin>] [settings ...]
 
 from <origin>
   Preinitialize the server settings by copying values from another server or
index dd6b186747941a5a469b800336b2a93be631ceab..be3fd3a7c6c0646bf100f0f3bd81d7bf9c95b8d1 100644 (file)
@@ -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.
index 78d298ec9ca5cfb1070b5b75998735577e966a14..48edfae62467c87fc44127d102aa7b49d7859be3 100644 (file)
@@ -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) {
index ce4f7032d858cea77d7d427de520308f43909ae4..f9a9f51495af78935c94b58dd447de84415be782 100644 (file)
@@ -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);
index bea64e74b5ef56e87297a675d09306ff2993ab15..6a15801d478bdb7cc5d584d0ccbb0ebacb684e9e 100644 (file)
@@ -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 {