MEDIUM: bwlim: Support constants limit or period on set-bandwidth-limit actions

It is now possible to set a constant for the limit or period parameters on a
set-bandwidth-limit actions. The limit must follow the HAProxy size format
and is expressed in bytes. The period must follow the HAProxy time format
and is expressed in milliseconds. Of course, it is still possible to use
sample expressions instead.

The documentation was updated accordingly.

It is not really a bug. Only exemples were written this way in the
documentation. But it could be good to backport this change in 2.7.
This commit is contained in:
Christopher Faulet 2023-01-13 15:33:32 +01:00
parent ab34ebe5f5
commit da2e117369
2 changed files with 68 additions and 22 deletions

View File

@ -6592,7 +6592,7 @@ http-request <action> [options...] [ { if | unless } <condition> ]
- sc-inc-gpc1(<sc-id>)
- sc-set-gpt(<idx>,<sc-id>) { <int> | <expr> }
- sc-set-gpt0(<sc-id>) { <int> | <expr> }
- set-bandwidth-limit <name> [limit <expr>] [period <expr>]
- set-bandwidth-limit <name> [limit {<expr> | <size>}] [period {<expr> | <time>}]
- set-dst <expr>
- set-dst-port <expr>
- set-header <name> <fmt>
@ -7287,7 +7287,8 @@ http-request send-spoe-group <engine-name> <group-name>
<group-name> The SPOE group name as specified in the engine
configuration.
http-request set-bandwidth-limit <name> [limit <expr>] [period <expr>] [ { if | unless } <condition> ]
http-request set-bandwidth-limit <name> [limit { <expr> | <size> }]
[period { <expr> | <time> }] [ { if | unless } <condition> ]
This action is used to enable the bandwidth limitation filter <name>, either
on the upload or download direction depending on the filter type. Custom
@ -7308,6 +7309,12 @@ http-request set-bandwidth-limit <name> [limit <expr>] [period <expr>] [ { if |
interpreted as a size in bytes for the "limit" parameter and as a
duration in milliseconds for the "period" parameter.
<size> Is a number. It follows the HAProxy size format and is expressed in
bytes.
<time> Is a number. It follows the HAProxy time format and is expressed in
milliseconds.
Example:
http-request set-bandwidth-limit global-limit
http-request set-bandwidth-limit my-limit limit 1m period 10s
@ -7791,7 +7798,7 @@ http-response <action> <options...> [ { if | unless } <condition> ]
- sc-set-gpt(<idx>,<sc-id>) { <int> | <expr> }
- sc-set-gpt0(<sc-id>) { <int> | <expr> }
- send-spoe-group <engine-name> <group-name>
- set-bandwidth-limit <name> [limit <expr>] [period <expr>]
- set-bandwidth-limit <name> [limit {<expr> | <size>}] [period {<expr> | <time>}]
- set-header <name> <fmt>
- set-log-level <level>
- set-map(<file-name>) <key fmt> <value fmt>
@ -7987,7 +7994,8 @@ http-response send-spoe-group <engine-name> <group-name>
This action is used to trigger sending of a group of SPOE messages. Please
refer to "http-request send-spoe-group" for a complete description.
http-response set-bandwidth-limit <name> [limit <expr>] [period <expr>] [ { if | unless } <condition> ]
http-response set-bandwidth-limit <name> [limit { <expr> | <size> }]
[period { <expr> | <time> }] [ { if | unless } <condition> ]
This action is used to enable the bandwidth limitation filter <name>, either
on the upload or download direction depending on the filter type. Please
@ -12939,7 +12947,7 @@ tcp-request content <action> [{if | unless} <condition>]
- sc-set-gpt(<idx>,<sc-id>) { <int> | <expr> }
- sc-set-gpt0(<sc-id>) { <int> | <expr> }
- send-spoe-group <engine-name> <group-name>
- set-bandwidth-limit <name> [limit <expr>] [period <expr>]
- set-bandwidth-limit <name> [limit {<expr> | <size>}] [period {<expr> | <time>}]
- set-dst <expr>
- set-dst-port <expr>
- set-log-level <level>
@ -13133,8 +13141,8 @@ tcp-request content send-spoe-group <engine-name> <group-name>
Thaction is is used to trigger sending of a group of SPOE messages. Please
refer to "http-request send-spoe-group" for a complete description.
tcp-request content set-bandwidth-limit <name> [limit <expr>] [period <expr>]
[ { if | unless } <condition> ]
tcp-request content set-bandwidth-limit <name> [limit { <expr> | <size> }]
[period { <expr> | <time> }] [ { if | unless } <condition> ]
This action is used to enable the bandwidth limitation filter <name>, either
on the upload or download direction depending on the filter type. Please
@ -13507,7 +13515,7 @@ tcp-response content <action> [{if | unless} <condition>]
- sc-set-gpt(<idx>,<sc-id>) { <int> | <expr> }
- sc-set-gpt0(<sc-id>) { <int> | <expr> }
- send-spoe-group <engine-name> <group-name>
- set-bandwidth-limit <name> [limit <expr>] [period <expr>]
- set-bandwidth-limit <name> [limit {<expr> | <size>}] [period {<expr> | <time>}]
- set-log-level <level>
- set-mark <mark>
- set-nice <nice>
@ -13586,8 +13594,8 @@ tcp-response content send-spoe-group <engine-name> <group-name>
refer to "http-request send-spoe-group" for a complete description.
tcp-response content set-bandwidth-limit <name> [limit <expr>] [period <expr>]
[ { if | unless } <condition> ]
tcp-response content set-bandwidth-limit <name> [limit { <expr> | <size> }]
[period { <expr> | <time> }] [ { if | unless } <condition> ]
This action is used to enable the bandwidth limitation filter <name>, either
on the upload or download direction depending on the filter type. Please

View File

@ -35,6 +35,11 @@ struct flt_ops bwlim_ops;
#define BWLIM_FL_OUT 0x00000002 /* Limit clients downloads */
#define BWLIM_FL_SHARED 0x00000004 /* Limit shared between clients (using stick-tables) */
#define BWLIM_ACT_LIMIT_EXPR 0x00000001
#define BWLIM_ACT_LIMIT_CONST 0x00000002
#define BWLIM_ACT_PERIOD_EXPR 0x00000004
#define BWLIM_ACT_PERIOD_CONST 0x00000008
struct bwlim_config {
struct proxy *proxy;
char *name;
@ -384,16 +389,21 @@ static enum act_return bwlim_set_limit(struct act_rule *rule, struct proxy *px,
st->limit = 0;
st->period = 0;
if (rule->arg.act.p[1]) {
if (rule->action & BWLIM_ACT_LIMIT_EXPR) {
smp = sample_fetch_as_type(px, sess, s, opt, rule->arg.act.p[1], SMP_T_SINT);
if (smp && smp->data.u.sint > 0)
st->limit = smp->data.u.sint;
}
if (rule->arg.act.p[2]) {
else if (rule->action & BWLIM_ACT_LIMIT_CONST)
st->limit = (uintptr_t)rule->arg.act.p[1];
if (rule->action & BWLIM_ACT_PERIOD_EXPR) {
smp = sample_fetch_as_type(px, sess, s, opt, rule->arg.act.p[2], SMP_T_SINT);
if (smp && smp->data.u.sint > 0)
st->period = smp->data.u.sint;
}
else if (rule->action & BWLIM_ACT_PERIOD_CONST)
st->period = (uintptr_t)rule->arg.act.p[2];
}
st->exp = TICK_ETERNITY;
@ -445,7 +455,7 @@ int check_bwlim_action(struct act_rule *rule, struct proxy *px, char **err)
if (px->cap & PR_CAP_BE)
where |= (rule->from == ACT_F_HTTP_REQ ? SMP_VAL_BE_HRQ_HDR : SMP_VAL_BE_HRS_HDR);
if (rule->arg.act.p[1]) {
if ((rule->action & BWLIM_ACT_LIMIT_EXPR) && rule->arg.act.p[1]) {
struct sample_expr *expr = rule->arg.act.p[1];
if (!(expr->fetch->val & where)) {
@ -465,7 +475,7 @@ int check_bwlim_action(struct act_rule *rule, struct proxy *px, char **err)
}
}
if (rule->arg.act.p[2]) {
if ((rule->action & BWLIM_ACT_PERIOD_EXPR) && rule->arg.act.p[2]) {
struct sample_expr *expr = rule->arg.act.p[2];
if (!(expr->fetch->val & where)) {
@ -512,11 +522,11 @@ int check_bwlim_action(struct act_rule *rule, struct proxy *px, char **err)
static void release_bwlim_action(struct act_rule *rule)
{
ha_free(&rule->arg.act.p[0]);
if (rule->arg.act.p[1]) {
if ((rule->action & BWLIM_ACT_LIMIT_EXPR) && rule->arg.act.p[1]) {
release_sample_expr(rule->arg.act.p[1]);
rule->arg.act.p[1] = NULL;
}
if (rule->arg.act.p[2]) {
if ((rule->action & BWLIM_ACT_PERIOD_EXPR) && rule->arg.act.p[2]) {
release_sample_expr(rule->arg.act.p[2]);
rule->arg.act.p[2] = NULL;
}
@ -556,27 +566,55 @@ static enum act_parse_ret parse_bandwidth_limit(const char **args, int *orig_arg
while (1) {
if (strcmp(args[cur_arg], "limit") == 0) {
const char *res;
unsigned int limit;
cur_arg++;
if (!args[cur_arg]) {
memprintf(err, "missing limit expression");
memprintf(err, "missing limit value or expression");
goto error;
}
expr = sample_parse_expr((char **)args, &cur_arg, px->conf.args.file, px->conf.args.line, err, &px->conf.args, NULL);
if (!expr)
res = parse_size_err(args[cur_arg], &limit);
if (!res) {
rule->action |= BWLIM_ACT_LIMIT_CONST;
rule->arg.act.p[1] = (void *)(uintptr_t)limit;
cur_arg++;
continue;
}
expr = sample_parse_expr((char **)args, &cur_arg, px->conf.args.file, px->conf.args.line, NULL, &px->conf.args, NULL);
if (!expr) {
memprintf(err, "'%s': invalid size value or unknown fetch method '%s'", args[cur_arg-1], args[cur_arg]);
goto error;
}
rule->action |= BWLIM_ACT_LIMIT_EXPR;
rule->arg.act.p[1] = expr;
}
else if (strcmp(args[cur_arg], "period") == 0) {
const char *res;
unsigned int period;
cur_arg++;
if (!args[cur_arg]) {
memprintf(err, "missing period expression");
memprintf(err, "missing period value or expression");
goto error;
}
expr = sample_parse_expr((char **)args, &cur_arg, px->conf.args.file, px->conf.args.line, err, &px->conf.args, NULL);
if (!expr)
res = parse_time_err(args[cur_arg], &period, TIME_UNIT_MS);
if (!res) {
rule->action |= BWLIM_ACT_PERIOD_CONST;
rule->arg.act.p[2] = (void *)(uintptr_t)period;
cur_arg++;
continue;
}
expr = sample_parse_expr((char **)args, &cur_arg, px->conf.args.file, px->conf.args.line, NULL, &px->conf.args, NULL);
if (!expr) {
memprintf(err, "'%s': invalid time value or unknown fetch method '%s'", args[cur_arg-1], args[cur_arg]);
goto error;
}
rule->action |= BWLIM_ACT_PERIOD_EXPR;
rule->arg.act.p[2] = expr;
}
else