blob: 99b1d3334605d49260f27876df7b0416d3f209c8 [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 Tarreauf0b38bf2010-06-06 13:22:23 +020053
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;
2459 struct stkctr *stkctr;
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. */
2463 if (s)
2464 stkctr = &s->stkctr[rule->arg.gpc.sc];
2465 else
2466 stkctr = &sess->stkctr[rule->arg.gpc.sc];
2467
2468 ts = stkctr_entry(stkctr);
2469 if (ts) {
2470 void *ptr1, *ptr2;
2471
2472 /* First, update gpc1_rate if it's tracked. Second, update its gpc1 if tracked. */
2473 ptr1 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC1_RATE);
Emeric Brun726783d2021-06-30 19:06:43 +02002474 if (ptr1) {
2475 period = stkctr->table->data_arg[STKTABLE_DT_GPC1_RATE].u;
2476 }
2477 else {
2478 /* fallback on the gpc array */
2479 ptr1 = stktable_data_ptr_idx(stkctr->table, ts, STKTABLE_DT_GPC_RATE, 1);
2480 if (ptr1)
2481 period = stkctr->table->data_arg[STKTABLE_DT_GPC_RATE].u;
2482 }
2483
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002484 ptr2 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC1);
Emeric Brun726783d2021-06-30 19:06:43 +02002485 if (!ptr2) {
2486 /* fallback on the gpc array */
2487 ptr2 = stktable_data_ptr_idx(stkctr->table, ts, STKTABLE_DT_GPC, 1);
2488 }
2489
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002490 if (ptr1 || ptr2) {
2491 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
2492
2493 if (ptr1)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002494 update_freq_ctr_period(&stktable_data_cast(ptr1, std_t_frqp),
Emeric Brun726783d2021-06-30 19:06:43 +02002495 period, 1);
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002496
2497 if (ptr2)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002498 stktable_data_cast(ptr2, std_t_uint)++;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002499
2500 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
2501
2502 /* If data was modified, we need to touch to re-schedule sync */
2503 stktable_touch_local(stkctr->table, ts, 0);
2504 }
2505 }
2506 return ACT_RET_CONT;
2507}
2508
Emeric Brun4d7ada82021-06-30 19:04:16 +02002509/* This function is a common parser for actions incrementing the GPC
2510 * (General Purpose Counters). It understands the formats:
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002511 *
Emeric Brun4d7ada82021-06-30 19:04:16 +02002512 * sc-inc-gpc(<gpc IDX>,<track ID>)
2513 * sc-inc-gpc0([<track ID>])
2514 * sc-inc-gpc1([<track ID>])
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002515 *
Emeric Brun4d7ada82021-06-30 19:04:16 +02002516 * It returns ACT_RET_PRS_ERR if fails and <err> is filled with an error
2517 * message. Otherwise it returns ACT_RET_PRS_OK.
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002518 */
Emeric Brun4d7ada82021-06-30 19:04:16 +02002519static enum act_parse_ret parse_inc_gpc(const char **args, int *arg, struct proxy *px,
2520 struct act_rule *rule, char **err)
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002521{
2522 const char *cmd_name = args[*arg-1];
2523 char *error;
2524
Emeric Brun4d7ada82021-06-30 19:04:16 +02002525 cmd_name += strlen("sc-inc-gpc");
2526 if (*cmd_name == '(') {
2527 cmd_name++; /* skip the '(' */
2528 rule->arg.gpc.idx = strtoul(cmd_name, &error, 10); /* Convert stick table id. */
2529 if (*error != ',') {
2530 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 +01002531 return ACT_RET_PRS_ERR;
2532 }
Emeric Brun4d7ada82021-06-30 19:04:16 +02002533 else {
2534 cmd_name = error + 1; /* skip the ',' */
2535 rule->arg.gpc.sc = strtol(cmd_name, &error, 10); /* Convert stick table id. */
2536 if (*error != ')') {
2537 memprintf(err, "invalid stick table track ID '%s'. Expects sc-inc-gpc(<GPC ID>,<Track ID>)", args[*arg-1]);
2538 return ACT_RET_PRS_ERR;
2539 }
2540
2541 if (rule->arg.gpc.sc >= MAX_SESS_STKCTR) {
2542 memprintf(err, "invalid stick table track ID '%s'. The max allowed ID is %d",
2543 args[*arg-1], MAX_SESS_STKCTR-1);
2544 return ACT_RET_PRS_ERR;
2545 }
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002546 }
Emeric Brun4d7ada82021-06-30 19:04:16 +02002547 rule->action_ptr = action_inc_gpc;
2548 }
2549 else if (*cmd_name == '0' ||*cmd_name == '1') {
2550 char c = *cmd_name;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002551
Emeric Brun4d7ada82021-06-30 19:04:16 +02002552 cmd_name++;
2553 if (*cmd_name == '\0') {
2554 /* default stick table id. */
2555 rule->arg.gpc.sc = 0;
2556 } else {
2557 /* parse the stick table id. */
2558 if (*cmd_name != '(') {
2559 memprintf(err, "invalid stick table track ID. Expects %s(<Track ID>)", args[*arg-1]);
2560 return ACT_RET_PRS_ERR;
2561 }
2562 cmd_name++; /* jump the '(' */
2563 rule->arg.gpc.sc = strtol(cmd_name, &error, 10); /* Convert stick table id. */
2564 if (*error != ')') {
2565 memprintf(err, "invalid stick table track ID. Expects %s(<Track ID>)", args[*arg-1]);
2566 return ACT_RET_PRS_ERR;
2567 }
2568
2569 if (rule->arg.gpc.sc >= MAX_SESS_STKCTR) {
2570 memprintf(err, "invalid stick table track ID. The max allowed ID is %d",
2571 MAX_SESS_STKCTR-1);
2572 return ACT_RET_PRS_ERR;
2573 }
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002574 }
Emeric Brun4d7ada82021-06-30 19:04:16 +02002575 if (c == '1')
2576 rule->action_ptr = action_inc_gpc1;
2577 else
2578 rule->action_ptr = action_inc_gpc0;
2579 }
2580 else {
2581 /* default stick table id. */
2582 memprintf(err, "invalid gpc ID '%s'. Expects sc-set-gpc(<GPC ID>,<Track ID>)", args[*arg-1]);
2583 return ACT_RET_PRS_ERR;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002584 }
2585 rule->action = ACT_CUSTOM;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002586 return ACT_RET_PRS_OK;
2587}
2588
Emeric Brun877b0b52021-06-30 18:57:49 +02002589/* This function sets the gpt at index 'rule->arg.gpt.idx' of the array on the
2590 * tracksc counter of index 'rule->arg.gpt.sc' stored into the <stream> or
2591 * directly in the session <sess> if <stream> is set to NULL. This gpt is
2592 * set to the value computed by the expression 'rule->arg.gpt.expr' or if
2593 * 'rule->arg.gpt.expr' is null directly to the value of 'rule->arg.gpt.value'.
2594 *
2595 * This function always returns ACT_RET_CONT and parameter flags is unused.
2596 */
2597static enum act_return action_set_gpt(struct act_rule *rule, struct proxy *px,
2598 struct session *sess, struct stream *s, int flags)
2599{
2600 void *ptr;
2601 struct stksess *ts;
2602 struct stkctr *stkctr;
2603 unsigned int value = 0;
2604 struct sample *smp;
2605 int smp_opt_dir;
2606
2607 /* Extract the stksess, return OK if no stksess available. */
2608 if (s)
2609 stkctr = &s->stkctr[rule->arg.gpt.sc];
2610 else
2611 stkctr = &sess->stkctr[rule->arg.gpt.sc];
2612
2613 ts = stkctr_entry(stkctr);
2614 if (!ts)
2615 return ACT_RET_CONT;
2616
2617 /* Store the sample in the required sc, and ignore errors. */
2618 ptr = stktable_data_ptr_idx(stkctr->table, ts, STKTABLE_DT_GPT, rule->arg.gpt.idx);
2619 if (ptr) {
2620
2621 if (!rule->arg.gpt.expr)
2622 value = (unsigned int)(rule->arg.gpt.value);
2623 else {
2624 switch (rule->from) {
2625 case ACT_F_TCP_REQ_SES: smp_opt_dir = SMP_OPT_DIR_REQ; break;
2626 case ACT_F_TCP_REQ_CNT: smp_opt_dir = SMP_OPT_DIR_REQ; break;
2627 case ACT_F_TCP_RES_CNT: smp_opt_dir = SMP_OPT_DIR_RES; break;
2628 case ACT_F_HTTP_REQ: smp_opt_dir = SMP_OPT_DIR_REQ; break;
2629 case ACT_F_HTTP_RES: smp_opt_dir = SMP_OPT_DIR_RES; break;
2630 default:
2631 send_log(px, LOG_ERR, "stick table: internal error while setting gpt%u.", rule->arg.gpt.idx);
2632 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))
2633 ha_alert("stick table: internal error while executing setting gpt%u.\n", rule->arg.gpt.idx);
2634 return ACT_RET_CONT;
2635 }
2636
2637 /* Fetch and cast the expression. */
2638 smp = sample_fetch_as_type(px, sess, s, smp_opt_dir|SMP_OPT_FINAL, rule->arg.gpt.expr, SMP_T_SINT);
2639 if (!smp) {
2640 send_log(px, LOG_WARNING, "stick table: invalid expression or data type while setting gpt%u.", rule->arg.gpt.idx);
2641 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))
2642 ha_alert("stick table: invalid expression or data type while setting gpt%u.\n", rule->arg.gpt.idx);
2643 return ACT_RET_CONT;
2644 }
2645 value = (unsigned int)(smp->data.u.sint);
2646 }
2647
2648 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
2649
2650 stktable_data_cast(ptr, std_t_uint) = value;
2651
2652 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
2653
2654 stktable_touch_local(stkctr->table, ts, 0);
2655 }
2656
2657 return ACT_RET_CONT;
2658}
2659
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002660/* Always returns 1. */
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002661static enum act_return action_set_gpt0(struct act_rule *rule, struct proxy *px,
Willy Tarreau658b85b2015-09-27 10:00:49 +02002662 struct session *sess, struct stream *s, int flags)
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002663{
2664 void *ptr;
2665 struct stksess *ts;
2666 struct stkctr *stkctr;
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002667 unsigned int value = 0;
2668 struct sample *smp;
2669 int smp_opt_dir;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002670
2671 /* Extract the stksess, return OK if no stksess available. */
2672 if (s)
2673 stkctr = &s->stkctr[rule->arg.gpt.sc];
2674 else
2675 stkctr = &sess->stkctr[rule->arg.gpt.sc];
Willy Tarreau79c1e912016-01-25 14:54:45 +01002676
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002677 ts = stkctr_entry(stkctr);
2678 if (!ts)
2679 return ACT_RET_CONT;
2680
2681 /* Store the sample in the required sc, and ignore errors. */
2682 ptr = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPT0);
Emeric Brunf7ab0bf2021-06-30 18:58:22 +02002683 if (!ptr)
2684 ptr = stktable_data_ptr_idx(stkctr->table, ts, STKTABLE_DT_GPT, 0);
2685
Willy Tarreau79c1e912016-01-25 14:54:45 +01002686 if (ptr) {
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002687 if (!rule->arg.gpt.expr)
2688 value = (unsigned int)(rule->arg.gpt.value);
2689 else {
2690 switch (rule->from) {
2691 case ACT_F_TCP_REQ_SES: smp_opt_dir = SMP_OPT_DIR_REQ; break;
2692 case ACT_F_TCP_REQ_CNT: smp_opt_dir = SMP_OPT_DIR_REQ; break;
2693 case ACT_F_TCP_RES_CNT: smp_opt_dir = SMP_OPT_DIR_RES; break;
2694 case ACT_F_HTTP_REQ: smp_opt_dir = SMP_OPT_DIR_REQ; break;
2695 case ACT_F_HTTP_RES: smp_opt_dir = SMP_OPT_DIR_RES; break;
2696 default:
2697 send_log(px, LOG_ERR, "stick table: internal error while setting gpt0.");
2698 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))
2699 ha_alert("stick table: internal error while executing setting gpt0.\n");
2700 return ACT_RET_CONT;
2701 }
2702
2703 /* Fetch and cast the expression. */
2704 smp = sample_fetch_as_type(px, sess, s, smp_opt_dir|SMP_OPT_FINAL, rule->arg.gpt.expr, SMP_T_SINT);
2705 if (!smp) {
2706 send_log(px, LOG_WARNING, "stick table: invalid expression or data type while setting gpt0.");
2707 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))
2708 ha_alert("stick table: invalid expression or data type while setting gpt0.\n");
2709 return ACT_RET_CONT;
2710 }
2711 value = (unsigned int)(smp->data.u.sint);
2712 }
2713
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002714 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002715
Emeric Brun0e3457b2021-06-30 17:18:28 +02002716 stktable_data_cast(ptr, std_t_uint) = value;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002717
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002718 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002719
2720 stktable_touch_local(stkctr->table, ts, 0);
Willy Tarreau79c1e912016-01-25 14:54:45 +01002721 }
2722
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002723 return ACT_RET_CONT;
2724}
2725
Emeric Brun877b0b52021-06-30 18:57:49 +02002726/* This function is a parser for the "sc-set-gpt" and "sc-set-gpt0" actions.
2727 * It understands the formats:
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002728 *
Emeric Brun877b0b52021-06-30 18:57:49 +02002729 * sc-set-gpt(<gpt IDX>,<track ID>) <expression>
2730 * sc-set-gpt0(<track ID>) <expression>
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002731 *
Emeric Brun877b0b52021-06-30 18:57:49 +02002732 * It returns ACT_RET_PRS_ERR if fails and <err> is filled with an error message.
2733 * Otherwise, it returns ACT_RET_PRS_OK and the variable 'rule->arg.gpt.expr'
2734 * is filled with the pointer to the expression to execute or NULL if the arg
2735 * is directly an integer stored into 'rule->arg.gpt.value'.
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002736 */
Emeric Brun877b0b52021-06-30 18:57:49 +02002737static enum act_parse_ret parse_set_gpt(const char **args, int *arg, struct proxy *px,
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002738 struct act_rule *rule, char **err)
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002739{
2740 const char *cmd_name = args[*arg-1];
2741 char *error;
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002742 int smp_val;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002743
Emeric Brun877b0b52021-06-30 18:57:49 +02002744 cmd_name += strlen("sc-set-gpt");
2745 if (*cmd_name == '(') {
2746 cmd_name++; /* skip the '(' */
2747 rule->arg.gpt.idx = strtoul(cmd_name, &error, 10); /* Convert stick table id. */
2748 if (*error != ',') {
2749 memprintf(err, "Missing gpt ID '%s'. Expects sc-set-gpt(<GPT ID>,<Track ID>)", args[*arg-1]);
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002750 return ACT_RET_PRS_ERR;
2751 }
Emeric Brun877b0b52021-06-30 18:57:49 +02002752 else {
2753 cmd_name = error + 1; /* skip the ',' */
2754 rule->arg.gpt.sc = strtol(cmd_name, &error, 10); /* Convert stick table id. */
2755 if (*error != ')') {
2756 memprintf(err, "invalid stick table track ID '%s'. Expects sc-set-gpt(<GPT ID>,<Track ID>)", args[*arg-1]);
2757 return ACT_RET_PRS_ERR;
2758 }
2759
2760 if (rule->arg.gpt.sc >= MAX_SESS_STKCTR) {
2761 memprintf(err, "invalid stick table track ID '%s'. The max allowed ID is %d",
2762 args[*arg-1], MAX_SESS_STKCTR-1);
2763 return ACT_RET_PRS_ERR;
2764 }
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002765 }
Emeric Brun877b0b52021-06-30 18:57:49 +02002766 rule->action_ptr = action_set_gpt;
2767 }
2768 else if (*cmd_name == '0') {
2769 cmd_name++;
2770 if (*cmd_name == '\0') {
2771 /* default stick table id. */
2772 rule->arg.gpt.sc = 0;
2773 } else {
2774 /* parse the stick table id. */
2775 if (*cmd_name != '(') {
2776 memprintf(err, "invalid stick table track ID '%s'. Expects sc-set-gpt0(<Track ID>)", args[*arg-1]);
2777 return ACT_RET_PRS_ERR;
2778 }
2779 cmd_name++; /* jump the '(' */
2780 rule->arg.gpt.sc = strtol(cmd_name, &error, 10); /* Convert stick table id. */
2781 if (*error != ')') {
2782 memprintf(err, "invalid stick table track ID '%s'. Expects sc-set-gpt0(<Track ID>)", args[*arg-1]);
2783 return ACT_RET_PRS_ERR;
2784 }
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002785
Emeric Brun877b0b52021-06-30 18:57:49 +02002786 if (rule->arg.gpt.sc >= MAX_SESS_STKCTR) {
2787 memprintf(err, "invalid stick table track ID '%s'. The max allowed ID is %d",
2788 args[*arg-1], MAX_SESS_STKCTR-1);
2789 return ACT_RET_PRS_ERR;
2790 }
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002791 }
Emeric Brun877b0b52021-06-30 18:57:49 +02002792 rule->action_ptr = action_set_gpt0;
2793 }
2794 else {
2795 /* default stick table id. */
2796 memprintf(err, "invalid gpt ID '%s'. Expects sc-set-gpt(<GPT ID>,<Track ID>)", args[*arg-1]);
2797 return ACT_RET_PRS_ERR;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002798 }
2799
Willy Tarreauece4c4a2021-08-24 14:57:28 +02002800 /* value may be either an integer or an expression */
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002801 rule->arg.gpt.expr = NULL;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002802 rule->arg.gpt.value = strtol(args[*arg], &error, 10);
Willy Tarreauece4c4a2021-08-24 14:57:28 +02002803 if (*error == '\0') {
2804 /* valid integer, skip it */
2805 (*arg)++;
2806 } else {
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002807 rule->arg.gpt.expr = sample_parse_expr((char **)args, arg, px->conf.args.file,
Willy Tarreaue3b57bf2020-02-14 16:50:14 +01002808 px->conf.args.line, err, &px->conf.args, NULL);
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002809 if (!rule->arg.gpt.expr)
2810 return ACT_RET_PRS_ERR;
2811
2812 switch (rule->from) {
2813 case ACT_F_TCP_REQ_SES: smp_val = SMP_VAL_FE_SES_ACC; break;
2814 case ACT_F_TCP_REQ_CNT: smp_val = SMP_VAL_FE_REQ_CNT; break;
2815 case ACT_F_TCP_RES_CNT: smp_val = SMP_VAL_BE_RES_CNT; break;
2816 case ACT_F_HTTP_REQ: smp_val = SMP_VAL_FE_HRQ_HDR; break;
2817 case ACT_F_HTTP_RES: smp_val = SMP_VAL_BE_HRS_HDR; break;
2818 default:
2819 memprintf(err, "internal error, unexpected rule->from=%d, please report this bug!", rule->from);
2820 return ACT_RET_PRS_ERR;
2821 }
2822 if (!(rule->arg.gpt.expr->fetch->val & smp_val)) {
2823 memprintf(err, "fetch method '%s' extracts information from '%s', none of which is available here", args[*arg-1],
2824 sample_src_names(rule->arg.gpt.expr->fetch->use));
2825 free(rule->arg.gpt.expr);
2826 return ACT_RET_PRS_ERR;
2827 }
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002828 }
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002829
Thierry FOURNIER42148732015-09-02 17:17:33 +02002830 rule->action = ACT_CUSTOM;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002831
2832 return ACT_RET_PRS_OK;
2833}
2834
Willy Tarreau7d562212016-11-25 16:10:05 +01002835/* set temp integer to the number of used entries in the table pointed to by expr.
2836 * Accepts exactly 1 argument of type table.
2837 */
2838static int
2839smp_fetch_table_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
2840{
2841 smp->flags = SMP_F_VOL_TEST;
2842 smp->data.type = SMP_T_SINT;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002843 smp->data.u.sint = args->data.t->current;
Willy Tarreau7d562212016-11-25 16:10:05 +01002844 return 1;
2845}
2846
2847/* set temp integer to the number of free entries in the table pointed to by expr.
2848 * Accepts exactly 1 argument of type table.
2849 */
2850static int
2851smp_fetch_table_avl(const struct arg *args, struct sample *smp, const char *kw, void *private)
2852{
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002853 struct stktable *t;
Willy Tarreau7d562212016-11-25 16:10:05 +01002854
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002855 t = args->data.t;
Willy Tarreau7d562212016-11-25 16:10:05 +01002856 smp->flags = SMP_F_VOL_TEST;
2857 smp->data.type = SMP_T_SINT;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002858 smp->data.u.sint = t->size - t->current;
Willy Tarreau7d562212016-11-25 16:10:05 +01002859 return 1;
2860}
2861
2862/* Returns a pointer to a stkctr depending on the fetch keyword name.
2863 * It is designed to be called as sc[0-9]_* sc_* or src_* exclusively.
2864 * sc[0-9]_* will return a pointer to the respective field in the
2865 * stream <l4>. sc_* requires an UINT argument specifying the stick
2866 * counter number. src_* will fill a locally allocated structure with
2867 * the table and entry corresponding to what is specified with src_*.
2868 * NULL may be returned if the designated stkctr is not tracked. For
2869 * the sc_* and sc[0-9]_* forms, an optional table argument may be
2870 * passed. When present, the currently tracked key is then looked up
2871 * in the specified table instead of the current table. The purpose is
Ilya Shipitsin47d17182020-06-21 21:42:57 +05002872 * to be able to convert multiple values per key (eg: have gpc0 from
Willy Tarreau7d562212016-11-25 16:10:05 +01002873 * multiple tables). <strm> is allowed to be NULL, in which case only
2874 * the session will be consulted.
2875 */
2876struct stkctr *
Emeric Brun819fc6f2017-06-13 19:37:32 +02002877smp_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 +01002878{
Willy Tarreau7d562212016-11-25 16:10:05 +01002879 struct stkctr *stkptr;
2880 struct stksess *stksess;
2881 unsigned int num = kw[2] - '0';
2882 int arg = 0;
2883
2884 if (num == '_' - '0') {
2885 /* sc_* variant, args[0] = ctr# (mandatory) */
2886 num = args[arg++].data.sint;
Willy Tarreau7d562212016-11-25 16:10:05 +01002887 }
2888 else if (num > 9) { /* src_* variant, args[0] = table */
2889 struct stktable_key *key;
2890 struct connection *conn = objt_conn(sess->origin);
2891 struct sample smp;
2892
2893 if (!conn)
2894 return NULL;
2895
Joseph Herlant5662fa42018-11-15 13:43:28 -08002896 /* Fetch source address in a sample. */
Willy Tarreau7d562212016-11-25 16:10:05 +01002897 smp.px = NULL;
2898 smp.sess = sess;
2899 smp.strm = strm;
Amaury Denoyellec460c702021-05-12 10:17:47 +02002900 if (!smp_fetch_src || !smp_fetch_src(empty_arg_list, &smp, "src", NULL))
Willy Tarreau7d562212016-11-25 16:10:05 +01002901 return NULL;
2902
2903 /* Converts into key. */
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002904 key = smp_to_stkey(&smp, args->data.t);
Willy Tarreau7d562212016-11-25 16:10:05 +01002905 if (!key)
2906 return NULL;
2907
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002908 stkctr->table = args->data.t;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002909 stkctr_set_entry(stkctr, stktable_lookup_key(stkctr->table, key));
2910 return stkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002911 }
2912
2913 /* Here, <num> contains the counter number from 0 to 9 for
2914 * the sc[0-9]_ form, or even higher using sc_(num) if needed.
2915 * args[arg] is the first optional argument. We first lookup the
2916 * ctr form the stream, then from the session if it was not there.
Christopher Fauleta9fa88a2019-10-21 10:53:34 +02002917 * But we must be sure the counter does not exceed MAX_SESS_STKCTR.
Willy Tarreau7d562212016-11-25 16:10:05 +01002918 */
Christopher Fauleta9fa88a2019-10-21 10:53:34 +02002919 if (num >= MAX_SESS_STKCTR)
2920 return NULL;
Willy Tarreau7d562212016-11-25 16:10:05 +01002921
2922 if (strm)
2923 stkptr = &strm->stkctr[num];
2924 if (!strm || !stkctr_entry(stkptr)) {
2925 stkptr = &sess->stkctr[num];
2926 if (!stkctr_entry(stkptr))
2927 return NULL;
2928 }
2929
2930 stksess = stkctr_entry(stkptr);
2931 if (!stksess)
2932 return NULL;
2933
2934 if (unlikely(args[arg].type == ARGT_TAB)) {
2935 /* an alternate table was specified, let's look up the same key there */
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002936 stkctr->table = args[arg].data.t;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002937 stkctr_set_entry(stkctr, stktable_lookup(stkctr->table, stksess));
2938 return stkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002939 }
2940 return stkptr;
2941}
2942
2943/* same as smp_fetch_sc_stkctr() but dedicated to src_* and can create
2944 * the entry if it doesn't exist yet. This is needed for a few fetch
2945 * functions which need to create an entry, such as src_inc_gpc* and
2946 * src_clr_gpc*.
2947 */
2948struct stkctr *
Emeric Brun819fc6f2017-06-13 19:37:32 +02002949smp_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 +01002950{
Willy Tarreau7d562212016-11-25 16:10:05 +01002951 struct stktable_key *key;
2952 struct connection *conn = objt_conn(sess->origin);
2953 struct sample smp;
2954
2955 if (strncmp(kw, "src_", 4) != 0)
2956 return NULL;
2957
2958 if (!conn)
2959 return NULL;
2960
Joseph Herlant5662fa42018-11-15 13:43:28 -08002961 /* Fetch source address in a sample. */
Willy Tarreau7d562212016-11-25 16:10:05 +01002962 smp.px = NULL;
2963 smp.sess = sess;
2964 smp.strm = strm;
Amaury Denoyellec460c702021-05-12 10:17:47 +02002965 if (!smp_fetch_src || !smp_fetch_src(empty_arg_list, &smp, "src", NULL))
Willy Tarreau7d562212016-11-25 16:10:05 +01002966 return NULL;
2967
2968 /* Converts into key. */
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002969 key = smp_to_stkey(&smp, args->data.t);
Willy Tarreau7d562212016-11-25 16:10:05 +01002970 if (!key)
2971 return NULL;
2972
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002973 stkctr->table = args->data.t;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002974 stkctr_set_entry(stkctr, stktable_get_entry(stkctr->table, key));
2975 return stkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002976}
2977
2978/* set return a boolean indicating if the requested stream counter is
2979 * currently being tracked or not.
2980 * Supports being called as "sc[0-9]_tracked" only.
2981 */
2982static int
2983smp_fetch_sc_tracked(const struct arg *args, struct sample *smp, const char *kw, void *private)
2984{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002985 struct stkctr tmpstkctr;
2986 struct stkctr *stkctr;
2987
Willy Tarreau7d562212016-11-25 16:10:05 +01002988 smp->flags = SMP_F_VOL_TEST;
2989 smp->data.type = SMP_T_BOOL;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002990 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2991 smp->data.u.sint = !!stkctr;
2992
2993 /* release the ref count */
Dirkjan Bussinkff57f1b2018-09-14 14:31:22 +02002994 if (stkctr == &tmpstkctr)
Emeric Brun819fc6f2017-06-13 19:37:32 +02002995 stktable_release(stkctr->table, stkctr_entry(stkctr));
2996
Emeric Brun877b0b52021-06-30 18:57:49 +02002997 return 1;
2998}
2999
3000/* set <smp> to the General Purpose Tag of index set as first arg
3001 * to value from the stream's tracked frontend counters or from the src.
3002 * Supports being called as "sc_get_gpt(<gpt-idx>,<sc-idx>[,<table>])" or
3003 * "src_get_gpt(<gpt-idx>[,<table>])" only. Value zero is returned if
3004 * the key is new or gpt is not stored.
3005 */
3006static int
3007smp_fetch_sc_get_gpt(const struct arg *args, struct sample *smp, const char *kw, void *private)
3008{
3009 struct stkctr tmpstkctr;
3010 struct stkctr *stkctr;
3011 unsigned int idx;
3012
3013 idx = args[0].data.sint;
3014
3015 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args + 1, kw, &tmpstkctr);
3016 if (!stkctr)
3017 return 0;
3018
3019 smp->flags = SMP_F_VOL_TEST;
3020 smp->data.type = SMP_T_SINT;
3021 smp->data.u.sint = 0;
3022
3023 if (stkctr_entry(stkctr)) {
3024 void *ptr;
3025
3026 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPT, idx);
3027 if (!ptr) {
3028 if (stkctr == &tmpstkctr)
3029 stktable_release(stkctr->table, stkctr_entry(stkctr));
3030 return 0; /* parameter not stored */
3031 }
3032
3033 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3034
3035 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
3036
3037 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3038
3039 if (stkctr == &tmpstkctr)
3040 stktable_release(stkctr->table, stkctr_entry(stkctr));
3041 }
Willy Tarreau7d562212016-11-25 16:10:05 +01003042 return 1;
3043}
3044
3045/* set <smp> to the General Purpose Flag 0 value from the stream's tracked
3046 * frontend counters or from the src.
3047 * Supports being called as "sc[0-9]_get_gpc0" or "src_get_gpt0" only. Value
3048 * zero is returned if the key is new.
3049 */
3050static int
3051smp_fetch_sc_get_gpt0(const struct arg *args, struct sample *smp, const char *kw, void *private)
3052{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003053 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003054 struct stkctr *stkctr;
3055
Emeric Brun819fc6f2017-06-13 19:37:32 +02003056 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003057 if (!stkctr)
3058 return 0;
3059
3060 smp->flags = SMP_F_VOL_TEST;
3061 smp->data.type = SMP_T_SINT;
3062 smp->data.u.sint = 0;
3063
Emeric Brun819fc6f2017-06-13 19:37:32 +02003064 if (stkctr_entry(stkctr)) {
3065 void *ptr;
3066
3067 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPT0);
Emeric Brunf7ab0bf2021-06-30 18:58:22 +02003068 if (!ptr)
3069 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPT, 0);
3070
Emeric Brun4d7ada82021-06-30 19:04:16 +02003071 if (!ptr) {
3072 if (stkctr == &tmpstkctr)
3073 stktable_release(stkctr->table, stkctr_entry(stkctr));
3074 return 0; /* parameter not stored */
3075 }
3076
3077 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3078
3079 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
3080
3081 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3082
3083 if (stkctr == &tmpstkctr)
3084 stktable_release(stkctr->table, stkctr_entry(stkctr));
3085 }
3086 return 1;
3087}
3088
3089/* set <smp> to the GPC[args(0)]'s value from the stream's tracked
3090 * frontend counters or from the src.
3091 * Supports being called as "sc_get_gpc(<gpc-idx>,<sc-idx>[,<table>])" or
3092 * "src_get_gpc(<gpc-idx>[,<table>])" only. Value
3093 * Value zero is returned if the key is new or gpc is not stored.
3094 */
3095static int
3096smp_fetch_sc_get_gpc(const struct arg *args, struct sample *smp, const char *kw, void *private)
3097{
3098 struct stkctr tmpstkctr;
3099 struct stkctr *stkctr;
3100 unsigned int idx;
3101
3102 idx = args[0].data.sint;
3103
3104 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args + 1, kw, &tmpstkctr);
3105 if (!stkctr)
3106 return 0;
3107
3108 smp->flags = SMP_F_VOL_TEST;
3109 smp->data.type = SMP_T_SINT;
3110 smp->data.u.sint = 0;
3111
3112 if (stkctr_entry(stkctr) != NULL) {
3113 void *ptr;
3114
3115 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC, idx);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003116 if (!ptr) {
3117 if (stkctr == &tmpstkctr)
3118 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003119 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003120 }
3121
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003122 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003123
Emeric Brun0e3457b2021-06-30 17:18:28 +02003124 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003125
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003126 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003127
3128 if (stkctr == &tmpstkctr)
3129 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003130 }
3131 return 1;
3132}
3133
3134/* set <smp> to the General Purpose Counter 0 value from the stream's tracked
3135 * frontend counters or from the src.
3136 * Supports being called as "sc[0-9]_get_gpc0" or "src_get_gpc0" only. Value
3137 * zero is returned if the key is new.
3138 */
3139static int
3140smp_fetch_sc_get_gpc0(const struct arg *args, struct sample *smp, const char *kw, void *private)
3141{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003142 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003143 struct stkctr *stkctr;
3144
Emeric Brun819fc6f2017-06-13 19:37:32 +02003145 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003146 if (!stkctr)
3147 return 0;
3148
3149 smp->flags = SMP_F_VOL_TEST;
3150 smp->data.type = SMP_T_SINT;
3151 smp->data.u.sint = 0;
3152
3153 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003154 void *ptr;
3155
3156 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0);
3157 if (!ptr) {
Emeric Brun726783d2021-06-30 19:06:43 +02003158 /* fallback on the gpc array */
3159 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC, 0);
3160 }
3161
3162 if (!ptr) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003163 if (stkctr == &tmpstkctr)
3164 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003165 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003166 }
3167
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003168 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003169
Emeric Brun0e3457b2021-06-30 17:18:28 +02003170 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003171
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003172 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003173
3174 if (stkctr == &tmpstkctr)
3175 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003176 }
3177 return 1;
3178}
3179
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003180/* set <smp> to the General Purpose Counter 1 value from the stream's tracked
3181 * frontend counters or from the src.
3182 * Supports being called as "sc[0-9]_get_gpc1" or "src_get_gpc1" only. Value
3183 * zero is returned if the key is new.
3184 */
3185static int
3186smp_fetch_sc_get_gpc1(const struct arg *args, struct sample *smp, const char *kw, void *private)
3187{
3188 struct stkctr tmpstkctr;
3189 struct stkctr *stkctr;
3190
3191 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
3192 if (!stkctr)
3193 return 0;
3194
3195 smp->flags = SMP_F_VOL_TEST;
3196 smp->data.type = SMP_T_SINT;
3197 smp->data.u.sint = 0;
3198
3199 if (stkctr_entry(stkctr) != NULL) {
3200 void *ptr;
3201
3202 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1);
3203 if (!ptr) {
Emeric Brun726783d2021-06-30 19:06:43 +02003204 /* fallback on the gpc array */
3205 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC, 1);
3206 }
3207
3208 if (!ptr) {
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003209 if (stkctr == &tmpstkctr)
3210 stktable_release(stkctr->table, stkctr_entry(stkctr));
3211 return 0; /* parameter not stored */
3212 }
3213
3214 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3215
Emeric Brun0e3457b2021-06-30 17:18:28 +02003216 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003217
3218 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3219
3220 if (stkctr == &tmpstkctr)
3221 stktable_release(stkctr->table, stkctr_entry(stkctr));
3222 }
3223 return 1;
3224}
3225
Emeric Brun4d7ada82021-06-30 19:04:16 +02003226/* set <smp> to the GPC[args(0)]'s event rate from the stream's
3227 * tracked frontend counters or from the src.
3228 * Supports being called as "sc_gpc_rate(<gpc-idx>,<sc-idx>[,<table])"
3229 * or "src_gpc_rate(<gpc-idx>[,<table>])" only.
3230 * Value zero is returned if the key is new or gpc_rate is not stored.
3231 */
3232static int
3233smp_fetch_sc_gpc_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3234{
3235 struct stkctr tmpstkctr;
3236 struct stkctr *stkctr;
3237 unsigned int idx;
3238
3239 idx = args[0].data.sint;
3240
3241 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args + 1, kw, &tmpstkctr);
3242 if (!stkctr)
3243 return 0;
3244
3245 smp->flags = SMP_F_VOL_TEST;
3246 smp->data.type = SMP_T_SINT;
3247 smp->data.u.sint = 0;
3248 if (stkctr_entry(stkctr) != NULL) {
3249 void *ptr;
3250
3251 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC_RATE, idx);
3252 if (!ptr) {
3253 if (stkctr == &tmpstkctr)
3254 stktable_release(stkctr->table, stkctr_entry(stkctr));
3255 return 0; /* parameter not stored */
3256 }
3257
3258 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3259
3260 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
3261 stkctr->table->data_arg[STKTABLE_DT_GPC_RATE].u);
3262
3263 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3264
3265 if (stkctr == &tmpstkctr)
3266 stktable_release(stkctr->table, stkctr_entry(stkctr));
3267 }
3268 return 1;
3269}
3270
Willy Tarreau7d562212016-11-25 16:10:05 +01003271/* set <smp> to the General Purpose Counter 0's event rate from the stream's
3272 * tracked frontend counters or from the src.
3273 * Supports being called as "sc[0-9]_gpc0_rate" or "src_gpc0_rate" only.
3274 * Value zero is returned if the key is new.
3275 */
3276static int
3277smp_fetch_sc_gpc0_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3278{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003279 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003280 struct stkctr *stkctr;
Emeric Brun726783d2021-06-30 19:06:43 +02003281 unsigned int period;
Willy Tarreau7d562212016-11-25 16:10:05 +01003282
Emeric Brun819fc6f2017-06-13 19:37:32 +02003283 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003284 if (!stkctr)
3285 return 0;
3286
3287 smp->flags = SMP_F_VOL_TEST;
3288 smp->data.type = SMP_T_SINT;
3289 smp->data.u.sint = 0;
3290 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003291 void *ptr;
3292
3293 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0_RATE);
Emeric Brun726783d2021-06-30 19:06:43 +02003294 if (ptr) {
3295 period = stkctr->table->data_arg[STKTABLE_DT_GPC0_RATE].u;
3296 }
3297 else {
3298 /* fallback on the gpc array */
3299 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC_RATE, 0);
3300 if (ptr)
3301 period = stkctr->table->data_arg[STKTABLE_DT_GPC_RATE].u;
3302 }
3303
Emeric Brun819fc6f2017-06-13 19:37:32 +02003304 if (!ptr) {
3305 if (stkctr == &tmpstkctr)
3306 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003307 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003308 }
3309
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003310 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003311
Emeric Brun726783d2021-06-30 19:06:43 +02003312 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp), period);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003313
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003314 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003315
3316 if (stkctr == &tmpstkctr)
3317 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003318 }
3319 return 1;
3320}
3321
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003322/* set <smp> to the General Purpose Counter 1's event rate from the stream's
3323 * tracked frontend counters or from the src.
3324 * Supports being called as "sc[0-9]_gpc1_rate" or "src_gpc1_rate" only.
3325 * Value zero is returned if the key is new.
3326 */
3327static int
3328smp_fetch_sc_gpc1_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3329{
3330 struct stkctr tmpstkctr;
3331 struct stkctr *stkctr;
Emeric Brun726783d2021-06-30 19:06:43 +02003332 unsigned int period;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003333
3334 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
3335 if (!stkctr)
3336 return 0;
3337
3338 smp->flags = SMP_F_VOL_TEST;
3339 smp->data.type = SMP_T_SINT;
3340 smp->data.u.sint = 0;
3341 if (stkctr_entry(stkctr) != NULL) {
3342 void *ptr;
3343
3344 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1_RATE);
Emeric Brun726783d2021-06-30 19:06:43 +02003345 if (ptr) {
3346 period = stkctr->table->data_arg[STKTABLE_DT_GPC1_RATE].u;
3347 }
3348 else {
3349 /* fallback on the gpc array */
3350 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC_RATE, 1);
3351 if (ptr)
3352 period = stkctr->table->data_arg[STKTABLE_DT_GPC_RATE].u;
3353 }
3354
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003355 if (!ptr) {
3356 if (stkctr == &tmpstkctr)
3357 stktable_release(stkctr->table, stkctr_entry(stkctr));
3358 return 0; /* parameter not stored */
3359 }
3360
3361 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3362
Emeric Brun726783d2021-06-30 19:06:43 +02003363 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 +01003364
3365 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3366
3367 if (stkctr == &tmpstkctr)
3368 stktable_release(stkctr->table, stkctr_entry(stkctr));
3369 }
3370 return 1;
3371}
3372
Emeric Brun4d7ada82021-06-30 19:04:16 +02003373/* Increment the GPC[args(0)] value from the stream's tracked
3374 * frontend counters and return it into temp integer.
3375 * Supports being called as "sc_inc_gpc(<gpc-idx>,<sc-idx>[,<table>])"
3376 * or "src_inc_gpc(<gpc-idx>[,<table>])" only.
3377 */
3378static int
3379smp_fetch_sc_inc_gpc(const struct arg *args, struct sample *smp, const char *kw, void *private)
3380{
3381 struct stkctr tmpstkctr;
3382 struct stkctr *stkctr;
3383 unsigned int idx;
3384
3385 idx = args[0].data.sint;
3386
3387 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args + 1, kw, &tmpstkctr);
3388 if (!stkctr)
3389 return 0;
3390
3391 smp->flags = SMP_F_VOL_TEST;
3392 smp->data.type = SMP_T_SINT;
3393 smp->data.u.sint = 0;
3394
3395 if (!stkctr_entry(stkctr))
3396 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
3397
3398 if (stkctr && stkctr_entry(stkctr)) {
3399 void *ptr1,*ptr2;
3400
3401
3402 /* First, update gpc0_rate if it's tracked. Second, update its
3403 * gpc0 if tracked. Returns gpc0's value otherwise the curr_ctr.
3404 */
3405 ptr1 = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC_RATE, idx);
3406 ptr2 = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC, idx);
3407 if (ptr1 || ptr2) {
3408 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3409
3410 if (ptr1) {
3411 update_freq_ctr_period(&stktable_data_cast(ptr1, std_t_frqp),
3412 stkctr->table->data_arg[STKTABLE_DT_GPC_RATE].u, 1);
3413 smp->data.u.sint = (&stktable_data_cast(ptr1, std_t_frqp))->curr_ctr;
3414 }
3415
3416 if (ptr2)
3417 smp->data.u.sint = ++stktable_data_cast(ptr2, std_t_uint);
3418
3419 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3420
3421 /* If data was modified, we need to touch to re-schedule sync */
3422 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
3423 }
3424 else if (stkctr == &tmpstkctr)
3425 stktable_release(stkctr->table, stkctr_entry(stkctr));
3426 }
3427 return 1;
3428}
3429
Willy Tarreau7d562212016-11-25 16:10:05 +01003430/* Increment the General Purpose Counter 0 value from the stream's tracked
3431 * frontend counters and return it into temp integer.
3432 * Supports being called as "sc[0-9]_inc_gpc0" or "src_inc_gpc0" only.
3433 */
3434static int
3435smp_fetch_sc_inc_gpc0(const struct arg *args, struct sample *smp, const char *kw, void *private)
3436{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003437 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003438 struct stkctr *stkctr;
Willy Tarreau5b654ad2021-07-06 18:51:12 +02003439 unsigned int period = 0;
Willy Tarreau7d562212016-11-25 16:10:05 +01003440
Emeric Brun819fc6f2017-06-13 19:37:32 +02003441 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003442 if (!stkctr)
3443 return 0;
3444
3445 smp->flags = SMP_F_VOL_TEST;
3446 smp->data.type = SMP_T_SINT;
3447 smp->data.u.sint = 0;
3448
Emeric Brun819fc6f2017-06-13 19:37:32 +02003449 if (!stkctr_entry(stkctr))
3450 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003451
3452 if (stkctr && stkctr_entry(stkctr)) {
3453 void *ptr1,*ptr2;
3454
Emeric Brun819fc6f2017-06-13 19:37:32 +02003455
Willy Tarreau7d562212016-11-25 16:10:05 +01003456 /* First, update gpc0_rate if it's tracked. Second, update its
3457 * gpc0 if tracked. Returns gpc0's value otherwise the curr_ctr.
3458 */
3459 ptr1 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0_RATE);
Emeric Brun726783d2021-06-30 19:06:43 +02003460 if (ptr1) {
3461 period = stkctr->table->data_arg[STKTABLE_DT_GPC0_RATE].u;
3462 }
3463 else {
3464 /* fallback on the gpc array */
3465 ptr1 = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC_RATE, 0);
3466 if (ptr1)
3467 period = stkctr->table->data_arg[STKTABLE_DT_GPC_RATE].u;
3468 }
3469
Willy Tarreau7d562212016-11-25 16:10:05 +01003470 ptr2 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0);
Emeric Brun726783d2021-06-30 19:06:43 +02003471 if (!ptr2) {
3472 /* fallback on the gpc array */
3473 ptr2 = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC, 0);
3474 }
3475
Emeric Brun819fc6f2017-06-13 19:37:32 +02003476 if (ptr1 || ptr2) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003477 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Willy Tarreau7d562212016-11-25 16:10:05 +01003478
Emeric Brun819fc6f2017-06-13 19:37:32 +02003479 if (ptr1) {
Emeric Brun0e3457b2021-06-30 17:18:28 +02003480 update_freq_ctr_period(&stktable_data_cast(ptr1, std_t_frqp),
Emeric Brun726783d2021-06-30 19:06:43 +02003481 period, 1);
Emeric Brun0e3457b2021-06-30 17:18:28 +02003482 smp->data.u.sint = (&stktable_data_cast(ptr1, std_t_frqp))->curr_ctr;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003483 }
3484
3485 if (ptr2)
Emeric Brun0e3457b2021-06-30 17:18:28 +02003486 smp->data.u.sint = ++stktable_data_cast(ptr2, std_t_uint);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003487
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003488 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003489
3490 /* If data was modified, we need to touch to re-schedule sync */
3491 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
3492 }
3493 else if (stkctr == &tmpstkctr)
3494 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003495 }
3496 return 1;
3497}
3498
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003499/* Increment the General Purpose Counter 1 value from the stream's tracked
3500 * frontend counters and return it into temp integer.
3501 * Supports being called as "sc[0-9]_inc_gpc1" or "src_inc_gpc1" only.
3502 */
3503static int
3504smp_fetch_sc_inc_gpc1(const struct arg *args, struct sample *smp, const char *kw, void *private)
3505{
3506 struct stkctr tmpstkctr;
3507 struct stkctr *stkctr;
Willy Tarreau5b654ad2021-07-06 18:51:12 +02003508 unsigned int period = 0;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003509
3510 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
3511 if (!stkctr)
3512 return 0;
3513
3514 smp->flags = SMP_F_VOL_TEST;
3515 smp->data.type = SMP_T_SINT;
3516 smp->data.u.sint = 0;
3517
3518 if (!stkctr_entry(stkctr))
3519 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
3520
3521 if (stkctr && stkctr_entry(stkctr)) {
3522 void *ptr1,*ptr2;
3523
3524
3525 /* First, update gpc1_rate if it's tracked. Second, update its
3526 * gpc1 if tracked. Returns gpc1's value otherwise the curr_ctr.
3527 */
3528 ptr1 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1_RATE);
Emeric Brun726783d2021-06-30 19:06:43 +02003529 if (ptr1) {
3530 period = stkctr->table->data_arg[STKTABLE_DT_GPC1_RATE].u;
3531 }
3532 else {
3533 /* fallback on the gpc array */
3534 ptr1 = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC_RATE, 1);
3535 if (ptr1)
3536 period = stkctr->table->data_arg[STKTABLE_DT_GPC_RATE].u;
3537 }
3538
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003539 ptr2 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1);
Emeric Brun726783d2021-06-30 19:06:43 +02003540 if (!ptr2) {
3541 /* fallback on the gpc array */
3542 ptr2 = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC, 1);
3543 }
3544
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003545 if (ptr1 || ptr2) {
3546 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3547
3548 if (ptr1) {
Emeric Brun0e3457b2021-06-30 17:18:28 +02003549 update_freq_ctr_period(&stktable_data_cast(ptr1, std_t_frqp),
Emeric Brun726783d2021-06-30 19:06:43 +02003550 period, 1);
Emeric Brun0e3457b2021-06-30 17:18:28 +02003551 smp->data.u.sint = (&stktable_data_cast(ptr1, std_t_frqp))->curr_ctr;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003552 }
3553
3554 if (ptr2)
Emeric Brun0e3457b2021-06-30 17:18:28 +02003555 smp->data.u.sint = ++stktable_data_cast(ptr2, std_t_uint);
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003556
3557 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3558
3559 /* If data was modified, we need to touch to re-schedule sync */
3560 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
3561 }
3562 else if (stkctr == &tmpstkctr)
3563 stktable_release(stkctr->table, stkctr_entry(stkctr));
3564 }
3565 return 1;
3566}
3567
Emeric Brun4d7ada82021-06-30 19:04:16 +02003568/* Clear the GPC[args(0)] value from the stream's tracked
3569 * frontend counters and return its previous value into temp integer.
3570 * Supports being called as "sc_clr_gpc(<gpc-idx>,<sc-idx>[,<table>])"
3571 * or "src_clr_gpc(<gpc-idx>[,<table>])" only.
3572 */
3573static int
3574smp_fetch_sc_clr_gpc(const struct arg *args, struct sample *smp, const char *kw, void *private)
3575{
3576 struct stkctr tmpstkctr;
3577 struct stkctr *stkctr;
3578 unsigned int idx;
3579
3580 idx = args[0].data.sint;
3581
3582 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args + 1, kw, &tmpstkctr);
3583 if (!stkctr)
3584 return 0;
3585
3586 smp->flags = SMP_F_VOL_TEST;
3587 smp->data.type = SMP_T_SINT;
3588 smp->data.u.sint = 0;
3589
3590 if (!stkctr_entry(stkctr))
3591 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
3592
3593 if (stkctr && stkctr_entry(stkctr)) {
3594 void *ptr;
3595
3596 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC, idx);
3597 if (!ptr) {
3598 if (stkctr == &tmpstkctr)
3599 stktable_release(stkctr->table, stkctr_entry(stkctr));
3600 return 0; /* parameter not stored */
3601 }
3602
3603 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3604
3605 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
3606 stktable_data_cast(ptr, std_t_uint) = 0;
3607
3608 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3609
3610 /* If data was modified, we need to touch to re-schedule sync */
3611 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
3612 }
3613 return 1;
3614}
3615
Willy Tarreau7d562212016-11-25 16:10:05 +01003616/* Clear the General Purpose Counter 0 value from the stream's tracked
3617 * frontend counters and return its previous value into temp integer.
3618 * Supports being called as "sc[0-9]_clr_gpc0" or "src_clr_gpc0" only.
3619 */
3620static int
3621smp_fetch_sc_clr_gpc0(const struct arg *args, struct sample *smp, const char *kw, void *private)
3622{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003623 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003624 struct stkctr *stkctr;
3625
Emeric Brun819fc6f2017-06-13 19:37:32 +02003626 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003627 if (!stkctr)
3628 return 0;
3629
3630 smp->flags = SMP_F_VOL_TEST;
3631 smp->data.type = SMP_T_SINT;
3632 smp->data.u.sint = 0;
3633
Emeric Brun819fc6f2017-06-13 19:37:32 +02003634 if (!stkctr_entry(stkctr))
3635 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003636
Emeric Brun819fc6f2017-06-13 19:37:32 +02003637 if (stkctr && stkctr_entry(stkctr)) {
3638 void *ptr;
3639
3640 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0);
3641 if (!ptr) {
Emeric Brun726783d2021-06-30 19:06:43 +02003642 /* fallback on the gpc array */
3643 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC, 0);
3644 }
3645
3646 if (!ptr) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003647 if (stkctr == &tmpstkctr)
3648 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003649 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003650 }
3651
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003652 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003653
Emeric Brun0e3457b2021-06-30 17:18:28 +02003654 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
3655 stktable_data_cast(ptr, std_t_uint) = 0;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003656
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003657 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003658
Willy Tarreau7d562212016-11-25 16:10:05 +01003659 /* If data was modified, we need to touch to re-schedule sync */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003660 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
Willy Tarreau7d562212016-11-25 16:10:05 +01003661 }
3662 return 1;
3663}
3664
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003665/* Clear the General Purpose Counter 1 value from the stream's tracked
3666 * frontend counters and return its previous value into temp integer.
3667 * Supports being called as "sc[0-9]_clr_gpc1" or "src_clr_gpc1" only.
3668 */
3669static int
3670smp_fetch_sc_clr_gpc1(const struct arg *args, struct sample *smp, const char *kw, void *private)
3671{
3672 struct stkctr tmpstkctr;
3673 struct stkctr *stkctr;
3674
3675 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
3676 if (!stkctr)
3677 return 0;
3678
3679 smp->flags = SMP_F_VOL_TEST;
3680 smp->data.type = SMP_T_SINT;
3681 smp->data.u.sint = 0;
3682
3683 if (!stkctr_entry(stkctr))
3684 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
3685
3686 if (stkctr && stkctr_entry(stkctr)) {
3687 void *ptr;
3688
3689 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1);
3690 if (!ptr) {
Emeric Brun726783d2021-06-30 19:06:43 +02003691 /* fallback on the gpc array */
3692 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC, 1);
3693 }
3694
3695 if (!ptr) {
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003696 if (stkctr == &tmpstkctr)
3697 stktable_release(stkctr->table, stkctr_entry(stkctr));
3698 return 0; /* parameter not stored */
3699 }
3700
3701 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3702
Emeric Brun0e3457b2021-06-30 17:18:28 +02003703 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
3704 stktable_data_cast(ptr, std_t_uint) = 0;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003705
3706 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3707
3708 /* If data was modified, we need to touch to re-schedule sync */
3709 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
3710 }
3711 return 1;
3712}
3713
Willy Tarreau7d562212016-11-25 16:10:05 +01003714/* set <smp> to the cumulated number of connections from the stream's tracked
3715 * frontend counters. Supports being called as "sc[0-9]_conn_cnt" or
3716 * "src_conn_cnt" only.
3717 */
3718static int
3719smp_fetch_sc_conn_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
3720{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003721 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003722 struct stkctr *stkctr;
3723
Emeric Brun819fc6f2017-06-13 19:37:32 +02003724 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003725 if (!stkctr)
3726 return 0;
3727
3728 smp->flags = SMP_F_VOL_TEST;
3729 smp->data.type = SMP_T_SINT;
3730 smp->data.u.sint = 0;
3731 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003732 void *ptr;
3733
3734 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_CONN_CNT);
3735 if (!ptr) {
3736 if (stkctr == &tmpstkctr)
3737 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003738 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003739 }
3740
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003741 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003742
Emeric Brun0e3457b2021-06-30 17:18:28 +02003743 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003744
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003745 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003746
3747 if (stkctr == &tmpstkctr)
3748 stktable_release(stkctr->table, stkctr_entry(stkctr));
3749
3750
Willy Tarreau7d562212016-11-25 16:10:05 +01003751 }
3752 return 1;
3753}
3754
3755/* set <smp> to the connection rate from the stream's tracked frontend
3756 * counters. Supports being called as "sc[0-9]_conn_rate" or "src_conn_rate"
3757 * only.
3758 */
3759static int
3760smp_fetch_sc_conn_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3761{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003762 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003763 struct stkctr *stkctr;
3764
Emeric Brun819fc6f2017-06-13 19:37:32 +02003765 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003766 if (!stkctr)
3767 return 0;
3768
3769 smp->flags = SMP_F_VOL_TEST;
3770 smp->data.type = SMP_T_SINT;
3771 smp->data.u.sint = 0;
3772 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003773 void *ptr;
3774
3775 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_CONN_RATE);
3776 if (!ptr) {
3777 if (stkctr == &tmpstkctr)
3778 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003779 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003780 }
3781
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003782 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003783
Emeric Brun0e3457b2021-06-30 17:18:28 +02003784 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Willy Tarreau7d562212016-11-25 16:10:05 +01003785 stkctr->table->data_arg[STKTABLE_DT_CONN_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003786
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003787 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003788
3789 if (stkctr == &tmpstkctr)
3790 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003791 }
3792 return 1;
3793}
3794
3795/* set temp integer to the number of connections from the stream's source address
3796 * in the table pointed to by expr, after updating it.
3797 * Accepts exactly 1 argument of type table.
3798 */
3799static int
3800smp_fetch_src_updt_conn_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
3801{
3802 struct connection *conn = objt_conn(smp->sess->origin);
3803 struct stksess *ts;
3804 struct stktable_key *key;
3805 void *ptr;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003806 struct stktable *t;
Willy Tarreau7d562212016-11-25 16:10:05 +01003807
3808 if (!conn)
3809 return 0;
3810
Joseph Herlant5662fa42018-11-15 13:43:28 -08003811 /* Fetch source address in a sample. */
Amaury Denoyellec460c702021-05-12 10:17:47 +02003812 if (!smp_fetch_src || !smp_fetch_src(empty_arg_list, smp, "src", NULL))
Willy Tarreau7d562212016-11-25 16:10:05 +01003813 return 0;
3814
3815 /* Converts into key. */
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003816 key = smp_to_stkey(smp, args->data.t);
Willy Tarreau7d562212016-11-25 16:10:05 +01003817 if (!key)
3818 return 0;
3819
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003820 t = args->data.t;
Willy Tarreau7d562212016-11-25 16:10:05 +01003821
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003822 if ((ts = stktable_get_entry(t, key)) == NULL)
Willy Tarreau7d562212016-11-25 16:10:05 +01003823 /* entry does not exist and could not be created */
3824 return 0;
3825
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003826 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_CONN_CNT);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003827 if (!ptr) {
Willy Tarreau7d562212016-11-25 16:10:05 +01003828 return 0; /* parameter not stored in this table */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003829 }
Willy Tarreau7d562212016-11-25 16:10:05 +01003830
3831 smp->data.type = SMP_T_SINT;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003832
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003833 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003834
Emeric Brun0e3457b2021-06-30 17:18:28 +02003835 smp->data.u.sint = ++stktable_data_cast(ptr, std_t_uint);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003836
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003837 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003838
Willy Tarreau7d562212016-11-25 16:10:05 +01003839 smp->flags = SMP_F_VOL_TEST;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003840
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003841 stktable_touch_local(t, ts, 1);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003842
3843 /* Touch was previously performed by stktable_update_key */
Willy Tarreau7d562212016-11-25 16:10:05 +01003844 return 1;
3845}
3846
3847/* set <smp> to the number of concurrent connections from the stream's tracked
3848 * frontend counters. Supports being called as "sc[0-9]_conn_cur" or
3849 * "src_conn_cur" only.
3850 */
3851static int
3852smp_fetch_sc_conn_cur(const struct arg *args, struct sample *smp, const char *kw, void *private)
3853{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003854 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003855 struct stkctr *stkctr;
3856
Emeric Brun819fc6f2017-06-13 19:37:32 +02003857 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003858 if (!stkctr)
3859 return 0;
3860
3861 smp->flags = SMP_F_VOL_TEST;
3862 smp->data.type = SMP_T_SINT;
3863 smp->data.u.sint = 0;
3864 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003865 void *ptr;
3866
3867 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_CONN_CUR);
3868 if (!ptr) {
3869 if (stkctr == &tmpstkctr)
3870 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003871 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003872 }
3873
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003874 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003875
Emeric Brun0e3457b2021-06-30 17:18:28 +02003876 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003877
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003878 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003879
3880 if (stkctr == &tmpstkctr)
3881 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003882 }
3883 return 1;
3884}
3885
3886/* set <smp> to the cumulated number of streams from the stream's tracked
3887 * frontend counters. Supports being called as "sc[0-9]_sess_cnt" or
3888 * "src_sess_cnt" only.
3889 */
3890static int
3891smp_fetch_sc_sess_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
3892{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003893 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003894 struct stkctr *stkctr;
3895
Emeric Brun819fc6f2017-06-13 19:37:32 +02003896 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003897 if (!stkctr)
3898 return 0;
3899
3900 smp->flags = SMP_F_VOL_TEST;
3901 smp->data.type = SMP_T_SINT;
3902 smp->data.u.sint = 0;
3903 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003904 void *ptr;
3905
3906 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_SESS_CNT);
3907 if (!ptr) {
3908 if (stkctr == &tmpstkctr)
3909 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003910 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003911 }
3912
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003913 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003914
Emeric Brun0e3457b2021-06-30 17:18:28 +02003915 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003916
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003917 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003918
3919 if (stkctr == &tmpstkctr)
3920 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003921 }
3922 return 1;
3923}
3924
3925/* set <smp> to the stream rate from the stream's tracked frontend counters.
3926 * Supports being called as "sc[0-9]_sess_rate" or "src_sess_rate" only.
3927 */
3928static int
3929smp_fetch_sc_sess_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3930{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003931 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003932 struct stkctr *stkctr;
3933
Emeric Brun819fc6f2017-06-13 19:37:32 +02003934 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003935 if (!stkctr)
3936 return 0;
3937
3938 smp->flags = SMP_F_VOL_TEST;
3939 smp->data.type = SMP_T_SINT;
3940 smp->data.u.sint = 0;
3941 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003942 void *ptr;
3943
3944 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_SESS_RATE);
3945 if (!ptr) {
3946 if (stkctr == &tmpstkctr)
3947 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003948 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003949 }
3950
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003951 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003952
Emeric Brun0e3457b2021-06-30 17:18:28 +02003953 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Willy Tarreau7d562212016-11-25 16:10:05 +01003954 stkctr->table->data_arg[STKTABLE_DT_SESS_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003955
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003956 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003957
3958 if (stkctr == &tmpstkctr)
3959 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003960 }
3961 return 1;
3962}
3963
3964/* set <smp> to the cumulated number of HTTP requests from the stream's tracked
3965 * frontend counters. Supports being called as "sc[0-9]_http_req_cnt" or
3966 * "src_http_req_cnt" only.
3967 */
3968static int
3969smp_fetch_sc_http_req_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
3970{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003971 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003972 struct stkctr *stkctr;
3973
Emeric Brun819fc6f2017-06-13 19:37:32 +02003974 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003975 if (!stkctr)
3976 return 0;
3977
3978 smp->flags = SMP_F_VOL_TEST;
3979 smp->data.type = SMP_T_SINT;
3980 smp->data.u.sint = 0;
3981 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003982 void *ptr;
3983
3984 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_REQ_CNT);
3985 if (!ptr) {
3986 if (stkctr == &tmpstkctr)
3987 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003988 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003989 }
3990
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003991 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003992
Emeric Brun0e3457b2021-06-30 17:18:28 +02003993 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003994
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003995 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003996
3997 if (stkctr == &tmpstkctr)
3998 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003999 }
4000 return 1;
4001}
4002
4003/* set <smp> to the HTTP request rate from the stream's tracked frontend
4004 * counters. Supports being called as "sc[0-9]_http_req_rate" or
4005 * "src_http_req_rate" only.
4006 */
4007static int
4008smp_fetch_sc_http_req_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
4009{
Emeric Brun819fc6f2017-06-13 19:37:32 +02004010 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01004011 struct stkctr *stkctr;
4012
Emeric Brun819fc6f2017-06-13 19:37:32 +02004013 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01004014 if (!stkctr)
4015 return 0;
4016
4017 smp->flags = SMP_F_VOL_TEST;
4018 smp->data.type = SMP_T_SINT;
4019 smp->data.u.sint = 0;
4020 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02004021 void *ptr;
4022
4023 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_REQ_RATE);
4024 if (!ptr) {
4025 if (stkctr == &tmpstkctr)
4026 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004027 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02004028 }
4029
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004030 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004031
Emeric Brun0e3457b2021-06-30 17:18:28 +02004032 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Willy Tarreau7d562212016-11-25 16:10:05 +01004033 stkctr->table->data_arg[STKTABLE_DT_HTTP_REQ_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004034
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004035 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004036
4037 if (stkctr == &tmpstkctr)
4038 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004039 }
4040 return 1;
4041}
4042
4043/* set <smp> to the cumulated number of HTTP requests errors from the stream's
4044 * tracked frontend counters. Supports being called as "sc[0-9]_http_err_cnt" or
4045 * "src_http_err_cnt" only.
4046 */
4047static int
4048smp_fetch_sc_http_err_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
4049{
Emeric Brun819fc6f2017-06-13 19:37:32 +02004050 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01004051 struct stkctr *stkctr;
4052
Emeric Brun819fc6f2017-06-13 19:37:32 +02004053 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01004054 if (!stkctr)
4055 return 0;
4056
4057 smp->flags = SMP_F_VOL_TEST;
4058 smp->data.type = SMP_T_SINT;
4059 smp->data.u.sint = 0;
4060 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02004061 void *ptr;
4062
4063 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_ERR_CNT);
4064 if (!ptr) {
4065 if (stkctr == &tmpstkctr)
4066 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004067 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02004068 }
4069
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004070 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004071
Emeric Brun0e3457b2021-06-30 17:18:28 +02004072 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004073
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004074 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004075
4076 if (stkctr == &tmpstkctr)
4077 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004078 }
4079 return 1;
4080}
4081
4082/* set <smp> to the HTTP request error rate from the stream's tracked frontend
4083 * counters. Supports being called as "sc[0-9]_http_err_rate" or
4084 * "src_http_err_rate" only.
4085 */
4086static int
4087smp_fetch_sc_http_err_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
4088{
Emeric Brun819fc6f2017-06-13 19:37:32 +02004089 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01004090 struct stkctr *stkctr;
4091
Emeric Brun819fc6f2017-06-13 19:37:32 +02004092 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01004093 if (!stkctr)
4094 return 0;
4095
4096 smp->flags = SMP_F_VOL_TEST;
4097 smp->data.type = SMP_T_SINT;
4098 smp->data.u.sint = 0;
4099 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02004100 void *ptr;
4101
4102 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_ERR_RATE);
4103 if (!ptr) {
4104 if (stkctr == &tmpstkctr)
4105 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004106 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02004107 }
4108
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004109 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004110
Emeric Brun0e3457b2021-06-30 17:18:28 +02004111 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Willy Tarreau7d562212016-11-25 16:10:05 +01004112 stkctr->table->data_arg[STKTABLE_DT_HTTP_ERR_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004113
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004114 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004115
4116 if (stkctr == &tmpstkctr)
4117 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004118 }
4119 return 1;
4120}
4121
Willy Tarreau826f3ab2021-02-10 12:07:15 +01004122/* set <smp> to the cumulated number of HTTP response failures from the stream's
4123 * tracked frontend counters. Supports being called as "sc[0-9]_http_fail_cnt" or
4124 * "src_http_fail_cnt" only.
4125 */
4126static int
4127smp_fetch_sc_http_fail_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
4128{
4129 struct stkctr tmpstkctr;
4130 struct stkctr *stkctr;
4131
4132 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
4133 if (!stkctr)
4134 return 0;
4135
4136 smp->flags = SMP_F_VOL_TEST;
4137 smp->data.type = SMP_T_SINT;
4138 smp->data.u.sint = 0;
4139 if (stkctr_entry(stkctr) != NULL) {
4140 void *ptr;
4141
4142 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_FAIL_CNT);
4143 if (!ptr) {
4144 if (stkctr == &tmpstkctr)
4145 stktable_release(stkctr->table, stkctr_entry(stkctr));
4146 return 0; /* parameter not stored */
4147 }
4148
4149 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
4150
Emeric Brun0e3457b2021-06-30 17:18:28 +02004151 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Willy Tarreau826f3ab2021-02-10 12:07:15 +01004152
4153 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
4154
4155 if (stkctr == &tmpstkctr)
4156 stktable_release(stkctr->table, stkctr_entry(stkctr));
4157 }
4158 return 1;
4159}
4160
4161/* set <smp> to the HTTP response failure rate from the stream's tracked frontend
4162 * counters. Supports being called as "sc[0-9]_http_fail_rate" or
4163 * "src_http_fail_rate" only.
4164 */
4165static int
4166smp_fetch_sc_http_fail_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
4167{
4168 struct stkctr tmpstkctr;
4169 struct stkctr *stkctr;
4170
4171 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
4172 if (!stkctr)
4173 return 0;
4174
4175 smp->flags = SMP_F_VOL_TEST;
4176 smp->data.type = SMP_T_SINT;
4177 smp->data.u.sint = 0;
4178 if (stkctr_entry(stkctr) != NULL) {
4179 void *ptr;
4180
4181 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_FAIL_RATE);
4182 if (!ptr) {
4183 if (stkctr == &tmpstkctr)
4184 stktable_release(stkctr->table, stkctr_entry(stkctr));
4185 return 0; /* parameter not stored */
4186 }
4187
4188 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
4189
Emeric Brun0e3457b2021-06-30 17:18:28 +02004190 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Willy Tarreau826f3ab2021-02-10 12:07:15 +01004191 stkctr->table->data_arg[STKTABLE_DT_HTTP_FAIL_RATE].u);
4192
4193 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
4194
4195 if (stkctr == &tmpstkctr)
4196 stktable_release(stkctr->table, stkctr_entry(stkctr));
4197 }
4198 return 1;
4199}
4200
Willy Tarreau7d562212016-11-25 16:10:05 +01004201/* set <smp> to the number of kbytes received from clients, as found in the
4202 * stream's tracked frontend counters. Supports being called as
4203 * "sc[0-9]_kbytes_in" or "src_kbytes_in" only.
4204 */
4205static int
4206smp_fetch_sc_kbytes_in(const struct arg *args, struct sample *smp, const char *kw, void *private)
4207{
Emeric Brun819fc6f2017-06-13 19:37:32 +02004208 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01004209 struct stkctr *stkctr;
4210
Emeric Brun819fc6f2017-06-13 19:37:32 +02004211 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01004212 if (!stkctr)
4213 return 0;
4214
4215 smp->flags = SMP_F_VOL_TEST;
4216 smp->data.type = SMP_T_SINT;
4217 smp->data.u.sint = 0;
4218 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02004219 void *ptr;
4220
4221 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_IN_CNT);
4222 if (!ptr) {
4223 if (stkctr == &tmpstkctr)
4224 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004225 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02004226 }
4227
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004228 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004229
Emeric Brun0e3457b2021-06-30 17:18:28 +02004230 smp->data.u.sint = stktable_data_cast(ptr, std_t_ull) >> 10;
Emeric Brun819fc6f2017-06-13 19:37:32 +02004231
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004232 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004233
4234 if (stkctr == &tmpstkctr)
4235 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004236 }
4237 return 1;
4238}
4239
4240/* set <smp> to the data rate received from clients in bytes/s, as found
4241 * in the stream's tracked frontend counters. Supports being called as
4242 * "sc[0-9]_bytes_in_rate" or "src_bytes_in_rate" only.
4243 */
4244static int
4245smp_fetch_sc_bytes_in_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
4246{
Emeric Brun819fc6f2017-06-13 19:37:32 +02004247 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01004248 struct stkctr *stkctr;
4249
Emeric Brun819fc6f2017-06-13 19:37:32 +02004250 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01004251 if (!stkctr)
4252 return 0;
4253
4254 smp->flags = SMP_F_VOL_TEST;
4255 smp->data.type = SMP_T_SINT;
4256 smp->data.u.sint = 0;
4257 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02004258 void *ptr;
4259
4260 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_IN_RATE);
4261 if (!ptr) {
4262 if (stkctr == &tmpstkctr)
4263 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004264 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02004265 }
4266
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004267 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004268
Emeric Brun0e3457b2021-06-30 17:18:28 +02004269 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Willy Tarreau7d562212016-11-25 16:10:05 +01004270 stkctr->table->data_arg[STKTABLE_DT_BYTES_IN_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004271
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004272 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004273
4274 if (stkctr == &tmpstkctr)
4275 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004276 }
4277 return 1;
4278}
4279
4280/* set <smp> to the number of kbytes sent to clients, as found in the
4281 * stream's tracked frontend counters. Supports being called as
4282 * "sc[0-9]_kbytes_out" or "src_kbytes_out" only.
4283 */
4284static int
4285smp_fetch_sc_kbytes_out(const struct arg *args, struct sample *smp, const char *kw, void *private)
4286{
Emeric Brun819fc6f2017-06-13 19:37:32 +02004287 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01004288 struct stkctr *stkctr;
4289
Emeric Brun819fc6f2017-06-13 19:37:32 +02004290 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01004291 if (!stkctr)
4292 return 0;
4293
4294 smp->flags = SMP_F_VOL_TEST;
4295 smp->data.type = SMP_T_SINT;
4296 smp->data.u.sint = 0;
4297 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02004298 void *ptr;
4299
4300 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_OUT_CNT);
4301 if (!ptr) {
4302 if (stkctr == &tmpstkctr)
4303 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004304 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02004305 }
4306
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004307 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004308
Emeric Brun0e3457b2021-06-30 17:18:28 +02004309 smp->data.u.sint = stktable_data_cast(ptr, std_t_ull) >> 10;
Emeric Brun819fc6f2017-06-13 19:37:32 +02004310
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004311 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004312
4313 if (stkctr == &tmpstkctr)
4314 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004315 }
4316 return 1;
4317}
4318
4319/* set <smp> to the data rate sent to clients in bytes/s, as found in the
4320 * stream's tracked frontend counters. Supports being called as
4321 * "sc[0-9]_bytes_out_rate" or "src_bytes_out_rate" only.
4322 */
4323static int
4324smp_fetch_sc_bytes_out_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
4325{
Emeric Brun819fc6f2017-06-13 19:37:32 +02004326 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01004327 struct stkctr *stkctr;
4328
Emeric Brun819fc6f2017-06-13 19:37:32 +02004329 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01004330 if (!stkctr)
4331 return 0;
4332
4333 smp->flags = SMP_F_VOL_TEST;
4334 smp->data.type = SMP_T_SINT;
4335 smp->data.u.sint = 0;
4336 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02004337 void *ptr;
4338
4339 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_OUT_RATE);
4340 if (!ptr) {
4341 if (stkctr == &tmpstkctr)
4342 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004343 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02004344 }
4345
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004346 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004347
Emeric Brun0e3457b2021-06-30 17:18:28 +02004348 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Willy Tarreau7d562212016-11-25 16:10:05 +01004349 stkctr->table->data_arg[STKTABLE_DT_BYTES_OUT_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004350
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004351 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004352
4353 if (stkctr == &tmpstkctr)
4354 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004355 }
4356 return 1;
4357}
4358
4359/* set <smp> to the number of active trackers on the SC entry in the stream's
4360 * tracked frontend counters. Supports being called as "sc[0-9]_trackers" only.
4361 */
4362static int
4363smp_fetch_sc_trackers(const struct arg *args, struct sample *smp, const char *kw, void *private)
4364{
Emeric Brun819fc6f2017-06-13 19:37:32 +02004365 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01004366 struct stkctr *stkctr;
4367
Emeric Brun819fc6f2017-06-13 19:37:32 +02004368 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01004369 if (!stkctr)
4370 return 0;
4371
4372 smp->flags = SMP_F_VOL_TEST;
4373 smp->data.type = SMP_T_SINT;
Emeric Brun819fc6f2017-06-13 19:37:32 +02004374 if (stkctr == &tmpstkctr) {
4375 smp->data.u.sint = stkctr_entry(stkctr) ? (stkctr_entry(stkctr)->ref_cnt-1) : 0;
4376 stktable_release(stkctr->table, stkctr_entry(stkctr));
4377 }
4378 else {
4379 smp->data.u.sint = stkctr_entry(stkctr) ? stkctr_entry(stkctr)->ref_cnt : 0;
4380 }
4381
Willy Tarreau7d562212016-11-25 16:10:05 +01004382 return 1;
4383}
4384
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004385
4386/* The functions below are used to manipulate table contents from the CLI.
4387 * There are 3 main actions, "clear", "set" and "show". The code is shared
4388 * between all actions, and the action is encoded in the void *private in
4389 * the appctx as well as in the keyword registration, among one of the
4390 * following values.
4391 */
4392
4393enum {
4394 STK_CLI_ACT_CLR,
4395 STK_CLI_ACT_SET,
4396 STK_CLI_ACT_SHOW,
4397};
4398
Willy Tarreau4596fe22022-05-17 19:07:51 +02004399/* Dump the status of a table to a stream connector's
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004400 * read buffer. It returns 0 if the output buffer is full
4401 * and needs to be called again, otherwise non-zero.
4402 */
Willy Tarreau83061a82018-07-13 11:56:34 +02004403static int table_dump_head_to_buffer(struct buffer *msg,
Willy Tarreaud0a06d52022-05-18 15:07:19 +02004404 struct appctx *appctx,
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004405 struct stktable *t, struct stktable *target)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004406{
Willy Tarreauc12b3212022-05-27 11:08:15 +02004407 struct stream *s = __sc_strm(appctx_sc(appctx));
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004408
4409 chunk_appendf(msg, "# table: %s, type: %s, size:%d, used:%d\n",
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004410 t->id, stktable_types[t->type].kw, t->size, t->current);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004411
4412 /* any other information should be dumped here */
4413
William Lallemand07a62f72017-05-24 00:57:40 +02004414 if (target && (strm_li(s)->bind_conf->level & ACCESS_LVL_MASK) < ACCESS_LVL_OPER)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004415 chunk_appendf(msg, "# contents not dumped due to insufficient privileges\n");
4416
Willy Tarreaud0a06d52022-05-18 15:07:19 +02004417 if (applet_putchk(appctx, msg) == -1)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004418 return 0;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004419
4420 return 1;
4421}
4422
Willy Tarreau4596fe22022-05-17 19:07:51 +02004423/* Dump a table entry to a stream connector's
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004424 * read buffer. It returns 0 if the output buffer is full
4425 * and needs to be called again, otherwise non-zero.
4426 */
Willy Tarreau83061a82018-07-13 11:56:34 +02004427static int table_dump_entry_to_buffer(struct buffer *msg,
Willy Tarreaud0a06d52022-05-18 15:07:19 +02004428 struct appctx *appctx,
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004429 struct stktable *t, struct stksess *entry)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004430{
4431 int dt;
4432
4433 chunk_appendf(msg, "%p:", entry);
4434
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004435 if (t->type == SMP_T_IPV4) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004436 char addr[INET_ADDRSTRLEN];
4437 inet_ntop(AF_INET, (const void *)&entry->key.key, addr, sizeof(addr));
4438 chunk_appendf(msg, " key=%s", addr);
4439 }
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004440 else if (t->type == SMP_T_IPV6) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004441 char addr[INET6_ADDRSTRLEN];
4442 inet_ntop(AF_INET6, (const void *)&entry->key.key, addr, sizeof(addr));
4443 chunk_appendf(msg, " key=%s", addr);
4444 }
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004445 else if (t->type == SMP_T_SINT) {
Willy Tarreau6cde5d82020-02-25 09:41:22 +01004446 chunk_appendf(msg, " key=%u", read_u32(entry->key.key));
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004447 }
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004448 else if (t->type == SMP_T_STR) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004449 chunk_appendf(msg, " key=");
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004450 dump_text(msg, (const char *)entry->key.key, t->key_size);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004451 }
4452 else {
4453 chunk_appendf(msg, " key=");
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004454 dump_binary(msg, (const char *)entry->key.key, t->key_size);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004455 }
4456
Willy Tarreau16b282f2022-11-29 11:55:18 +01004457 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 +01004458
4459 for (dt = 0; dt < STKTABLE_DATA_TYPES; dt++) {
4460 void *ptr;
4461
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004462 if (t->data_ofs[dt] == 0)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004463 continue;
Emeric Brunc64a2a32021-06-30 18:01:02 +02004464 if (stktable_data_types[dt].is_array) {
4465 char tmp[16] = {};
4466 const char *name_pfx = stktable_data_types[dt].name;
4467 const char *name_sfx = NULL;
4468 unsigned int idx = 0;
4469 int i = 0;
4470
4471 /* split name to show index before first _ of the name
4472 * for example: 'gpc3_rate' if array name is 'gpc_rate'.
4473 */
4474 for (i = 0 ; i < (sizeof(tmp) - 1); i++) {
4475 if (!name_pfx[i])
4476 break;
4477 if (name_pfx[i] == '_') {
4478 name_pfx = &tmp[0];
4479 name_sfx = &stktable_data_types[dt].name[i];
4480 break;
4481 }
4482 tmp[i] = name_pfx[i];
4483 }
4484
4485 ptr = stktable_data_ptr_idx(t, entry, dt, idx);
4486 while (ptr) {
4487 if (stktable_data_types[dt].arg_type == ARG_T_DELAY)
4488 chunk_appendf(msg, " %s%u%s(%u)=", name_pfx, idx, name_sfx ? name_sfx : "", t->data_arg[dt].u);
4489 else
4490 chunk_appendf(msg, " %s%u%s=", name_pfx, idx, name_sfx ? name_sfx : "");
4491 switch (stktable_data_types[dt].std_type) {
4492 case STD_T_SINT:
4493 chunk_appendf(msg, "%d", stktable_data_cast(ptr, std_t_sint));
4494 break;
4495 case STD_T_UINT:
4496 chunk_appendf(msg, "%u", stktable_data_cast(ptr, std_t_uint));
4497 break;
4498 case STD_T_ULL:
4499 chunk_appendf(msg, "%llu", stktable_data_cast(ptr, std_t_ull));
4500 break;
4501 case STD_T_FRQP:
4502 chunk_appendf(msg, "%u",
4503 read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
4504 t->data_arg[dt].u));
4505 break;
4506 }
4507 ptr = stktable_data_ptr_idx(t, entry, dt, ++idx);
4508 }
4509 continue;
4510 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004511 if (stktable_data_types[dt].arg_type == ARG_T_DELAY)
Emeric Brun01928ae2021-06-30 16:24:04 +02004512 chunk_appendf(msg, " %s(%u)=", stktable_data_types[dt].name, t->data_arg[dt].u);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004513 else
4514 chunk_appendf(msg, " %s=", stktable_data_types[dt].name);
4515
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004516 ptr = stktable_data_ptr(t, entry, dt);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004517 switch (stktable_data_types[dt].std_type) {
4518 case STD_T_SINT:
4519 chunk_appendf(msg, "%d", stktable_data_cast(ptr, std_t_sint));
4520 break;
4521 case STD_T_UINT:
4522 chunk_appendf(msg, "%u", stktable_data_cast(ptr, std_t_uint));
4523 break;
4524 case STD_T_ULL:
Emeric Brun01928ae2021-06-30 16:24:04 +02004525 chunk_appendf(msg, "%llu", stktable_data_cast(ptr, std_t_ull));
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004526 break;
4527 case STD_T_FRQP:
Emeric Brun01928ae2021-06-30 16:24:04 +02004528 chunk_appendf(msg, "%u",
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004529 read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004530 t->data_arg[dt].u));
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004531 break;
Frédéric Lécaille16b4f542019-05-23 12:15:04 +02004532 case STD_T_DICT: {
4533 struct dict_entry *de;
4534 de = stktable_data_cast(ptr, std_t_dict);
4535 chunk_appendf(msg, "%s", de ? (char *)de->value.key : "-");
4536 break;
4537 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004538 }
4539 }
4540 chunk_appendf(msg, "\n");
4541
Willy Tarreaud0a06d52022-05-18 15:07:19 +02004542 if (applet_putchk(appctx, msg) == -1)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004543 return 0;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004544
4545 return 1;
4546}
4547
Willy Tarreau3c69e082022-05-03 11:35:07 +02004548/* appctx context used by the "show table" command */
4549struct show_table_ctx {
4550 void *target; /* table we want to dump, or NULL for all */
4551 struct stktable *t; /* table being currently dumped (first if NULL) */
4552 struct stksess *entry; /* last entry we were trying to dump (or first if NULL) */
4553 long long value[STKTABLE_FILTER_LEN]; /* value to compare against */
4554 signed char data_type[STKTABLE_FILTER_LEN]; /* type of data to compare, or -1 if none */
4555 signed char data_op[STKTABLE_FILTER_LEN]; /* operator (STD_OP_*) when data_type set */
Willy Tarreau7849d4c2022-05-03 11:45:02 +02004556 enum {
Willy Tarreau0f154ed2022-05-03 12:02:36 +02004557 STATE_NEXT = 0, /* px points to next table, entry=NULL */
Willy Tarreau7849d4c2022-05-03 11:45:02 +02004558 STATE_DUMP, /* px points to curr table, entry is valid, refcount held */
4559 STATE_DONE, /* done dumping */
4560 } state;
Willy Tarreau3c69e082022-05-03 11:35:07 +02004561 char action; /* action on the table : one of STK_CLI_ACT_* */
4562};
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004563
4564/* Processes a single table entry matching a specific key passed in argument.
4565 * returns 0 if wants to be called again, 1 if has ended processing.
4566 */
4567static int table_process_entry_per_key(struct appctx *appctx, char **args)
4568{
Willy Tarreau3c69e082022-05-03 11:35:07 +02004569 struct show_table_ctx *ctx = appctx->svcctx;
4570 struct stktable *t = ctx->target;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004571 struct stksess *ts;
4572 uint32_t uint32_key;
4573 unsigned char ip6_key[sizeof(struct in6_addr)];
4574 long long value;
4575 int data_type;
4576 int cur_arg;
4577 void *ptr;
Willy Tarreaufa1258f2021-04-10 23:00:53 +02004578 struct freq_ctr *frqp;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004579
Willy Tarreau9d008692019-08-09 11:21:01 +02004580 if (!*args[4])
4581 return cli_err(appctx, "Key value expected\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004582
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004583 switch (t->type) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004584 case SMP_T_IPV4:
4585 uint32_key = htonl(inetaddr_host(args[4]));
Christopher Fauletca20d022017-08-29 15:30:31 +02004586 static_table_key.key = &uint32_key;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004587 break;
4588 case SMP_T_IPV6:
Christopher Fauletb7c962b2021-11-15 09:17:25 +01004589 if (inet_pton(AF_INET6, args[4], ip6_key) <= 0)
4590 return cli_err(appctx, "Invalid key\n");
Christopher Fauletca20d022017-08-29 15:30:31 +02004591 static_table_key.key = &ip6_key;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004592 break;
4593 case SMP_T_SINT:
4594 {
4595 char *endptr;
4596 unsigned long val;
4597 errno = 0;
4598 val = strtoul(args[4], &endptr, 10);
4599 if ((errno == ERANGE && val == ULONG_MAX) ||
4600 (errno != 0 && val == 0) || endptr == args[4] ||
Willy Tarreau9d008692019-08-09 11:21:01 +02004601 val > 0xffffffff)
4602 return cli_err(appctx, "Invalid key\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004603 uint32_key = (uint32_t) val;
Christopher Fauletca20d022017-08-29 15:30:31 +02004604 static_table_key.key = &uint32_key;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004605 break;
4606 }
4607 break;
4608 case SMP_T_STR:
Christopher Fauletca20d022017-08-29 15:30:31 +02004609 static_table_key.key = args[4];
4610 static_table_key.key_len = strlen(args[4]);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004611 break;
4612 default:
Willy Tarreau3c69e082022-05-03 11:35:07 +02004613 switch (ctx->action) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004614 case STK_CLI_ACT_SHOW:
Willy Tarreau9d008692019-08-09 11:21:01 +02004615 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 +01004616 case STK_CLI_ACT_CLR:
Willy Tarreau9d008692019-08-09 11:21:01 +02004617 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 +01004618 case STK_CLI_ACT_SET:
Willy Tarreau9d008692019-08-09 11:21:01 +02004619 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 +01004620 default:
Willy Tarreau9d008692019-08-09 11:21:01 +02004621 return cli_err(appctx, "Unknown action\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004622 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004623 }
4624
4625 /* check permissions */
4626 if (!cli_has_level(appctx, ACCESS_LVL_OPER))
4627 return 1;
4628
Willy Tarreau3c69e082022-05-03 11:35:07 +02004629 switch (ctx->action) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004630 case STK_CLI_ACT_SHOW:
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004631 ts = stktable_lookup_key(t, &static_table_key);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004632 if (!ts)
4633 return 1;
4634 chunk_reset(&trash);
Willy Tarreaud0a06d52022-05-18 15:07:19 +02004635 if (!table_dump_head_to_buffer(&trash, appctx, t, t)) {
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004636 stktable_release(t, ts);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004637 return 0;
Emeric Brun819fc6f2017-06-13 19:37:32 +02004638 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004639 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &ts->lock);
Willy Tarreaud0a06d52022-05-18 15:07:19 +02004640 if (!table_dump_entry_to_buffer(&trash, appctx, t, ts)) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004641 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004642 stktable_release(t, ts);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004643 return 0;
Emeric Brun819fc6f2017-06-13 19:37:32 +02004644 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004645 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004646 stktable_release(t, ts);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004647 break;
4648
4649 case STK_CLI_ACT_CLR:
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004650 ts = stktable_lookup_key(t, &static_table_key);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004651 if (!ts)
4652 return 1;
Emeric Brun819fc6f2017-06-13 19:37:32 +02004653
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004654 if (!stksess_kill(t, ts, 1)) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004655 /* don't delete an entry which is currently referenced */
Willy Tarreau9d008692019-08-09 11:21:01 +02004656 return cli_err(appctx, "Entry currently in use, cannot remove\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004657 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004658 break;
4659
4660 case STK_CLI_ACT_SET:
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004661 ts = stktable_get_entry(t, &static_table_key);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004662 if (!ts) {
4663 /* don't delete an entry which is currently referenced */
Willy Tarreau9d008692019-08-09 11:21:01 +02004664 return cli_err(appctx, "Unable to allocate a new entry\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004665 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004666 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004667 for (cur_arg = 5; *args[cur_arg]; cur_arg += 2) {
4668 if (strncmp(args[cur_arg], "data.", 5) != 0) {
Willy Tarreau9d008692019-08-09 11:21:01 +02004669 cli_err(appctx, "\"data.<type>\" followed by a value expected\n");
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004670 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004671 stktable_touch_local(t, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004672 return 1;
4673 }
4674
4675 data_type = stktable_get_data_type(args[cur_arg] + 5);
4676 if (data_type < 0) {
Willy Tarreau9d008692019-08-09 11:21:01 +02004677 cli_err(appctx, "Unknown data type\n");
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004678 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004679 stktable_touch_local(t, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004680 return 1;
4681 }
4682
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004683 if (!t->data_ofs[data_type]) {
Willy Tarreau9d008692019-08-09 11:21:01 +02004684 cli_err(appctx, "Data type not stored in this table\n");
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004685 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004686 stktable_touch_local(t, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004687 return 1;
4688 }
4689
4690 if (!*args[cur_arg+1] || strl2llrc(args[cur_arg+1], strlen(args[cur_arg+1]), &value) != 0) {
Willy Tarreau9d008692019-08-09 11:21:01 +02004691 cli_err(appctx, "Require a valid integer value to store\n");
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004692 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004693 stktable_touch_local(t, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004694 return 1;
4695 }
4696
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004697 ptr = stktable_data_ptr(t, ts, data_type);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004698
4699 switch (stktable_data_types[data_type].std_type) {
4700 case STD_T_SINT:
4701 stktable_data_cast(ptr, std_t_sint) = value;
4702 break;
4703 case STD_T_UINT:
4704 stktable_data_cast(ptr, std_t_uint) = value;
4705 break;
4706 case STD_T_ULL:
4707 stktable_data_cast(ptr, std_t_ull) = value;
4708 break;
4709 case STD_T_FRQP:
4710 /* We set both the current and previous values. That way
4711 * the reported frequency is stable during all the period
4712 * then slowly fades out. This allows external tools to
4713 * push measures without having to update them too often.
4714 */
4715 frqp = &stktable_data_cast(ptr, std_t_frqp);
Willy Tarreaufa1258f2021-04-10 23:00:53 +02004716 /* First bit is reserved for the freq_ctr lock
Emeric Brunf2fc1fd2017-11-02 17:32:43 +01004717 Note: here we're still protected by the stksess lock
Willy Tarreaufa1258f2021-04-10 23:00:53 +02004718 so we don't need to update the update the freq_ctr
Emeric Brunf2fc1fd2017-11-02 17:32:43 +01004719 using its internal lock */
4720 frqp->curr_tick = now_ms & ~0x1;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004721 frqp->prev_ctr = 0;
4722 frqp->curr_ctr = value;
4723 break;
4724 }
4725 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004726 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004727 stktable_touch_local(t, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004728 break;
4729
4730 default:
Willy Tarreau9d008692019-08-09 11:21:01 +02004731 return cli_err(appctx, "Unknown action\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004732 }
4733 return 1;
4734}
4735
4736/* Prepares the appctx fields with the data-based filters from the command line.
4737 * Returns 0 if the dump can proceed, 1 if has ended processing.
4738 */
4739static int table_prepare_data_request(struct appctx *appctx, char **args)
4740{
Willy Tarreau3c69e082022-05-03 11:35:07 +02004741 struct show_table_ctx *ctx = appctx->svcctx;
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004742 int i;
Adis Nezirovicd0142e72020-01-22 16:50:27 +01004743 char *err = NULL;
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004744
Willy Tarreau3c69e082022-05-03 11:35:07 +02004745 if (ctx->action != STK_CLI_ACT_SHOW && ctx->action != STK_CLI_ACT_CLR)
Willy Tarreau9d008692019-08-09 11:21:01 +02004746 return cli_err(appctx, "content-based lookup is only supported with the \"show\" and \"clear\" actions\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004747
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004748 for (i = 0; i < STKTABLE_FILTER_LEN; i++) {
4749 if (i > 0 && !*args[3+3*i]) // number of filter entries can be less than STKTABLE_FILTER_LEN
4750 break;
4751 /* condition on stored data value */
Willy Tarreau3c69e082022-05-03 11:35:07 +02004752 ctx->data_type[i] = stktable_get_data_type(args[3+3*i] + 5);
4753 if (ctx->data_type[i] < 0)
Adis Nezirovicd0142e72020-01-22 16:50:27 +01004754 return cli_dynerr(appctx, memprintf(&err, "Filter entry #%i: Unknown data type\n", i + 1));
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004755
Willy Tarreau3c69e082022-05-03 11:35:07 +02004756 if (!((struct stktable *)ctx->target)->data_ofs[ctx->data_type[i]])
Adis Nezirovicd0142e72020-01-22 16:50:27 +01004757 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 +01004758
Willy Tarreau3c69e082022-05-03 11:35:07 +02004759 ctx->data_op[i] = get_std_op(args[4+3*i]);
4760 if (ctx->data_op[i] < 0)
Adis Nezirovicd0142e72020-01-22 16:50:27 +01004761 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 +01004762
Willy Tarreau3c69e082022-05-03 11:35:07 +02004763 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 +01004764 return cli_dynerr(appctx, memprintf(&err, "Filter entry #%i: Require a valid integer value to compare against\n", i + 1));
4765 }
4766
4767 if (*args[3+3*i]) {
4768 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 +01004769 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004770
4771 /* OK we're done, all the fields are set */
4772 return 0;
4773}
4774
4775/* returns 0 if wants to be called, 1 if has ended processing */
Aurélien Nephtaliabbf6072018-04-18 13:26:46 +02004776static int cli_parse_table_req(char **args, char *payload, struct appctx *appctx, void *private)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004777{
Willy Tarreau3c69e082022-05-03 11:35:07 +02004778 struct show_table_ctx *ctx = applet_reserve_svcctx(appctx, sizeof(*ctx));
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004779 int i;
4780
4781 for (i = 0; i < STKTABLE_FILTER_LEN; i++)
Willy Tarreau3c69e082022-05-03 11:35:07 +02004782 ctx->data_type[i] = -1;
4783 ctx->target = NULL;
4784 ctx->entry = NULL;
4785 ctx->action = (long)private; // keyword argument, one of STK_CLI_ACT_*
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004786
4787 if (*args[2]) {
Willy Tarreau0f154ed2022-05-03 12:02:36 +02004788 ctx->t = ctx->target = stktable_find_by_name(args[2]);
Willy Tarreau3c69e082022-05-03 11:35:07 +02004789 if (!ctx->target)
Willy Tarreau9d008692019-08-09 11:21:01 +02004790 return cli_err(appctx, "No such table\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004791 }
4792 else {
Willy Tarreau0f154ed2022-05-03 12:02:36 +02004793 ctx->t = stktables_list;
Willy Tarreau3c69e082022-05-03 11:35:07 +02004794 if (ctx->action != STK_CLI_ACT_SHOW)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004795 goto err_args;
4796 return 0;
4797 }
4798
4799 if (strcmp(args[3], "key") == 0)
4800 return table_process_entry_per_key(appctx, args);
4801 else if (strncmp(args[3], "data.", 5) == 0)
4802 return table_prepare_data_request(appctx, args);
4803 else if (*args[3])
4804 goto err_args;
4805
4806 return 0;
4807
4808err_args:
Willy Tarreau3c69e082022-05-03 11:35:07 +02004809 switch (ctx->action) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004810 case STK_CLI_ACT_SHOW:
Willy Tarreau9d008692019-08-09 11:21:01 +02004811 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 +01004812 case STK_CLI_ACT_CLR:
Willy Tarreau9d008692019-08-09 11:21:01 +02004813 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 +01004814 case STK_CLI_ACT_SET:
Willy Tarreau9d008692019-08-09 11:21:01 +02004815 return cli_err(appctx, "Required arguments: <table> key <key> [data.<store_data_type> <value>]*\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004816 default:
Willy Tarreau9d008692019-08-09 11:21:01 +02004817 return cli_err(appctx, "Unknown action\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004818 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004819}
4820
4821/* This function is used to deal with table operations (dump or clear depending
4822 * on the action stored in appctx->private). It returns 0 if the output buffer is
4823 * full and it needs to be called again, otherwise non-zero.
4824 */
4825static int cli_io_handler_table(struct appctx *appctx)
4826{
Willy Tarreau3c69e082022-05-03 11:35:07 +02004827 struct show_table_ctx *ctx = appctx->svcctx;
Willy Tarreauc12b3212022-05-27 11:08:15 +02004828 struct stconn *sc = appctx_sc(appctx);
Willy Tarreau475e4632022-05-27 10:26:46 +02004829 struct stream *s = __sc_strm(sc);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004830 struct ebmb_node *eb;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004831 int skip_entry;
Willy Tarreau3c69e082022-05-03 11:35:07 +02004832 int show = ctx->action == STK_CLI_ACT_SHOW;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004833
4834 /*
Willy Tarreau0f154ed2022-05-03 12:02:36 +02004835 * We have 3 possible states in ctx->state :
Willy Tarreau7849d4c2022-05-03 11:45:02 +02004836 * - STATE_NEXT : the proxy pointer points to the next table to
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004837 * dump, the entry pointer is NULL ;
Willy Tarreau7849d4c2022-05-03 11:45:02 +02004838 * - STATE_DUMP : the proxy pointer points to the current table
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004839 * and the entry pointer points to the next entry to be dumped,
4840 * and the refcount on the next entry is held ;
Willy Tarreau7849d4c2022-05-03 11:45:02 +02004841 * - STATE_DONE : nothing left to dump, the buffer may contain some
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004842 * data though.
4843 */
4844
Willy Tarreau475e4632022-05-27 10:26:46 +02004845 if (unlikely(sc_ic(sc)->flags & (CF_WRITE_ERROR|CF_SHUTW))) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004846 /* in case of abort, remove any refcount we might have set on an entry */
Willy Tarreau7849d4c2022-05-03 11:45:02 +02004847 if (ctx->state == STATE_DUMP) {
Willy Tarreau3c69e082022-05-03 11:35:07 +02004848 stksess_kill_if_expired(ctx->t, ctx->entry, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004849 }
4850 return 1;
4851 }
4852
4853 chunk_reset(&trash);
4854
Willy Tarreau7849d4c2022-05-03 11:45:02 +02004855 while (ctx->state != STATE_DONE) {
4856 switch (ctx->state) {
Willy Tarreau7849d4c2022-05-03 11:45:02 +02004857 case STATE_NEXT:
Willy Tarreau3c69e082022-05-03 11:35:07 +02004858 if (!ctx->t ||
4859 (ctx->target &&
4860 ctx->t != ctx->target)) {
Willy Tarreau7849d4c2022-05-03 11:45:02 +02004861 ctx->state = STATE_DONE;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004862 break;
4863 }
4864
Willy Tarreau3c69e082022-05-03 11:35:07 +02004865 if (ctx->t->size) {
Willy Tarreaud0a06d52022-05-18 15:07:19 +02004866 if (show && !table_dump_head_to_buffer(&trash, appctx, ctx->t, ctx->target))
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004867 return 0;
4868
Willy Tarreau3c69e082022-05-03 11:35:07 +02004869 if (ctx->target &&
William Lallemand07a62f72017-05-24 00:57:40 +02004870 (strm_li(s)->bind_conf->level & ACCESS_LVL_MASK) >= ACCESS_LVL_OPER) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004871 /* dump entries only if table explicitly requested */
Willy Tarreau76642222022-10-11 12:02:50 +02004872 HA_RWLOCK_WRLOCK(STK_TABLE_LOCK, &ctx->t->lock);
Willy Tarreau3c69e082022-05-03 11:35:07 +02004873 eb = ebmb_first(&ctx->t->keys);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004874 if (eb) {
Willy Tarreau3c69e082022-05-03 11:35:07 +02004875 ctx->entry = ebmb_entry(eb, struct stksess, key);
4876 ctx->entry->ref_cnt++;
Willy Tarreau7849d4c2022-05-03 11:45:02 +02004877 ctx->state = STATE_DUMP;
Willy Tarreau76642222022-10-11 12:02:50 +02004878 HA_RWLOCK_WRUNLOCK(STK_TABLE_LOCK, &ctx->t->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004879 break;
4880 }
Willy Tarreau76642222022-10-11 12:02:50 +02004881 HA_RWLOCK_WRUNLOCK(STK_TABLE_LOCK, &ctx->t->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004882 }
4883 }
Willy Tarreau3c69e082022-05-03 11:35:07 +02004884 ctx->t = ctx->t->next;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004885 break;
4886
Willy Tarreau7849d4c2022-05-03 11:45:02 +02004887 case STATE_DUMP:
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004888 skip_entry = 0;
4889
Willy Tarreau3c69e082022-05-03 11:35:07 +02004890 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &ctx->entry->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004891
Willy Tarreau3c69e082022-05-03 11:35:07 +02004892 if (ctx->data_type[0] >= 0) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004893 /* we're filtering on some data contents */
4894 void *ptr;
Willy Tarreau2b64a352020-01-22 17:09:47 +01004895 int dt, i;
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004896 signed char op;
4897 long long data, value;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004898
Emeric Brun819fc6f2017-06-13 19:37:32 +02004899
Willy Tarreau2b64a352020-01-22 17:09:47 +01004900 for (i = 0; i < STKTABLE_FILTER_LEN; i++) {
Willy Tarreau3c69e082022-05-03 11:35:07 +02004901 if (ctx->data_type[i] == -1)
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004902 break;
Willy Tarreau3c69e082022-05-03 11:35:07 +02004903 dt = ctx->data_type[i];
4904 ptr = stktable_data_ptr(ctx->t,
4905 ctx->entry,
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004906 dt);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004907
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004908 data = 0;
4909 switch (stktable_data_types[dt].std_type) {
4910 case STD_T_SINT:
4911 data = stktable_data_cast(ptr, std_t_sint);
4912 break;
4913 case STD_T_UINT:
4914 data = stktable_data_cast(ptr, std_t_uint);
4915 break;
4916 case STD_T_ULL:
4917 data = stktable_data_cast(ptr, std_t_ull);
4918 break;
4919 case STD_T_FRQP:
4920 data = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Willy Tarreau3c69e082022-05-03 11:35:07 +02004921 ctx->t->data_arg[dt].u);
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004922 break;
4923 }
4924
Willy Tarreau3c69e082022-05-03 11:35:07 +02004925 op = ctx->data_op[i];
4926 value = ctx->value[i];
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004927
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004928 /* skip the entry if the data does not match the test and the value */
4929 if ((data < value &&
4930 (op == STD_OP_EQ || op == STD_OP_GT || op == STD_OP_GE)) ||
4931 (data == value &&
4932 (op == STD_OP_NE || op == STD_OP_GT || op == STD_OP_LT)) ||
4933 (data > value &&
4934 (op == STD_OP_EQ || op == STD_OP_LT || op == STD_OP_LE))) {
4935 skip_entry = 1;
4936 break;
4937 }
4938 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004939 }
4940
4941 if (show && !skip_entry &&
Willy Tarreaud0a06d52022-05-18 15:07:19 +02004942 !table_dump_entry_to_buffer(&trash, appctx, ctx->t, ctx->entry)) {
Willy Tarreau3c69e082022-05-03 11:35:07 +02004943 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &ctx->entry->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004944 return 0;
4945 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004946
Willy Tarreau3c69e082022-05-03 11:35:07 +02004947 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &ctx->entry->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004948
Willy Tarreau76642222022-10-11 12:02:50 +02004949 HA_RWLOCK_WRLOCK(STK_TABLE_LOCK, &ctx->t->lock);
Willy Tarreau3c69e082022-05-03 11:35:07 +02004950 ctx->entry->ref_cnt--;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004951
Willy Tarreau3c69e082022-05-03 11:35:07 +02004952 eb = ebmb_next(&ctx->entry->key);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004953 if (eb) {
Willy Tarreau3c69e082022-05-03 11:35:07 +02004954 struct stksess *old = ctx->entry;
4955 ctx->entry = ebmb_entry(eb, struct stksess, key);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004956 if (show)
Willy Tarreau3c69e082022-05-03 11:35:07 +02004957 __stksess_kill_if_expired(ctx->t, old);
4958 else if (!skip_entry && !ctx->entry->ref_cnt)
4959 __stksess_kill(ctx->t, old);
4960 ctx->entry->ref_cnt++;
Willy Tarreau76642222022-10-11 12:02:50 +02004961 HA_RWLOCK_WRUNLOCK(STK_TABLE_LOCK, &ctx->t->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004962 break;
4963 }
4964
4965
4966 if (show)
Willy Tarreau3c69e082022-05-03 11:35:07 +02004967 __stksess_kill_if_expired(ctx->t, ctx->entry);
4968 else if (!skip_entry && !ctx->entry->ref_cnt)
4969 __stksess_kill(ctx->t, ctx->entry);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004970
Willy Tarreau76642222022-10-11 12:02:50 +02004971 HA_RWLOCK_WRUNLOCK(STK_TABLE_LOCK, &ctx->t->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004972
Willy Tarreau3c69e082022-05-03 11:35:07 +02004973 ctx->t = ctx->t->next;
Willy Tarreau7849d4c2022-05-03 11:45:02 +02004974 ctx->state = STATE_NEXT;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004975 break;
4976
Willy Tarreau7849d4c2022-05-03 11:45:02 +02004977 default:
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004978 break;
4979 }
4980 }
4981 return 1;
4982}
4983
4984static void cli_release_show_table(struct appctx *appctx)
4985{
Willy Tarreau3c69e082022-05-03 11:35:07 +02004986 struct show_table_ctx *ctx = appctx->svcctx;
4987
Willy Tarreau7849d4c2022-05-03 11:45:02 +02004988 if (ctx->state == STATE_DUMP) {
Willy Tarreau3c69e082022-05-03 11:35:07 +02004989 stksess_kill_if_expired(ctx->t, ctx->entry, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004990 }
4991}
4992
Willy Tarreau478331d2020-08-28 11:31:31 +02004993static void stkt_late_init(void)
4994{
4995 struct sample_fetch *f;
4996
4997 f = find_sample_fetch("src", strlen("src"));
4998 if (f)
4999 smp_fetch_src = f->process;
5000}
5001
5002INITCALL0(STG_INIT, stkt_late_init);
5003
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01005004/* register cli keywords */
5005static struct cli_kw_list cli_kws = {{ },{
Willy Tarreaub205bfd2021-05-07 11:38:37 +02005006 { { "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 },
5007 { { "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 },
5008 { { "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 +01005009 {{},}
5010}};
5011
Willy Tarreau0108d902018-11-25 19:14:37 +01005012INITCALL1(STG_REGISTER, cli_register_kw, &cli_kws);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01005013
Thierry FOURNIER236657b2015-08-19 08:25:14 +02005014static struct action_kw_list tcp_conn_kws = { { }, {
Emeric Brun4d7ada82021-06-30 19:04:16 +02005015 { "sc-inc-gpc", parse_inc_gpc, KWF_MATCH_PREFIX },
5016 { "sc-inc-gpc0", parse_inc_gpc, KWF_MATCH_PREFIX },
5017 { "sc-inc-gpc1", parse_inc_gpc, KWF_MATCH_PREFIX },
Emeric Brun877b0b52021-06-30 18:57:49 +02005018 { "sc-set-gpt", parse_set_gpt, KWF_MATCH_PREFIX },
5019 { "sc-set-gpt0", parse_set_gpt, KWF_MATCH_PREFIX },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02005020 { /* END */ }
5021}};
5022
Willy Tarreau0108d902018-11-25 19:14:37 +01005023INITCALL1(STG_REGISTER, tcp_req_conn_keywords_register, &tcp_conn_kws);
5024
Willy Tarreau620408f2016-10-21 16:37:51 +02005025static struct action_kw_list tcp_sess_kws = { { }, {
Emeric Brun4d7ada82021-06-30 19:04:16 +02005026 { "sc-inc-gpc", parse_inc_gpc, KWF_MATCH_PREFIX },
5027 { "sc-inc-gpc0", parse_inc_gpc, KWF_MATCH_PREFIX },
5028 { "sc-inc-gpc1", parse_inc_gpc, KWF_MATCH_PREFIX },
Emeric Brun877b0b52021-06-30 18:57:49 +02005029 { "sc-set-gpt", parse_set_gpt, KWF_MATCH_PREFIX },
5030 { "sc-set-gpt0", parse_set_gpt, KWF_MATCH_PREFIX },
Willy Tarreau620408f2016-10-21 16:37:51 +02005031 { /* END */ }
5032}};
5033
Willy Tarreau0108d902018-11-25 19:14:37 +01005034INITCALL1(STG_REGISTER, tcp_req_sess_keywords_register, &tcp_sess_kws);
5035
Thierry FOURNIER236657b2015-08-19 08:25:14 +02005036static struct action_kw_list tcp_req_kws = { { }, {
Emeric Brun4d7ada82021-06-30 19:04:16 +02005037 { "sc-inc-gpc", parse_inc_gpc, KWF_MATCH_PREFIX },
5038 { "sc-inc-gpc0", parse_inc_gpc, KWF_MATCH_PREFIX },
5039 { "sc-inc-gpc1", parse_inc_gpc, KWF_MATCH_PREFIX },
Emeric Brun877b0b52021-06-30 18:57:49 +02005040 { "sc-set-gpt", parse_set_gpt, KWF_MATCH_PREFIX },
5041 { "sc-set-gpt0", parse_set_gpt, KWF_MATCH_PREFIX },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02005042 { /* END */ }
5043}};
5044
Willy Tarreau0108d902018-11-25 19:14:37 +01005045INITCALL1(STG_REGISTER, tcp_req_cont_keywords_register, &tcp_req_kws);
5046
Thierry FOURNIER236657b2015-08-19 08:25:14 +02005047static struct action_kw_list tcp_res_kws = { { }, {
Emeric Brun4d7ada82021-06-30 19:04:16 +02005048 { "sc-inc-gpc", parse_inc_gpc, KWF_MATCH_PREFIX },
5049 { "sc-inc-gpc0", parse_inc_gpc, KWF_MATCH_PREFIX },
5050 { "sc-inc-gpc1", parse_inc_gpc, KWF_MATCH_PREFIX },
Emeric Brun877b0b52021-06-30 18:57:49 +02005051 { "sc-set-gpt", parse_set_gpt, KWF_MATCH_PREFIX },
5052 { "sc-set-gpt0", parse_set_gpt, KWF_MATCH_PREFIX },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02005053 { /* END */ }
5054}};
5055
Willy Tarreau0108d902018-11-25 19:14:37 +01005056INITCALL1(STG_REGISTER, tcp_res_cont_keywords_register, &tcp_res_kws);
5057
Thierry FOURNIER236657b2015-08-19 08:25:14 +02005058static struct action_kw_list http_req_kws = { { }, {
Emeric Brun4d7ada82021-06-30 19:04:16 +02005059 { "sc-inc-gpc", parse_inc_gpc, KWF_MATCH_PREFIX },
5060 { "sc-inc-gpc0", parse_inc_gpc, KWF_MATCH_PREFIX },
5061 { "sc-inc-gpc1", parse_inc_gpc, KWF_MATCH_PREFIX },
Emeric Brun877b0b52021-06-30 18:57:49 +02005062 { "sc-set-gpt", parse_set_gpt, KWF_MATCH_PREFIX },
5063 { "sc-set-gpt0", parse_set_gpt, KWF_MATCH_PREFIX },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02005064 { /* END */ }
5065}};
5066
Willy Tarreau0108d902018-11-25 19:14:37 +01005067INITCALL1(STG_REGISTER, http_req_keywords_register, &http_req_kws);
5068
Thierry FOURNIER236657b2015-08-19 08:25:14 +02005069static struct action_kw_list http_res_kws = { { }, {
Emeric Brun4d7ada82021-06-30 19:04:16 +02005070 { "sc-inc-gpc", parse_inc_gpc, KWF_MATCH_PREFIX },
5071 { "sc-inc-gpc0", parse_inc_gpc, KWF_MATCH_PREFIX },
5072 { "sc-inc-gpc1", parse_inc_gpc, KWF_MATCH_PREFIX },
Emeric Brun877b0b52021-06-30 18:57:49 +02005073 { "sc-set-gpt", parse_set_gpt, KWF_MATCH_PREFIX },
5074 { "sc-set-gpt0", parse_set_gpt, KWF_MATCH_PREFIX },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02005075 { /* END */ }
5076}};
5077
Willy Tarreau0108d902018-11-25 19:14:37 +01005078INITCALL1(STG_REGISTER, http_res_keywords_register, &http_res_kws);
5079
Willy Tarreau7d562212016-11-25 16:10:05 +01005080/* Note: must not be declared <const> as its list will be overwritten.
5081 * Please take care of keeping this list alphabetically sorted.
5082 */
5083static struct sample_fetch_kw_list smp_fetch_keywords = {ILH, {
5084 { "sc_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5085 { "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 +02005086 { "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 +01005087 { "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 +01005088 { "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 +01005089 { "sc_conn_cnt", smp_fetch_sc_conn_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5090 { "sc_conn_cur", smp_fetch_sc_conn_cur, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5091 { "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 +02005092 { "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 +01005093 { "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 +02005094 { "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 +01005095 { "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 +01005096 { "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 +02005097 { "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 +01005098 { "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 +01005099 { "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 +01005100 { "sc_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5101 { "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 +01005102 { "sc_http_fail_cnt", smp_fetch_sc_http_fail_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5103 { "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 +01005104 { "sc_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5105 { "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 +02005106 { "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 +01005107 { "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 +01005108 { "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 +01005109 { "sc_kbytes_in", smp_fetch_sc_kbytes_in, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5110 { "sc_kbytes_out", smp_fetch_sc_kbytes_out, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5111 { "sc_sess_cnt", smp_fetch_sc_sess_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5112 { "sc_sess_rate", smp_fetch_sc_sess_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5113 { "sc_tracked", smp_fetch_sc_tracked, ARG2(1,SINT,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
5114 { "sc_trackers", smp_fetch_sc_trackers, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5115 { "sc0_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5116 { "sc0_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5117 { "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 +01005118 { "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 +01005119 { "sc0_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5120 { "sc0_conn_cur", smp_fetch_sc_conn_cur, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5121 { "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 +01005122 { "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 +01005123 { "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 +01005124 { "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 +01005125 { "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 +01005126 { "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 +01005127 { "sc0_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5128 { "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 +01005129 { "sc0_http_fail_cnt", smp_fetch_sc_http_fail_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5130 { "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 +01005131 { "sc0_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5132 { "sc0_http_req_rate", smp_fetch_sc_http_req_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5133 { "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 +01005134 { "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 +01005135 { "sc0_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5136 { "sc0_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5137 { "sc0_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5138 { "sc0_sess_rate", smp_fetch_sc_sess_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5139 { "sc0_tracked", smp_fetch_sc_tracked, ARG1(0,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
5140 { "sc0_trackers", smp_fetch_sc_trackers, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5141 { "sc1_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5142 { "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 +02005143 { "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 +01005144 { "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 +01005145 { "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 +01005146 { "sc1_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5147 { "sc1_conn_cur", smp_fetch_sc_conn_cur, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5148 { "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 +01005149 { "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 +01005150 { "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 +01005151 { "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 +01005152 { "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 +01005153 { "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 +01005154 { "sc1_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5155 { "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 +01005156 { "sc1_http_fail_cnt", smp_fetch_sc_http_fail_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5157 { "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 +01005158 { "sc1_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5159 { "sc1_http_req_rate", smp_fetch_sc_http_req_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5160 { "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 +01005161 { "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 +01005162 { "sc1_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5163 { "sc1_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5164 { "sc1_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5165 { "sc1_sess_rate", smp_fetch_sc_sess_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5166 { "sc1_tracked", smp_fetch_sc_tracked, ARG1(0,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
5167 { "sc1_trackers", smp_fetch_sc_trackers, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5168 { "sc2_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5169 { "sc2_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5170 { "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 +01005171 { "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 +01005172 { "sc2_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5173 { "sc2_conn_cur", smp_fetch_sc_conn_cur, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5174 { "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 +01005175 { "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 +01005176 { "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 +01005177 { "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 +01005178 { "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 +01005179 { "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 +01005180 { "sc2_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5181 { "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 +01005182 { "sc2_http_fail_cnt", smp_fetch_sc_http_fail_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5183 { "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 +01005184 { "sc2_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5185 { "sc2_http_req_rate", smp_fetch_sc_http_req_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5186 { "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 +01005187 { "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 +01005188 { "sc2_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5189 { "sc2_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5190 { "sc2_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5191 { "sc2_sess_rate", smp_fetch_sc_sess_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5192 { "sc2_tracked", smp_fetch_sc_tracked, ARG1(0,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
5193 { "sc2_trackers", smp_fetch_sc_trackers, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5194 { "src_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5195 { "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 +02005196 { "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 +01005197 { "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 +01005198 { "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 +01005199 { "src_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5200 { "src_conn_cur", smp_fetch_sc_conn_cur, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5201 { "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 +02005202 { "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 +01005203 { "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 +02005204 { "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 +01005205 { "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 +01005206 { "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 +02005207 { "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 +01005208 { "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 +01005209 { "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 +01005210 { "src_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5211 { "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 +01005212 { "src_http_fail_cnt", smp_fetch_sc_http_fail_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5213 { "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 +01005214 { "src_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5215 { "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 +02005216 { "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 +01005217 { "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 +01005218 { "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 +01005219 { "src_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5220 { "src_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5221 { "src_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5222 { "src_sess_rate", smp_fetch_sc_sess_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5223 { "src_updt_conn_cnt", smp_fetch_src_updt_conn_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5224 { "table_avl", smp_fetch_table_avl, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5225 { "table_cnt", smp_fetch_table_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5226 { /* END */ },
5227}};
5228
Willy Tarreau0108d902018-11-25 19:14:37 +01005229INITCALL1(STG_REGISTER, sample_register_fetches, &smp_fetch_keywords);
Willy Tarreau7d562212016-11-25 16:10:05 +01005230
Willy Tarreaud9f316a2014-07-10 14:03:38 +02005231/* Note: must not be declared <const> as its list will be overwritten */
5232static struct sample_conv_kw_list sample_conv_kws = {ILH, {
Willy Tarreau2d17db52016-05-25 17:16:38 +02005233 { "in_table", sample_conv_in_table, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_BOOL },
5234 { "table_bytes_in_rate", sample_conv_table_bytes_in_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5235 { "table_bytes_out_rate", sample_conv_table_bytes_out_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5236 { "table_conn_cnt", sample_conv_table_conn_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5237 { "table_conn_cur", sample_conv_table_conn_cur, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5238 { "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 +02005239 { "table_expire", sample_conv_table_expire, ARG2(1,TAB,SINT), NULL, SMP_T_ANY, SMP_T_SINT },
Emeric Brun877b0b52021-06-30 18:57:49 +02005240 { "table_gpt", sample_conv_table_gpt, ARG2(2,SINT,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
Willy Tarreau2d17db52016-05-25 17:16:38 +02005241 { "table_gpt0", sample_conv_table_gpt0, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
Emeric Brun4d7ada82021-06-30 19:04:16 +02005242 { "table_gpc", sample_conv_table_gpc, ARG2(2,SINT,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
Willy Tarreau2d17db52016-05-25 17:16:38 +02005243 { "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 +01005244 { "table_gpc1", sample_conv_table_gpc1, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
Emeric Brun4d7ada82021-06-30 19:04:16 +02005245 { "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 +02005246 { "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 +01005247 { "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 +02005248 { "table_http_err_cnt", sample_conv_table_http_err_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5249 { "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 +01005250 { "table_http_fail_cnt", sample_conv_table_http_fail_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5251 { "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 +02005252 { "table_http_req_cnt", sample_conv_table_http_req_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5253 { "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 +02005254 { "table_idle", sample_conv_table_idle, ARG2(1,TAB,SINT), NULL, SMP_T_ANY, SMP_T_SINT },
Willy Tarreau2d17db52016-05-25 17:16:38 +02005255 { "table_kbytes_in", sample_conv_table_kbytes_in, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5256 { "table_kbytes_out", sample_conv_table_kbytes_out, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5257 { "table_server_id", sample_conv_table_server_id, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5258 { "table_sess_cnt", sample_conv_table_sess_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5259 { "table_sess_rate", sample_conv_table_sess_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5260 { "table_trackers", sample_conv_table_trackers, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
Willy Tarreaud9f316a2014-07-10 14:03:38 +02005261 { /* END */ },
5262}};
5263
Willy Tarreau0108d902018-11-25 19:14:37 +01005264INITCALL1(STG_REGISTER, sample_register_convs, &sample_conv_kws);