[sorry for mis-threading; hoping I got the git send-mail --in-reply-to right]
Hello Willy!
Actually, reading through your original and last comments, I realize I must
have misunderstood the sample_expr() part and got carried away.
Unless I'm mistaken, we can use the existing sample_fetch_as_type() function
directly (without any further addition to sample.c). Or am I missing something ?
This leaves the switch(rule->from) <-> smpt_opt_dir stuff. Since there is
nothing about act_rule in sample.c so I felt it has no place there.
Wouldn't an extra function call just to deal with this switch() be overkill ?
Let me know if you still think this ought to go in a separate function
(like if anticipating set_gpt1 :-) ).
Best,
Cédric
[patch]
Allow the sc-set-gpt0 action to set GPT0 to a value dynamically evaluated from
its <expr> argument (in addition to the existing static <int> alternative).
---
doc/configuration.txt | 44 +++++++++++++++++---------------
include/types/action.h | 1 +
src/stick_table.c | 57 +++++++++++++++++++++++++++++++++++++++---
3 files changed, 79 insertions(+), 23 deletions(-)
diff --git a/doc/configuration.txt b/doc/configuration.txt
index 8dedbfc48..bea62bd98 100644
--- a/doc/configuration.txt
+++ b/doc/configuration.txt
@@ -4465,11 +4465,13 @@ http-request sc-inc-gpc1(<sc-id>) [ { if | unless }
<condition> ]
counter designated by <sc-id>. If an error occurs, this action silently fails
and the actions evaluation continues.
-http-request sc-set-gpt0(<sc-id>) <int> [ { if | unless } <condition> ]
+http-request sc-set-gpt0(<sc-id>) { <int> | <expr> }
+ [ { if | unless } <condition> ]
- This action sets the GPT0 tag according to the sticky counter designated by
- <sc-id> and the value of <int>. The expected result is a boolean. If an error
- occurs, this action silently fails and the actions evaluation continues.
+ This action sets the 32-bit unsigned GPT0 tag according to the sticky counter
+ designated by <sc-id> and the value of <int>/<expr>. The expected result is a
+ boolean. If an error occurs, this action silently fails and the actions
+ evaluation continues.
http-request set-dst <expr> [ { if | unless } <condition> ]
@@ -4974,11 +4976,13 @@ http-response sc-inc-gpc1(<sc-id>) [ { if | unless }
<condition> ]
counter designated by <sc-id>. If an error occurs, this action silently fails
and the actions evaluation continues.
-http-response sc-set-gpt0(<sc-id>) <int> [ { if | unless } <condition> ]
+http-response sc-set-gpt0(<sc-id>) { <int> | <expr> }
+ [ { if | unless } <condition> ]
- This action sets the GPT0 tag according to the sticky counter designated by
- <sc-id> and the value of <int>. The expected result is a boolean. If an error
- occurs, this action silently fails and the actions evaluation continues.
+ This action sets the 32-bit unsigned GPT0 tag according to the sticky counter
+ designated by <sc-id> and the value of <int>/<expr>. The expected result is a
+ boolean. If an error occurs, this action silently fails and the actions
+ evaluation continues.
http-response send-spoe-group [ { if | unless } <condition> ]
@@ -9394,11 +9398,11 @@ tcp-request connection <action> [{if | unless}
<condition>]
counter designated by <sc-id>. If an error occurs, this action silently
fails and the actions evaluation continues.
- - sc-set-gpt0(<sc-id>) <int>:
- This action sets the GPT0 tag according to the sticky counter
designated
- by <sc-id> and the value of <int>. The expected result is a boolean. If
- an error occurs, this action silently fails and the actions evaluation
- continues.
+ - sc-set-gpt0(<sc-id>) { <int> | <expr> }:
+ This action sets the 32-bit unsigned GPT0 tag according to the sticky
+ counter designated by <sc-id> and the value of <int>/<expr>. The
+ expected result is a boolean. If an error occurs, this action silently
+ fails and the actions evaluation continues.
- set-src <expr> :
Is used to set the source IP address to the value of specified
@@ -9556,7 +9560,7 @@ tcp-request content <action> [{if | unless} <condition>]
- { track-sc0 | track-sc1 | track-sc2 } <key> [table <table>]
- sc-inc-gpc0(<sc-id>)
- sc-inc-gpc1(<sc-id>)
- - sc-set-gpt0(<sc-id>) <int>
+ - sc-set-gpt0(<sc-id>) { <int> | <expr> }
- set-dst <expr>
- set-dst-port <expr>
- set-var(<var-name>) <expr>
@@ -9820,11 +9824,11 @@ tcp-response content <action> [{if | unless}
<condition>]
counter designated by <sc-id>. If an error occurs, this action fails
silently and the actions evaluation continues.
- - sc-set-gpt0(<sc-id>) <int> :
- This action sets the GPT0 tag according to the sticky counter
designated
- by <sc-id> and the value of <int>. The expected result is a boolean. If
- an error occurs, this action silently fails and the actions evaluation
- continues.
+ - sc-set-gpt0(<sc-id>) { <int> | <expr> }
+ This action sets the 32-bit unsigned GPT0 tag according to the sticky
+ counter designated by <sc-id> and the value of <int>/<expr>. The
+ expected result is a boolean. If an error occurs, this action silently
+ fails and the actions evaluation continues.
- "silent-drop" :
This stops the evaluation of the rules and makes the client-facing
@@ -9945,7 +9949,7 @@ tcp-request session <action> [{if | unless} <condition>]
- { track-sc0 | track-sc1 | track-sc2 } <key> [table <table>]
- sc-inc-gpc0(<sc-id>)
- sc-inc-gpc1(<sc-id>)
- - sc-set-gpt0(<sc-id>) <int>
+ - sc-set-gpt0(<sc-id>) { <int> | <expr> }
- set-var(<var-name>) <expr>
- unset-var(<var-name>)
- silent-drop
diff --git a/include/types/action.h b/include/types/action.h
index 54a6f71a4..516ffddd0 100644
--- a/include/types/action.h
+++ b/include/types/action.h
@@ -168,6 +168,7 @@ struct act_rule {
struct {
int sc;
long long int value;
+ struct sample_expr *expr;
} gpt;
struct track_ctr_prm trk_ctr;
struct {
diff --git a/src/stick_table.c b/src/stick_table.c
index c9f3e0636..1b70b468e 100644
--- a/src/stick_table.c
+++ b/src/stick_table.c
@@ -2016,6 +2016,9 @@ static enum act_return action_set_gpt0(struct act_rule
*rule, struct proxy *px,
void *ptr;
struct stksess *ts;
struct stkctr *stkctr;
+ unsigned int value = 0;
+ struct sample *smp;
+ int smp_opt_dir;
/* Extract the stksess, return OK if no stksess available. */
if (s)
@@ -2030,9 +2033,36 @@ static enum act_return action_set_gpt0(struct act_rule
*rule, struct proxy *px,
/* Store the sample in the required sc, and ignore errors. */
ptr = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPT0);
if (ptr) {
+ if (!rule->arg.gpt.expr)
+ value = (unsigned int)(rule->arg.gpt.value);
+ else {
+ switch (rule->from) {
+ case ACT_F_TCP_REQ_SES: smp_opt_dir = SMP_OPT_DIR_REQ;
break;
+ case ACT_F_TCP_REQ_CNT: smp_opt_dir = SMP_OPT_DIR_REQ;
break;
+ case ACT_F_TCP_RES_CNT: smp_opt_dir = SMP_OPT_DIR_RES;
break;
+ case ACT_F_HTTP_REQ: smp_opt_dir = SMP_OPT_DIR_REQ;
break;
+ case ACT_F_HTTP_RES: smp_opt_dir = SMP_OPT_DIR_RES;
break;
+ default:
+ send_log(px, LOG_ERR, "stick table: internal
error while setting gpt0.");
+ if (!(global.mode & MODE_QUIET) || (global.mode
& MODE_VERBOSE))
+ ha_alert("stick table: internal error
while executing setting gpt0.\n");
+ return ACT_RET_CONT;
+ }
+
+ /* Fetch and cast the expression. */
+ smp = sample_fetch_as_type(px, sess, s,
smp_opt_dir|SMP_OPT_FINAL, rule->arg.gpt.expr, SMP_T_SINT);
+ if (!smp) {
+ send_log(px, LOG_WARNING, "stick table: invalid
expression or data type while setting gpt0.");
+ if (!(global.mode & MODE_QUIET) || (global.mode
& MODE_VERBOSE))
+ ha_alert("stick table: invalid
expression or data type while setting gpt0.\n");
+ return ACT_RET_CONT;
+ }
+ value = (unsigned int)(smp->data.u.sint);
+ }
+
HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
- stktable_data_cast(ptr, gpt0) = rule->arg.gpt.value;
+ stktable_data_cast(ptr, gpt0) = value;
HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
@@ -2058,6 +2088,7 @@ static enum act_parse_ret parse_set_gpt0(const char
**args, int *arg, struct pro
{
const char *cmd_name = args[*arg-1];
char *error;
+ int smp_val;
cmd_name += strlen("sc-set-gpt0");
if (*cmd_name == '\0') {
@@ -2083,10 +2114,30 @@ static enum act_parse_ret parse_set_gpt0(const char
**args, int *arg, struct pro
}
}
+ rule->arg.gpt.expr = NULL;
rule->arg.gpt.value = strtol(args[*arg], &error, 10);
if (*error != '\0') {
- memprintf(err, "invalid integer value '%s'", args[*arg]);
- return ACT_RET_PRS_ERR;
+ rule->arg.gpt.expr = sample_parse_expr((char **)args, arg,
px->conf.args.file,
+ px->conf.args.line, err,
&px->conf.args);
+ if (!rule->arg.gpt.expr)
+ return ACT_RET_PRS_ERR;
+
+ switch (rule->from) {
+ case ACT_F_TCP_REQ_SES: smp_val = SMP_VAL_FE_SES_ACC; break;
+ case ACT_F_TCP_REQ_CNT: smp_val = SMP_VAL_FE_REQ_CNT; break;
+ case ACT_F_TCP_RES_CNT: smp_val = SMP_VAL_BE_RES_CNT; break;
+ case ACT_F_HTTP_REQ: smp_val = SMP_VAL_FE_HRQ_HDR; break;
+ case ACT_F_HTTP_RES: smp_val = SMP_VAL_BE_HRS_HDR; break;
+ default:
+ memprintf(err, "internal error, unexpected
rule->from=%d, please report this bug!", rule->from);
+ return ACT_RET_PRS_ERR;
+ }
+ if (!(rule->arg.gpt.expr->fetch->val & smp_val)) {
+ memprintf(err, "fetch method '%s' extracts information
from '%s', none of which is available here", args[*arg-1],
+
sample_src_names(rule->arg.gpt.expr->fetch->use));
+ free(rule->arg.gpt.expr);
+ return ACT_RET_PRS_ERR;
+ }
}
(*arg)++;
--
2.20.1