diff --git a/doc/configuration.txt b/doc/configuration.txt index f0481a72e..9736b0799 100644 --- a/doc/configuration.txt +++ b/doc/configuration.txt @@ -6409,6 +6409,17 @@ http-request return [status ] [content-type ] lf-string "Access denied. IP %[src] is blacklisted." \ if { src -f /etc/haproxy/blacklist.lst } +http-request sc-inc-gpc(,) [ { if | unless } ] + + This actions increments the General Purpose Counter at the index + of the array associated to the sticky counter designated by . + If an error occurs, this action silently fails and the actions evaluation + continues. is an integer between 0 and 99 and is an integer + between 0 and 2. It also silently fails if the there is no GPC stored + at this index. + This action applies only to the 'gpc' and 'gpc_rate' array data_types (and + not to the legacy 'gpc0', 'gpc1', 'gpc0_rate' nor 'gpc1_rate' data_types). + http-request sc-inc-gpc0() [ { if | unless } ] http-request sc-inc-gpc1() [ { if | unless } ] @@ -7120,6 +7131,17 @@ http-response return [status ] [content-type ] string "This is the end !" \ if { status eq 500 } +http-response sc-inc-gpc(,) [ { if | unless } ] + + This actions increments the General Purpose Counter at the index + of the array associated to the sticky counter designated by . + If an error occurs, this action silently fails and the actions evaluation + continues. is an integer between 0 and 99 and is an integer + between 0 and 2. It also silently fails if the there is no GPC stored + at this index. + This action applies only to the 'gpc' and 'gpc_rate' array data_types (and + not to the legacy 'gpc0', 'gpc1', 'gpc0_rate' nor 'gpc1_rate' data_types). + http-response sc-inc-gpc0() [ { if | unless } ] http-response sc-inc-gpc1() [ { if | unless } ] @@ -11183,6 +11205,30 @@ stick-table type {ip | integer | string [len ] | binary [len ]} request was assigned to. It is used by the "stick match", "stick store", and "stick on" rules. It is automatically enabled when referenced. + - gpc() : General Purpose Counters Array of elements. This is an + array of positive 32-bit integers which may be used to count anything. + Most of the time they will be used as a incremental counters on some + entries, for instance to note that a limit is reached and trigger some + actions. This array is limited to a maximum of 100 elements: + gpc0 to gpc99, to ensure that the build of a peer update + message can fit into the buffer. Users should take in consideration + that a large amount of counters will increase the data size and the + traffic load using peers protocol since all data/counters are pushed + each time any of them is updated. + + - gpc_rate(,) : Array of increment rates of General Purpose + Counters over a period. Those elements are positive 32-bit integers which + may be used for anything. Just like , the count events, but instead + of keeping a cumulative number, they maintain the rate at which the + counter is incremented. Most of the time it will be used to measure the + frequency of occurrence of certain events (e.g. requests to a specific + URL). This array is limited to a maximum of 100 elements: gpc0 to gpc99, + to ensure that the build of a peer update message can fit into the + buffer. Users should take in consideration that a large amount of + counters will increase the data size and the traffic load using peers + protocol since all data/counters are pushed each time any of them is + updated. + - gpc0 : first General Purpose Counter. It is a positive 32-bit integer integer which may be used for anything. Most of the time it will be used to put a special tag on some entries, for instance to note that a @@ -11930,6 +11976,17 @@ tcp-request connection [{if | unless} ] advantage over just checking the keys, because only one table lookup is performed for all ACL checks that make use of it. + - sc-inc-gpc(,): + This actions increments the General Purpose Counter at the index + of the array associated to the sticky counter designated by . + If an error occurs, this action silently fails and the actions + evaluation continues. is an integer between 0 and 99 and + is an integer between 0 and 2. It also silently fails if the there is + no GPC stored at this index. + This action applies only to the 'gpc' and 'gpc_rate' array data_types + (and not to the legacy 'gpc0', 'gpc1', 'gpc0_rate' nor 'gpc1_rate' + data_types). + - sc-inc-gpc0(): The "sc-inc-gpc0" increments the GPC0 counter according to the sticky counter designated by . If an error occurs, this action silently @@ -12133,6 +12190,7 @@ tcp-request content [{if | unless} ] - capture : the specified sample expression is captured - set-priority-class | set-priority-offset - { track-sc0 | track-sc1 | track-sc2 } [table ] + - sc-inc-gpc(,) - sc-inc-gpc0() - sc-inc-gpc1() - sc-set-gpt(,) { | } @@ -12475,6 +12533,17 @@ tcp-response content [{if | unless} ] - unset-var() Unsets a variable. + - sc-inc-gpc(,): + This actions increments the General Purpose Counter at the index + of the array associated to the sticky counter designated by . + If an error occurs, this action silently fails and the actions + evaluation continues. is an integer between 0 and 99 and + is an integer between 0 and 2. It also silently fails if the there is + no GPC stored at this index. + This action applies only to the 'gpc' and 'gpc_rate' array data_types + (and not to the legacy 'gpc0', 'gpc1', 'gpc0_rate' nor 'gpc1_rate' + data_types). + - sc-inc-gpc0(): This action increments the GPC0 counter according to the sticky counter designated by . If an error occurs, this action fails @@ -12619,6 +12688,7 @@ tcp-request session [{if | unless} ] - accept : the request is accepted - reject : the request is rejected and the connection is closed - { track-sc0 | track-sc1 | track-sc2 } [table
] + - sc-inc-gpc(,) - sc-inc-gpc0() - sc-inc-gpc1() - sc-set-gpt(,) { | } @@ -16783,6 +16853,31 @@ table_gpt0(
) general purpose tag associated with the input sample in the designated table. See also the sc_get_gpt0 sample fetch keyword. +table_gpc(,
) + Uses the string representation of the input sample to perform a lookup in + the specified table. If the key is not found in the table, integer value zero + is returned. Otherwise the converter returns the current value of the + General Purpose Counter at the index of the array associated + to the input sample in the designated
. is an integer + between 0 and 99. + If there is no GPC stored at this index, it also returns the boolean value 0. + This applies only to the 'gpc' array data_type (and not to the legacy + 'gpc0' nor 'gpc1' data_types). + See also the sc_get_gpc sample fetch keyword. + +table_gpc_rate(,
) + Uses the string representation of the input sample to perform a lookup in + the specified table. If the key is not found in the table, integer value zero + is returned. Otherwise the converter returns the frequency which the Global + Purpose Counter at index of the array (associated to the input sample + in the designated stick-table
) was incremented over the + configured period. is an integer between 0 and 99. + If there is no gpc_rate stored at this index, it also returns the boolean + value 0. + This applies only to the 'gpc_rate' array data_type (and not to the + legacy 'gpc0_rate' nor 'gpc1_rate' data_types). + See also the sc_gpc_rate sample fetch keyword. + table_gpc0(
) Uses the string representation of the input sample to perform a look up in the specified table. If the key is not found in the table, integer value zero @@ -17761,6 +17856,17 @@ sc2_bytes_out_rate([
]) : integer counters, measured in amount of bytes over the period configured in the table. See also src_bytes_out_rate. +sc_clr_gpc(,[,
]) : integer + Clears the General Purpose Counter at the index of the array + associated to the designated tracked counter of ID from current + proxy's stick table or from the designated stick-table
, and + returns its previous value. is an integer between 0 and 99 and + an integer between 0 and 2. + Before the first invocation, the stored value is zero, so first invocation + will always return zero. + This fetch applies only to the 'gpc' array data_type (and not to the legacy + 'gpc0' nor 'gpc1' data_types). + sc_clr_gpc0([,
]) : integer sc0_clr_gpc0([
]) : integer sc1_clr_gpc0([
]) : integer @@ -17813,6 +17919,16 @@ sc2_conn_rate([
]) : integer measured in amount of connections over the period configured in the table. See also src_conn_rate. +sc_get_gpc(,[,
]) : integer + Returns the value of the General Purpose Counter at the index + in the GPC array and associated to the currently tracked counter of + ID from the current proxy's stick-table or from the designated + stick-table
. is an integer between 0 and 99 and + an integer between 0 and 2. If there is not gpc stored at this + index, zero is returned. + This fetch applies only to the 'gpc' array data_type (and not to the legacy + 'gpc0' nor 'gpc1' data_types). See also src_get_gpc and sc_inc_gpc. + sc_get_gpc0([,
]) : integer sc0_get_gpc0([
]) : integer sc1_get_gpc0([
]) : integer @@ -17843,6 +17959,19 @@ sc2_get_gpt0([
]) : integer Returns the value of the first General Purpose Tag associated to the currently tracked counters. See also src_get_gpt0. +sc_gpc_rate(,[,
]) : integer + Returns the average increment rate of the General Purpose Counter at the + index of the array associated to the tracked counter of ID from + the current proxy's table or from the designated stick-table
. + It reports the frequency which the gpc counter was incremented over the + configured period. is an integer between 0 and 99 and an integer + between 0 and 2. + Note that the 'gpc_rate' counter array must be stored in the stick-table + for a value to be returned, as 'gpc' only holds the event count. + This fetch applies only to the 'gpc_rate' array data_type (and not to + the legacy 'gpc0_rate' nor 'gpc1_rate' data_types). + See also src_gpc_rate, sc_get_gpc, and sc_inc_gpc. + sc_gpc0_rate([,
]) : integer sc0_gpc0_rate([
]) : integer sc1_gpc0_rate([
]) : integer @@ -17916,6 +18045,17 @@ sc2_http_req_rate([
]) : integer the table. This includes every started request, valid or not. See also src_http_req_rate. +sc_inc_gpc(,[,
]) : integer + Increments the General Purpose Counter at the index of the array + associated to the designated tracked counter of ID from current + proxy's stick table or from the designated stick-table
, and + returns its new value. is an integer between 0 and 99 and + an integer between 0 and 2. + Before the first invocation, the stored value is zero, so first invocation + will increase it to 1 and will return 1. + This fetch applies only to the 'gpc' array data_type (and not to the legacy + 'gpc0' nor 'gpc1' data_types). + sc_inc_gpc0([,
]) : integer sc0_inc_gpc0([
]) : integer sc1_inc_gpc0([
]) : integer @@ -18042,6 +18182,16 @@ src_bytes_out_rate([
]) : integer amount of bytes over the period configured in the table. If the address is not found, zero is returned. See also sc/sc0/sc1/sc2_bytes_out_rate. +src_clr_gpc(,[
]) : integer + Clears the General Purpose Counter at the index of the array + associated to the incoming connection's source address in the current proxy's + stick-table or in the designated stick-table
, and returns its + previous value. is an integer between 0 and 99. + If the address is not found, an entry is created and 0 is returned. + This fetch applies only to the 'gpc' array data_type (and not to the legacy + 'gpc0' nor 'gpc1' data_types). + See also sc_clr_gpc. + src_clr_gpc0([
]) : integer Clears the first General Purpose Counter associated to the incoming connection's source address in the current proxy's stick-table or in the @@ -18085,6 +18235,17 @@ src_conn_rate([
]) : integer measured in amount of connections over the period configured in the table. If the address is not found, zero is returned. See also sc/sc0/sc1/sc2_conn_rate. +src_get_gpc(,[
]) : integer + Returns the value of the General Purpose Counter at the index of the + array associated to the incoming connection's source address in the + current proxy's stick-table or in the designated stick-table
. + is an integer between 0 and 99. + If the address is not found or there is no gpc stored at this index, zero + is returned. + This fetch applies only to the 'gpc' array data_type (and not on the legacy + 'gpc0' nor 'gpc1' data_types). + See also sc_get_gpc and src_inc_gpc. + src_get_gpc0([
]) : integer Returns the value of the first General Purpose Counter associated to the incoming connection's source address in the current proxy's stick-table or in @@ -18111,6 +18272,18 @@ src_get_gpt0([
]) : integer the designated stick-table. If the address is not found, zero is returned. See also sc/sc0/sc1/sc2_get_gpt0. +src_gpc_rate([,
]) : integer + Returns the average increment rate of the General Purpose Counter at the + index of the array associated to the incoming connection's + source address in the current proxy's stick-table or in the designated + stick-table
. It reports the frequency which the gpc counter was + incremented over the configured period. is an integer between 0 and 99. + Note that the 'gpc_rate' counter must be stored in the stick-table for a + value to be returned, as 'gpc' only holds the event count. + This fetch applies only to the 'gpc_rate' array data_type (and not to + the legacy 'gpc0_rate' nor 'gpc1_rate' data_types). + See also sc_gpc_rate, src_get_gpc, and sc_inc_gpc. + src_gpc0_rate([
]) : integer Returns the average increment rate of the first General Purpose Counter associated to the incoming connection's source address in the current proxy's @@ -18171,6 +18344,16 @@ src_http_req_rate([
]) : integer table. This includes every started request, valid or not. If the address is not found, zero is returned. See also sc/sc0/sc1/sc2_http_req_rate. +src_inc_gpc(,[
]) : integer + Increments the General Purpose Counter at index of the array + associated to the incoming connection's source address in the current proxy's + stick-table or in the designated stick-table
, and returns its new + value. is an integer between 0 and 99. + If the address is not found, an entry is created and 1 is returned. + This fetch applies only to the 'gpc' array data_type (and not to the legacy + 'gpc0' nor 'gpc1' data_types). + See also sc_inc_gpc. + src_inc_gpc0([
]) : integer Increments the first General Purpose Counter associated to the incoming connection's source address in the current proxy's stick-table or in the diff --git a/include/haproxy/action-t.h b/include/haproxy/action-t.h index 5494f76ad..cceed8039 100644 --- a/include/haproxy/action-t.h +++ b/include/haproxy/action-t.h @@ -168,6 +168,7 @@ struct act_rule { } vars; struct { int sc; + unsigned int idx; } gpc; struct { int sc; diff --git a/include/haproxy/stick_table-t.h b/include/haproxy/stick_table-t.h index fe21c9b20..9dd4ede5a 100644 --- a/include/haproxy/stick_table-t.h +++ b/include/haproxy/stick_table-t.h @@ -61,6 +61,8 @@ enum { STKTABLE_DT_HTTP_FAIL_CNT, /* cumulated number of HTTP server failures */ STKTABLE_DT_HTTP_FAIL_RATE,/* HTTP server failures rate */ STKTABLE_DT_GPT, /* array of gpt */ + STKTABLE_DT_GPC, /* array of gpc */ + STKTABLE_DT_GPC_RATE, /* array of gpc_rate */ STKTABLE_STATIC_DATA_TYPES,/* number of types above */ diff --git a/src/stick_table.c b/src/stick_table.c index 7bf0e5217..03c7a3820 100644 --- a/src/stick_table.c +++ b/src/stick_table.c @@ -1150,6 +1150,8 @@ struct stktable_data_type stktable_data_types[STKTABLE_DATA_TYPES] = { [STKTABLE_DT_HTTP_FAIL_CNT] = { .name = "http_fail_cnt", .std_type = STD_T_UINT }, [STKTABLE_DT_HTTP_FAIL_RATE]= { .name = "http_fail_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY }, [STKTABLE_DT_GPT] = { .name = "gpt", .std_type = STD_T_UINT, .is_array = 1 }, + [STKTABLE_DT_GPC] = { .name = "gpc", .std_type = STD_T_UINT, .is_array = 1 }, + [STKTABLE_DT_GPC_RATE] = { .name = "gpc_rate", .std_type = STD_T_FRQP, .is_array = 1, .arg_type = ARG_T_DELAY }, }; /* Registers stick-table extra data type with index , name , type @@ -1491,6 +1493,85 @@ static int sample_conv_table_gpt0(const struct arg *arg_p, struct sample *smp, v return !!ptr; } +/* Casts sample to the type of the table specified in arg_p(1), and looks + * it up into this table. Returns the value of the GPC[arg_p(0)] counter for the key + * if the key is present in the table, otherwise zero, so that comparisons can + * be easily performed. If the inspected parameter is not stored in the table, + * is returned. + */ +static int sample_conv_table_gpc(const struct arg *arg_p, struct sample *smp, void *private) +{ + struct stktable *t; + struct stktable_key *key; + struct stksess *ts; + void *ptr; + unsigned int idx; + + idx = arg_p[0].data.sint; + + t = arg_p[1].data.t; + + key = smp_to_stkey(smp, t); + if (!key) + return 0; + + ts = stktable_lookup_key(t, key); + + smp->flags = SMP_F_VOL_TEST; + smp->data.type = SMP_T_SINT; + smp->data.u.sint = 0; + + if (!ts) /* key not present */ + return 1; + + ptr = stktable_data_ptr_idx(t, ts, STKTABLE_DT_GPC, idx); + if (ptr) + smp->data.u.sint = stktable_data_cast(ptr, std_t_uint); + + stktable_release(t, ts); + return !!ptr; +} + +/* Casts sample to the type of the table specified in arg_p(1), and looks + * it up into this table. Returns the event rate of the GPC[arg_p(0)] counter + * for the key if the key is present in the table, otherwise zero, so that + * comparisons can be easily performed. If the inspected parameter is not + * stored in the table, is returned. + */ +static int sample_conv_table_gpc_rate(const struct arg *arg_p, struct sample *smp, void *private) +{ + struct stktable *t; + struct stktable_key *key; + struct stksess *ts; + void *ptr; + unsigned int idx; + + idx = arg_p[0].data.sint; + + t = arg_p[1].data.t; + + key = smp_to_stkey(smp, t); + if (!key) + return 0; + + ts = stktable_lookup_key(t, key); + + smp->flags = SMP_F_VOL_TEST; + smp->data.type = SMP_T_SINT; + smp->data.u.sint = 0; + + if (!ts) /* key not present */ + return 1; + + ptr = stktable_data_ptr_idx(t, ts, STKTABLE_DT_GPC_RATE, idx); + if (ptr) + smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp), + t->data_arg[STKTABLE_DT_GPC_RATE].u); + + stktable_release(t, ts); + return !!ptr; +} + /* Casts sample to the type of the table specified in arg(0), and looks * it up into this table. Returns the value of the GPC0 counter for the key * if the key is present in the table, otherwise zero, so that comparisons can @@ -2070,7 +2151,52 @@ static int sample_conv_table_trackers(const struct arg *arg_p, struct sample *sm return 1; } -/* Always returns 1. */ +/* This function increments the gpc counter at index 'rule->arg.gpc.idx' of the + * array on the tracksc counter of index 'rule->arg.gpc.sc' stored into the + * or directly in the session if is set to NULL + * + * This function always returns ACT_RET_CONT and parameter flags is unused. + */ +static enum act_return action_inc_gpc(struct act_rule *rule, struct proxy *px, + struct session *sess, struct stream *s, int flags) +{ + struct stksess *ts; + struct stkctr *stkctr; + + /* Extract the stksess, return OK if no stksess available. */ + if (s) + stkctr = &s->stkctr[rule->arg.gpc.sc]; + else + stkctr = &sess->stkctr[rule->arg.gpc.sc]; + + ts = stkctr_entry(stkctr); + if (ts) { + void *ptr1, *ptr2; + + /* First, update gpc_rate if it's tracked. Second, update its gpc if tracked. */ + ptr1 = stktable_data_ptr_idx(stkctr->table, ts, STKTABLE_DT_GPC_RATE, rule->arg.gpc.idx); + ptr2 = stktable_data_ptr_idx(stkctr->table, ts, STKTABLE_DT_GPC, rule->arg.gpc.idx); + + if (ptr1 || ptr2) { + HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock); + + if (ptr1) + update_freq_ctr_period(&stktable_data_cast(ptr1, std_t_frqp), + stkctr->table->data_arg[STKTABLE_DT_GPC_RATE].u, 1); + + if (ptr2) + stktable_data_cast(ptr2, std_t_uint)++; + + HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock); + + /* If data was modified, we need to touch to re-schedule sync */ + stktable_touch_local(stkctr->table, ts, 0); + } + } + return ACT_RET_CONT; +} + +/* Same as action_inc_gpc() but for gpc0 only */ static enum act_return action_inc_gpc0(struct act_rule *rule, struct proxy *px, struct session *sess, struct stream *s, int flags) { @@ -2109,50 +2235,7 @@ static enum act_return action_inc_gpc0(struct act_rule *rule, struct proxy *px, return ACT_RET_CONT; } -/* This function is a common parser for using variables. It understands - * the formats: - * - * sc-inc-gpc0() - * - * It returns 0 if fails and is filled with an error message. Otherwise, - * it returns 1 and the variable is filled with the pointer to the - * expression to execute. - */ -static enum act_parse_ret parse_inc_gpc0(const char **args, int *arg, struct proxy *px, - struct act_rule *rule, char **err) -{ - const char *cmd_name = args[*arg-1]; - char *error; - - cmd_name += strlen("sc-inc-gpc0"); - if (*cmd_name == '\0') { - /* default stick table id. */ - rule->arg.gpc.sc = 0; - } else { - /* parse the stick table id. */ - if (*cmd_name != '(') { - memprintf(err, "invalid stick table track ID. Expects %s()", args[*arg-1]); - return ACT_RET_PRS_ERR; - } - cmd_name++; /* jump the '(' */ - rule->arg.gpc.sc = strtol(cmd_name, &error, 10); /* Convert stick table id. */ - if (*error != ')') { - memprintf(err, "invalid stick table track ID. Expects %s()", args[*arg-1]); - return ACT_RET_PRS_ERR; - } - - if (rule->arg.gpc.sc >= MAX_SESS_STKCTR) { - memprintf(err, "invalid stick table track ID. The max allowed ID is %d", - MAX_SESS_STKCTR-1); - return ACT_RET_PRS_ERR; - } - } - rule->action = ACT_CUSTOM; - rule->action_ptr = action_inc_gpc0; - return ACT_RET_PRS_OK; -} - -/* Always returns 1. */ +/* Same as action_inc_gpc() but for gpc1 only */ static enum act_return action_inc_gpc1(struct act_rule *rule, struct proxy *px, struct session *sess, struct stream *s, int flags) { @@ -2191,46 +2274,83 @@ static enum act_return action_inc_gpc1(struct act_rule *rule, struct proxy *px, return ACT_RET_CONT; } -/* This function is a common parser for using variables. It understands - * the formats: +/* This function is a common parser for actions incrementing the GPC + * (General Purpose Counters). It understands the formats: * - * sc-inc-gpc1() + * sc-inc-gpc(,) + * sc-inc-gpc0([]) + * sc-inc-gpc1([]) * - * It returns 0 if fails and is filled with an error message. Otherwise, - * it returns 1 and the variable is filled with the pointer to the - * expression to execute. + * It returns ACT_RET_PRS_ERR if fails and is filled with an error + * message. Otherwise it returns ACT_RET_PRS_OK. */ -static enum act_parse_ret parse_inc_gpc1(const char **args, int *arg, struct proxy *px, - struct act_rule *rule, char **err) +static enum act_parse_ret parse_inc_gpc(const char **args, int *arg, struct proxy *px, + struct act_rule *rule, char **err) { const char *cmd_name = args[*arg-1]; char *error; - cmd_name += strlen("sc-inc-gpc1"); - if (*cmd_name == '\0') { - /* default stick table id. */ - rule->arg.gpc.sc = 0; - } else { - /* parse the stick table id. */ - if (*cmd_name != '(') { - memprintf(err, "invalid stick table track ID. Expects %s()", args[*arg-1]); - return ACT_RET_PRS_ERR; - } - cmd_name++; /* jump the '(' */ - rule->arg.gpc.sc = strtol(cmd_name, &error, 10); /* Convert stick table id. */ - if (*error != ')') { - memprintf(err, "invalid stick table track ID. Expects %s()", args[*arg-1]); + cmd_name += strlen("sc-inc-gpc"); + if (*cmd_name == '(') { + cmd_name++; /* skip the '(' */ + rule->arg.gpc.idx = strtoul(cmd_name, &error, 10); /* Convert stick table id. */ + if (*error != ',') { + memprintf(err, "Missing gpc ID '%s'. Expects sc-inc-gpc(,)", args[*arg-1]); return ACT_RET_PRS_ERR; } + else { + cmd_name = error + 1; /* skip the ',' */ + rule->arg.gpc.sc = strtol(cmd_name, &error, 10); /* Convert stick table id. */ + if (*error != ')') { + memprintf(err, "invalid stick table track ID '%s'. Expects sc-inc-gpc(,)", args[*arg-1]); + return ACT_RET_PRS_ERR; + } - if (rule->arg.gpc.sc >= MAX_SESS_STKCTR) { - memprintf(err, "invalid stick table track ID. The max allowed ID is %d", - MAX_SESS_STKCTR-1); - return ACT_RET_PRS_ERR; + if (rule->arg.gpc.sc >= MAX_SESS_STKCTR) { + memprintf(err, "invalid stick table track ID '%s'. The max allowed ID is %d", + args[*arg-1], MAX_SESS_STKCTR-1); + return ACT_RET_PRS_ERR; + } } + rule->action_ptr = action_inc_gpc; + } + else if (*cmd_name == '0' ||*cmd_name == '1') { + char c = *cmd_name; + + cmd_name++; + if (*cmd_name == '\0') { + /* default stick table id. */ + rule->arg.gpc.sc = 0; + } else { + /* parse the stick table id. */ + if (*cmd_name != '(') { + memprintf(err, "invalid stick table track ID. Expects %s()", args[*arg-1]); + return ACT_RET_PRS_ERR; + } + cmd_name++; /* jump the '(' */ + rule->arg.gpc.sc = strtol(cmd_name, &error, 10); /* Convert stick table id. */ + if (*error != ')') { + memprintf(err, "invalid stick table track ID. Expects %s()", args[*arg-1]); + return ACT_RET_PRS_ERR; + } + + if (rule->arg.gpc.sc >= MAX_SESS_STKCTR) { + memprintf(err, "invalid stick table track ID. The max allowed ID is %d", + MAX_SESS_STKCTR-1); + return ACT_RET_PRS_ERR; + } + } + if (c == '1') + rule->action_ptr = action_inc_gpc1; + else + rule->action_ptr = action_inc_gpc0; + } + else { + /* default stick table id. */ + memprintf(err, "invalid gpc ID '%s'. Expects sc-set-gpc(,)", args[*arg-1]); + return ACT_RET_PRS_ERR; } rule->action = ACT_CUSTOM; - rule->action_ptr = action_inc_gpc1; return ACT_RET_PRS_OK; } @@ -2731,6 +2851,51 @@ smp_fetch_sc_get_gpt0(const struct arg *args, struct sample *smp, const char *kw return 1; } +/* set to the GPC[args(0)]'s value from the stream's tracked + * frontend counters or from the src. + * Supports being called as "sc_get_gpc(,[,
])" or + * "src_get_gpc([,
])" only. Value + * Value zero is returned if the key is new or gpc is not stored. + */ +static int +smp_fetch_sc_get_gpc(const struct arg *args, struct sample *smp, const char *kw, void *private) +{ + struct stkctr tmpstkctr; + struct stkctr *stkctr; + unsigned int idx; + + idx = args[0].data.sint; + + stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args + 1, kw, &tmpstkctr); + if (!stkctr) + return 0; + + smp->flags = SMP_F_VOL_TEST; + smp->data.type = SMP_T_SINT; + smp->data.u.sint = 0; + + if (stkctr_entry(stkctr) != NULL) { + void *ptr; + + ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC, idx); + if (!ptr) { + if (stkctr == &tmpstkctr) + stktable_release(stkctr->table, stkctr_entry(stkctr)); + return 0; /* parameter not stored */ + } + + HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock); + + smp->data.u.sint = stktable_data_cast(ptr, std_t_uint); + + HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock); + + if (stkctr == &tmpstkctr) + stktable_release(stkctr->table, stkctr_entry(stkctr)); + } + return 1; +} + /* set to the General Purpose Counter 0 value from the stream's tracked * frontend counters or from the src. * Supports being called as "sc[0-9]_get_gpc0" or "src_get_gpc0" only. Value @@ -2813,6 +2978,51 @@ smp_fetch_sc_get_gpc1(const struct arg *args, struct sample *smp, const char *kw return 1; } +/* set to the GPC[args(0)]'s event rate from the stream's + * tracked frontend counters or from the src. + * Supports being called as "sc_gpc_rate(,[,[,
])" only. + * Value zero is returned if the key is new or gpc_rate is not stored. + */ +static int +smp_fetch_sc_gpc_rate(const struct arg *args, struct sample *smp, const char *kw, void *private) +{ + struct stkctr tmpstkctr; + struct stkctr *stkctr; + unsigned int idx; + + idx = args[0].data.sint; + + stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args + 1, kw, &tmpstkctr); + if (!stkctr) + return 0; + + smp->flags = SMP_F_VOL_TEST; + smp->data.type = SMP_T_SINT; + smp->data.u.sint = 0; + if (stkctr_entry(stkctr) != NULL) { + void *ptr; + + ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC_RATE, idx); + if (!ptr) { + if (stkctr == &tmpstkctr) + stktable_release(stkctr->table, stkctr_entry(stkctr)); + return 0; /* parameter not stored */ + } + + HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock); + + smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp), + stkctr->table->data_arg[STKTABLE_DT_GPC_RATE].u); + + HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock); + + if (stkctr == &tmpstkctr) + stktable_release(stkctr->table, stkctr_entry(stkctr)); + } + return 1; +} + /* set to the General Purpose Counter 0's event rate from the stream's * tracked frontend counters or from the src. * Supports being called as "sc[0-9]_gpc0_rate" or "src_gpc0_rate" only. @@ -2895,6 +3105,63 @@ smp_fetch_sc_gpc1_rate(const struct arg *args, struct sample *smp, const char *k return 1; } +/* Increment the GPC[args(0)] value from the stream's tracked + * frontend counters and return it into temp integer. + * Supports being called as "sc_inc_gpc(,[,
])" + * or "src_inc_gpc([,
])" only. + */ +static int +smp_fetch_sc_inc_gpc(const struct arg *args, struct sample *smp, const char *kw, void *private) +{ + struct stkctr tmpstkctr; + struct stkctr *stkctr; + unsigned int idx; + + idx = args[0].data.sint; + + stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args + 1, kw, &tmpstkctr); + if (!stkctr) + return 0; + + smp->flags = SMP_F_VOL_TEST; + smp->data.type = SMP_T_SINT; + smp->data.u.sint = 0; + + if (!stkctr_entry(stkctr)) + stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr); + + if (stkctr && stkctr_entry(stkctr)) { + void *ptr1,*ptr2; + + + /* First, update gpc0_rate if it's tracked. Second, update its + * gpc0 if tracked. Returns gpc0's value otherwise the curr_ctr. + */ + ptr1 = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC_RATE, idx); + ptr2 = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC, idx); + if (ptr1 || ptr2) { + HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock); + + if (ptr1) { + update_freq_ctr_period(&stktable_data_cast(ptr1, std_t_frqp), + stkctr->table->data_arg[STKTABLE_DT_GPC_RATE].u, 1); + smp->data.u.sint = (&stktable_data_cast(ptr1, std_t_frqp))->curr_ctr; + } + + if (ptr2) + smp->data.u.sint = ++stktable_data_cast(ptr2, std_t_uint); + + HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock); + + /* If data was modified, we need to touch to re-schedule sync */ + stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0); + } + else if (stkctr == &tmpstkctr) + stktable_release(stkctr->table, stkctr_entry(stkctr)); + } + return 1; +} + /* Increment the General Purpose Counter 0 value from the stream's tracked * frontend counters and return it into temp integer. * Supports being called as "sc[0-9]_inc_gpc0" or "src_inc_gpc0" only. @@ -3001,6 +3268,54 @@ smp_fetch_sc_inc_gpc1(const struct arg *args, struct sample *smp, const char *kw return 1; } +/* Clear the GPC[args(0)] value from the stream's tracked + * frontend counters and return its previous value into temp integer. + * Supports being called as "sc_clr_gpc(,[,
])" + * or "src_clr_gpc([,
])" only. + */ +static int +smp_fetch_sc_clr_gpc(const struct arg *args, struct sample *smp, const char *kw, void *private) +{ + struct stkctr tmpstkctr; + struct stkctr *stkctr; + unsigned int idx; + + idx = args[0].data.sint; + + stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args + 1, kw, &tmpstkctr); + if (!stkctr) + return 0; + + smp->flags = SMP_F_VOL_TEST; + smp->data.type = SMP_T_SINT; + smp->data.u.sint = 0; + + if (!stkctr_entry(stkctr)) + stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr); + + if (stkctr && stkctr_entry(stkctr)) { + void *ptr; + + ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC, idx); + if (!ptr) { + if (stkctr == &tmpstkctr) + stktable_release(stkctr->table, stkctr_entry(stkctr)); + return 0; /* parameter not stored */ + } + + HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock); + + smp->data.u.sint = stktable_data_cast(ptr, std_t_uint); + stktable_data_cast(ptr, std_t_uint) = 0; + + HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock); + + /* If data was modified, we need to touch to re-schedule sync */ + stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0); + } + return 1; +} + /* Clear the General Purpose Counter 0 value from the stream's tracked * frontend counters and return its previous value into temp integer. * Supports being called as "sc[0-9]_clr_gpc0" or "src_clr_gpc0" only. @@ -4383,8 +4698,9 @@ static struct cli_kw_list cli_kws = {{ },{ INITCALL1(STG_REGISTER, cli_register_kw, &cli_kws); static struct action_kw_list tcp_conn_kws = { { }, { - { "sc-inc-gpc0", parse_inc_gpc0, KWF_MATCH_PREFIX }, - { "sc-inc-gpc1", parse_inc_gpc1, KWF_MATCH_PREFIX }, + { "sc-inc-gpc", parse_inc_gpc, KWF_MATCH_PREFIX }, + { "sc-inc-gpc0", parse_inc_gpc, KWF_MATCH_PREFIX }, + { "sc-inc-gpc1", parse_inc_gpc, KWF_MATCH_PREFIX }, { "sc-set-gpt", parse_set_gpt, KWF_MATCH_PREFIX }, { "sc-set-gpt0", parse_set_gpt, KWF_MATCH_PREFIX }, { /* END */ } @@ -4393,8 +4709,9 @@ static struct action_kw_list tcp_conn_kws = { { }, { INITCALL1(STG_REGISTER, tcp_req_conn_keywords_register, &tcp_conn_kws); static struct action_kw_list tcp_sess_kws = { { }, { - { "sc-inc-gpc0", parse_inc_gpc0, KWF_MATCH_PREFIX }, - { "sc-inc-gpc1", parse_inc_gpc1, KWF_MATCH_PREFIX }, + { "sc-inc-gpc", parse_inc_gpc, KWF_MATCH_PREFIX }, + { "sc-inc-gpc0", parse_inc_gpc, KWF_MATCH_PREFIX }, + { "sc-inc-gpc1", parse_inc_gpc, KWF_MATCH_PREFIX }, { "sc-set-gpt", parse_set_gpt, KWF_MATCH_PREFIX }, { "sc-set-gpt0", parse_set_gpt, KWF_MATCH_PREFIX }, { /* END */ } @@ -4403,8 +4720,9 @@ static struct action_kw_list tcp_sess_kws = { { }, { INITCALL1(STG_REGISTER, tcp_req_sess_keywords_register, &tcp_sess_kws); static struct action_kw_list tcp_req_kws = { { }, { - { "sc-inc-gpc0", parse_inc_gpc0, KWF_MATCH_PREFIX }, - { "sc-inc-gpc1", parse_inc_gpc1, KWF_MATCH_PREFIX }, + { "sc-inc-gpc", parse_inc_gpc, KWF_MATCH_PREFIX }, + { "sc-inc-gpc0", parse_inc_gpc, KWF_MATCH_PREFIX }, + { "sc-inc-gpc1", parse_inc_gpc, KWF_MATCH_PREFIX }, { "sc-set-gpt", parse_set_gpt, KWF_MATCH_PREFIX }, { "sc-set-gpt0", parse_set_gpt, KWF_MATCH_PREFIX }, { /* END */ } @@ -4413,8 +4731,9 @@ static struct action_kw_list tcp_req_kws = { { }, { INITCALL1(STG_REGISTER, tcp_req_cont_keywords_register, &tcp_req_kws); static struct action_kw_list tcp_res_kws = { { }, { - { "sc-inc-gpc0", parse_inc_gpc0, KWF_MATCH_PREFIX }, - { "sc-inc-gpc1", parse_inc_gpc1, KWF_MATCH_PREFIX }, + { "sc-inc-gpc", parse_inc_gpc, KWF_MATCH_PREFIX }, + { "sc-inc-gpc0", parse_inc_gpc, KWF_MATCH_PREFIX }, + { "sc-inc-gpc1", parse_inc_gpc, KWF_MATCH_PREFIX }, { "sc-set-gpt", parse_set_gpt, KWF_MATCH_PREFIX }, { "sc-set-gpt0", parse_set_gpt, KWF_MATCH_PREFIX }, { /* END */ } @@ -4423,8 +4742,9 @@ static struct action_kw_list tcp_res_kws = { { }, { INITCALL1(STG_REGISTER, tcp_res_cont_keywords_register, &tcp_res_kws); static struct action_kw_list http_req_kws = { { }, { - { "sc-inc-gpc0", parse_inc_gpc0, KWF_MATCH_PREFIX }, - { "sc-inc-gpc1", parse_inc_gpc1, KWF_MATCH_PREFIX }, + { "sc-inc-gpc", parse_inc_gpc, KWF_MATCH_PREFIX }, + { "sc-inc-gpc0", parse_inc_gpc, KWF_MATCH_PREFIX }, + { "sc-inc-gpc1", parse_inc_gpc, KWF_MATCH_PREFIX }, { "sc-set-gpt", parse_set_gpt, KWF_MATCH_PREFIX }, { "sc-set-gpt0", parse_set_gpt, KWF_MATCH_PREFIX }, { /* END */ } @@ -4433,8 +4753,9 @@ static struct action_kw_list http_req_kws = { { }, { INITCALL1(STG_REGISTER, http_req_keywords_register, &http_req_kws); static struct action_kw_list http_res_kws = { { }, { - { "sc-inc-gpc0", parse_inc_gpc0, KWF_MATCH_PREFIX }, - { "sc-inc-gpc1", parse_inc_gpc1, KWF_MATCH_PREFIX }, + { "sc-inc-gpc", parse_inc_gpc, KWF_MATCH_PREFIX }, + { "sc-inc-gpc0", parse_inc_gpc, KWF_MATCH_PREFIX }, + { "sc-inc-gpc1", parse_inc_gpc, KWF_MATCH_PREFIX }, { "sc-set-gpt", parse_set_gpt, KWF_MATCH_PREFIX }, { "sc-set-gpt0", parse_set_gpt, KWF_MATCH_PREFIX }, { /* END */ } @@ -4448,6 +4769,7 @@ INITCALL1(STG_REGISTER, http_res_keywords_register, &http_res_kws); static struct sample_fetch_kw_list smp_fetch_keywords = {ILH, { { "sc_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, }, { "sc_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, }, + { "sc_clr_gpc", smp_fetch_sc_clr_gpc, ARG3(2,SINT,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, }, { "sc_clr_gpc0", smp_fetch_sc_clr_gpc0, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, }, { "sc_clr_gpc1", smp_fetch_sc_clr_gpc1, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN }, { "sc_conn_cnt", smp_fetch_sc_conn_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, }, @@ -4455,8 +4777,10 @@ static struct sample_fetch_kw_list smp_fetch_keywords = {ILH, { { "sc_conn_rate", smp_fetch_sc_conn_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, }, { "sc_get_gpt", smp_fetch_sc_get_gpt, ARG3(2,SINT,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, }, { "sc_get_gpt0", smp_fetch_sc_get_gpt0, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, }, + { "sc_get_gpc", smp_fetch_sc_get_gpc, ARG3(2,SINT,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, }, { "sc_get_gpc0", smp_fetch_sc_get_gpc0, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, }, { "sc_get_gpc1", smp_fetch_sc_get_gpc1, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN }, + { "sc_gpc_rate", smp_fetch_sc_gpc_rate, ARG3(2,SINT,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, }, { "sc_gpc0_rate", smp_fetch_sc_gpc0_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, }, { "sc_gpc1_rate", smp_fetch_sc_gpc1_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, }, { "sc_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, }, @@ -4465,6 +4789,7 @@ static struct sample_fetch_kw_list smp_fetch_keywords = {ILH, { { "sc_http_fail_rate", smp_fetch_sc_http_fail_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, }, { "sc_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, }, { "sc_http_req_rate", smp_fetch_sc_http_req_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, }, + { "sc_inc_gpc", smp_fetch_sc_inc_gpc, ARG3(2,SINT,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, }, { "sc_inc_gpc0", smp_fetch_sc_inc_gpc0, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, }, { "sc_inc_gpc1", smp_fetch_sc_inc_gpc1, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, }, { "sc_kbytes_in", smp_fetch_sc_kbytes_in, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, }, @@ -4501,6 +4826,7 @@ static struct sample_fetch_kw_list smp_fetch_keywords = {ILH, { { "sc0_trackers", smp_fetch_sc_trackers, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, }, { "sc1_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, }, { "sc1_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, }, + { "sc1_clr_gpc", smp_fetch_sc_clr_gpc, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, }, { "sc1_clr_gpc0", smp_fetch_sc_clr_gpc0, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, }, { "sc1_clr_gpc1", smp_fetch_sc_clr_gpc1, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, }, { "sc1_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, }, @@ -4553,6 +4879,7 @@ static struct sample_fetch_kw_list smp_fetch_keywords = {ILH, { { "sc2_trackers", smp_fetch_sc_trackers, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, }, { "src_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, }, { "src_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, }, + { "src_clr_gpc", smp_fetch_sc_clr_gpc, ARG2(2,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, }, { "src_clr_gpc0", smp_fetch_sc_clr_gpc0, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, }, { "src_clr_gpc1", smp_fetch_sc_clr_gpc1, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, }, { "src_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, }, @@ -4560,8 +4887,10 @@ static struct sample_fetch_kw_list smp_fetch_keywords = {ILH, { { "src_conn_rate", smp_fetch_sc_conn_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, }, { "src_get_gpt" , smp_fetch_sc_get_gpt, ARG2(2,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, }, { "src_get_gpt0", smp_fetch_sc_get_gpt0, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, }, + { "src_get_gpc", smp_fetch_sc_get_gpc, ARG2(2,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, }, { "src_get_gpc0", smp_fetch_sc_get_gpc0, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, }, { "src_get_gpc1", smp_fetch_sc_get_gpc1, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, }, + { "src_gpc_rate", smp_fetch_sc_gpc_rate, ARG2(2,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, }, { "src_gpc0_rate", smp_fetch_sc_gpc0_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, }, { "src_gpc1_rate", smp_fetch_sc_gpc1_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, }, { "src_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, }, @@ -4570,6 +4899,7 @@ static struct sample_fetch_kw_list smp_fetch_keywords = {ILH, { { "src_http_fail_rate", smp_fetch_sc_http_fail_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, }, { "src_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, }, { "src_http_req_rate", smp_fetch_sc_http_req_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, }, + { "src_inc_gpc", smp_fetch_sc_inc_gpc, ARG2(2,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, }, { "src_inc_gpc0", smp_fetch_sc_inc_gpc0, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, }, { "src_inc_gpc1", smp_fetch_sc_inc_gpc1, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, }, { "src_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, }, @@ -4594,8 +4924,10 @@ static struct sample_conv_kw_list sample_conv_kws = {ILH, { { "table_conn_rate", sample_conv_table_conn_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT }, { "table_gpt", sample_conv_table_gpt, ARG2(2,SINT,TAB), NULL, SMP_T_ANY, SMP_T_SINT }, { "table_gpt0", sample_conv_table_gpt0, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT }, + { "table_gpc", sample_conv_table_gpc, ARG2(2,SINT,TAB), NULL, SMP_T_ANY, SMP_T_SINT }, { "table_gpc0", sample_conv_table_gpc0, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT }, { "table_gpc1", sample_conv_table_gpc1, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT }, + { "table_gpc_rate", sample_conv_table_gpc_rate, ARG2(2,SINT,TAB), NULL, SMP_T_ANY, SMP_T_SINT }, { "table_gpc0_rate", sample_conv_table_gpc0_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT }, { "table_gpc1_rate", sample_conv_table_gpc1_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT }, { "table_http_err_cnt", sample_conv_table_http_err_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },