MINOR: lb: make LB initialization even more declarative

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.
This commit is contained in:
Maxime Henrion 2026-04-29 13:56:34 -04:00 committed by Willy Tarreau
parent 731fc033dd
commit 87a4f6d47e
16 changed files with 82 additions and 57 deletions

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

View File

@ -30,6 +30,10 @@
#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);

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

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

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

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

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

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

View File

@ -64,6 +64,13 @@
#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)
{

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

View 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

View 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

View 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

View 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

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

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