From 6c0117168e4411e108e93b0861f23a533481e136 Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Fri, 6 Jan 2023 16:09:58 +0100 Subject: [PATCH] MEDIUM: stick-table: set the track-sc limit at boottime via tune.stick-counters The number of stick-counter entries usable by track-sc rules is currently set at build time. There is no good value for this since the vast majority of users don't need any, most need only a few and rare users need more. Adding more counters for everyone increases memory and CPU usages for no reason. This patch moves the per-session and per-stream arrays to a pool of a size defined at boot time. This way it becomes possible to set the number of entries at boot time via a new global setting "tune.stick-counters" that sets the limit for the whole process. When not set, the MAX_SESS_STR_CTR value still applies, or 3 if not set, as before. It is also possible to lower the value to 0 to save a bit of memory if not used at all. Note that a few low-level sample-fetch functions had to be protected due to the ability to use sample-fetches in the global section to set some variables. --- doc/configuration.txt | 35 +++++++--- include/haproxy/global-t.h | 1 + include/haproxy/session-t.h | 2 +- include/haproxy/session.h | 20 ++++-- include/haproxy/stick_table.h | 1 + include/haproxy/stream-t.h | 2 +- include/haproxy/stream.h | 30 +++++++-- src/cfgparse.c | 10 ++- src/haproxy.c | 1 + src/session.c | 14 +++- src/stick_table.c | 117 ++++++++++++++++++++++++++-------- src/stream.c | 28 +++++--- src/tcp_rules.c | 2 +- 13 files changed, 202 insertions(+), 61 deletions(-) diff --git a/doc/configuration.txt b/doc/configuration.txt index c5e6d2a03..6d1c2d8aa 100644 --- a/doc/configuration.txt +++ b/doc/configuration.txt @@ -1158,6 +1158,7 @@ The following keywords are supported in the "global" section : - tune.sched.low-latency - tune.sndbuf.client - tune.sndbuf.server + - tune.stick-counters - tune.ssl.cachesize - tune.ssl.capture-buffer-size - tune.ssl.capture-cipherlist-size (deprecated) @@ -3305,6 +3306,21 @@ tune.ssl.ssl-ctx-cache-size dynamically is expensive, they are cached. The default cache size is set to 1000 entries. +tune.stick-counters + Sets the number of stick-counters that may be tracked at the same time by a + connection or a request via "track-sc*" actions in "tcp-request" or + "http-request" rules. The defaut value is set at build time by the macro + MAX_SESS_STK_CTR, and defaults to 3. With this setting it is possible to + change the value and ignore the one passed at build time. Increasing this + value may be needed when porting complex configurations to haproxy, but users + are warned against the costs: each entry takes 16 bytes per connection and + 16 bytes per request, all of which need to be allocated and zeroed for all + requests even when not used. As such a value of 10 will inflate the memory + consumption per request by 320 bytes and will cause this memory to be erased + for each request, which does have measurable CPU impacts. Conversely, when + no "track-sc" rules are used, the value may be lowered (0 being valid to + entirely disable stick-counters). + tune.vars.global-max-size tune.vars.proc-max-size tune.vars.reqres-max-size @@ -7617,9 +7633,10 @@ http-request track-sc2 [table ] [ { if | unless } ] This enables tracking of sticky counters from current request. These rules do not stop evaluation and do not change default action. The number of counters - that may be simultaneously tracked by the same connection is set in - MAX_SESS_STKCTR at build time (reported in haproxy -vv) which defaults to 3, - so the track-sc number is between 0 and (MAX_SESS_STKCTR-1). The first + that may be simultaneously tracked by the same connection is set by the + global "tune.stick-counters" setting, which defaults to MAX_SESS_STKCTR if + set at build time (it is reported in haproxy -vv) and which defaults to 3, + so the track-sc number is between 0 and (tune.stick-counters-1). The first "track-sc0" rule executed enables tracking of the counters of the specified table as the first set. The first "track-sc1" rule executed enables tracking of the counters of the specified table as the second set. The first @@ -18924,12 +18941,12 @@ TCP/IP addresses and ports, as well as elements from stick-tables related to the incoming connection. For retrieving a value from a sticky counters, the counter number can be explicitly set as 0, 1, or 2 using the pre-defined "sc0_", "sc1_", or "sc2_" prefix. These three pre-defined prefixes can only be -used if MAX_SESS_STKCTR value does not exceed 3, otherwise the counter number -can be specified as the first integer argument when using the "sc_" prefix. -Starting from "sc_0" to "sc_N" where N is (MAX_SESS_STKCTR-1). An optional -table may be specified with the "sc*" form, in which case the currently -tracked key will be looked up into this alternate table instead of the table -currently being tracked. +used if the global "tune.stick-counters" value does not exceed 3, otherwise the +counter number can be specified as the first integer argument when using the +"sc_" prefix starting from "sc_0" to "sc_N" where N is (tune.stick-counters-1). +An optional table may be specified with the "sc*" form, in which case the +currently tracked key will be looked up into this alternate table instead of +the table currently being tracked. bc_dst : ip This is the destination ip address of the connection on the server side, diff --git a/include/haproxy/global-t.h b/include/haproxy/global-t.h index 11f4b2c0a..92827c6fd 100644 --- a/include/haproxy/global-t.h +++ b/include/haproxy/global-t.h @@ -162,6 +162,7 @@ struct global { int pool_high_count; /* max number of opened fd before we start killing idle connections when creating new connections */ size_t pool_cache_size; /* per-thread cache size per pool (defaults to CONFIG_HAP_POOL_CACHE_SIZE) */ unsigned short idle_timer; /* how long before an empty buffer is considered idle (ms) */ + int nb_stk_ctr; /* number of stick counters, defaults to MAX_SESS_STKCTR */ #ifdef USE_QUIC unsigned int quic_backend_max_idle_timeout; unsigned int quic_frontend_max_idle_timeout; diff --git a/include/haproxy/session-t.h b/include/haproxy/session-t.h index e7a989962..46023f023 100644 --- a/include/haproxy/session-t.h +++ b/include/haproxy/session-t.h @@ -50,7 +50,7 @@ struct session { enum obj_type *origin; /* the connection / applet which initiated this session */ struct timeval accept_date; /* date of the session's accept() in user date */ struct timeval tv_accept; /* date of the session's accept() in internal date (monotonic) */ - struct stkctr stkctr[MAX_SESS_STKCTR]; /* stick counters for tcp-connection */ + struct stkctr *stkctr; /* stick counters for tcp-connection */ struct vars vars; /* list of variables for the session scope. */ struct task *task; /* handshake timeout processing */ long t_handshake; /* handshake duration, -1 = not completed */ diff --git a/include/haproxy/session.h b/include/haproxy/session.h index 13152cf1b..38335e4a5 100644 --- a/include/haproxy/session.h +++ b/include/haproxy/session.h @@ -50,7 +50,10 @@ static inline void session_store_counters(struct session *sess) int i; struct stksess *ts; - for (i = 0; i < MAX_SESS_STKCTR; i++) { + if (unlikely(!sess->stkctr)) // pool not allocated yet + return; + + for (i = 0; i < global.tune.nb_stk_ctr; i++) { struct stkctr *stkctr = &sess->stkctr[i]; ts = stkctr_entry(stkctr); @@ -80,7 +83,10 @@ static inline void session_inc_http_req_ctr(struct session *sess) { int i; - for (i = 0; i < MAX_SESS_STKCTR; i++) + if (unlikely(!sess->stkctr)) // pool not allocated yet + return; + + for (i = 0; i < global.tune.nb_stk_ctr; i++) stkctr_inc_http_req_ctr(&sess->stkctr[i]); } @@ -94,7 +100,10 @@ static inline void session_inc_http_err_ctr(struct session *sess) { int i; - for (i = 0; i < MAX_SESS_STKCTR; i++) + if (unlikely(!sess->stkctr)) // pool not allocated yet + return; + + for (i = 0; i < global.tune.nb_stk_ctr; i++) stkctr_inc_http_err_ctr(&sess->stkctr[i]); } @@ -107,7 +116,10 @@ static inline void session_inc_http_fail_ctr(struct session *sess) { int i; - for (i = 0; i < MAX_SESS_STKCTR; i++) + if (unlikely(!sess->stkctr)) // pool not allocated yet + return; + + for (i = 0; i < global.tune.nb_stk_ctr; i++) stkctr_inc_http_fail_ctr(&sess->stkctr[i]); } diff --git a/include/haproxy/stick_table.h b/include/haproxy/stick_table.h index 196aabb35..cbec13795 100644 --- a/include/haproxy/stick_table.h +++ b/include/haproxy/stick_table.h @@ -32,6 +32,7 @@ #include extern struct stktable *stktables_list; +extern struct pool_head *pool_head_stk_ctr; extern struct stktable_type stktable_types[]; #define stktable_data_size(type) (sizeof(((union stktable_data*)0)->type)) diff --git a/include/haproxy/stream-t.h b/include/haproxy/stream-t.h index 1ec40f513..fe85217c0 100644 --- a/include/haproxy/stream-t.h +++ b/include/haproxy/stream-t.h @@ -245,7 +245,7 @@ struct stream { struct stktable *table; } store[8]; /* tracked stickiness values to store */ - struct stkctr stkctr[MAX_SESS_STKCTR]; /* content-aware stick counters */ + struct stkctr *stkctr; /* content-aware stick counters */ struct strm_flt strm_flt; /* current state of filters active on this stream */ diff --git a/include/haproxy/stream.h b/include/haproxy/stream.h index 06716aeeb..ac2158d1c 100644 --- a/include/haproxy/stream.h +++ b/include/haproxy/stream.h @@ -116,7 +116,10 @@ static inline void stream_store_counters(struct stream *s) int i; struct stksess *ts; - for (i = 0; i < MAX_SESS_STKCTR; i++) { + if (unlikely(!s->stkctr)) // pool not allocated yet + return; + + for (i = 0; i < global.tune.nb_stk_ctr; i++) { ts = stkctr_entry(&s->stkctr[i]); if (!ts) continue; @@ -152,7 +155,10 @@ static inline void stream_stop_content_counters(struct stream *s) void *ptr; int i; - for (i = 0; i < MAX_SESS_STKCTR; i++) { + if (unlikely(!s->stkctr)) // pool not allocated yet + return; + + for (i = 0; i < global.tune.nb_stk_ctr; i++) { ts = stkctr_entry(&s->stkctr[i]); if (!ts) continue; @@ -231,7 +237,10 @@ static inline void stream_inc_http_req_ctr(struct stream *s) { int i; - for (i = 0; i < MAX_SESS_STKCTR; i++) { + if (unlikely(!s->stkctr)) // pool not allocated yet + return; + + for (i = 0; i < global.tune.nb_stk_ctr; i++) { if (!stkctr_inc_http_req_ctr(&s->stkctr[i])) stkctr_inc_http_req_ctr(&s->sess->stkctr[i]); } @@ -244,7 +253,10 @@ static inline void stream_inc_be_http_req_ctr(struct stream *s) { int i; - for (i = 0; i < MAX_SESS_STKCTR; i++) { + if (unlikely(!s->stkctr)) // pool not allocated yet + return; + + for (i = 0; i < global.tune.nb_stk_ctr; i++) { if (!stkctr_entry(&s->stkctr[i]) || !(stkctr_flags(&s->stkctr[i]) & STKCTR_TRACK_BACKEND)) continue; @@ -262,7 +274,10 @@ static inline void stream_inc_http_err_ctr(struct stream *s) { int i; - for (i = 0; i < MAX_SESS_STKCTR; i++) { + if (unlikely(!s->stkctr)) // pool not allocated yet + return; + + for (i = 0; i < global.tune.nb_stk_ctr; i++) { if (!stkctr_inc_http_err_ctr(&s->stkctr[i])) stkctr_inc_http_err_ctr(&s->sess->stkctr[i]); } @@ -277,7 +292,10 @@ static inline void stream_inc_http_fail_ctr(struct stream *s) { int i; - for (i = 0; i < MAX_SESS_STKCTR; i++) { + if (unlikely(!s->stkctr)) // pool not allocated yet + return; + + for (i = 0; i < global.tune.nb_stk_ctr; i++) { if (!stkctr_inc_http_fail_ctr(&s->stkctr[i])) stkctr_inc_http_fail_ctr(&s->sess->stkctr[i]); } diff --git a/src/cfgparse.c b/src/cfgparse.c index ac98a9567..6f2d93a05 100644 --- a/src/cfgparse.c +++ b/src/cfgparse.c @@ -1564,9 +1564,13 @@ cfg_parse_track_sc_num(unsigned int *track_sc_num, return -1; } - if (num >= MAX_SESS_STKCTR) { - memprintf(errmsg, "%u track-sc number exceeding " - "%d (MAX_SESS_STKCTR-1) value", num, MAX_SESS_STKCTR - 1); + if (num >= global.tune.nb_stk_ctr) { + if (!global.tune.nb_stk_ctr) + memprintf(errmsg, "%u track-sc number not usable, stick-counters " + "are disabled by tune.stick-counters", num); + else + memprintf(errmsg, "%u track-sc number exceeding " + "%d (tune.stick-counters-1) value", num, global.tune.nb_stk_ctr - 1); return -1; } diff --git a/src/haproxy.c b/src/haproxy.c index c454c803d..5f345f99d 100644 --- a/src/haproxy.c +++ b/src/haproxy.c @@ -204,6 +204,7 @@ struct global global = { #else .idle_timer = 1000, /* 1 second */ #endif + .nb_stk_ctr = MAX_SESS_STKCTR, #ifdef USE_QUIC .quic_backend_max_idle_timeout = QUIC_TP_DFLT_BACK_MAX_IDLE_TIMEOUT, .quic_frontend_max_idle_timeout = QUIC_TP_DFLT_FRONT_MAX_IDLE_TIMEOUT, diff --git a/src/session.c b/src/session.c index 3cbacc7ae..5c868ae09 100644 --- a/src/session.c +++ b/src/session.c @@ -46,7 +46,13 @@ struct session *session_new(struct proxy *fe, struct listener *li, enum obj_type sess->origin = origin; sess->accept_date = date; /* user-visible date for logging */ sess->tv_accept = now; /* corrected date for internal use */ - memset(sess->stkctr, 0, sizeof(sess->stkctr)); + sess->stkctr = NULL; + if (pool_head_stk_ctr) { + sess->stkctr = pool_alloc(pool_head_stk_ctr); + if (!sess->stkctr) + goto out_fail_alloc; + memset(sess->stkctr, 0, sizeof(sess->stkctr[0]) * global.tune.nb_stk_ctr); + } vars_init_head(&sess->vars, SCOPE_SESS); sess->task = NULL; sess->t_handshake = -1; /* handshake not done yet */ @@ -60,6 +66,9 @@ struct session *session_new(struct proxy *fe, struct listener *li, enum obj_type sess->dst = NULL; } return sess; + out_fail_alloc: + pool_free(pool_head_session, sess); + return NULL; } void session_free(struct session *sess) @@ -70,6 +79,7 @@ void session_free(struct session *sess) if (sess->listener) listener_release(sess->listener); session_store_counters(sess); + pool_free(pool_head_stk_ctr, sess->stkctr); vars_prune_per_sess(&sess->vars); conn = objt_conn(sess->origin); if (conn != NULL && conn->mux) @@ -116,7 +126,7 @@ static void session_count_new(struct session *sess) proxy_inc_fe_sess_ctr(sess->listener, sess->fe); - for (i = 0; i < MAX_SESS_STKCTR; i++) { + for (i = 0; i < global.tune.nb_stk_ctr; i++) { stkctr = &sess->stkctr[i]; if (!stkctr_entry(stkctr)) continue; diff --git a/src/stick_table.c b/src/stick_table.c index 3533ec09e..6a861110a 100644 --- a/src/stick_table.c +++ b/src/stick_table.c @@ -50,7 +50,7 @@ /* structure used to return a table key built from a sample */ static THREAD_LOCAL struct stktable_key static_table_key; static int (*smp_fetch_src)(const struct arg *, struct sample *, const char *, void *); - +struct pool_head *pool_head_stk_ctr __read_mostly = NULL; struct stktable *stktables_list; struct eb_root stktable_by_name = EB_ROOT; @@ -2456,14 +2456,16 @@ static enum act_return action_inc_gpc1(struct act_rule *rule, struct proxy *px, struct session *sess, struct stream *s, int flags) { struct stksess *ts; - struct stkctr *stkctr; + struct stkctr *stkctr = NULL; unsigned int period = 0; /* Extract the stksess, return OK if no stksess available. */ - if (s) + if (s && s->stkctr) stkctr = &s->stkctr[rule->arg.gpc.sc]; - else + else if (sess->stkctr) stkctr = &sess->stkctr[rule->arg.gpc.sc]; + else + return ACT_RET_CONT; ts = stkctr_entry(stkctr); if (ts) { @@ -2522,6 +2524,11 @@ static enum act_parse_ret parse_inc_gpc(const char **args, int *arg, struct prox const char *cmd_name = args[*arg-1]; char *error; + if (!global.tune.nb_stk_ctr) { + memprintf(err, "Cannot use '%s', stick-counters are disabled via tune.stick-counters", args[*arg-1]); + return ACT_RET_PRS_ERR; + } + cmd_name += strlen("sc-inc-gpc"); if (*cmd_name == '(') { cmd_name++; /* skip the '(' */ @@ -2538,9 +2545,9 @@ static enum act_parse_ret parse_inc_gpc(const char **args, int *arg, struct prox return ACT_RET_PRS_ERR; } - if (rule->arg.gpc.sc >= MAX_SESS_STKCTR) { - memprintf(err, "invalid stick table track ID '%s'. The max allowed ID is %d", - args[*arg-1], MAX_SESS_STKCTR-1); + if (rule->arg.gpc.sc >= global.tune.nb_stk_ctr) { + memprintf(err, "invalid stick table track ID '%s'. The max allowed ID is %d (tune.stick-counters)", + args[*arg-1], global.tune.nb_stk_ctr-1); return ACT_RET_PRS_ERR; } } @@ -2566,9 +2573,9 @@ static enum act_parse_ret parse_inc_gpc(const char **args, int *arg, struct prox return ACT_RET_PRS_ERR; } - if (rule->arg.gpc.sc >= MAX_SESS_STKCTR) { - memprintf(err, "invalid stick table track ID. The max allowed ID is %d", - MAX_SESS_STKCTR-1); + if (rule->arg.gpc.sc >= global.tune.nb_stk_ctr) { + memprintf(err, "invalid stick table track ID. The max allowed ID is %d (tune.stick-counters)", + global.tune.nb_stk_ctr-1); return ACT_RET_PRS_ERR; } } @@ -2599,16 +2606,18 @@ static enum act_return action_set_gpt(struct act_rule *rule, struct proxy *px, { void *ptr; struct stksess *ts; - struct stkctr *stkctr; + struct stkctr *stkctr = NULL; unsigned int value = 0; struct sample *smp; int smp_opt_dir; /* Extract the stksess, return OK if no stksess available. */ - if (s) + if (s && s->stkctr) stkctr = &s->stkctr[rule->arg.gpt.sc]; - else + else if (sess->stkctr) stkctr = &sess->stkctr[rule->arg.gpt.sc]; + else + return ACT_RET_CONT; ts = stkctr_entry(stkctr); if (!ts) @@ -2663,16 +2672,18 @@ static enum act_return action_set_gpt0(struct act_rule *rule, struct proxy *px, { void *ptr; struct stksess *ts; - struct stkctr *stkctr; + struct stkctr *stkctr = NULL; unsigned int value = 0; struct sample *smp; int smp_opt_dir; /* Extract the stksess, return OK if no stksess available. */ - if (s) + if (s && s->stkctr) stkctr = &s->stkctr[rule->arg.gpt.sc]; - else + else if (sess->stkctr) stkctr = &sess->stkctr[rule->arg.gpt.sc]; + else + return ACT_RET_CONT; ts = stkctr_entry(stkctr); if (!ts) @@ -2741,6 +2752,11 @@ static enum act_parse_ret parse_set_gpt(const char **args, int *arg, struct prox char *error; int smp_val; + if (!global.tune.nb_stk_ctr) { + memprintf(err, "Cannot use '%s', stick-counters are disabled via tune.stick-counters", args[*arg-1]); + return ACT_RET_PRS_ERR; + } + cmd_name += strlen("sc-set-gpt"); if (*cmd_name == '(') { cmd_name++; /* skip the '(' */ @@ -2757,9 +2773,9 @@ static enum act_parse_ret parse_set_gpt(const char **args, int *arg, struct prox return ACT_RET_PRS_ERR; } - if (rule->arg.gpt.sc >= MAX_SESS_STKCTR) { + if (rule->arg.gpt.sc >= global.tune.nb_stk_ctr) { memprintf(err, "invalid stick table track ID '%s'. The max allowed ID is %d", - args[*arg-1], MAX_SESS_STKCTR-1); + args[*arg-1], global.tune.nb_stk_ctr-1); return ACT_RET_PRS_ERR; } } @@ -2783,9 +2799,9 @@ static enum act_parse_ret parse_set_gpt(const char **args, int *arg, struct prox return ACT_RET_PRS_ERR; } - if (rule->arg.gpt.sc >= MAX_SESS_STKCTR) { + if (rule->arg.gpt.sc >= global.tune.nb_stk_ctr) { memprintf(err, "invalid stick table track ID '%s'. The max allowed ID is %d", - args[*arg-1], MAX_SESS_STKCTR-1); + args[*arg-1], global.tune.nb_stk_ctr-1); return ACT_RET_PRS_ERR; } } @@ -2914,15 +2930,19 @@ smp_fetch_sc_stkctr(struct session *sess, struct stream *strm, const struct arg * the sc[0-9]_ form, or even higher using sc_(num) if needed. * args[arg] is the first optional argument. We first lookup the * ctr form the stream, then from the session if it was not there. - * But we must be sure the counter does not exceed MAX_SESS_STKCTR. + * But we must be sure the counter does not exceed global.tune.nb_stk_ctr. */ - if (num >= MAX_SESS_STKCTR) + if (num >= global.tune.nb_stk_ctr) return NULL; - if (strm) + stkptr = NULL; + if (strm && strm->stkctr) stkptr = &strm->stkctr[num]; - if (!strm || !stkctr_entry(stkptr)) { - stkptr = &sess->stkctr[num]; + if (!strm || !stkptr || !stkctr_entry(stkptr)) { + if (sess->stkctr) + stkptr = &sess->stkctr[num]; + else + return NULL; if (!stkctr_entry(stkptr)) return NULL; } @@ -4990,6 +5010,45 @@ static void cli_release_show_table(struct appctx *appctx) } } +static int stk_parse_stick_counters(char **args, int section_type, struct proxy *curpx, + const struct proxy *defpx, const char *file, int line, + char **err) +{ + char *error; + int counters; + + counters = strtol(args[1], &error, 10); + if (*error != 0) { + memprintf(err, "%s: '%s' is an invalid number", args[0], args[1]); + return -1; + } + + if (counters < 0) { + memprintf(err, "%s: the number of stick-counters may not be negative (was %d)", args[0], counters); + return -1; + } + + global.tune.nb_stk_ctr = counters; + return 0; +} + +/* This function creates the stk_ctr pools after the configuration parsing. It + * returns 0 on success otherwise ERR_*. If nb_stk_ctr is 0, the pool remains + * NULL. + */ +static int stkt_create_stk_ctr_pool(void) +{ + if (!global.tune.nb_stk_ctr) + return 0; + + pool_head_stk_ctr = create_pool("stk_ctr", sizeof(*((struct session*)0)->stkctr) * global.tune.nb_stk_ctr, MEM_F_SHARED); + if (!pool_head_stk_ctr) { + ha_alert("out of memory while creating the stick-counters pool.\n"); + return ERR_ABORT; + } + return 0; +} + static void stkt_late_init(void) { struct sample_fetch *f; @@ -4997,6 +5056,7 @@ static void stkt_late_init(void) f = find_sample_fetch("src", strlen("src")); if (f) smp_fetch_src = f->process; + hap_register_post_check(stkt_create_stk_ctr_pool); } INITCALL0(STG_INIT, stkt_late_init); @@ -5273,3 +5333,10 @@ static struct sample_conv_kw_list sample_conv_kws = {ILH, { }}; INITCALL1(STG_REGISTER, sample_register_convs, &sample_conv_kws); + +static struct cfg_kw_list cfg_kws = {{ },{ + { CFG_GLOBAL, "tune.stick-counters", stk_parse_stick_counters }, + { /* END */ } +}}; + +INITCALL1(STG_REGISTER, cfg_register_keywords, &cfg_kws); diff --git a/src/stream.c b/src/stream.c index 006c22964..04b408136 100644 --- a/src/stream.c +++ b/src/stream.c @@ -388,13 +388,20 @@ struct stream *stream_new(struct session *sess, struct stconn *sc, struct buffer s->last_rule_file = NULL; s->last_rule_line = 0; - /* Copy SC counters for the stream. We don't touch refcounts because - * any reference we have is inherited from the session. Since the stream - * doesn't exist without the session, the session's existence guarantees - * we don't lose the entry. During the store operation, the stream won't - * touch these ones. - */ - memcpy(s->stkctr, sess->stkctr, sizeof(s->stkctr)); + s->stkctr = NULL; + if (pool_head_stk_ctr) { + s->stkctr = pool_alloc(pool_head_stk_ctr); + if (!s->stkctr) + goto out_fail_alloc; + + /* Copy SC counters for the stream. We don't touch refcounts because + * any reference we have is inherited from the session. Since the stream + * doesn't exist without the session, the session's existence guarantees + * we don't lose the entry. During the store operation, the stream won't + * touch these ones. + */ + memcpy(s->stkctr, sess->stkctr, sizeof(s->stkctr[0]) * global.tune.nb_stk_ctr); + } s->sess = sess; @@ -582,6 +589,8 @@ struct stream *stream_new(struct session *sess, struct stconn *sc, struct buffer out_fail_attach_scf: task_destroy(t); out_fail_alloc: + if (s) + pool_free(pool_head_stk_ctr, s->stkctr); pool_free(pool_head_stream, s); DBG_TRACE_DEVEL("leaving on error", STRM_EV_STRM_NEW|STRM_EV_STRM_ERR); return NULL; @@ -701,6 +710,7 @@ void stream_free(struct stream *s) vars_prune(&s->vars_reqres, s->sess, s); stream_store_counters(s); + pool_free(pool_head_stk_ctr, s->stkctr); list_for_each_entry_safe(bref, back, &s->back_refs, users) { /* we have to unlink all watchers. We must not relink them if @@ -797,7 +807,7 @@ void stream_process_counters(struct stream *s) if (sess->listener && sess->listener->counters) _HA_ATOMIC_ADD(&sess->listener->counters->bytes_in, bytes); - for (i = 0; i < MAX_SESS_STKCTR; i++) { + for (i = 0; i < global.tune.nb_stk_ctr; i++) { if (!stkctr_inc_bytes_in_ctr(&s->stkctr[i], bytes)) stkctr_inc_bytes_in_ctr(&sess->stkctr[i], bytes); } @@ -815,7 +825,7 @@ void stream_process_counters(struct stream *s) if (sess->listener && sess->listener->counters) _HA_ATOMIC_ADD(&sess->listener->counters->bytes_out, bytes); - for (i = 0; i < MAX_SESS_STKCTR; i++) { + for (i = 0; i < global.tune.nb_stk_ctr; i++) { if (!stkctr_inc_bytes_out_ctr(&s->stkctr[i], bytes)) stkctr_inc_bytes_out_ctr(&sess->stkctr[i], bytes); } diff --git a/src/tcp_rules.c b/src/tcp_rules.c index e64979495..6465e6ed1 100644 --- a/src/tcp_rules.c +++ b/src/tcp_rules.c @@ -1058,7 +1058,7 @@ static int tcp_parse_request_rule(char **args, int arg, int section_type, memprintf(err, "'%s %s' expects 'accept', 'reject', 'capture', 'expect-proxy', 'expect-netscaler-cip', 'track-sc0' ... 'track-sc%d', %s " "in %s '%s' (got '%s').%s%s%s\n", - args[0], args[1], MAX_SESS_STKCTR-1, + args[0], args[1], global.tune.nb_stk_ctr-1, trash.area, proxy_type_str(curpx), curpx->id, args[arg], best ? " Did you mean '" : "",