diff --git a/doc/configuration.txt b/doc/configuration.txt index 1ce423bab..3665fe0f7 100644 --- a/doc/configuration.txt +++ b/doc/configuration.txt @@ -3903,6 +3903,7 @@ http-request { allow | auth [realm ] | redirect | reject | unset-var() | { track-sc0 | track-sc1 | track-sc2 } [table ] | sc-inc-gpc0() | + sc-inc-gpc1() | sc-set-gpt0() | silent-drop | send-spoe-group | @@ -4194,6 +4195,9 @@ http-request { allow | auth [realm ] | redirect | reject | designated by . If an error occurs, this action silently fails and the actions evaluation continues. + - sc-inc-gpc1(): + Same as "sc-inc-gpc0" action above but for GPC1 counter. + - set-var() : Is used to set the contents of a variable. The variable is declared inline. @@ -4403,6 +4407,7 @@ http-response { allow | deny | add-header | set-nice | unset-var() | { track-sc0 | track-sc1 | track-sc2 } [table
] | sc-inc-gpc0() | + sc-inc-gpc1() | sc-set-gpt0() | silent-drop | send-spoe-group | @@ -4644,6 +4649,9 @@ http-response { allow | deny | add-header | set-nice | designated by . If an error occurs, this action silently fails and the actions evaluation continues. + - sc-inc-gpc1(): + Same as "sc-inc-gpc0" action above but for GPC1 counter. + - "silent-drop" : this stops the evaluation of the rules and makes the client-facing connection suddenly disappear using a system-dependent way that tries to prevent the client from being notified. The effect it then @@ -8743,6 +8751,18 @@ stick-table type {ip | integer | string [len ] | binary [len ]} 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). + - gpc1 : second 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 + specific behavior was detected and must be known for future matches. + + - gpc1_rate() : increment rate of the second General Purpose Counter + over a period. It is a positive 32-bit integer integer which may be used + for anything. Just like , it counts events, but instead of keeping + a cumulative number, it maintains 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). + - conn_cnt : Connection Count. It is a positive 32-bit integer which counts the absolute number of connections received from clients which matched this entry. It does not mean the connections were accepted, just that @@ -9255,6 +9275,11 @@ tcp-request connection [{if | unless} ] counter designated by . If an error occurs, this action silently fails and the actions evaluation continues. + - sc-inc-gpc1(): + The "sc-inc-gpc1" increments the GPC1 counter according to the sticky + counter designated by . If an error occurs, this action silently + fails and the actions evaluation continues. + - sc-set-gpt0() : This action sets the GPT0 tag according to the sticky counter designated by and the value of . The expected result is a boolean. If @@ -9414,6 +9439,7 @@ tcp-request content [{if | unless} ] - capture : the specified sample expression is captured - { track-sc0 | track-sc1 | track-sc2 } [table
] - sc-inc-gpc0() + - sc-inc-gpc1() - sc-set-gpt0() - set-var() - unset-var() @@ -9648,6 +9674,11 @@ tcp-response content [{if | unless} ] counter designated by . If an error occurs, this action fails silently and the actions evaluation continues. + - sc-inc-gpc1(): + This action increments the GPC1 counter according to the sticky + counter designated by . If an error occurs, this action fails + silently and the actions evaluation continues. + - sc-set-gpt0() : This action sets the GPT0 tag according to the sticky counter designated by and the value of . The expected result is a boolean. If @@ -9772,6 +9803,7 @@ tcp-request session [{if | unless} ] - reject : the request is rejected and the connection is closed - { track-sc0 | track-sc1 | track-sc2 } [table
] - sc-inc-gpc0() + - sc-inc-gpc1() - sc-set-gpt0() - set-var() - unset-var() @@ -13237,6 +13269,21 @@ table_gpc0_rate(
) with the input sample in the designated table. See also the sc_get_gpc0_rate sample fetch keyword. +table_gpc1(
) + 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 + is returned. Otherwise the converter returns the current value of the second + general purpose counter associated with the input sample in the designated + table. See also the sc_get_gpc1 sample fetch keyword. + +table_gpc1_rate(
) + 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 + is returned. Otherwise the converter returns the frequency which the gpc1 + counter was incremented over the configured period in the table, associated + with the input sample in the designated table. See also the sc_get_gpc1_rate + sample fetch keyword. + table_http_err_cnt(
) 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 @@ -13880,6 +13927,16 @@ sc2_clr_gpc0([
]) : integer tcp-request connection accept if !abuse save tcp-request connection reject if abuse kill +sc_clr_gpc1([,
]) : integer +sc0_clr_gpc1([
]) : integer +sc1_clr_gpc1([
]) : integer +sc2_clr_gpc1([
]) : integer + Clears the second General Purpose Counter associated to the currently tracked + counters, and returns its previous value. Before the first invocation, the + stored value is zero, so first invocation will always return zero. This is + typically used as a second ACL in an expression in order to mark a connection + when a first ACL was verified. + sc_conn_cnt([,
]) : integer sc0_conn_cnt([
]) : integer sc1_conn_cnt([
]) : integer @@ -13910,6 +13967,13 @@ sc2_get_gpc0([
]) : integer Returns the value of the first General Purpose Counter associated to the currently tracked counters. See also src_get_gpc0 and sc/sc0/sc1/sc2_inc_gpc0. +sc_get_gpc1([,
]) : integer +sc0_get_gpc1([
]) : integer +sc1_get_gpc1([
]) : integer +sc2_get_gpc1([
]) : integer + Returns the value of the second General Purpose Counter associated to the + currently tracked counters. See also src_get_gpc1 and sc/sc0/sc1/sc2_inc_gpc1. + sc_get_gpt0([,
]) : integer sc0_get_gpt0([
]) : integer sc1_get_gpt0([
]) : integer @@ -13928,6 +13992,17 @@ sc2_gpc0_rate([
]) : integer that the "gpc0_rate" counter must be stored in the stick-table for a value to be returned, as "gpc0" only holds the event count. +sc_gpc1_rate([,
]) : integer +sc0_gpc1_rate([
]) : integer +sc1_gpc1_rate([
]) : integer +sc2_gpc1_rate([
]) : integer + Returns the average increment rate of the second General Purpose Counter + associated to the currently tracked counters. It reports the frequency + which the gpc1 counter was incremented over the configured period. See also + src_gpcA_rate, sc/sc0/sc1/sc2_get_gpc1, and sc/sc0/sc1/sc2_inc_gpc1. Note + that the "gpc1_rate" counter must be stored in the stick-table for a value to + be returned, as "gpc1" only holds the event count. + sc_http_err_cnt([,
]) : integer sc0_http_err_cnt([
]) : integer sc1_http_err_cnt([
]) : integer @@ -13977,6 +14052,16 @@ sc2_inc_gpc0([
]) : integer acl kill sc0_inc_gpc0 gt 0 tcp-request connection reject if abuse kill +sc_inc_gpc1([,
]) : integer +sc0_inc_gpc1([
]) : integer +sc1_inc_gpc1([
]) : integer +sc2_inc_gpc1([
]) : integer + Increments the second General Purpose Counter associated to the currently + tracked counters, and returns its new value. Before the first invocation, + the stored value is zero, so first invocation will increase it to 1 and will + return 1. This is typically used as a second ACL in an expression in order + to mark a connection when a first ACL was verified. + sc_kbytes_in([,
]) : integer sc0_kbytes_in([
]) : integer sc1_kbytes_in([
]) : integer @@ -14084,6 +14169,14 @@ src_clr_gpc0([
]) : integer tcp-request connection accept if !abuse save tcp-request connection reject if abuse kill +src_clr_gpc1([
]) : integer + Clears the second General Purpose Counter 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. If the address is not + found, an entry is created and 0 is returned. This is typically used as a + second ACL in an expression in order to mark a connection when a first ACL + was verified. + src_conn_cnt([
]) : integer Returns the cumulative number of connections initiated from the current incoming connection's source address in the current proxy's stick-table or in @@ -14108,6 +14201,12 @@ src_get_gpc0([
]) : integer the designated stick-table. If the address is not found, zero is returned. See also sc/sc0/sc1/sc2_get_gpc0 and src_inc_gpc0. +src_get_gpc1([
]) : integer + Returns the value of the second General Purpose Counter associated to the + incoming connection's source address in the current proxy's stick-table or in + the designated stick-table. If the address is not found, zero is returned. + See also sc/sc0/sc1/sc2_get_gpc1 and src_inc_gpc1. + src_get_gpt0([
]) : integer Returns the value of the first General Purpose Tag associated to the incoming connection's source address in the current proxy's stick-table or in @@ -14123,6 +14222,15 @@ src_gpc0_rate([
]) : integer that the "gpc0_rate" counter must be stored in the stick-table for a value to be returned, as "gpc0" only holds the event count. +src_gpc1_rate([
]) : integer + Returns the average increment rate of the second General Purpose Counter + 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 gpc1 counter was incremented over the configured period. See also + sc/sc0/sc1/sc2_gpc1_rate, src_get_gpc1, and sc/sc0/sc1/sc2_inc_gpc1. Note + that the "gpc1_rate" counter must be stored in the stick-table for a value to + be returned, as "gpc1" only holds the event count. + src_http_err_cnt([
]) : integer Returns the cumulative number of HTTP errors from the incoming connection's source address in the current proxy's stick-table or in the designated @@ -14163,6 +14271,14 @@ src_inc_gpc0([
]) : integer acl kill src_inc_gpc0 gt 0 tcp-request connection reject if abuse kill +src_inc_gpc1([
]) : integer + Increments the second General Purpose Counter 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. If the address is not + found, an entry is created and 1 is returned. See also sc0/sc2/sc2_inc_gpc1. + This is typically used as a second ACL in an expression in order to mark a + connection when a first ACL was verified. + src_is_local : boolean Returns true if the source address of the incoming connection is local to the system, or false if the address doesn't exist on the system, meaning that it diff --git a/doc/peers-v2.0.txt b/doc/peers-v2.0.txt index 767721eb3..6812c85a0 100644 --- a/doc/peers-v2.0.txt +++ b/doc/peers-v2.0.txt @@ -219,6 +219,8 @@ bit 14: bytes in rate 15: bytes out rate 16: bytes out rate + 17: gpc1 + 18: gpc1 rate d) Table Switch Message diff --git a/include/types/stick_table.h b/include/types/stick_table.h index 4a8d8c7db..28e255fb8 100644 --- a/include/types/stick_table.h +++ b/include/types/stick_table.h @@ -52,6 +52,8 @@ enum { STKTABLE_DT_BYTES_IN_RATE,/* bytes rate from client to servers */ STKTABLE_DT_BYTES_OUT_CNT,/* cumulated bytes count from servers to client */ STKTABLE_DT_BYTES_OUT_RATE,/* bytes rate from servers to client */ + STKTABLE_DT_GPC1, /* General Purpose Counter 1 (unsigned 32-bit integer) */ + STKTABLE_DT_GPC1_RATE, /* General Purpose Counter 1's event rate */ STKTABLE_STATIC_DATA_TYPES,/* number of types above */ /* up to STKTABLE_EXTRA_DATA_TYPES types may be registered here, always * followed by the number of data types, must always be last. @@ -87,6 +89,8 @@ union stktable_data { unsigned int gpt0; unsigned int gpc0; struct freq_ctr_period gpc0_rate; + unsigned int gpc1; + struct freq_ctr_period gpc1_rate; unsigned int conn_cnt; struct freq_ctr_period conn_rate; unsigned int conn_cur; diff --git a/src/stick_table.c b/src/stick_table.c index 40c9258a0..fe26e3121 100644 --- a/src/stick_table.c +++ b/src/stick_table.c @@ -800,6 +800,8 @@ struct stktable_data_type stktable_data_types[STKTABLE_DATA_TYPES] = { [STKTABLE_DT_BYTES_IN_RATE] = { .name = "bytes_in_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY }, [STKTABLE_DT_BYTES_OUT_CNT] = { .name = "bytes_out_cnt", .std_type = STD_T_ULL }, [STKTABLE_DT_BYTES_OUT_RATE]= { .name = "bytes_out_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY }, + [STKTABLE_DT_GPC1] = { .name = "gpc1", .std_type = STD_T_UINT }, + [STKTABLE_DT_GPC1_RATE] = { .name = "gpc1_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY }, }; /* Registers stick-table extra data type with index , name , type @@ -1168,6 +1170,79 @@ static int sample_conv_table_gpc0_rate(const struct arg *arg_p, struct sample *s return 1; } +/* Casts sample to the type of the table specified in arg(0), and looks + * it up into this table. Returns the value of the GPC1 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_gpc1(const struct arg *arg_p, struct sample *smp, void *private) +{ + struct stktable *t; + struct stktable_key *key; + struct stksess *ts; + void *ptr; + + t = &arg_p[0].data.prx->table; + + 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(t, ts, STKTABLE_DT_GPC1); + if (!ptr) + return 0; /* parameter not stored */ + + smp->data.u.sint = stktable_data_cast(ptr, gpc1); + return 1; +} + +/* Casts sample to the type of the table specified in arg(0), and looks + * it up into this table. Returns the event rate of the GPC1 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_gpc1_rate(const struct arg *arg_p, struct sample *smp, void *private) +{ + struct stktable *t; + struct stktable_key *key; + struct stksess *ts; + void *ptr; + + t = &arg_p[0].data.prx->table; + + 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(t, ts, STKTABLE_DT_GPC1_RATE); + if (!ptr) + return 0; /* parameter not stored */ + + smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, gpc1_rate), + t->data_arg[STKTABLE_DT_GPC1_RATE].u); + return 1; +} + /* Casts sample to the type of the table specified in arg(0), and looks * it up into this table. Returns the cumulated number of HTTP request errors * for the key if the key is present in the table, otherwise zero, so that @@ -1607,6 +1682,88 @@ static enum act_parse_ret parse_inc_gpc0(const char **args, int *arg, struct pro return ACT_RET_PRS_OK; } +/* Always returns 1. */ +static enum act_return action_inc_gpc1(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 gpc1_rate if it's tracked. Second, update its gpc1 if tracked. */ + ptr1 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC1_RATE); + ptr2 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC1); + if (ptr1 || ptr2) { + HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock); + + if (ptr1) + update_freq_ctr_period(&stktable_data_cast(ptr1, gpc1_rate), + stkctr->table->data_arg[STKTABLE_DT_GPC1_RATE].u, 1); + + if (ptr2) + stktable_data_cast(ptr2, gpc1)++; + + 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; +} + +/* This function is a common parser for using variables. It understands + * the formats: + * + * 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. + */ +static enum act_parse_ret parse_inc_gpc1(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]); + return ACT_RET_PRS_ERR; + } + + if (rule->arg.gpc.sc >= ACT_ACTION_TRK_SCMAX) { + memprintf(err, "invalid stick table track ID. The max allowed ID is %d", + ACT_ACTION_TRK_SCMAX-1); + return ACT_RET_PRS_ERR; + } + } + rule->action = ACT_CUSTOM; + rule->action_ptr = action_inc_gpc1; + return ACT_RET_PRS_OK; +} + /* Always returns 1. */ static enum act_return action_set_gpt0(struct act_rule *rule, struct proxy *px, struct session *sess, struct stream *s, int flags) @@ -1940,6 +2097,47 @@ smp_fetch_sc_get_gpc0(const struct arg *args, struct sample *smp, const char *kw return 1; } +/* set to the General Purpose Counter 1 value from the stream's tracked + * frontend counters or from the src. + * Supports being called as "sc[0-9]_get_gpc1" or "src_get_gpc1" only. Value + * zero is returned if the key is new. + */ +static int +smp_fetch_sc_get_gpc1(const struct arg *args, struct sample *smp, const char *kw, void *private) +{ + struct stkctr tmpstkctr; + struct stkctr *stkctr; + + stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, 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(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1); + 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, gpc1); + + 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. @@ -1981,6 +2179,47 @@ smp_fetch_sc_gpc0_rate(const struct arg *args, struct sample *smp, const char *k return 1; } +/* set to the General Purpose Counter 1's event rate from the stream's + * tracked frontend counters or from the src. + * Supports being called as "sc[0-9]_gpc1_rate" or "src_gpc1_rate" only. + * Value zero is returned if the key is new. + */ +static int +smp_fetch_sc_gpc1_rate(const struct arg *args, struct sample *smp, const char *kw, void *private) +{ + struct stkctr tmpstkctr; + struct stkctr *stkctr; + + stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, 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(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1_RATE); + 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, gpc1_rate), + stkctr->table->data_arg[STKTABLE_DT_GPC1_RATE].u); + + HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock); + + 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. @@ -2034,6 +2273,59 @@ smp_fetch_sc_inc_gpc0(const struct arg *args, struct sample *smp, const char *kw return 1; } +/* Increment the General Purpose Counter 1 value from the stream's tracked + * frontend counters and return it into temp integer. + * Supports being called as "sc[0-9]_inc_gpc1" or "src_inc_gpc1" only. + */ +static int +smp_fetch_sc_inc_gpc1(const struct arg *args, struct sample *smp, const char *kw, void *private) +{ + struct stkctr tmpstkctr; + struct stkctr *stkctr; + + stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, 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 gpc1_rate if it's tracked. Second, update its + * gpc1 if tracked. Returns gpc1's value otherwise the curr_ctr. + */ + ptr1 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1_RATE); + ptr2 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1); + if (ptr1 || ptr2) { + HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock); + + if (ptr1) { + update_freq_ctr_period(&stktable_data_cast(ptr1, gpc1_rate), + stkctr->table->data_arg[STKTABLE_DT_GPC1_RATE].u, 1); + smp->data.u.sint = (&stktable_data_cast(ptr1, gpc1_rate))->curr_ctr; + } + + if (ptr2) + smp->data.u.sint = ++stktable_data_cast(ptr2, gpc1); + + 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; +} + /* 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. @@ -2078,6 +2370,50 @@ smp_fetch_sc_clr_gpc0(const struct arg *args, struct sample *smp, const char *kw return 1; } +/* Clear the General Purpose Counter 1 value from the stream's tracked + * frontend counters and return its previous value into temp integer. + * Supports being called as "sc[0-9]_clr_gpc1" or "src_clr_gpc1" only. + */ +static int +smp_fetch_sc_clr_gpc1(const struct arg *args, struct sample *smp, const char *kw, void *private) +{ + struct stkctr tmpstkctr; + struct stkctr *stkctr; + + stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, 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(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1); + 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, gpc1); + stktable_data_cast(ptr, gpc1) = 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; +} + /* set to the cumulated number of connections from the stream's tracked * frontend counters. Supports being called as "sc[0-9]_conn_cnt" or * "src_conn_cnt" only. @@ -3281,36 +3617,42 @@ static struct cli_kw_list cli_kws = {{ },{ static struct action_kw_list tcp_conn_kws = { { }, { { "sc-inc-gpc0", parse_inc_gpc0, 1 }, + { "sc-inc-gpc1", parse_inc_gpc1, 1 }, { "sc-set-gpt0", parse_set_gpt0, 1 }, { /* END */ } }}; static struct action_kw_list tcp_sess_kws = { { }, { { "sc-inc-gpc0", parse_inc_gpc0, 1 }, + { "sc-inc-gpc1", parse_inc_gpc1, 1 }, { "sc-set-gpt0", parse_set_gpt0, 1 }, { /* END */ } }}; static struct action_kw_list tcp_req_kws = { { }, { { "sc-inc-gpc0", parse_inc_gpc0, 1 }, + { "sc-inc-gpc1", parse_inc_gpc1, 1 }, { "sc-set-gpt0", parse_set_gpt0, 1 }, { /* END */ } }}; static struct action_kw_list tcp_res_kws = { { }, { { "sc-inc-gpc0", parse_inc_gpc0, 1 }, + { "sc-inc-gpc1", parse_inc_gpc1, 1 }, { "sc-set-gpt0", parse_set_gpt0, 1 }, { /* END */ } }}; static struct action_kw_list http_req_kws = { { }, { { "sc-inc-gpc0", parse_inc_gpc0, 1 }, + { "sc-inc-gpc1", parse_inc_gpc1, 1 }, { "sc-set-gpt0", parse_set_gpt0, 1 }, { /* END */ } }}; static struct action_kw_list http_res_kws = { { }, { { "sc-inc-gpc0", parse_inc_gpc0, 1 }, + { "sc-inc-gpc1", parse_inc_gpc1, 1 }, { "sc-set-gpt0", parse_set_gpt0, 1 }, { /* END */ } }}; @@ -3330,17 +3672,21 @@ 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_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, }, { "sc_conn_cur", smp_fetch_sc_conn_cur, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, }, { "sc_conn_rate", smp_fetch_sc_conn_rate, ARG2(1,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_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_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, }, { "sc_http_err_rate", smp_fetch_sc_http_err_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_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, }, { "sc_kbytes_out", smp_fetch_sc_kbytes_out, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, }, { "sc_sess_cnt", smp_fetch_sc_sess_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, }, @@ -3350,17 +3696,21 @@ static struct sample_fetch_kw_list smp_fetch_keywords = {ILH, { { "sc0_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, }, { "sc0_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, }, { "sc0_clr_gpc0", smp_fetch_sc_clr_gpc0, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, }, + { "sc0_clr_gpc1", smp_fetch_sc_clr_gpc1, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, }, { "sc0_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, }, { "sc0_conn_cur", smp_fetch_sc_conn_cur, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, }, { "sc0_conn_rate", smp_fetch_sc_conn_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, }, { "sc0_get_gpt0", smp_fetch_sc_get_gpt0, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, }, { "sc0_get_gpc0", smp_fetch_sc_get_gpc0, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, }, + { "sc0_get_gpc1", smp_fetch_sc_get_gpc1, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, }, { "sc0_gpc0_rate", smp_fetch_sc_gpc0_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, }, + { "sc0_gpc1_rate", smp_fetch_sc_gpc1_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, }, { "sc0_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, }, { "sc0_http_err_rate", smp_fetch_sc_http_err_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, }, { "sc0_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, }, { "sc0_http_req_rate", smp_fetch_sc_http_req_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, }, { "sc0_inc_gpc0", smp_fetch_sc_inc_gpc0, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, }, + { "sc0_inc_gpc1", smp_fetch_sc_inc_gpc1, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, }, { "sc0_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, }, { "sc0_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, }, { "sc0_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, }, @@ -3370,17 +3720,21 @@ static struct sample_fetch_kw_list smp_fetch_keywords = {ILH, { { "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_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, }, { "sc1_conn_cur", smp_fetch_sc_conn_cur, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, }, { "sc1_conn_rate", smp_fetch_sc_conn_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, }, { "sc1_get_gpt0", smp_fetch_sc_get_gpt0, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, }, { "sc1_get_gpc0", smp_fetch_sc_get_gpc0, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, }, + { "sc1_get_gpc1", smp_fetch_sc_get_gpc1, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, }, { "sc1_gpc0_rate", smp_fetch_sc_gpc0_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, }, + { "sc1_gpc1_rate", smp_fetch_sc_gpc1_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, }, { "sc1_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, }, { "sc1_http_err_rate", smp_fetch_sc_http_err_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, }, { "sc1_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, }, { "sc1_http_req_rate", smp_fetch_sc_http_req_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, }, { "sc1_inc_gpc0", smp_fetch_sc_inc_gpc0, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, }, + { "sc1_inc_gpc1", smp_fetch_sc_inc_gpc1, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, }, { "sc1_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, }, { "sc1_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, }, { "sc1_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, }, @@ -3390,17 +3744,21 @@ static struct sample_fetch_kw_list smp_fetch_keywords = {ILH, { { "sc2_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, }, { "sc2_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, }, { "sc2_clr_gpc0", smp_fetch_sc_clr_gpc0, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, }, + { "sc2_clr_gpc1", smp_fetch_sc_clr_gpc1, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, }, { "sc2_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, }, { "sc2_conn_cur", smp_fetch_sc_conn_cur, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, }, { "sc2_conn_rate", smp_fetch_sc_conn_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, }, { "sc2_get_gpt0", smp_fetch_sc_get_gpt0, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, }, { "sc2_get_gpc0", smp_fetch_sc_get_gpc0, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, }, + { "sc2_get_gpc1", smp_fetch_sc_get_gpc1, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, }, { "sc2_gpc0_rate", smp_fetch_sc_gpc0_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, }, + { "sc2_gpc1_rate", smp_fetch_sc_gpc1_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, }, { "sc2_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, }, { "sc2_http_err_rate", smp_fetch_sc_http_err_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, }, { "sc2_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, }, { "sc2_http_req_rate", smp_fetch_sc_http_req_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, }, { "sc2_inc_gpc0", smp_fetch_sc_inc_gpc0, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, }, + { "sc2_inc_gpc1", smp_fetch_sc_inc_gpc1, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, }, { "sc2_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, }, { "sc2_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, }, { "sc2_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, }, @@ -3410,17 +3768,21 @@ static struct sample_fetch_kw_list smp_fetch_keywords = {ILH, { { "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_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, }, { "src_conn_cur", smp_fetch_sc_conn_cur, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, }, { "src_conn_rate", smp_fetch_sc_conn_rate, ARG1(1,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_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_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, }, { "src_http_err_rate", smp_fetch_sc_http_err_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_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, }, { "src_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, }, { "src_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, }, @@ -3442,7 +3804,9 @@ 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_gpt0", sample_conv_table_gpt0, ARG1(1,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_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 }, { "table_http_err_rate", sample_conv_table_http_err_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT }, { "table_http_req_cnt", sample_conv_table_http_req_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },