]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MEDIUM: bwlim: Support constants limit or period on set-bandwidth-limit actions
authorChristopher Faulet <cfaulet@haproxy.com>
Fri, 13 Jan 2023 14:33:32 +0000 (15:33 +0100)
committerChristopher Faulet <cfaulet@haproxy.com>
Thu, 19 Jan 2023 15:15:12 +0000 (16:15 +0100)
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.

doc/configuration.txt
src/flt_bwlim.c

index c6df770c0f845dec081291dc4aae36a9b4221b99..26cc044aff4db78d0db5064903a6cf41aa2fcf2e 100644 (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
index d59da23cc96827c9f16c7d764faf3104d80fc540..ff39d660d52b6f709ec7341b69145064da13915b 100644 (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