diff --git a/doc/configuration.txt b/doc/configuration.txt index 15bf24e34..11d687928 100644 --- a/doc/configuration.txt +++ b/doc/configuration.txt @@ -12446,7 +12446,7 @@ stick store-request [table ] [{if | unless} ] stick-table type {ip | integer | string [len ] | binary [len ]} size [expire ] [nopurge] [peers ] [srvkey ] - [write-to ] [store ]* + [write-to ] [store ]* [brates-factor ] Configure the stickiness table for the current section May be used in the following contexts: tcp, http @@ -12568,6 +12568,13 @@ stick-table type {ip | integer | string [len ] | binary [len ]} the type between parenthesis. See below for the supported data types and their arguments. + is used to define a factor to be applied on in/out bytes rate. + Instead of counting each bytes, blocks of bytes are counted. + Internally, rates are defined on 32-bits counters. By using this + parameter, it is possible to have rates exceeding the 4G on the + defined period. The factor must be greater than 0 and lower or + equal to 1024. + The data types that can be stored with an entry are the following : - server_id : this is an integer which holds the numeric ID of the server a request was assigned to. It is used by the "stick match", "stick store", diff --git a/include/haproxy/stick_table-t.h b/include/haproxy/stick_table-t.h index 4b984396e..3aa55e378 100644 --- a/include/haproxy/stick_table-t.h +++ b/include/haproxy/stick_table-t.h @@ -184,6 +184,7 @@ struct stktable { int data_size; /* the size of the data that is prepended *before* stksess */ int data_ofs[STKTABLE_DATA_TYPES]; /* negative offsets of present data types, or 0 if absent */ unsigned int data_nbelem[STKTABLE_DATA_TYPES]; /* to store nb_elem in case of array types */ + unsigned int brates_factor; /* Factor used for IN/OUT bytes rates */ union { int i; unsigned int u; diff --git a/include/haproxy/stick_table.h b/include/haproxy/stick_table.h index 4132af129..14b3e2d8f 100644 --- a/include/haproxy/stick_table.h +++ b/include/haproxy/stick_table.h @@ -395,7 +395,8 @@ static inline int stkctr_inc_bytes_in_ctr(struct stkctr *stkctr, unsigned long l ptr2 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_BYTES_IN_RATE); if (ptr2) update_freq_ctr_period(&stktable_data_cast(ptr2, std_t_frqp), - stkctr->table->data_arg[STKTABLE_DT_BYTES_IN_RATE].u, bytes); + stkctr->table->data_arg[STKTABLE_DT_BYTES_IN_RATE].u, + div64_32(bytes + stkctr->table->brates_factor - 1, stkctr->table->brates_factor)); HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock); @@ -426,7 +427,8 @@ static inline int stkctr_inc_bytes_out_ctr(struct stkctr *stkctr, unsigned long ptr2 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_BYTES_OUT_RATE); if (ptr2) update_freq_ctr_period(&stktable_data_cast(ptr2, std_t_frqp), - stkctr->table->data_arg[STKTABLE_DT_BYTES_OUT_RATE].u, bytes); + stkctr->table->data_arg[STKTABLE_DT_BYTES_OUT_RATE].u, + div64_32(bytes + stkctr->table->brates_factor - 1, stkctr->table->brates_factor)); HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock); diff --git a/src/flt_bwlim.c b/src/flt_bwlim.c index 11eb2484a..1d0759803 100644 --- a/src/flt_bwlim.c +++ b/src/flt_bwlim.c @@ -78,7 +78,8 @@ static int bwlim_apply_limit(struct filter *filter, struct channel *chn, unsigne struct bwlim_config *conf = FLT_CONF(filter); struct bwlim_state *st = filter->ctx; struct freq_ctr *bytes_rate; - unsigned int period, limit, remain, tokens, users; + uint64_t remain; + unsigned int period, limit, tokens, users, factor; unsigned int wait = 0; int overshoot, ret = 0; @@ -110,6 +111,7 @@ static int bwlim_apply_limit(struct filter *filter, struct channel *chn, unsigne period = conf->table.t->data_arg[type].u; limit = conf->limit; users = st->ts->ref_cnt; + factor = conf->table.t->brates_factor; } else { /* On per-stream mode, the freq-counter is private to the @@ -121,6 +123,7 @@ static int bwlim_apply_limit(struct filter *filter, struct channel *chn, unsigne period = (st->period ? st->period : conf->period); limit = (st->limit ? st->limit : conf->limit); users = 1; + factor = 1; } /* Be sure the current rate does not exceed the limit over the current @@ -143,7 +146,7 @@ static int bwlim_apply_limit(struct filter *filter, struct channel *chn, unsigne } /* Get the allowed quota per user. */ - remain = freq_ctr_remain_period(bytes_rate, period, limit, 0); + remain = (uint64_t)freq_ctr_remain_period(bytes_rate, period, limit, 0) * factor; tokens = div64_32((uint64_t)(remain + users - 1), users); if (tokens < len) { @@ -159,16 +162,16 @@ static int bwlim_apply_limit(struct filter *filter, struct channel *chn, unsigne : conf->min_size; if (ret <= remain) - wait = div64_32((uint64_t)(ret - tokens) * period * users + limit - 1, limit); + wait = div64_32((uint64_t)(ret - tokens) * period * users + limit * factor - 1, limit * factor); else - ret = (limit < ret) ? remain : 0; + ret = (limit * factor < ret) ? remain : 0; } } /* At the end, update the freq-counter and compute the waiting time if * the stream is limited */ - update_freq_ctr_period(bytes_rate, period, ret); + update_freq_ctr_period(bytes_rate, period, div64_32((uint64_t)ret + factor -1, factor)); if (ret < len) { wait += next_event_delay_period(bytes_rate, period, limit, MIN(len - ret, conf->min_size * users)); st->exp = tick_add(now_ms, (wait ? wait : 1)); diff --git a/src/stick_table.c b/src/stick_table.c index c6e5cf0c7..f69146d1d 100644 --- a/src/stick_table.c +++ b/src/stick_table.c @@ -1184,6 +1184,7 @@ int parse_stick_table(const char *file, int linenum, char **args, t->conf.file = file; t->conf.line = linenum; t->write_to.name = NULL; + t->brates_factor = 1; while (*args[idx]) { const char *err; @@ -1388,6 +1389,28 @@ int parse_stick_table(const char *file, int linenum, char **args, t->write_to.name = strdup(write_to); idx++; } + else if (strcmp(args[idx], "brates-factor") == 0) { + idx++; + if (!*(args[idx])) { + ha_alert("parsing [%s:%d] : %s: missing argument after '%s'.\n", + file, linenum, args[0], args[idx-1]); + err_code |= ERR_ALERT | ERR_FATAL; + goto out; + } + if ((err = parse_size_err(args[idx], &t->brates_factor))) { + ha_alert("parsing [%s:%d] : %s: unexpected character '%c' in argument of '%s'.\n", + file, linenum, args[0], *err, args[idx-1]); + err_code |= ERR_ALERT | ERR_FATAL; + goto out; + } + if (t->brates_factor == 0 || t->brates_factor > 1024) { + ha_alert("parsing [%s:%d] : %s: argument '%s' must be greater than 0 and lower or equal than 1024.\n", + file, linenum, args[0], args[idx-1]); + err_code |= ERR_ALERT | ERR_FATAL; + goto out; + } + idx++; + } else { ha_alert("parsing [%s:%d] : %s: unknown argument '%s'.\n", file, linenum, args[0], args[idx]); @@ -1677,8 +1700,8 @@ static int sample_conv_table_bytes_in_rate(const struct arg *arg_p, struct sampl ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_IN_RATE); if (ptr) - smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp), - t->data_arg[STKTABLE_DT_BYTES_IN_RATE].u); + smp->data.u.sint = (uint64_t)read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp), + t->data_arg[STKTABLE_DT_BYTES_IN_RATE].u) * t->brates_factor; stktable_release(t, ts); return !!ptr; @@ -1899,8 +1922,9 @@ static int sample_conv_table_bytes_out_rate(const struct arg *arg_p, struct samp ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_OUT_RATE); if (ptr) - smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp), - t->data_arg[STKTABLE_DT_BYTES_OUT_RATE].u); + smp->data.u.sint = (uint64_t)read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp), + t->data_arg[STKTABLE_DT_BYTES_OUT_RATE].u) * t->brates_factor; + stktable_release(t, ts); return !!ptr; @@ -4918,8 +4942,8 @@ smp_fetch_sc_bytes_in_rate(const struct arg *args, struct sample *smp, const cha HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock); - smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp), - stkctr->table->data_arg[STKTABLE_DT_BYTES_IN_RATE].u); + smp->data.u.sint = (uint64_t)read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp), + stkctr->table->data_arg[STKTABLE_DT_BYTES_IN_RATE].u) * stkctr->table->brates_factor; HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock); @@ -4997,8 +5021,8 @@ smp_fetch_sc_bytes_out_rate(const struct arg *args, struct sample *smp, const ch HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock); - smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp), - stkctr->table->data_arg[STKTABLE_DT_BYTES_OUT_RATE].u); + smp->data.u.sint = (uint64_t)read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp), + stkctr->table->data_arg[STKTABLE_DT_BYTES_OUT_RATE].u) * stkctr->table->brates_factor; HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock); @@ -5110,6 +5134,7 @@ static int table_dump_entry_to_buffer(struct buffer *msg, for (dt = 0; dt < STKTABLE_DATA_TYPES; dt++) { void *ptr; + long long data; if (t->data_ofs[dt] == 0) continue; @@ -5151,9 +5176,11 @@ static int table_dump_entry_to_buffer(struct buffer *msg, chunk_appendf(msg, "%llu", stktable_data_cast(ptr, std_t_ull)); break; case STD_T_FRQP: - chunk_appendf(msg, "%u", - read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp), - t->data_arg[dt].u)); + data = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp), + t->data_arg[dt].u); + if (dt == STKTABLE_DT_BYTES_IN_RATE || dt == STKTABLE_DT_BYTES_OUT_RATE) + data *= t->brates_factor; + chunk_appendf(msg, "%llu", data); break; } ptr = stktable_data_ptr_idx(t, entry, dt, ++idx); @@ -5177,9 +5204,11 @@ static int table_dump_entry_to_buffer(struct buffer *msg, chunk_appendf(msg, "%llu", stktable_data_cast(ptr, std_t_ull)); break; case STD_T_FRQP: - chunk_appendf(msg, "%u", - read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp), - t->data_arg[dt].u)); + data = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp), + t->data_arg[dt].u); + if (dt == STKTABLE_DT_BYTES_IN_RATE || dt == STKTABLE_DT_BYTES_OUT_RATE) + data *= t->brates_factor; + chunk_appendf(msg, "%llu", data); break; case STD_T_DICT: { struct dict_entry *de; @@ -5617,6 +5646,8 @@ static int cli_io_handler_table(struct appctx *appctx) case STD_T_FRQP: data = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp), ctx->t->data_arg[dt].u); + if (dt == STKTABLE_DT_BYTES_IN_RATE || dt == STKTABLE_DT_BYTES_OUT_RATE) + data *= ctx->t->brates_factor; break; }