]> git.kaiwu.me - haproxy.git/commitdiff
MINOR: lb: make LB initialization even more declarative
authorMaxime Henrion <mhenrion@haproxy.com>
Wed, 29 Apr 2026 17:56:34 +0000 (13:56 -0400)
committerWilly Tarreau <w@1wt.eu>
Mon, 11 May 2026 06:50:40 +0000 (08:50 +0200)
This lets lb_ops specify the conditions necessary to bind to this set of
ops. The condition is expressed as a list of mask and match fields on
the algorithm flags. This is then used in proxy_finalize() to locate the
lb_ops corresponding to the current configuration, by iterating  over
the list of lb_ops structures. This list is implemented using the same
mechanisms used for configuration keywords: an INITCALL1 macro to a
registration function.

This also moves the lookup and property flags into the lb_ops structure
that were previously applied manually on a case by case basis.

16 files changed:
include/haproxy/backend-t.h
include/haproxy/backend.h
include/haproxy/lb_chash.h
include/haproxy/lb_fas.h
include/haproxy/lb_fwlc.h
include/haproxy/lb_fwrr.h
include/haproxy/lb_map.h
include/haproxy/lb_ss.h
src/backend.c
src/lb_chash.c
src/lb_fas.c
src/lb_fwlc.c
src/lb_fwrr.c
src/lb_map.c
src/lb_ss.c
src/proxy.c

index b966ff321a02da7f967a410202b6743f68291a06..53c3f8748ab2d5cc2cb7d8712430b891d29fd756 100644 (file)
@@ -156,6 +156,7 @@ struct lbprm_per_tgrp {
  * The other ones might take it themselves if needed.
  */
 struct lb_ops {
+       struct list link;
        int  (*proxy_init)(struct proxy *);              /* set up per-proxy LB state at config time; <0=fail */
        void (*update_server_eweight)(struct server *);  /* to be called after eweight change // srvlock */
        void (*set_server_status_up)(struct server *);   /* to be called after status changes to UP // srvlock */
@@ -166,6 +167,11 @@ struct lb_ops {
        void (*proxy_deinit)(struct proxy *);            /* to be called when we're destroying the proxy */
        void (*server_deinit)(struct server *);          /* to be called when we're destroying the server */
        int  (*server_init)(struct server *);            /* initialize a freshly added server (runtime); <0=fail. */
+       uint32_t algo_prop;                              /* load balancing algorithm lookup and properties */
+       struct {
+               uint32_t mask;
+               uint32_t match;
+       } map[VAR_ARRAY];
 };
 
 /* LB parameters for all algorithms */
index 263a2e2c23f5354a3c2167d5a4178b37022d7c6d..5d2cb657c47bf1bcbc4bffe86b5e9f3718df0dc5 100644 (file)
 #include <haproxy/stream-t.h>
 #include <haproxy/time.h>
 
+extern struct list lb_ops_list;
+
+void lb_ops_register(struct lb_ops *ops);
+
 struct server *get_server_sh(struct proxy *px, const char *addr, int len, const struct server *avoid);
 struct server *get_server_uh(struct proxy *px, char *uri, int uri_len, const struct server *avoid);
 struct server *get_server_ph(struct proxy *px, const char *uri, int uri_len, const struct server *avoid);
index 9ffb59c063d62e2218767227ce19525d9f90d565..fd8ad111fac6c6e0285afba1c71d55fdd5d85104 100644 (file)
@@ -31,8 +31,6 @@ struct server;
 struct server *chash_get_next_server(struct proxy *p, struct server *srvtoavoid);
 struct server *chash_get_server_hash(struct proxy *p, unsigned int hash, const struct server *avoid);
 
-extern const struct lb_ops lb_chash_ops;
-
 #endif /* _HAPROXY_LB_CHASH_H */
 
 /*
index 55ef90a676a5082aa79df29843ac7642e58ef853..003553235ff677651d60f2ccf6bc7d7e9f41d2eb 100644 (file)
@@ -30,8 +30,6 @@
 
 struct server *fas_get_next_server(struct proxy *p, struct server *srvtoavoid);
 
-extern const struct lb_ops lb_fas_ops;
-
 #endif /* _HAPROXY_LB_FAS_H */
 
 /*
index fae30ada5ddc39ee87156f533e0d9d79798e15e1..7fb4b6d67a12646c635870f232dc31fe09b450ea 100644 (file)
@@ -30,8 +30,6 @@
 
 struct server *fwlc_get_next_server(struct proxy *p, struct server *srvtoavoid);
 
-extern const struct lb_ops lb_fwlc_ops;
-
 #endif /* _HAPROXY_LB_FWLC_H */
 
 /*
index 2b3f5ad9cc0dc4df21773bb72afdcfa783912d01..f1a7f7d6535bfd969b8939d8c80de466f1f8f3aa 100644 (file)
@@ -30,8 +30,6 @@
 
 struct server *fwrr_get_next_server(struct proxy *p, struct server *srvtoavoid);
 
-extern const struct lb_ops lb_fwrr_ops;
-
 #endif /* _HAPROXY_LB_FWRR_H */
 
 /*
index c4f624600a18e2418bde412f1d16c5b4871701b2..f32a110416716a1617420b4922fbdb4abac7fcd9 100644 (file)
@@ -30,8 +30,6 @@
 struct server *map_get_server_rr(struct proxy *px, struct server *srvtoavoid);
 struct server *map_get_server_hash(struct proxy *px, unsigned int hash);
 
-extern const struct lb_ops lb_map_ops;
-
 #endif /* _HAPROXY_LB_MAP_H */
 
 /*
index 063c7fd2d852beb673e15f74401fe3de6ce8ba3f..66fd79d7f0f97aa6cafbc44c56a00e3001dc4cf4 100644 (file)
@@ -29,6 +29,4 @@
 
 struct server *ss_get_server(struct proxy *px);
 
-extern const struct lb_ops lb_ss_ops;
-
 #endif /* _HAPROXY_LB_SS_H */
index fe1f680224109c6bddc146ee30289ae7e6d7cdd0..84115cb229e7c6729c826c5dfc9ebddb68aa2279 100644 (file)
 
 #define TRACE_SOURCE &trace_strm
 
+struct list lb_ops_list = LIST_HEAD_INIT(lb_ops_list);
+
+void lb_ops_register(struct lb_ops *ops)
+{
+       LIST_APPEND(&lb_ops_list, &ops->link);
+}
+
 /* helper function to invoke the correct hash method */
 unsigned int gen_hash(const struct proxy* px, const char* key, unsigned long len)
 {
index abbdcc64534a00081e0a2a371fa50cde544c69b9..362299d254bc29f3216aeb64b4e391bf373e83a1 100644 (file)
@@ -619,7 +619,13 @@ static int chash_init_server_tree(struct proxy *p)
        return 0;
 }
 
-const struct lb_ops lb_chash_ops = {
+static struct lb_ops lb_chash_ops = {ILH,
+       .map = {
+               { .mask = BE_LB_KIND | BE_LB_PARM,      .match = BE_LB_KIND_RR | BE_LB_RR_RANDOM },
+               { .mask = BE_LB_KIND | BE_LB_HASH_TYPE, .match = BE_LB_KIND_HI | BE_LB_HASH_CONS },
+               { 0, 0 }
+       },
+       .algo_prop              = BE_LB_LKUP_CHTREE | BE_LB_PROP_DYN,
        .proxy_init             = chash_init_server_tree,
        .set_server_status_up   = chash_set_server_status_up,
        .set_server_status_down = chash_set_server_status_down,
@@ -627,3 +633,5 @@ const struct lb_ops lb_chash_ops = {
        .server_init            = chash_server_init,
        .server_deinit          = chash_server_deinit,
 };
+
+INITCALL1(STG_REGISTER, lb_ops_register, &lb_chash_ops);
index 9cf000cc671bed55403cb77d64f44142c22ae7a8..f789d19db64e50a32d9d2b5f7d7d70970439d6b1 100644 (file)
@@ -334,7 +334,12 @@ struct server *fas_get_next_server(struct proxy *p, struct server *srvtoavoid)
        return srv;
 }
 
-const struct lb_ops lb_fas_ops = {
+static struct lb_ops lb_fas_ops = {ILH,
+       .map = {
+               { .mask = BE_LB_KIND | BE_LB_PARM, .match = BE_LB_KIND_CB | BE_LB_CB_FAS },
+               { 0, 0 }
+       },
+       .algo_prop              = BE_LB_LKUP_FSTREE | BE_LB_PROP_DYN,
        .proxy_init             = fas_init_server_tree,
        .set_server_status_up   = fas_set_server_status_up,
        .set_server_status_down = fas_set_server_status_down,
@@ -343,6 +348,8 @@ const struct lb_ops lb_fas_ops = {
        .server_drop_conn       = fas_srv_reposition,
 };
 
+INITCALL1(STG_REGISTER, lb_ops_register, &lb_fas_ops);
+
 /*
  * Local variables:
  *  c-indent-level: 8
index 394ce9ef861193882058448867ac3e4cb6a95b11..6657d4c1e70cb6733ad7aadad19cad79e5913f22 100644 (file)
@@ -878,7 +878,12 @@ redo:
        return srv;
 }
 
-const struct lb_ops lb_fwlc_ops = {
+static struct lb_ops lb_fwlc_ops = {ILH,
+       .map = {
+               { .mask = BE_LB_KIND | BE_LB_PARM, .match = BE_LB_KIND_CB | BE_LB_CB_LC },
+               { 0, 0 }
+       },
+       .algo_prop              = BE_LB_LKUP_LCTREE | BE_LB_PROP_DYN,
        .proxy_init             = fwlc_init_server_tree,
        .set_server_status_up   = fwlc_set_server_status_up,
        .set_server_status_down = fwlc_set_server_status_down,
@@ -890,6 +895,8 @@ const struct lb_ops lb_fwlc_ops = {
        .proxy_deinit           = fwlc_proxy_deinit,
 };
 
+INITCALL1(STG_REGISTER, lb_ops_register, &lb_fwlc_ops);
+
 /*
  * Local variables:
  *  c-indent-level: 8
index 0b6113baf81b6cddf2265eaf3057f8321076a0f6..8d2386529b64fb473de4364039a2a780641de1b0 100644 (file)
@@ -668,13 +668,20 @@ struct server *fwrr_get_next_server(struct proxy *p, struct server *srvtoavoid)
        return srv;
 }
 
-const struct lb_ops lb_fwrr_ops = {
+static struct lb_ops lb_fwrr_ops = {ILH,
+       .map = {
+               { .mask = BE_LB_KIND | BE_LB_PARM, .match = BE_LB_KIND_RR | BE_LB_RR_DYN },
+               { 0, 0 }
+       },
+       .algo_prop              = BE_LB_LKUP_RRTREE | BE_LB_PROP_DYN,
        .proxy_init             = fwrr_init_server_groups,
        .set_server_status_up   = fwrr_set_server_status_up,
        .set_server_status_down = fwrr_set_server_status_down,
        .update_server_eweight  = fwrr_update_server_weight,
 };
 
+INITCALL1(STG_REGISTER, lb_ops_register, &lb_fwrr_ops);
+
 /*
  * Local variables:
  *  c-indent-level: 8
index bb6ffb8f7efd6e3f1c6ff81f2e937e3770d139ef..91d09caf5745e5741cb4911b1c14f8d3a89ebb53 100644 (file)
@@ -269,12 +269,20 @@ struct server *map_get_server_hash(struct proxy *px, unsigned int hash)
        return srv;
 }
 
-const struct lb_ops lb_map_ops = {
+static struct lb_ops lb_map_ops = {ILH,
+       .map = {
+               { .mask = BE_LB_KIND | BE_LB_PARM,      .match = BE_LB_KIND_RR | BE_LB_RR_STATIC },
+               { .mask = BE_LB_KIND | BE_LB_HASH_TYPE, .match = BE_LB_KIND_HI | BE_LB_HASH_MAP },
+               { 0, 0 }
+       },
+       .algo_prop              = BE_LB_LKUP_MAP,
        .proxy_init             = init_server_map,
        .set_server_status_up   = map_set_server_status_up,
        .set_server_status_down = map_set_server_status_down,
 };
 
+INITCALL1(STG_REGISTER, lb_ops_register, &lb_map_ops);
+
 /*
  * Local variables:
  *  c-indent-level: 8
index add9f19dd5d39a585b0a77a2a6e220ae062ca0e7..d9c18ee03e7a992d0a1acbf313a86dced0a23d4d 100644 (file)
@@ -21,6 +21,7 @@
 #include <haproxy/api.h>
 #include <haproxy/backend.h>
 #include <haproxy/lb_ss.h>
+#include <haproxy/list.h>
 #include <haproxy/server-t.h>
 
 /* This function elects a new stick server for proxy px.
@@ -179,8 +180,15 @@ struct server *ss_get_server(struct proxy *px)
        return srv;
 }
 
-const struct lb_ops lb_ss_ops = {
+static struct lb_ops lb_ss_ops = {ILH,
+       .map = {
+               { .mask = BE_LB_KIND | BE_LB_PARM, .match = BE_LB_KIND_SA | BE_LB_SA_SS },
+               { 0, 0 }
+       },
+       .algo_prop              = BE_LB_PROP_DYN,
        .proxy_init             = init_server_ss,
        .set_server_status_up   = ss_set_server_status_up,
        .set_server_status_down = ss_set_server_status_down,
 };
+
+INITCALL1(STG_REGISTER, lb_ops_register, &lb_ss_ops);
index 5656a51d5fffa4d04f72d7a352118d7f2836c360..3ac67464f5366bf28fd9a75634dc10aa5a795d5e 100644 (file)
@@ -1648,6 +1648,7 @@ int proxy_finalize(struct proxy *px, int *err_code)
        struct server_rule *srule;
        struct sticking_rule *mrule;
        struct logger *tmplogger;
+       struct lb_ops *ops;
        unsigned int next_id;
        int cfgerr = 0;
        char *err = NULL;
@@ -2611,49 +2612,23 @@ int proxy_finalize(struct proxy *px, int *err_code)
         */
 
        px->lbprm.algo &= ~(BE_LB_LKUP | BE_LB_PROP_DYN);
-       switch (px->lbprm.algo & BE_LB_KIND) {
-       case BE_LB_KIND_RR:
-               if ((px->lbprm.algo & BE_LB_PARM) == BE_LB_RR_STATIC) {
-                       px->lbprm.algo |= BE_LB_LKUP_MAP;
-                       px->lbprm.ops = &lb_map_ops;
-               } else if ((px->lbprm.algo & BE_LB_PARM) == BE_LB_RR_RANDOM) {
-                       px->lbprm.algo |= BE_LB_LKUP_CHTREE | BE_LB_PROP_DYN;
-                       px->lbprm.ops = &lb_chash_ops;
-               } else {
-                       px->lbprm.algo |= BE_LB_LKUP_RRTREE | BE_LB_PROP_DYN;
-                       px->lbprm.ops = &lb_fwrr_ops;
-               }
-               break;
-
-       case BE_LB_KIND_CB:
-               if ((px->lbprm.algo & BE_LB_PARM) == BE_LB_CB_LC) {
-                       px->lbprm.algo |= BE_LB_LKUP_LCTREE | BE_LB_PROP_DYN;
-                       px->lbprm.ops = &lb_fwlc_ops;
-               } else {
-                       px->lbprm.algo |= BE_LB_LKUP_FSTREE | BE_LB_PROP_DYN;
-                       px->lbprm.ops = &lb_fas_ops;
+       list_for_each_entry(ops, &lb_ops_list, link) {
+               int i;
+               for (i = 0; ops->map[i].match != 0; i++) {
+                       if ((px->lbprm.algo & ops->map[i].mask) == ops->map[i].match) {
+                               px->lbprm.ops = ops;
+                               break;
+                       }
                }
-               break;
 
-       case BE_LB_KIND_HI:
-               if ((px->lbprm.algo & BE_LB_HASH_TYPE) == BE_LB_HASH_CONS) {
-                       px->lbprm.algo |= BE_LB_LKUP_CHTREE | BE_LB_PROP_DYN;
-                       px->lbprm.ops = &lb_chash_ops;
-               } else {
-                       px->lbprm.algo |= BE_LB_LKUP_MAP;
-                       px->lbprm.ops = &lb_map_ops;
-               }
-               break;
-       case BE_LB_KIND_SA:
-               if ((px->lbprm.algo & BE_LB_PARM) == BE_LB_SA_SS) {
-                       px->lbprm.algo |= BE_LB_PROP_DYN;
-                       px->lbprm.ops = &lb_ss_ops;
+               if (px->lbprm.ops) {
+                       px->lbprm.algo |= px->lbprm.ops->algo_prop;
+                       if (px->lbprm.ops->proxy_init && px->lbprm.ops->proxy_init(px) < 0)
+                               cfgerr++;
+                       break;
                }
-               break;
        }
-       if (px->lbprm.ops && px->lbprm.ops->proxy_init &&
-           px->lbprm.ops->proxy_init(px) < 0)
-               cfgerr++;
+
        HA_RWLOCK_INIT(&px->lbprm.lock);
 
        if (px->options & PR_O_LOGASAP)