MEDIUM: vars/sample: operators can use variables as parameter

This patch allow the existing operators to take a variable as parameter.
This is useful to add the content of two variables. This patch modify
the behavior of operators.
This commit is contained in:
Thierry FOURNIER 2015-07-07 21:10:16 +02:00 committed by Willy Tarreau
parent fd77e05f65
commit 5d86fae234
2 changed files with 217 additions and 54 deletions

View File

@ -11031,11 +11031,29 @@ The currently available list of transformation keywords include :
add(<value>) add(<value>)
Adds <value> to the input value of type signed integer, and returns the Adds <value> to the input value of type signed integer, and returns the
result as a signed integer. result as a signed integer. <value> can be a numeric value or a variable
name. The name of the variable starts by an indication about its scope. The
allowed scopes are:
"sess" : the variable is shared with all the session,
"txn" : the variable is shared with all the transaction (request and
response),
"req" : the variable is shared only during the request processing,
"res" : the variable is shared only during the response processing.
This prefix is followed by a name. The separator is a '.'. The name may only
contain characters 'a-z', 'A-Z', '0-9' and '_'.
and(<value>) and(<value>)
Performs a bitwise "AND" between <value> and the input value of type signed Performs a bitwise "AND" between <value> and the input value of type signed
integer, and returns the result as an signed integer. integer, and returns the result as an signed integer. <value> can be a
numeric value or a variable name. The name of the variable starts by an
indication about its scope. The allowed scopes are:
"sess" : the variable is shared with all the session,
"txn" : the variable is shared with all the transaction (request and
response),
"req" : the variable is shared only during the request processing,
"res" : the variable is shared only during the response processing.
This prefix is followed by a name. The separator is a '.'. The name may only
contain characters 'a-z', 'A-Z', '0-9' and '_'.
base64 base64
Converts a binary input sample to a base64 string. It is used to log or Converts a binary input sample to a base64 string. It is used to log or
@ -11092,7 +11110,16 @@ debug
div(<value>) div(<value>)
Divides the input value of type signed integer by <value>, and returns the Divides the input value of type signed integer by <value>, and returns the
result as an signed integer. If <value> is null, the largest unsigned result as an signed integer. If <value> is null, the largest unsigned
integer is returned (typically 2^63-1). integer is returned (typically 2^63-1). <value> can be a numeric value or a
variable name. The name of the variable starts by an indication about it
scope. The scope allowed are:
"sess" : the variable is shared with all the session,
"txn" : the variable is shared with all the transaction (request and
response),
"req" : the variable is shared only during the request processing,
"res" : the variable is shared only during the response processing.
This prefix is followed by a name. The separator is a '.'. The name may only
contain characters 'a-z', 'A-Z', '0-9' and '_'.
djb2([<avalanche>]) djb2([<avalanche>])
Hashes a binary input sample into an unsigned 32-bit quantity using the DJB2 Hashes a binary input sample into an unsigned 32-bit quantity using the DJB2
@ -11287,11 +11314,29 @@ map_<match_type>_<output_type>(<map_file>[,<default_value>])
mod(<value>) mod(<value>)
Divides the input value of type signed integer by <value>, and returns the Divides the input value of type signed integer by <value>, and returns the
remainder as an signed integer. If <value> is null, then zero is returned. remainder as an signed integer. If <value> is null, then zero is returned.
<value> can be a numeric value or a variable name. The name of the variable
starts by an indication about its scope. The allowed scopes are:
"sess" : the variable is shared with all the session,
"txn" : the variable is shared with all the transaction (request and
response),
"req" : the variable is shared only during the request processing,
"res" : the variable is shared only during the response processing.
This prefix is followed by a name. The separator is a '.'. The name may only
contain characters 'a-z', 'A-Z', '0-9' and '_'.
mul(<value>) mul(<value>)
Multiplies the input value of type signed integer by <value>, and returns Multiplies the input value of type signed integer by <value>, and returns
the product as an signed integer. In case of overflow, the largest possible the product as an signed integer. In case of overflow, the largest possible
value for the sign is returned so that the operation doesn't wrap around. value for the sign is returned so that the operation doesn't wrap around.
<value> can be a numeric value or a variable name. The name of the variable
starts by an indication about its scope. The allowed scopes are:
"sess" : the variable is shared with all the session,
"txn" : the variable is shared with all the transaction (request and
response),
"req" : the variable is shared only during the request processing,
"res" : the variable is shared only during the response processing.
This prefix is followed by a name. The separator is a '.'. The name may only
contain characters 'a-z', 'A-Z', '0-9' and '_'.
neg neg
Takes the input value of type signed integer, computes the opposite value, Takes the input value of type signed integer, computes the opposite value,
@ -11311,7 +11356,16 @@ odd
or(<value>) or(<value>)
Performs a bitwise "OR" between <value> and the input value of type signed Performs a bitwise "OR" between <value> and the input value of type signed
integer, and returns the result as an signed integer. integer, and returns the result as an signed integer. <value> can be a
numeric value or a variable name. The name of the variable starts by an
indication about its scope. The allowed scopes are:
"sess" : the variable is shared with all the session,
"txn" : the variable is shared with all the transaction (request and
response),
"req" : the variable is shared only during the request processing,
"res" : the variable is shared only during the response processing.
This prefix is followed by a name. The separator is a '.'. The name may only
contain characters 'a-z', 'A-Z', '0-9' and '_'.
regsub(<regex>,<subst>[,<flags>]) regsub(<regex>,<subst>[,<flags>])
Applies a regex-based substitution to the input string. It does the same Applies a regex-based substitution to the input string. It does the same
@ -11377,7 +11431,16 @@ set-var(<var name>)
sub(<value>) sub(<value>)
Subtracts <value> from the input value of type signed integer, and returns Subtracts <value> from the input value of type signed integer, and returns
the result as an signed integer. Note: in order to subtract the input from the result as an signed integer. Note: in order to subtract the input from
a constant, simply perform a "neg,add(value)". a constant, simply perform a "neg,add(value)". <value> can be a numeric value
or a variable name. The name of the variable starts by an indication about its
scope. The allowed scopes are:
"sess" : the variable is shared with all the session,
"txn" : the variable is shared with all the transaction (request and
response),
"req" : the variable is shared only during the request processing,
"res" : the variable is shared only during the response processing.
This prefix is followed by a name. The separator is a '.'. The name may only
contain characters 'a-z', 'A-Z', '0-9' and '_'.
table_bytes_in_rate(<table>) table_bytes_in_rate(<table>)
Uses the string representation of the input sample to perform a look up in Uses the string representation of the input sample to perform a look up in
@ -11559,6 +11622,15 @@ wt6([<avalanche>])
xor(<value>) xor(<value>)
Performs a bitwise "XOR" (exclusive OR) between <value> and the input value Performs a bitwise "XOR" (exclusive OR) between <value> and the input value
of type signed integer, and returns the result as an signed integer. of type signed integer, and returns the result as an signed integer.
<value> can be a numeric value or a variable name. The name of the variable
starts by an indication about its scope. The allowed scopes are:
"sess" : the variable is shared with all the session,
"txn" : the variable is shared with all the transaction (request and
response),
"req" : the variable is shared only during the request processing,
"res" : the variable is shared only during the response processing.
This prefix is followed by a name. The separator is a '.'. The name may only
contain characters 'a-z', 'A-Z', '0-9' and '_'.
7.3.2. Fetching samples from internal states 7.3.2. Fetching samples from internal states

View File

@ -31,6 +31,7 @@
#include <proto/proxy.h> #include <proto/proxy.h>
#include <proto/sample.h> #include <proto/sample.h>
#include <proto/stick_table.h> #include <proto/stick_table.h>
#include <proto/vars.h>
/* sample type names */ /* sample type names */
const char *smp_to_type[SMP_TYPES] = { const char *smp_to_type[SMP_TYPES] = {
@ -2017,6 +2018,58 @@ static int sample_conv_regsub(const struct arg *arg_p, struct sample *smp, void
return 1; return 1;
} }
/* This function check an operator entry. It expects a string.
* The string can be an integer or a variable name.
*/
static int check_operator(struct arg *args, struct sample_conv *conv,
const char *file, int line, char **err)
{
const char *str;
const char *end;
/* Try to decode a variable. */
if (vars_check_arg(&args[0], NULL))
return 1;
/* Try to convert an integer */
str = args[0].data.str.str;
end = str + strlen(str);
args[0].data.sint = read_int64(&str, end);
if (*str != '\0') {
memprintf(err, "expects an integer or a variable name");
return 0;
}
args[0].type = ARGT_SINT;
return 1;
}
/* This fucntion returns a sample struct filled with a arg content.
* If the arg contain an integer, the integer is returned in the
* sample. If the arg contains a variable descriptor, it returns the
* variable value.
*
* This function returns 0 if an error occurs, otherwise it returns 1.
*/
static inline int sample_conv_var2smp(const struct arg *arg, struct stream *strm, struct sample *smp)
{
switch (arg->type) {
case ARGT_SINT:
smp->type = SMP_T_SINT;
smp->data.sint = arg->data.sint;
return 1;
case ARGT_VAR:
if (!vars_get_by_desc(&arg->data.var, strm, smp))
return 0;
if (!sample_casts[smp->type][SMP_T_SINT])
return 0;
if (!sample_casts[smp->type][SMP_T_SINT](smp))
return 0;
return 1;
default:
return 0;
}
}
/* Takes a SINT on input, applies a binary twos complement and returns the SINT /* Takes a SINT on input, applies a binary twos complement and returns the SINT
* result. * result.
*/ */
@ -2026,30 +2079,42 @@ static int sample_conv_binary_cpl(const struct arg *arg_p, struct sample *smp, v
return 1; return 1;
} }
/* Takes a SINT on input, applies a binary "and" with the UINT in arg_p, and /* Takes a SINT on input, applies a binary "and" with the SINT directly in
* returns the SINT result. * arg_p or in the varaible described in arg_p, and returns the SINT result.
*/ */
static int sample_conv_binary_and(const struct arg *arg_p, struct sample *smp, void *private) static int sample_conv_binary_and(const struct arg *arg_p, struct sample *smp, void *private)
{ {
smp->data.sint &= arg_p->data.sint; struct sample tmp;
if (!sample_conv_var2smp(arg_p, smp->strm, &tmp))
return 0;
smp->data.sint &= tmp.data.sint;
return 1; return 1;
} }
/* Takes a SINT on input, applies a binary "or" with the UINT in arg_p, and /* Takes a SINT on input, applies a binary "or" with the SINT directly in
* returns the SINT result. * arg_p or in the varaible described in arg_p, and returns the SINT result.
*/ */
static int sample_conv_binary_or(const struct arg *arg_p, struct sample *smp, void *private) static int sample_conv_binary_or(const struct arg *arg_p, struct sample *smp, void *private)
{ {
smp->data.sint |= arg_p->data.sint; struct sample tmp;
if (!sample_conv_var2smp(arg_p, smp->strm, &tmp))
return 0;
smp->data.sint |= tmp.data.sint;
return 1; return 1;
} }
/* Takes a SINT on input, applies a binary "xor" with the UINT in arg_p, and /* Takes a SINT on input, applies a binary "xor" with the SINT directly in
* returns the SINT result. * arg_p or in the varaible described in arg_p, and returns the SINT result.
*/ */
static int sample_conv_binary_xor(const struct arg *arg_p, struct sample *smp, void *private) static int sample_conv_binary_xor(const struct arg *arg_p, struct sample *smp, void *private)
{ {
smp->data.sint ^= arg_p->data.sint; struct sample tmp;
if (!sample_conv_var2smp(arg_p, smp->strm, &tmp))
return 0;
smp->data.sint ^= tmp.data.sint;
return 1; return 1;
} }
@ -2079,26 +2144,35 @@ static inline long long int arith_add(long long int a, long long int b)
return a + b; return a + b;
} }
/* Takes a SINT on input, applies an arithmetic "add" with the UINT in arg_p, /* Takes a SINT on input, applies an arithmetic "add" with the SINT directly in
* and returns the SINT result. * arg_p or in the varaible described in arg_p, and returns the SINT result.
*/ */
static int sample_conv_arith_add(const struct arg *arg_p, struct sample *smp, void *private) static int sample_conv_arith_add(const struct arg *arg_p, struct sample *smp, void *private)
{ {
smp->data.sint = arith_add(smp->data.sint, arg_p->data.sint); struct sample tmp;
if (!sample_conv_var2smp(arg_p, smp->strm, &tmp))
return 0;
smp->data.sint = arith_add(smp->data.sint, tmp.data.sint);
return 1; return 1;
} }
/* Takes a SINT on input, applies an arithmetic "sub" with the UINT in arg_p, /* Takes a SINT on input, applies an arithmetic "sub" with the SINT directly in
* and returns the SINT result. * arg_p or in the varaible described in arg_p, and returns the SINT result.
*/ */
static int sample_conv_arith_sub(const struct arg *arg_p, static int sample_conv_arith_sub(const struct arg *arg_p,
struct sample *smp, void *private) struct sample *smp, void *private)
{ {
struct sample tmp;
if (!sample_conv_var2smp(arg_p, smp->strm, &tmp))
return 0;
/* We cannot represent -LLONG_MIN because abs(LLONG_MIN) is greater /* We cannot represent -LLONG_MIN because abs(LLONG_MIN) is greater
* than abs(LLONG_MAX). So, the following code use LLONG_MAX in place * than abs(LLONG_MAX). So, the following code use LLONG_MAX in place
* of -LLONG_MIN and correct the result. * of -LLONG_MIN and correct the result.
*/ */
if (arg_p->data.sint == LLONG_MIN) { if (tmp.data.sint == LLONG_MIN) {
smp->data.sint = arith_add(smp->data.sint, LLONG_MAX); smp->data.sint = arith_add(smp->data.sint, LLONG_MAX);
if (smp->data.sint < LLONG_MAX) if (smp->data.sint < LLONG_MAX)
smp->data.sint++; smp->data.sint++;
@ -2108,20 +2182,26 @@ static int sample_conv_arith_sub(const struct arg *arg_p,
/* standard substraction: we use the "add" function and negate /* standard substraction: we use the "add" function and negate
* the second operand. * the second operand.
*/ */
smp->data.sint = arith_add(smp->data.sint, -arg_p->data.sint); smp->data.sint = arith_add(smp->data.sint, -tmp.data.sint);
return 1; return 1;
} }
/* Takes a SINT on input, applies an arithmetic "mul" with the UINT in arg_p, /* Takes a SINT on input, applies an arithmetic "mul" with the SINT directly in
* and returns the SINT result. * arg_p or in the varaible described in arg_p, and returns the SINT result.
* If the result makes an overflow, then the largest possible quantity is
* returned.
*/ */
static int sample_conv_arith_mul(const struct arg *arg_p, static int sample_conv_arith_mul(const struct arg *arg_p,
struct sample *smp, void *private) struct sample *smp, void *private)
{ {
struct sample tmp;
long long int c; long long int c;
if (!sample_conv_var2smp(arg_p, smp->strm, &tmp))
return 0;
/* prevent divide by 0 during the check */ /* prevent divide by 0 during the check */
if (!smp->data.sint || !arg_p->data.sint) { if (!smp->data.sint || !tmp.data.sint) {
smp->data.sint = 0; smp->data.sint = 0;
return 1; return 1;
} }
@ -2129,17 +2209,17 @@ static int sample_conv_arith_mul(const struct arg *arg_p,
/* The multiply between LLONG_MIN and -1 returns a /* The multiply between LLONG_MIN and -1 returns a
* "floting point exception". * "floting point exception".
*/ */
if (smp->data.sint == LLONG_MIN && arg_p->data.sint == -1) { if (smp->data.sint == LLONG_MIN && tmp.data.sint == -1) {
smp->data.sint = LLONG_MAX; smp->data.sint = LLONG_MAX;
return 1; return 1;
} }
/* execute standard multiplication. */ /* execute standard multiplication. */
c = smp->data.sint * arg_p->data.sint; c = smp->data.sint * tmp.data.sint;
/* check for overflow and makes capped multiply. */ /* check for overflow and makes capped multiply. */
if (smp->data.sint != c / arg_p->data.sint) { if (smp->data.sint != c / tmp.data.sint) {
if ((smp->data.sint < 0) == (arg_p->data.sint < 0)) { if ((smp->data.sint < 0) == (tmp.data.sint < 0)) {
smp->data.sint = LLONG_MAX; smp->data.sint = LLONG_MAX;
return 1; return 1;
} }
@ -2150,44 +2230,55 @@ static int sample_conv_arith_mul(const struct arg *arg_p,
return 1; return 1;
} }
/* Takes a SINT on input, applies an arithmetic "div" with the SINT in arg_p, /* Takes a SINT on input, applies an arithmetic "div" with the SINT directly in
* and returns the SINT result. If arg_p makes the result overflow, then the * arg_p or in the varaible described in arg_p, and returns the SINT result.
* largest possible quantity is returned. * If arg_p makes the result overflow, then the largest possible quantity is
* returned.
*/ */
static int sample_conv_arith_div(const struct arg *arg_p, static int sample_conv_arith_div(const struct arg *arg_p,
struct sample *smp, void *private) struct sample *smp, void *private)
{ {
if (arg_p->data.sint) { struct sample tmp;
if (!sample_conv_var2smp(arg_p, smp->strm, &tmp))
return 0;
if (tmp.data.sint) {
/* The divide between LLONG_MIN and -1 returns a /* The divide between LLONG_MIN and -1 returns a
* "floting point exception". * "floting point exception".
*/ */
if (smp->data.sint == LLONG_MIN && arg_p->data.sint == -1) { if (smp->data.sint == LLONG_MIN && tmp.data.sint == -1) {
smp->data.sint = LLONG_MAX; smp->data.sint = LLONG_MAX;
return 1; return 1;
} }
smp->data.sint /= arg_p->data.sint; smp->data.sint /= tmp.data.sint;
return 1; return 1;
} }
smp->data.sint = LLONG_MAX; smp->data.sint = LLONG_MAX;
return 1; return 1;
} }
/* Takes a SINT on input, applies an arithmetic "mod" with the SINT in arg_p, /* Takes a SINT on input, applies an arithmetic "mod" with the SINT directly in
* and returns the SINT result. If arg_p makes the result overflow, then zero * arg_p or in the varaible described in arg_p, and returns the SINT result.
* is returned. * If arg_p makes the result overflow, then 0 is returned.
*/ */
static int sample_conv_arith_mod(const struct arg *arg_p, static int sample_conv_arith_mod(const struct arg *arg_p,
struct sample *smp, void *private) struct sample *smp, void *private)
{ {
if (arg_p->data.sint) { struct sample tmp;
if (!sample_conv_var2smp(arg_p, smp->strm, &tmp))
return 0;
if (tmp.data.sint) {
/* The divide between LLONG_MIN and -1 returns a /* The divide between LLONG_MIN and -1 returns a
* "floting point exception". * "floting point exception".
*/ */
if (smp->data.sint == LLONG_MIN && arg_p->data.sint == -1) { if (smp->data.sint == LLONG_MIN && tmp.data.sint == -1) {
smp->data.sint = 0; smp->data.sint = 0;
return 1; return 1;
} }
smp->data.sint %= arg_p->data.sint; smp->data.sint %= tmp.data.sint;
return 1; return 1;
} }
smp->data.sint = 0; smp->data.sint = 0;
@ -2522,19 +2613,19 @@ static struct sample_conv_kw_list sample_conv_kws = {ILH, {
{ "word", sample_conv_word, ARG2(2,SINT,STR), sample_conv_field_check, SMP_T_STR, SMP_T_STR }, { "word", sample_conv_word, ARG2(2,SINT,STR), sample_conv_field_check, SMP_T_STR, SMP_T_STR },
{ "regsub", sample_conv_regsub, ARG3(2,REG,STR,STR), sample_conv_regsub_check, SMP_T_STR, SMP_T_STR }, { "regsub", sample_conv_regsub, ARG3(2,REG,STR,STR), sample_conv_regsub_check, SMP_T_STR, SMP_T_STR },
{ "and", sample_conv_binary_and, ARG1(1,SINT), NULL, SMP_T_SINT, SMP_T_SINT }, { "and", sample_conv_binary_and, ARG1(1,STR), check_operator, SMP_T_SINT, SMP_T_SINT },
{ "or", sample_conv_binary_or, ARG1(1,SINT), NULL, SMP_T_SINT, SMP_T_SINT }, { "or", sample_conv_binary_or, ARG1(1,STR), check_operator, SMP_T_SINT, SMP_T_SINT },
{ "xor", sample_conv_binary_xor, ARG1(1,SINT), NULL, SMP_T_SINT, SMP_T_SINT }, { "xor", sample_conv_binary_xor, ARG1(1,STR), check_operator, SMP_T_SINT, SMP_T_SINT },
{ "cpl", sample_conv_binary_cpl, 0, NULL, SMP_T_SINT, SMP_T_SINT }, { "cpl", sample_conv_binary_cpl, 0, NULL, SMP_T_SINT, SMP_T_SINT },
{ "bool", sample_conv_arith_bool, 0, NULL, SMP_T_SINT, SMP_T_BOOL }, { "bool", sample_conv_arith_bool, 0, NULL, SMP_T_SINT, SMP_T_BOOL },
{ "not", sample_conv_arith_not, 0, NULL, SMP_T_SINT, SMP_T_BOOL }, { "not", sample_conv_arith_not, 0, NULL, SMP_T_SINT, SMP_T_BOOL },
{ "odd", sample_conv_arith_odd, 0, NULL, SMP_T_SINT, SMP_T_BOOL }, { "odd", sample_conv_arith_odd, 0, NULL, SMP_T_SINT, SMP_T_BOOL },
{ "even", sample_conv_arith_even, 0, NULL, SMP_T_SINT, SMP_T_BOOL }, { "even", sample_conv_arith_even, 0, NULL, SMP_T_SINT, SMP_T_BOOL },
{ "add", sample_conv_arith_add, ARG1(1,SINT), NULL, SMP_T_SINT, SMP_T_SINT }, { "add", sample_conv_arith_add, ARG1(1,STR), check_operator, SMP_T_SINT, SMP_T_SINT },
{ "sub", sample_conv_arith_sub, ARG1(1,SINT), NULL, SMP_T_SINT, SMP_T_SINT }, { "sub", sample_conv_arith_sub, ARG1(1,STR), check_operator, SMP_T_SINT, SMP_T_SINT },
{ "mul", sample_conv_arith_mul, ARG1(1,SINT), NULL, SMP_T_SINT, SMP_T_SINT }, { "mul", sample_conv_arith_mul, ARG1(1,STR), check_operator, SMP_T_SINT, SMP_T_SINT },
{ "div", sample_conv_arith_div, ARG1(1,SINT), NULL, SMP_T_SINT, SMP_T_SINT }, { "div", sample_conv_arith_div, ARG1(1,STR), check_operator, SMP_T_SINT, SMP_T_SINT },
{ "mod", sample_conv_arith_mod, ARG1(1,SINT), NULL, SMP_T_SINT, SMP_T_SINT }, { "mod", sample_conv_arith_mod, ARG1(1,STR), check_operator, SMP_T_SINT, SMP_T_SINT },
{ "neg", sample_conv_arith_neg, 0, NULL, SMP_T_SINT, SMP_T_SINT }, { "neg", sample_conv_arith_neg, 0, NULL, SMP_T_SINT, SMP_T_SINT },
{ NULL, NULL, 0, 0, 0 }, { NULL, NULL, 0, 0, 0 },