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>)
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>)
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
Converts a binary input sample to a base64 string. It is used to log or
@ -11092,7 +11110,16 @@ debug
div(<value>)
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
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>])
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>)
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.
<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>)
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
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
Takes the input value of type signed integer, computes the opposite value,
@ -11311,7 +11356,16 @@ odd
or(<value>)
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>])
Applies a regex-based substitution to the input string. It does the same
@ -11377,7 +11431,16 @@ set-var(<var name>)
sub(<value>)
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
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>)
Uses the string representation of the input sample to perform a look up in
@ -11559,6 +11622,15 @@ wt6([<avalanche>])
xor(<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.
<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

View File

@ -31,6 +31,7 @@
#include <proto/proxy.h>
#include <proto/sample.h>
#include <proto/stick_table.h>
#include <proto/vars.h>
/* sample type names */
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;
}
/* 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
* result.
*/
@ -2026,30 +2079,42 @@ static int sample_conv_binary_cpl(const struct arg *arg_p, struct sample *smp, v
return 1;
}
/* Takes a SINT on input, applies a binary "and" with the UINT in arg_p, and
* returns the SINT result.
/* Takes a SINT on input, applies a binary "and" with the SINT directly in
* 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)
{
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;
}
/* Takes a SINT on input, applies a binary "or" with the UINT in arg_p, and
* returns the SINT result.
/* Takes a SINT on input, applies a binary "or" with the SINT directly in
* 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)
{
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;
}
/* Takes a SINT on input, applies a binary "xor" with the UINT in arg_p, and
* returns the SINT result.
/* Takes a SINT on input, applies a binary "xor" with the SINT directly in
* 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)
{
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;
}
@ -2079,26 +2144,35 @@ static inline long long int arith_add(long long int a, long long int b)
return a + b;
}
/* Takes a SINT on input, applies an arithmetic "add" with the UINT in arg_p,
* and returns the SINT result.
/* Takes a SINT on input, applies an arithmetic "add" with the SINT directly in
* 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)
{
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;
}
/* Takes a SINT on input, applies an arithmetic "sub" with the UINT in arg_p,
* and returns the SINT result.
/* Takes a SINT on input, applies an arithmetic "sub" with the SINT directly in
* 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,
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
* than abs(LLONG_MAX). So, the following code use LLONG_MAX in place
* 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);
if (smp->data.sint < LLONG_MAX)
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
* 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;
}
/* Takes a SINT on input, applies an arithmetic "mul" with the UINT in arg_p,
* and returns the SINT result.
/* Takes a SINT on input, applies an arithmetic "mul" with the SINT directly in
* 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,
struct sample *smp, void *private)
{
struct sample tmp;
long long int c;
if (!sample_conv_var2smp(arg_p, smp->strm, &tmp))
return 0;
/* 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;
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
* "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;
return 1;
}
/* 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. */
if (smp->data.sint != c / arg_p->data.sint) {
if ((smp->data.sint < 0) == (arg_p->data.sint < 0)) {
if (smp->data.sint != c / tmp.data.sint) {
if ((smp->data.sint < 0) == (tmp.data.sint < 0)) {
smp->data.sint = LLONG_MAX;
return 1;
}
@ -2150,44 +2230,55 @@ static int sample_conv_arith_mul(const struct arg *arg_p,
return 1;
}
/* Takes a SINT on input, applies an arithmetic "div" with the SINT in arg_p,
* and returns the SINT result. If arg_p makes the result overflow, then the
* largest possible quantity is returned.
/* Takes a SINT on input, applies an arithmetic "div" with the SINT directly in
* arg_p or in the varaible described in arg_p, and returns the SINT result.
* 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,
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
* "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;
return 1;
}
smp->data.sint /= arg_p->data.sint;
smp->data.sint /= tmp.data.sint;
return 1;
}
smp->data.sint = LLONG_MAX;
return 1;
}
/* Takes a SINT on input, applies an arithmetic "mod" with the SINT in arg_p,
* and returns the SINT result. If arg_p makes the result overflow, then zero
* is returned.
/* Takes a SINT on input, applies an arithmetic "mod" with the SINT directly in
* arg_p or in the varaible described in arg_p, and returns the SINT result.
* If arg_p makes the result overflow, then 0 is returned.
*/
static int sample_conv_arith_mod(const struct arg *arg_p,
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
* "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;
return 1;
}
smp->data.sint %= arg_p->data.sint;
smp->data.sint %= tmp.data.sint;
return 1;
}
smp->data.sint = 0;
@ -2522,20 +2613,20 @@ 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 },
{ "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 },
{ "or", sample_conv_binary_or, ARG1(1,SINT), NULL, SMP_T_SINT, SMP_T_SINT },
{ "xor", sample_conv_binary_xor, ARG1(1,SINT), 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 },
{ "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 },
{ "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 },
{ "sub", sample_conv_arith_sub, ARG1(1,SINT), NULL, SMP_T_SINT, SMP_T_SINT },
{ "mul", sample_conv_arith_mul, ARG1(1,SINT), NULL, SMP_T_SINT, SMP_T_SINT },
{ "div", sample_conv_arith_div, ARG1(1,SINT), NULL, SMP_T_SINT, SMP_T_SINT },
{ "mod", sample_conv_arith_mod, ARG1(1,SINT), NULL, SMP_T_SINT, SMP_T_SINT },
{ "neg", sample_conv_arith_neg, 0, 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,STR), check_operator, 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 },
{ "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 },
{ "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 },
{ "add", sample_conv_arith_add, ARG1(1,STR), check_operator, 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,STR), check_operator, 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,STR), check_operator, SMP_T_SINT, SMP_T_SINT },
{ "neg", sample_conv_arith_neg, 0, NULL, SMP_T_SINT, SMP_T_SINT },
{ NULL, NULL, 0, 0, 0 },
}};