From: Amaury Denoyelle Date: Wed, 22 Jul 2026 13:01:59 +0000 (+0200) Subject: MAJOR: proxy: convert server list to a doubly linked struct list X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=81fc22033596b615c30b752a68a0bf22a7c52bd8;p=thirdparty%2Fhaproxy.git MAJOR: proxy: convert server list to a doubly linked struct list Servers are stored in a list in their parent proxy. Prior to this patch, this list was singly linked. This patch converts the proxy server list to a doubly linked struct list. Server pointer is replaced by a struct list attach point. The main benefit from this patch is that it removes the bottleneck performance for add and delete server operations at runtime. As with main proxies list conversion, this is labelled as major as it is an API change. Most of the changes are straightforward : for/while statements are replaced by list_for_each_entry() macros. LIST_ISEMPTY() is now used to detect if a proxy does not contain any server. Server insertion at the front position during config parsing is kept at the moment, with reordering on post parsing. With the current patch, this is not strictly necessary so this will be removed in a next change. --- diff --git a/addons/promex/service-prometheus.c b/addons/promex/service-prometheus.c index e28dc7d55..d655c4345 100644 --- a/addons/promex/service-prometheus.c +++ b/addons/promex/service-prometheus.c @@ -966,13 +966,11 @@ static int promex_dump_back_metrics(struct appctx *appctx, struct htx *htx) switch (ctx->field_num) { case ST_I_PX_AGG_SRV_CHECK_STATUS: // DEPRECATED case ST_I_PX_AGG_SRV_STATUS: - if (!px->srv) + if (LIST_ISEMPTY(&px->servers)) goto next_px; - sv = px->srv; - while (sv) { + list_for_each_entry(sv, &px->servers, el_px) { srv_state = promex_srv_status(sv); srv_state_count[srv_state] += 1; - sv = sv->next; } for (; ctx->obj_state < PROMEX_SRV_STATE_COUNT; ctx->obj_state++) { val = mkf_u32(FN_GAUGE, srv_state_count[ctx->obj_state]); @@ -986,15 +984,13 @@ static int promex_dump_back_metrics(struct appctx *appctx, struct htx *htx) ctx->obj_state = 0; goto next_px; case ST_I_PX_AGG_CHECK_STATUS: - if (!px->srv) + if (LIST_ISEMPTY(&px->servers)) goto next_px; - sv = px->srv; - while (sv) { + list_for_each_entry(sv, &px->servers, el_px) { if ((sv->check.state & (CHK_ST_ENABLED|CHK_ST_PAUSED)) == CHK_ST_ENABLED) { srv_check_status = sv->check.status; srv_check_count[srv_check_status] += 1; } - sv = sv->next; } for (; ctx->obj_state < HCHK_STATUS_SIZE; ctx->obj_state++) { if (get_check_status_result(ctx->obj_state) < CHK_RES_FAILED) @@ -1011,7 +1007,7 @@ static int promex_dump_back_metrics(struct appctx *appctx, struct htx *htx) ctx->obj_state = 0; goto next_px; case ST_I_PX_STATUS: - bkd_state = ((px->lbprm.tot_weight > 0 || !px->srv) ? 1 : 0); + bkd_state = ((px->lbprm.tot_weight > 0 || LIST_ISEMPTY(&px->servers)) ? 1 : 0); for (; ctx->obj_state < PROMEX_BACK_STATE_COUNT; ctx->obj_state++) { labels[lb_idx].name = ist("state"); labels[lb_idx].value = promex_back_st[ctx->obj_state]; diff --git a/include/haproxy/proxy-t.h b/include/haproxy/proxy-t.h index 3d30cc28d..dd6b18674 100644 --- a/include/haproxy/proxy-t.h +++ b/include/haproxy/proxy-t.h @@ -367,7 +367,8 @@ struct proxy { #ifdef USE_QUIC struct list quic_init_rules; /* quic-initial rules */ #endif - struct server *srv, *defsrv; /* known servers; default server configuration */ + struct list servers; /* servers present in current backend */ + struct server *defsrv; /* default server configuration */ 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/include/haproxy/proxy.h b/include/haproxy/proxy.h index 8470d61cc..0c0bc730d 100644 --- a/include/haproxy/proxy.h +++ b/include/haproxy/proxy.h @@ -348,12 +348,15 @@ static inline struct proxy *main_proxies_next(const struct proxy *px) static inline struct server *proxy_first_server(const struct proxy *px) { - return px->srv; + return !LIST_ISEMPTY(&px->servers) ? + LIST_NEXT(&px->servers, struct server *, el_px) : NULL; } static inline struct server *proxy_next_server(const struct server *srv) { - return srv->next; + if (srv->el_px.n == &srv->proxy->servers) + return NULL; + return LIST_ELEM(srv->el_px.n, struct server *, el_px); } #endif /* _HAPROXY_PROXY_H */ diff --git a/include/haproxy/server-t.h b/include/haproxy/server-t.h index 75e1cf603..a7dfd6de0 100644 --- a/include/haproxy/server-t.h +++ b/include/haproxy/server-t.h @@ -350,8 +350,8 @@ struct server { signed char use_ssl; /* ssl enabled (1: on, 0: disabled, -1 forced off) */ unsigned int flags; /* server flags (SRV_F_*) */ unsigned int pp_opts; /* proxy protocol options (SRV_PP_*) */ - struct mt_list global_list; /* attach point in the global servers_list */ - struct server *next; + struct mt_list global_list; /* attach point in the global servers */ + struct list el_px; /* attach point in parent proxy */ int cklen; /* the len of the cookie, to speed up checks */ int rdr_len; /* the length of the redirection prefix */ char *cookie; /* the id set in the cookie */ diff --git a/include/haproxy/server.h b/include/haproxy/server.h index 6d47cb343..17764aff9 100644 --- a/include/haproxy/server.h +++ b/include/haproxy/server.h @@ -395,18 +395,8 @@ static inline int srv_is_transparent(const struct server *srv) static inline void srv_detach(struct server *srv) { struct proxy *px = srv->proxy; - struct server *prev; - - if (px->srv == srv) { - px->srv = srv->next; - } - else { - for (prev = px->srv; prev && prev->next != srv; prev = prev->next) - ; - BUG_ON(!prev); /* Server instance not found in proxy list ? */ - prev->next = srv->next; - } + LIST_DEL_INIT(&srv->el_px); /* Reset the proxy's ready_srv if it was this one. */ HA_ATOMIC_CAS(&px->ready_srv, &srv, NULL); } diff --git a/src/backend.c b/src/backend.c index 388e4ad03..ab1a8d963 100644 --- a/src/backend.c +++ b/src/backend.c @@ -127,7 +127,7 @@ void recount_servers(struct proxy *px) px->srv_act = px->srv_bck = 0; px->lbprm.tot_wact = px->lbprm.tot_wbck = 0; px->lbprm.fbck = NULL; - for (srv = px->srv; srv != NULL; srv = srv->next) { + list_for_each_entry(srv, &px->servers, el_px) { if (!srv_willbe_usable(srv)) continue; @@ -3011,7 +3011,7 @@ int tcp_persist_rdp_cookie(struct stream *s, struct channel *req, int an_bit) struct proxy *px = s->be; int ret; struct sample smp; - struct server *srv = px->srv; + struct server *srv; uint16_t port; uint32_t addr; char *p; @@ -3042,7 +3042,7 @@ int tcp_persist_rdp_cookie(struct stream *s, struct channel *req, int an_bit) goto no_cookie; stream_set_target(s, NULL); - while (srv) { + list_for_each_entry(srv, &px->servers, el_px) { if (srv->addr.ss_family == AF_INET && port == srv->svc_port && addr == ((struct sockaddr_in *)&srv->addr)->sin_addr.s_addr) { @@ -3053,7 +3053,6 @@ int tcp_persist_rdp_cookie(struct stream *s, struct channel *req, int an_bit) break; } } - srv = srv->next; } no_cookie: @@ -3408,7 +3407,7 @@ smp_fetch_connslots(const struct arg *args, struct sample *smp, const char *kw, smp->data.type = SMP_T_SINT; smp->data.u.sint = 0; - for (iterator = px->srv; iterator; iterator = iterator->next) { + list_for_each_entry(iterator, &px->servers, el_px) { if (iterator->cur_state == SRV_ST_STOPPED) continue; @@ -3572,7 +3571,7 @@ smp_fetch_be_conn_free(const struct arg *args, struct sample *smp, const char *k smp->data.type = SMP_T_SINT; smp->data.u.sint = 0; - for (iterator = px->srv; iterator; iterator = iterator->next) { + list_for_each_entry(iterator, &px->servers, el_px) { if (iterator->cur_state == SRV_ST_STOPPED) continue; diff --git a/src/cfgdiag.c b/src/cfgdiag.c index 592120b3b..4774dbf42 100644 --- a/src/cfgdiag.c +++ b/src/cfgdiag.c @@ -91,7 +91,7 @@ static void run_servers_diag(int *ret) struct server *srv; list_for_each_entry(px, &main_proxies, el) { - for (srv = px->srv; srv; srv = srv->next) { + list_for_each_entry(srv, &px->servers, el_px) { srv_diag_cookies(ret, srv, &cookies_tree); srv_diag_check_reuse(ret, srv, px); } diff --git a/src/check.c b/src/check.c index 3a5442094..78bde2e89 100644 --- a/src/check.c +++ b/src/check.c @@ -1698,7 +1698,7 @@ static int start_checks() * too short an interval for all others. */ list_for_each_entry(px, &main_proxies, el) { - for (s = px->srv; s; s = s->next) { + list_for_each_entry(s, &px->servers, el_px) { if ((px->options2 & PR_O2_USE_SBUF_CHECK) && (s->check.tcpcheck->rs && s->check.tcpcheck->rs->flags & TCPCHK_RULES_MAY_USE_SBUF)) s->check.state |= CHK_ST_USE_SMALL_BUFF; @@ -1737,7 +1737,7 @@ static int start_checks() } } - for (s = px->srv; s; s = s->next) { + list_for_each_entry(s, &px->servers, el_px) { /* A task for the main check */ if (s->check.state & CHK_ST_CONFIGURED) { if (s->check.type == PR_O2_EXT_CHK) { diff --git a/src/fcgi-app.c b/src/fcgi-app.c index 49f87a70f..efcfd98d8 100644 --- a/src/fcgi-app.c +++ b/src/fcgi-app.c @@ -643,7 +643,7 @@ static int cfg_fcgi_apps_postparser() if (fcgi_conf && !(px->options2 & PR_O2_RSTRICT_REQ_HDR_NAMES_MASK)) px->options2 |= PR_O2_RSTRICT_REQ_HDR_NAMES_DEL; - for (srv = px->srv; srv; srv = srv->next) { + list_for_each_entry(srv, &px->servers, el_px) { if (srv->mux_proto && isteq(srv->mux_proto->mux_proto, ist("fcgi"))) { nb_fcgi_srv++; if (fcgi_conf) diff --git a/src/flt_spoe.c b/src/flt_spoe.c index 48bce2507..706c5c8f8 100644 --- a/src/flt_spoe.c +++ b/src/flt_spoe.c @@ -1237,7 +1237,7 @@ static int spoe_init(struct proxy *px, struct flt_conf *fconf) conf->agent->fe.options2 |= PR_O2_INDEPSTR; conf->agent->fe.conn_retries = CONN_RETRIES; conf->agent->fe.accept = frontend_accept; - conf->agent->fe.srv = NULL; + LIST_INIT(&conf->agent->fe.servers); conf->agent->fe.timeout.client = TICK_ETERNITY; conf->agent->fe.fe_req_ana = AN_REQ_SWITCHING_RULES; @@ -2870,7 +2870,7 @@ static int spoe_postcheck_spop_proxy(struct proxy *px) if (!(px->cap & PR_CAP_BE) || px->mode != PR_MODE_SPOP) goto out; - for (srv = px->srv; srv; srv = srv->next) { + list_for_each_entry(srv, &px->servers, el_px) { if (srv->pool_conn_name) { ha_free(&srv->pool_conn_name); release_sample_expr(srv->pool_conn_name_expr); diff --git a/src/haproxy.c b/src/haproxy.c index 5838271a4..b242be44b 100644 --- a/src/haproxy.c +++ b/src/haproxy.c @@ -908,10 +908,10 @@ static void sig_dump_state(struct sig_handler *sh) ha_warning("SIGHUP received, dumping servers states.\n"); list_for_each_entry(p, &main_proxies, el) { - struct server *s = p->srv; + struct server *s; send_log(p, LOG_NOTICE, "SIGHUP received, dumping servers states for proxy %s.\n", p->id); - while (s) { + list_for_each_entry(s, &p->servers, el_px) { chunk_printf(&trash, "SIGHUP: Server %s/%s is %s. Conn: %d act, %d pend, %llu tot.", p->id, s->id, @@ -919,11 +919,10 @@ static void sig_dump_state(struct sig_handler *sh) s->cur_sess, s->queueslength, (ullong)COUNTERS_SHARED_TOTAL(s->counters.shared.tg, cum_sess, HA_ATOMIC_LOAD)); ha_warning("%s\n", trash.area); send_log(p, LOG_NOTICE, "%s\n", trash.area); - s = s->next; } /* FIXME: those info are a bit outdated. We should be able to distinguish between FE and BE. */ - if (!p->srv) { + if (LIST_ISEMPTY(&p->servers)) { chunk_printf(&trash, "SIGHUP: Proxy %s has no servers. Conn: act(FE+BE): %d+%d, %d pend (%d unass), tot(FE+BE): %llu+%llu.", p->id, @@ -2267,7 +2266,7 @@ static void step_init_2(int argc, char** argv) continue; list_for_each_entry(pscf, &post_server_check_list, list) { - for (srv = px->srv; srv; srv = srv->next) { + list_for_each_entry(srv, &px->servers, el_px) { err_code |= pscf->fct(srv); if (err_code & (ERR_ABORT|ERR_FATAL)) { ha_alert("Fatal errors found in configuration.\n"); diff --git a/src/http_client.c b/src/http_client.c index a34ad2bd2..5e0b1ce97 100644 --- a/src/http_client.c +++ b/src/http_client.c @@ -505,7 +505,7 @@ int httpclient_set_proxy(struct httpclient *hc, struct proxy *px) hc->px = px; - for (srv = px->srv; srv != NULL; srv = srv->next) { + list_for_each_entry(srv, &px->servers, el_px) { if (srv->xprt == xprt_get(XPRT_RAW)) { hc->srv_raw = srv; #ifdef USE_OPENSSL @@ -1277,7 +1277,7 @@ static int httpclient_postcheck_proxy(struct proxy *curproxy) #ifdef USE_OPENSSL /* initialize the SNI for the SSL servers */ - for (srv = curproxy->srv; srv != NULL; srv = srv->next) { + list_for_each_entry(srv, &curproxy->servers, el_px) { if (srv->xprt == xprt_get(XPRT_SSL)) { srv_ssl = srv; } diff --git a/src/lb_chash.c b/src/lb_chash.c index d19f06de4..a92ba7cef 100644 --- a/src/lb_chash.c +++ b/src/lb_chash.c @@ -606,7 +606,7 @@ static int chash_init_server_tree(struct proxy *p) struct eb_root init_head = EB_ROOT; p->lbprm.wdiv = BE_WEIGHT_SCALE; - for (srv = p->srv; srv; srv = srv->next) { + list_for_each_entry(srv, &p->servers, el_px) { srv->next_eweight = (srv->uweight * p->lbprm.wdiv + p->lbprm.wmult - 1) / p->lbprm.wmult; srv_lb_commit_status(srv); } @@ -619,7 +619,7 @@ static int chash_init_server_tree(struct proxy *p) p->lbprm.chash.last = NULL; /* queue active and backup servers in two distinct groups */ - for (srv = p->srv; srv; srv = srv->next) { + list_for_each_entry(srv, &p->servers, el_px) { srv->lb_tree = (srv->flags & SRV_F_BACKUP) ? &p->lbprm.chash.bck : &p->lbprm.chash.act; srv->lb_nodes_tot = srv->uweight * BE_WEIGHT_SCALE; srv->lb_nodes_now = 0; diff --git a/src/lb_fas.c b/src/lb_fas.c index 3f601d8a5..845d31771 100644 --- a/src/lb_fas.c +++ b/src/lb_fas.c @@ -262,7 +262,7 @@ static int fas_init_server_tree(struct proxy *p) struct eb_root init_head = EB_ROOT; p->lbprm.wdiv = BE_WEIGHT_SCALE; - for (srv = p->srv; srv; srv = srv->next) { + list_for_each_entry(srv, &p->servers, el_px) { srv->next_eweight = (srv->uweight * p->lbprm.wdiv + p->lbprm.wmult - 1) / p->lbprm.wmult; srv_lb_commit_status(srv); } @@ -274,7 +274,7 @@ static int fas_init_server_tree(struct proxy *p) p->lbprm.fas.bck = init_head; /* queue active and backup servers in two distinct groups */ - for (srv = p->srv; srv; srv = srv->next) { + list_for_each_entry(srv, &p->servers, el_px) { if (!srv_currently_usable(srv)) continue; srv->lb_tree = (srv->flags & SRV_F_BACKUP) ? &p->lbprm.fas.bck : &p->lbprm.fas.act; diff --git a/src/lb_fwlc.c b/src/lb_fwlc.c index c635d5edc..8fd1e7383 100644 --- a/src/lb_fwlc.c +++ b/src/lb_fwlc.c @@ -716,7 +716,7 @@ static int fwlc_init_server_tree(struct proxy *p) struct eb_root init_head = EB_ROOT; p->lbprm.wdiv = BE_WEIGHT_SCALE; - for (srv = p->srv; srv; srv = srv->next) { + list_for_each_entry(srv, &p->servers, el_px) { srv->next_eweight = (srv->uweight * p->lbprm.wdiv + p->lbprm.wmult - 1) / p->lbprm.wmult; srv_lb_commit_status(srv); } @@ -730,7 +730,7 @@ static int fwlc_init_server_tree(struct proxy *p) p->lbprm.fwlc.bck = init_head; /* queue active and backup servers in two distinct groups */ - for (srv = p->srv; srv; srv = srv->next) { + list_for_each_entry(srv, &p->servers, el_px) { if (!srv_currently_usable(srv)) continue; srv->lb_tree = (srv->flags & SRV_F_BACKUP) ? &p->lbprm.fwlc.bck : &p->lbprm.fwlc.act; diff --git a/src/lb_fwrr.c b/src/lb_fwrr.c index 28fca679d..92d786fb3 100644 --- a/src/lb_fwrr.c +++ b/src/lb_fwrr.c @@ -301,7 +301,7 @@ static int fwrr_init_server_groups(struct proxy *p) int i, j; p->lbprm.wdiv = BE_WEIGHT_SCALE; - for (srv = p->srv; srv; srv = srv->next) { + list_for_each_entry(srv, &p->servers, el_px) { srv->next_eweight = (srv->uweight * p->lbprm.wdiv + p->lbprm.wmult - 1) / p->lbprm.wmult; srv_lb_commit_status(srv); } @@ -332,7 +332,7 @@ static int fwrr_init_server_groups(struct proxy *p) /* queue active and backup servers in two distinct groups */ j = 0; - for (srv = p->srv; srv; srv = srv->next) { + list_for_each_entry(srv, &p->servers, el_px) { j++; if (!srv_currently_usable(srv)) continue; diff --git a/src/lb_map.c b/src/lb_map.c index e71400349..3252d4469 100644 --- a/src/lb_map.c +++ b/src/lb_map.c @@ -50,13 +50,13 @@ static void recalc_server_map(struct proxy *px) * the first declared. This is an important assumption for the backup * case, where we want the first server only. */ - for (cur = px->srv; cur; cur = cur->next) + list_for_each_entry(cur, &px->servers, el_px) cur->wscore = 0; for (o = 0; o < tot; o++) { int max = 0; best = NULL; - for (cur = px->srv; cur; cur = cur->next) { + list_for_each_entry(cur, &px->servers, el_px) { if ((cur->flags & SRV_F_BACKUP) == flag && srv_willbe_usable(cur)) { int v; @@ -144,7 +144,7 @@ static int init_server_map(struct proxy *p) int pgcd; int act, bck; - if (!p->srv) + if (LIST_ISEMPTY(&p->servers)) return 0; /* We will factor the weights to reduce the table, @@ -176,7 +176,7 @@ static int init_server_map(struct proxy *p) p->lbprm.wmult = pgcd; act = bck = 0; - for (srv = p->srv; srv; srv = srv->next) { + list_for_each_entry(srv, &p->servers, el_px) { srv->next_eweight = (srv->uweight * p->lbprm.wdiv + p->lbprm.wmult - 1) / p->lbprm.wmult; if (srv->flags & SRV_F_BACKUP) diff --git a/src/lb_ss.c b/src/lb_ss.c index d9c18ee03..fd62a2a0b 100644 --- a/src/lb_ss.c +++ b/src/lb_ss.c @@ -44,7 +44,7 @@ static void recalc_server_ss(struct proxy *px) first = NULL; - for (cur = px->srv; cur; cur = cur->next) { + list_for_each_entry(cur, &px->servers, el_px) { if ((cur->flags & SRV_F_BACKUP) == flag && srv_willbe_usable(cur)) { first = cur; @@ -148,10 +148,10 @@ static int init_server_ss(struct proxy *p) { struct server *srv; - if (!p->srv) + if (LIST_ISEMPTY(&p->servers)) return 0; - for (srv = p->srv; srv; srv = srv->next) { + list_for_each_entry(srv, &p->servers, el_px) { srv->next_eweight = 1; /* ignore weights, all servers have the same weight */ srv_lb_commit_status(srv); } diff --git a/src/log.c b/src/log.c index bd3a03aa9..8b0606115 100644 --- a/src/log.c +++ b/src/log.c @@ -1447,8 +1447,7 @@ static int postcheck_log_backend(struct proxy *be) } /* finish the initialization of proxy's servers */ - srv = be->srv; - while (srv) { + list_for_each_entry(srv, &be->servers, el_px) { BUG_ON(srv->log_target); BUG_ON(srv->addr_type.proto_type != PROTO_TYPE_DGRAM && srv->addr_type.proto_type != PROTO_TYPE_STREAM); @@ -1497,7 +1496,6 @@ static int postcheck_log_backend(struct proxy *be) goto end; } srv->log_target->flags |= LOG_TARGET_FL_RESOLVED; - srv = srv->next; } end: if (err_code & ERR_CODE) { diff --git a/src/proxy.c b/src/proxy.c index 4789a86f6..8b72f9d45 100644 --- a/src/proxy.c +++ b/src/proxy.c @@ -326,7 +326,7 @@ static inline void proxy_free_common(struct proxy *px) */ void deinit_proxy(struct proxy *p) { - struct server *s, *s_next; + struct server *s, *s_back; struct cap_hdr *h,*h_next; struct listener *l,*l_next; struct bind_conf *bind_conf, *bind_back; @@ -406,17 +406,14 @@ void deinit_proxy(struct proxy *p) h = h_next; }/* end while(h) */ - s = p->srv; - while (s) { + list_for_each_entry_safe(s, s_back, &p->servers, el_px) { list_for_each_entry(srvdf, &server_deinit_list, list) srvdf->fct(s); if (p->lbprm.ops && p->lbprm.ops->server_deinit) p->lbprm.ops->server_deinit(s); - s_next = s->next; srv_drop(s); - s = s_next; }/* end while(s) */ /* also free default-server parameters since some of them might have @@ -1571,6 +1568,7 @@ void init_new_proxy(struct proxy *p) memset(p, 0, sizeof(struct proxy)); p->obj_type = OBJ_TYPE_PROXY; LIST_INIT(&p->global_list); + LIST_INIT(&p->servers); LIST_INIT(&p->el); LIST_INIT(&p->acl); LIST_INIT(&p->http_req_rules); @@ -1663,8 +1661,9 @@ int proxy_init_per_thr(struct proxy *px) int proxy_finalize(struct proxy *px, int *err_code) { + struct list tmp_list = LIST_HEAD_INIT(tmp_list); struct bind_conf *bind_conf; - struct server *newsrv; + struct server *newsrv, *newsrv_back; struct switching_rule *rule; struct server_rule *srule; struct sticking_rule *mrule; @@ -1997,7 +1996,7 @@ int proxy_finalize(struct proxy *px, int *err_code) free(px->defbe.name); px->defbe.be = target; /* Emit a warning if this proxy also has some servers */ - if (px->srv) { + if (!LIST_ISEMPTY(&px->servers)) { ha_warning("In proxy '%s', the 'default_backend' rule always has precedence over the servers, which will never be used.\n", px->id); *err_code |= ERR_WARN; @@ -2176,7 +2175,7 @@ int proxy_finalize(struct proxy *px, int *err_code) #endif /* Warn is a switch-mode http is used on a TCP listener with servers but no backend */ - if (!px->defbe.name && LIST_ISEMPTY(&px->switching_rules) && px->srv) { + if (!px->defbe.name && LIST_ISEMPTY(&px->switching_rules) && !LIST_ISEMPTY(&px->servers)) { if ((px->options & PR_O_HTTP_UPG) && px->mode == PR_MODE_TCP) ha_warning("Proxy '%s' : 'switch-mode http' configured for a %s %s with no backend. " "Incoming connections upgraded to HTTP cannot be routed to TCP servers\n", @@ -2436,7 +2435,7 @@ int proxy_finalize(struct proxy *px, int *err_code) if (!(px->cap & PR_CAP_INT) && (px->mode == PR_MODE_TCP || px->mode == PR_MODE_HTTP) && (((px->cap & PR_CAP_FE) && !px->timeout.client) || - ((px->cap & PR_CAP_BE) && (px->srv) && + ((px->cap & PR_CAP_BE) && !LIST_ISEMPTY(&px->servers) && (!px->timeout.connect || (!px->timeout.server && (px->mode == PR_MODE_HTTP || !px->timeout.tunnel)))))) { ha_warning("missing timeouts for %s '%s'.\n" @@ -2497,17 +2496,11 @@ int proxy_finalize(struct proxy *px, int *err_code) } /* first, we will invert the servers list order */ - newsrv = NULL; - while (px->srv) { - struct server *next; - - next = px->srv->next; - px->srv->next = newsrv; - newsrv = px->srv; - if (!next) - break; - px->srv = next; + list_for_each_entry_safe(newsrv, newsrv_back, &px->servers, el_px) { + LIST_DEL_INIT(&newsrv->el_px); + LIST_INSERT(&tmp_list, &newsrv->el_px); } + LIST_SPLICE(&px->servers, &tmp_list); /* Check that no server name conflicts. This causes trouble in the stats. * We only emit an error for the first conflict affecting each server, @@ -2516,7 +2509,7 @@ int proxy_finalize(struct proxy *px, int *err_code) * we simply have to check for the current server's duplicates to spot * conflicts. */ - for (newsrv = px->srv; newsrv; newsrv = newsrv->next) { + list_for_each_entry(newsrv, &px->servers, el_px) { struct server *other_srv; /* Note: internal servers are not always registered and @@ -2537,8 +2530,7 @@ int proxy_finalize(struct proxy *px, int *err_code) /* assign automatic UIDs to servers which don't have one yet */ next_id = 1; - newsrv = px->srv; - while (newsrv != NULL) { + list_for_each_entry(newsrv, &px->servers, el_px) { if (!newsrv->puid) { /* server ID not set, use automatic numbering with first * spare entry starting with next_svid. @@ -2549,7 +2541,6 @@ int proxy_finalize(struct proxy *px, int *err_code) } next_id++; - newsrv = newsrv->next; } px->lbprm.wmult = 1; /* default weight multiplier */ @@ -2560,8 +2551,7 @@ int proxy_finalize(struct proxy *px, int *err_code) * tasks to fill the emptied slots when a connection leaves. * Also, resolve deferred tracking dependency if needed. */ - newsrv = px->srv; - while (newsrv != NULL) { + list_for_each_entry(newsrv, &px->servers, el_px) { set_usermsgs_ctx(newsrv->conf.file, newsrv->conf.line, &newsrv->obj_type); srv_minmax_conn_apply(newsrv); @@ -2615,7 +2605,6 @@ int proxy_finalize(struct proxy *px, int *err_code) next_srv: reset_usermsgs_ctx(); - newsrv = newsrv->next; } /* @@ -2626,11 +2615,8 @@ int proxy_finalize(struct proxy *px, int *err_code) * have been provided yet. */ if (px->ck_opts & PR_CK_DYNAMIC) { - newsrv = px->srv; - while (newsrv != NULL) { + list_for_each_entry(newsrv, &px->servers, el_px) srv_set_dyncookie(newsrv); - newsrv = newsrv->next; - } } /* We have to initialize the server lookup mechanism depending @@ -2752,8 +2738,7 @@ int proxy_finalize(struct proxy *px, int *err_code) /* * ensure that we're not cross-dressing a TCP server into HTTP. */ - newsrv = px->srv; - while (newsrv != NULL) { + list_for_each_entry(newsrv, &px->servers, el_px) { if ((px->mode != PR_MODE_HTTP) && newsrv->rdr_len) { ha_alert("%s '%s' : server cannot have cookie or redirect prefix in non-HTTP mode.\n", proxy_type_str(px), px->id); @@ -2793,8 +2778,6 @@ int proxy_finalize(struct proxy *px, int *err_code) *err_code |= ERR_FATAL | ERR_ALERT; goto out; } - - newsrv = newsrv->next; } /* Check filter configuration, if any */ @@ -2857,7 +2840,7 @@ int proxy_finalize(struct proxy *px, int *err_code) /* Check the mux protocols, if any, for each server attached to * the current proxy */ - for (newsrv = px->srv; newsrv; newsrv = newsrv->next) { + list_for_each_entry(newsrv, &px->servers, el_px) { int mode = conn_pr_mode_to_proto_mode(px->mode); const struct mux_proto_list *mux_ent; @@ -4682,7 +4665,7 @@ static int cli_parse_enable_dyncookie_backend(char **args, char *payload, struct px->ck_opts |= PR_CK_DYNAMIC; HA_RWLOCK_WRUNLOCK(PROXY_LOCK, &px->lock); - for (s = px->srv; s != NULL; s = s->next) { + list_for_each_entry(s, &px->servers, el_px) { HA_SPIN_LOCK(SERVER_LOCK, &s->lock); srv_set_dyncookie(s); HA_SPIN_UNLOCK(SERVER_LOCK, &s->lock); @@ -4717,7 +4700,7 @@ static int cli_parse_disable_dyncookie_backend(char **args, char *payload, struc px->ck_opts &= ~PR_CK_DYNAMIC; HA_RWLOCK_WRUNLOCK(PROXY_LOCK, &px->lock); - for (s = px->srv; s != NULL; s = s->next) { + list_for_each_entry(s, &px->servers, el_px) { HA_SPIN_LOCK(SERVER_LOCK, &s->lock); if (!(s->flags & SRV_F_COOKIESET)) ha_free(&s->cookie); @@ -4762,7 +4745,7 @@ static int cli_parse_set_dyncookie_key_backend(char **args, char *payload, struc px->dyncookie_key = newkey; HA_RWLOCK_WRUNLOCK(PROXY_LOCK, &px->lock); - for (s = px->srv; s != NULL; s = s->next) { + list_for_each_entry(s, &px->servers, el_px) { HA_SPIN_LOCK(SERVER_LOCK, &s->lock); srv_set_dyncookie(s); HA_SPIN_UNLOCK(SERVER_LOCK, &s->lock); @@ -5062,7 +5045,7 @@ int be_check_for_deletion(const char *bename, struct proxy **pb, const char **pm goto out; } - if (be->srv) { + if (!LIST_ISEMPTY(&be->servers)) { msg = "Only a backend without server can be deleted."; goto out; } diff --git a/src/resolvers.c b/src/resolvers.c index 1d99dd953..c166ccaa6 100644 --- a/src/resolvers.c +++ b/src/resolvers.c @@ -2818,7 +2818,7 @@ static int resolvers_finalize_config(void) continue; } - for (srv = px->srv; srv; srv = srv->next) { + list_for_each_entry(srv, &px->servers, el_px) { struct resolvers *resolvers; if (!srv->resolvers_id) @@ -4064,8 +4064,7 @@ static int cfg_post_check_resolvers(void) list_for_each_entry(r, &sec_resolvers, list) { /* prepare forward server descriptors */ if (r->px) { - srv = r->px->srv; - while (srv) { + list_for_each_entry(srv, &r->px->servers, el_px) { /* init ssl if needed */ if (srv->use_ssl == 1 && xprt_get(XPRT_SSL) && xprt_get(XPRT_SSL)->prepare_srv) { if (xprt_get(XPRT_SSL)->prepare_srv(srv)) { @@ -4074,7 +4073,6 @@ static int cfg_post_check_resolvers(void) break; } } - srv = srv->next; } } } diff --git a/src/server.c b/src/server.c index 1171c7364..0e66762fc 100644 --- a/src/server.c +++ b/src/server.c @@ -550,8 +550,7 @@ static inline void srv_check_for_dup_dyncookie(struct server *s) struct proxy *p = s->proxy; struct server *tmpserv; - for (tmpserv = p->srv; tmpserv != NULL; - tmpserv = tmpserv->next) { + list_for_each_entry(tmpserv, &p->servers, el_px) { if (tmpserv == s) continue; if (tmpserv->next_admin & SRV_ADMF_FMAINT) @@ -2135,9 +2134,10 @@ void srv_shutdown_backup_streams(struct proxy *px, int why) { struct server *srv; - for (srv = px->srv; srv != NULL; srv = srv->next) + list_for_each_entry(srv, &px->servers, el_px) { if (srv->flags & SRV_F_BACKUP) srv_shutdown_streams(srv, why); + } } static void srv_append_op_chg_cause(struct buffer *msg, struct server *s, enum srv_op_st_chg_cause cause) @@ -2393,7 +2393,7 @@ void srv_compute_all_admin_states(struct proxy *px) { struct server *srv; - for (srv = px->srv; srv; srv = srv->next) { + list_for_each_entry(srv, &px->servers, el_px) { if (srv->track) continue; srv_propagate_admin_state(srv); @@ -3185,21 +3185,15 @@ struct server *new_server(struct proxy *proxy) #endif // add server to proxy list: - /* TODO use a double-linked list for px->srv */ - if (!(proxy->flags & PR_FL_CHECKED) || !proxy->srv) { + if (!(proxy->flags & PR_FL_CHECKED)) { /* they are linked backwards first during parsing * This will be restablished after parsing. */ - srv->next = proxy->srv; - proxy->srv = srv; + LIST_INSERT(&proxy->servers, &srv->el_px); } else { - struct server *sv = proxy->srv; - // runtime, add the server at the end of the list - while (sv && sv->next) - sv = sv->next; - sv->next = srv; + LIST_APPEND(&proxy->servers, &srv->el_px); } HA_RWLOCK_INIT(&srv->path_params.param_lock); @@ -5194,7 +5188,7 @@ struct server *snr_check_ip_callback(struct server *srv, void *ip, unsigned char return NULL; be = srv->proxy; - for (tmpsrv = be->srv; tmpsrv; tmpsrv = tmpsrv->next) { + list_for_each_entry(tmpsrv, &be->servers, el_px) { /* we found the current server is the same, ignore it */ if (srv == tmpsrv) continue; @@ -5460,7 +5454,7 @@ int srv_init_addr(void) if (!(curproxy->cap & PR_CAP_BE) || (curproxy->flags & (PR_FL_DISABLED|PR_FL_STOPPED))) continue; - for (srv = curproxy->srv; srv; srv = srv->next) { + list_for_each_entry(srv, &curproxy->servers, el_px) { set_usermsgs_ctx(srv->conf.file, srv->conf.line, &srv->obj_type); if (srv->hostname || srv->srvrq) return_code |= srv_iterate_initaddr(srv); diff --git a/src/server_state.c b/src/server_state.c index 426cad956..def8de56d 100644 --- a/src/server_state.c +++ b/src/server_state.c @@ -503,7 +503,7 @@ static void srv_state_px_update(const struct proxy *px, int vsn, struct eb_root struct server *srv; unsigned long key; - for (srv = px->srv; srv; srv = srv->next) { + list_for_each_entry(srv, &px->servers, el_px) { chunk_printf(&trash, "%s %s", px->id, srv->id); key = XXH3(trash.area, trash.data, 0); node = eb64_lookup(st_tree, key); @@ -837,7 +837,7 @@ void apply_server_state(void) struct eb_root local_state_tree = EB_ROOT_UNIQUE; /* Must be an enabled backend with at least a server */ - if (!(curproxy->cap & PR_CAP_BE) || (curproxy->flags & (PR_FL_DISABLED|PR_FL_STOPPED)) || !curproxy->srv) + if (!(curproxy->cap & PR_CAP_BE) || (curproxy->flags & (PR_FL_DISABLED|PR_FL_STOPPED)) || LIST_ISEMPTY(&curproxy->servers)) continue; /* next proxy */ /* Mode must be specified */ diff --git a/src/sink.c b/src/sink.c index 7fa559a57..de2a4518a 100644 --- a/src/sink.c +++ b/src/sink.c @@ -929,13 +929,11 @@ static int sink_finalize(struct sink *sink) /* prepare forward server descriptors */ if (sink->forward_px) { /* sink proxy is set: register all servers from the proxy */ - srv = sink->forward_px->srv; - while (srv) { + list_for_each_entry(srv, &sink->forward_px->servers, el_px) { if (!sink_add_srv(sink, srv)) { err_code |= ERR_ALERT | ERR_FATAL; break; } - srv = srv->next; } } /* init forwarding if at least one sft is registered */ diff --git a/src/stats-html.c b/src/stats-html.c index 4deeb695a..ae256fb02 100644 --- a/src/stats-html.c +++ b/src/stats-html.c @@ -1374,7 +1374,7 @@ void stats_dump_html_px_hdr(struct stconn *sc, struct proxy *px) struct stats_module *mod; int stats_module_len = 0; - if (px->cap & PR_CAP_BE && px->srv && (ctx->flags & STAT_F_ADMIN)) { + if (px->cap & PR_CAP_BE && !LIST_ISEMPTY(&px->servers) && (ctx->flags & STAT_F_ADMIN)) { /* A form to enable/disable this proxy servers */ /* scope_txt = search pattern + search query, ctx->scope_len is always <= STAT_SCOPE_TXT_MAXLEN */ @@ -1424,7 +1424,7 @@ void stats_dump_html_px_hdr(struct stconn *sc, struct proxy *px) if (ctx->flags & STAT_F_ADMIN) { /* Column heading for Enable or Disable server */ - if ((px->cap & PR_CAP_BE) && px->srv) + if ((px->cap & PR_CAP_BE) && !LIST_ISEMPTY(&px->servers)) chunk_appendf(chk, ""); - if ((px->cap & PR_CAP_BE) && px->srv && (ctx->flags & STAT_F_ADMIN)) { + if ((px->cap & PR_CAP_BE) && !LIST_ISEMPTY(&px->servers) && (ctx->flags & STAT_F_ADMIN)) { /* close the form used to enable/disable this proxy servers */ chunk_appendf(chk, "Choose the action to perform on the checked servers : " diff --git a/src/stats-proxy.c b/src/stats-proxy.c index e9337769f..51bd17a33 100644 --- a/src/stats-proxy.c +++ b/src/stats-proxy.c @@ -1160,7 +1160,7 @@ static void stats_fill_be_computesrv(struct proxy *px, int *nbup, int *nbsrv, in const struct server *srv; nbup_tmp = nbsrv_tmp = totuw_tmp = 0; - for (srv = px->srv; srv; srv = srv->next) { + list_for_each_entry(srv, &px->servers, el_px) { if (srv->cur_state != SRV_ST_STOPPED) { nbup_tmp++; if (srv_currently_usable(srv) && @@ -1254,7 +1254,7 @@ int stats_fill_be_line(struct proxy *px, int flags, struct field *line, int len, break; case ST_I_PX_STATUS: fld = chunk_newstr(out); - chunk_appendf(out, "%s", (px->lbprm.tot_weight > 0 || !px->srv) ? "UP" : "DOWN"); + chunk_appendf(out, "%s", (px->lbprm.tot_weight > 0 || LIST_ISEMPTY(&px->servers)) ? "UP" : "DOWN"); if (px->flags & PR_FL_BE_UNPUBLISHED) chunk_appendf(out, " (UNPUB)"); if (flags & (STAT_F_HIDE_MAINT|STAT_F_HIDE_DOWN)) @@ -1281,7 +1281,7 @@ int stats_fill_be_line(struct proxy *px, int flags, struct field *line, int len, field = mkf_u32(0, px->srv_bck); break; case ST_I_PX_DOWNTIME: - if (px->srv) + if (!LIST_ISEMPTY(&px->servers)) field = mkf_u32(FN_COUNTER, be_downtime(px)); break; case ST_I_PX_PID: @@ -1689,7 +1689,7 @@ void proxy_stats_clear_counters(int clrall, struct list *stat_modules) px->fe_counters.cps_max = 0; } - for (sv = px->srv; sv; sv = sv->next) + list_for_each_entry(sv, &px->servers, el_px) { if (clrall) memset(&sv->counters, 0, sizeof(sv->counters)); else { @@ -1701,6 +1701,7 @@ void proxy_stats_clear_counters(int clrall, struct list *stat_modules) sv->counters.dtime_max = 0; sv->counters.ttime_max = 0; } + } list_for_each_entry(li, &px->conf.listeners, by_fe) if (li->counters) { @@ -1733,7 +1734,7 @@ void proxy_stats_clear_counters(int clrall, struct list *stat_modules) } if (mod_cap & STATS_PX_CAP_SRV) { - for (sv = px->srv; sv; sv = sv->next) { + list_for_each_entry(sv, &px->servers, el_px) { EXTRA_COUNTERS_INIT(sv->extra_counters, mod, mod->counters, diff --git a/src/stats.c b/src/stats.c index cf0d89e00..f0737df0e 100644 --- a/src/stats.c +++ b/src/stats.c @@ -1167,7 +1167,7 @@ int stats_allocate_proxy_counters(struct proxy *px) } } - for (sv = px->srv; sv; sv = sv->next) { + list_for_each_entry(sv, &px->servers, el_px) { if (!stats_allocate_proxy_counters_internal(&sv->extra_counters, COUNTERS_SV, STATS_PX_CAP_SRV,