blob: 09c7c74316430cea105cd7202d2be98120d7ed94 [file] [log] [blame]
Emeric Brun3bd697e2010-01-04 15:23:48 +01001/*
2 * Stick tables management functions.
3 *
4 * Copyright 2009-2010 EXCELIANCE, Emeric Brun <ebrun@exceliance.fr>
Willy Tarreau08d5f982010-06-06 13:34:54 +02005 * Copyright (C) 2010 Willy Tarreau <w@1wt.eu>
Emeric Brun3bd697e2010-01-04 15:23:48 +01006 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version
10 * 2 of the License, or (at your option) any later version.
11 *
12 */
13
14#include <string.h>
Willy Tarreauf13ebdf2016-11-22 18:00:53 +010015#include <errno.h>
Emeric Brun3bd697e2010-01-04 15:23:48 +010016
Willy Tarreaub2551052020-06-09 09:07:15 +020017#include <import/ebmbtree.h>
18#include <import/ebsttree.h>
19#include <import/ebistree.h>
20
Willy Tarreau4c7e4b72020-05-27 12:58:42 +020021#include <haproxy/api.h>
Willy Tarreau3c69e082022-05-03 11:35:07 +020022#include <haproxy/applet.h>
Willy Tarreaub2551052020-06-09 09:07:15 +020023#include <haproxy/arg.h>
Willy Tarreau6be78492020-06-05 00:00:29 +020024#include <haproxy/cfgparse.h>
Willy Tarreau83487a82020-06-04 20:19:54 +020025#include <haproxy/cli.h>
Thayne McCombs92149f92020-11-20 01:28:26 -070026#include <haproxy/dict.h>
Willy Tarreau36979d92020-06-05 17:27:29 +020027#include <haproxy/errors.h>
Willy Tarreauf268ee82020-06-04 17:05:57 +020028#include <haproxy/global.h>
Willy Tarreauc761f842020-06-04 11:40:28 +020029#include <haproxy/http_rules.h>
Willy Tarreau853b2972020-05-27 18:01:47 +020030#include <haproxy/list.h>
Willy Tarreauaeed4a82020-06-04 22:01:04 +020031#include <haproxy/log.h>
Willy Tarreau6131d6a2020-06-02 16:48:09 +020032#include <haproxy/net_helper.h>
Willy Tarreau3c2a7c22020-06-04 18:38:21 +020033#include <haproxy/peers.h>
Willy Tarreaub2551052020-06-09 09:07:15 +020034#include <haproxy/pool.h>
35#include <haproxy/proto_tcp.h>
Willy Tarreaua264d962020-06-04 22:29:18 +020036#include <haproxy/proxy.h>
Willy Tarreaub2551052020-06-09 09:07:15 +020037#include <haproxy/sample.h>
Willy Tarreau5edca2f2022-05-27 09:25:10 +020038#include <haproxy/sc_strm.h>
Willy Tarreau2eec9b52020-06-04 19:58:55 +020039#include <haproxy/stats-t.h>
Willy Tarreaucb086c62022-05-27 09:47:12 +020040#include <haproxy/stconn.h>
Willy Tarreaub2551052020-06-09 09:07:15 +020041#include <haproxy/stick_table.h>
Willy Tarreaudfd3de82020-06-04 23:46:14 +020042#include <haproxy/stream.h>
Willy Tarreaucea0e1b2020-06-04 17:25:40 +020043#include <haproxy/task.h>
Willy Tarreau8b550af2020-06-04 17:42:48 +020044#include <haproxy/tcp_rules.h>
Willy Tarreau9310f482021-10-06 16:18:40 +020045#include <haproxy/ticks.h>
Willy Tarreaub2551052020-06-09 09:07:15 +020046#include <haproxy/tools.h>
Willy Tarreaua4728582022-11-24 07:35:17 +010047#include <haproxy/xxhash.h>
Emeric Brun3bd697e2010-01-04 15:23:48 +010048
Emeric Brun3bd697e2010-01-04 15:23:48 +010049
Willy Tarreau12785782012-04-27 21:37:17 +020050/* structure used to return a table key built from a sample */
Emeric Brun819fc6f2017-06-13 19:37:32 +020051static THREAD_LOCAL struct stktable_key static_table_key;
Willy Tarreau478331d2020-08-28 11:31:31 +020052static int (*smp_fetch_src)(const struct arg *, struct sample *, const char *, void *);
Willy Tarreau6c011712023-01-06 16:09:58 +010053struct pool_head *pool_head_stk_ctr __read_mostly = NULL;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +010054struct stktable *stktables_list;
55struct eb_root stktable_by_name = EB_ROOT;
56
Olivier Houchard52dabbc2018-11-14 17:54:36 +010057#define round_ptr_size(i) (((i) + (sizeof(void *) - 1)) &~ (sizeof(void *) - 1))
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +010058
59/* This function inserts stktable <t> into the tree of known stick-table.
60 * The stick-table ID is used as the storing key so it must already have
61 * been initialized.
62 */
63void stktable_store_name(struct stktable *t)
64{
65 t->name.key = t->id;
66 ebis_insert(&stktable_by_name, &t->name);
67}
68
69struct stktable *stktable_find_by_name(const char *name)
70{
71 struct ebpt_node *node;
72 struct stktable *t;
73
74 node = ebis_lookup(&stktable_by_name, name);
75 if (node) {
76 t = container_of(node, struct stktable, name);
Tim Duesterhuse5ff1412021-01-02 22:31:53 +010077 if (strcmp(t->id, name) == 0)
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +010078 return t;
79 }
80
81 return NULL;
82}
83
Emeric Brun3bd697e2010-01-04 15:23:48 +010084/*
Willy Tarreauaea940e2010-06-06 11:56:36 +020085 * Free an allocated sticky session <ts>, and decrease sticky sessions counter
Willy Tarreau996f1a52022-10-11 16:19:35 +020086 * in table <t>. It's safe to call it under or out of a lock.
Emeric Brun3bd697e2010-01-04 15:23:48 +010087 */
Emeric Brun819fc6f2017-06-13 19:37:32 +020088void __stksess_free(struct stktable *t, struct stksess *ts)
Emeric Brun3bd697e2010-01-04 15:23:48 +010089{
Willy Tarreau996f1a52022-10-11 16:19:35 +020090 HA_ATOMIC_DEC(&t->current);
Olivier Houchard52dabbc2018-11-14 17:54:36 +010091 pool_free(t->pool, (void *)ts - round_ptr_size(t->data_size));
Emeric Brun3bd697e2010-01-04 15:23:48 +010092}
93
94/*
Emeric Brun819fc6f2017-06-13 19:37:32 +020095 * Free an allocated sticky session <ts>, and decrease sticky sessions counter
96 * in table <t>.
97 * This function locks the table
98 */
99void stksess_free(struct stktable *t, struct stksess *ts)
100{
Thayne McCombs92149f92020-11-20 01:28:26 -0700101 void *data;
102 data = stktable_data_ptr(t, ts, STKTABLE_DT_SERVER_KEY);
103 if (data) {
Emeric Brun0e3457b2021-06-30 17:18:28 +0200104 dict_entry_unref(&server_key_dict, stktable_data_cast(data, std_t_dict));
105 stktable_data_cast(data, std_t_dict) = NULL;
Thayne McCombs92149f92020-11-20 01:28:26 -0700106 }
Willy Tarreau8d3c3332022-10-11 18:50:22 +0000107 HA_RWLOCK_RDLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200108 __stksess_free(t, ts);
Willy Tarreau8d3c3332022-10-11 18:50:22 +0000109 HA_RWLOCK_RDUNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200110}
111
112/*
Willy Tarreauf6efda12010-08-03 20:34:06 +0200113 * Kill an stksess (only if its ref_cnt is zero).
114 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200115int __stksess_kill(struct stktable *t, struct stksess *ts)
Willy Tarreauf6efda12010-08-03 20:34:06 +0200116{
117 if (ts->ref_cnt)
Emeric Brun819fc6f2017-06-13 19:37:32 +0200118 return 0;
Willy Tarreauf6efda12010-08-03 20:34:06 +0200119
120 eb32_delete(&ts->exp);
Emeric Brun85e77c72010-09-23 18:16:52 +0200121 eb32_delete(&ts->upd);
Willy Tarreauf6efda12010-08-03 20:34:06 +0200122 ebmb_delete(&ts->key);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200123 __stksess_free(t, ts);
124 return 1;
Willy Tarreauf6efda12010-08-03 20:34:06 +0200125}
126
127/*
Emeric Brun819fc6f2017-06-13 19:37:32 +0200128 * Decrease the refcount if decrefcnt is not 0.
129 * and try to kill the stksess
130 * This function locks the table
131 */
132int stksess_kill(struct stktable *t, struct stksess *ts, int decrefcnt)
133{
134 int ret;
135
Willy Tarreau76642222022-10-11 12:02:50 +0200136 HA_RWLOCK_WRLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200137 if (decrefcnt)
138 ts->ref_cnt--;
139 ret = __stksess_kill(t, ts);
Willy Tarreau76642222022-10-11 12:02:50 +0200140 HA_RWLOCK_WRUNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200141
142 return ret;
143}
144
145/*
Willy Tarreauaea940e2010-06-06 11:56:36 +0200146 * Initialize or update the key in the sticky session <ts> present in table <t>
147 * from the value present in <key>.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100148 */
Willy Tarreau393379c2010-06-06 12:11:37 +0200149void stksess_setkey(struct stktable *t, struct stksess *ts, struct stktable_key *key)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100150{
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200151 if (t->type != SMP_T_STR)
Willy Tarreau86257dc2010-06-06 12:57:10 +0200152 memcpy(ts->key.key, key->key, t->key_size);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100153 else {
Willy Tarreau86257dc2010-06-06 12:57:10 +0200154 memcpy(ts->key.key, key->key, MIN(t->key_size - 1, key->key_len));
155 ts->key.key[MIN(t->key_size - 1, key->key_len)] = 0;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100156 }
157}
158
Willy Tarreaud5cae6a2022-11-29 17:36:44 +0100159/* return a shard number for key <key> of len <len> present in table <t>. This
160 * takes into account the presence or absence of a peers section with shards
161 * and the number of shards, the table's hash_seed, and of course the key. The
162 * caller must pass a valid <key> and <len>. The shard number to be used by the
163 * entry is returned (from 1 to nb_shards, otherwise 0 for none).
Frédéric Lécaille36d15652022-10-17 14:58:19 +0200164 */
Willy Tarreaud5cae6a2022-11-29 17:36:44 +0100165int stktable_get_key_shard(struct stktable *t, const void *key, size_t len)
Frédéric Lécaille36d15652022-10-17 14:58:19 +0200166{
Willy Tarreaud5cae6a2022-11-29 17:36:44 +0100167 /* no peers section or no shards in the peers section */
168 if (!t->peers.p || !t->peers.p->nb_shards)
169 return 0;
Frédéric Lécaille36d15652022-10-17 14:58:19 +0200170
Willy Tarreaud5cae6a2022-11-29 17:36:44 +0100171 return XXH64(key, len, t->hash_seed) % t->peers.p->nb_shards + 1;
Frédéric Lécaille36d15652022-10-17 14:58:19 +0200172}
Emeric Brun3bd697e2010-01-04 15:23:48 +0100173
174/*
Frédéric Lécaille36d15652022-10-17 14:58:19 +0200175 * Set the shard for <key> key of <ts> sticky session attached to <t> stick table.
Willy Tarreaud5cae6a2022-11-29 17:36:44 +0100176 * Use zero for stick-table without peers synchronisation.
Frédéric Lécaille36d15652022-10-17 14:58:19 +0200177 */
178static void stksess_setkey_shard(struct stktable *t, struct stksess *ts,
179 struct stktable_key *key)
180{
Willy Tarreaud5cae6a2022-11-29 17:36:44 +0100181 size_t keylen;
Frédéric Lécaille36d15652022-10-17 14:58:19 +0200182
Willy Tarreaud5cae6a2022-11-29 17:36:44 +0100183 if (t->type == SMP_T_STR)
184 keylen = key->key_len;
Frédéric Lécaille36d15652022-10-17 14:58:19 +0200185 else
Willy Tarreaud5cae6a2022-11-29 17:36:44 +0100186 keylen = t->key_size;
187
188 ts->shard = stktable_get_key_shard(t, key->key, keylen);
Frédéric Lécaille36d15652022-10-17 14:58:19 +0200189}
190
191/*
Willy Tarreau393379c2010-06-06 12:11:37 +0200192 * Init sticky session <ts> of table <t>. The data parts are cleared and <ts>
193 * is returned.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100194 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200195static struct stksess *__stksess_init(struct stktable *t, struct stksess * ts)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100196{
Willy Tarreau393379c2010-06-06 12:11:37 +0200197 memset((void *)ts - t->data_size, 0, t->data_size);
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200198 ts->ref_cnt = 0;
Willy Tarreaue548a7a2022-11-29 16:08:35 +0100199 ts->shard = 0;
Willy Tarreau86257dc2010-06-06 12:57:10 +0200200 ts->key.node.leaf_p = NULL;
201 ts->exp.node.leaf_p = NULL;
Emeric Brun85e77c72010-09-23 18:16:52 +0200202 ts->upd.node.leaf_p = NULL;
Emeric Brun819fc6f2017-06-13 19:37:32 +0200203 ts->expire = tick_add(now_ms, MS_TO_TICKS(t->expire));
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100204 HA_RWLOCK_INIT(&ts->lock);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100205 return ts;
206}
207
208/*
Willy Tarreauaea940e2010-06-06 11:56:36 +0200209 * Trash oldest <to_batch> sticky sessions from table <t>
Willy Tarreaudfe79252020-11-03 17:47:41 +0100210 * Returns number of trashed sticky sessions. It may actually trash less
211 * than expected if finding these requires too long a search time (e.g.
212 * most of them have ts->ref_cnt>0).
Emeric Brun3bd697e2010-01-04 15:23:48 +0100213 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200214int __stktable_trash_oldest(struct stktable *t, int to_batch)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100215{
216 struct stksess *ts;
217 struct eb32_node *eb;
Willy Tarreaudfe79252020-11-03 17:47:41 +0100218 int max_search = to_batch * 2; // no more than 50% misses
Emeric Brun3bd697e2010-01-04 15:23:48 +0100219 int batched = 0;
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200220 int looped = 0;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100221
222 eb = eb32_lookup_ge(&t->exps, now_ms - TIMER_LOOK_BACK);
223
224 while (batched < to_batch) {
225
226 if (unlikely(!eb)) {
227 /* we might have reached the end of the tree, typically because
228 * <now_ms> is in the first half and we're first scanning the last
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200229 * half. Let's loop back to the beginning of the tree now if we
230 * have not yet visited it.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100231 */
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200232 if (looped)
233 break;
234 looped = 1;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100235 eb = eb32_first(&t->exps);
236 if (likely(!eb))
237 break;
238 }
239
Willy Tarreaudfe79252020-11-03 17:47:41 +0100240 if (--max_search < 0)
241 break;
242
Emeric Brun3bd697e2010-01-04 15:23:48 +0100243 /* timer looks expired, detach it from the queue */
Willy Tarreau86257dc2010-06-06 12:57:10 +0200244 ts = eb32_entry(eb, struct stksess, exp);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100245 eb = eb32_next(eb);
246
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200247 /* don't delete an entry which is currently referenced */
248 if (ts->ref_cnt)
249 continue;
250
Willy Tarreau86257dc2010-06-06 12:57:10 +0200251 eb32_delete(&ts->exp);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100252
Willy Tarreau86257dc2010-06-06 12:57:10 +0200253 if (ts->expire != ts->exp.key) {
Emeric Brun3bd697e2010-01-04 15:23:48 +0100254 if (!tick_isset(ts->expire))
255 continue;
256
Willy Tarreau86257dc2010-06-06 12:57:10 +0200257 ts->exp.key = ts->expire;
258 eb32_insert(&t->exps, &ts->exp);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100259
Willy Tarreau86257dc2010-06-06 12:57:10 +0200260 if (!eb || eb->key > ts->exp.key)
261 eb = &ts->exp;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100262
263 continue;
264 }
Emeric Brun3bd697e2010-01-04 15:23:48 +0100265
Willy Tarreauaea940e2010-06-06 11:56:36 +0200266 /* session expired, trash it */
Willy Tarreau86257dc2010-06-06 12:57:10 +0200267 ebmb_delete(&ts->key);
Emeric Brun85e77c72010-09-23 18:16:52 +0200268 eb32_delete(&ts->upd);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200269 __stksess_free(t, ts);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100270 batched++;
271 }
272
273 return batched;
274}
275
276/*
Emeric Brun819fc6f2017-06-13 19:37:32 +0200277 * Trash oldest <to_batch> sticky sessions from table <t>
278 * Returns number of trashed sticky sessions.
279 * This function locks the table
280 */
281int stktable_trash_oldest(struct stktable *t, int to_batch)
282{
283 int ret;
284
Willy Tarreau76642222022-10-11 12:02:50 +0200285 HA_RWLOCK_WRLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200286 ret = __stktable_trash_oldest(t, to_batch);
Willy Tarreau76642222022-10-11 12:02:50 +0200287 HA_RWLOCK_WRUNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200288
289 return ret;
290}
291/*
Willy Tarreauaea940e2010-06-06 11:56:36 +0200292 * Allocate and initialise a new sticky session.
293 * The new sticky session is returned or NULL in case of lack of memory.
294 * Sticky sessions should only be allocated this way, and must be freed using
Willy Tarreaua7b46b52013-04-11 16:55:37 +0200295 * stksess_free(). Table <t>'s sticky session counter is increased. If <key>
Willy Tarreau996f1a52022-10-11 16:19:35 +0200296 * is not NULL, it is assigned to the new session. It must be called unlocked
297 * as it may rely on a lock to trash older entries.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100298 */
Willy Tarreau996f1a52022-10-11 16:19:35 +0200299struct stksess *stksess_new(struct stktable *t, struct stktable_key *key)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100300{
301 struct stksess *ts;
Willy Tarreau996f1a52022-10-11 16:19:35 +0200302 unsigned int current;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100303
Willy Tarreau996f1a52022-10-11 16:19:35 +0200304 current = HA_ATOMIC_FETCH_ADD(&t->current, 1);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100305
Willy Tarreau996f1a52022-10-11 16:19:35 +0200306 if (unlikely(current >= t->size)) {
307 /* the table was already full, we may have to purge entries */
308 if (t->nopurge || !stktable_trash_oldest(t, (t->size >> 8) + 1)) {
309 HA_ATOMIC_DEC(&t->current);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100310 return NULL;
Willy Tarreau996f1a52022-10-11 16:19:35 +0200311 }
Emeric Brun3bd697e2010-01-04 15:23:48 +0100312 }
313
Willy Tarreaubafbe012017-11-24 17:34:44 +0100314 ts = pool_alloc(t->pool);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100315 if (ts) {
Olivier Houchard52dabbc2018-11-14 17:54:36 +0100316 ts = (void *)ts + round_ptr_size(t->data_size);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200317 __stksess_init(t, ts);
Frédéric Lécaille36d15652022-10-17 14:58:19 +0200318 if (key) {
Willy Tarreaua7b46b52013-04-11 16:55:37 +0200319 stksess_setkey(t, ts, key);
Frédéric Lécaille36d15652022-10-17 14:58:19 +0200320 stksess_setkey_shard(t, ts, key);
321 }
Emeric Brun3bd697e2010-01-04 15:23:48 +0100322 }
323
324 return ts;
325}
326
327/*
Willy Tarreauf16d2b82010-06-06 15:38:59 +0200328 * Looks in table <t> for a sticky session matching key <key>.
Willy Tarreauaea940e2010-06-06 11:56:36 +0200329 * Returns pointer on requested sticky session or NULL if none was found.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100330 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200331struct stksess *__stktable_lookup_key(struct stktable *t, struct stktable_key *key)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100332{
333 struct ebmb_node *eb;
334
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200335 if (t->type == SMP_T_STR)
Emeric Brun485479d2010-09-23 18:02:19 +0200336 eb = ebst_lookup_len(&t->keys, key->key, key->key_len+1 < t->key_size ? key->key_len : t->key_size-1);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100337 else
338 eb = ebmb_lookup(&t->keys, key->key, t->key_size);
339
340 if (unlikely(!eb)) {
341 /* no session found */
342 return NULL;
343 }
344
Willy Tarreau86257dc2010-06-06 12:57:10 +0200345 return ebmb_entry(eb, struct stksess, key);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100346}
347
Emeric Brun819fc6f2017-06-13 19:37:32 +0200348/*
349 * Looks in table <t> for a sticky session matching key <key>.
350 * Returns pointer on requested sticky session or NULL if none was found.
351 * The refcount of the found entry is increased and this function
352 * is protected using the table lock
Willy Tarreau1f7e9252010-06-20 12:27:21 +0200353 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200354struct stksess *stktable_lookup_key(struct stktable *t, struct stktable_key *key)
Willy Tarreau1f7e9252010-06-20 12:27:21 +0200355{
356 struct stksess *ts;
357
Willy Tarreaua7d6a132022-10-11 15:42:54 +0200358 HA_RWLOCK_RDLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200359 ts = __stktable_lookup_key(t, key);
360 if (ts)
Willy Tarreaua7d6a132022-10-11 15:42:54 +0200361 HA_ATOMIC_INC(&ts->ref_cnt);
362 HA_RWLOCK_RDUNLOCK(STK_TABLE_LOCK, &t->lock);
Willy Tarreau1f7e9252010-06-20 12:27:21 +0200363
Willy Tarreau1f7e9252010-06-20 12:27:21 +0200364 return ts;
365}
366
Willy Tarreauf16d2b82010-06-06 15:38:59 +0200367/*
368 * Looks in table <t> for a sticky session with same key as <ts>.
369 * Returns pointer on requested sticky session or NULL if none was found.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100370 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200371struct stksess *__stktable_lookup(struct stktable *t, struct stksess *ts)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100372{
Emeric Brun3bd697e2010-01-04 15:23:48 +0100373 struct ebmb_node *eb;
374
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200375 if (t->type == SMP_T_STR)
Willy Tarreau86257dc2010-06-06 12:57:10 +0200376 eb = ebst_lookup(&(t->keys), (char *)ts->key.key);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100377 else
Willy Tarreau86257dc2010-06-06 12:57:10 +0200378 eb = ebmb_lookup(&(t->keys), ts->key.key, t->key_size);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100379
Willy Tarreauf16d2b82010-06-06 15:38:59 +0200380 if (unlikely(!eb))
381 return NULL;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100382
Willy Tarreauf16d2b82010-06-06 15:38:59 +0200383 return ebmb_entry(eb, struct stksess, key);
384}
Emeric Brun3bd697e2010-01-04 15:23:48 +0100385
Emeric Brun819fc6f2017-06-13 19:37:32 +0200386/*
387 * Looks in table <t> for a sticky session with same key as <ts>.
388 * Returns pointer on requested sticky session or NULL if none was found.
389 * The refcount of the found entry is increased and this function
390 * is protected using the table lock
391 */
392struct stksess *stktable_lookup(struct stktable *t, struct stksess *ts)
393{
394 struct stksess *lts;
395
Willy Tarreaua7d6a132022-10-11 15:42:54 +0200396 HA_RWLOCK_RDLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200397 lts = __stktable_lookup(t, ts);
398 if (lts)
Willy Tarreaua7d6a132022-10-11 15:42:54 +0200399 HA_ATOMIC_INC(&lts->ref_cnt);
400 HA_RWLOCK_RDUNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200401
402 return lts;
403}
404
Willy Tarreaucb183642010-06-06 17:58:34 +0200405/* Update the expiration timer for <ts> but do not touch its expiration node.
406 * The table's expiration timer is updated if set.
Emeric Brun819fc6f2017-06-13 19:37:32 +0200407 * The node will be also inserted into the update tree if needed, at a position
Willy Tarreau9f5cb432022-10-11 18:17:58 +0000408 * depending if the update is a local or coming from a remote node.
409 * If <decrefcnt> is set, the ts entry's ref_cnt will be decremented. The table's
410 * write lock may be taken.
Willy Tarreaucb183642010-06-06 17:58:34 +0200411 */
Willy Tarreau9f5cb432022-10-11 18:17:58 +0000412void stktable_touch_with_exp(struct stktable *t, struct stksess *ts, int local, int expire, int decrefcnt)
Willy Tarreaucb183642010-06-06 17:58:34 +0200413{
Emeric Brun85e77c72010-09-23 18:16:52 +0200414 struct eb32_node * eb;
Willy Tarreaua7536ef2022-10-11 18:31:04 +0000415 int locked = 0;
Willy Tarreau9f5cb432022-10-11 18:17:58 +0000416
Willy Tarreaua7536ef2022-10-11 18:31:04 +0000417 if (expire != HA_ATOMIC_LOAD(&ts->expire)) {
418 /* we'll need to set the expiration and to wake up the expiration timer .*/
419 HA_ATOMIC_STORE(&ts->expire, expire);
Willy Tarreaudbae89e2022-10-12 10:00:50 +0000420 stktable_requeue_exp(t, ts);
Willy Tarreaucb183642010-06-06 17:58:34 +0200421 }
Emeric Brun85e77c72010-09-23 18:16:52 +0200422
Emeric Brun819fc6f2017-06-13 19:37:32 +0200423 /* If sync is enabled */
424 if (t->sync_task) {
425 if (local) {
426 /* If this entry is not in the tree
Willy Tarreaua7536ef2022-10-11 18:31:04 +0000427 * or not scheduled for at least one peer.
428 */
429 if (!locked++)
430 HA_RWLOCK_WRLOCK(STK_TABLE_LOCK, &t->lock);
431
Emeric Brun819fc6f2017-06-13 19:37:32 +0200432 if (!ts->upd.node.leaf_p
433 || (int)(t->commitupdate - ts->upd.key) >= 0
434 || (int)(ts->upd.key - t->localupdate) >= 0) {
435 ts->upd.key = ++t->update;
436 t->localupdate = t->update;
437 eb32_delete(&ts->upd);
438 eb = eb32_insert(&t->updates, &ts->upd);
439 if (eb != &ts->upd) {
440 eb32_delete(eb);
441 eb32_insert(&t->updates, &ts->upd);
442 }
Emeric Brunaaf58602015-06-15 17:23:30 +0200443 }
Emeric Brun819fc6f2017-06-13 19:37:32 +0200444 task_wakeup(t->sync_task, TASK_WOKEN_MSG);
Emeric Brun85e77c72010-09-23 18:16:52 +0200445 }
Emeric Brun819fc6f2017-06-13 19:37:32 +0200446 else {
447 /* If this entry is not in the tree */
Willy Tarreaua7536ef2022-10-11 18:31:04 +0000448 if (!locked++)
449 HA_RWLOCK_WRLOCK(STK_TABLE_LOCK, &t->lock);
450
Emeric Brun819fc6f2017-06-13 19:37:32 +0200451 if (!ts->upd.node.leaf_p) {
452 ts->upd.key= (++t->update)+(2147483648U);
453 eb = eb32_insert(&t->updates, &ts->upd);
454 if (eb != &ts->upd) {
455 eb32_delete(eb);
456 eb32_insert(&t->updates, &ts->upd);
457 }
458 }
459 }
Emeric Brun85e77c72010-09-23 18:16:52 +0200460 }
Willy Tarreau9f5cb432022-10-11 18:17:58 +0000461
Willy Tarreaua7536ef2022-10-11 18:31:04 +0000462 if (decrefcnt) {
463 if (locked)
464 ts->ref_cnt--;
465 else {
466 HA_RWLOCK_RDLOCK(STK_TABLE_LOCK, &t->lock);
467 HA_ATOMIC_DEC(&ts->ref_cnt);
468 HA_RWLOCK_RDUNLOCK(STK_TABLE_LOCK, &t->lock);
469 }
470 }
471
472 if (locked)
473 HA_RWLOCK_WRUNLOCK(STK_TABLE_LOCK, &t->lock);
Willy Tarreaucb183642010-06-06 17:58:34 +0200474}
475
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200476/* Update the expiration timer for <ts> but do not touch its expiration node.
Emeric Brun819fc6f2017-06-13 19:37:32 +0200477 * The table's expiration timer is updated using the date of expiration coming from
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200478 * <t> stick-table configuration.
Emeric Brun819fc6f2017-06-13 19:37:32 +0200479 * The node will be also inserted into the update tree if needed, at a position
480 * considering the update is coming from a remote node
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200481 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200482void stktable_touch_remote(struct stktable *t, struct stksess *ts, int decrefcnt)
483{
Willy Tarreau9f5cb432022-10-11 18:17:58 +0000484 stktable_touch_with_exp(t, ts, 0, ts->expire, decrefcnt);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200485}
486
487/* Update the expiration timer for <ts> but do not touch its expiration node.
488 * The table's expiration timer is updated using the date of expiration coming from
489 * <t> stick-table configuration.
490 * The node will be also inserted into the update tree if needed, at a position
491 * considering the update was made locally
492 */
493void stktable_touch_local(struct stktable *t, struct stksess *ts, int decrefcnt)
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200494{
495 int expire = tick_add(now_ms, MS_TO_TICKS(t->expire));
496
Willy Tarreau9f5cb432022-10-11 18:17:58 +0000497 stktable_touch_with_exp(t, ts, 1, expire, decrefcnt);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200498}
Willy Tarreau4be073b2022-10-11 18:10:27 +0000499/* Just decrease the ref_cnt of the current session. Does nothing if <ts> is NULL.
500 * Note that we still need to take the read lock because a number of other places
501 * (including in Lua and peers) update the ref_cnt non-atomically under the write
502 * lock.
503 */
Willy Tarreau43e90352018-06-27 06:25:57 +0200504static void stktable_release(struct stktable *t, struct stksess *ts)
Emeric Brun819fc6f2017-06-13 19:37:32 +0200505{
Willy Tarreau43e90352018-06-27 06:25:57 +0200506 if (!ts)
507 return;
Willy Tarreau4be073b2022-10-11 18:10:27 +0000508 HA_RWLOCK_RDLOCK(STK_TABLE_LOCK, &t->lock);
509 HA_ATOMIC_DEC(&ts->ref_cnt);
510 HA_RWLOCK_RDUNLOCK(STK_TABLE_LOCK, &t->lock);
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200511}
512
Willy Tarreauf16d2b82010-06-06 15:38:59 +0200513/* Insert new sticky session <ts> in the table. It is assumed that it does not
514 * yet exist (the caller must check this). The table's timeout is updated if it
Willy Tarreaud2d3fd92022-10-11 15:09:46 +0200515 * is set. <ts> is returned if properly inserted, otherwise the one already
516 * present if any.
Willy Tarreauf16d2b82010-06-06 15:38:59 +0200517 */
Willy Tarreaud2d3fd92022-10-11 15:09:46 +0200518struct stksess *__stktable_store(struct stktable *t, struct stksess *ts)
Willy Tarreauf16d2b82010-06-06 15:38:59 +0200519{
Willy Tarreaud2d3fd92022-10-11 15:09:46 +0200520 struct ebmb_node *eb;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100521
Willy Tarreaud2d3fd92022-10-11 15:09:46 +0200522 eb = ebmb_insert(&t->keys, &ts->key, t->key_size);
523 if (likely(eb == &ts->key)) {
524 ts->exp.key = ts->expire;
525 eb32_insert(&t->exps, &ts->exp);
526 }
Willy Tarreaud2d3fd92022-10-11 15:09:46 +0200527 return ebmb_entry(eb, struct stksess, key); // most commonly this is <ts>
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200528}
529
Willy Tarreaueb23e3e2022-10-12 09:56:08 +0000530/* requeues the table's expiration task to take the recently added <ts> into
531 * account. This is performed atomically and doesn't require any lock.
532 */
Willy Tarreaudbae89e2022-10-12 10:00:50 +0000533void stktable_requeue_exp(struct stktable *t, const struct stksess *ts)
Willy Tarreaueb23e3e2022-10-12 09:56:08 +0000534{
Willy Tarreaudbae89e2022-10-12 10:00:50 +0000535 int old_exp, new_exp;
536 int expire = ts->expire;
537
Willy Tarreaueb23e3e2022-10-12 09:56:08 +0000538 if (!t->expire)
539 return;
Willy Tarreaudbae89e2022-10-12 10:00:50 +0000540
Willy Tarreau63427142022-11-14 17:33:02 +0100541 /* set the task's expire to the newest expiration date. */
Willy Tarreaudbae89e2022-10-12 10:00:50 +0000542 old_exp = HA_ATOMIC_LOAD(&t->exp_task->expire);
Willy Tarreau3238f792022-11-14 17:54:07 +0100543 new_exp = tick_first(expire, old_exp);
544
545 /* let's not go further if we're already up to date */
546 if (new_exp == old_exp)
547 return;
548
Willy Tarreaufbb934d2022-11-14 18:02:44 +0100549 HA_RWLOCK_WRLOCK(STK_TABLE_LOCK, &t->lock);
550
Willy Tarreau3238f792022-11-14 17:54:07 +0100551 while (new_exp != old_exp &&
552 !HA_ATOMIC_CAS(&t->exp_task->expire, &old_exp, new_exp)) {
553 __ha_cpu_relax();
Willy Tarreau63427142022-11-14 17:33:02 +0100554 new_exp = tick_first(expire, old_exp);
Willy Tarreau3238f792022-11-14 17:54:07 +0100555 }
Willy Tarreaudbae89e2022-10-12 10:00:50 +0000556
Willy Tarreaueb23e3e2022-10-12 09:56:08 +0000557 task_queue(t->exp_task);
Willy Tarreaufbb934d2022-11-14 18:02:44 +0100558
559 HA_RWLOCK_WRUNLOCK(STK_TABLE_LOCK, &t->lock);
Willy Tarreaueb23e3e2022-10-12 09:56:08 +0000560}
561
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200562/* Returns a valid or initialized stksess for the specified stktable_key in the
563 * specified table, or NULL if the key was NULL, or if no entry was found nor
Willy Tarreau47f22972022-10-11 15:22:42 +0200564 * could be created. The entry's expiration is updated. This function locks the
565 * table, and the refcount of the entry is increased.
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200566 */
Willy Tarreau47f22972022-10-11 15:22:42 +0200567struct stksess *stktable_get_entry(struct stktable *table, struct stktable_key *key)
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200568{
Willy Tarreau175aa062022-10-11 15:13:46 +0200569 struct stksess *ts, *ts2;
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200570
571 if (!key)
572 return NULL;
573
Willy Tarreau47f22972022-10-11 15:22:42 +0200574 ts = stktable_lookup_key(table, key);
575 if (ts)
576 return ts;
Emeric Brun819fc6f2017-06-13 19:37:32 +0200577
Willy Tarreau996f1a52022-10-11 16:19:35 +0200578 /* No such entry exists, let's try to create a new one. this doesn't
579 * require locking yet.
580 */
581
582 ts = stksess_new(table, key);
583 if (!ts)
584 return NULL;
585
586 /* Now we're certain to have a ts. We need to store it. For this we'll
Willy Tarreau47f22972022-10-11 15:22:42 +0200587 * need an exclusive access. We don't need an atomic upgrade, this is
588 * rare and an unlock+lock sequence will do the job fine. Given that
589 * this will not be atomic, the missing entry might appear in the mean
590 * tome so we have to be careful that the one we try to insert is the
591 * one we find.
592 */
Willy Tarreau47f22972022-10-11 15:22:42 +0200593
Willy Tarreau996f1a52022-10-11 16:19:35 +0200594 HA_RWLOCK_WRLOCK(STK_TABLE_LOCK, &table->lock);
Willy Tarreau47f22972022-10-11 15:22:42 +0200595
596 ts2 = __stktable_store(table, ts);
597 if (unlikely(ts2 != ts)) {
598 /* another entry was added in the mean time, let's
599 * switch to it.
600 */
601 __stksess_free(table, ts);
602 ts = ts2;
603 }
604
605 HA_ATOMIC_INC(&ts->ref_cnt);
Willy Tarreau76642222022-10-11 12:02:50 +0200606 HA_RWLOCK_WRUNLOCK(STK_TABLE_LOCK, &table->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200607
Willy Tarreaucbdb5282022-10-12 10:04:01 +0000608 stktable_requeue_exp(table, ts);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200609 return ts;
610}
611
612/* Lookup for an entry with the same key and store the submitted
Willy Tarreaue6288522022-10-12 09:13:14 +0000613 * stksess if not found. This function locks the table either shared or
614 * exclusively, and the refcount of the entry is increased.
Emeric Brun819fc6f2017-06-13 19:37:32 +0200615 */
Willy Tarreaue6288522022-10-12 09:13:14 +0000616struct stksess *stktable_set_entry(struct stktable *table, struct stksess *nts)
Emeric Brun819fc6f2017-06-13 19:37:32 +0200617{
618 struct stksess *ts;
619
Willy Tarreaue6288522022-10-12 09:13:14 +0000620 HA_RWLOCK_RDLOCK(STK_TABLE_LOCK, &table->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200621 ts = __stktable_lookup(table, nts);
Willy Tarreaue6288522022-10-12 09:13:14 +0000622 if (ts) {
623 HA_ATOMIC_INC(&ts->ref_cnt);
624 HA_RWLOCK_RDUNLOCK(STK_TABLE_LOCK, &table->lock);
625 return ts;
Emeric Brun819fc6f2017-06-13 19:37:32 +0200626 }
Willy Tarreaue6288522022-10-12 09:13:14 +0000627 ts = nts;
Emeric Brun819fc6f2017-06-13 19:37:32 +0200628
Willy Tarreaue6288522022-10-12 09:13:14 +0000629 /* let's increment it before switching to exclusive */
630 HA_ATOMIC_INC(&ts->ref_cnt);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200631
Willy Tarreaue6288522022-10-12 09:13:14 +0000632 if (HA_RWLOCK_TRYRDTOSK(STK_TABLE_LOCK, &table->lock) != 0) {
633 /* upgrade to seek lock failed, let's drop and take */
634 HA_RWLOCK_RDUNLOCK(STK_TABLE_LOCK, &table->lock);
635 HA_RWLOCK_WRLOCK(STK_TABLE_LOCK, &table->lock);
636 }
637 else
638 HA_RWLOCK_SKTOWR(STK_TABLE_LOCK, &table->lock);
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200639
Willy Tarreaue6288522022-10-12 09:13:14 +0000640 /* now we're write-locked */
641
642 __stktable_store(table, ts);
643 HA_RWLOCK_WRUNLOCK(STK_TABLE_LOCK, &table->lock);
Willy Tarreaucbdb5282022-10-12 10:04:01 +0000644
645 stktable_requeue_exp(table, ts);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200646 return ts;
647}
Willy Tarreaue6288522022-10-12 09:13:14 +0000648
Emeric Brun3bd697e2010-01-04 15:23:48 +0100649/*
Willy Tarreaufbb934d2022-11-14 18:02:44 +0100650 * Task processing function to trash expired sticky sessions. A pointer to the
651 * task itself is returned since it never dies.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100652 */
Willy Tarreaufbb934d2022-11-14 18:02:44 +0100653struct task *process_table_expire(struct task *task, void *context, unsigned int state)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100654{
Willy Tarreaufbb934d2022-11-14 18:02:44 +0100655 struct stktable *t = context;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100656 struct stksess *ts;
657 struct eb32_node *eb;
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200658 int looped = 0;
Willy Tarreau63427142022-11-14 17:33:02 +0100659 int exp_next;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100660
Willy Tarreau76642222022-10-11 12:02:50 +0200661 HA_RWLOCK_WRLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100662 eb = eb32_lookup_ge(&t->exps, now_ms - TIMER_LOOK_BACK);
663
664 while (1) {
665 if (unlikely(!eb)) {
666 /* we might have reached the end of the tree, typically because
667 * <now_ms> is in the first half and we're first scanning the last
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200668 * half. Let's loop back to the beginning of the tree now if we
669 * have not yet visited it.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100670 */
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200671 if (looped)
672 break;
673 looped = 1;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100674 eb = eb32_first(&t->exps);
675 if (likely(!eb))
676 break;
677 }
678
679 if (likely(tick_is_lt(now_ms, eb->key))) {
680 /* timer not expired yet, revisit it later */
Willy Tarreau63427142022-11-14 17:33:02 +0100681 exp_next = eb->key;
Willy Tarreau4d5f13c2017-11-05 11:04:47 +0100682 goto out_unlock;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100683 }
684
685 /* timer looks expired, detach it from the queue */
Willy Tarreau86257dc2010-06-06 12:57:10 +0200686 ts = eb32_entry(eb, struct stksess, exp);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100687 eb = eb32_next(eb);
688
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200689 /* don't delete an entry which is currently referenced */
690 if (ts->ref_cnt)
691 continue;
692
Willy Tarreau86257dc2010-06-06 12:57:10 +0200693 eb32_delete(&ts->exp);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100694
695 if (!tick_is_expired(ts->expire, now_ms)) {
696 if (!tick_isset(ts->expire))
697 continue;
698
Willy Tarreau86257dc2010-06-06 12:57:10 +0200699 ts->exp.key = ts->expire;
700 eb32_insert(&t->exps, &ts->exp);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100701
Willy Tarreau86257dc2010-06-06 12:57:10 +0200702 if (!eb || eb->key > ts->exp.key)
703 eb = &ts->exp;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100704 continue;
705 }
706
707 /* session expired, trash it */
Willy Tarreau86257dc2010-06-06 12:57:10 +0200708 ebmb_delete(&ts->key);
Emeric Brun85e77c72010-09-23 18:16:52 +0200709 eb32_delete(&ts->upd);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200710 __stksess_free(t, ts);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100711 }
712
713 /* We have found no task to expire in any tree */
Willy Tarreau63427142022-11-14 17:33:02 +0100714 exp_next = TICK_ETERNITY;
Willy Tarreaufbb934d2022-11-14 18:02:44 +0100715
Willy Tarreau4d5f13c2017-11-05 11:04:47 +0100716out_unlock:
Willy Tarreaufbb934d2022-11-14 18:02:44 +0100717 task->expire = exp_next;
Willy Tarreau76642222022-10-11 12:02:50 +0200718 HA_RWLOCK_WRUNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100719 return task;
720}
721
Willy Tarreauaea940e2010-06-06 11:56:36 +0200722/* Perform minimal stick table intializations, report 0 in case of error, 1 if OK. */
Emeric Brun3bd697e2010-01-04 15:23:48 +0100723int stktable_init(struct stktable *t)
724{
Remi Tricot-Le Breton208ff012021-05-12 17:39:04 +0200725 int peers_retval = 0;
Willy Tarreau56460ee2022-11-28 18:53:06 +0100726
727 t->hash_seed = XXH64(t->id, t->idlen, 0);
728
Emeric Brun3bd697e2010-01-04 15:23:48 +0100729 if (t->size) {
Emeric Brun819fc6f2017-06-13 19:37:32 +0200730 t->keys = EB_ROOT_UNIQUE;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100731 memset(&t->exps, 0, sizeof(t->exps));
Emeric Brun1c6235d2015-12-16 15:28:12 +0100732 t->updates = EB_ROOT_UNIQUE;
Amaury Denoyelle3e064882022-10-12 16:47:59 +0200733 HA_RWLOCK_INIT(&t->lock);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100734
Olivier Houchard52dabbc2018-11-14 17:54:36 +0100735 t->pool = create_pool("sticktables", sizeof(struct stksess) + round_ptr_size(t->data_size) + t->key_size, MEM_F_SHARED);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100736
Emeric Brun3bd697e2010-01-04 15:23:48 +0100737 if ( t->expire ) {
Willy Tarreaubeeabf52021-10-01 18:23:30 +0200738 t->exp_task = task_new_anywhere();
Willy Tarreau848522f2018-10-15 11:12:15 +0200739 if (!t->exp_task)
740 return 0;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100741 t->exp_task->process = process_table_expire;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100742 t->exp_task->context = (void *)t;
743 }
Christopher Fauletdfd10ab2021-10-06 14:24:19 +0200744 if (t->peers.p && t->peers.p->peers_fe && !(t->peers.p->peers_fe->flags & (PR_FL_DISABLED|PR_FL_STOPPED))) {
Remi Tricot-Le Breton208ff012021-05-12 17:39:04 +0200745 peers_retval = peers_register_table(t->peers.p, t);
Emeric Brun32da3c42010-09-23 18:39:19 +0200746 }
747
Remi Tricot-Le Breton208ff012021-05-12 17:39:04 +0200748 return (t->pool != NULL) && !peers_retval;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100749 }
750 return 1;
751}
752
753/*
754 * Configuration keywords of known table types
755 */
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200756struct stktable_type stktable_types[SMP_TYPES] = {
757 [SMP_T_SINT] = { "integer", 0, 4 },
758 [SMP_T_IPV4] = { "ip", 0, 4 },
759 [SMP_T_IPV6] = { "ipv6", 0, 16 },
760 [SMP_T_STR] = { "string", STK_F_CUSTOM_KEYSIZE, 32 },
761 [SMP_T_BIN] = { "binary", STK_F_CUSTOM_KEYSIZE, 32 }
762};
Emeric Brun3bd697e2010-01-04 15:23:48 +0100763
764/*
765 * Parse table type configuration.
766 * Returns 0 on successful parsing, else 1.
767 * <myidx> is set at next configuration <args> index.
768 */
769int stktable_parse_type(char **args, int *myidx, unsigned long *type, size_t *key_size)
770{
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200771 for (*type = 0; *type < SMP_TYPES; (*type)++) {
772 if (!stktable_types[*type].kw)
773 continue;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100774 if (strcmp(args[*myidx], stktable_types[*type].kw) != 0)
775 continue;
776
777 *key_size = stktable_types[*type].default_size;
778 (*myidx)++;
779
Willy Tarreauaea940e2010-06-06 11:56:36 +0200780 if (stktable_types[*type].flags & STK_F_CUSTOM_KEYSIZE) {
Emeric Brun3bd697e2010-01-04 15:23:48 +0100781 if (strcmp("len", args[*myidx]) == 0) {
782 (*myidx)++;
783 *key_size = atol(args[*myidx]);
Emeric Brun485479d2010-09-23 18:02:19 +0200784 if (!*key_size)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100785 break;
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200786 if (*type == SMP_T_STR) {
Emeric Brun485479d2010-09-23 18:02:19 +0200787 /* null terminated string needs +1 for '\0'. */
788 (*key_size)++;
789 }
Emeric Brun3bd697e2010-01-04 15:23:48 +0100790 (*myidx)++;
791 }
792 }
793 return 0;
794 }
795 return 1;
796}
797
Emeric Brunc64a2a32021-06-30 18:01:02 +0200798/* reserve some space for data type <type>, there is 2 optionnals
799 * argument at <sa> and <sa2> to configure this data type and
800 * they can be NULL if unused for a given type.
801 * Returns PE_NONE (0) if OK or an error code among :
Willy Tarreau3b63ca22021-05-08 14:10:42 +0200802 * - PE_ENUM_OOR if <type> does not exist
803 * - PE_EXIST if <type> is already registered
Emeric Brunc64a2a32021-06-30 18:01:02 +0200804 * - PE_ARG_NOT_USE if <sa>/<sa2> was provided but not expected
805 * - PE_ARG_MISSING if <sa>/<sa2> was expected but not provided
806 * - PE_ARG_VALUE_OOR if type is an array and <sa> it out of array size range.
Willy Tarreau3b63ca22021-05-08 14:10:42 +0200807 */
Emeric Brunc64a2a32021-06-30 18:01:02 +0200808int stktable_alloc_data_type(struct stktable *t, int type, const char *sa, const char *sa2)
809
Willy Tarreau3b63ca22021-05-08 14:10:42 +0200810{
811 if (type >= STKTABLE_DATA_TYPES)
812 return PE_ENUM_OOR;
813
814 if (t->data_ofs[type])
815 /* already allocated */
816 return PE_EXIST;
817
Emeric Brunc64a2a32021-06-30 18:01:02 +0200818 t->data_nbelem[type] = 1;
819 if (stktable_data_types[type].is_array) {
820 /* arrays take their element count on first argument */
821 if (!sa)
822 return PE_ARG_MISSING;
823 t->data_nbelem[type] = atoi(sa);
824 if (!t->data_nbelem[type] || (t->data_nbelem[type] > STKTABLE_MAX_DT_ARRAY_SIZE))
825 return PE_ARG_VALUE_OOR;
826 sa = sa2;
827 }
828
Willy Tarreau3b63ca22021-05-08 14:10:42 +0200829 switch (stktable_data_types[type].arg_type) {
830 case ARG_T_NONE:
831 if (sa)
832 return PE_ARG_NOT_USED;
833 break;
834 case ARG_T_INT:
835 if (!sa)
836 return PE_ARG_MISSING;
837 t->data_arg[type].i = atoi(sa);
838 break;
839 case ARG_T_DELAY:
840 if (!sa)
841 return PE_ARG_MISSING;
842 sa = parse_time_err(sa, &t->data_arg[type].u, TIME_UNIT_MS);
843 if (sa)
844 return PE_ARG_INVC; /* invalid char */
845 break;
846 }
847
Emeric Brunc64a2a32021-06-30 18:01:02 +0200848 t->data_size += t->data_nbelem[type] * stktable_type_size(stktable_data_types[type].std_type);
Willy Tarreau3b63ca22021-05-08 14:10:42 +0200849 t->data_ofs[type] = -t->data_size;
850 return PE_NONE;
851}
852
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100853/*
Frédéric Lécaillec02766a2019-03-20 15:06:55 +0100854 * Parse a line with <linenum> as number in <file> configuration file to configure
855 * the stick-table with <t> as address and <id> as ID.
856 * <peers> provides the "peers" section pointer only if this function is called
857 * from a "peers" section.
858 * <nid> is the stick-table name which is sent over the network. It must be equal
859 * to <id> if this stick-table is parsed from a proxy section, and prefixed by <peers>
860 * "peers" section name followed by a '/' character if parsed from a "peers" section.
Ilya Shipitsind4259502020-04-08 01:07:56 +0500861 * This is the responsibility of the caller to check this.
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100862 * Return an error status with ERR_* flags set if required, 0 if no error was encountered.
863 */
864int parse_stick_table(const char *file, int linenum, char **args,
Frédéric Lécaillec02766a2019-03-20 15:06:55 +0100865 struct stktable *t, char *id, char *nid, struct peers *peers)
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100866{
867 int err_code = 0;
868 int idx = 1;
869 unsigned int val;
870
871 if (!id || !*id) {
872 ha_alert("parsing [%s:%d] : %s: ID not provided.\n", file, linenum, args[0]);
873 err_code |= ERR_ALERT | ERR_ABORT;
874 goto out;
875 }
876
877 /* Store the "peers" section if this function is called from a "peers" section. */
878 if (peers) {
879 t->peers.p = peers;
880 idx++;
881 }
882
883 t->id = id;
Frédéric Lécaille36d15652022-10-17 14:58:19 +0200884 t->idlen = strlen(id);
Frédéric Lécaillec02766a2019-03-20 15:06:55 +0100885 t->nid = nid;
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100886 t->type = (unsigned int)-1;
887 t->conf.file = file;
888 t->conf.line = linenum;
889
890 while (*args[idx]) {
891 const char *err;
892
893 if (strcmp(args[idx], "size") == 0) {
894 idx++;
895 if (!*(args[idx])) {
896 ha_alert("parsing [%s:%d] : %s: missing argument after '%s'.\n",
897 file, linenum, args[0], args[idx-1]);
898 err_code |= ERR_ALERT | ERR_FATAL;
899 goto out;
900 }
901 if ((err = parse_size_err(args[idx], &t->size))) {
902 ha_alert("parsing [%s:%d] : %s: unexpected character '%c' in argument of '%s'.\n",
903 file, linenum, args[0], *err, args[idx-1]);
904 err_code |= ERR_ALERT | ERR_FATAL;
905 goto out;
906 }
907 idx++;
908 }
909 /* This argument does not exit in "peers" section. */
910 else if (!peers && strcmp(args[idx], "peers") == 0) {
911 idx++;
912 if (!*(args[idx])) {
913 ha_alert("parsing [%s:%d] : %s: missing argument after '%s'.\n",
914 file, linenum, args[0], args[idx-1]);
915 err_code |= ERR_ALERT | ERR_FATAL;
916 goto out;
917 }
918 t->peers.name = strdup(args[idx++]);
919 }
920 else if (strcmp(args[idx], "expire") == 0) {
921 idx++;
922 if (!*(args[idx])) {
923 ha_alert("parsing [%s:%d] : %s: missing argument after '%s'.\n",
924 file, linenum, args[0], args[idx-1]);
925 err_code |= ERR_ALERT | ERR_FATAL;
926 goto out;
927 }
928 err = parse_time_err(args[idx], &val, TIME_UNIT_MS);
Willy Tarreau9faebe32019-06-07 19:00:37 +0200929 if (err == PARSE_TIME_OVER) {
930 ha_alert("parsing [%s:%d]: %s: timer overflow in argument <%s> to <%s>, maximum value is 2147483647 ms (~24.8 days).\n",
931 file, linenum, args[0], args[idx], args[idx-1]);
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100932 err_code |= ERR_ALERT | ERR_FATAL;
933 goto out;
934 }
Willy Tarreau9faebe32019-06-07 19:00:37 +0200935 else if (err == PARSE_TIME_UNDER) {
936 ha_alert("parsing [%s:%d]: %s: timer underflow in argument <%s> to <%s>, minimum non-null value is 1 ms.\n",
937 file, linenum, args[0], args[idx], args[idx-1]);
938 err_code |= ERR_ALERT | ERR_FATAL;
939 goto out;
940 }
941 else if (err) {
942 ha_alert("parsing [%s:%d] : %s: unexpected character '%c' in argument of '%s'.\n",
943 file, linenum, args[0], *err, args[idx-1]);
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100944 err_code |= ERR_ALERT | ERR_FATAL;
945 goto out;
946 }
947 t->expire = val;
948 idx++;
949 }
950 else if (strcmp(args[idx], "nopurge") == 0) {
951 t->nopurge = 1;
952 idx++;
953 }
954 else if (strcmp(args[idx], "type") == 0) {
955 idx++;
956 if (stktable_parse_type(args, &idx, &t->type, &t->key_size) != 0) {
957 ha_alert("parsing [%s:%d] : %s: unknown type '%s'.\n",
958 file, linenum, args[0], args[idx]);
959 err_code |= ERR_ALERT | ERR_FATAL;
960 goto out;
961 }
962 /* idx already points to next arg */
963 }
964 else if (strcmp(args[idx], "store") == 0) {
965 int type, err;
Emeric Brunc64a2a32021-06-30 18:01:02 +0200966 char *cw, *nw, *sa, *sa2;
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100967
968 idx++;
969 nw = args[idx];
970 while (*nw) {
971 /* the "store" keyword supports a comma-separated list */
972 cw = nw;
973 sa = NULL; /* store arg */
Emeric Brunc64a2a32021-06-30 18:01:02 +0200974 sa2 = NULL;
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100975 while (*nw && *nw != ',') {
976 if (*nw == '(') {
977 *nw = 0;
978 sa = ++nw;
979 while (*nw != ')') {
980 if (!*nw) {
981 ha_alert("parsing [%s:%d] : %s: missing closing parenthesis after store option '%s'.\n",
982 file, linenum, args[0], cw);
983 err_code |= ERR_ALERT | ERR_FATAL;
984 goto out;
985 }
Emeric Brunc64a2a32021-06-30 18:01:02 +0200986 if (*nw == ',') {
987 *nw = '\0';
988 sa2 = nw + 1;
989 }
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100990 nw++;
991 }
992 *nw = '\0';
993 }
994 nw++;
995 }
996 if (*nw)
997 *nw++ = '\0';
998 type = stktable_get_data_type(cw);
999 if (type < 0) {
1000 ha_alert("parsing [%s:%d] : %s: unknown store option '%s'.\n",
1001 file, linenum, args[0], cw);
1002 err_code |= ERR_ALERT | ERR_FATAL;
1003 goto out;
1004 }
1005
Emeric Brunc64a2a32021-06-30 18:01:02 +02001006 err = stktable_alloc_data_type(t, type, sa, sa2);
Frédéric Lécailled456aa42019-03-08 14:47:00 +01001007 switch (err) {
1008 case PE_NONE: break;
1009 case PE_EXIST:
1010 ha_warning("parsing [%s:%d]: %s: store option '%s' already enabled, ignored.\n",
1011 file, linenum, args[0], cw);
1012 err_code |= ERR_WARN;
1013 break;
1014
1015 case PE_ARG_MISSING:
1016 ha_alert("parsing [%s:%d] : %s: missing argument to store option '%s'.\n",
1017 file, linenum, args[0], cw);
1018 err_code |= ERR_ALERT | ERR_FATAL;
1019 goto out;
1020
1021 case PE_ARG_NOT_USED:
1022 ha_alert("parsing [%s:%d] : %s: unexpected argument to store option '%s'.\n",
1023 file, linenum, args[0], cw);
1024 err_code |= ERR_ALERT | ERR_FATAL;
1025 goto out;
Emeric Brunc64a2a32021-06-30 18:01:02 +02001026 case PE_ARG_VALUE_OOR:
1027 ha_alert("parsing [%s:%d] : %s: array size is out of allowed range (1-%d) for store option '%s'.\n",
1028 file, linenum, args[0], STKTABLE_MAX_DT_ARRAY_SIZE, cw);
1029 err_code |= ERR_ALERT | ERR_FATAL;
1030 goto out;
Frédéric Lécailled456aa42019-03-08 14:47:00 +01001031
1032 default:
1033 ha_alert("parsing [%s:%d] : %s: error when processing store option '%s'.\n",
1034 file, linenum, args[0], cw);
1035 err_code |= ERR_ALERT | ERR_FATAL;
1036 goto out;
1037 }
1038 }
1039 idx++;
Emeric Brunf7ab0bf2021-06-30 18:58:22 +02001040 if (t->data_ofs[STKTABLE_DT_GPT] && t->data_ofs[STKTABLE_DT_GPT0]) {
1041 ha_alert("parsing [%s:%d] : %s: simultaneous usage of 'gpt' and 'gpt0' in a same table is not permitted as 'gpt' overrides 'gpt0'.\n",
1042 file, linenum, args[0]);
1043 err_code |= ERR_ALERT | ERR_FATAL;
1044 goto out;
1045 }
Emeric Brun726783d2021-06-30 19:06:43 +02001046 else if (t->data_ofs[STKTABLE_DT_GPC] && (t->data_ofs[STKTABLE_DT_GPC0] || t->data_ofs[STKTABLE_DT_GPC1])) {
1047 ha_alert("parsing [%s:%d] : %s: simultaneous usage of 'gpc' and 'gpc[0/1]' in a same table is not permitted as 'gpc' overrides 'gpc[0/1]'.\n",
1048 file, linenum, args[0]);
1049 err_code |= ERR_ALERT | ERR_FATAL;
1050 goto out;
1051 }
1052 else if (t->data_ofs[STKTABLE_DT_GPC_RATE] && (t->data_ofs[STKTABLE_DT_GPC0_RATE] || t->data_ofs[STKTABLE_DT_GPC1_RATE])) {
1053 ha_alert("parsing [%s:%d] : %s: simultaneous usage of 'gpc_rate' and 'gpc[0/1]_rate' in a same table is not permitted as 'gpc_rate' overrides 'gpc[0/1]_rate'.\n",
1054 file, linenum, args[0]);
1055 err_code |= ERR_ALERT | ERR_FATAL;
1056 goto out;
1057 }
Frédéric Lécailled456aa42019-03-08 14:47:00 +01001058 }
Thayne McCombs92149f92020-11-20 01:28:26 -07001059 else if (strcmp(args[idx], "srvkey") == 0) {
1060 char *keytype;
1061 idx++;
1062 keytype = args[idx];
1063 if (strcmp(keytype, "name") == 0) {
1064 t->server_key_type = STKTABLE_SRV_NAME;
1065 }
1066 else if (strcmp(keytype, "addr") == 0) {
1067 t->server_key_type = STKTABLE_SRV_ADDR;
1068 }
1069 else {
1070 ha_alert("parsing [%s:%d] : %s : unknown server key type '%s'.\n",
1071 file, linenum, args[0], keytype);
1072 err_code |= ERR_ALERT | ERR_FATAL;
1073 goto out;
1074
1075 }
1076 idx++;
1077 }
Frédéric Lécailled456aa42019-03-08 14:47:00 +01001078 else {
1079 ha_alert("parsing [%s:%d] : %s: unknown argument '%s'.\n",
1080 file, linenum, args[0], args[idx]);
1081 err_code |= ERR_ALERT | ERR_FATAL;
1082 goto out;
1083 }
1084 }
1085
1086 if (!t->size) {
1087 ha_alert("parsing [%s:%d] : %s: missing size.\n",
1088 file, linenum, args[0]);
1089 err_code |= ERR_ALERT | ERR_FATAL;
1090 goto out;
1091 }
1092
1093 if (t->type == (unsigned int)-1) {
1094 ha_alert("parsing [%s:%d] : %s: missing type.\n",
1095 file, linenum, args[0]);
1096 err_code |= ERR_ALERT | ERR_FATAL;
1097 goto out;
1098 }
1099
1100 out:
1101 return err_code;
1102}
1103
Willy Tarreau8fed9032014-07-03 17:02:46 +02001104/* Prepares a stktable_key from a sample <smp> to search into table <t>.
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001105 * Note that the sample *is* modified and that the returned key may point
1106 * to it, so the sample must not be modified afterwards before the lookup.
Willy Tarreau8fed9032014-07-03 17:02:46 +02001107 * Returns NULL if the sample could not be converted (eg: no matching type),
1108 * otherwise a pointer to the static stktable_key filled with what is needed
1109 * for the lookup.
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001110 */
Willy Tarreau8fed9032014-07-03 17:02:46 +02001111struct stktable_key *smp_to_stkey(struct sample *smp, struct stktable *t)
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001112{
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001113 /* Convert sample. */
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +02001114 if (!sample_convert(smp, t->type))
Willy Tarreau7fc1c6e2012-04-26 11:03:17 +02001115 return NULL;
1116
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001117 /* Fill static_table_key. */
1118 switch (t->type) {
Emeric Brun485479d2010-09-23 18:02:19 +02001119
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +02001120 case SMP_T_IPV4:
Christopher Fauletca20d022017-08-29 15:30:31 +02001121 static_table_key.key = &smp->data.u.ipv4;
1122 static_table_key.key_len = 4;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001123 break;
Emeric Brun485479d2010-09-23 18:02:19 +02001124
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +02001125 case SMP_T_IPV6:
Christopher Fauletca20d022017-08-29 15:30:31 +02001126 static_table_key.key = &smp->data.u.ipv6;
1127 static_table_key.key_len = 16;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001128 break;
Emeric Brun485479d2010-09-23 18:02:19 +02001129
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +02001130 case SMP_T_SINT:
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001131 /* The stick table require a 32bit unsigned int, "sint" is a
1132 * signed 64 it, so we can convert it inplace.
1133 */
Willy Tarreau28c63c12019-10-23 06:21:05 +02001134 smp->data.u.sint = (unsigned int)smp->data.u.sint;
Christopher Fauletca20d022017-08-29 15:30:31 +02001135 static_table_key.key = &smp->data.u.sint;
1136 static_table_key.key_len = 4;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001137 break;
1138
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +02001139 case SMP_T_STR:
Willy Tarreauce6955e2016-08-09 11:59:12 +02001140 if (!smp_make_safe(smp))
1141 return NULL;
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001142 static_table_key.key = smp->data.u.str.area;
1143 static_table_key.key_len = smp->data.u.str.data;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001144 break;
Emeric Brun485479d2010-09-23 18:02:19 +02001145
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +02001146 case SMP_T_BIN:
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001147 if (smp->data.u.str.data < t->key_size) {
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001148 /* This type needs padding with 0. */
Willy Tarreauf65c6c02016-08-09 12:08:41 +02001149 if (!smp_make_rw(smp))
1150 return NULL;
1151
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001152 if (smp->data.u.str.size < t->key_size)
1153 if (!smp_dup(smp))
1154 return NULL;
1155 if (smp->data.u.str.size < t->key_size)
1156 return NULL;
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001157 memset(smp->data.u.str.area + smp->data.u.str.data, 0,
1158 t->key_size - smp->data.u.str.data);
1159 smp->data.u.str.data = t->key_size;
Emeric Brun485479d2010-09-23 18:02:19 +02001160 }
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001161 static_table_key.key = smp->data.u.str.area;
1162 static_table_key.key_len = smp->data.u.str.data;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001163 break;
Emeric Brun485479d2010-09-23 18:02:19 +02001164
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001165 default: /* impossible case. */
1166 return NULL;
Emeric Brun485479d2010-09-23 18:02:19 +02001167 }
1168
Christopher Fauletca20d022017-08-29 15:30:31 +02001169 return &static_table_key;
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001170}
1171
1172/*
Willy Tarreau8fed9032014-07-03 17:02:46 +02001173 * Process a fetch + format conversion as defined by the sample expression <expr>
1174 * on request or response considering the <opt> parameter. Returns either NULL if
1175 * no key could be extracted, or a pointer to the converted result stored in
1176 * static_table_key in format <table_type>. If <smp> is not NULL, it will be reset
1177 * and its flags will be initialized so that the caller gets a copy of the input
Willy Tarreau6bcb0a82014-07-30 08:56:35 +02001178 * sample, and knows why it was not accepted (eg: SMP_F_MAY_CHANGE is present
1179 * without SMP_OPT_FINAL). The output will be usable like this :
1180 *
1181 * return MAY_CHANGE FINAL Meaning for the sample
1182 * NULL 0 * Not present and will never be (eg: header)
1183 * NULL 1 0 Not present or unstable, could change (eg: req_len)
1184 * NULL 1 1 Not present, will not change anymore
1185 * smp 0 * Present and will not change (eg: header)
1186 * smp 1 0 not possible
1187 * smp 1 1 Present, last known value (eg: request length)
Willy Tarreau8fed9032014-07-03 17:02:46 +02001188 */
Willy Tarreau192252e2015-04-04 01:47:55 +02001189struct stktable_key *stktable_fetch_key(struct stktable *t, struct proxy *px, struct session *sess, struct stream *strm,
Willy Tarreau8fed9032014-07-03 17:02:46 +02001190 unsigned int opt, struct sample_expr *expr, struct sample *smp)
1191{
1192 if (smp)
1193 memset(smp, 0, sizeof(*smp));
1194
Willy Tarreau192252e2015-04-04 01:47:55 +02001195 smp = sample_process(px, sess, strm, opt, expr, smp);
Willy Tarreau8fed9032014-07-03 17:02:46 +02001196 if (!smp)
1197 return NULL;
1198
1199 if ((smp->flags & SMP_F_MAY_CHANGE) && !(opt & SMP_OPT_FINAL))
1200 return NULL; /* we can only use stable samples */
1201
1202 return smp_to_stkey(smp, t);
1203}
1204
1205/*
Willy Tarreau12785782012-04-27 21:37:17 +02001206 * Returns 1 if sample expression <expr> result can be converted to table key of
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001207 * type <table_type>, otherwise zero. Used in configuration check.
1208 */
Willy Tarreau12785782012-04-27 21:37:17 +02001209int stktable_compatible_sample(struct sample_expr *expr, unsigned long table_type)
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001210{
Thierry FOURNIERf73eb8f2013-11-27 15:30:55 +01001211 int out_type;
1212
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +02001213 if (table_type >= SMP_TYPES || !stktable_types[table_type].kw)
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001214 return 0;
1215
Thierry FOURNIERf73eb8f2013-11-27 15:30:55 +01001216 out_type = smp_expr_output_type(expr);
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001217
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001218 /* Convert sample. */
1219 if (!sample_casts[out_type][table_type])
Thierry FOURNIERf73eb8f2013-11-27 15:30:55 +01001220 return 0;
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001221
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001222 return 1;
1223}
Emeric Brun3bd697e2010-01-04 15:23:48 +01001224
Willy Tarreauedee1d62014-07-15 16:44:27 +02001225/* Extra data types processing : after the last one, some room may remain
1226 * before STKTABLE_DATA_TYPES that may be used to register extra data types
1227 * at run time.
1228 */
Willy Tarreau08d5f982010-06-06 13:34:54 +02001229struct stktable_data_type stktable_data_types[STKTABLE_DATA_TYPES] = {
Willy Tarreau3b9c6e02010-07-18 08:04:30 +02001230 [STKTABLE_DT_SERVER_ID] = { .name = "server_id", .std_type = STD_T_SINT },
Thierry FOURNIER3cf11112015-07-28 08:57:05 +02001231 [STKTABLE_DT_GPT0] = { .name = "gpt0", .std_type = STD_T_UINT },
Willy Tarreau3b9c6e02010-07-18 08:04:30 +02001232 [STKTABLE_DT_GPC0] = { .name = "gpc0", .std_type = STD_T_UINT },
Willy Tarreauba2ffd12013-05-29 15:54:14 +02001233 [STKTABLE_DT_GPC0_RATE] = { .name = "gpc0_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
Willy Tarreau3b9c6e02010-07-18 08:04:30 +02001234 [STKTABLE_DT_CONN_CNT] = { .name = "conn_cnt", .std_type = STD_T_UINT },
1235 [STKTABLE_DT_CONN_RATE] = { .name = "conn_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
Willy Tarreaudb2ab822021-10-08 17:53:12 +02001236 [STKTABLE_DT_CONN_CUR] = { .name = "conn_cur", .std_type = STD_T_UINT, .is_local = 1 },
Willy Tarreau3b9c6e02010-07-18 08:04:30 +02001237 [STKTABLE_DT_SESS_CNT] = { .name = "sess_cnt", .std_type = STD_T_UINT },
1238 [STKTABLE_DT_SESS_RATE] = { .name = "sess_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
1239 [STKTABLE_DT_HTTP_REQ_CNT] = { .name = "http_req_cnt", .std_type = STD_T_UINT },
1240 [STKTABLE_DT_HTTP_REQ_RATE] = { .name = "http_req_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
1241 [STKTABLE_DT_HTTP_ERR_CNT] = { .name = "http_err_cnt", .std_type = STD_T_UINT },
1242 [STKTABLE_DT_HTTP_ERR_RATE] = { .name = "http_err_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
1243 [STKTABLE_DT_BYTES_IN_CNT] = { .name = "bytes_in_cnt", .std_type = STD_T_ULL },
1244 [STKTABLE_DT_BYTES_IN_RATE] = { .name = "bytes_in_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
1245 [STKTABLE_DT_BYTES_OUT_CNT] = { .name = "bytes_out_cnt", .std_type = STD_T_ULL },
1246 [STKTABLE_DT_BYTES_OUT_RATE]= { .name = "bytes_out_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001247 [STKTABLE_DT_GPC1] = { .name = "gpc1", .std_type = STD_T_UINT },
1248 [STKTABLE_DT_GPC1_RATE] = { .name = "gpc1_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
Thayne McCombs92149f92020-11-20 01:28:26 -07001249 [STKTABLE_DT_SERVER_KEY] = { .name = "server_key", .std_type = STD_T_DICT },
Willy Tarreau826f3ab2021-02-10 12:07:15 +01001250 [STKTABLE_DT_HTTP_FAIL_CNT] = { .name = "http_fail_cnt", .std_type = STD_T_UINT },
1251 [STKTABLE_DT_HTTP_FAIL_RATE]= { .name = "http_fail_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
Emeric Brun877b0b52021-06-30 18:57:49 +02001252 [STKTABLE_DT_GPT] = { .name = "gpt", .std_type = STD_T_UINT, .is_array = 1 },
Emeric Brun4d7ada82021-06-30 19:04:16 +02001253 [STKTABLE_DT_GPC] = { .name = "gpc", .std_type = STD_T_UINT, .is_array = 1 },
1254 [STKTABLE_DT_GPC_RATE] = { .name = "gpc_rate", .std_type = STD_T_FRQP, .is_array = 1, .arg_type = ARG_T_DELAY },
Willy Tarreau08d5f982010-06-06 13:34:54 +02001255};
1256
Willy Tarreauedee1d62014-07-15 16:44:27 +02001257/* Registers stick-table extra data type with index <idx>, name <name>, type
1258 * <std_type> and arg type <arg_type>. If the index is negative, the next free
1259 * index is automatically allocated. The allocated index is returned, or -1 if
1260 * no free index was found or <name> was already registered. The <name> is used
1261 * directly as a pointer, so if it's not stable, the caller must allocate it.
1262 */
1263int stktable_register_data_store(int idx, const char *name, int std_type, int arg_type)
1264{
1265 if (idx < 0) {
1266 for (idx = 0; idx < STKTABLE_DATA_TYPES; idx++) {
1267 if (!stktable_data_types[idx].name)
1268 break;
1269
1270 if (strcmp(stktable_data_types[idx].name, name) == 0)
1271 return -1;
1272 }
1273 }
1274
1275 if (idx >= STKTABLE_DATA_TYPES)
1276 return -1;
1277
1278 if (stktable_data_types[idx].name != NULL)
1279 return -1;
1280
1281 stktable_data_types[idx].name = name;
1282 stktable_data_types[idx].std_type = std_type;
1283 stktable_data_types[idx].arg_type = arg_type;
1284 return idx;
1285}
1286
Willy Tarreau08d5f982010-06-06 13:34:54 +02001287/*
1288 * Returns the data type number for the stktable_data_type whose name is <name>,
1289 * or <0 if not found.
1290 */
1291int stktable_get_data_type(char *name)
1292{
1293 int type;
1294
1295 for (type = 0; type < STKTABLE_DATA_TYPES; type++) {
Willy Tarreauedee1d62014-07-15 16:44:27 +02001296 if (!stktable_data_types[type].name)
1297 continue;
Willy Tarreau08d5f982010-06-06 13:34:54 +02001298 if (strcmp(name, stktable_data_types[type].name) == 0)
1299 return type;
1300 }
Thayne McCombs92149f92020-11-20 01:28:26 -07001301 /* For backwards compatibility */
1302 if (strcmp(name, "server_name") == 0)
1303 return STKTABLE_DT_SERVER_KEY;
Willy Tarreau08d5f982010-06-06 13:34:54 +02001304 return -1;
1305}
1306
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001307/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1308 * it up into this table. Returns true if found, false otherwise. The input
1309 * type is STR so that input samples are converted to string (since all types
1310 * can be converted to strings), then the function casts the string again into
1311 * the table's type. This is a double conversion, but in the future we might
1312 * support automatic input types to perform the cast on the fly.
1313 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001314static int sample_conv_in_table(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001315{
1316 struct stktable *t;
1317 struct stktable_key *key;
1318 struct stksess *ts;
1319
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001320 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001321
1322 key = smp_to_stkey(smp, t);
1323 if (!key)
1324 return 0;
1325
1326 ts = stktable_lookup_key(t, key);
1327
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001328 smp->data.type = SMP_T_BOOL;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001329 smp->data.u.sint = !!ts;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001330 smp->flags = SMP_F_VOL_TEST;
Willy Tarreau43e90352018-06-27 06:25:57 +02001331 stktable_release(t, ts);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001332 return 1;
1333}
1334
1335/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1336 * it up into this table. Returns the data rate received from clients in bytes/s
1337 * if the key is present in the table, otherwise zero, so that comparisons can
1338 * be easily performed. If the inspected parameter is not stored in the table,
1339 * <not found> is returned.
1340 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001341static int sample_conv_table_bytes_in_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001342{
1343 struct stktable *t;
1344 struct stktable_key *key;
1345 struct stksess *ts;
1346 void *ptr;
1347
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001348 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001349
1350 key = smp_to_stkey(smp, t);
1351 if (!key)
1352 return 0;
1353
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001354 ts = stktable_lookup_key(t, key);
1355
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001356 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001357 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001358 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001359
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001360 if (!ts) /* key not present */
1361 return 1;
1362
1363 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_IN_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001364 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001365 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Daniel Corbett3e60b112018-05-27 09:47:12 -04001366 t->data_arg[STKTABLE_DT_BYTES_IN_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001367
Daniel Corbett3e60b112018-05-27 09:47:12 -04001368 stktable_release(t, ts);
1369 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001370}
1371
1372/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1373 * it up into this table. Returns the cumulated number of connections for the key
1374 * if the key is present in the table, otherwise zero, so that comparisons can
1375 * be easily performed. If the inspected parameter is not stored in the table,
1376 * <not found> is returned.
1377 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001378static int sample_conv_table_conn_cnt(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001379{
1380 struct stktable *t;
1381 struct stktable_key *key;
1382 struct stksess *ts;
1383 void *ptr;
1384
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001385 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001386
1387 key = smp_to_stkey(smp, t);
1388 if (!key)
1389 return 0;
1390
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001391 ts = stktable_lookup_key(t, key);
1392
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001393 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001394 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001395 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001396
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001397 if (!ts) /* key not present */
1398 return 1;
1399
1400 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_CONN_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001401 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001402 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001403
Daniel Corbett3e60b112018-05-27 09:47:12 -04001404 stktable_release(t, ts);
1405 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001406}
1407
1408/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1409 * it up into this table. Returns the number of concurrent connections for the
1410 * key if the key is present in the table, otherwise zero, so that comparisons
1411 * can be easily performed. If the inspected parameter is not stored in the
1412 * table, <not found> is returned.
1413 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001414static int sample_conv_table_conn_cur(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001415{
1416 struct stktable *t;
1417 struct stktable_key *key;
1418 struct stksess *ts;
1419 void *ptr;
1420
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001421 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001422
1423 key = smp_to_stkey(smp, t);
1424 if (!key)
1425 return 0;
1426
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001427 ts = stktable_lookup_key(t, key);
1428
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001429 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001430 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001431 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001432
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001433 if (!ts) /* key not present */
1434 return 1;
1435
1436 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_CONN_CUR);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001437 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001438 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001439
Daniel Corbett3e60b112018-05-27 09:47:12 -04001440 stktable_release(t, ts);
1441 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001442}
1443
1444/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1445 * it up into this table. Returns the rate of incoming connections from the key
1446 * if the key is present in the table, otherwise zero, so that comparisons can
1447 * be easily performed. If the inspected parameter is not stored in the table,
1448 * <not found> is returned.
1449 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001450static int sample_conv_table_conn_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001451{
1452 struct stktable *t;
1453 struct stktable_key *key;
1454 struct stksess *ts;
1455 void *ptr;
1456
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001457 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001458
1459 key = smp_to_stkey(smp, t);
1460 if (!key)
1461 return 0;
1462
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001463 ts = stktable_lookup_key(t, key);
1464
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001465 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001466 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001467 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001468
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001469 if (!ts) /* key not present */
1470 return 1;
1471
1472 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_CONN_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001473 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001474 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Daniel Corbett3e60b112018-05-27 09:47:12 -04001475 t->data_arg[STKTABLE_DT_CONN_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001476
Daniel Corbett3e60b112018-05-27 09:47:12 -04001477 stktable_release(t, ts);
1478 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001479}
1480
1481/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Frédéric Lécaillebbeec372022-08-16 18:11:25 +02001482 * it up into this table. Returns the expiration delay for the key if the key is
1483 * present in the table, otherwise the default value provided as second argument
1484 * if any, if not (no default value), <not found> is returned.
1485 */
1486static int sample_conv_table_expire(const struct arg *arg_p, struct sample *smp, void *private)
1487{
1488 struct stktable *t;
1489 struct stktable_key *key;
1490 struct stksess *ts;
1491
1492 t = arg_p[0].data.t;
1493
1494 key = smp_to_stkey(smp, t);
1495 if (!key)
1496 return 0;
1497
1498 ts = stktable_lookup_key(t, key);
1499
1500 smp->flags = SMP_F_VOL_TEST;
1501 smp->data.type = SMP_T_SINT;
1502 smp->data.u.sint = 0;
1503
1504 if (!ts) { /* key not present */
1505 if (arg_p[1].type == ARGT_STOP)
1506 return 0;
1507
1508 /* default value */
1509 smp->data.u.sint = arg_p[1].data.sint;
1510 return 1;
1511 }
1512
1513 smp->data.u.sint = tick_remain(now_ms, ts->expire);
1514
1515 stktable_release(t, ts);
1516 return 1;
1517}
1518
1519/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1520 * it up into this table. Returns the time the key remains unused if the key is
1521 * present in the table, otherwise the default value provided as second argument
1522 * if any, if not (no default value), <not found> is returned.
1523 */
1524static int sample_conv_table_idle(const struct arg *arg_p, struct sample *smp, void *private)
1525{
1526 struct stktable *t;
1527 struct stktable_key *key;
1528 struct stksess *ts;
1529
1530 t = arg_p[0].data.t;
1531
1532 key = smp_to_stkey(smp, t);
1533 if (!key)
1534 return 0;
1535
1536 ts = stktable_lookup_key(t, key);
1537
1538 smp->flags = SMP_F_VOL_TEST;
1539 smp->data.type = SMP_T_SINT;
1540 smp->data.u.sint = 0;
1541
1542 if (!ts) { /* key not present */
1543 if (arg_p[1].type == ARGT_STOP)
1544 return 0;
1545
1546 /* default value */
1547 smp->data.u.sint = arg_p[1].data.sint;
1548 return 1;
1549 }
1550
1551 smp->data.u.sint = tick_remain(tick_remain(now_ms, ts->expire), t->expire);
1552
1553 stktable_release(t, ts);
1554 return 1;
1555}
1556
1557/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001558 * it up into this table. Returns the data rate sent to clients in bytes/s
1559 * if the key is present in the table, otherwise zero, so that comparisons can
1560 * be easily performed. If the inspected parameter is not stored in the table,
1561 * <not found> is returned.
1562 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001563static int sample_conv_table_bytes_out_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001564{
1565 struct stktable *t;
1566 struct stktable_key *key;
1567 struct stksess *ts;
1568 void *ptr;
1569
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001570 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001571
1572 key = smp_to_stkey(smp, t);
1573 if (!key)
1574 return 0;
1575
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001576 ts = stktable_lookup_key(t, key);
1577
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001578 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001579 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001580 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001581
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001582 if (!ts) /* key not present */
1583 return 1;
1584
1585 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_OUT_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001586 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001587 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Daniel Corbett3e60b112018-05-27 09:47:12 -04001588 t->data_arg[STKTABLE_DT_BYTES_OUT_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001589
Daniel Corbett3e60b112018-05-27 09:47:12 -04001590 stktable_release(t, ts);
1591 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001592}
1593
Emeric Brun877b0b52021-06-30 18:57:49 +02001594/* Casts sample <smp> to the type of the table specified in arg_p(1), and looks
1595 * it up into this table. Returns the value of the GPT[arg_p(0)] tag for the key
1596 * if the key is present in the table, otherwise false, so that comparisons can
1597 * be easily performed. If the inspected parameter is not stored in the table,
1598 * <not found> is returned.
1599 */
1600static int sample_conv_table_gpt(const struct arg *arg_p, struct sample *smp, void *private)
1601{
1602 struct stktable *t;
1603 struct stktable_key *key;
1604 struct stksess *ts;
1605 void *ptr;
1606 unsigned int idx;
1607
1608 idx = arg_p[0].data.sint;
1609
1610 t = arg_p[1].data.t;
1611
1612 key = smp_to_stkey(smp, t);
1613 if (!key)
1614 return 0;
1615
1616 ts = stktable_lookup_key(t, key);
1617
1618 smp->flags = SMP_F_VOL_TEST;
1619 smp->data.type = SMP_T_SINT;
1620 smp->data.u.sint = 0;
1621
1622 if (!ts) /* key not present */
1623 return 1;
1624
1625 ptr = stktable_data_ptr_idx(t, ts, STKTABLE_DT_GPT, idx);
1626 if (ptr)
1627 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
1628
1629 stktable_release(t, ts);
1630 return !!ptr;
1631}
1632
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001633/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001634 * it up into this table. Returns the value of the GPT0 tag for the key
1635 * if the key is present in the table, otherwise false, so that comparisons can
1636 * be easily performed. If the inspected parameter is not stored in the table,
1637 * <not found> is returned.
1638 */
1639static int sample_conv_table_gpt0(const struct arg *arg_p, struct sample *smp, void *private)
1640{
1641 struct stktable *t;
1642 struct stktable_key *key;
1643 struct stksess *ts;
1644 void *ptr;
1645
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001646 t = arg_p[0].data.t;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001647
1648 key = smp_to_stkey(smp, t);
1649 if (!key)
1650 return 0;
1651
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001652 ts = stktable_lookup_key(t, key);
1653
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001654 smp->flags = SMP_F_VOL_TEST;
1655 smp->data.type = SMP_T_SINT;
1656 smp->data.u.sint = 0;
1657
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001658 if (!ts) /* key not present */
1659 return 1;
1660
1661 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPT0);
Emeric Brunf7ab0bf2021-06-30 18:58:22 +02001662 if (!ptr)
1663 ptr = stktable_data_ptr_idx(t, ts, STKTABLE_DT_GPT, 0);
1664
Daniel Corbett3e60b112018-05-27 09:47:12 -04001665 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001666 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001667
Daniel Corbett3e60b112018-05-27 09:47:12 -04001668 stktable_release(t, ts);
1669 return !!ptr;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001670}
1671
Emeric Brun4d7ada82021-06-30 19:04:16 +02001672/* Casts sample <smp> to the type of the table specified in arg_p(1), and looks
1673 * it up into this table. Returns the value of the GPC[arg_p(0)] counter for the key
1674 * if the key is present in the table, otherwise zero, so that comparisons can
1675 * be easily performed. If the inspected parameter is not stored in the table,
1676 * <not found> is returned.
1677 */
1678static int sample_conv_table_gpc(const struct arg *arg_p, struct sample *smp, void *private)
1679{
1680 struct stktable *t;
1681 struct stktable_key *key;
1682 struct stksess *ts;
1683 void *ptr;
1684 unsigned int idx;
1685
1686 idx = arg_p[0].data.sint;
1687
1688 t = arg_p[1].data.t;
1689
1690 key = smp_to_stkey(smp, t);
1691 if (!key)
1692 return 0;
1693
1694 ts = stktable_lookup_key(t, key);
1695
1696 smp->flags = SMP_F_VOL_TEST;
1697 smp->data.type = SMP_T_SINT;
1698 smp->data.u.sint = 0;
1699
1700 if (!ts) /* key not present */
1701 return 1;
1702
1703 ptr = stktable_data_ptr_idx(t, ts, STKTABLE_DT_GPC, idx);
1704 if (ptr)
1705 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
1706
1707 stktable_release(t, ts);
1708 return !!ptr;
1709}
1710
1711/* Casts sample <smp> to the type of the table specified in arg_p(1), and looks
1712 * it up into this table. Returns the event rate of the GPC[arg_p(0)] counter
1713 * for the key if the key is present in the table, otherwise zero, so that
1714 * comparisons can be easily performed. If the inspected parameter is not
1715 * stored in the table, <not found> is returned.
1716 */
1717static int sample_conv_table_gpc_rate(const struct arg *arg_p, struct sample *smp, void *private)
1718{
1719 struct stktable *t;
1720 struct stktable_key *key;
1721 struct stksess *ts;
1722 void *ptr;
1723 unsigned int idx;
1724
1725 idx = arg_p[0].data.sint;
1726
1727 t = arg_p[1].data.t;
1728
1729 key = smp_to_stkey(smp, t);
1730 if (!key)
1731 return 0;
1732
1733 ts = stktable_lookup_key(t, key);
1734
1735 smp->flags = SMP_F_VOL_TEST;
1736 smp->data.type = SMP_T_SINT;
1737 smp->data.u.sint = 0;
1738
1739 if (!ts) /* key not present */
1740 return 1;
1741
1742 ptr = stktable_data_ptr_idx(t, ts, STKTABLE_DT_GPC_RATE, idx);
1743 if (ptr)
1744 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
1745 t->data_arg[STKTABLE_DT_GPC_RATE].u);
1746
1747 stktable_release(t, ts);
1748 return !!ptr;
1749}
1750
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001751/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001752 * it up into this table. Returns the value of the GPC0 counter for the key
1753 * if the key is present in the table, otherwise zero, so that comparisons can
1754 * be easily performed. If the inspected parameter is not stored in the table,
1755 * <not found> is returned.
1756 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001757static int sample_conv_table_gpc0(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001758{
1759 struct stktable *t;
1760 struct stktable_key *key;
1761 struct stksess *ts;
1762 void *ptr;
1763
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001764 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001765
1766 key = smp_to_stkey(smp, t);
1767 if (!key)
1768 return 0;
1769
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001770 ts = stktable_lookup_key(t, key);
1771
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001772 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001773 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001774 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001775
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001776 if (!ts) /* key not present */
1777 return 1;
1778
1779 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPC0);
Emeric Brun726783d2021-06-30 19:06:43 +02001780 if (!ptr) {
1781 /* fallback on the gpc array */
1782 ptr = stktable_data_ptr_idx(t, ts, STKTABLE_DT_GPC, 0);
1783 }
1784
Daniel Corbett3e60b112018-05-27 09:47:12 -04001785 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001786 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001787
Daniel Corbett3e60b112018-05-27 09:47:12 -04001788 stktable_release(t, ts);
1789 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001790}
1791
1792/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1793 * it up into this table. Returns the event rate of the GPC0 counter for the key
1794 * if the key is present in the table, otherwise zero, so that comparisons can
1795 * be easily performed. If the inspected parameter is not stored in the table,
1796 * <not found> is returned.
1797 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001798static int sample_conv_table_gpc0_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001799{
1800 struct stktable *t;
1801 struct stktable_key *key;
1802 struct stksess *ts;
1803 void *ptr;
1804
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001805 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001806
1807 key = smp_to_stkey(smp, t);
1808 if (!key)
1809 return 0;
1810
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001811 ts = stktable_lookup_key(t, key);
1812
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001813 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001814 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001815 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001816
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001817 if (!ts) /* key not present */
1818 return 1;
1819
1820 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPC0_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001821 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001822 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Daniel Corbett3e60b112018-05-27 09:47:12 -04001823 t->data_arg[STKTABLE_DT_GPC0_RATE].u);
Emeric Brun726783d2021-06-30 19:06:43 +02001824 else {
1825 /* fallback on the gpc array */
1826 ptr = stktable_data_ptr_idx(t, ts, STKTABLE_DT_GPC_RATE, 0);
1827 if (ptr)
1828 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
1829 t->data_arg[STKTABLE_DT_GPC_RATE].u);
1830 }
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001831
Daniel Corbett3e60b112018-05-27 09:47:12 -04001832 stktable_release(t, ts);
1833 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001834}
1835
1836/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001837 * it up into this table. Returns the value of the GPC1 counter for the key
1838 * if the key is present in the table, otherwise zero, so that comparisons can
1839 * be easily performed. If the inspected parameter is not stored in the table,
1840 * <not found> is returned.
1841 */
1842static int sample_conv_table_gpc1(const struct arg *arg_p, struct sample *smp, void *private)
1843{
1844 struct stktable *t;
1845 struct stktable_key *key;
1846 struct stksess *ts;
1847 void *ptr;
1848
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001849 t = arg_p[0].data.t;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001850
1851 key = smp_to_stkey(smp, t);
1852 if (!key)
1853 return 0;
1854
1855 ts = stktable_lookup_key(t, key);
1856
1857 smp->flags = SMP_F_VOL_TEST;
1858 smp->data.type = SMP_T_SINT;
1859 smp->data.u.sint = 0;
1860
1861 if (!ts) /* key not present */
1862 return 1;
1863
1864 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPC1);
Emeric Brun726783d2021-06-30 19:06:43 +02001865 if (!ptr) {
1866 /* fallback on the gpc array */
1867 ptr = stktable_data_ptr_idx(t, ts, STKTABLE_DT_GPC, 1);
1868 }
1869
Daniel Corbett3e60b112018-05-27 09:47:12 -04001870 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001871 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001872
Daniel Corbett3e60b112018-05-27 09:47:12 -04001873 stktable_release(t, ts);
1874 return !!ptr;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001875}
1876
1877/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1878 * it up into this table. Returns the event rate of the GPC1 counter for the key
1879 * if the key is present in the table, otherwise zero, so that comparisons can
1880 * be easily performed. If the inspected parameter is not stored in the table,
1881 * <not found> is returned.
1882 */
1883static int sample_conv_table_gpc1_rate(const struct arg *arg_p, struct sample *smp, void *private)
1884{
1885 struct stktable *t;
1886 struct stktable_key *key;
1887 struct stksess *ts;
1888 void *ptr;
1889
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001890 t = arg_p[0].data.t;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001891
1892 key = smp_to_stkey(smp, t);
1893 if (!key)
1894 return 0;
1895
1896 ts = stktable_lookup_key(t, key);
1897
1898 smp->flags = SMP_F_VOL_TEST;
1899 smp->data.type = SMP_T_SINT;
1900 smp->data.u.sint = 0;
1901
1902 if (!ts) /* key not present */
1903 return 1;
1904
1905 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPC1_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001906 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001907 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Daniel Corbett3e60b112018-05-27 09:47:12 -04001908 t->data_arg[STKTABLE_DT_GPC1_RATE].u);
Emeric Brun726783d2021-06-30 19:06:43 +02001909 else {
1910 /* fallback on the gpc array */
1911 ptr = stktable_data_ptr_idx(t, ts, STKTABLE_DT_GPC_RATE, 1);
1912 if (ptr)
1913 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
1914 t->data_arg[STKTABLE_DT_GPC_RATE].u);
1915 }
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001916
Daniel Corbett3e60b112018-05-27 09:47:12 -04001917 stktable_release(t, ts);
1918 return !!ptr;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001919}
1920
1921/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001922 * it up into this table. Returns the cumulated number of HTTP request errors
1923 * for the key if the key is present in the table, otherwise zero, so that
1924 * comparisons can be easily performed. If the inspected parameter is not stored
1925 * in the table, <not found> is returned.
1926 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001927static int sample_conv_table_http_err_cnt(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001928{
1929 struct stktable *t;
1930 struct stktable_key *key;
1931 struct stksess *ts;
1932 void *ptr;
1933
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001934 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001935
1936 key = smp_to_stkey(smp, t);
1937 if (!key)
1938 return 0;
1939
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001940 ts = stktable_lookup_key(t, key);
1941
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001942 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001943 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001944 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001945
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001946 if (!ts) /* key not present */
1947 return 1;
1948
1949 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_ERR_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001950 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001951 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001952
Daniel Corbett3e60b112018-05-27 09:47:12 -04001953 stktable_release(t, ts);
1954 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001955}
1956
1957/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1958 * it up into this table. Returns the HTTP request error rate the key
1959 * if the key is present in the table, otherwise zero, so that comparisons can
1960 * be easily performed. If the inspected parameter is not stored in the table,
1961 * <not found> is returned.
1962 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001963static int sample_conv_table_http_err_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001964{
1965 struct stktable *t;
1966 struct stktable_key *key;
1967 struct stksess *ts;
1968 void *ptr;
1969
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001970 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001971
1972 key = smp_to_stkey(smp, t);
1973 if (!key)
1974 return 0;
1975
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001976 ts = stktable_lookup_key(t, key);
1977
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001978 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001979 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001980 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001981
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001982 if (!ts) /* key not present */
1983 return 1;
1984
1985 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_ERR_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001986 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001987 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Daniel Corbett3e60b112018-05-27 09:47:12 -04001988 t->data_arg[STKTABLE_DT_HTTP_ERR_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001989
Daniel Corbett3e60b112018-05-27 09:47:12 -04001990 stktable_release(t, ts);
1991 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001992}
1993
1994/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Willy Tarreau826f3ab2021-02-10 12:07:15 +01001995 * it up into this table. Returns the cumulated number of HTTP response failures
1996 * for the key if the key is present in the table, otherwise zero, so that
1997 * comparisons can be easily performed. If the inspected parameter is not stored
1998 * in the table, <not found> is returned.
1999 */
2000static int sample_conv_table_http_fail_cnt(const struct arg *arg_p, struct sample *smp, void *private)
2001{
2002 struct stktable *t;
2003 struct stktable_key *key;
2004 struct stksess *ts;
2005 void *ptr;
2006
2007 t = arg_p[0].data.t;
2008
2009 key = smp_to_stkey(smp, t);
2010 if (!key)
2011 return 0;
2012
2013 ts = stktable_lookup_key(t, key);
2014
2015 smp->flags = SMP_F_VOL_TEST;
2016 smp->data.type = SMP_T_SINT;
2017 smp->data.u.sint = 0;
2018
2019 if (!ts) /* key not present */
2020 return 1;
2021
2022 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_FAIL_CNT);
2023 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002024 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Willy Tarreau826f3ab2021-02-10 12:07:15 +01002025
2026 stktable_release(t, ts);
2027 return !!ptr;
2028}
2029
2030/* Casts sample <smp> to the type of the table specified in arg(0), and looks
2031 * it up into this table. Returns the HTTP response failure rate for the key
2032 * if the key is present in the table, otherwise zero, so that comparisons can
2033 * be easily performed. If the inspected parameter is not stored in the table,
2034 * <not found> is returned.
2035 */
2036static int sample_conv_table_http_fail_rate(const struct arg *arg_p, struct sample *smp, void *private)
2037{
2038 struct stktable *t;
2039 struct stktable_key *key;
2040 struct stksess *ts;
2041 void *ptr;
2042
2043 t = arg_p[0].data.t;
2044
2045 key = smp_to_stkey(smp, t);
2046 if (!key)
2047 return 0;
2048
2049 ts = stktable_lookup_key(t, key);
2050
2051 smp->flags = SMP_F_VOL_TEST;
2052 smp->data.type = SMP_T_SINT;
2053 smp->data.u.sint = 0;
2054
2055 if (!ts) /* key not present */
2056 return 1;
2057
2058 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_FAIL_RATE);
2059 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002060 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Willy Tarreau826f3ab2021-02-10 12:07:15 +01002061 t->data_arg[STKTABLE_DT_HTTP_FAIL_RATE].u);
2062
2063 stktable_release(t, ts);
2064 return !!ptr;
2065}
2066
2067/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002068 * it up into this table. Returns the cumulated number of HTTP request for the
2069 * key if the key is present in the table, otherwise zero, so that comparisons
2070 * can be easily performed. If the inspected parameter is not stored in the
2071 * table, <not found> is returned.
2072 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02002073static int sample_conv_table_http_req_cnt(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002074{
2075 struct stktable *t;
2076 struct stktable_key *key;
2077 struct stksess *ts;
2078 void *ptr;
2079
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002080 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002081
2082 key = smp_to_stkey(smp, t);
2083 if (!key)
2084 return 0;
2085
Willy Tarreauf0c730a2016-05-25 17:07:56 +02002086 ts = stktable_lookup_key(t, key);
2087
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002088 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02002089 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02002090 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002091
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002092 if (!ts) /* key not present */
2093 return 1;
2094
2095 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_REQ_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04002096 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002097 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002098
Daniel Corbett3e60b112018-05-27 09:47:12 -04002099 stktable_release(t, ts);
2100 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002101}
2102
2103/* Casts sample <smp> to the type of the table specified in arg(0), and looks
2104 * it up into this table. Returns the HTTP request rate the key if the key is
2105 * present in the table, otherwise zero, so that comparisons can be easily
2106 * performed. If the inspected parameter is not stored in the table, <not found>
2107 * is returned.
2108 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02002109static int sample_conv_table_http_req_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002110{
2111 struct stktable *t;
2112 struct stktable_key *key;
2113 struct stksess *ts;
2114 void *ptr;
2115
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002116 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002117
2118 key = smp_to_stkey(smp, t);
2119 if (!key)
2120 return 0;
2121
Willy Tarreauf0c730a2016-05-25 17:07:56 +02002122 ts = stktable_lookup_key(t, key);
2123
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002124 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02002125 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02002126 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002127
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002128 if (!ts) /* key not present */
2129 return 1;
2130
2131 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_REQ_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04002132 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002133 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Daniel Corbett3e60b112018-05-27 09:47:12 -04002134 t->data_arg[STKTABLE_DT_HTTP_REQ_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002135
Daniel Corbett3e60b112018-05-27 09:47:12 -04002136 stktable_release(t, ts);
2137 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002138}
2139
2140/* Casts sample <smp> to the type of the table specified in arg(0), and looks
2141 * it up into this table. Returns the volume of datareceived from clients in kbytes
2142 * if the key is present in the table, otherwise zero, so that comparisons can
2143 * be easily performed. If the inspected parameter is not stored in the table,
2144 * <not found> is returned.
2145 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02002146static int sample_conv_table_kbytes_in(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002147{
2148 struct stktable *t;
2149 struct stktable_key *key;
2150 struct stksess *ts;
2151 void *ptr;
2152
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002153 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002154
2155 key = smp_to_stkey(smp, t);
2156 if (!key)
2157 return 0;
2158
Willy Tarreauf0c730a2016-05-25 17:07:56 +02002159 ts = stktable_lookup_key(t, key);
2160
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002161 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02002162 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02002163 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002164
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002165 if (!ts) /* key not present */
2166 return 1;
2167
2168 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_IN_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04002169 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002170 smp->data.u.sint = stktable_data_cast(ptr, std_t_ull) >> 10;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002171
Daniel Corbett3e60b112018-05-27 09:47:12 -04002172 stktable_release(t, ts);
2173 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002174}
2175
2176/* Casts sample <smp> to the type of the table specified in arg(0), and looks
2177 * it up into this table. Returns the volume of data sent to clients in kbytes
2178 * if the key is present in the table, otherwise zero, so that comparisons can
2179 * be easily performed. If the inspected parameter is not stored in the table,
2180 * <not found> is returned.
2181 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02002182static int sample_conv_table_kbytes_out(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002183{
2184 struct stktable *t;
2185 struct stktable_key *key;
2186 struct stksess *ts;
2187 void *ptr;
2188
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002189 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002190
2191 key = smp_to_stkey(smp, t);
2192 if (!key)
2193 return 0;
2194
Willy Tarreauf0c730a2016-05-25 17:07:56 +02002195 ts = stktable_lookup_key(t, key);
2196
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002197 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02002198 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02002199 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002200
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002201 if (!ts) /* key not present */
2202 return 1;
2203
2204 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_OUT_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04002205 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002206 smp->data.u.sint = stktable_data_cast(ptr, std_t_ull) >> 10;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002207
Daniel Corbett3e60b112018-05-27 09:47:12 -04002208 stktable_release(t, ts);
2209 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002210}
2211
2212/* Casts sample <smp> to the type of the table specified in arg(0), and looks
2213 * it up into this table. Returns the server ID associated with the key if the
2214 * key is present in the table, otherwise zero, so that comparisons can be
2215 * easily performed. If the inspected parameter is not stored in the table,
2216 * <not found> is returned.
2217 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02002218static int sample_conv_table_server_id(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002219{
2220 struct stktable *t;
2221 struct stktable_key *key;
2222 struct stksess *ts;
2223 void *ptr;
2224
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002225 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002226
2227 key = smp_to_stkey(smp, t);
2228 if (!key)
2229 return 0;
2230
Willy Tarreauf0c730a2016-05-25 17:07:56 +02002231 ts = stktable_lookup_key(t, key);
2232
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002233 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02002234 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02002235 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002236
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002237 if (!ts) /* key not present */
2238 return 1;
2239
2240 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_SERVER_ID);
Daniel Corbett3e60b112018-05-27 09:47:12 -04002241 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002242 smp->data.u.sint = stktable_data_cast(ptr, std_t_sint);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002243
Daniel Corbett3e60b112018-05-27 09:47:12 -04002244 stktable_release(t, ts);
2245 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002246}
2247
2248/* Casts sample <smp> to the type of the table specified in arg(0), and looks
2249 * it up into this table. Returns the cumulated number of sessions for the
2250 * key if the key is present in the table, otherwise zero, so that comparisons
2251 * can be easily performed. If the inspected parameter is not stored in the
2252 * table, <not found> is returned.
2253 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02002254static int sample_conv_table_sess_cnt(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002255{
2256 struct stktable *t;
2257 struct stktable_key *key;
2258 struct stksess *ts;
2259 void *ptr;
2260
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002261 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002262
2263 key = smp_to_stkey(smp, t);
2264 if (!key)
2265 return 0;
2266
Willy Tarreauf0c730a2016-05-25 17:07:56 +02002267 ts = stktable_lookup_key(t, key);
2268
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002269 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02002270 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02002271 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002272
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002273 if (!ts) /* key not present */
2274 return 1;
2275
2276 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_SESS_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04002277 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002278 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002279
Daniel Corbett3e60b112018-05-27 09:47:12 -04002280 stktable_release(t, ts);
2281 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002282}
2283
2284/* Casts sample <smp> to the type of the table specified in arg(0), and looks
2285 * it up into this table. Returns the session rate the key if the key is
2286 * present in the table, otherwise zero, so that comparisons can be easily
2287 * performed. If the inspected parameter is not stored in the table, <not found>
2288 * is returned.
2289 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02002290static int sample_conv_table_sess_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002291{
2292 struct stktable *t;
2293 struct stktable_key *key;
2294 struct stksess *ts;
2295 void *ptr;
2296
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002297 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002298
2299 key = smp_to_stkey(smp, t);
2300 if (!key)
2301 return 0;
2302
Willy Tarreauf0c730a2016-05-25 17:07:56 +02002303 ts = stktable_lookup_key(t, key);
2304
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002305 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02002306 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02002307 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002308
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002309 if (!ts) /* key not present */
2310 return 1;
2311
2312 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_SESS_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04002313 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002314 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Daniel Corbett3e60b112018-05-27 09:47:12 -04002315 t->data_arg[STKTABLE_DT_SESS_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002316
Daniel Corbett3e60b112018-05-27 09:47:12 -04002317 stktable_release(t, ts);
2318 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002319}
2320
2321/* Casts sample <smp> to the type of the table specified in arg(0), and looks
2322 * it up into this table. Returns the amount of concurrent connections tracking
2323 * the same key if the key is present in the table, otherwise zero, so that
2324 * comparisons can be easily performed. If the inspected parameter is not
2325 * stored in the table, <not found> is returned.
2326 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02002327static int sample_conv_table_trackers(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002328{
2329 struct stktable *t;
2330 struct stktable_key *key;
2331 struct stksess *ts;
2332
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002333 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002334
2335 key = smp_to_stkey(smp, t);
2336 if (!key)
2337 return 0;
2338
Willy Tarreauf0c730a2016-05-25 17:07:56 +02002339 ts = stktable_lookup_key(t, key);
2340
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002341 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02002342 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02002343 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002344
Tim Duesterhus65189c12018-06-26 15:57:29 +02002345 if (!ts)
2346 return 1;
2347
2348 smp->data.u.sint = ts->ref_cnt;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002349
Daniel Corbett3e60b112018-05-27 09:47:12 -04002350 stktable_release(t, ts);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002351 return 1;
2352}
2353
Emeric Brun4d7ada82021-06-30 19:04:16 +02002354/* This function increments the gpc counter at index 'rule->arg.gpc.idx' of the
2355 * array on the tracksc counter of index 'rule->arg.gpc.sc' stored into the
2356 * <stream> or directly in the session <sess> if <stream> is set to NULL
2357 *
2358 * This function always returns ACT_RET_CONT and parameter flags is unused.
2359 */
2360static enum act_return action_inc_gpc(struct act_rule *rule, struct proxy *px,
2361 struct session *sess, struct stream *s, int flags)
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002362{
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002363 struct stksess *ts;
2364 struct stkctr *stkctr;
2365
2366 /* Extract the stksess, return OK if no stksess available. */
2367 if (s)
2368 stkctr = &s->stkctr[rule->arg.gpc.sc];
2369 else
2370 stkctr = &sess->stkctr[rule->arg.gpc.sc];
Willy Tarreau79c1e912016-01-25 14:54:45 +01002371
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002372 ts = stkctr_entry(stkctr);
Willy Tarreau79c1e912016-01-25 14:54:45 +01002373 if (ts) {
2374 void *ptr1, *ptr2;
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002375
Emeric Brun4d7ada82021-06-30 19:04:16 +02002376 /* First, update gpc_rate if it's tracked. Second, update its gpc if tracked. */
2377 ptr1 = stktable_data_ptr_idx(stkctr->table, ts, STKTABLE_DT_GPC_RATE, rule->arg.gpc.idx);
2378 ptr2 = stktable_data_ptr_idx(stkctr->table, ts, STKTABLE_DT_GPC, rule->arg.gpc.idx);
2379
Emeric Brun819fc6f2017-06-13 19:37:32 +02002380 if (ptr1 || ptr2) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002381 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002382
2383 if (ptr1)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002384 update_freq_ctr_period(&stktable_data_cast(ptr1, std_t_frqp),
Emeric Brun4d7ada82021-06-30 19:04:16 +02002385 stkctr->table->data_arg[STKTABLE_DT_GPC_RATE].u, 1);
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002386
Emeric Brun819fc6f2017-06-13 19:37:32 +02002387 if (ptr2)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002388 stktable_data_cast(ptr2, std_t_uint)++;
Willy Tarreau79c1e912016-01-25 14:54:45 +01002389
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002390 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002391
2392 /* If data was modified, we need to touch to re-schedule sync */
2393 stktable_touch_local(stkctr->table, ts, 0);
2394 }
Willy Tarreau79c1e912016-01-25 14:54:45 +01002395 }
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002396 return ACT_RET_CONT;
2397}
2398
Emeric Brun4d7ada82021-06-30 19:04:16 +02002399/* Same as action_inc_gpc() but for gpc0 only */
2400static enum act_return action_inc_gpc0(struct act_rule *rule, struct proxy *px,
2401 struct session *sess, struct stream *s, int flags)
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002402{
Emeric Brun4d7ada82021-06-30 19:04:16 +02002403 struct stksess *ts;
2404 struct stkctr *stkctr;
Willy Tarreau5b654ad2021-07-06 18:51:12 +02002405 unsigned int period = 0;
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002406
Emeric Brun4d7ada82021-06-30 19:04:16 +02002407 /* Extract the stksess, return OK if no stksess available. */
2408 if (s)
2409 stkctr = &s->stkctr[rule->arg.gpc.sc];
2410 else
2411 stkctr = &sess->stkctr[rule->arg.gpc.sc];
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002412
Emeric Brun4d7ada82021-06-30 19:04:16 +02002413 ts = stkctr_entry(stkctr);
2414 if (ts) {
2415 void *ptr1, *ptr2;
2416
2417 /* First, update gpc0_rate if it's tracked. Second, update its gpc0 if tracked. */
2418 ptr1 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC0_RATE);
Emeric Brun726783d2021-06-30 19:06:43 +02002419 if (ptr1) {
2420 period = stkctr->table->data_arg[STKTABLE_DT_GPC0_RATE].u;
2421 }
2422 else {
2423 /* fallback on the gpc array */
2424 ptr1 = stktable_data_ptr_idx(stkctr->table, ts, STKTABLE_DT_GPC_RATE, 0);
2425 if (ptr1)
2426 period = stkctr->table->data_arg[STKTABLE_DT_GPC_RATE].u;
2427 }
2428
Emeric Brun4d7ada82021-06-30 19:04:16 +02002429 ptr2 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC0);
Emeric Brun726783d2021-06-30 19:06:43 +02002430 if (!ptr2) {
2431 /* fallback on the gpc array */
2432 ptr2 = stktable_data_ptr_idx(stkctr->table, ts, STKTABLE_DT_GPC, 0);
2433 }
2434
Emeric Brun4d7ada82021-06-30 19:04:16 +02002435 if (ptr1 || ptr2) {
2436 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
2437
2438 if (ptr1)
2439 update_freq_ctr_period(&stktable_data_cast(ptr1, std_t_frqp),
Emeric Brun726783d2021-06-30 19:06:43 +02002440 period, 1);
Emeric Brun4d7ada82021-06-30 19:04:16 +02002441
2442 if (ptr2)
2443 stktable_data_cast(ptr2, std_t_uint)++;
2444
2445 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
2446
2447 /* If data was modified, we need to touch to re-schedule sync */
2448 stktable_touch_local(stkctr->table, ts, 0);
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002449 }
2450 }
Emeric Brun4d7ada82021-06-30 19:04:16 +02002451 return ACT_RET_CONT;
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002452}
2453
Emeric Brun4d7ada82021-06-30 19:04:16 +02002454/* Same as action_inc_gpc() but for gpc1 only */
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002455static enum act_return action_inc_gpc1(struct act_rule *rule, struct proxy *px,
2456 struct session *sess, struct stream *s, int flags)
2457{
2458 struct stksess *ts;
Willy Tarreau6c011712023-01-06 16:09:58 +01002459 struct stkctr *stkctr = NULL;
Willy Tarreau5b654ad2021-07-06 18:51:12 +02002460 unsigned int period = 0;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002461
2462 /* Extract the stksess, return OK if no stksess available. */
Willy Tarreau6c011712023-01-06 16:09:58 +01002463 if (s && s->stkctr)
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002464 stkctr = &s->stkctr[rule->arg.gpc.sc];
Willy Tarreau6c011712023-01-06 16:09:58 +01002465 else if (sess->stkctr)
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002466 stkctr = &sess->stkctr[rule->arg.gpc.sc];
Willy Tarreau6c011712023-01-06 16:09:58 +01002467 else
2468 return ACT_RET_CONT;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002469
2470 ts = stkctr_entry(stkctr);
2471 if (ts) {
2472 void *ptr1, *ptr2;
2473
2474 /* First, update gpc1_rate if it's tracked. Second, update its gpc1 if tracked. */
2475 ptr1 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC1_RATE);
Emeric Brun726783d2021-06-30 19:06:43 +02002476 if (ptr1) {
2477 period = stkctr->table->data_arg[STKTABLE_DT_GPC1_RATE].u;
2478 }
2479 else {
2480 /* fallback on the gpc array */
2481 ptr1 = stktable_data_ptr_idx(stkctr->table, ts, STKTABLE_DT_GPC_RATE, 1);
2482 if (ptr1)
2483 period = stkctr->table->data_arg[STKTABLE_DT_GPC_RATE].u;
2484 }
2485
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002486 ptr2 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC1);
Emeric Brun726783d2021-06-30 19:06:43 +02002487 if (!ptr2) {
2488 /* fallback on the gpc array */
2489 ptr2 = stktable_data_ptr_idx(stkctr->table, ts, STKTABLE_DT_GPC, 1);
2490 }
2491
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002492 if (ptr1 || ptr2) {
2493 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
2494
2495 if (ptr1)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002496 update_freq_ctr_period(&stktable_data_cast(ptr1, std_t_frqp),
Emeric Brun726783d2021-06-30 19:06:43 +02002497 period, 1);
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002498
2499 if (ptr2)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002500 stktable_data_cast(ptr2, std_t_uint)++;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002501
2502 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
2503
2504 /* If data was modified, we need to touch to re-schedule sync */
2505 stktable_touch_local(stkctr->table, ts, 0);
2506 }
2507 }
2508 return ACT_RET_CONT;
2509}
2510
Emeric Brun4d7ada82021-06-30 19:04:16 +02002511/* This function is a common parser for actions incrementing the GPC
2512 * (General Purpose Counters). It understands the formats:
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002513 *
Emeric Brun4d7ada82021-06-30 19:04:16 +02002514 * sc-inc-gpc(<gpc IDX>,<track ID>)
2515 * sc-inc-gpc0([<track ID>])
2516 * sc-inc-gpc1([<track ID>])
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002517 *
Emeric Brun4d7ada82021-06-30 19:04:16 +02002518 * It returns ACT_RET_PRS_ERR if fails and <err> is filled with an error
2519 * message. Otherwise it returns ACT_RET_PRS_OK.
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002520 */
Emeric Brun4d7ada82021-06-30 19:04:16 +02002521static enum act_parse_ret parse_inc_gpc(const char **args, int *arg, struct proxy *px,
2522 struct act_rule *rule, char **err)
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002523{
2524 const char *cmd_name = args[*arg-1];
2525 char *error;
2526
Willy Tarreau6c011712023-01-06 16:09:58 +01002527 if (!global.tune.nb_stk_ctr) {
2528 memprintf(err, "Cannot use '%s', stick-counters are disabled via tune.stick-counters", args[*arg-1]);
2529 return ACT_RET_PRS_ERR;
2530 }
2531
Emeric Brun4d7ada82021-06-30 19:04:16 +02002532 cmd_name += strlen("sc-inc-gpc");
2533 if (*cmd_name == '(') {
2534 cmd_name++; /* skip the '(' */
2535 rule->arg.gpc.idx = strtoul(cmd_name, &error, 10); /* Convert stick table id. */
2536 if (*error != ',') {
2537 memprintf(err, "Missing gpc ID '%s'. Expects sc-inc-gpc(<GPC ID>,<Track ID>)", args[*arg-1]);
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002538 return ACT_RET_PRS_ERR;
2539 }
Emeric Brun4d7ada82021-06-30 19:04:16 +02002540 else {
2541 cmd_name = error + 1; /* skip the ',' */
2542 rule->arg.gpc.sc = strtol(cmd_name, &error, 10); /* Convert stick table id. */
2543 if (*error != ')') {
2544 memprintf(err, "invalid stick table track ID '%s'. Expects sc-inc-gpc(<GPC ID>,<Track ID>)", args[*arg-1]);
2545 return ACT_RET_PRS_ERR;
2546 }
2547
Willy Tarreau6c011712023-01-06 16:09:58 +01002548 if (rule->arg.gpc.sc >= global.tune.nb_stk_ctr) {
2549 memprintf(err, "invalid stick table track ID '%s'. The max allowed ID is %d (tune.stick-counters)",
2550 args[*arg-1], global.tune.nb_stk_ctr-1);
Emeric Brun4d7ada82021-06-30 19:04:16 +02002551 return ACT_RET_PRS_ERR;
2552 }
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002553 }
Emeric Brun4d7ada82021-06-30 19:04:16 +02002554 rule->action_ptr = action_inc_gpc;
2555 }
2556 else if (*cmd_name == '0' ||*cmd_name == '1') {
2557 char c = *cmd_name;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002558
Emeric Brun4d7ada82021-06-30 19:04:16 +02002559 cmd_name++;
2560 if (*cmd_name == '\0') {
2561 /* default stick table id. */
2562 rule->arg.gpc.sc = 0;
2563 } else {
2564 /* parse the stick table id. */
2565 if (*cmd_name != '(') {
2566 memprintf(err, "invalid stick table track ID. Expects %s(<Track ID>)", args[*arg-1]);
2567 return ACT_RET_PRS_ERR;
2568 }
2569 cmd_name++; /* jump the '(' */
2570 rule->arg.gpc.sc = strtol(cmd_name, &error, 10); /* Convert stick table id. */
2571 if (*error != ')') {
2572 memprintf(err, "invalid stick table track ID. Expects %s(<Track ID>)", args[*arg-1]);
2573 return ACT_RET_PRS_ERR;
2574 }
2575
Willy Tarreau6c011712023-01-06 16:09:58 +01002576 if (rule->arg.gpc.sc >= global.tune.nb_stk_ctr) {
2577 memprintf(err, "invalid stick table track ID. The max allowed ID is %d (tune.stick-counters)",
2578 global.tune.nb_stk_ctr-1);
Emeric Brun4d7ada82021-06-30 19:04:16 +02002579 return ACT_RET_PRS_ERR;
2580 }
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002581 }
Emeric Brun4d7ada82021-06-30 19:04:16 +02002582 if (c == '1')
2583 rule->action_ptr = action_inc_gpc1;
2584 else
2585 rule->action_ptr = action_inc_gpc0;
2586 }
2587 else {
2588 /* default stick table id. */
Willy Tarreau20391512023-01-02 17:35:50 +01002589 memprintf(err, "invalid gpc ID '%s'. Expects sc-inc-gpc(<GPC ID>,<Track ID>)", args[*arg-1]);
Emeric Brun4d7ada82021-06-30 19:04:16 +02002590 return ACT_RET_PRS_ERR;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002591 }
2592 rule->action = ACT_CUSTOM;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002593 return ACT_RET_PRS_OK;
2594}
2595
Emeric Brun877b0b52021-06-30 18:57:49 +02002596/* This function sets the gpt at index 'rule->arg.gpt.idx' of the array on the
2597 * tracksc counter of index 'rule->arg.gpt.sc' stored into the <stream> or
2598 * directly in the session <sess> if <stream> is set to NULL. This gpt is
2599 * set to the value computed by the expression 'rule->arg.gpt.expr' or if
2600 * 'rule->arg.gpt.expr' is null directly to the value of 'rule->arg.gpt.value'.
2601 *
2602 * This function always returns ACT_RET_CONT and parameter flags is unused.
2603 */
2604static enum act_return action_set_gpt(struct act_rule *rule, struct proxy *px,
2605 struct session *sess, struct stream *s, int flags)
2606{
2607 void *ptr;
2608 struct stksess *ts;
Willy Tarreau6c011712023-01-06 16:09:58 +01002609 struct stkctr *stkctr = NULL;
Emeric Brun877b0b52021-06-30 18:57:49 +02002610 unsigned int value = 0;
2611 struct sample *smp;
2612 int smp_opt_dir;
2613
2614 /* Extract the stksess, return OK if no stksess available. */
Willy Tarreau6c011712023-01-06 16:09:58 +01002615 if (s && s->stkctr)
Emeric Brun877b0b52021-06-30 18:57:49 +02002616 stkctr = &s->stkctr[rule->arg.gpt.sc];
Willy Tarreau6c011712023-01-06 16:09:58 +01002617 else if (sess->stkctr)
Emeric Brun877b0b52021-06-30 18:57:49 +02002618 stkctr = &sess->stkctr[rule->arg.gpt.sc];
Willy Tarreau6c011712023-01-06 16:09:58 +01002619 else
2620 return ACT_RET_CONT;
Emeric Brun877b0b52021-06-30 18:57:49 +02002621
2622 ts = stkctr_entry(stkctr);
2623 if (!ts)
2624 return ACT_RET_CONT;
2625
2626 /* Store the sample in the required sc, and ignore errors. */
2627 ptr = stktable_data_ptr_idx(stkctr->table, ts, STKTABLE_DT_GPT, rule->arg.gpt.idx);
2628 if (ptr) {
2629
2630 if (!rule->arg.gpt.expr)
2631 value = (unsigned int)(rule->arg.gpt.value);
2632 else {
2633 switch (rule->from) {
2634 case ACT_F_TCP_REQ_SES: smp_opt_dir = SMP_OPT_DIR_REQ; break;
2635 case ACT_F_TCP_REQ_CNT: smp_opt_dir = SMP_OPT_DIR_REQ; break;
2636 case ACT_F_TCP_RES_CNT: smp_opt_dir = SMP_OPT_DIR_RES; break;
2637 case ACT_F_HTTP_REQ: smp_opt_dir = SMP_OPT_DIR_REQ; break;
2638 case ACT_F_HTTP_RES: smp_opt_dir = SMP_OPT_DIR_RES; break;
2639 default:
2640 send_log(px, LOG_ERR, "stick table: internal error while setting gpt%u.", rule->arg.gpt.idx);
2641 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))
2642 ha_alert("stick table: internal error while executing setting gpt%u.\n", rule->arg.gpt.idx);
2643 return ACT_RET_CONT;
2644 }
2645
2646 /* Fetch and cast the expression. */
2647 smp = sample_fetch_as_type(px, sess, s, smp_opt_dir|SMP_OPT_FINAL, rule->arg.gpt.expr, SMP_T_SINT);
2648 if (!smp) {
2649 send_log(px, LOG_WARNING, "stick table: invalid expression or data type while setting gpt%u.", rule->arg.gpt.idx);
2650 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))
2651 ha_alert("stick table: invalid expression or data type while setting gpt%u.\n", rule->arg.gpt.idx);
2652 return ACT_RET_CONT;
2653 }
2654 value = (unsigned int)(smp->data.u.sint);
2655 }
2656
2657 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
2658
2659 stktable_data_cast(ptr, std_t_uint) = value;
2660
2661 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
2662
2663 stktable_touch_local(stkctr->table, ts, 0);
2664 }
2665
2666 return ACT_RET_CONT;
2667}
2668
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002669/* Always returns 1. */
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002670static enum act_return action_set_gpt0(struct act_rule *rule, struct proxy *px,
Willy Tarreau658b85b2015-09-27 10:00:49 +02002671 struct session *sess, struct stream *s, int flags)
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002672{
2673 void *ptr;
2674 struct stksess *ts;
Willy Tarreau6c011712023-01-06 16:09:58 +01002675 struct stkctr *stkctr = NULL;
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002676 unsigned int value = 0;
2677 struct sample *smp;
2678 int smp_opt_dir;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002679
2680 /* Extract the stksess, return OK if no stksess available. */
Willy Tarreau6c011712023-01-06 16:09:58 +01002681 if (s && s->stkctr)
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002682 stkctr = &s->stkctr[rule->arg.gpt.sc];
Willy Tarreau6c011712023-01-06 16:09:58 +01002683 else if (sess->stkctr)
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002684 stkctr = &sess->stkctr[rule->arg.gpt.sc];
Willy Tarreau6c011712023-01-06 16:09:58 +01002685 else
2686 return ACT_RET_CONT;
Willy Tarreau79c1e912016-01-25 14:54:45 +01002687
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002688 ts = stkctr_entry(stkctr);
2689 if (!ts)
2690 return ACT_RET_CONT;
2691
2692 /* Store the sample in the required sc, and ignore errors. */
2693 ptr = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPT0);
Emeric Brunf7ab0bf2021-06-30 18:58:22 +02002694 if (!ptr)
2695 ptr = stktable_data_ptr_idx(stkctr->table, ts, STKTABLE_DT_GPT, 0);
2696
Willy Tarreau79c1e912016-01-25 14:54:45 +01002697 if (ptr) {
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002698 if (!rule->arg.gpt.expr)
2699 value = (unsigned int)(rule->arg.gpt.value);
2700 else {
2701 switch (rule->from) {
2702 case ACT_F_TCP_REQ_SES: smp_opt_dir = SMP_OPT_DIR_REQ; break;
2703 case ACT_F_TCP_REQ_CNT: smp_opt_dir = SMP_OPT_DIR_REQ; break;
2704 case ACT_F_TCP_RES_CNT: smp_opt_dir = SMP_OPT_DIR_RES; break;
2705 case ACT_F_HTTP_REQ: smp_opt_dir = SMP_OPT_DIR_REQ; break;
2706 case ACT_F_HTTP_RES: smp_opt_dir = SMP_OPT_DIR_RES; break;
2707 default:
2708 send_log(px, LOG_ERR, "stick table: internal error while setting gpt0.");
2709 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))
2710 ha_alert("stick table: internal error while executing setting gpt0.\n");
2711 return ACT_RET_CONT;
2712 }
2713
2714 /* Fetch and cast the expression. */
2715 smp = sample_fetch_as_type(px, sess, s, smp_opt_dir|SMP_OPT_FINAL, rule->arg.gpt.expr, SMP_T_SINT);
2716 if (!smp) {
2717 send_log(px, LOG_WARNING, "stick table: invalid expression or data type while setting gpt0.");
2718 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))
2719 ha_alert("stick table: invalid expression or data type while setting gpt0.\n");
2720 return ACT_RET_CONT;
2721 }
2722 value = (unsigned int)(smp->data.u.sint);
2723 }
2724
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002725 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002726
Emeric Brun0e3457b2021-06-30 17:18:28 +02002727 stktable_data_cast(ptr, std_t_uint) = value;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002728
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002729 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002730
2731 stktable_touch_local(stkctr->table, ts, 0);
Willy Tarreau79c1e912016-01-25 14:54:45 +01002732 }
2733
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002734 return ACT_RET_CONT;
2735}
2736
Emeric Brun877b0b52021-06-30 18:57:49 +02002737/* This function is a parser for the "sc-set-gpt" and "sc-set-gpt0" actions.
2738 * It understands the formats:
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002739 *
Emeric Brun877b0b52021-06-30 18:57:49 +02002740 * sc-set-gpt(<gpt IDX>,<track ID>) <expression>
2741 * sc-set-gpt0(<track ID>) <expression>
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002742 *
Emeric Brun877b0b52021-06-30 18:57:49 +02002743 * It returns ACT_RET_PRS_ERR if fails and <err> is filled with an error message.
2744 * Otherwise, it returns ACT_RET_PRS_OK and the variable 'rule->arg.gpt.expr'
2745 * is filled with the pointer to the expression to execute or NULL if the arg
2746 * is directly an integer stored into 'rule->arg.gpt.value'.
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002747 */
Emeric Brun877b0b52021-06-30 18:57:49 +02002748static enum act_parse_ret parse_set_gpt(const char **args, int *arg, struct proxy *px,
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002749 struct act_rule *rule, char **err)
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002750{
2751 const char *cmd_name = args[*arg-1];
2752 char *error;
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002753 int smp_val;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002754
Willy Tarreau6c011712023-01-06 16:09:58 +01002755 if (!global.tune.nb_stk_ctr) {
2756 memprintf(err, "Cannot use '%s', stick-counters are disabled via tune.stick-counters", args[*arg-1]);
2757 return ACT_RET_PRS_ERR;
2758 }
2759
Emeric Brun877b0b52021-06-30 18:57:49 +02002760 cmd_name += strlen("sc-set-gpt");
2761 if (*cmd_name == '(') {
2762 cmd_name++; /* skip the '(' */
2763 rule->arg.gpt.idx = strtoul(cmd_name, &error, 10); /* Convert stick table id. */
2764 if (*error != ',') {
2765 memprintf(err, "Missing gpt ID '%s'. Expects sc-set-gpt(<GPT ID>,<Track ID>)", args[*arg-1]);
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002766 return ACT_RET_PRS_ERR;
2767 }
Emeric Brun877b0b52021-06-30 18:57:49 +02002768 else {
2769 cmd_name = error + 1; /* skip the ',' */
2770 rule->arg.gpt.sc = strtol(cmd_name, &error, 10); /* Convert stick table id. */
2771 if (*error != ')') {
2772 memprintf(err, "invalid stick table track ID '%s'. Expects sc-set-gpt(<GPT ID>,<Track ID>)", args[*arg-1]);
2773 return ACT_RET_PRS_ERR;
2774 }
2775
Willy Tarreau6c011712023-01-06 16:09:58 +01002776 if (rule->arg.gpt.sc >= global.tune.nb_stk_ctr) {
Emeric Brun877b0b52021-06-30 18:57:49 +02002777 memprintf(err, "invalid stick table track ID '%s'. The max allowed ID is %d",
Willy Tarreau6c011712023-01-06 16:09:58 +01002778 args[*arg-1], global.tune.nb_stk_ctr-1);
Emeric Brun877b0b52021-06-30 18:57:49 +02002779 return ACT_RET_PRS_ERR;
2780 }
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002781 }
Emeric Brun877b0b52021-06-30 18:57:49 +02002782 rule->action_ptr = action_set_gpt;
2783 }
2784 else if (*cmd_name == '0') {
2785 cmd_name++;
2786 if (*cmd_name == '\0') {
2787 /* default stick table id. */
2788 rule->arg.gpt.sc = 0;
2789 } else {
2790 /* parse the stick table id. */
2791 if (*cmd_name != '(') {
2792 memprintf(err, "invalid stick table track ID '%s'. Expects sc-set-gpt0(<Track ID>)", args[*arg-1]);
2793 return ACT_RET_PRS_ERR;
2794 }
2795 cmd_name++; /* jump the '(' */
2796 rule->arg.gpt.sc = strtol(cmd_name, &error, 10); /* Convert stick table id. */
2797 if (*error != ')') {
2798 memprintf(err, "invalid stick table track ID '%s'. Expects sc-set-gpt0(<Track ID>)", args[*arg-1]);
2799 return ACT_RET_PRS_ERR;
2800 }
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002801
Willy Tarreau6c011712023-01-06 16:09:58 +01002802 if (rule->arg.gpt.sc >= global.tune.nb_stk_ctr) {
Emeric Brun877b0b52021-06-30 18:57:49 +02002803 memprintf(err, "invalid stick table track ID '%s'. The max allowed ID is %d",
Willy Tarreau6c011712023-01-06 16:09:58 +01002804 args[*arg-1], global.tune.nb_stk_ctr-1);
Emeric Brun877b0b52021-06-30 18:57:49 +02002805 return ACT_RET_PRS_ERR;
2806 }
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002807 }
Emeric Brun877b0b52021-06-30 18:57:49 +02002808 rule->action_ptr = action_set_gpt0;
2809 }
2810 else {
2811 /* default stick table id. */
2812 memprintf(err, "invalid gpt ID '%s'. Expects sc-set-gpt(<GPT ID>,<Track ID>)", args[*arg-1]);
2813 return ACT_RET_PRS_ERR;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002814 }
2815
Willy Tarreauece4c4a2021-08-24 14:57:28 +02002816 /* value may be either an integer or an expression */
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002817 rule->arg.gpt.expr = NULL;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002818 rule->arg.gpt.value = strtol(args[*arg], &error, 10);
Willy Tarreauece4c4a2021-08-24 14:57:28 +02002819 if (*error == '\0') {
2820 /* valid integer, skip it */
2821 (*arg)++;
2822 } else {
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002823 rule->arg.gpt.expr = sample_parse_expr((char **)args, arg, px->conf.args.file,
Willy Tarreaue3b57bf2020-02-14 16:50:14 +01002824 px->conf.args.line, err, &px->conf.args, NULL);
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002825 if (!rule->arg.gpt.expr)
2826 return ACT_RET_PRS_ERR;
2827
2828 switch (rule->from) {
2829 case ACT_F_TCP_REQ_SES: smp_val = SMP_VAL_FE_SES_ACC; break;
2830 case ACT_F_TCP_REQ_CNT: smp_val = SMP_VAL_FE_REQ_CNT; break;
2831 case ACT_F_TCP_RES_CNT: smp_val = SMP_VAL_BE_RES_CNT; break;
2832 case ACT_F_HTTP_REQ: smp_val = SMP_VAL_FE_HRQ_HDR; break;
2833 case ACT_F_HTTP_RES: smp_val = SMP_VAL_BE_HRS_HDR; break;
2834 default:
2835 memprintf(err, "internal error, unexpected rule->from=%d, please report this bug!", rule->from);
2836 return ACT_RET_PRS_ERR;
2837 }
2838 if (!(rule->arg.gpt.expr->fetch->val & smp_val)) {
2839 memprintf(err, "fetch method '%s' extracts information from '%s', none of which is available here", args[*arg-1],
2840 sample_src_names(rule->arg.gpt.expr->fetch->use));
2841 free(rule->arg.gpt.expr);
2842 return ACT_RET_PRS_ERR;
2843 }
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002844 }
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002845
Thierry FOURNIER42148732015-09-02 17:17:33 +02002846 rule->action = ACT_CUSTOM;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002847
2848 return ACT_RET_PRS_OK;
2849}
2850
Willy Tarreau5a72d032023-01-02 18:15:20 +01002851/* This function updates the gpc at index 'rule->arg.gpc.idx' of the array on
2852 * the tracksc counter of index 'rule->arg.gpc.sc' stored into the <stream> or
2853 * directly in the session <sess> if <stream> is set to NULL. This gpc is
2854 * set to the value computed by the expression 'rule->arg.gpc.expr' or if
2855 * 'rule->arg.gpc.expr' is null directly to the value of 'rule->arg.gpc.value'.
2856 *
2857 * This function always returns ACT_RET_CONT and parameter flags is unused.
2858 */
2859static enum act_return action_add_gpc(struct act_rule *rule, struct proxy *px,
2860 struct session *sess, struct stream *s, int flags)
2861{
2862 void *ptr1, *ptr2;
2863 struct stksess *ts;
2864 struct stkctr *stkctr;
2865 unsigned int value = 0;
2866 struct sample *smp;
2867 int smp_opt_dir;
2868
2869 /* Extract the stksess, return OK if no stksess available. */
2870 if (s)
2871 stkctr = &s->stkctr[rule->arg.gpc.sc];
2872 else
2873 stkctr = &sess->stkctr[rule->arg.gpc.sc];
2874
2875 ts = stkctr_entry(stkctr);
2876 if (!ts)
2877 return ACT_RET_CONT;
2878
2879 /* First, update gpc_rate if it's tracked. Second, update its gpc if tracked. */
2880 ptr1 = stktable_data_ptr_idx(stkctr->table, ts, STKTABLE_DT_GPC_RATE, rule->arg.gpc.idx);
2881 ptr2 = stktable_data_ptr_idx(stkctr->table, ts, STKTABLE_DT_GPC, rule->arg.gpc.idx);
2882
2883 if (ptr1 || ptr2) {
2884 if (!rule->arg.gpc.expr)
2885 value = (unsigned int)(rule->arg.gpc.value);
2886 else {
2887 switch (rule->from) {
2888 case ACT_F_TCP_REQ_SES: smp_opt_dir = SMP_OPT_DIR_REQ; break;
2889 case ACT_F_TCP_REQ_CNT: smp_opt_dir = SMP_OPT_DIR_REQ; break;
2890 case ACT_F_TCP_RES_CNT: smp_opt_dir = SMP_OPT_DIR_RES; break;
2891 case ACT_F_HTTP_REQ: smp_opt_dir = SMP_OPT_DIR_REQ; break;
2892 case ACT_F_HTTP_RES: smp_opt_dir = SMP_OPT_DIR_RES; break;
2893 default:
2894 send_log(px, LOG_ERR, "stick table: internal error while setting gpc%u.", rule->arg.gpc.idx);
2895 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))
2896 ha_alert("stick table: internal error while executing setting gpc%u.\n", rule->arg.gpc.idx);
2897 return ACT_RET_CONT;
2898 }
2899
2900 /* Fetch and cast the expression. */
2901 smp = sample_fetch_as_type(px, sess, s, smp_opt_dir|SMP_OPT_FINAL, rule->arg.gpc.expr, SMP_T_SINT);
2902 if (!smp) {
2903 send_log(px, LOG_WARNING, "stick table: invalid expression or data type while setting gpc%u.", rule->arg.gpc.idx);
2904 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))
2905 ha_alert("stick table: invalid expression or data type while setting gpc%u.\n", rule->arg.gpc.idx);
2906 return ACT_RET_CONT;
2907 }
2908 value = (unsigned int)(smp->data.u.sint);
2909 }
2910
2911 if (value) {
2912 /* only update the value if non-null increment */
2913 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
2914
2915 if (ptr1)
2916 update_freq_ctr_period(&stktable_data_cast(ptr1, std_t_frqp),
2917 stkctr->table->data_arg[STKTABLE_DT_GPC_RATE].u, value);
2918
2919 if (ptr2)
2920 stktable_data_cast(ptr2, std_t_uint) += value;
2921
2922 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
2923 }
2924 /* always touch the table so that it doesn't expire */
2925 stktable_touch_local(stkctr->table, ts, 0);
2926 }
2927
2928 return ACT_RET_CONT;
2929}
2930
2931/* This function is a parser for the "sc-add-gpc" action. It understands the
2932 * format:
2933 *
2934 * sc-add-gpc(<gpc IDX>,<track ID>) <expression>
2935 *
2936 * It returns ACT_RET_PRS_ERR if fails and <err> is filled with an error message.
2937 * Otherwise, it returns ACT_RET_PRS_OK and the variable 'rule->arg.gpc.expr'
2938 * is filled with the pointer to the expression to execute or NULL if the arg
2939 * is directly an integer stored into 'rule->arg.gpt.value'.
2940 */
2941static enum act_parse_ret parse_add_gpc(const char **args, int *arg, struct proxy *px,
2942 struct act_rule *rule, char **err)
2943{
2944 const char *cmd_name = args[*arg-1];
2945 char *error;
2946 int smp_val;
2947
2948 cmd_name += strlen("sc-add-gpc");
2949 if (*cmd_name != '(') {
2950 memprintf(err, "Missing or invalid arguments for '%s'. Expects sc-add-gpc(<GPC ID>,<Track ID>)", args[*arg-1]);
2951 return ACT_RET_PRS_ERR;
2952 }
2953 cmd_name++; /* skip the '(' */
2954 rule->arg.gpc.idx = strtoul(cmd_name, &error, 10); /* Convert stick table id. */
2955 if (*error != ',') {
2956 memprintf(err, "Missing gpc ID. Expects %s(<GPC ID>,<Track ID>)", args[*arg-1]);
2957 return ACT_RET_PRS_ERR;
2958 }
2959 else {
2960 cmd_name = error + 1; /* skip the ',' */
2961 rule->arg.gpc.sc = strtol(cmd_name, &error, 10); /* Convert stick table id. */
2962 if (*error != ')') {
2963 memprintf(err, "invalid stick table track ID '%s'. Expects %s(<GPC ID>,<Track ID>)", cmd_name, args[*arg-1]);
2964 return ACT_RET_PRS_ERR;
2965 }
2966
2967 if (rule->arg.gpc.sc >= MAX_SESS_STKCTR) {
2968 memprintf(err, "invalid stick table track ID '%s' for '%s'. The max allowed ID is %d",
2969 cmd_name, args[*arg-1], MAX_SESS_STKCTR-1);
2970 return ACT_RET_PRS_ERR;
2971 }
2972 }
2973 rule->action_ptr = action_add_gpc;
2974
2975 /* value may be either an integer or an expression */
2976 rule->arg.gpc.expr = NULL;
2977 rule->arg.gpc.value = strtol(args[*arg], &error, 10);
2978 if (*error == '\0') {
2979 /* valid integer, skip it */
2980 (*arg)++;
2981 } else {
2982 rule->arg.gpc.expr = sample_parse_expr((char **)args, arg, px->conf.args.file,
2983 px->conf.args.line, err, &px->conf.args, NULL);
2984 if (!rule->arg.gpc.expr)
2985 return ACT_RET_PRS_ERR;
2986
2987 switch (rule->from) {
2988 case ACT_F_TCP_REQ_SES: smp_val = SMP_VAL_FE_SES_ACC; break;
2989 case ACT_F_TCP_REQ_CNT: smp_val = SMP_VAL_FE_REQ_CNT; break;
2990 case ACT_F_TCP_RES_CNT: smp_val = SMP_VAL_BE_RES_CNT; break;
2991 case ACT_F_HTTP_REQ: smp_val = SMP_VAL_FE_HRQ_HDR; break;
2992 case ACT_F_HTTP_RES: smp_val = SMP_VAL_BE_HRS_HDR; break;
2993 default:
2994 memprintf(err, "internal error, unexpected rule->from=%d, please report this bug!", rule->from);
2995 return ACT_RET_PRS_ERR;
2996 }
2997
2998 if (!(rule->arg.gpc.expr->fetch->val & smp_val)) {
2999 memprintf(err, "fetch method '%s' extracts information from '%s', none of which is available here", args[*arg-1],
3000 sample_src_names(rule->arg.gpc.expr->fetch->use));
3001 free(rule->arg.gpc.expr);
3002 return ACT_RET_PRS_ERR;
3003 }
3004 }
3005
3006 rule->action = ACT_CUSTOM;
3007
3008 return ACT_RET_PRS_OK;
3009}
3010
Willy Tarreau7d562212016-11-25 16:10:05 +01003011/* set temp integer to the number of used entries in the table pointed to by expr.
3012 * Accepts exactly 1 argument of type table.
3013 */
3014static int
3015smp_fetch_table_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
3016{
3017 smp->flags = SMP_F_VOL_TEST;
3018 smp->data.type = SMP_T_SINT;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003019 smp->data.u.sint = args->data.t->current;
Willy Tarreau7d562212016-11-25 16:10:05 +01003020 return 1;
3021}
3022
3023/* set temp integer to the number of free entries in the table pointed to by expr.
3024 * Accepts exactly 1 argument of type table.
3025 */
3026static int
3027smp_fetch_table_avl(const struct arg *args, struct sample *smp, const char *kw, void *private)
3028{
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003029 struct stktable *t;
Willy Tarreau7d562212016-11-25 16:10:05 +01003030
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003031 t = args->data.t;
Willy Tarreau7d562212016-11-25 16:10:05 +01003032 smp->flags = SMP_F_VOL_TEST;
3033 smp->data.type = SMP_T_SINT;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003034 smp->data.u.sint = t->size - t->current;
Willy Tarreau7d562212016-11-25 16:10:05 +01003035 return 1;
3036}
3037
3038/* Returns a pointer to a stkctr depending on the fetch keyword name.
3039 * It is designed to be called as sc[0-9]_* sc_* or src_* exclusively.
3040 * sc[0-9]_* will return a pointer to the respective field in the
3041 * stream <l4>. sc_* requires an UINT argument specifying the stick
3042 * counter number. src_* will fill a locally allocated structure with
3043 * the table and entry corresponding to what is specified with src_*.
3044 * NULL may be returned if the designated stkctr is not tracked. For
3045 * the sc_* and sc[0-9]_* forms, an optional table argument may be
3046 * passed. When present, the currently tracked key is then looked up
3047 * in the specified table instead of the current table. The purpose is
Ilya Shipitsin47d17182020-06-21 21:42:57 +05003048 * to be able to convert multiple values per key (eg: have gpc0 from
Willy Tarreau7d562212016-11-25 16:10:05 +01003049 * multiple tables). <strm> is allowed to be NULL, in which case only
3050 * the session will be consulted.
3051 */
3052struct stkctr *
Emeric Brun819fc6f2017-06-13 19:37:32 +02003053smp_fetch_sc_stkctr(struct session *sess, struct stream *strm, const struct arg *args, const char *kw, struct stkctr *stkctr)
Willy Tarreau7d562212016-11-25 16:10:05 +01003054{
Willy Tarreau7d562212016-11-25 16:10:05 +01003055 struct stkctr *stkptr;
3056 struct stksess *stksess;
3057 unsigned int num = kw[2] - '0';
3058 int arg = 0;
3059
3060 if (num == '_' - '0') {
3061 /* sc_* variant, args[0] = ctr# (mandatory) */
3062 num = args[arg++].data.sint;
Willy Tarreau7d562212016-11-25 16:10:05 +01003063 }
3064 else if (num > 9) { /* src_* variant, args[0] = table */
3065 struct stktable_key *key;
3066 struct connection *conn = objt_conn(sess->origin);
3067 struct sample smp;
3068
3069 if (!conn)
3070 return NULL;
3071
Joseph Herlant5662fa42018-11-15 13:43:28 -08003072 /* Fetch source address in a sample. */
Willy Tarreau7d562212016-11-25 16:10:05 +01003073 smp.px = NULL;
3074 smp.sess = sess;
3075 smp.strm = strm;
Amaury Denoyellec460c702021-05-12 10:17:47 +02003076 if (!smp_fetch_src || !smp_fetch_src(empty_arg_list, &smp, "src", NULL))
Willy Tarreau7d562212016-11-25 16:10:05 +01003077 return NULL;
3078
3079 /* Converts into key. */
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003080 key = smp_to_stkey(&smp, args->data.t);
Willy Tarreau7d562212016-11-25 16:10:05 +01003081 if (!key)
3082 return NULL;
3083
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003084 stkctr->table = args->data.t;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003085 stkctr_set_entry(stkctr, stktable_lookup_key(stkctr->table, key));
3086 return stkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003087 }
3088
3089 /* Here, <num> contains the counter number from 0 to 9 for
3090 * the sc[0-9]_ form, or even higher using sc_(num) if needed.
3091 * args[arg] is the first optional argument. We first lookup the
3092 * ctr form the stream, then from the session if it was not there.
Willy Tarreau6c011712023-01-06 16:09:58 +01003093 * But we must be sure the counter does not exceed global.tune.nb_stk_ctr.
Willy Tarreau7d562212016-11-25 16:10:05 +01003094 */
Willy Tarreau6c011712023-01-06 16:09:58 +01003095 if (num >= global.tune.nb_stk_ctr)
Christopher Fauleta9fa88a2019-10-21 10:53:34 +02003096 return NULL;
Willy Tarreau7d562212016-11-25 16:10:05 +01003097
Willy Tarreau6c011712023-01-06 16:09:58 +01003098 stkptr = NULL;
3099 if (strm && strm->stkctr)
Willy Tarreau7d562212016-11-25 16:10:05 +01003100 stkptr = &strm->stkctr[num];
Willy Tarreau6c011712023-01-06 16:09:58 +01003101 if (!strm || !stkptr || !stkctr_entry(stkptr)) {
3102 if (sess->stkctr)
3103 stkptr = &sess->stkctr[num];
3104 else
3105 return NULL;
Willy Tarreau7d562212016-11-25 16:10:05 +01003106 if (!stkctr_entry(stkptr))
3107 return NULL;
3108 }
3109
3110 stksess = stkctr_entry(stkptr);
3111 if (!stksess)
3112 return NULL;
3113
3114 if (unlikely(args[arg].type == ARGT_TAB)) {
3115 /* an alternate table was specified, let's look up the same key there */
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003116 stkctr->table = args[arg].data.t;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003117 stkctr_set_entry(stkctr, stktable_lookup(stkctr->table, stksess));
3118 return stkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003119 }
3120 return stkptr;
3121}
3122
3123/* same as smp_fetch_sc_stkctr() but dedicated to src_* and can create
3124 * the entry if it doesn't exist yet. This is needed for a few fetch
3125 * functions which need to create an entry, such as src_inc_gpc* and
3126 * src_clr_gpc*.
3127 */
3128struct stkctr *
Emeric Brun819fc6f2017-06-13 19:37:32 +02003129smp_create_src_stkctr(struct session *sess, struct stream *strm, const struct arg *args, const char *kw, struct stkctr *stkctr)
Willy Tarreau7d562212016-11-25 16:10:05 +01003130{
Willy Tarreau7d562212016-11-25 16:10:05 +01003131 struct stktable_key *key;
3132 struct connection *conn = objt_conn(sess->origin);
3133 struct sample smp;
3134
3135 if (strncmp(kw, "src_", 4) != 0)
3136 return NULL;
3137
3138 if (!conn)
3139 return NULL;
3140
Joseph Herlant5662fa42018-11-15 13:43:28 -08003141 /* Fetch source address in a sample. */
Willy Tarreau7d562212016-11-25 16:10:05 +01003142 smp.px = NULL;
3143 smp.sess = sess;
3144 smp.strm = strm;
Amaury Denoyellec460c702021-05-12 10:17:47 +02003145 if (!smp_fetch_src || !smp_fetch_src(empty_arg_list, &smp, "src", NULL))
Willy Tarreau7d562212016-11-25 16:10:05 +01003146 return NULL;
3147
3148 /* Converts into key. */
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003149 key = smp_to_stkey(&smp, args->data.t);
Willy Tarreau7d562212016-11-25 16:10:05 +01003150 if (!key)
3151 return NULL;
3152
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003153 stkctr->table = args->data.t;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003154 stkctr_set_entry(stkctr, stktable_get_entry(stkctr->table, key));
3155 return stkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003156}
3157
3158/* set return a boolean indicating if the requested stream counter is
3159 * currently being tracked or not.
3160 * Supports being called as "sc[0-9]_tracked" only.
3161 */
3162static int
3163smp_fetch_sc_tracked(const struct arg *args, struct sample *smp, const char *kw, void *private)
3164{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003165 struct stkctr tmpstkctr;
3166 struct stkctr *stkctr;
3167
Willy Tarreau7d562212016-11-25 16:10:05 +01003168 smp->flags = SMP_F_VOL_TEST;
3169 smp->data.type = SMP_T_BOOL;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003170 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
3171 smp->data.u.sint = !!stkctr;
3172
3173 /* release the ref count */
Dirkjan Bussinkff57f1b2018-09-14 14:31:22 +02003174 if (stkctr == &tmpstkctr)
Emeric Brun819fc6f2017-06-13 19:37:32 +02003175 stktable_release(stkctr->table, stkctr_entry(stkctr));
3176
Emeric Brun877b0b52021-06-30 18:57:49 +02003177 return 1;
3178}
3179
3180/* set <smp> to the General Purpose Tag of index set as first arg
3181 * to value from the stream's tracked frontend counters or from the src.
3182 * Supports being called as "sc_get_gpt(<gpt-idx>,<sc-idx>[,<table>])" or
3183 * "src_get_gpt(<gpt-idx>[,<table>])" only. Value zero is returned if
3184 * the key is new or gpt is not stored.
3185 */
3186static int
3187smp_fetch_sc_get_gpt(const struct arg *args, struct sample *smp, const char *kw, void *private)
3188{
3189 struct stkctr tmpstkctr;
3190 struct stkctr *stkctr;
3191 unsigned int idx;
3192
3193 idx = args[0].data.sint;
3194
3195 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args + 1, kw, &tmpstkctr);
3196 if (!stkctr)
3197 return 0;
3198
3199 smp->flags = SMP_F_VOL_TEST;
3200 smp->data.type = SMP_T_SINT;
3201 smp->data.u.sint = 0;
3202
3203 if (stkctr_entry(stkctr)) {
3204 void *ptr;
3205
3206 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPT, idx);
3207 if (!ptr) {
3208 if (stkctr == &tmpstkctr)
3209 stktable_release(stkctr->table, stkctr_entry(stkctr));
3210 return 0; /* parameter not stored */
3211 }
3212
3213 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3214
3215 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
3216
3217 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3218
3219 if (stkctr == &tmpstkctr)
3220 stktable_release(stkctr->table, stkctr_entry(stkctr));
3221 }
Willy Tarreau7d562212016-11-25 16:10:05 +01003222 return 1;
3223}
3224
3225/* set <smp> to the General Purpose Flag 0 value from the stream's tracked
3226 * frontend counters or from the src.
3227 * Supports being called as "sc[0-9]_get_gpc0" or "src_get_gpt0" only. Value
3228 * zero is returned if the key is new.
3229 */
3230static int
3231smp_fetch_sc_get_gpt0(const struct arg *args, struct sample *smp, const char *kw, void *private)
3232{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003233 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003234 struct stkctr *stkctr;
3235
Emeric Brun819fc6f2017-06-13 19:37:32 +02003236 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003237 if (!stkctr)
3238 return 0;
3239
3240 smp->flags = SMP_F_VOL_TEST;
3241 smp->data.type = SMP_T_SINT;
3242 smp->data.u.sint = 0;
3243
Emeric Brun819fc6f2017-06-13 19:37:32 +02003244 if (stkctr_entry(stkctr)) {
3245 void *ptr;
3246
3247 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPT0);
Emeric Brunf7ab0bf2021-06-30 18:58:22 +02003248 if (!ptr)
3249 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPT, 0);
3250
Emeric Brun4d7ada82021-06-30 19:04:16 +02003251 if (!ptr) {
3252 if (stkctr == &tmpstkctr)
3253 stktable_release(stkctr->table, stkctr_entry(stkctr));
3254 return 0; /* parameter not stored */
3255 }
3256
3257 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3258
3259 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
3260
3261 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3262
3263 if (stkctr == &tmpstkctr)
3264 stktable_release(stkctr->table, stkctr_entry(stkctr));
3265 }
3266 return 1;
3267}
3268
3269/* set <smp> to the GPC[args(0)]'s value from the stream's tracked
3270 * frontend counters or from the src.
3271 * Supports being called as "sc_get_gpc(<gpc-idx>,<sc-idx>[,<table>])" or
3272 * "src_get_gpc(<gpc-idx>[,<table>])" only. Value
3273 * Value zero is returned if the key is new or gpc is not stored.
3274 */
3275static int
3276smp_fetch_sc_get_gpc(const struct arg *args, struct sample *smp, const char *kw, void *private)
3277{
3278 struct stkctr tmpstkctr;
3279 struct stkctr *stkctr;
3280 unsigned int idx;
3281
3282 idx = args[0].data.sint;
3283
3284 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args + 1, kw, &tmpstkctr);
3285 if (!stkctr)
3286 return 0;
3287
3288 smp->flags = SMP_F_VOL_TEST;
3289 smp->data.type = SMP_T_SINT;
3290 smp->data.u.sint = 0;
3291
3292 if (stkctr_entry(stkctr) != NULL) {
3293 void *ptr;
3294
3295 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC, idx);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003296 if (!ptr) {
3297 if (stkctr == &tmpstkctr)
3298 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003299 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003300 }
3301
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003302 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003303
Emeric Brun0e3457b2021-06-30 17:18:28 +02003304 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003305
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003306 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003307
3308 if (stkctr == &tmpstkctr)
3309 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003310 }
3311 return 1;
3312}
3313
3314/* set <smp> to the General Purpose Counter 0 value from the stream's tracked
3315 * frontend counters or from the src.
3316 * Supports being called as "sc[0-9]_get_gpc0" or "src_get_gpc0" only. Value
3317 * zero is returned if the key is new.
3318 */
3319static int
3320smp_fetch_sc_get_gpc0(const struct arg *args, struct sample *smp, const char *kw, void *private)
3321{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003322 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003323 struct stkctr *stkctr;
3324
Emeric Brun819fc6f2017-06-13 19:37:32 +02003325 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003326 if (!stkctr)
3327 return 0;
3328
3329 smp->flags = SMP_F_VOL_TEST;
3330 smp->data.type = SMP_T_SINT;
3331 smp->data.u.sint = 0;
3332
3333 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003334 void *ptr;
3335
3336 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0);
3337 if (!ptr) {
Emeric Brun726783d2021-06-30 19:06:43 +02003338 /* fallback on the gpc array */
3339 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC, 0);
3340 }
3341
3342 if (!ptr) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003343 if (stkctr == &tmpstkctr)
3344 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003345 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003346 }
3347
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003348 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003349
Emeric Brun0e3457b2021-06-30 17:18:28 +02003350 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003351
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003352 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003353
3354 if (stkctr == &tmpstkctr)
3355 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003356 }
3357 return 1;
3358}
3359
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003360/* set <smp> to the General Purpose Counter 1 value from the stream's tracked
3361 * frontend counters or from the src.
3362 * Supports being called as "sc[0-9]_get_gpc1" or "src_get_gpc1" only. Value
3363 * zero is returned if the key is new.
3364 */
3365static int
3366smp_fetch_sc_get_gpc1(const struct arg *args, struct sample *smp, const char *kw, void *private)
3367{
3368 struct stkctr tmpstkctr;
3369 struct stkctr *stkctr;
3370
3371 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
3372 if (!stkctr)
3373 return 0;
3374
3375 smp->flags = SMP_F_VOL_TEST;
3376 smp->data.type = SMP_T_SINT;
3377 smp->data.u.sint = 0;
3378
3379 if (stkctr_entry(stkctr) != NULL) {
3380 void *ptr;
3381
3382 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1);
3383 if (!ptr) {
Emeric Brun726783d2021-06-30 19:06:43 +02003384 /* fallback on the gpc array */
3385 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC, 1);
3386 }
3387
3388 if (!ptr) {
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003389 if (stkctr == &tmpstkctr)
3390 stktable_release(stkctr->table, stkctr_entry(stkctr));
3391 return 0; /* parameter not stored */
3392 }
3393
3394 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3395
Emeric Brun0e3457b2021-06-30 17:18:28 +02003396 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003397
3398 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3399
3400 if (stkctr == &tmpstkctr)
3401 stktable_release(stkctr->table, stkctr_entry(stkctr));
3402 }
3403 return 1;
3404}
3405
Emeric Brun4d7ada82021-06-30 19:04:16 +02003406/* set <smp> to the GPC[args(0)]'s event rate from the stream's
3407 * tracked frontend counters or from the src.
3408 * Supports being called as "sc_gpc_rate(<gpc-idx>,<sc-idx>[,<table])"
3409 * or "src_gpc_rate(<gpc-idx>[,<table>])" only.
3410 * Value zero is returned if the key is new or gpc_rate is not stored.
3411 */
3412static int
3413smp_fetch_sc_gpc_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3414{
3415 struct stkctr tmpstkctr;
3416 struct stkctr *stkctr;
3417 unsigned int idx;
3418
3419 idx = args[0].data.sint;
3420
3421 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args + 1, kw, &tmpstkctr);
3422 if (!stkctr)
3423 return 0;
3424
3425 smp->flags = SMP_F_VOL_TEST;
3426 smp->data.type = SMP_T_SINT;
3427 smp->data.u.sint = 0;
3428 if (stkctr_entry(stkctr) != NULL) {
3429 void *ptr;
3430
3431 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC_RATE, idx);
3432 if (!ptr) {
3433 if (stkctr == &tmpstkctr)
3434 stktable_release(stkctr->table, stkctr_entry(stkctr));
3435 return 0; /* parameter not stored */
3436 }
3437
3438 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3439
3440 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
3441 stkctr->table->data_arg[STKTABLE_DT_GPC_RATE].u);
3442
3443 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3444
3445 if (stkctr == &tmpstkctr)
3446 stktable_release(stkctr->table, stkctr_entry(stkctr));
3447 }
3448 return 1;
3449}
3450
Willy Tarreau7d562212016-11-25 16:10:05 +01003451/* set <smp> to the General Purpose Counter 0's event rate from the stream's
3452 * tracked frontend counters or from the src.
3453 * Supports being called as "sc[0-9]_gpc0_rate" or "src_gpc0_rate" only.
3454 * Value zero is returned if the key is new.
3455 */
3456static int
3457smp_fetch_sc_gpc0_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3458{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003459 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003460 struct stkctr *stkctr;
Emeric Brun726783d2021-06-30 19:06:43 +02003461 unsigned int period;
Willy Tarreau7d562212016-11-25 16:10:05 +01003462
Emeric Brun819fc6f2017-06-13 19:37:32 +02003463 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003464 if (!stkctr)
3465 return 0;
3466
3467 smp->flags = SMP_F_VOL_TEST;
3468 smp->data.type = SMP_T_SINT;
3469 smp->data.u.sint = 0;
3470 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003471 void *ptr;
3472
3473 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0_RATE);
Emeric Brun726783d2021-06-30 19:06:43 +02003474 if (ptr) {
3475 period = stkctr->table->data_arg[STKTABLE_DT_GPC0_RATE].u;
3476 }
3477 else {
3478 /* fallback on the gpc array */
3479 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC_RATE, 0);
3480 if (ptr)
3481 period = stkctr->table->data_arg[STKTABLE_DT_GPC_RATE].u;
3482 }
3483
Emeric Brun819fc6f2017-06-13 19:37:32 +02003484 if (!ptr) {
3485 if (stkctr == &tmpstkctr)
3486 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003487 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003488 }
3489
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003490 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003491
Emeric Brun726783d2021-06-30 19:06:43 +02003492 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp), period);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003493
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003494 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003495
3496 if (stkctr == &tmpstkctr)
3497 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003498 }
3499 return 1;
3500}
3501
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003502/* set <smp> to the General Purpose Counter 1's event rate from the stream's
3503 * tracked frontend counters or from the src.
3504 * Supports being called as "sc[0-9]_gpc1_rate" or "src_gpc1_rate" only.
3505 * Value zero is returned if the key is new.
3506 */
3507static int
3508smp_fetch_sc_gpc1_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3509{
3510 struct stkctr tmpstkctr;
3511 struct stkctr *stkctr;
Emeric Brun726783d2021-06-30 19:06:43 +02003512 unsigned int period;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003513
3514 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
3515 if (!stkctr)
3516 return 0;
3517
3518 smp->flags = SMP_F_VOL_TEST;
3519 smp->data.type = SMP_T_SINT;
3520 smp->data.u.sint = 0;
3521 if (stkctr_entry(stkctr) != NULL) {
3522 void *ptr;
3523
3524 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1_RATE);
Emeric Brun726783d2021-06-30 19:06:43 +02003525 if (ptr) {
3526 period = stkctr->table->data_arg[STKTABLE_DT_GPC1_RATE].u;
3527 }
3528 else {
3529 /* fallback on the gpc array */
3530 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC_RATE, 1);
3531 if (ptr)
3532 period = stkctr->table->data_arg[STKTABLE_DT_GPC_RATE].u;
3533 }
3534
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003535 if (!ptr) {
3536 if (stkctr == &tmpstkctr)
3537 stktable_release(stkctr->table, stkctr_entry(stkctr));
3538 return 0; /* parameter not stored */
3539 }
3540
3541 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3542
Emeric Brun726783d2021-06-30 19:06:43 +02003543 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp), period);
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003544
3545 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3546
3547 if (stkctr == &tmpstkctr)
3548 stktable_release(stkctr->table, stkctr_entry(stkctr));
3549 }
3550 return 1;
3551}
3552
Emeric Brun4d7ada82021-06-30 19:04:16 +02003553/* Increment the GPC[args(0)] value from the stream's tracked
3554 * frontend counters and return it into temp integer.
3555 * Supports being called as "sc_inc_gpc(<gpc-idx>,<sc-idx>[,<table>])"
3556 * or "src_inc_gpc(<gpc-idx>[,<table>])" only.
3557 */
3558static int
3559smp_fetch_sc_inc_gpc(const struct arg *args, struct sample *smp, const char *kw, void *private)
3560{
3561 struct stkctr tmpstkctr;
3562 struct stkctr *stkctr;
3563 unsigned int idx;
3564
3565 idx = args[0].data.sint;
3566
3567 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args + 1, kw, &tmpstkctr);
3568 if (!stkctr)
3569 return 0;
3570
3571 smp->flags = SMP_F_VOL_TEST;
3572 smp->data.type = SMP_T_SINT;
3573 smp->data.u.sint = 0;
3574
3575 if (!stkctr_entry(stkctr))
3576 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
3577
3578 if (stkctr && stkctr_entry(stkctr)) {
3579 void *ptr1,*ptr2;
3580
3581
3582 /* First, update gpc0_rate if it's tracked. Second, update its
3583 * gpc0 if tracked. Returns gpc0's value otherwise the curr_ctr.
3584 */
3585 ptr1 = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC_RATE, idx);
3586 ptr2 = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC, idx);
3587 if (ptr1 || ptr2) {
3588 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3589
3590 if (ptr1) {
3591 update_freq_ctr_period(&stktable_data_cast(ptr1, std_t_frqp),
3592 stkctr->table->data_arg[STKTABLE_DT_GPC_RATE].u, 1);
3593 smp->data.u.sint = (&stktable_data_cast(ptr1, std_t_frqp))->curr_ctr;
3594 }
3595
3596 if (ptr2)
3597 smp->data.u.sint = ++stktable_data_cast(ptr2, std_t_uint);
3598
3599 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3600
3601 /* If data was modified, we need to touch to re-schedule sync */
3602 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
3603 }
3604 else if (stkctr == &tmpstkctr)
3605 stktable_release(stkctr->table, stkctr_entry(stkctr));
3606 }
3607 return 1;
3608}
3609
Willy Tarreau7d562212016-11-25 16:10:05 +01003610/* Increment the General Purpose Counter 0 value from the stream's tracked
3611 * frontend counters and return it into temp integer.
3612 * Supports being called as "sc[0-9]_inc_gpc0" or "src_inc_gpc0" only.
3613 */
3614static int
3615smp_fetch_sc_inc_gpc0(const struct arg *args, struct sample *smp, const char *kw, void *private)
3616{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003617 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003618 struct stkctr *stkctr;
Willy Tarreau5b654ad2021-07-06 18:51:12 +02003619 unsigned int period = 0;
Willy Tarreau7d562212016-11-25 16:10:05 +01003620
Emeric Brun819fc6f2017-06-13 19:37:32 +02003621 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003622 if (!stkctr)
3623 return 0;
3624
3625 smp->flags = SMP_F_VOL_TEST;
3626 smp->data.type = SMP_T_SINT;
3627 smp->data.u.sint = 0;
3628
Emeric Brun819fc6f2017-06-13 19:37:32 +02003629 if (!stkctr_entry(stkctr))
3630 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003631
3632 if (stkctr && stkctr_entry(stkctr)) {
3633 void *ptr1,*ptr2;
3634
Emeric Brun819fc6f2017-06-13 19:37:32 +02003635
Willy Tarreau7d562212016-11-25 16:10:05 +01003636 /* First, update gpc0_rate if it's tracked. Second, update its
3637 * gpc0 if tracked. Returns gpc0's value otherwise the curr_ctr.
3638 */
3639 ptr1 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0_RATE);
Emeric Brun726783d2021-06-30 19:06:43 +02003640 if (ptr1) {
3641 period = stkctr->table->data_arg[STKTABLE_DT_GPC0_RATE].u;
3642 }
3643 else {
3644 /* fallback on the gpc array */
3645 ptr1 = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC_RATE, 0);
3646 if (ptr1)
3647 period = stkctr->table->data_arg[STKTABLE_DT_GPC_RATE].u;
3648 }
3649
Willy Tarreau7d562212016-11-25 16:10:05 +01003650 ptr2 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0);
Emeric Brun726783d2021-06-30 19:06:43 +02003651 if (!ptr2) {
3652 /* fallback on the gpc array */
3653 ptr2 = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC, 0);
3654 }
3655
Emeric Brun819fc6f2017-06-13 19:37:32 +02003656 if (ptr1 || ptr2) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003657 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Willy Tarreau7d562212016-11-25 16:10:05 +01003658
Emeric Brun819fc6f2017-06-13 19:37:32 +02003659 if (ptr1) {
Emeric Brun0e3457b2021-06-30 17:18:28 +02003660 update_freq_ctr_period(&stktable_data_cast(ptr1, std_t_frqp),
Emeric Brun726783d2021-06-30 19:06:43 +02003661 period, 1);
Emeric Brun0e3457b2021-06-30 17:18:28 +02003662 smp->data.u.sint = (&stktable_data_cast(ptr1, std_t_frqp))->curr_ctr;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003663 }
3664
3665 if (ptr2)
Emeric Brun0e3457b2021-06-30 17:18:28 +02003666 smp->data.u.sint = ++stktable_data_cast(ptr2, std_t_uint);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003667
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003668 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003669
3670 /* If data was modified, we need to touch to re-schedule sync */
3671 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
3672 }
3673 else if (stkctr == &tmpstkctr)
3674 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003675 }
3676 return 1;
3677}
3678
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003679/* Increment the General Purpose Counter 1 value from the stream's tracked
3680 * frontend counters and return it into temp integer.
3681 * Supports being called as "sc[0-9]_inc_gpc1" or "src_inc_gpc1" only.
3682 */
3683static int
3684smp_fetch_sc_inc_gpc1(const struct arg *args, struct sample *smp, const char *kw, void *private)
3685{
3686 struct stkctr tmpstkctr;
3687 struct stkctr *stkctr;
Willy Tarreau5b654ad2021-07-06 18:51:12 +02003688 unsigned int period = 0;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003689
3690 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
3691 if (!stkctr)
3692 return 0;
3693
3694 smp->flags = SMP_F_VOL_TEST;
3695 smp->data.type = SMP_T_SINT;
3696 smp->data.u.sint = 0;
3697
3698 if (!stkctr_entry(stkctr))
3699 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
3700
3701 if (stkctr && stkctr_entry(stkctr)) {
3702 void *ptr1,*ptr2;
3703
3704
3705 /* First, update gpc1_rate if it's tracked. Second, update its
3706 * gpc1 if tracked. Returns gpc1's value otherwise the curr_ctr.
3707 */
3708 ptr1 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1_RATE);
Emeric Brun726783d2021-06-30 19:06:43 +02003709 if (ptr1) {
3710 period = stkctr->table->data_arg[STKTABLE_DT_GPC1_RATE].u;
3711 }
3712 else {
3713 /* fallback on the gpc array */
3714 ptr1 = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC_RATE, 1);
3715 if (ptr1)
3716 period = stkctr->table->data_arg[STKTABLE_DT_GPC_RATE].u;
3717 }
3718
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003719 ptr2 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1);
Emeric Brun726783d2021-06-30 19:06:43 +02003720 if (!ptr2) {
3721 /* fallback on the gpc array */
3722 ptr2 = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC, 1);
3723 }
3724
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003725 if (ptr1 || ptr2) {
3726 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3727
3728 if (ptr1) {
Emeric Brun0e3457b2021-06-30 17:18:28 +02003729 update_freq_ctr_period(&stktable_data_cast(ptr1, std_t_frqp),
Emeric Brun726783d2021-06-30 19:06:43 +02003730 period, 1);
Emeric Brun0e3457b2021-06-30 17:18:28 +02003731 smp->data.u.sint = (&stktable_data_cast(ptr1, std_t_frqp))->curr_ctr;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003732 }
3733
3734 if (ptr2)
Emeric Brun0e3457b2021-06-30 17:18:28 +02003735 smp->data.u.sint = ++stktable_data_cast(ptr2, std_t_uint);
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003736
3737 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3738
3739 /* If data was modified, we need to touch to re-schedule sync */
3740 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
3741 }
3742 else if (stkctr == &tmpstkctr)
3743 stktable_release(stkctr->table, stkctr_entry(stkctr));
3744 }
3745 return 1;
3746}
3747
Emeric Brun4d7ada82021-06-30 19:04:16 +02003748/* Clear the GPC[args(0)] value from the stream's tracked
3749 * frontend counters and return its previous value into temp integer.
3750 * Supports being called as "sc_clr_gpc(<gpc-idx>,<sc-idx>[,<table>])"
3751 * or "src_clr_gpc(<gpc-idx>[,<table>])" only.
3752 */
3753static int
3754smp_fetch_sc_clr_gpc(const struct arg *args, struct sample *smp, const char *kw, void *private)
3755{
3756 struct stkctr tmpstkctr;
3757 struct stkctr *stkctr;
3758 unsigned int idx;
3759
3760 idx = args[0].data.sint;
3761
3762 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args + 1, kw, &tmpstkctr);
3763 if (!stkctr)
3764 return 0;
3765
3766 smp->flags = SMP_F_VOL_TEST;
3767 smp->data.type = SMP_T_SINT;
3768 smp->data.u.sint = 0;
3769
3770 if (!stkctr_entry(stkctr))
3771 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
3772
3773 if (stkctr && stkctr_entry(stkctr)) {
3774 void *ptr;
3775
3776 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC, idx);
3777 if (!ptr) {
3778 if (stkctr == &tmpstkctr)
3779 stktable_release(stkctr->table, stkctr_entry(stkctr));
3780 return 0; /* parameter not stored */
3781 }
3782
3783 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3784
3785 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
3786 stktable_data_cast(ptr, std_t_uint) = 0;
3787
3788 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3789
3790 /* If data was modified, we need to touch to re-schedule sync */
3791 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
3792 }
3793 return 1;
3794}
3795
Willy Tarreau7d562212016-11-25 16:10:05 +01003796/* Clear the General Purpose Counter 0 value from the stream's tracked
3797 * frontend counters and return its previous value into temp integer.
3798 * Supports being called as "sc[0-9]_clr_gpc0" or "src_clr_gpc0" only.
3799 */
3800static int
3801smp_fetch_sc_clr_gpc0(const struct arg *args, struct sample *smp, const char *kw, void *private)
3802{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003803 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003804 struct stkctr *stkctr;
3805
Emeric Brun819fc6f2017-06-13 19:37:32 +02003806 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003807 if (!stkctr)
3808 return 0;
3809
3810 smp->flags = SMP_F_VOL_TEST;
3811 smp->data.type = SMP_T_SINT;
3812 smp->data.u.sint = 0;
3813
Emeric Brun819fc6f2017-06-13 19:37:32 +02003814 if (!stkctr_entry(stkctr))
3815 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003816
Emeric Brun819fc6f2017-06-13 19:37:32 +02003817 if (stkctr && stkctr_entry(stkctr)) {
3818 void *ptr;
3819
3820 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0);
3821 if (!ptr) {
Emeric Brun726783d2021-06-30 19:06:43 +02003822 /* fallback on the gpc array */
3823 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC, 0);
3824 }
3825
3826 if (!ptr) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003827 if (stkctr == &tmpstkctr)
3828 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003829 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003830 }
3831
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003832 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003833
Emeric Brun0e3457b2021-06-30 17:18:28 +02003834 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
3835 stktable_data_cast(ptr, std_t_uint) = 0;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003836
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003837 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003838
Willy Tarreau7d562212016-11-25 16:10:05 +01003839 /* If data was modified, we need to touch to re-schedule sync */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003840 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
Willy Tarreau7d562212016-11-25 16:10:05 +01003841 }
3842 return 1;
3843}
3844
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003845/* Clear the General Purpose Counter 1 value from the stream's tracked
3846 * frontend counters and return its previous value into temp integer.
3847 * Supports being called as "sc[0-9]_clr_gpc1" or "src_clr_gpc1" only.
3848 */
3849static int
3850smp_fetch_sc_clr_gpc1(const struct arg *args, struct sample *smp, const char *kw, void *private)
3851{
3852 struct stkctr tmpstkctr;
3853 struct stkctr *stkctr;
3854
3855 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
3856 if (!stkctr)
3857 return 0;
3858
3859 smp->flags = SMP_F_VOL_TEST;
3860 smp->data.type = SMP_T_SINT;
3861 smp->data.u.sint = 0;
3862
3863 if (!stkctr_entry(stkctr))
3864 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
3865
3866 if (stkctr && stkctr_entry(stkctr)) {
3867 void *ptr;
3868
3869 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1);
3870 if (!ptr) {
Emeric Brun726783d2021-06-30 19:06:43 +02003871 /* fallback on the gpc array */
3872 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC, 1);
3873 }
3874
3875 if (!ptr) {
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003876 if (stkctr == &tmpstkctr)
3877 stktable_release(stkctr->table, stkctr_entry(stkctr));
3878 return 0; /* parameter not stored */
3879 }
3880
3881 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3882
Emeric Brun0e3457b2021-06-30 17:18:28 +02003883 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
3884 stktable_data_cast(ptr, std_t_uint) = 0;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003885
3886 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3887
3888 /* If data was modified, we need to touch to re-schedule sync */
3889 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
3890 }
3891 return 1;
3892}
3893
Willy Tarreau7d562212016-11-25 16:10:05 +01003894/* set <smp> to the cumulated number of connections from the stream's tracked
3895 * frontend counters. Supports being called as "sc[0-9]_conn_cnt" or
3896 * "src_conn_cnt" only.
3897 */
3898static int
3899smp_fetch_sc_conn_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
3900{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003901 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003902 struct stkctr *stkctr;
3903
Emeric Brun819fc6f2017-06-13 19:37:32 +02003904 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003905 if (!stkctr)
3906 return 0;
3907
3908 smp->flags = SMP_F_VOL_TEST;
3909 smp->data.type = SMP_T_SINT;
3910 smp->data.u.sint = 0;
3911 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003912 void *ptr;
3913
3914 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_CONN_CNT);
3915 if (!ptr) {
3916 if (stkctr == &tmpstkctr)
3917 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003918 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003919 }
3920
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003921 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003922
Emeric Brun0e3457b2021-06-30 17:18:28 +02003923 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003924
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003925 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003926
3927 if (stkctr == &tmpstkctr)
3928 stktable_release(stkctr->table, stkctr_entry(stkctr));
3929
3930
Willy Tarreau7d562212016-11-25 16:10:05 +01003931 }
3932 return 1;
3933}
3934
3935/* set <smp> to the connection rate from the stream's tracked frontend
3936 * counters. Supports being called as "sc[0-9]_conn_rate" or "src_conn_rate"
3937 * only.
3938 */
3939static int
3940smp_fetch_sc_conn_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3941{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003942 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003943 struct stkctr *stkctr;
3944
Emeric Brun819fc6f2017-06-13 19:37:32 +02003945 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003946 if (!stkctr)
3947 return 0;
3948
3949 smp->flags = SMP_F_VOL_TEST;
3950 smp->data.type = SMP_T_SINT;
3951 smp->data.u.sint = 0;
3952 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003953 void *ptr;
3954
3955 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_CONN_RATE);
3956 if (!ptr) {
3957 if (stkctr == &tmpstkctr)
3958 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003959 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003960 }
3961
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003962 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003963
Emeric Brun0e3457b2021-06-30 17:18:28 +02003964 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Willy Tarreau7d562212016-11-25 16:10:05 +01003965 stkctr->table->data_arg[STKTABLE_DT_CONN_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003966
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003967 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003968
3969 if (stkctr == &tmpstkctr)
3970 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003971 }
3972 return 1;
3973}
3974
3975/* set temp integer to the number of connections from the stream's source address
3976 * in the table pointed to by expr, after updating it.
3977 * Accepts exactly 1 argument of type table.
3978 */
3979static int
3980smp_fetch_src_updt_conn_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
3981{
3982 struct connection *conn = objt_conn(smp->sess->origin);
3983 struct stksess *ts;
3984 struct stktable_key *key;
3985 void *ptr;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003986 struct stktable *t;
Willy Tarreau7d562212016-11-25 16:10:05 +01003987
3988 if (!conn)
3989 return 0;
3990
Joseph Herlant5662fa42018-11-15 13:43:28 -08003991 /* Fetch source address in a sample. */
Amaury Denoyellec460c702021-05-12 10:17:47 +02003992 if (!smp_fetch_src || !smp_fetch_src(empty_arg_list, smp, "src", NULL))
Willy Tarreau7d562212016-11-25 16:10:05 +01003993 return 0;
3994
3995 /* Converts into key. */
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003996 key = smp_to_stkey(smp, args->data.t);
Willy Tarreau7d562212016-11-25 16:10:05 +01003997 if (!key)
3998 return 0;
3999
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004000 t = args->data.t;
Willy Tarreau7d562212016-11-25 16:10:05 +01004001
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004002 if ((ts = stktable_get_entry(t, key)) == NULL)
Willy Tarreau7d562212016-11-25 16:10:05 +01004003 /* entry does not exist and could not be created */
4004 return 0;
4005
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004006 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_CONN_CNT);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004007 if (!ptr) {
Willy Tarreau7d562212016-11-25 16:10:05 +01004008 return 0; /* parameter not stored in this table */
Emeric Brun819fc6f2017-06-13 19:37:32 +02004009 }
Willy Tarreau7d562212016-11-25 16:10:05 +01004010
4011 smp->data.type = SMP_T_SINT;
Emeric Brun819fc6f2017-06-13 19:37:32 +02004012
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004013 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004014
Emeric Brun0e3457b2021-06-30 17:18:28 +02004015 smp->data.u.sint = ++stktable_data_cast(ptr, std_t_uint);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004016
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004017 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004018
Willy Tarreau7d562212016-11-25 16:10:05 +01004019 smp->flags = SMP_F_VOL_TEST;
Emeric Brun819fc6f2017-06-13 19:37:32 +02004020
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004021 stktable_touch_local(t, ts, 1);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004022
4023 /* Touch was previously performed by stktable_update_key */
Willy Tarreau7d562212016-11-25 16:10:05 +01004024 return 1;
4025}
4026
4027/* set <smp> to the number of concurrent connections from the stream's tracked
4028 * frontend counters. Supports being called as "sc[0-9]_conn_cur" or
4029 * "src_conn_cur" only.
4030 */
4031static int
4032smp_fetch_sc_conn_cur(const struct arg *args, struct sample *smp, const char *kw, void *private)
4033{
Emeric Brun819fc6f2017-06-13 19:37:32 +02004034 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01004035 struct stkctr *stkctr;
4036
Emeric Brun819fc6f2017-06-13 19:37:32 +02004037 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01004038 if (!stkctr)
4039 return 0;
4040
4041 smp->flags = SMP_F_VOL_TEST;
4042 smp->data.type = SMP_T_SINT;
4043 smp->data.u.sint = 0;
4044 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02004045 void *ptr;
4046
4047 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_CONN_CUR);
4048 if (!ptr) {
4049 if (stkctr == &tmpstkctr)
4050 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004051 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02004052 }
4053
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004054 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004055
Emeric Brun0e3457b2021-06-30 17:18:28 +02004056 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004057
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004058 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004059
4060 if (stkctr == &tmpstkctr)
4061 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004062 }
4063 return 1;
4064}
4065
4066/* set <smp> to the cumulated number of streams from the stream's tracked
4067 * frontend counters. Supports being called as "sc[0-9]_sess_cnt" or
4068 * "src_sess_cnt" only.
4069 */
4070static int
4071smp_fetch_sc_sess_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
4072{
Emeric Brun819fc6f2017-06-13 19:37:32 +02004073 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01004074 struct stkctr *stkctr;
4075
Emeric Brun819fc6f2017-06-13 19:37:32 +02004076 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01004077 if (!stkctr)
4078 return 0;
4079
4080 smp->flags = SMP_F_VOL_TEST;
4081 smp->data.type = SMP_T_SINT;
4082 smp->data.u.sint = 0;
4083 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02004084 void *ptr;
4085
4086 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_SESS_CNT);
4087 if (!ptr) {
4088 if (stkctr == &tmpstkctr)
4089 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004090 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02004091 }
4092
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004093 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004094
Emeric Brun0e3457b2021-06-30 17:18:28 +02004095 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004096
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004097 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004098
4099 if (stkctr == &tmpstkctr)
4100 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004101 }
4102 return 1;
4103}
4104
4105/* set <smp> to the stream rate from the stream's tracked frontend counters.
4106 * Supports being called as "sc[0-9]_sess_rate" or "src_sess_rate" only.
4107 */
4108static int
4109smp_fetch_sc_sess_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
4110{
Emeric Brun819fc6f2017-06-13 19:37:32 +02004111 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01004112 struct stkctr *stkctr;
4113
Emeric Brun819fc6f2017-06-13 19:37:32 +02004114 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01004115 if (!stkctr)
4116 return 0;
4117
4118 smp->flags = SMP_F_VOL_TEST;
4119 smp->data.type = SMP_T_SINT;
4120 smp->data.u.sint = 0;
4121 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02004122 void *ptr;
4123
4124 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_SESS_RATE);
4125 if (!ptr) {
4126 if (stkctr == &tmpstkctr)
4127 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004128 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02004129 }
4130
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004131 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004132
Emeric Brun0e3457b2021-06-30 17:18:28 +02004133 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Willy Tarreau7d562212016-11-25 16:10:05 +01004134 stkctr->table->data_arg[STKTABLE_DT_SESS_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004135
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004136 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004137
4138 if (stkctr == &tmpstkctr)
4139 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004140 }
4141 return 1;
4142}
4143
4144/* set <smp> to the cumulated number of HTTP requests from the stream's tracked
4145 * frontend counters. Supports being called as "sc[0-9]_http_req_cnt" or
4146 * "src_http_req_cnt" only.
4147 */
4148static int
4149smp_fetch_sc_http_req_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
4150{
Emeric Brun819fc6f2017-06-13 19:37:32 +02004151 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01004152 struct stkctr *stkctr;
4153
Emeric Brun819fc6f2017-06-13 19:37:32 +02004154 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01004155 if (!stkctr)
4156 return 0;
4157
4158 smp->flags = SMP_F_VOL_TEST;
4159 smp->data.type = SMP_T_SINT;
4160 smp->data.u.sint = 0;
4161 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02004162 void *ptr;
4163
4164 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_REQ_CNT);
4165 if (!ptr) {
4166 if (stkctr == &tmpstkctr)
4167 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004168 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02004169 }
4170
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004171 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004172
Emeric Brun0e3457b2021-06-30 17:18:28 +02004173 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004174
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004175 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004176
4177 if (stkctr == &tmpstkctr)
4178 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004179 }
4180 return 1;
4181}
4182
4183/* set <smp> to the HTTP request rate from the stream's tracked frontend
4184 * counters. Supports being called as "sc[0-9]_http_req_rate" or
4185 * "src_http_req_rate" only.
4186 */
4187static int
4188smp_fetch_sc_http_req_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
4189{
Emeric Brun819fc6f2017-06-13 19:37:32 +02004190 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01004191 struct stkctr *stkctr;
4192
Emeric Brun819fc6f2017-06-13 19:37:32 +02004193 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01004194 if (!stkctr)
4195 return 0;
4196
4197 smp->flags = SMP_F_VOL_TEST;
4198 smp->data.type = SMP_T_SINT;
4199 smp->data.u.sint = 0;
4200 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02004201 void *ptr;
4202
4203 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_REQ_RATE);
4204 if (!ptr) {
4205 if (stkctr == &tmpstkctr)
4206 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004207 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02004208 }
4209
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004210 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004211
Emeric Brun0e3457b2021-06-30 17:18:28 +02004212 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Willy Tarreau7d562212016-11-25 16:10:05 +01004213 stkctr->table->data_arg[STKTABLE_DT_HTTP_REQ_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004214
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004215 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004216
4217 if (stkctr == &tmpstkctr)
4218 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004219 }
4220 return 1;
4221}
4222
4223/* set <smp> to the cumulated number of HTTP requests errors from the stream's
4224 * tracked frontend counters. Supports being called as "sc[0-9]_http_err_cnt" or
4225 * "src_http_err_cnt" only.
4226 */
4227static int
4228smp_fetch_sc_http_err_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
4229{
Emeric Brun819fc6f2017-06-13 19:37:32 +02004230 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01004231 struct stkctr *stkctr;
4232
Emeric Brun819fc6f2017-06-13 19:37:32 +02004233 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01004234 if (!stkctr)
4235 return 0;
4236
4237 smp->flags = SMP_F_VOL_TEST;
4238 smp->data.type = SMP_T_SINT;
4239 smp->data.u.sint = 0;
4240 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02004241 void *ptr;
4242
4243 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_ERR_CNT);
4244 if (!ptr) {
4245 if (stkctr == &tmpstkctr)
4246 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004247 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02004248 }
4249
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004250 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004251
Emeric Brun0e3457b2021-06-30 17:18:28 +02004252 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004253
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004254 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004255
4256 if (stkctr == &tmpstkctr)
4257 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004258 }
4259 return 1;
4260}
4261
4262/* set <smp> to the HTTP request error rate from the stream's tracked frontend
4263 * counters. Supports being called as "sc[0-9]_http_err_rate" or
4264 * "src_http_err_rate" only.
4265 */
4266static int
4267smp_fetch_sc_http_err_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
4268{
Emeric Brun819fc6f2017-06-13 19:37:32 +02004269 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01004270 struct stkctr *stkctr;
4271
Emeric Brun819fc6f2017-06-13 19:37:32 +02004272 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01004273 if (!stkctr)
4274 return 0;
4275
4276 smp->flags = SMP_F_VOL_TEST;
4277 smp->data.type = SMP_T_SINT;
4278 smp->data.u.sint = 0;
4279 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02004280 void *ptr;
4281
4282 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_ERR_RATE);
4283 if (!ptr) {
4284 if (stkctr == &tmpstkctr)
4285 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004286 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02004287 }
4288
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004289 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004290
Emeric Brun0e3457b2021-06-30 17:18:28 +02004291 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Willy Tarreau7d562212016-11-25 16:10:05 +01004292 stkctr->table->data_arg[STKTABLE_DT_HTTP_ERR_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004293
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004294 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004295
4296 if (stkctr == &tmpstkctr)
4297 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004298 }
4299 return 1;
4300}
4301
Willy Tarreau826f3ab2021-02-10 12:07:15 +01004302/* set <smp> to the cumulated number of HTTP response failures from the stream's
4303 * tracked frontend counters. Supports being called as "sc[0-9]_http_fail_cnt" or
4304 * "src_http_fail_cnt" only.
4305 */
4306static int
4307smp_fetch_sc_http_fail_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
4308{
4309 struct stkctr tmpstkctr;
4310 struct stkctr *stkctr;
4311
4312 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
4313 if (!stkctr)
4314 return 0;
4315
4316 smp->flags = SMP_F_VOL_TEST;
4317 smp->data.type = SMP_T_SINT;
4318 smp->data.u.sint = 0;
4319 if (stkctr_entry(stkctr) != NULL) {
4320 void *ptr;
4321
4322 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_FAIL_CNT);
4323 if (!ptr) {
4324 if (stkctr == &tmpstkctr)
4325 stktable_release(stkctr->table, stkctr_entry(stkctr));
4326 return 0; /* parameter not stored */
4327 }
4328
4329 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
4330
Emeric Brun0e3457b2021-06-30 17:18:28 +02004331 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Willy Tarreau826f3ab2021-02-10 12:07:15 +01004332
4333 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
4334
4335 if (stkctr == &tmpstkctr)
4336 stktable_release(stkctr->table, stkctr_entry(stkctr));
4337 }
4338 return 1;
4339}
4340
4341/* set <smp> to the HTTP response failure rate from the stream's tracked frontend
4342 * counters. Supports being called as "sc[0-9]_http_fail_rate" or
4343 * "src_http_fail_rate" only.
4344 */
4345static int
4346smp_fetch_sc_http_fail_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
4347{
4348 struct stkctr tmpstkctr;
4349 struct stkctr *stkctr;
4350
4351 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
4352 if (!stkctr)
4353 return 0;
4354
4355 smp->flags = SMP_F_VOL_TEST;
4356 smp->data.type = SMP_T_SINT;
4357 smp->data.u.sint = 0;
4358 if (stkctr_entry(stkctr) != NULL) {
4359 void *ptr;
4360
4361 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_FAIL_RATE);
4362 if (!ptr) {
4363 if (stkctr == &tmpstkctr)
4364 stktable_release(stkctr->table, stkctr_entry(stkctr));
4365 return 0; /* parameter not stored */
4366 }
4367
4368 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
4369
Emeric Brun0e3457b2021-06-30 17:18:28 +02004370 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Willy Tarreau826f3ab2021-02-10 12:07:15 +01004371 stkctr->table->data_arg[STKTABLE_DT_HTTP_FAIL_RATE].u);
4372
4373 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
4374
4375 if (stkctr == &tmpstkctr)
4376 stktable_release(stkctr->table, stkctr_entry(stkctr));
4377 }
4378 return 1;
4379}
4380
Willy Tarreau7d562212016-11-25 16:10:05 +01004381/* set <smp> to the number of kbytes received from clients, as found in the
4382 * stream's tracked frontend counters. Supports being called as
4383 * "sc[0-9]_kbytes_in" or "src_kbytes_in" only.
4384 */
4385static int
4386smp_fetch_sc_kbytes_in(const struct arg *args, struct sample *smp, const char *kw, void *private)
4387{
Emeric Brun819fc6f2017-06-13 19:37:32 +02004388 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01004389 struct stkctr *stkctr;
4390
Emeric Brun819fc6f2017-06-13 19:37:32 +02004391 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01004392 if (!stkctr)
4393 return 0;
4394
4395 smp->flags = SMP_F_VOL_TEST;
4396 smp->data.type = SMP_T_SINT;
4397 smp->data.u.sint = 0;
4398 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02004399 void *ptr;
4400
4401 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_IN_CNT);
4402 if (!ptr) {
4403 if (stkctr == &tmpstkctr)
4404 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004405 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02004406 }
4407
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004408 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004409
Emeric Brun0e3457b2021-06-30 17:18:28 +02004410 smp->data.u.sint = stktable_data_cast(ptr, std_t_ull) >> 10;
Emeric Brun819fc6f2017-06-13 19:37:32 +02004411
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004412 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004413
4414 if (stkctr == &tmpstkctr)
4415 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004416 }
4417 return 1;
4418}
4419
4420/* set <smp> to the data rate received from clients in bytes/s, as found
4421 * in the stream's tracked frontend counters. Supports being called as
4422 * "sc[0-9]_bytes_in_rate" or "src_bytes_in_rate" only.
4423 */
4424static int
4425smp_fetch_sc_bytes_in_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
4426{
Emeric Brun819fc6f2017-06-13 19:37:32 +02004427 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01004428 struct stkctr *stkctr;
4429
Emeric Brun819fc6f2017-06-13 19:37:32 +02004430 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01004431 if (!stkctr)
4432 return 0;
4433
4434 smp->flags = SMP_F_VOL_TEST;
4435 smp->data.type = SMP_T_SINT;
4436 smp->data.u.sint = 0;
4437 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02004438 void *ptr;
4439
4440 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_IN_RATE);
4441 if (!ptr) {
4442 if (stkctr == &tmpstkctr)
4443 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004444 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02004445 }
4446
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004447 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004448
Emeric Brun0e3457b2021-06-30 17:18:28 +02004449 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Willy Tarreau7d562212016-11-25 16:10:05 +01004450 stkctr->table->data_arg[STKTABLE_DT_BYTES_IN_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004451
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004452 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004453
4454 if (stkctr == &tmpstkctr)
4455 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004456 }
4457 return 1;
4458}
4459
4460/* set <smp> to the number of kbytes sent to clients, as found in the
4461 * stream's tracked frontend counters. Supports being called as
4462 * "sc[0-9]_kbytes_out" or "src_kbytes_out" only.
4463 */
4464static int
4465smp_fetch_sc_kbytes_out(const struct arg *args, struct sample *smp, const char *kw, void *private)
4466{
Emeric Brun819fc6f2017-06-13 19:37:32 +02004467 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01004468 struct stkctr *stkctr;
4469
Emeric Brun819fc6f2017-06-13 19:37:32 +02004470 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01004471 if (!stkctr)
4472 return 0;
4473
4474 smp->flags = SMP_F_VOL_TEST;
4475 smp->data.type = SMP_T_SINT;
4476 smp->data.u.sint = 0;
4477 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02004478 void *ptr;
4479
4480 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_OUT_CNT);
4481 if (!ptr) {
4482 if (stkctr == &tmpstkctr)
4483 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004484 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02004485 }
4486
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004487 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004488
Emeric Brun0e3457b2021-06-30 17:18:28 +02004489 smp->data.u.sint = stktable_data_cast(ptr, std_t_ull) >> 10;
Emeric Brun819fc6f2017-06-13 19:37:32 +02004490
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004491 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004492
4493 if (stkctr == &tmpstkctr)
4494 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004495 }
4496 return 1;
4497}
4498
4499/* set <smp> to the data rate sent to clients in bytes/s, as found in the
4500 * stream's tracked frontend counters. Supports being called as
4501 * "sc[0-9]_bytes_out_rate" or "src_bytes_out_rate" only.
4502 */
4503static int
4504smp_fetch_sc_bytes_out_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
4505{
Emeric Brun819fc6f2017-06-13 19:37:32 +02004506 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01004507 struct stkctr *stkctr;
4508
Emeric Brun819fc6f2017-06-13 19:37:32 +02004509 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01004510 if (!stkctr)
4511 return 0;
4512
4513 smp->flags = SMP_F_VOL_TEST;
4514 smp->data.type = SMP_T_SINT;
4515 smp->data.u.sint = 0;
4516 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02004517 void *ptr;
4518
4519 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_OUT_RATE);
4520 if (!ptr) {
4521 if (stkctr == &tmpstkctr)
4522 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004523 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02004524 }
4525
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004526 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004527
Emeric Brun0e3457b2021-06-30 17:18:28 +02004528 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Willy Tarreau7d562212016-11-25 16:10:05 +01004529 stkctr->table->data_arg[STKTABLE_DT_BYTES_OUT_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004530
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004531 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004532
4533 if (stkctr == &tmpstkctr)
4534 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004535 }
4536 return 1;
4537}
4538
4539/* set <smp> to the number of active trackers on the SC entry in the stream's
4540 * tracked frontend counters. Supports being called as "sc[0-9]_trackers" only.
4541 */
4542static int
4543smp_fetch_sc_trackers(const struct arg *args, struct sample *smp, const char *kw, void *private)
4544{
Emeric Brun819fc6f2017-06-13 19:37:32 +02004545 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01004546 struct stkctr *stkctr;
4547
Emeric Brun819fc6f2017-06-13 19:37:32 +02004548 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01004549 if (!stkctr)
4550 return 0;
4551
4552 smp->flags = SMP_F_VOL_TEST;
4553 smp->data.type = SMP_T_SINT;
Emeric Brun819fc6f2017-06-13 19:37:32 +02004554 if (stkctr == &tmpstkctr) {
4555 smp->data.u.sint = stkctr_entry(stkctr) ? (stkctr_entry(stkctr)->ref_cnt-1) : 0;
4556 stktable_release(stkctr->table, stkctr_entry(stkctr));
4557 }
4558 else {
4559 smp->data.u.sint = stkctr_entry(stkctr) ? stkctr_entry(stkctr)->ref_cnt : 0;
4560 }
4561
Willy Tarreau7d562212016-11-25 16:10:05 +01004562 return 1;
4563}
4564
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004565
4566/* The functions below are used to manipulate table contents from the CLI.
4567 * There are 3 main actions, "clear", "set" and "show". The code is shared
4568 * between all actions, and the action is encoded in the void *private in
4569 * the appctx as well as in the keyword registration, among one of the
4570 * following values.
4571 */
4572
4573enum {
4574 STK_CLI_ACT_CLR,
4575 STK_CLI_ACT_SET,
4576 STK_CLI_ACT_SHOW,
4577};
4578
Willy Tarreau4596fe22022-05-17 19:07:51 +02004579/* Dump the status of a table to a stream connector's
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004580 * read buffer. It returns 0 if the output buffer is full
4581 * and needs to be called again, otherwise non-zero.
4582 */
Willy Tarreau83061a82018-07-13 11:56:34 +02004583static int table_dump_head_to_buffer(struct buffer *msg,
Willy Tarreaud0a06d52022-05-18 15:07:19 +02004584 struct appctx *appctx,
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004585 struct stktable *t, struct stktable *target)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004586{
Willy Tarreauc12b3212022-05-27 11:08:15 +02004587 struct stream *s = __sc_strm(appctx_sc(appctx));
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004588
4589 chunk_appendf(msg, "# table: %s, type: %s, size:%d, used:%d\n",
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004590 t->id, stktable_types[t->type].kw, t->size, t->current);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004591
4592 /* any other information should be dumped here */
4593
William Lallemand07a62f72017-05-24 00:57:40 +02004594 if (target && (strm_li(s)->bind_conf->level & ACCESS_LVL_MASK) < ACCESS_LVL_OPER)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004595 chunk_appendf(msg, "# contents not dumped due to insufficient privileges\n");
4596
Willy Tarreaud0a06d52022-05-18 15:07:19 +02004597 if (applet_putchk(appctx, msg) == -1)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004598 return 0;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004599
4600 return 1;
4601}
4602
Willy Tarreau4596fe22022-05-17 19:07:51 +02004603/* Dump a table entry to a stream connector's
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004604 * read buffer. It returns 0 if the output buffer is full
4605 * and needs to be called again, otherwise non-zero.
4606 */
Willy Tarreau83061a82018-07-13 11:56:34 +02004607static int table_dump_entry_to_buffer(struct buffer *msg,
Willy Tarreaud0a06d52022-05-18 15:07:19 +02004608 struct appctx *appctx,
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004609 struct stktable *t, struct stksess *entry)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004610{
4611 int dt;
4612
4613 chunk_appendf(msg, "%p:", entry);
4614
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004615 if (t->type == SMP_T_IPV4) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004616 char addr[INET_ADDRSTRLEN];
4617 inet_ntop(AF_INET, (const void *)&entry->key.key, addr, sizeof(addr));
4618 chunk_appendf(msg, " key=%s", addr);
4619 }
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004620 else if (t->type == SMP_T_IPV6) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004621 char addr[INET6_ADDRSTRLEN];
4622 inet_ntop(AF_INET6, (const void *)&entry->key.key, addr, sizeof(addr));
4623 chunk_appendf(msg, " key=%s", addr);
4624 }
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004625 else if (t->type == SMP_T_SINT) {
Willy Tarreau6cde5d82020-02-25 09:41:22 +01004626 chunk_appendf(msg, " key=%u", read_u32(entry->key.key));
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004627 }
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004628 else if (t->type == SMP_T_STR) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004629 chunk_appendf(msg, " key=");
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004630 dump_text(msg, (const char *)entry->key.key, t->key_size);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004631 }
4632 else {
4633 chunk_appendf(msg, " key=");
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004634 dump_binary(msg, (const char *)entry->key.key, t->key_size);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004635 }
4636
Willy Tarreau16b282f2022-11-29 11:55:18 +01004637 chunk_appendf(msg, " use=%d exp=%d shard=%d", entry->ref_cnt - 1, tick_remain(now_ms, entry->expire), entry->shard);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004638
4639 for (dt = 0; dt < STKTABLE_DATA_TYPES; dt++) {
4640 void *ptr;
4641
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004642 if (t->data_ofs[dt] == 0)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004643 continue;
Emeric Brunc64a2a32021-06-30 18:01:02 +02004644 if (stktable_data_types[dt].is_array) {
4645 char tmp[16] = {};
4646 const char *name_pfx = stktable_data_types[dt].name;
4647 const char *name_sfx = NULL;
4648 unsigned int idx = 0;
4649 int i = 0;
4650
4651 /* split name to show index before first _ of the name
4652 * for example: 'gpc3_rate' if array name is 'gpc_rate'.
4653 */
4654 for (i = 0 ; i < (sizeof(tmp) - 1); i++) {
4655 if (!name_pfx[i])
4656 break;
4657 if (name_pfx[i] == '_') {
4658 name_pfx = &tmp[0];
4659 name_sfx = &stktable_data_types[dt].name[i];
4660 break;
4661 }
4662 tmp[i] = name_pfx[i];
4663 }
4664
4665 ptr = stktable_data_ptr_idx(t, entry, dt, idx);
4666 while (ptr) {
4667 if (stktable_data_types[dt].arg_type == ARG_T_DELAY)
4668 chunk_appendf(msg, " %s%u%s(%u)=", name_pfx, idx, name_sfx ? name_sfx : "", t->data_arg[dt].u);
4669 else
4670 chunk_appendf(msg, " %s%u%s=", name_pfx, idx, name_sfx ? name_sfx : "");
4671 switch (stktable_data_types[dt].std_type) {
4672 case STD_T_SINT:
4673 chunk_appendf(msg, "%d", stktable_data_cast(ptr, std_t_sint));
4674 break;
4675 case STD_T_UINT:
4676 chunk_appendf(msg, "%u", stktable_data_cast(ptr, std_t_uint));
4677 break;
4678 case STD_T_ULL:
4679 chunk_appendf(msg, "%llu", stktable_data_cast(ptr, std_t_ull));
4680 break;
4681 case STD_T_FRQP:
4682 chunk_appendf(msg, "%u",
4683 read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
4684 t->data_arg[dt].u));
4685 break;
4686 }
4687 ptr = stktable_data_ptr_idx(t, entry, dt, ++idx);
4688 }
4689 continue;
4690 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004691 if (stktable_data_types[dt].arg_type == ARG_T_DELAY)
Emeric Brun01928ae2021-06-30 16:24:04 +02004692 chunk_appendf(msg, " %s(%u)=", stktable_data_types[dt].name, t->data_arg[dt].u);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004693 else
4694 chunk_appendf(msg, " %s=", stktable_data_types[dt].name);
4695
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004696 ptr = stktable_data_ptr(t, entry, dt);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004697 switch (stktable_data_types[dt].std_type) {
4698 case STD_T_SINT:
4699 chunk_appendf(msg, "%d", stktable_data_cast(ptr, std_t_sint));
4700 break;
4701 case STD_T_UINT:
4702 chunk_appendf(msg, "%u", stktable_data_cast(ptr, std_t_uint));
4703 break;
4704 case STD_T_ULL:
Emeric Brun01928ae2021-06-30 16:24:04 +02004705 chunk_appendf(msg, "%llu", stktable_data_cast(ptr, std_t_ull));
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004706 break;
4707 case STD_T_FRQP:
Emeric Brun01928ae2021-06-30 16:24:04 +02004708 chunk_appendf(msg, "%u",
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004709 read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004710 t->data_arg[dt].u));
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004711 break;
Frédéric Lécaille16b4f542019-05-23 12:15:04 +02004712 case STD_T_DICT: {
4713 struct dict_entry *de;
4714 de = stktable_data_cast(ptr, std_t_dict);
4715 chunk_appendf(msg, "%s", de ? (char *)de->value.key : "-");
4716 break;
4717 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004718 }
4719 }
4720 chunk_appendf(msg, "\n");
4721
Willy Tarreaud0a06d52022-05-18 15:07:19 +02004722 if (applet_putchk(appctx, msg) == -1)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004723 return 0;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004724
4725 return 1;
4726}
4727
Willy Tarreau3c69e082022-05-03 11:35:07 +02004728/* appctx context used by the "show table" command */
4729struct show_table_ctx {
4730 void *target; /* table we want to dump, or NULL for all */
4731 struct stktable *t; /* table being currently dumped (first if NULL) */
4732 struct stksess *entry; /* last entry we were trying to dump (or first if NULL) */
4733 long long value[STKTABLE_FILTER_LEN]; /* value to compare against */
4734 signed char data_type[STKTABLE_FILTER_LEN]; /* type of data to compare, or -1 if none */
4735 signed char data_op[STKTABLE_FILTER_LEN]; /* operator (STD_OP_*) when data_type set */
Willy Tarreau7849d4c2022-05-03 11:45:02 +02004736 enum {
Willy Tarreau0f154ed2022-05-03 12:02:36 +02004737 STATE_NEXT = 0, /* px points to next table, entry=NULL */
Willy Tarreau7849d4c2022-05-03 11:45:02 +02004738 STATE_DUMP, /* px points to curr table, entry is valid, refcount held */
4739 STATE_DONE, /* done dumping */
4740 } state;
Willy Tarreau3c69e082022-05-03 11:35:07 +02004741 char action; /* action on the table : one of STK_CLI_ACT_* */
4742};
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004743
4744/* Processes a single table entry matching a specific key passed in argument.
4745 * returns 0 if wants to be called again, 1 if has ended processing.
4746 */
4747static int table_process_entry_per_key(struct appctx *appctx, char **args)
4748{
Willy Tarreau3c69e082022-05-03 11:35:07 +02004749 struct show_table_ctx *ctx = appctx->svcctx;
4750 struct stktable *t = ctx->target;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004751 struct stksess *ts;
4752 uint32_t uint32_key;
4753 unsigned char ip6_key[sizeof(struct in6_addr)];
4754 long long value;
4755 int data_type;
4756 int cur_arg;
4757 void *ptr;
Willy Tarreaufa1258f2021-04-10 23:00:53 +02004758 struct freq_ctr *frqp;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004759
Willy Tarreau9d008692019-08-09 11:21:01 +02004760 if (!*args[4])
4761 return cli_err(appctx, "Key value expected\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004762
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004763 switch (t->type) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004764 case SMP_T_IPV4:
4765 uint32_key = htonl(inetaddr_host(args[4]));
Christopher Fauletca20d022017-08-29 15:30:31 +02004766 static_table_key.key = &uint32_key;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004767 break;
4768 case SMP_T_IPV6:
Christopher Fauletb7c962b2021-11-15 09:17:25 +01004769 if (inet_pton(AF_INET6, args[4], ip6_key) <= 0)
4770 return cli_err(appctx, "Invalid key\n");
Christopher Fauletca20d022017-08-29 15:30:31 +02004771 static_table_key.key = &ip6_key;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004772 break;
4773 case SMP_T_SINT:
4774 {
4775 char *endptr;
4776 unsigned long val;
4777 errno = 0;
4778 val = strtoul(args[4], &endptr, 10);
4779 if ((errno == ERANGE && val == ULONG_MAX) ||
4780 (errno != 0 && val == 0) || endptr == args[4] ||
Willy Tarreau9d008692019-08-09 11:21:01 +02004781 val > 0xffffffff)
4782 return cli_err(appctx, "Invalid key\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004783 uint32_key = (uint32_t) val;
Christopher Fauletca20d022017-08-29 15:30:31 +02004784 static_table_key.key = &uint32_key;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004785 break;
4786 }
4787 break;
4788 case SMP_T_STR:
Christopher Fauletca20d022017-08-29 15:30:31 +02004789 static_table_key.key = args[4];
4790 static_table_key.key_len = strlen(args[4]);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004791 break;
4792 default:
Willy Tarreau3c69e082022-05-03 11:35:07 +02004793 switch (ctx->action) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004794 case STK_CLI_ACT_SHOW:
Willy Tarreau9d008692019-08-09 11:21:01 +02004795 return cli_err(appctx, "Showing keys from tables of type other than ip, ipv6, string and integer is not supported\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004796 case STK_CLI_ACT_CLR:
Willy Tarreau9d008692019-08-09 11:21:01 +02004797 return cli_err(appctx, "Removing keys from tables of type other than ip, ipv6, string and integer is not supported\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004798 case STK_CLI_ACT_SET:
Willy Tarreau9d008692019-08-09 11:21:01 +02004799 return cli_err(appctx, "Inserting keys into tables of type other than ip, ipv6, string and integer is not supported\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004800 default:
Willy Tarreau9d008692019-08-09 11:21:01 +02004801 return cli_err(appctx, "Unknown action\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004802 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004803 }
4804
4805 /* check permissions */
4806 if (!cli_has_level(appctx, ACCESS_LVL_OPER))
4807 return 1;
4808
Willy Tarreau3c69e082022-05-03 11:35:07 +02004809 switch (ctx->action) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004810 case STK_CLI_ACT_SHOW:
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004811 ts = stktable_lookup_key(t, &static_table_key);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004812 if (!ts)
4813 return 1;
4814 chunk_reset(&trash);
Willy Tarreaud0a06d52022-05-18 15:07:19 +02004815 if (!table_dump_head_to_buffer(&trash, appctx, t, t)) {
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004816 stktable_release(t, ts);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004817 return 0;
Emeric Brun819fc6f2017-06-13 19:37:32 +02004818 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004819 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &ts->lock);
Willy Tarreaud0a06d52022-05-18 15:07:19 +02004820 if (!table_dump_entry_to_buffer(&trash, appctx, t, ts)) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004821 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004822 stktable_release(t, ts);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004823 return 0;
Emeric Brun819fc6f2017-06-13 19:37:32 +02004824 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004825 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004826 stktable_release(t, ts);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004827 break;
4828
4829 case STK_CLI_ACT_CLR:
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004830 ts = stktable_lookup_key(t, &static_table_key);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004831 if (!ts)
4832 return 1;
Emeric Brun819fc6f2017-06-13 19:37:32 +02004833
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004834 if (!stksess_kill(t, ts, 1)) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004835 /* don't delete an entry which is currently referenced */
Willy Tarreau9d008692019-08-09 11:21:01 +02004836 return cli_err(appctx, "Entry currently in use, cannot remove\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004837 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004838 break;
4839
4840 case STK_CLI_ACT_SET:
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004841 ts = stktable_get_entry(t, &static_table_key);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004842 if (!ts) {
4843 /* don't delete an entry which is currently referenced */
Willy Tarreau9d008692019-08-09 11:21:01 +02004844 return cli_err(appctx, "Unable to allocate a new entry\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004845 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004846 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004847 for (cur_arg = 5; *args[cur_arg]; cur_arg += 2) {
4848 if (strncmp(args[cur_arg], "data.", 5) != 0) {
Willy Tarreau9d008692019-08-09 11:21:01 +02004849 cli_err(appctx, "\"data.<type>\" followed by a value expected\n");
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004850 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004851 stktable_touch_local(t, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004852 return 1;
4853 }
4854
4855 data_type = stktable_get_data_type(args[cur_arg] + 5);
4856 if (data_type < 0) {
Willy Tarreau9d008692019-08-09 11:21:01 +02004857 cli_err(appctx, "Unknown data type\n");
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004858 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004859 stktable_touch_local(t, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004860 return 1;
4861 }
4862
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004863 if (!t->data_ofs[data_type]) {
Willy Tarreau9d008692019-08-09 11:21:01 +02004864 cli_err(appctx, "Data type not stored in this table\n");
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004865 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004866 stktable_touch_local(t, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004867 return 1;
4868 }
4869
4870 if (!*args[cur_arg+1] || strl2llrc(args[cur_arg+1], strlen(args[cur_arg+1]), &value) != 0) {
Willy Tarreau9d008692019-08-09 11:21:01 +02004871 cli_err(appctx, "Require a valid integer value to store\n");
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004872 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004873 stktable_touch_local(t, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004874 return 1;
4875 }
4876
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004877 ptr = stktable_data_ptr(t, ts, data_type);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004878
4879 switch (stktable_data_types[data_type].std_type) {
4880 case STD_T_SINT:
4881 stktable_data_cast(ptr, std_t_sint) = value;
4882 break;
4883 case STD_T_UINT:
4884 stktable_data_cast(ptr, std_t_uint) = value;
4885 break;
4886 case STD_T_ULL:
4887 stktable_data_cast(ptr, std_t_ull) = value;
4888 break;
4889 case STD_T_FRQP:
4890 /* We set both the current and previous values. That way
4891 * the reported frequency is stable during all the period
4892 * then slowly fades out. This allows external tools to
4893 * push measures without having to update them too often.
4894 */
4895 frqp = &stktable_data_cast(ptr, std_t_frqp);
Willy Tarreaufa1258f2021-04-10 23:00:53 +02004896 /* First bit is reserved for the freq_ctr lock
Emeric Brunf2fc1fd2017-11-02 17:32:43 +01004897 Note: here we're still protected by the stksess lock
Willy Tarreaufa1258f2021-04-10 23:00:53 +02004898 so we don't need to update the update the freq_ctr
Emeric Brunf2fc1fd2017-11-02 17:32:43 +01004899 using its internal lock */
4900 frqp->curr_tick = now_ms & ~0x1;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004901 frqp->prev_ctr = 0;
4902 frqp->curr_ctr = value;
4903 break;
4904 }
4905 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004906 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004907 stktable_touch_local(t, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004908 break;
4909
4910 default:
Willy Tarreau9d008692019-08-09 11:21:01 +02004911 return cli_err(appctx, "Unknown action\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004912 }
4913 return 1;
4914}
4915
4916/* Prepares the appctx fields with the data-based filters from the command line.
4917 * Returns 0 if the dump can proceed, 1 if has ended processing.
4918 */
4919static int table_prepare_data_request(struct appctx *appctx, char **args)
4920{
Willy Tarreau3c69e082022-05-03 11:35:07 +02004921 struct show_table_ctx *ctx = appctx->svcctx;
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004922 int i;
Adis Nezirovicd0142e72020-01-22 16:50:27 +01004923 char *err = NULL;
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004924
Willy Tarreau3c69e082022-05-03 11:35:07 +02004925 if (ctx->action != STK_CLI_ACT_SHOW && ctx->action != STK_CLI_ACT_CLR)
Willy Tarreau9d008692019-08-09 11:21:01 +02004926 return cli_err(appctx, "content-based lookup is only supported with the \"show\" and \"clear\" actions\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004927
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004928 for (i = 0; i < STKTABLE_FILTER_LEN; i++) {
4929 if (i > 0 && !*args[3+3*i]) // number of filter entries can be less than STKTABLE_FILTER_LEN
4930 break;
4931 /* condition on stored data value */
Willy Tarreau3c69e082022-05-03 11:35:07 +02004932 ctx->data_type[i] = stktable_get_data_type(args[3+3*i] + 5);
4933 if (ctx->data_type[i] < 0)
Adis Nezirovicd0142e72020-01-22 16:50:27 +01004934 return cli_dynerr(appctx, memprintf(&err, "Filter entry #%i: Unknown data type\n", i + 1));
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004935
Willy Tarreau3c69e082022-05-03 11:35:07 +02004936 if (!((struct stktable *)ctx->target)->data_ofs[ctx->data_type[i]])
Adis Nezirovicd0142e72020-01-22 16:50:27 +01004937 return cli_dynerr(appctx, memprintf(&err, "Filter entry #%i: Data type not stored in this table\n", i + 1));
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004938
Willy Tarreau3c69e082022-05-03 11:35:07 +02004939 ctx->data_op[i] = get_std_op(args[4+3*i]);
4940 if (ctx->data_op[i] < 0)
Adis Nezirovicd0142e72020-01-22 16:50:27 +01004941 return cli_dynerr(appctx, memprintf(&err, "Filter entry #%i: Require and operator among \"eq\", \"ne\", \"le\", \"ge\", \"lt\", \"gt\"\n", i + 1));
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004942
Willy Tarreau3c69e082022-05-03 11:35:07 +02004943 if (!*args[5+3*i] || strl2llrc(args[5+3*i], strlen(args[5+3*i]), &ctx->value[i]) != 0)
Adis Nezirovicd0142e72020-01-22 16:50:27 +01004944 return cli_dynerr(appctx, memprintf(&err, "Filter entry #%i: Require a valid integer value to compare against\n", i + 1));
4945 }
4946
4947 if (*args[3+3*i]) {
4948 return cli_dynerr(appctx, memprintf(&err, "Detected extra data in filter, %ith word of input, after '%s'\n", 3+3*i + 1, args[2+3*i]));
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004949 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004950
4951 /* OK we're done, all the fields are set */
4952 return 0;
4953}
4954
4955/* returns 0 if wants to be called, 1 if has ended processing */
Aurélien Nephtaliabbf6072018-04-18 13:26:46 +02004956static int cli_parse_table_req(char **args, char *payload, struct appctx *appctx, void *private)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004957{
Willy Tarreau3c69e082022-05-03 11:35:07 +02004958 struct show_table_ctx *ctx = applet_reserve_svcctx(appctx, sizeof(*ctx));
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004959 int i;
4960
4961 for (i = 0; i < STKTABLE_FILTER_LEN; i++)
Willy Tarreau3c69e082022-05-03 11:35:07 +02004962 ctx->data_type[i] = -1;
4963 ctx->target = NULL;
4964 ctx->entry = NULL;
4965 ctx->action = (long)private; // keyword argument, one of STK_CLI_ACT_*
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004966
4967 if (*args[2]) {
Willy Tarreau0f154ed2022-05-03 12:02:36 +02004968 ctx->t = ctx->target = stktable_find_by_name(args[2]);
Willy Tarreau3c69e082022-05-03 11:35:07 +02004969 if (!ctx->target)
Willy Tarreau9d008692019-08-09 11:21:01 +02004970 return cli_err(appctx, "No such table\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004971 }
4972 else {
Willy Tarreau0f154ed2022-05-03 12:02:36 +02004973 ctx->t = stktables_list;
Willy Tarreau3c69e082022-05-03 11:35:07 +02004974 if (ctx->action != STK_CLI_ACT_SHOW)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004975 goto err_args;
4976 return 0;
4977 }
4978
4979 if (strcmp(args[3], "key") == 0)
4980 return table_process_entry_per_key(appctx, args);
4981 else if (strncmp(args[3], "data.", 5) == 0)
4982 return table_prepare_data_request(appctx, args);
4983 else if (*args[3])
4984 goto err_args;
4985
4986 return 0;
4987
4988err_args:
Willy Tarreau3c69e082022-05-03 11:35:07 +02004989 switch (ctx->action) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004990 case STK_CLI_ACT_SHOW:
Willy Tarreau9d008692019-08-09 11:21:01 +02004991 return cli_err(appctx, "Optional argument only supports \"data.<store_data_type>\" <operator> <value> and key <key>\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004992 case STK_CLI_ACT_CLR:
Willy Tarreau9d008692019-08-09 11:21:01 +02004993 return cli_err(appctx, "Required arguments: <table> \"data.<store_data_type>\" <operator> <value> or <table> key <key>\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004994 case STK_CLI_ACT_SET:
Willy Tarreau9d008692019-08-09 11:21:01 +02004995 return cli_err(appctx, "Required arguments: <table> key <key> [data.<store_data_type> <value>]*\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004996 default:
Willy Tarreau9d008692019-08-09 11:21:01 +02004997 return cli_err(appctx, "Unknown action\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004998 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004999}
5000
5001/* This function is used to deal with table operations (dump or clear depending
5002 * on the action stored in appctx->private). It returns 0 if the output buffer is
5003 * full and it needs to be called again, otherwise non-zero.
5004 */
5005static int cli_io_handler_table(struct appctx *appctx)
5006{
Willy Tarreau3c69e082022-05-03 11:35:07 +02005007 struct show_table_ctx *ctx = appctx->svcctx;
Willy Tarreauc12b3212022-05-27 11:08:15 +02005008 struct stconn *sc = appctx_sc(appctx);
Willy Tarreau475e4632022-05-27 10:26:46 +02005009 struct stream *s = __sc_strm(sc);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01005010 struct ebmb_node *eb;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01005011 int skip_entry;
Willy Tarreau3c69e082022-05-03 11:35:07 +02005012 int show = ctx->action == STK_CLI_ACT_SHOW;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01005013
5014 /*
Willy Tarreau0f154ed2022-05-03 12:02:36 +02005015 * We have 3 possible states in ctx->state :
Willy Tarreau7849d4c2022-05-03 11:45:02 +02005016 * - STATE_NEXT : the proxy pointer points to the next table to
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01005017 * dump, the entry pointer is NULL ;
Willy Tarreau7849d4c2022-05-03 11:45:02 +02005018 * - STATE_DUMP : the proxy pointer points to the current table
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01005019 * and the entry pointer points to the next entry to be dumped,
5020 * and the refcount on the next entry is held ;
Willy Tarreau7849d4c2022-05-03 11:45:02 +02005021 * - STATE_DONE : nothing left to dump, the buffer may contain some
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01005022 * data though.
5023 */
5024
Christopher Fauletda89e9b2023-01-04 14:11:10 +01005025 if (unlikely(sc_ic(sc)->flags & CF_SHUTW)) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01005026 /* in case of abort, remove any refcount we might have set on an entry */
Willy Tarreau7849d4c2022-05-03 11:45:02 +02005027 if (ctx->state == STATE_DUMP) {
Willy Tarreau3c69e082022-05-03 11:35:07 +02005028 stksess_kill_if_expired(ctx->t, ctx->entry, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01005029 }
5030 return 1;
5031 }
5032
5033 chunk_reset(&trash);
5034
Willy Tarreau7849d4c2022-05-03 11:45:02 +02005035 while (ctx->state != STATE_DONE) {
5036 switch (ctx->state) {
Willy Tarreau7849d4c2022-05-03 11:45:02 +02005037 case STATE_NEXT:
Willy Tarreau3c69e082022-05-03 11:35:07 +02005038 if (!ctx->t ||
5039 (ctx->target &&
5040 ctx->t != ctx->target)) {
Willy Tarreau7849d4c2022-05-03 11:45:02 +02005041 ctx->state = STATE_DONE;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01005042 break;
5043 }
5044
Willy Tarreau3c69e082022-05-03 11:35:07 +02005045 if (ctx->t->size) {
Willy Tarreaud0a06d52022-05-18 15:07:19 +02005046 if (show && !table_dump_head_to_buffer(&trash, appctx, ctx->t, ctx->target))
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01005047 return 0;
5048
Willy Tarreau3c69e082022-05-03 11:35:07 +02005049 if (ctx->target &&
William Lallemand07a62f72017-05-24 00:57:40 +02005050 (strm_li(s)->bind_conf->level & ACCESS_LVL_MASK) >= ACCESS_LVL_OPER) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01005051 /* dump entries only if table explicitly requested */
Willy Tarreau76642222022-10-11 12:02:50 +02005052 HA_RWLOCK_WRLOCK(STK_TABLE_LOCK, &ctx->t->lock);
Willy Tarreau3c69e082022-05-03 11:35:07 +02005053 eb = ebmb_first(&ctx->t->keys);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01005054 if (eb) {
Willy Tarreau3c69e082022-05-03 11:35:07 +02005055 ctx->entry = ebmb_entry(eb, struct stksess, key);
5056 ctx->entry->ref_cnt++;
Willy Tarreau7849d4c2022-05-03 11:45:02 +02005057 ctx->state = STATE_DUMP;
Willy Tarreau76642222022-10-11 12:02:50 +02005058 HA_RWLOCK_WRUNLOCK(STK_TABLE_LOCK, &ctx->t->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01005059 break;
5060 }
Willy Tarreau76642222022-10-11 12:02:50 +02005061 HA_RWLOCK_WRUNLOCK(STK_TABLE_LOCK, &ctx->t->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01005062 }
5063 }
Willy Tarreau3c69e082022-05-03 11:35:07 +02005064 ctx->t = ctx->t->next;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01005065 break;
5066
Willy Tarreau7849d4c2022-05-03 11:45:02 +02005067 case STATE_DUMP:
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01005068 skip_entry = 0;
5069
Willy Tarreau3c69e082022-05-03 11:35:07 +02005070 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &ctx->entry->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02005071
Willy Tarreau3c69e082022-05-03 11:35:07 +02005072 if (ctx->data_type[0] >= 0) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01005073 /* we're filtering on some data contents */
5074 void *ptr;
Willy Tarreau2b64a352020-01-22 17:09:47 +01005075 int dt, i;
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01005076 signed char op;
5077 long long data, value;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01005078
Emeric Brun819fc6f2017-06-13 19:37:32 +02005079
Willy Tarreau2b64a352020-01-22 17:09:47 +01005080 for (i = 0; i < STKTABLE_FILTER_LEN; i++) {
Willy Tarreau3c69e082022-05-03 11:35:07 +02005081 if (ctx->data_type[i] == -1)
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01005082 break;
Willy Tarreau3c69e082022-05-03 11:35:07 +02005083 dt = ctx->data_type[i];
5084 ptr = stktable_data_ptr(ctx->t,
5085 ctx->entry,
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01005086 dt);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01005087
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01005088 data = 0;
5089 switch (stktable_data_types[dt].std_type) {
5090 case STD_T_SINT:
5091 data = stktable_data_cast(ptr, std_t_sint);
5092 break;
5093 case STD_T_UINT:
5094 data = stktable_data_cast(ptr, std_t_uint);
5095 break;
5096 case STD_T_ULL:
5097 data = stktable_data_cast(ptr, std_t_ull);
5098 break;
5099 case STD_T_FRQP:
5100 data = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Willy Tarreau3c69e082022-05-03 11:35:07 +02005101 ctx->t->data_arg[dt].u);
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01005102 break;
5103 }
5104
Willy Tarreau3c69e082022-05-03 11:35:07 +02005105 op = ctx->data_op[i];
5106 value = ctx->value[i];
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01005107
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01005108 /* skip the entry if the data does not match the test and the value */
5109 if ((data < value &&
5110 (op == STD_OP_EQ || op == STD_OP_GT || op == STD_OP_GE)) ||
5111 (data == value &&
5112 (op == STD_OP_NE || op == STD_OP_GT || op == STD_OP_LT)) ||
5113 (data > value &&
5114 (op == STD_OP_EQ || op == STD_OP_LT || op == STD_OP_LE))) {
5115 skip_entry = 1;
5116 break;
5117 }
5118 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01005119 }
5120
5121 if (show && !skip_entry &&
Willy Tarreaud0a06d52022-05-18 15:07:19 +02005122 !table_dump_entry_to_buffer(&trash, appctx, ctx->t, ctx->entry)) {
Willy Tarreau3c69e082022-05-03 11:35:07 +02005123 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &ctx->entry->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02005124 return 0;
5125 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01005126
Willy Tarreau3c69e082022-05-03 11:35:07 +02005127 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &ctx->entry->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02005128
Willy Tarreau76642222022-10-11 12:02:50 +02005129 HA_RWLOCK_WRLOCK(STK_TABLE_LOCK, &ctx->t->lock);
Willy Tarreau3c69e082022-05-03 11:35:07 +02005130 ctx->entry->ref_cnt--;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01005131
Willy Tarreau3c69e082022-05-03 11:35:07 +02005132 eb = ebmb_next(&ctx->entry->key);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01005133 if (eb) {
Willy Tarreau3c69e082022-05-03 11:35:07 +02005134 struct stksess *old = ctx->entry;
5135 ctx->entry = ebmb_entry(eb, struct stksess, key);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01005136 if (show)
Willy Tarreau3c69e082022-05-03 11:35:07 +02005137 __stksess_kill_if_expired(ctx->t, old);
5138 else if (!skip_entry && !ctx->entry->ref_cnt)
5139 __stksess_kill(ctx->t, old);
5140 ctx->entry->ref_cnt++;
Willy Tarreau76642222022-10-11 12:02:50 +02005141 HA_RWLOCK_WRUNLOCK(STK_TABLE_LOCK, &ctx->t->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01005142 break;
5143 }
5144
5145
5146 if (show)
Willy Tarreau3c69e082022-05-03 11:35:07 +02005147 __stksess_kill_if_expired(ctx->t, ctx->entry);
5148 else if (!skip_entry && !ctx->entry->ref_cnt)
5149 __stksess_kill(ctx->t, ctx->entry);
Emeric Brun819fc6f2017-06-13 19:37:32 +02005150
Willy Tarreau76642222022-10-11 12:02:50 +02005151 HA_RWLOCK_WRUNLOCK(STK_TABLE_LOCK, &ctx->t->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01005152
Willy Tarreau3c69e082022-05-03 11:35:07 +02005153 ctx->t = ctx->t->next;
Willy Tarreau7849d4c2022-05-03 11:45:02 +02005154 ctx->state = STATE_NEXT;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01005155 break;
5156
Willy Tarreau7849d4c2022-05-03 11:45:02 +02005157 default:
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01005158 break;
5159 }
5160 }
5161 return 1;
5162}
5163
5164static void cli_release_show_table(struct appctx *appctx)
5165{
Willy Tarreau3c69e082022-05-03 11:35:07 +02005166 struct show_table_ctx *ctx = appctx->svcctx;
5167
Willy Tarreau7849d4c2022-05-03 11:45:02 +02005168 if (ctx->state == STATE_DUMP) {
Willy Tarreau3c69e082022-05-03 11:35:07 +02005169 stksess_kill_if_expired(ctx->t, ctx->entry, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01005170 }
5171}
5172
Willy Tarreau6c011712023-01-06 16:09:58 +01005173static int stk_parse_stick_counters(char **args, int section_type, struct proxy *curpx,
5174 const struct proxy *defpx, const char *file, int line,
5175 char **err)
5176{
5177 char *error;
5178 int counters;
5179
5180 counters = strtol(args[1], &error, 10);
5181 if (*error != 0) {
5182 memprintf(err, "%s: '%s' is an invalid number", args[0], args[1]);
5183 return -1;
5184 }
5185
5186 if (counters < 0) {
5187 memprintf(err, "%s: the number of stick-counters may not be negative (was %d)", args[0], counters);
5188 return -1;
5189 }
5190
5191 global.tune.nb_stk_ctr = counters;
5192 return 0;
5193}
5194
5195/* This function creates the stk_ctr pools after the configuration parsing. It
5196 * returns 0 on success otherwise ERR_*. If nb_stk_ctr is 0, the pool remains
5197 * NULL.
5198 */
5199static int stkt_create_stk_ctr_pool(void)
5200{
5201 if (!global.tune.nb_stk_ctr)
5202 return 0;
5203
5204 pool_head_stk_ctr = create_pool("stk_ctr", sizeof(*((struct session*)0)->stkctr) * global.tune.nb_stk_ctr, MEM_F_SHARED);
5205 if (!pool_head_stk_ctr) {
5206 ha_alert("out of memory while creating the stick-counters pool.\n");
5207 return ERR_ABORT;
5208 }
5209 return 0;
5210}
5211
Willy Tarreau478331d2020-08-28 11:31:31 +02005212static void stkt_late_init(void)
5213{
5214 struct sample_fetch *f;
5215
5216 f = find_sample_fetch("src", strlen("src"));
5217 if (f)
5218 smp_fetch_src = f->process;
Willy Tarreau6c011712023-01-06 16:09:58 +01005219 hap_register_post_check(stkt_create_stk_ctr_pool);
Willy Tarreau478331d2020-08-28 11:31:31 +02005220}
5221
5222INITCALL0(STG_INIT, stkt_late_init);
5223
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01005224/* register cli keywords */
5225static struct cli_kw_list cli_kws = {{ },{
Willy Tarreaub205bfd2021-05-07 11:38:37 +02005226 { { "clear", "table", NULL }, "clear table <table> [<filter>]* : remove an entry from a table (filter: data/key)", cli_parse_table_req, cli_io_handler_table, cli_release_show_table, (void *)STK_CLI_ACT_CLR },
5227 { { "set", "table", NULL }, "set table <table> key <k> [data.* <v>]* : update or create a table entry's data", cli_parse_table_req, cli_io_handler_table, NULL, (void *)STK_CLI_ACT_SET },
5228 { { "show", "table", NULL }, "show table <table> [<filter>]* : report table usage stats or dump this table's contents (filter: data/key)", cli_parse_table_req, cli_io_handler_table, cli_release_show_table, (void *)STK_CLI_ACT_SHOW },
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01005229 {{},}
5230}};
5231
Willy Tarreau0108d902018-11-25 19:14:37 +01005232INITCALL1(STG_REGISTER, cli_register_kw, &cli_kws);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01005233
Thierry FOURNIER236657b2015-08-19 08:25:14 +02005234static struct action_kw_list tcp_conn_kws = { { }, {
Willy Tarreau5a72d032023-01-02 18:15:20 +01005235 { "sc-add-gpc", parse_add_gpc, KWF_MATCH_PREFIX },
Emeric Brun4d7ada82021-06-30 19:04:16 +02005236 { "sc-inc-gpc", parse_inc_gpc, KWF_MATCH_PREFIX },
5237 { "sc-inc-gpc0", parse_inc_gpc, KWF_MATCH_PREFIX },
5238 { "sc-inc-gpc1", parse_inc_gpc, KWF_MATCH_PREFIX },
Emeric Brun877b0b52021-06-30 18:57:49 +02005239 { "sc-set-gpt", parse_set_gpt, KWF_MATCH_PREFIX },
5240 { "sc-set-gpt0", parse_set_gpt, KWF_MATCH_PREFIX },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02005241 { /* END */ }
5242}};
5243
Willy Tarreau0108d902018-11-25 19:14:37 +01005244INITCALL1(STG_REGISTER, tcp_req_conn_keywords_register, &tcp_conn_kws);
5245
Willy Tarreau620408f2016-10-21 16:37:51 +02005246static struct action_kw_list tcp_sess_kws = { { }, {
Willy Tarreau5a72d032023-01-02 18:15:20 +01005247 { "sc-add-gpc", parse_add_gpc, KWF_MATCH_PREFIX },
Emeric Brun4d7ada82021-06-30 19:04:16 +02005248 { "sc-inc-gpc", parse_inc_gpc, KWF_MATCH_PREFIX },
5249 { "sc-inc-gpc0", parse_inc_gpc, KWF_MATCH_PREFIX },
5250 { "sc-inc-gpc1", parse_inc_gpc, KWF_MATCH_PREFIX },
Emeric Brun877b0b52021-06-30 18:57:49 +02005251 { "sc-set-gpt", parse_set_gpt, KWF_MATCH_PREFIX },
5252 { "sc-set-gpt0", parse_set_gpt, KWF_MATCH_PREFIX },
Willy Tarreau620408f2016-10-21 16:37:51 +02005253 { /* END */ }
5254}};
5255
Willy Tarreau0108d902018-11-25 19:14:37 +01005256INITCALL1(STG_REGISTER, tcp_req_sess_keywords_register, &tcp_sess_kws);
5257
Thierry FOURNIER236657b2015-08-19 08:25:14 +02005258static struct action_kw_list tcp_req_kws = { { }, {
Willy Tarreau5a72d032023-01-02 18:15:20 +01005259 { "sc-add-gpc", parse_add_gpc, KWF_MATCH_PREFIX },
Emeric Brun4d7ada82021-06-30 19:04:16 +02005260 { "sc-inc-gpc", parse_inc_gpc, KWF_MATCH_PREFIX },
5261 { "sc-inc-gpc0", parse_inc_gpc, KWF_MATCH_PREFIX },
5262 { "sc-inc-gpc1", parse_inc_gpc, KWF_MATCH_PREFIX },
Emeric Brun877b0b52021-06-30 18:57:49 +02005263 { "sc-set-gpt", parse_set_gpt, KWF_MATCH_PREFIX },
5264 { "sc-set-gpt0", parse_set_gpt, KWF_MATCH_PREFIX },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02005265 { /* END */ }
5266}};
5267
Willy Tarreau0108d902018-11-25 19:14:37 +01005268INITCALL1(STG_REGISTER, tcp_req_cont_keywords_register, &tcp_req_kws);
5269
Thierry FOURNIER236657b2015-08-19 08:25:14 +02005270static struct action_kw_list tcp_res_kws = { { }, {
Willy Tarreau5a72d032023-01-02 18:15:20 +01005271 { "sc-add-gpc", parse_add_gpc, KWF_MATCH_PREFIX },
Emeric Brun4d7ada82021-06-30 19:04:16 +02005272 { "sc-inc-gpc", parse_inc_gpc, KWF_MATCH_PREFIX },
5273 { "sc-inc-gpc0", parse_inc_gpc, KWF_MATCH_PREFIX },
5274 { "sc-inc-gpc1", parse_inc_gpc, KWF_MATCH_PREFIX },
Emeric Brun877b0b52021-06-30 18:57:49 +02005275 { "sc-set-gpt", parse_set_gpt, KWF_MATCH_PREFIX },
5276 { "sc-set-gpt0", parse_set_gpt, KWF_MATCH_PREFIX },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02005277 { /* END */ }
5278}};
5279
Willy Tarreau0108d902018-11-25 19:14:37 +01005280INITCALL1(STG_REGISTER, tcp_res_cont_keywords_register, &tcp_res_kws);
5281
Thierry FOURNIER236657b2015-08-19 08:25:14 +02005282static struct action_kw_list http_req_kws = { { }, {
Willy Tarreau5a72d032023-01-02 18:15:20 +01005283 { "sc-add-gpc", parse_add_gpc, KWF_MATCH_PREFIX },
Emeric Brun4d7ada82021-06-30 19:04:16 +02005284 { "sc-inc-gpc", parse_inc_gpc, KWF_MATCH_PREFIX },
5285 { "sc-inc-gpc0", parse_inc_gpc, KWF_MATCH_PREFIX },
5286 { "sc-inc-gpc1", parse_inc_gpc, KWF_MATCH_PREFIX },
Emeric Brun877b0b52021-06-30 18:57:49 +02005287 { "sc-set-gpt", parse_set_gpt, KWF_MATCH_PREFIX },
5288 { "sc-set-gpt0", parse_set_gpt, KWF_MATCH_PREFIX },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02005289 { /* END */ }
5290}};
5291
Willy Tarreau0108d902018-11-25 19:14:37 +01005292INITCALL1(STG_REGISTER, http_req_keywords_register, &http_req_kws);
5293
Thierry FOURNIER236657b2015-08-19 08:25:14 +02005294static struct action_kw_list http_res_kws = { { }, {
Willy Tarreau5a72d032023-01-02 18:15:20 +01005295 { "sc-add-gpc", parse_add_gpc, KWF_MATCH_PREFIX },
Emeric Brun4d7ada82021-06-30 19:04:16 +02005296 { "sc-inc-gpc", parse_inc_gpc, KWF_MATCH_PREFIX },
5297 { "sc-inc-gpc0", parse_inc_gpc, KWF_MATCH_PREFIX },
5298 { "sc-inc-gpc1", parse_inc_gpc, KWF_MATCH_PREFIX },
Emeric Brun877b0b52021-06-30 18:57:49 +02005299 { "sc-set-gpt", parse_set_gpt, KWF_MATCH_PREFIX },
5300 { "sc-set-gpt0", parse_set_gpt, KWF_MATCH_PREFIX },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02005301 { /* END */ }
5302}};
5303
Willy Tarreau0108d902018-11-25 19:14:37 +01005304INITCALL1(STG_REGISTER, http_res_keywords_register, &http_res_kws);
5305
Christopher Fauleta9248042023-01-05 11:17:38 +01005306static struct action_kw_list http_after_res_kws = { { }, {
5307 { "sc-inc-gpc", parse_inc_gpc, KWF_MATCH_PREFIX },
5308 { "sc-inc-gpc0", parse_inc_gpc, KWF_MATCH_PREFIX },
5309 { "sc-inc-gpc1", parse_inc_gpc, KWF_MATCH_PREFIX },
5310 { "sc-set-gpt", parse_set_gpt, KWF_MATCH_PREFIX },
5311 { "sc-set-gpt0", parse_set_gpt, KWF_MATCH_PREFIX },
5312 { /* END */ }
5313}};
5314
5315INITCALL1(STG_REGISTER, http_after_res_keywords_register, &http_after_res_kws);
5316
Willy Tarreau7d562212016-11-25 16:10:05 +01005317/* Note: must not be declared <const> as its list will be overwritten.
5318 * Please take care of keeping this list alphabetically sorted.
5319 */
5320static struct sample_fetch_kw_list smp_fetch_keywords = {ILH, {
5321 { "sc_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5322 { "sc_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
Emeric Brun4d7ada82021-06-30 19:04:16 +02005323 { "sc_clr_gpc", smp_fetch_sc_clr_gpc, ARG3(2,SINT,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
Willy Tarreau7d562212016-11-25 16:10:05 +01005324 { "sc_clr_gpc0", smp_fetch_sc_clr_gpc0, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
Frédéric Lécaille6778b272018-01-29 15:22:53 +01005325 { "sc_clr_gpc1", smp_fetch_sc_clr_gpc1, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN },
Willy Tarreau7d562212016-11-25 16:10:05 +01005326 { "sc_conn_cnt", smp_fetch_sc_conn_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5327 { "sc_conn_cur", smp_fetch_sc_conn_cur, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5328 { "sc_conn_rate", smp_fetch_sc_conn_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
Emeric Brun877b0b52021-06-30 18:57:49 +02005329 { "sc_get_gpt", smp_fetch_sc_get_gpt, ARG3(2,SINT,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
Thierry FOURNIER401c64b2017-01-05 11:44:09 +01005330 { "sc_get_gpt0", smp_fetch_sc_get_gpt0, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
Emeric Brun4d7ada82021-06-30 19:04:16 +02005331 { "sc_get_gpc", smp_fetch_sc_get_gpc, ARG3(2,SINT,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
Willy Tarreau7d562212016-11-25 16:10:05 +01005332 { "sc_get_gpc0", smp_fetch_sc_get_gpc0, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
Frédéric Lécaille6778b272018-01-29 15:22:53 +01005333 { "sc_get_gpc1", smp_fetch_sc_get_gpc1, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN },
Emeric Brun4d7ada82021-06-30 19:04:16 +02005334 { "sc_gpc_rate", smp_fetch_sc_gpc_rate, ARG3(2,SINT,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
Willy Tarreau7d562212016-11-25 16:10:05 +01005335 { "sc_gpc0_rate", smp_fetch_sc_gpc0_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
Frédéric Lécaille6778b272018-01-29 15:22:53 +01005336 { "sc_gpc1_rate", smp_fetch_sc_gpc1_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
Willy Tarreau7d562212016-11-25 16:10:05 +01005337 { "sc_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5338 { "sc_http_err_rate", smp_fetch_sc_http_err_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
Willy Tarreau826f3ab2021-02-10 12:07:15 +01005339 { "sc_http_fail_cnt", smp_fetch_sc_http_fail_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5340 { "sc_http_fail_rate", smp_fetch_sc_http_fail_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
Willy Tarreau7d562212016-11-25 16:10:05 +01005341 { "sc_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5342 { "sc_http_req_rate", smp_fetch_sc_http_req_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
Emeric Brun4d7ada82021-06-30 19:04:16 +02005343 { "sc_inc_gpc", smp_fetch_sc_inc_gpc, ARG3(2,SINT,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
Willy Tarreau7d562212016-11-25 16:10:05 +01005344 { "sc_inc_gpc0", smp_fetch_sc_inc_gpc0, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
Frédéric Lécaille6778b272018-01-29 15:22:53 +01005345 { "sc_inc_gpc1", smp_fetch_sc_inc_gpc1, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
Willy Tarreau7d562212016-11-25 16:10:05 +01005346 { "sc_kbytes_in", smp_fetch_sc_kbytes_in, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5347 { "sc_kbytes_out", smp_fetch_sc_kbytes_out, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5348 { "sc_sess_cnt", smp_fetch_sc_sess_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5349 { "sc_sess_rate", smp_fetch_sc_sess_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5350 { "sc_tracked", smp_fetch_sc_tracked, ARG2(1,SINT,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
5351 { "sc_trackers", smp_fetch_sc_trackers, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5352 { "sc0_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5353 { "sc0_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5354 { "sc0_clr_gpc0", smp_fetch_sc_clr_gpc0, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
Frédéric Lécaille6778b272018-01-29 15:22:53 +01005355 { "sc0_clr_gpc1", smp_fetch_sc_clr_gpc1, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
Willy Tarreau7d562212016-11-25 16:10:05 +01005356 { "sc0_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5357 { "sc0_conn_cur", smp_fetch_sc_conn_cur, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5358 { "sc0_conn_rate", smp_fetch_sc_conn_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
Thierry FOURNIER401c64b2017-01-05 11:44:09 +01005359 { "sc0_get_gpt0", smp_fetch_sc_get_gpt0, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
Willy Tarreau7d562212016-11-25 16:10:05 +01005360 { "sc0_get_gpc0", smp_fetch_sc_get_gpc0, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
Frédéric Lécaille6778b272018-01-29 15:22:53 +01005361 { "sc0_get_gpc1", smp_fetch_sc_get_gpc1, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
Willy Tarreau7d562212016-11-25 16:10:05 +01005362 { "sc0_gpc0_rate", smp_fetch_sc_gpc0_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
Frédéric Lécaille6778b272018-01-29 15:22:53 +01005363 { "sc0_gpc1_rate", smp_fetch_sc_gpc1_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
Willy Tarreau7d562212016-11-25 16:10:05 +01005364 { "sc0_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5365 { "sc0_http_err_rate", smp_fetch_sc_http_err_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
Willy Tarreau826f3ab2021-02-10 12:07:15 +01005366 { "sc0_http_fail_cnt", smp_fetch_sc_http_fail_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5367 { "sc0_http_fail_rate", smp_fetch_sc_http_fail_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
Willy Tarreau7d562212016-11-25 16:10:05 +01005368 { "sc0_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5369 { "sc0_http_req_rate", smp_fetch_sc_http_req_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5370 { "sc0_inc_gpc0", smp_fetch_sc_inc_gpc0, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
Frédéric Lécaille6778b272018-01-29 15:22:53 +01005371 { "sc0_inc_gpc1", smp_fetch_sc_inc_gpc1, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
Willy Tarreau7d562212016-11-25 16:10:05 +01005372 { "sc0_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5373 { "sc0_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5374 { "sc0_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5375 { "sc0_sess_rate", smp_fetch_sc_sess_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5376 { "sc0_tracked", smp_fetch_sc_tracked, ARG1(0,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
5377 { "sc0_trackers", smp_fetch_sc_trackers, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5378 { "sc1_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5379 { "sc1_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
Emeric Brun4d7ada82021-06-30 19:04:16 +02005380 { "sc1_clr_gpc", smp_fetch_sc_clr_gpc, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
Willy Tarreau7d562212016-11-25 16:10:05 +01005381 { "sc1_clr_gpc0", smp_fetch_sc_clr_gpc0, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
Frédéric Lécaille6778b272018-01-29 15:22:53 +01005382 { "sc1_clr_gpc1", smp_fetch_sc_clr_gpc1, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
Willy Tarreau7d562212016-11-25 16:10:05 +01005383 { "sc1_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5384 { "sc1_conn_cur", smp_fetch_sc_conn_cur, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5385 { "sc1_conn_rate", smp_fetch_sc_conn_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
Thierry FOURNIER401c64b2017-01-05 11:44:09 +01005386 { "sc1_get_gpt0", smp_fetch_sc_get_gpt0, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
Willy Tarreau7d562212016-11-25 16:10:05 +01005387 { "sc1_get_gpc0", smp_fetch_sc_get_gpc0, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
Frédéric Lécaille6778b272018-01-29 15:22:53 +01005388 { "sc1_get_gpc1", smp_fetch_sc_get_gpc1, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
Willy Tarreau7d562212016-11-25 16:10:05 +01005389 { "sc1_gpc0_rate", smp_fetch_sc_gpc0_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
Frédéric Lécaille6778b272018-01-29 15:22:53 +01005390 { "sc1_gpc1_rate", smp_fetch_sc_gpc1_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
Willy Tarreau7d562212016-11-25 16:10:05 +01005391 { "sc1_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5392 { "sc1_http_err_rate", smp_fetch_sc_http_err_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
Willy Tarreau826f3ab2021-02-10 12:07:15 +01005393 { "sc1_http_fail_cnt", smp_fetch_sc_http_fail_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5394 { "sc1_http_fail_rate", smp_fetch_sc_http_fail_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
Willy Tarreau7d562212016-11-25 16:10:05 +01005395 { "sc1_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5396 { "sc1_http_req_rate", smp_fetch_sc_http_req_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5397 { "sc1_inc_gpc0", smp_fetch_sc_inc_gpc0, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
Frédéric Lécaille6778b272018-01-29 15:22:53 +01005398 { "sc1_inc_gpc1", smp_fetch_sc_inc_gpc1, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
Willy Tarreau7d562212016-11-25 16:10:05 +01005399 { "sc1_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5400 { "sc1_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5401 { "sc1_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5402 { "sc1_sess_rate", smp_fetch_sc_sess_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5403 { "sc1_tracked", smp_fetch_sc_tracked, ARG1(0,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
5404 { "sc1_trackers", smp_fetch_sc_trackers, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5405 { "sc2_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5406 { "sc2_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5407 { "sc2_clr_gpc0", smp_fetch_sc_clr_gpc0, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
Frédéric Lécaille6778b272018-01-29 15:22:53 +01005408 { "sc2_clr_gpc1", smp_fetch_sc_clr_gpc1, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
Willy Tarreau7d562212016-11-25 16:10:05 +01005409 { "sc2_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5410 { "sc2_conn_cur", smp_fetch_sc_conn_cur, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5411 { "sc2_conn_rate", smp_fetch_sc_conn_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
Thierry FOURNIER401c64b2017-01-05 11:44:09 +01005412 { "sc2_get_gpt0", smp_fetch_sc_get_gpt0, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
Willy Tarreau7d562212016-11-25 16:10:05 +01005413 { "sc2_get_gpc0", smp_fetch_sc_get_gpc0, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
Frédéric Lécaille6778b272018-01-29 15:22:53 +01005414 { "sc2_get_gpc1", smp_fetch_sc_get_gpc1, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
Willy Tarreau7d562212016-11-25 16:10:05 +01005415 { "sc2_gpc0_rate", smp_fetch_sc_gpc0_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
Frédéric Lécaille6778b272018-01-29 15:22:53 +01005416 { "sc2_gpc1_rate", smp_fetch_sc_gpc1_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
Willy Tarreau7d562212016-11-25 16:10:05 +01005417 { "sc2_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5418 { "sc2_http_err_rate", smp_fetch_sc_http_err_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
Willy Tarreau826f3ab2021-02-10 12:07:15 +01005419 { "sc2_http_fail_cnt", smp_fetch_sc_http_fail_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5420 { "sc2_http_fail_rate", smp_fetch_sc_http_fail_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
Willy Tarreau7d562212016-11-25 16:10:05 +01005421 { "sc2_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5422 { "sc2_http_req_rate", smp_fetch_sc_http_req_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5423 { "sc2_inc_gpc0", smp_fetch_sc_inc_gpc0, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
Frédéric Lécaille6778b272018-01-29 15:22:53 +01005424 { "sc2_inc_gpc1", smp_fetch_sc_inc_gpc1, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
Willy Tarreau7d562212016-11-25 16:10:05 +01005425 { "sc2_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5426 { "sc2_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5427 { "sc2_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5428 { "sc2_sess_rate", smp_fetch_sc_sess_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5429 { "sc2_tracked", smp_fetch_sc_tracked, ARG1(0,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
5430 { "sc2_trackers", smp_fetch_sc_trackers, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5431 { "src_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5432 { "src_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
Emeric Brun4d7ada82021-06-30 19:04:16 +02005433 { "src_clr_gpc", smp_fetch_sc_clr_gpc, ARG2(2,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
Willy Tarreau7d562212016-11-25 16:10:05 +01005434 { "src_clr_gpc0", smp_fetch_sc_clr_gpc0, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
Frédéric Lécaille6778b272018-01-29 15:22:53 +01005435 { "src_clr_gpc1", smp_fetch_sc_clr_gpc1, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
Willy Tarreau7d562212016-11-25 16:10:05 +01005436 { "src_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5437 { "src_conn_cur", smp_fetch_sc_conn_cur, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5438 { "src_conn_rate", smp_fetch_sc_conn_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
Emeric Brun877b0b52021-06-30 18:57:49 +02005439 { "src_get_gpt" , smp_fetch_sc_get_gpt, ARG2(2,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
Thierry FOURNIER401c64b2017-01-05 11:44:09 +01005440 { "src_get_gpt0", smp_fetch_sc_get_gpt0, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
Emeric Brun4d7ada82021-06-30 19:04:16 +02005441 { "src_get_gpc", smp_fetch_sc_get_gpc, ARG2(2,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
Willy Tarreau7d562212016-11-25 16:10:05 +01005442 { "src_get_gpc0", smp_fetch_sc_get_gpc0, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
Frédéric Lécaille6778b272018-01-29 15:22:53 +01005443 { "src_get_gpc1", smp_fetch_sc_get_gpc1, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
Emeric Brun4d7ada82021-06-30 19:04:16 +02005444 { "src_gpc_rate", smp_fetch_sc_gpc_rate, ARG2(2,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
Willy Tarreau7d562212016-11-25 16:10:05 +01005445 { "src_gpc0_rate", smp_fetch_sc_gpc0_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
Frédéric Lécaille6778b272018-01-29 15:22:53 +01005446 { "src_gpc1_rate", smp_fetch_sc_gpc1_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
Willy Tarreau7d562212016-11-25 16:10:05 +01005447 { "src_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5448 { "src_http_err_rate", smp_fetch_sc_http_err_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
Willy Tarreau826f3ab2021-02-10 12:07:15 +01005449 { "src_http_fail_cnt", smp_fetch_sc_http_fail_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5450 { "src_http_fail_rate", smp_fetch_sc_http_fail_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
Willy Tarreau7d562212016-11-25 16:10:05 +01005451 { "src_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5452 { "src_http_req_rate", smp_fetch_sc_http_req_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
Emeric Brun4d7ada82021-06-30 19:04:16 +02005453 { "src_inc_gpc", smp_fetch_sc_inc_gpc, ARG2(2,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
Willy Tarreau7d562212016-11-25 16:10:05 +01005454 { "src_inc_gpc0", smp_fetch_sc_inc_gpc0, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
Frédéric Lécaille6778b272018-01-29 15:22:53 +01005455 { "src_inc_gpc1", smp_fetch_sc_inc_gpc1, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
Willy Tarreau7d562212016-11-25 16:10:05 +01005456 { "src_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5457 { "src_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5458 { "src_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5459 { "src_sess_rate", smp_fetch_sc_sess_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5460 { "src_updt_conn_cnt", smp_fetch_src_updt_conn_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5461 { "table_avl", smp_fetch_table_avl, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5462 { "table_cnt", smp_fetch_table_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5463 { /* END */ },
5464}};
5465
Willy Tarreau0108d902018-11-25 19:14:37 +01005466INITCALL1(STG_REGISTER, sample_register_fetches, &smp_fetch_keywords);
Willy Tarreau7d562212016-11-25 16:10:05 +01005467
Willy Tarreaud9f316a2014-07-10 14:03:38 +02005468/* Note: must not be declared <const> as its list will be overwritten */
5469static struct sample_conv_kw_list sample_conv_kws = {ILH, {
Willy Tarreau2d17db52016-05-25 17:16:38 +02005470 { "in_table", sample_conv_in_table, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_BOOL },
5471 { "table_bytes_in_rate", sample_conv_table_bytes_in_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5472 { "table_bytes_out_rate", sample_conv_table_bytes_out_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5473 { "table_conn_cnt", sample_conv_table_conn_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5474 { "table_conn_cur", sample_conv_table_conn_cur, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5475 { "table_conn_rate", sample_conv_table_conn_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
Frédéric Lécaillebbeec372022-08-16 18:11:25 +02005476 { "table_expire", sample_conv_table_expire, ARG2(1,TAB,SINT), NULL, SMP_T_ANY, SMP_T_SINT },
Emeric Brun877b0b52021-06-30 18:57:49 +02005477 { "table_gpt", sample_conv_table_gpt, ARG2(2,SINT,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
Willy Tarreau2d17db52016-05-25 17:16:38 +02005478 { "table_gpt0", sample_conv_table_gpt0, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
Emeric Brun4d7ada82021-06-30 19:04:16 +02005479 { "table_gpc", sample_conv_table_gpc, ARG2(2,SINT,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
Willy Tarreau2d17db52016-05-25 17:16:38 +02005480 { "table_gpc0", sample_conv_table_gpc0, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
Frédéric Lécaille6778b272018-01-29 15:22:53 +01005481 { "table_gpc1", sample_conv_table_gpc1, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
Emeric Brun4d7ada82021-06-30 19:04:16 +02005482 { "table_gpc_rate", sample_conv_table_gpc_rate, ARG2(2,SINT,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
Willy Tarreau2d17db52016-05-25 17:16:38 +02005483 { "table_gpc0_rate", sample_conv_table_gpc0_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
Frédéric Lécaille6778b272018-01-29 15:22:53 +01005484 { "table_gpc1_rate", sample_conv_table_gpc1_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
Willy Tarreau2d17db52016-05-25 17:16:38 +02005485 { "table_http_err_cnt", sample_conv_table_http_err_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5486 { "table_http_err_rate", sample_conv_table_http_err_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
Willy Tarreau826f3ab2021-02-10 12:07:15 +01005487 { "table_http_fail_cnt", sample_conv_table_http_fail_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5488 { "table_http_fail_rate", sample_conv_table_http_fail_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
Willy Tarreau2d17db52016-05-25 17:16:38 +02005489 { "table_http_req_cnt", sample_conv_table_http_req_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5490 { "table_http_req_rate", sample_conv_table_http_req_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
Frédéric Lécaillebbeec372022-08-16 18:11:25 +02005491 { "table_idle", sample_conv_table_idle, ARG2(1,TAB,SINT), NULL, SMP_T_ANY, SMP_T_SINT },
Willy Tarreau2d17db52016-05-25 17:16:38 +02005492 { "table_kbytes_in", sample_conv_table_kbytes_in, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5493 { "table_kbytes_out", sample_conv_table_kbytes_out, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5494 { "table_server_id", sample_conv_table_server_id, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5495 { "table_sess_cnt", sample_conv_table_sess_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5496 { "table_sess_rate", sample_conv_table_sess_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5497 { "table_trackers", sample_conv_table_trackers, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
Willy Tarreaud9f316a2014-07-10 14:03:38 +02005498 { /* END */ },
5499}};
5500
Willy Tarreau0108d902018-11-25 19:14:37 +01005501INITCALL1(STG_REGISTER, sample_register_convs, &sample_conv_kws);
Willy Tarreau6c011712023-01-06 16:09:58 +01005502
5503static struct cfg_kw_list cfg_kws = {{ },{
5504 { CFG_GLOBAL, "tune.stick-counters", stk_parse_stick_counters },
5505 { /* END */ }
5506}};
5507
5508INITCALL1(STG_REGISTER, cfg_register_keywords, &cfg_kws);