blob: 3ca2c887f54e789d033184260c09be43965cdb94 [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
Frédéric Lécaille36d15652022-10-17 14:58:19 +0200159/*
160 * Initialize or update the key hash in the sticky session <ts> present in table <t>
161 * from the value present in <key>.
162 */
163static unsigned long long stksess_getkey_hash(struct stktable *t,
164 struct stksess *ts,
165 struct stktable_key *key)
166{
Frédéric Lécaille36d15652022-10-17 14:58:19 +0200167 size_t keylen;
168
Frédéric Lécaille36d15652022-10-17 14:58:19 +0200169 if (t->type == SMP_T_STR)
170 keylen = key->key_len;
171 else
172 keylen = t->key_size;
Frédéric Lécaille36d15652022-10-17 14:58:19 +0200173
Willy Tarreau56460ee2022-11-28 18:53:06 +0100174 return XXH64(key->key, keylen, t->hash_seed);
Frédéric Lécaille36d15652022-10-17 14:58:19 +0200175}
Emeric Brun3bd697e2010-01-04 15:23:48 +0100176
177/*
Frédéric Lécaille36d15652022-10-17 14:58:19 +0200178 * Set the shard for <key> key of <ts> sticky session attached to <t> stick table.
179 * Do nothing for stick-table without peers synchronisation.
180 */
181static void stksess_setkey_shard(struct stktable *t, struct stksess *ts,
182 struct stktable_key *key)
183{
184 if (!t->peers.p)
185 /* This stick-table is not attached to any peers section */
186 return;
187
188 if (!t->peers.p->nb_shards)
189 ts->shard = 0;
190 else
191 ts->shard = stksess_getkey_hash(t, ts, key) % t->peers.p->nb_shards + 1;
192}
193
194/*
Willy Tarreau393379c2010-06-06 12:11:37 +0200195 * Init sticky session <ts> of table <t>. The data parts are cleared and <ts>
196 * is returned.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100197 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200198static struct stksess *__stksess_init(struct stktable *t, struct stksess * ts)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100199{
Willy Tarreau393379c2010-06-06 12:11:37 +0200200 memset((void *)ts - t->data_size, 0, t->data_size);
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200201 ts->ref_cnt = 0;
Willy Tarreau86257dc2010-06-06 12:57:10 +0200202 ts->key.node.leaf_p = NULL;
203 ts->exp.node.leaf_p = NULL;
Emeric Brun85e77c72010-09-23 18:16:52 +0200204 ts->upd.node.leaf_p = NULL;
Emeric Brun819fc6f2017-06-13 19:37:32 +0200205 ts->expire = tick_add(now_ms, MS_TO_TICKS(t->expire));
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100206 HA_RWLOCK_INIT(&ts->lock);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100207 return ts;
208}
209
210/*
Willy Tarreauaea940e2010-06-06 11:56:36 +0200211 * Trash oldest <to_batch> sticky sessions from table <t>
Willy Tarreaudfe79252020-11-03 17:47:41 +0100212 * Returns number of trashed sticky sessions. It may actually trash less
213 * than expected if finding these requires too long a search time (e.g.
214 * most of them have ts->ref_cnt>0).
Emeric Brun3bd697e2010-01-04 15:23:48 +0100215 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200216int __stktable_trash_oldest(struct stktable *t, int to_batch)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100217{
218 struct stksess *ts;
219 struct eb32_node *eb;
Willy Tarreaudfe79252020-11-03 17:47:41 +0100220 int max_search = to_batch * 2; // no more than 50% misses
Emeric Brun3bd697e2010-01-04 15:23:48 +0100221 int batched = 0;
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200222 int looped = 0;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100223
224 eb = eb32_lookup_ge(&t->exps, now_ms - TIMER_LOOK_BACK);
225
226 while (batched < to_batch) {
227
228 if (unlikely(!eb)) {
229 /* we might have reached the end of the tree, typically because
230 * <now_ms> is in the first half and we're first scanning the last
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200231 * half. Let's loop back to the beginning of the tree now if we
232 * have not yet visited it.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100233 */
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200234 if (looped)
235 break;
236 looped = 1;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100237 eb = eb32_first(&t->exps);
238 if (likely(!eb))
239 break;
240 }
241
Willy Tarreaudfe79252020-11-03 17:47:41 +0100242 if (--max_search < 0)
243 break;
244
Emeric Brun3bd697e2010-01-04 15:23:48 +0100245 /* timer looks expired, detach it from the queue */
Willy Tarreau86257dc2010-06-06 12:57:10 +0200246 ts = eb32_entry(eb, struct stksess, exp);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100247 eb = eb32_next(eb);
248
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200249 /* don't delete an entry which is currently referenced */
250 if (ts->ref_cnt)
251 continue;
252
Willy Tarreau86257dc2010-06-06 12:57:10 +0200253 eb32_delete(&ts->exp);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100254
Willy Tarreau86257dc2010-06-06 12:57:10 +0200255 if (ts->expire != ts->exp.key) {
Emeric Brun3bd697e2010-01-04 15:23:48 +0100256 if (!tick_isset(ts->expire))
257 continue;
258
Willy Tarreau86257dc2010-06-06 12:57:10 +0200259 ts->exp.key = ts->expire;
260 eb32_insert(&t->exps, &ts->exp);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100261
Willy Tarreau86257dc2010-06-06 12:57:10 +0200262 if (!eb || eb->key > ts->exp.key)
263 eb = &ts->exp;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100264
265 continue;
266 }
Emeric Brun3bd697e2010-01-04 15:23:48 +0100267
Willy Tarreauaea940e2010-06-06 11:56:36 +0200268 /* session expired, trash it */
Willy Tarreau86257dc2010-06-06 12:57:10 +0200269 ebmb_delete(&ts->key);
Emeric Brun85e77c72010-09-23 18:16:52 +0200270 eb32_delete(&ts->upd);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200271 __stksess_free(t, ts);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100272 batched++;
273 }
274
275 return batched;
276}
277
278/*
Emeric Brun819fc6f2017-06-13 19:37:32 +0200279 * Trash oldest <to_batch> sticky sessions from table <t>
280 * Returns number of trashed sticky sessions.
281 * This function locks the table
282 */
283int stktable_trash_oldest(struct stktable *t, int to_batch)
284{
285 int ret;
286
Willy Tarreau76642222022-10-11 12:02:50 +0200287 HA_RWLOCK_WRLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200288 ret = __stktable_trash_oldest(t, to_batch);
Willy Tarreau76642222022-10-11 12:02:50 +0200289 HA_RWLOCK_WRUNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200290
291 return ret;
292}
293/*
Willy Tarreauaea940e2010-06-06 11:56:36 +0200294 * Allocate and initialise a new sticky session.
295 * The new sticky session is returned or NULL in case of lack of memory.
296 * Sticky sessions should only be allocated this way, and must be freed using
Willy Tarreaua7b46b52013-04-11 16:55:37 +0200297 * stksess_free(). Table <t>'s sticky session counter is increased. If <key>
Willy Tarreau996f1a52022-10-11 16:19:35 +0200298 * is not NULL, it is assigned to the new session. It must be called unlocked
299 * as it may rely on a lock to trash older entries.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100300 */
Willy Tarreau996f1a52022-10-11 16:19:35 +0200301struct stksess *stksess_new(struct stktable *t, struct stktable_key *key)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100302{
303 struct stksess *ts;
Willy Tarreau996f1a52022-10-11 16:19:35 +0200304 unsigned int current;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100305
Willy Tarreau996f1a52022-10-11 16:19:35 +0200306 current = HA_ATOMIC_FETCH_ADD(&t->current, 1);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100307
Willy Tarreau996f1a52022-10-11 16:19:35 +0200308 if (unlikely(current >= t->size)) {
309 /* the table was already full, we may have to purge entries */
310 if (t->nopurge || !stktable_trash_oldest(t, (t->size >> 8) + 1)) {
311 HA_ATOMIC_DEC(&t->current);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100312 return NULL;
Willy Tarreau996f1a52022-10-11 16:19:35 +0200313 }
Emeric Brun3bd697e2010-01-04 15:23:48 +0100314 }
315
Willy Tarreaubafbe012017-11-24 17:34:44 +0100316 ts = pool_alloc(t->pool);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100317 if (ts) {
Olivier Houchard52dabbc2018-11-14 17:54:36 +0100318 ts = (void *)ts + round_ptr_size(t->data_size);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200319 __stksess_init(t, ts);
Frédéric Lécaille36d15652022-10-17 14:58:19 +0200320 if (key) {
Willy Tarreaua7b46b52013-04-11 16:55:37 +0200321 stksess_setkey(t, ts, key);
Frédéric Lécaille36d15652022-10-17 14:58:19 +0200322 stksess_setkey_shard(t, ts, key);
323 }
Emeric Brun3bd697e2010-01-04 15:23:48 +0100324 }
325
326 return ts;
327}
328
329/*
Willy Tarreauf16d2b82010-06-06 15:38:59 +0200330 * Looks in table <t> for a sticky session matching key <key>.
Willy Tarreauaea940e2010-06-06 11:56:36 +0200331 * Returns pointer on requested sticky session or NULL if none was found.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100332 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200333struct stksess *__stktable_lookup_key(struct stktable *t, struct stktable_key *key)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100334{
335 struct ebmb_node *eb;
336
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200337 if (t->type == SMP_T_STR)
Emeric Brun485479d2010-09-23 18:02:19 +0200338 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 +0100339 else
340 eb = ebmb_lookup(&t->keys, key->key, t->key_size);
341
342 if (unlikely(!eb)) {
343 /* no session found */
344 return NULL;
345 }
346
Willy Tarreau86257dc2010-06-06 12:57:10 +0200347 return ebmb_entry(eb, struct stksess, key);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100348}
349
Emeric Brun819fc6f2017-06-13 19:37:32 +0200350/*
351 * Looks in table <t> for a sticky session matching key <key>.
352 * Returns pointer on requested sticky session or NULL if none was found.
353 * The refcount of the found entry is increased and this function
354 * is protected using the table lock
Willy Tarreau1f7e9252010-06-20 12:27:21 +0200355 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200356struct stksess *stktable_lookup_key(struct stktable *t, struct stktable_key *key)
Willy Tarreau1f7e9252010-06-20 12:27:21 +0200357{
358 struct stksess *ts;
359
Willy Tarreaua7d6a132022-10-11 15:42:54 +0200360 HA_RWLOCK_RDLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200361 ts = __stktable_lookup_key(t, key);
362 if (ts)
Willy Tarreaua7d6a132022-10-11 15:42:54 +0200363 HA_ATOMIC_INC(&ts->ref_cnt);
364 HA_RWLOCK_RDUNLOCK(STK_TABLE_LOCK, &t->lock);
Willy Tarreau1f7e9252010-06-20 12:27:21 +0200365
Willy Tarreau1f7e9252010-06-20 12:27:21 +0200366 return ts;
367}
368
Willy Tarreauf16d2b82010-06-06 15:38:59 +0200369/*
370 * Looks in table <t> for a sticky session with same key as <ts>.
371 * Returns pointer on requested sticky session or NULL if none was found.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100372 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200373struct stksess *__stktable_lookup(struct stktable *t, struct stksess *ts)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100374{
Emeric Brun3bd697e2010-01-04 15:23:48 +0100375 struct ebmb_node *eb;
376
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200377 if (t->type == SMP_T_STR)
Willy Tarreau86257dc2010-06-06 12:57:10 +0200378 eb = ebst_lookup(&(t->keys), (char *)ts->key.key);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100379 else
Willy Tarreau86257dc2010-06-06 12:57:10 +0200380 eb = ebmb_lookup(&(t->keys), ts->key.key, t->key_size);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100381
Willy Tarreauf16d2b82010-06-06 15:38:59 +0200382 if (unlikely(!eb))
383 return NULL;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100384
Willy Tarreauf16d2b82010-06-06 15:38:59 +0200385 return ebmb_entry(eb, struct stksess, key);
386}
Emeric Brun3bd697e2010-01-04 15:23:48 +0100387
Emeric Brun819fc6f2017-06-13 19:37:32 +0200388/*
389 * Looks in table <t> for a sticky session with same key as <ts>.
390 * Returns pointer on requested sticky session or NULL if none was found.
391 * The refcount of the found entry is increased and this function
392 * is protected using the table lock
393 */
394struct stksess *stktable_lookup(struct stktable *t, struct stksess *ts)
395{
396 struct stksess *lts;
397
Willy Tarreaua7d6a132022-10-11 15:42:54 +0200398 HA_RWLOCK_RDLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200399 lts = __stktable_lookup(t, ts);
400 if (lts)
Willy Tarreaua7d6a132022-10-11 15:42:54 +0200401 HA_ATOMIC_INC(&lts->ref_cnt);
402 HA_RWLOCK_RDUNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200403
404 return lts;
405}
406
Willy Tarreaucb183642010-06-06 17:58:34 +0200407/* Update the expiration timer for <ts> but do not touch its expiration node.
408 * The table's expiration timer is updated if set.
Emeric Brun819fc6f2017-06-13 19:37:32 +0200409 * The node will be also inserted into the update tree if needed, at a position
Willy Tarreau9f5cb432022-10-11 18:17:58 +0000410 * depending if the update is a local or coming from a remote node.
411 * If <decrefcnt> is set, the ts entry's ref_cnt will be decremented. The table's
412 * write lock may be taken.
Willy Tarreaucb183642010-06-06 17:58:34 +0200413 */
Willy Tarreau9f5cb432022-10-11 18:17:58 +0000414void stktable_touch_with_exp(struct stktable *t, struct stksess *ts, int local, int expire, int decrefcnt)
Willy Tarreaucb183642010-06-06 17:58:34 +0200415{
Emeric Brun85e77c72010-09-23 18:16:52 +0200416 struct eb32_node * eb;
Willy Tarreaua7536ef2022-10-11 18:31:04 +0000417 int locked = 0;
Willy Tarreau9f5cb432022-10-11 18:17:58 +0000418
Willy Tarreaua7536ef2022-10-11 18:31:04 +0000419 if (expire != HA_ATOMIC_LOAD(&ts->expire)) {
420 /* we'll need to set the expiration and to wake up the expiration timer .*/
421 HA_ATOMIC_STORE(&ts->expire, expire);
Willy Tarreaudbae89e2022-10-12 10:00:50 +0000422 stktable_requeue_exp(t, ts);
Willy Tarreaucb183642010-06-06 17:58:34 +0200423 }
Emeric Brun85e77c72010-09-23 18:16:52 +0200424
Emeric Brun819fc6f2017-06-13 19:37:32 +0200425 /* If sync is enabled */
426 if (t->sync_task) {
427 if (local) {
428 /* If this entry is not in the tree
Willy Tarreaua7536ef2022-10-11 18:31:04 +0000429 * or not scheduled for at least one peer.
430 */
431 if (!locked++)
432 HA_RWLOCK_WRLOCK(STK_TABLE_LOCK, &t->lock);
433
Emeric Brun819fc6f2017-06-13 19:37:32 +0200434 if (!ts->upd.node.leaf_p
435 || (int)(t->commitupdate - ts->upd.key) >= 0
436 || (int)(ts->upd.key - t->localupdate) >= 0) {
437 ts->upd.key = ++t->update;
438 t->localupdate = t->update;
439 eb32_delete(&ts->upd);
440 eb = eb32_insert(&t->updates, &ts->upd);
441 if (eb != &ts->upd) {
442 eb32_delete(eb);
443 eb32_insert(&t->updates, &ts->upd);
444 }
Emeric Brunaaf58602015-06-15 17:23:30 +0200445 }
Emeric Brun819fc6f2017-06-13 19:37:32 +0200446 task_wakeup(t->sync_task, TASK_WOKEN_MSG);
Emeric Brun85e77c72010-09-23 18:16:52 +0200447 }
Emeric Brun819fc6f2017-06-13 19:37:32 +0200448 else {
449 /* If this entry is not in the tree */
Willy Tarreaua7536ef2022-10-11 18:31:04 +0000450 if (!locked++)
451 HA_RWLOCK_WRLOCK(STK_TABLE_LOCK, &t->lock);
452
Emeric Brun819fc6f2017-06-13 19:37:32 +0200453 if (!ts->upd.node.leaf_p) {
454 ts->upd.key= (++t->update)+(2147483648U);
455 eb = eb32_insert(&t->updates, &ts->upd);
456 if (eb != &ts->upd) {
457 eb32_delete(eb);
458 eb32_insert(&t->updates, &ts->upd);
459 }
460 }
461 }
Emeric Brun85e77c72010-09-23 18:16:52 +0200462 }
Willy Tarreau9f5cb432022-10-11 18:17:58 +0000463
Willy Tarreaua7536ef2022-10-11 18:31:04 +0000464 if (decrefcnt) {
465 if (locked)
466 ts->ref_cnt--;
467 else {
468 HA_RWLOCK_RDLOCK(STK_TABLE_LOCK, &t->lock);
469 HA_ATOMIC_DEC(&ts->ref_cnt);
470 HA_RWLOCK_RDUNLOCK(STK_TABLE_LOCK, &t->lock);
471 }
472 }
473
474 if (locked)
475 HA_RWLOCK_WRUNLOCK(STK_TABLE_LOCK, &t->lock);
Willy Tarreaucb183642010-06-06 17:58:34 +0200476}
477
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200478/* Update the expiration timer for <ts> but do not touch its expiration node.
Emeric Brun819fc6f2017-06-13 19:37:32 +0200479 * The table's expiration timer is updated using the date of expiration coming from
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200480 * <t> stick-table configuration.
Emeric Brun819fc6f2017-06-13 19:37:32 +0200481 * The node will be also inserted into the update tree if needed, at a position
482 * considering the update is coming from a remote node
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200483 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200484void stktable_touch_remote(struct stktable *t, struct stksess *ts, int decrefcnt)
485{
Willy Tarreau9f5cb432022-10-11 18:17:58 +0000486 stktable_touch_with_exp(t, ts, 0, ts->expire, decrefcnt);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200487}
488
489/* Update the expiration timer for <ts> but do not touch its expiration node.
490 * The table's expiration timer is updated using the date of expiration coming from
491 * <t> stick-table configuration.
492 * The node will be also inserted into the update tree if needed, at a position
493 * considering the update was made locally
494 */
495void stktable_touch_local(struct stktable *t, struct stksess *ts, int decrefcnt)
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200496{
497 int expire = tick_add(now_ms, MS_TO_TICKS(t->expire));
498
Willy Tarreau9f5cb432022-10-11 18:17:58 +0000499 stktable_touch_with_exp(t, ts, 1, expire, decrefcnt);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200500}
Willy Tarreau4be073b2022-10-11 18:10:27 +0000501/* Just decrease the ref_cnt of the current session. Does nothing if <ts> is NULL.
502 * Note that we still need to take the read lock because a number of other places
503 * (including in Lua and peers) update the ref_cnt non-atomically under the write
504 * lock.
505 */
Willy Tarreau43e90352018-06-27 06:25:57 +0200506static void stktable_release(struct stktable *t, struct stksess *ts)
Emeric Brun819fc6f2017-06-13 19:37:32 +0200507{
Willy Tarreau43e90352018-06-27 06:25:57 +0200508 if (!ts)
509 return;
Willy Tarreau4be073b2022-10-11 18:10:27 +0000510 HA_RWLOCK_RDLOCK(STK_TABLE_LOCK, &t->lock);
511 HA_ATOMIC_DEC(&ts->ref_cnt);
512 HA_RWLOCK_RDUNLOCK(STK_TABLE_LOCK, &t->lock);
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200513}
514
Willy Tarreauf16d2b82010-06-06 15:38:59 +0200515/* Insert new sticky session <ts> in the table. It is assumed that it does not
516 * yet exist (the caller must check this). The table's timeout is updated if it
Willy Tarreaud2d3fd92022-10-11 15:09:46 +0200517 * is set. <ts> is returned if properly inserted, otherwise the one already
518 * present if any.
Willy Tarreauf16d2b82010-06-06 15:38:59 +0200519 */
Willy Tarreaud2d3fd92022-10-11 15:09:46 +0200520struct stksess *__stktable_store(struct stktable *t, struct stksess *ts)
Willy Tarreauf16d2b82010-06-06 15:38:59 +0200521{
Willy Tarreaud2d3fd92022-10-11 15:09:46 +0200522 struct ebmb_node *eb;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100523
Willy Tarreaud2d3fd92022-10-11 15:09:46 +0200524 eb = ebmb_insert(&t->keys, &ts->key, t->key_size);
525 if (likely(eb == &ts->key)) {
526 ts->exp.key = ts->expire;
527 eb32_insert(&t->exps, &ts->exp);
528 }
Willy Tarreaud2d3fd92022-10-11 15:09:46 +0200529 return ebmb_entry(eb, struct stksess, key); // most commonly this is <ts>
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200530}
531
Willy Tarreaueb23e3e2022-10-12 09:56:08 +0000532/* requeues the table's expiration task to take the recently added <ts> into
533 * account. This is performed atomically and doesn't require any lock.
534 */
Willy Tarreaudbae89e2022-10-12 10:00:50 +0000535void stktable_requeue_exp(struct stktable *t, const struct stksess *ts)
Willy Tarreaueb23e3e2022-10-12 09:56:08 +0000536{
Willy Tarreaudbae89e2022-10-12 10:00:50 +0000537 int old_exp, new_exp;
538 int expire = ts->expire;
539
Willy Tarreaueb23e3e2022-10-12 09:56:08 +0000540 if (!t->expire)
541 return;
Willy Tarreaudbae89e2022-10-12 10:00:50 +0000542
Willy Tarreau63427142022-11-14 17:33:02 +0100543 /* set the task's expire to the newest expiration date. */
Willy Tarreaudbae89e2022-10-12 10:00:50 +0000544 old_exp = HA_ATOMIC_LOAD(&t->exp_task->expire);
Willy Tarreau3238f792022-11-14 17:54:07 +0100545 new_exp = tick_first(expire, old_exp);
546
547 /* let's not go further if we're already up to date */
548 if (new_exp == old_exp)
549 return;
550
Willy Tarreaufbb934d2022-11-14 18:02:44 +0100551 HA_RWLOCK_WRLOCK(STK_TABLE_LOCK, &t->lock);
552
Willy Tarreau3238f792022-11-14 17:54:07 +0100553 while (new_exp != old_exp &&
554 !HA_ATOMIC_CAS(&t->exp_task->expire, &old_exp, new_exp)) {
555 __ha_cpu_relax();
Willy Tarreau63427142022-11-14 17:33:02 +0100556 new_exp = tick_first(expire, old_exp);
Willy Tarreau3238f792022-11-14 17:54:07 +0100557 }
Willy Tarreaudbae89e2022-10-12 10:00:50 +0000558
Willy Tarreaueb23e3e2022-10-12 09:56:08 +0000559 task_queue(t->exp_task);
Willy Tarreaufbb934d2022-11-14 18:02:44 +0100560
561 HA_RWLOCK_WRUNLOCK(STK_TABLE_LOCK, &t->lock);
Willy Tarreaueb23e3e2022-10-12 09:56:08 +0000562}
563
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200564/* Returns a valid or initialized stksess for the specified stktable_key in the
565 * specified table, or NULL if the key was NULL, or if no entry was found nor
Willy Tarreau47f22972022-10-11 15:22:42 +0200566 * could be created. The entry's expiration is updated. This function locks the
567 * table, and the refcount of the entry is increased.
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200568 */
Willy Tarreau47f22972022-10-11 15:22:42 +0200569struct stksess *stktable_get_entry(struct stktable *table, struct stktable_key *key)
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200570{
Willy Tarreau175aa062022-10-11 15:13:46 +0200571 struct stksess *ts, *ts2;
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200572
573 if (!key)
574 return NULL;
575
Willy Tarreau47f22972022-10-11 15:22:42 +0200576 ts = stktable_lookup_key(table, key);
577 if (ts)
578 return ts;
Emeric Brun819fc6f2017-06-13 19:37:32 +0200579
Willy Tarreau996f1a52022-10-11 16:19:35 +0200580 /* No such entry exists, let's try to create a new one. this doesn't
581 * require locking yet.
582 */
583
584 ts = stksess_new(table, key);
585 if (!ts)
586 return NULL;
587
588 /* Now we're certain to have a ts. We need to store it. For this we'll
Willy Tarreau47f22972022-10-11 15:22:42 +0200589 * need an exclusive access. We don't need an atomic upgrade, this is
590 * rare and an unlock+lock sequence will do the job fine. Given that
591 * this will not be atomic, the missing entry might appear in the mean
592 * tome so we have to be careful that the one we try to insert is the
593 * one we find.
594 */
Willy Tarreau47f22972022-10-11 15:22:42 +0200595
Willy Tarreau996f1a52022-10-11 16:19:35 +0200596 HA_RWLOCK_WRLOCK(STK_TABLE_LOCK, &table->lock);
Willy Tarreau47f22972022-10-11 15:22:42 +0200597
598 ts2 = __stktable_store(table, ts);
599 if (unlikely(ts2 != ts)) {
600 /* another entry was added in the mean time, let's
601 * switch to it.
602 */
603 __stksess_free(table, ts);
604 ts = ts2;
605 }
606
607 HA_ATOMIC_INC(&ts->ref_cnt);
Willy Tarreau76642222022-10-11 12:02:50 +0200608 HA_RWLOCK_WRUNLOCK(STK_TABLE_LOCK, &table->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200609
Willy Tarreaucbdb5282022-10-12 10:04:01 +0000610 stktable_requeue_exp(table, ts);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200611 return ts;
612}
613
614/* Lookup for an entry with the same key and store the submitted
Willy Tarreaue6288522022-10-12 09:13:14 +0000615 * stksess if not found. This function locks the table either shared or
616 * exclusively, and the refcount of the entry is increased.
Emeric Brun819fc6f2017-06-13 19:37:32 +0200617 */
Willy Tarreaue6288522022-10-12 09:13:14 +0000618struct stksess *stktable_set_entry(struct stktable *table, struct stksess *nts)
Emeric Brun819fc6f2017-06-13 19:37:32 +0200619{
620 struct stksess *ts;
621
Willy Tarreaue6288522022-10-12 09:13:14 +0000622 HA_RWLOCK_RDLOCK(STK_TABLE_LOCK, &table->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200623 ts = __stktable_lookup(table, nts);
Willy Tarreaue6288522022-10-12 09:13:14 +0000624 if (ts) {
625 HA_ATOMIC_INC(&ts->ref_cnt);
626 HA_RWLOCK_RDUNLOCK(STK_TABLE_LOCK, &table->lock);
627 return ts;
Emeric Brun819fc6f2017-06-13 19:37:32 +0200628 }
Willy Tarreaue6288522022-10-12 09:13:14 +0000629 ts = nts;
Emeric Brun819fc6f2017-06-13 19:37:32 +0200630
Willy Tarreaue6288522022-10-12 09:13:14 +0000631 /* let's increment it before switching to exclusive */
632 HA_ATOMIC_INC(&ts->ref_cnt);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200633
Willy Tarreaue6288522022-10-12 09:13:14 +0000634 if (HA_RWLOCK_TRYRDTOSK(STK_TABLE_LOCK, &table->lock) != 0) {
635 /* upgrade to seek lock failed, let's drop and take */
636 HA_RWLOCK_RDUNLOCK(STK_TABLE_LOCK, &table->lock);
637 HA_RWLOCK_WRLOCK(STK_TABLE_LOCK, &table->lock);
638 }
639 else
640 HA_RWLOCK_SKTOWR(STK_TABLE_LOCK, &table->lock);
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200641
Willy Tarreaue6288522022-10-12 09:13:14 +0000642 /* now we're write-locked */
643
644 __stktable_store(table, ts);
645 HA_RWLOCK_WRUNLOCK(STK_TABLE_LOCK, &table->lock);
Willy Tarreaucbdb5282022-10-12 10:04:01 +0000646
647 stktable_requeue_exp(table, ts);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200648 return ts;
649}
Willy Tarreaue6288522022-10-12 09:13:14 +0000650
Emeric Brun3bd697e2010-01-04 15:23:48 +0100651/*
Willy Tarreaufbb934d2022-11-14 18:02:44 +0100652 * Task processing function to trash expired sticky sessions. A pointer to the
653 * task itself is returned since it never dies.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100654 */
Willy Tarreaufbb934d2022-11-14 18:02:44 +0100655struct task *process_table_expire(struct task *task, void *context, unsigned int state)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100656{
Willy Tarreaufbb934d2022-11-14 18:02:44 +0100657 struct stktable *t = context;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100658 struct stksess *ts;
659 struct eb32_node *eb;
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200660 int looped = 0;
Willy Tarreau63427142022-11-14 17:33:02 +0100661 int exp_next;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100662
Willy Tarreau76642222022-10-11 12:02:50 +0200663 HA_RWLOCK_WRLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100664 eb = eb32_lookup_ge(&t->exps, now_ms - TIMER_LOOK_BACK);
665
666 while (1) {
667 if (unlikely(!eb)) {
668 /* we might have reached the end of the tree, typically because
669 * <now_ms> is in the first half and we're first scanning the last
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200670 * half. Let's loop back to the beginning of the tree now if we
671 * have not yet visited it.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100672 */
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200673 if (looped)
674 break;
675 looped = 1;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100676 eb = eb32_first(&t->exps);
677 if (likely(!eb))
678 break;
679 }
680
681 if (likely(tick_is_lt(now_ms, eb->key))) {
682 /* timer not expired yet, revisit it later */
Willy Tarreau63427142022-11-14 17:33:02 +0100683 exp_next = eb->key;
Willy Tarreau4d5f13c2017-11-05 11:04:47 +0100684 goto out_unlock;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100685 }
686
687 /* timer looks expired, detach it from the queue */
Willy Tarreau86257dc2010-06-06 12:57:10 +0200688 ts = eb32_entry(eb, struct stksess, exp);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100689 eb = eb32_next(eb);
690
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200691 /* don't delete an entry which is currently referenced */
692 if (ts->ref_cnt)
693 continue;
694
Willy Tarreau86257dc2010-06-06 12:57:10 +0200695 eb32_delete(&ts->exp);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100696
697 if (!tick_is_expired(ts->expire, now_ms)) {
698 if (!tick_isset(ts->expire))
699 continue;
700
Willy Tarreau86257dc2010-06-06 12:57:10 +0200701 ts->exp.key = ts->expire;
702 eb32_insert(&t->exps, &ts->exp);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100703
Willy Tarreau86257dc2010-06-06 12:57:10 +0200704 if (!eb || eb->key > ts->exp.key)
705 eb = &ts->exp;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100706 continue;
707 }
708
709 /* session expired, trash it */
Willy Tarreau86257dc2010-06-06 12:57:10 +0200710 ebmb_delete(&ts->key);
Emeric Brun85e77c72010-09-23 18:16:52 +0200711 eb32_delete(&ts->upd);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200712 __stksess_free(t, ts);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100713 }
714
715 /* We have found no task to expire in any tree */
Willy Tarreau63427142022-11-14 17:33:02 +0100716 exp_next = TICK_ETERNITY;
Willy Tarreaufbb934d2022-11-14 18:02:44 +0100717
Willy Tarreau4d5f13c2017-11-05 11:04:47 +0100718out_unlock:
Willy Tarreaufbb934d2022-11-14 18:02:44 +0100719 task->expire = exp_next;
Willy Tarreau76642222022-10-11 12:02:50 +0200720 HA_RWLOCK_WRUNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100721 return task;
722}
723
Willy Tarreauaea940e2010-06-06 11:56:36 +0200724/* Perform minimal stick table intializations, report 0 in case of error, 1 if OK. */
Emeric Brun3bd697e2010-01-04 15:23:48 +0100725int stktable_init(struct stktable *t)
726{
Remi Tricot-Le Breton208ff012021-05-12 17:39:04 +0200727 int peers_retval = 0;
Willy Tarreau56460ee2022-11-28 18:53:06 +0100728
729 t->hash_seed = XXH64(t->id, t->idlen, 0);
730
Emeric Brun3bd697e2010-01-04 15:23:48 +0100731 if (t->size) {
Emeric Brun819fc6f2017-06-13 19:37:32 +0200732 t->keys = EB_ROOT_UNIQUE;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100733 memset(&t->exps, 0, sizeof(t->exps));
Emeric Brun1c6235d2015-12-16 15:28:12 +0100734 t->updates = EB_ROOT_UNIQUE;
Amaury Denoyelle3e064882022-10-12 16:47:59 +0200735 HA_RWLOCK_INIT(&t->lock);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100736
Olivier Houchard52dabbc2018-11-14 17:54:36 +0100737 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 +0100738
Emeric Brun3bd697e2010-01-04 15:23:48 +0100739 if ( t->expire ) {
Willy Tarreaubeeabf52021-10-01 18:23:30 +0200740 t->exp_task = task_new_anywhere();
Willy Tarreau848522f2018-10-15 11:12:15 +0200741 if (!t->exp_task)
742 return 0;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100743 t->exp_task->process = process_table_expire;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100744 t->exp_task->context = (void *)t;
745 }
Christopher Fauletdfd10ab2021-10-06 14:24:19 +0200746 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 +0200747 peers_retval = peers_register_table(t->peers.p, t);
Emeric Brun32da3c42010-09-23 18:39:19 +0200748 }
749
Remi Tricot-Le Breton208ff012021-05-12 17:39:04 +0200750 return (t->pool != NULL) && !peers_retval;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100751 }
752 return 1;
753}
754
755/*
756 * Configuration keywords of known table types
757 */
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200758struct stktable_type stktable_types[SMP_TYPES] = {
759 [SMP_T_SINT] = { "integer", 0, 4 },
760 [SMP_T_IPV4] = { "ip", 0, 4 },
761 [SMP_T_IPV6] = { "ipv6", 0, 16 },
762 [SMP_T_STR] = { "string", STK_F_CUSTOM_KEYSIZE, 32 },
763 [SMP_T_BIN] = { "binary", STK_F_CUSTOM_KEYSIZE, 32 }
764};
Emeric Brun3bd697e2010-01-04 15:23:48 +0100765
766/*
767 * Parse table type configuration.
768 * Returns 0 on successful parsing, else 1.
769 * <myidx> is set at next configuration <args> index.
770 */
771int stktable_parse_type(char **args, int *myidx, unsigned long *type, size_t *key_size)
772{
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200773 for (*type = 0; *type < SMP_TYPES; (*type)++) {
774 if (!stktable_types[*type].kw)
775 continue;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100776 if (strcmp(args[*myidx], stktable_types[*type].kw) != 0)
777 continue;
778
779 *key_size = stktable_types[*type].default_size;
780 (*myidx)++;
781
Willy Tarreauaea940e2010-06-06 11:56:36 +0200782 if (stktable_types[*type].flags & STK_F_CUSTOM_KEYSIZE) {
Emeric Brun3bd697e2010-01-04 15:23:48 +0100783 if (strcmp("len", args[*myidx]) == 0) {
784 (*myidx)++;
785 *key_size = atol(args[*myidx]);
Emeric Brun485479d2010-09-23 18:02:19 +0200786 if (!*key_size)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100787 break;
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200788 if (*type == SMP_T_STR) {
Emeric Brun485479d2010-09-23 18:02:19 +0200789 /* null terminated string needs +1 for '\0'. */
790 (*key_size)++;
791 }
Emeric Brun3bd697e2010-01-04 15:23:48 +0100792 (*myidx)++;
793 }
794 }
795 return 0;
796 }
797 return 1;
798}
799
Emeric Brunc64a2a32021-06-30 18:01:02 +0200800/* reserve some space for data type <type>, there is 2 optionnals
801 * argument at <sa> and <sa2> to configure this data type and
802 * they can be NULL if unused for a given type.
803 * Returns PE_NONE (0) if OK or an error code among :
Willy Tarreau3b63ca22021-05-08 14:10:42 +0200804 * - PE_ENUM_OOR if <type> does not exist
805 * - PE_EXIST if <type> is already registered
Emeric Brunc64a2a32021-06-30 18:01:02 +0200806 * - PE_ARG_NOT_USE if <sa>/<sa2> was provided but not expected
807 * - PE_ARG_MISSING if <sa>/<sa2> was expected but not provided
808 * - PE_ARG_VALUE_OOR if type is an array and <sa> it out of array size range.
Willy Tarreau3b63ca22021-05-08 14:10:42 +0200809 */
Emeric Brunc64a2a32021-06-30 18:01:02 +0200810int stktable_alloc_data_type(struct stktable *t, int type, const char *sa, const char *sa2)
811
Willy Tarreau3b63ca22021-05-08 14:10:42 +0200812{
813 if (type >= STKTABLE_DATA_TYPES)
814 return PE_ENUM_OOR;
815
816 if (t->data_ofs[type])
817 /* already allocated */
818 return PE_EXIST;
819
Emeric Brunc64a2a32021-06-30 18:01:02 +0200820 t->data_nbelem[type] = 1;
821 if (stktable_data_types[type].is_array) {
822 /* arrays take their element count on first argument */
823 if (!sa)
824 return PE_ARG_MISSING;
825 t->data_nbelem[type] = atoi(sa);
826 if (!t->data_nbelem[type] || (t->data_nbelem[type] > STKTABLE_MAX_DT_ARRAY_SIZE))
827 return PE_ARG_VALUE_OOR;
828 sa = sa2;
829 }
830
Willy Tarreau3b63ca22021-05-08 14:10:42 +0200831 switch (stktable_data_types[type].arg_type) {
832 case ARG_T_NONE:
833 if (sa)
834 return PE_ARG_NOT_USED;
835 break;
836 case ARG_T_INT:
837 if (!sa)
838 return PE_ARG_MISSING;
839 t->data_arg[type].i = atoi(sa);
840 break;
841 case ARG_T_DELAY:
842 if (!sa)
843 return PE_ARG_MISSING;
844 sa = parse_time_err(sa, &t->data_arg[type].u, TIME_UNIT_MS);
845 if (sa)
846 return PE_ARG_INVC; /* invalid char */
847 break;
848 }
849
Emeric Brunc64a2a32021-06-30 18:01:02 +0200850 t->data_size += t->data_nbelem[type] * stktable_type_size(stktable_data_types[type].std_type);
Willy Tarreau3b63ca22021-05-08 14:10:42 +0200851 t->data_ofs[type] = -t->data_size;
852 return PE_NONE;
853}
854
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100855/*
Frédéric Lécaillec02766a2019-03-20 15:06:55 +0100856 * Parse a line with <linenum> as number in <file> configuration file to configure
857 * the stick-table with <t> as address and <id> as ID.
858 * <peers> provides the "peers" section pointer only if this function is called
859 * from a "peers" section.
860 * <nid> is the stick-table name which is sent over the network. It must be equal
861 * to <id> if this stick-table is parsed from a proxy section, and prefixed by <peers>
862 * "peers" section name followed by a '/' character if parsed from a "peers" section.
Ilya Shipitsind4259502020-04-08 01:07:56 +0500863 * This is the responsibility of the caller to check this.
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100864 * Return an error status with ERR_* flags set if required, 0 if no error was encountered.
865 */
866int parse_stick_table(const char *file, int linenum, char **args,
Frédéric Lécaillec02766a2019-03-20 15:06:55 +0100867 struct stktable *t, char *id, char *nid, struct peers *peers)
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100868{
869 int err_code = 0;
870 int idx = 1;
871 unsigned int val;
872
873 if (!id || !*id) {
874 ha_alert("parsing [%s:%d] : %s: ID not provided.\n", file, linenum, args[0]);
875 err_code |= ERR_ALERT | ERR_ABORT;
876 goto out;
877 }
878
879 /* Store the "peers" section if this function is called from a "peers" section. */
880 if (peers) {
881 t->peers.p = peers;
882 idx++;
883 }
884
885 t->id = id;
Frédéric Lécaille36d15652022-10-17 14:58:19 +0200886 t->idlen = strlen(id);
Frédéric Lécaillec02766a2019-03-20 15:06:55 +0100887 t->nid = nid;
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100888 t->type = (unsigned int)-1;
889 t->conf.file = file;
890 t->conf.line = linenum;
891
892 while (*args[idx]) {
893 const char *err;
894
895 if (strcmp(args[idx], "size") == 0) {
896 idx++;
897 if (!*(args[idx])) {
898 ha_alert("parsing [%s:%d] : %s: missing argument after '%s'.\n",
899 file, linenum, args[0], args[idx-1]);
900 err_code |= ERR_ALERT | ERR_FATAL;
901 goto out;
902 }
903 if ((err = parse_size_err(args[idx], &t->size))) {
904 ha_alert("parsing [%s:%d] : %s: unexpected character '%c' in argument of '%s'.\n",
905 file, linenum, args[0], *err, args[idx-1]);
906 err_code |= ERR_ALERT | ERR_FATAL;
907 goto out;
908 }
909 idx++;
910 }
911 /* This argument does not exit in "peers" section. */
912 else if (!peers && strcmp(args[idx], "peers") == 0) {
913 idx++;
914 if (!*(args[idx])) {
915 ha_alert("parsing [%s:%d] : %s: missing argument after '%s'.\n",
916 file, linenum, args[0], args[idx-1]);
917 err_code |= ERR_ALERT | ERR_FATAL;
918 goto out;
919 }
920 t->peers.name = strdup(args[idx++]);
921 }
922 else if (strcmp(args[idx], "expire") == 0) {
923 idx++;
924 if (!*(args[idx])) {
925 ha_alert("parsing [%s:%d] : %s: missing argument after '%s'.\n",
926 file, linenum, args[0], args[idx-1]);
927 err_code |= ERR_ALERT | ERR_FATAL;
928 goto out;
929 }
930 err = parse_time_err(args[idx], &val, TIME_UNIT_MS);
Willy Tarreau9faebe32019-06-07 19:00:37 +0200931 if (err == PARSE_TIME_OVER) {
932 ha_alert("parsing [%s:%d]: %s: timer overflow in argument <%s> to <%s>, maximum value is 2147483647 ms (~24.8 days).\n",
933 file, linenum, args[0], args[idx], args[idx-1]);
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100934 err_code |= ERR_ALERT | ERR_FATAL;
935 goto out;
936 }
Willy Tarreau9faebe32019-06-07 19:00:37 +0200937 else if (err == PARSE_TIME_UNDER) {
938 ha_alert("parsing [%s:%d]: %s: timer underflow in argument <%s> to <%s>, minimum non-null value is 1 ms.\n",
939 file, linenum, args[0], args[idx], args[idx-1]);
940 err_code |= ERR_ALERT | ERR_FATAL;
941 goto out;
942 }
943 else if (err) {
944 ha_alert("parsing [%s:%d] : %s: unexpected character '%c' in argument of '%s'.\n",
945 file, linenum, args[0], *err, args[idx-1]);
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100946 err_code |= ERR_ALERT | ERR_FATAL;
947 goto out;
948 }
949 t->expire = val;
950 idx++;
951 }
952 else if (strcmp(args[idx], "nopurge") == 0) {
953 t->nopurge = 1;
954 idx++;
955 }
956 else if (strcmp(args[idx], "type") == 0) {
957 idx++;
958 if (stktable_parse_type(args, &idx, &t->type, &t->key_size) != 0) {
959 ha_alert("parsing [%s:%d] : %s: unknown type '%s'.\n",
960 file, linenum, args[0], args[idx]);
961 err_code |= ERR_ALERT | ERR_FATAL;
962 goto out;
963 }
964 /* idx already points to next arg */
965 }
966 else if (strcmp(args[idx], "store") == 0) {
967 int type, err;
Emeric Brunc64a2a32021-06-30 18:01:02 +0200968 char *cw, *nw, *sa, *sa2;
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100969
970 idx++;
971 nw = args[idx];
972 while (*nw) {
973 /* the "store" keyword supports a comma-separated list */
974 cw = nw;
975 sa = NULL; /* store arg */
Emeric Brunc64a2a32021-06-30 18:01:02 +0200976 sa2 = NULL;
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100977 while (*nw && *nw != ',') {
978 if (*nw == '(') {
979 *nw = 0;
980 sa = ++nw;
981 while (*nw != ')') {
982 if (!*nw) {
983 ha_alert("parsing [%s:%d] : %s: missing closing parenthesis after store option '%s'.\n",
984 file, linenum, args[0], cw);
985 err_code |= ERR_ALERT | ERR_FATAL;
986 goto out;
987 }
Emeric Brunc64a2a32021-06-30 18:01:02 +0200988 if (*nw == ',') {
989 *nw = '\0';
990 sa2 = nw + 1;
991 }
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100992 nw++;
993 }
994 *nw = '\0';
995 }
996 nw++;
997 }
998 if (*nw)
999 *nw++ = '\0';
1000 type = stktable_get_data_type(cw);
1001 if (type < 0) {
1002 ha_alert("parsing [%s:%d] : %s: unknown store option '%s'.\n",
1003 file, linenum, args[0], cw);
1004 err_code |= ERR_ALERT | ERR_FATAL;
1005 goto out;
1006 }
1007
Emeric Brunc64a2a32021-06-30 18:01:02 +02001008 err = stktable_alloc_data_type(t, type, sa, sa2);
Frédéric Lécailled456aa42019-03-08 14:47:00 +01001009 switch (err) {
1010 case PE_NONE: break;
1011 case PE_EXIST:
1012 ha_warning("parsing [%s:%d]: %s: store option '%s' already enabled, ignored.\n",
1013 file, linenum, args[0], cw);
1014 err_code |= ERR_WARN;
1015 break;
1016
1017 case PE_ARG_MISSING:
1018 ha_alert("parsing [%s:%d] : %s: missing argument to store option '%s'.\n",
1019 file, linenum, args[0], cw);
1020 err_code |= ERR_ALERT | ERR_FATAL;
1021 goto out;
1022
1023 case PE_ARG_NOT_USED:
1024 ha_alert("parsing [%s:%d] : %s: unexpected argument to store option '%s'.\n",
1025 file, linenum, args[0], cw);
1026 err_code |= ERR_ALERT | ERR_FATAL;
1027 goto out;
Emeric Brunc64a2a32021-06-30 18:01:02 +02001028 case PE_ARG_VALUE_OOR:
1029 ha_alert("parsing [%s:%d] : %s: array size is out of allowed range (1-%d) for store option '%s'.\n",
1030 file, linenum, args[0], STKTABLE_MAX_DT_ARRAY_SIZE, cw);
1031 err_code |= ERR_ALERT | ERR_FATAL;
1032 goto out;
Frédéric Lécailled456aa42019-03-08 14:47:00 +01001033
1034 default:
1035 ha_alert("parsing [%s:%d] : %s: error when processing store option '%s'.\n",
1036 file, linenum, args[0], cw);
1037 err_code |= ERR_ALERT | ERR_FATAL;
1038 goto out;
1039 }
1040 }
1041 idx++;
Emeric Brunf7ab0bf2021-06-30 18:58:22 +02001042 if (t->data_ofs[STKTABLE_DT_GPT] && t->data_ofs[STKTABLE_DT_GPT0]) {
1043 ha_alert("parsing [%s:%d] : %s: simultaneous usage of 'gpt' and 'gpt0' in a same table is not permitted as 'gpt' overrides 'gpt0'.\n",
1044 file, linenum, args[0]);
1045 err_code |= ERR_ALERT | ERR_FATAL;
1046 goto out;
1047 }
Emeric Brun726783d2021-06-30 19:06:43 +02001048 else if (t->data_ofs[STKTABLE_DT_GPC] && (t->data_ofs[STKTABLE_DT_GPC0] || t->data_ofs[STKTABLE_DT_GPC1])) {
1049 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",
1050 file, linenum, args[0]);
1051 err_code |= ERR_ALERT | ERR_FATAL;
1052 goto out;
1053 }
1054 else if (t->data_ofs[STKTABLE_DT_GPC_RATE] && (t->data_ofs[STKTABLE_DT_GPC0_RATE] || t->data_ofs[STKTABLE_DT_GPC1_RATE])) {
1055 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",
1056 file, linenum, args[0]);
1057 err_code |= ERR_ALERT | ERR_FATAL;
1058 goto out;
1059 }
Frédéric Lécailled456aa42019-03-08 14:47:00 +01001060 }
Thayne McCombs92149f92020-11-20 01:28:26 -07001061 else if (strcmp(args[idx], "srvkey") == 0) {
1062 char *keytype;
1063 idx++;
1064 keytype = args[idx];
1065 if (strcmp(keytype, "name") == 0) {
1066 t->server_key_type = STKTABLE_SRV_NAME;
1067 }
1068 else if (strcmp(keytype, "addr") == 0) {
1069 t->server_key_type = STKTABLE_SRV_ADDR;
1070 }
1071 else {
1072 ha_alert("parsing [%s:%d] : %s : unknown server key type '%s'.\n",
1073 file, linenum, args[0], keytype);
1074 err_code |= ERR_ALERT | ERR_FATAL;
1075 goto out;
1076
1077 }
1078 idx++;
1079 }
Frédéric Lécailled456aa42019-03-08 14:47:00 +01001080 else {
1081 ha_alert("parsing [%s:%d] : %s: unknown argument '%s'.\n",
1082 file, linenum, args[0], args[idx]);
1083 err_code |= ERR_ALERT | ERR_FATAL;
1084 goto out;
1085 }
1086 }
1087
1088 if (!t->size) {
1089 ha_alert("parsing [%s:%d] : %s: missing size.\n",
1090 file, linenum, args[0]);
1091 err_code |= ERR_ALERT | ERR_FATAL;
1092 goto out;
1093 }
1094
1095 if (t->type == (unsigned int)-1) {
1096 ha_alert("parsing [%s:%d] : %s: missing type.\n",
1097 file, linenum, args[0]);
1098 err_code |= ERR_ALERT | ERR_FATAL;
1099 goto out;
1100 }
1101
1102 out:
1103 return err_code;
1104}
1105
Willy Tarreau8fed9032014-07-03 17:02:46 +02001106/* Prepares a stktable_key from a sample <smp> to search into table <t>.
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001107 * Note that the sample *is* modified and that the returned key may point
1108 * to it, so the sample must not be modified afterwards before the lookup.
Willy Tarreau8fed9032014-07-03 17:02:46 +02001109 * Returns NULL if the sample could not be converted (eg: no matching type),
1110 * otherwise a pointer to the static stktable_key filled with what is needed
1111 * for the lookup.
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001112 */
Willy Tarreau8fed9032014-07-03 17:02:46 +02001113struct stktable_key *smp_to_stkey(struct sample *smp, struct stktable *t)
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001114{
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001115 /* Convert sample. */
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +02001116 if (!sample_convert(smp, t->type))
Willy Tarreau7fc1c6e2012-04-26 11:03:17 +02001117 return NULL;
1118
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001119 /* Fill static_table_key. */
1120 switch (t->type) {
Emeric Brun485479d2010-09-23 18:02:19 +02001121
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +02001122 case SMP_T_IPV4:
Christopher Fauletca20d022017-08-29 15:30:31 +02001123 static_table_key.key = &smp->data.u.ipv4;
1124 static_table_key.key_len = 4;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001125 break;
Emeric Brun485479d2010-09-23 18:02:19 +02001126
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +02001127 case SMP_T_IPV6:
Christopher Fauletca20d022017-08-29 15:30:31 +02001128 static_table_key.key = &smp->data.u.ipv6;
1129 static_table_key.key_len = 16;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001130 break;
Emeric Brun485479d2010-09-23 18:02:19 +02001131
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +02001132 case SMP_T_SINT:
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001133 /* The stick table require a 32bit unsigned int, "sint" is a
1134 * signed 64 it, so we can convert it inplace.
1135 */
Willy Tarreau28c63c12019-10-23 06:21:05 +02001136 smp->data.u.sint = (unsigned int)smp->data.u.sint;
Christopher Fauletca20d022017-08-29 15:30:31 +02001137 static_table_key.key = &smp->data.u.sint;
1138 static_table_key.key_len = 4;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001139 break;
1140
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +02001141 case SMP_T_STR:
Willy Tarreauce6955e2016-08-09 11:59:12 +02001142 if (!smp_make_safe(smp))
1143 return NULL;
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001144 static_table_key.key = smp->data.u.str.area;
1145 static_table_key.key_len = smp->data.u.str.data;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001146 break;
Emeric Brun485479d2010-09-23 18:02:19 +02001147
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +02001148 case SMP_T_BIN:
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001149 if (smp->data.u.str.data < t->key_size) {
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001150 /* This type needs padding with 0. */
Willy Tarreauf65c6c02016-08-09 12:08:41 +02001151 if (!smp_make_rw(smp))
1152 return NULL;
1153
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001154 if (smp->data.u.str.size < t->key_size)
1155 if (!smp_dup(smp))
1156 return NULL;
1157 if (smp->data.u.str.size < t->key_size)
1158 return NULL;
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001159 memset(smp->data.u.str.area + smp->data.u.str.data, 0,
1160 t->key_size - smp->data.u.str.data);
1161 smp->data.u.str.data = t->key_size;
Emeric Brun485479d2010-09-23 18:02:19 +02001162 }
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001163 static_table_key.key = smp->data.u.str.area;
1164 static_table_key.key_len = smp->data.u.str.data;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001165 break;
Emeric Brun485479d2010-09-23 18:02:19 +02001166
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001167 default: /* impossible case. */
1168 return NULL;
Emeric Brun485479d2010-09-23 18:02:19 +02001169 }
1170
Christopher Fauletca20d022017-08-29 15:30:31 +02001171 return &static_table_key;
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001172}
1173
1174/*
Willy Tarreau8fed9032014-07-03 17:02:46 +02001175 * Process a fetch + format conversion as defined by the sample expression <expr>
1176 * on request or response considering the <opt> parameter. Returns either NULL if
1177 * no key could be extracted, or a pointer to the converted result stored in
1178 * static_table_key in format <table_type>. If <smp> is not NULL, it will be reset
1179 * and its flags will be initialized so that the caller gets a copy of the input
Willy Tarreau6bcb0a82014-07-30 08:56:35 +02001180 * sample, and knows why it was not accepted (eg: SMP_F_MAY_CHANGE is present
1181 * without SMP_OPT_FINAL). The output will be usable like this :
1182 *
1183 * return MAY_CHANGE FINAL Meaning for the sample
1184 * NULL 0 * Not present and will never be (eg: header)
1185 * NULL 1 0 Not present or unstable, could change (eg: req_len)
1186 * NULL 1 1 Not present, will not change anymore
1187 * smp 0 * Present and will not change (eg: header)
1188 * smp 1 0 not possible
1189 * smp 1 1 Present, last known value (eg: request length)
Willy Tarreau8fed9032014-07-03 17:02:46 +02001190 */
Willy Tarreau192252e2015-04-04 01:47:55 +02001191struct stktable_key *stktable_fetch_key(struct stktable *t, struct proxy *px, struct session *sess, struct stream *strm,
Willy Tarreau8fed9032014-07-03 17:02:46 +02001192 unsigned int opt, struct sample_expr *expr, struct sample *smp)
1193{
1194 if (smp)
1195 memset(smp, 0, sizeof(*smp));
1196
Willy Tarreau192252e2015-04-04 01:47:55 +02001197 smp = sample_process(px, sess, strm, opt, expr, smp);
Willy Tarreau8fed9032014-07-03 17:02:46 +02001198 if (!smp)
1199 return NULL;
1200
1201 if ((smp->flags & SMP_F_MAY_CHANGE) && !(opt & SMP_OPT_FINAL))
1202 return NULL; /* we can only use stable samples */
1203
1204 return smp_to_stkey(smp, t);
1205}
1206
1207/*
Willy Tarreau12785782012-04-27 21:37:17 +02001208 * Returns 1 if sample expression <expr> result can be converted to table key of
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001209 * type <table_type>, otherwise zero. Used in configuration check.
1210 */
Willy Tarreau12785782012-04-27 21:37:17 +02001211int stktable_compatible_sample(struct sample_expr *expr, unsigned long table_type)
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001212{
Thierry FOURNIERf73eb8f2013-11-27 15:30:55 +01001213 int out_type;
1214
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +02001215 if (table_type >= SMP_TYPES || !stktable_types[table_type].kw)
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001216 return 0;
1217
Thierry FOURNIERf73eb8f2013-11-27 15:30:55 +01001218 out_type = smp_expr_output_type(expr);
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001219
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001220 /* Convert sample. */
1221 if (!sample_casts[out_type][table_type])
Thierry FOURNIERf73eb8f2013-11-27 15:30:55 +01001222 return 0;
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001223
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001224 return 1;
1225}
Emeric Brun3bd697e2010-01-04 15:23:48 +01001226
Willy Tarreauedee1d62014-07-15 16:44:27 +02001227/* Extra data types processing : after the last one, some room may remain
1228 * before STKTABLE_DATA_TYPES that may be used to register extra data types
1229 * at run time.
1230 */
Willy Tarreau08d5f982010-06-06 13:34:54 +02001231struct stktable_data_type stktable_data_types[STKTABLE_DATA_TYPES] = {
Willy Tarreau3b9c6e02010-07-18 08:04:30 +02001232 [STKTABLE_DT_SERVER_ID] = { .name = "server_id", .std_type = STD_T_SINT },
Thierry FOURNIER3cf11112015-07-28 08:57:05 +02001233 [STKTABLE_DT_GPT0] = { .name = "gpt0", .std_type = STD_T_UINT },
Willy Tarreau3b9c6e02010-07-18 08:04:30 +02001234 [STKTABLE_DT_GPC0] = { .name = "gpc0", .std_type = STD_T_UINT },
Willy Tarreauba2ffd12013-05-29 15:54:14 +02001235 [STKTABLE_DT_GPC0_RATE] = { .name = "gpc0_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
Willy Tarreau3b9c6e02010-07-18 08:04:30 +02001236 [STKTABLE_DT_CONN_CNT] = { .name = "conn_cnt", .std_type = STD_T_UINT },
1237 [STKTABLE_DT_CONN_RATE] = { .name = "conn_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
Willy Tarreaudb2ab822021-10-08 17:53:12 +02001238 [STKTABLE_DT_CONN_CUR] = { .name = "conn_cur", .std_type = STD_T_UINT, .is_local = 1 },
Willy Tarreau3b9c6e02010-07-18 08:04:30 +02001239 [STKTABLE_DT_SESS_CNT] = { .name = "sess_cnt", .std_type = STD_T_UINT },
1240 [STKTABLE_DT_SESS_RATE] = { .name = "sess_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
1241 [STKTABLE_DT_HTTP_REQ_CNT] = { .name = "http_req_cnt", .std_type = STD_T_UINT },
1242 [STKTABLE_DT_HTTP_REQ_RATE] = { .name = "http_req_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
1243 [STKTABLE_DT_HTTP_ERR_CNT] = { .name = "http_err_cnt", .std_type = STD_T_UINT },
1244 [STKTABLE_DT_HTTP_ERR_RATE] = { .name = "http_err_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
1245 [STKTABLE_DT_BYTES_IN_CNT] = { .name = "bytes_in_cnt", .std_type = STD_T_ULL },
1246 [STKTABLE_DT_BYTES_IN_RATE] = { .name = "bytes_in_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
1247 [STKTABLE_DT_BYTES_OUT_CNT] = { .name = "bytes_out_cnt", .std_type = STD_T_ULL },
1248 [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 +01001249 [STKTABLE_DT_GPC1] = { .name = "gpc1", .std_type = STD_T_UINT },
1250 [STKTABLE_DT_GPC1_RATE] = { .name = "gpc1_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
Thayne McCombs92149f92020-11-20 01:28:26 -07001251 [STKTABLE_DT_SERVER_KEY] = { .name = "server_key", .std_type = STD_T_DICT },
Willy Tarreau826f3ab2021-02-10 12:07:15 +01001252 [STKTABLE_DT_HTTP_FAIL_CNT] = { .name = "http_fail_cnt", .std_type = STD_T_UINT },
1253 [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 +02001254 [STKTABLE_DT_GPT] = { .name = "gpt", .std_type = STD_T_UINT, .is_array = 1 },
Emeric Brun4d7ada82021-06-30 19:04:16 +02001255 [STKTABLE_DT_GPC] = { .name = "gpc", .std_type = STD_T_UINT, .is_array = 1 },
1256 [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 +02001257};
1258
Willy Tarreauedee1d62014-07-15 16:44:27 +02001259/* Registers stick-table extra data type with index <idx>, name <name>, type
1260 * <std_type> and arg type <arg_type>. If the index is negative, the next free
1261 * index is automatically allocated. The allocated index is returned, or -1 if
1262 * no free index was found or <name> was already registered. The <name> is used
1263 * directly as a pointer, so if it's not stable, the caller must allocate it.
1264 */
1265int stktable_register_data_store(int idx, const char *name, int std_type, int arg_type)
1266{
1267 if (idx < 0) {
1268 for (idx = 0; idx < STKTABLE_DATA_TYPES; idx++) {
1269 if (!stktable_data_types[idx].name)
1270 break;
1271
1272 if (strcmp(stktable_data_types[idx].name, name) == 0)
1273 return -1;
1274 }
1275 }
1276
1277 if (idx >= STKTABLE_DATA_TYPES)
1278 return -1;
1279
1280 if (stktable_data_types[idx].name != NULL)
1281 return -1;
1282
1283 stktable_data_types[idx].name = name;
1284 stktable_data_types[idx].std_type = std_type;
1285 stktable_data_types[idx].arg_type = arg_type;
1286 return idx;
1287}
1288
Willy Tarreau08d5f982010-06-06 13:34:54 +02001289/*
1290 * Returns the data type number for the stktable_data_type whose name is <name>,
1291 * or <0 if not found.
1292 */
1293int stktable_get_data_type(char *name)
1294{
1295 int type;
1296
1297 for (type = 0; type < STKTABLE_DATA_TYPES; type++) {
Willy Tarreauedee1d62014-07-15 16:44:27 +02001298 if (!stktable_data_types[type].name)
1299 continue;
Willy Tarreau08d5f982010-06-06 13:34:54 +02001300 if (strcmp(name, stktable_data_types[type].name) == 0)
1301 return type;
1302 }
Thayne McCombs92149f92020-11-20 01:28:26 -07001303 /* For backwards compatibility */
1304 if (strcmp(name, "server_name") == 0)
1305 return STKTABLE_DT_SERVER_KEY;
Willy Tarreau08d5f982010-06-06 13:34:54 +02001306 return -1;
1307}
1308
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001309/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1310 * it up into this table. Returns true if found, false otherwise. The input
1311 * type is STR so that input samples are converted to string (since all types
1312 * can be converted to strings), then the function casts the string again into
1313 * the table's type. This is a double conversion, but in the future we might
1314 * support automatic input types to perform the cast on the fly.
1315 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001316static int sample_conv_in_table(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001317{
1318 struct stktable *t;
1319 struct stktable_key *key;
1320 struct stksess *ts;
1321
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001322 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001323
1324 key = smp_to_stkey(smp, t);
1325 if (!key)
1326 return 0;
1327
1328 ts = stktable_lookup_key(t, key);
1329
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001330 smp->data.type = SMP_T_BOOL;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001331 smp->data.u.sint = !!ts;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001332 smp->flags = SMP_F_VOL_TEST;
Willy Tarreau43e90352018-06-27 06:25:57 +02001333 stktable_release(t, ts);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001334 return 1;
1335}
1336
1337/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1338 * it up into this table. Returns the data rate received from clients in bytes/s
1339 * if the key is present in the table, otherwise zero, so that comparisons can
1340 * be easily performed. If the inspected parameter is not stored in the table,
1341 * <not found> is returned.
1342 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001343static int sample_conv_table_bytes_in_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001344{
1345 struct stktable *t;
1346 struct stktable_key *key;
1347 struct stksess *ts;
1348 void *ptr;
1349
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001350 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001351
1352 key = smp_to_stkey(smp, t);
1353 if (!key)
1354 return 0;
1355
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001356 ts = stktable_lookup_key(t, key);
1357
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001358 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001359 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001360 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001361
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001362 if (!ts) /* key not present */
1363 return 1;
1364
1365 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_IN_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001366 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001367 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Daniel Corbett3e60b112018-05-27 09:47:12 -04001368 t->data_arg[STKTABLE_DT_BYTES_IN_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001369
Daniel Corbett3e60b112018-05-27 09:47:12 -04001370 stktable_release(t, ts);
1371 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001372}
1373
1374/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1375 * it up into this table. Returns the cumulated number of connections for the key
1376 * if the key is present in the table, otherwise zero, so that comparisons can
1377 * be easily performed. If the inspected parameter is not stored in the table,
1378 * <not found> is returned.
1379 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001380static int sample_conv_table_conn_cnt(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001381{
1382 struct stktable *t;
1383 struct stktable_key *key;
1384 struct stksess *ts;
1385 void *ptr;
1386
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001387 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001388
1389 key = smp_to_stkey(smp, t);
1390 if (!key)
1391 return 0;
1392
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001393 ts = stktable_lookup_key(t, key);
1394
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001395 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001396 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001397 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001398
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001399 if (!ts) /* key not present */
1400 return 1;
1401
1402 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_CONN_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001403 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001404 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001405
Daniel Corbett3e60b112018-05-27 09:47:12 -04001406 stktable_release(t, ts);
1407 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001408}
1409
1410/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1411 * it up into this table. Returns the number of concurrent connections for the
1412 * key if the key is present in the table, otherwise zero, so that comparisons
1413 * can be easily performed. If the inspected parameter is not stored in the
1414 * table, <not found> is returned.
1415 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001416static int sample_conv_table_conn_cur(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001417{
1418 struct stktable *t;
1419 struct stktable_key *key;
1420 struct stksess *ts;
1421 void *ptr;
1422
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001423 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001424
1425 key = smp_to_stkey(smp, t);
1426 if (!key)
1427 return 0;
1428
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001429 ts = stktable_lookup_key(t, key);
1430
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001431 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001432 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001433 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001434
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001435 if (!ts) /* key not present */
1436 return 1;
1437
1438 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_CONN_CUR);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001439 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001440 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001441
Daniel Corbett3e60b112018-05-27 09:47:12 -04001442 stktable_release(t, ts);
1443 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001444}
1445
1446/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1447 * it up into this table. Returns the rate of incoming connections from the key
1448 * if the key is present in the table, otherwise zero, so that comparisons can
1449 * be easily performed. If the inspected parameter is not stored in the table,
1450 * <not found> is returned.
1451 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001452static int sample_conv_table_conn_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001453{
1454 struct stktable *t;
1455 struct stktable_key *key;
1456 struct stksess *ts;
1457 void *ptr;
1458
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001459 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001460
1461 key = smp_to_stkey(smp, t);
1462 if (!key)
1463 return 0;
1464
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001465 ts = stktable_lookup_key(t, key);
1466
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001467 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001468 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001469 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001470
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001471 if (!ts) /* key not present */
1472 return 1;
1473
1474 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_CONN_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001475 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001476 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Daniel Corbett3e60b112018-05-27 09:47:12 -04001477 t->data_arg[STKTABLE_DT_CONN_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001478
Daniel Corbett3e60b112018-05-27 09:47:12 -04001479 stktable_release(t, ts);
1480 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001481}
1482
1483/* 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 +02001484 * it up into this table. Returns the expiration delay for the key if the key is
1485 * present in the table, otherwise the default value provided as second argument
1486 * if any, if not (no default value), <not found> is returned.
1487 */
1488static int sample_conv_table_expire(const struct arg *arg_p, struct sample *smp, void *private)
1489{
1490 struct stktable *t;
1491 struct stktable_key *key;
1492 struct stksess *ts;
1493
1494 t = arg_p[0].data.t;
1495
1496 key = smp_to_stkey(smp, t);
1497 if (!key)
1498 return 0;
1499
1500 ts = stktable_lookup_key(t, key);
1501
1502 smp->flags = SMP_F_VOL_TEST;
1503 smp->data.type = SMP_T_SINT;
1504 smp->data.u.sint = 0;
1505
1506 if (!ts) { /* key not present */
1507 if (arg_p[1].type == ARGT_STOP)
1508 return 0;
1509
1510 /* default value */
1511 smp->data.u.sint = arg_p[1].data.sint;
1512 return 1;
1513 }
1514
1515 smp->data.u.sint = tick_remain(now_ms, ts->expire);
1516
1517 stktable_release(t, ts);
1518 return 1;
1519}
1520
1521/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1522 * it up into this table. Returns the time the key remains unused if the key is
1523 * present in the table, otherwise the default value provided as second argument
1524 * if any, if not (no default value), <not found> is returned.
1525 */
1526static int sample_conv_table_idle(const struct arg *arg_p, struct sample *smp, void *private)
1527{
1528 struct stktable *t;
1529 struct stktable_key *key;
1530 struct stksess *ts;
1531
1532 t = arg_p[0].data.t;
1533
1534 key = smp_to_stkey(smp, t);
1535 if (!key)
1536 return 0;
1537
1538 ts = stktable_lookup_key(t, key);
1539
1540 smp->flags = SMP_F_VOL_TEST;
1541 smp->data.type = SMP_T_SINT;
1542 smp->data.u.sint = 0;
1543
1544 if (!ts) { /* key not present */
1545 if (arg_p[1].type == ARGT_STOP)
1546 return 0;
1547
1548 /* default value */
1549 smp->data.u.sint = arg_p[1].data.sint;
1550 return 1;
1551 }
1552
1553 smp->data.u.sint = tick_remain(tick_remain(now_ms, ts->expire), t->expire);
1554
1555 stktable_release(t, ts);
1556 return 1;
1557}
1558
1559/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001560 * it up into this table. Returns the data rate sent to clients in bytes/s
1561 * if the key is present in the table, otherwise zero, so that comparisons can
1562 * be easily performed. If the inspected parameter is not stored in the table,
1563 * <not found> is returned.
1564 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001565static int sample_conv_table_bytes_out_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001566{
1567 struct stktable *t;
1568 struct stktable_key *key;
1569 struct stksess *ts;
1570 void *ptr;
1571
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001572 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001573
1574 key = smp_to_stkey(smp, t);
1575 if (!key)
1576 return 0;
1577
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001578 ts = stktable_lookup_key(t, key);
1579
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001580 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001581 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001582 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001583
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001584 if (!ts) /* key not present */
1585 return 1;
1586
1587 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_OUT_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001588 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001589 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Daniel Corbett3e60b112018-05-27 09:47:12 -04001590 t->data_arg[STKTABLE_DT_BYTES_OUT_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001591
Daniel Corbett3e60b112018-05-27 09:47:12 -04001592 stktable_release(t, ts);
1593 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001594}
1595
Emeric Brun877b0b52021-06-30 18:57:49 +02001596/* Casts sample <smp> to the type of the table specified in arg_p(1), and looks
1597 * it up into this table. Returns the value of the GPT[arg_p(0)] tag for the key
1598 * if the key is present in the table, otherwise false, so that comparisons can
1599 * be easily performed. If the inspected parameter is not stored in the table,
1600 * <not found> is returned.
1601 */
1602static int sample_conv_table_gpt(const struct arg *arg_p, struct sample *smp, void *private)
1603{
1604 struct stktable *t;
1605 struct stktable_key *key;
1606 struct stksess *ts;
1607 void *ptr;
1608 unsigned int idx;
1609
1610 idx = arg_p[0].data.sint;
1611
1612 t = arg_p[1].data.t;
1613
1614 key = smp_to_stkey(smp, t);
1615 if (!key)
1616 return 0;
1617
1618 ts = stktable_lookup_key(t, key);
1619
1620 smp->flags = SMP_F_VOL_TEST;
1621 smp->data.type = SMP_T_SINT;
1622 smp->data.u.sint = 0;
1623
1624 if (!ts) /* key not present */
1625 return 1;
1626
1627 ptr = stktable_data_ptr_idx(t, ts, STKTABLE_DT_GPT, idx);
1628 if (ptr)
1629 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
1630
1631 stktable_release(t, ts);
1632 return !!ptr;
1633}
1634
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001635/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001636 * it up into this table. Returns the value of the GPT0 tag for the key
1637 * if the key is present in the table, otherwise false, so that comparisons can
1638 * be easily performed. If the inspected parameter is not stored in the table,
1639 * <not found> is returned.
1640 */
1641static int sample_conv_table_gpt0(const struct arg *arg_p, struct sample *smp, void *private)
1642{
1643 struct stktable *t;
1644 struct stktable_key *key;
1645 struct stksess *ts;
1646 void *ptr;
1647
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001648 t = arg_p[0].data.t;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001649
1650 key = smp_to_stkey(smp, t);
1651 if (!key)
1652 return 0;
1653
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001654 ts = stktable_lookup_key(t, key);
1655
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001656 smp->flags = SMP_F_VOL_TEST;
1657 smp->data.type = SMP_T_SINT;
1658 smp->data.u.sint = 0;
1659
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001660 if (!ts) /* key not present */
1661 return 1;
1662
1663 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPT0);
Emeric Brunf7ab0bf2021-06-30 18:58:22 +02001664 if (!ptr)
1665 ptr = stktable_data_ptr_idx(t, ts, STKTABLE_DT_GPT, 0);
1666
Daniel Corbett3e60b112018-05-27 09:47:12 -04001667 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001668 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001669
Daniel Corbett3e60b112018-05-27 09:47:12 -04001670 stktable_release(t, ts);
1671 return !!ptr;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001672}
1673
Emeric Brun4d7ada82021-06-30 19:04:16 +02001674/* Casts sample <smp> to the type of the table specified in arg_p(1), and looks
1675 * it up into this table. Returns the value of the GPC[arg_p(0)] counter for the key
1676 * if the key is present in the table, otherwise zero, so that comparisons can
1677 * be easily performed. If the inspected parameter is not stored in the table,
1678 * <not found> is returned.
1679 */
1680static int sample_conv_table_gpc(const struct arg *arg_p, struct sample *smp, void *private)
1681{
1682 struct stktable *t;
1683 struct stktable_key *key;
1684 struct stksess *ts;
1685 void *ptr;
1686 unsigned int idx;
1687
1688 idx = arg_p[0].data.sint;
1689
1690 t = arg_p[1].data.t;
1691
1692 key = smp_to_stkey(smp, t);
1693 if (!key)
1694 return 0;
1695
1696 ts = stktable_lookup_key(t, key);
1697
1698 smp->flags = SMP_F_VOL_TEST;
1699 smp->data.type = SMP_T_SINT;
1700 smp->data.u.sint = 0;
1701
1702 if (!ts) /* key not present */
1703 return 1;
1704
1705 ptr = stktable_data_ptr_idx(t, ts, STKTABLE_DT_GPC, idx);
1706 if (ptr)
1707 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
1708
1709 stktable_release(t, ts);
1710 return !!ptr;
1711}
1712
1713/* Casts sample <smp> to the type of the table specified in arg_p(1), and looks
1714 * it up into this table. Returns the event rate of the GPC[arg_p(0)] counter
1715 * for the key if the key is present in the table, otherwise zero, so that
1716 * comparisons can be easily performed. If the inspected parameter is not
1717 * stored in the table, <not found> is returned.
1718 */
1719static int sample_conv_table_gpc_rate(const struct arg *arg_p, struct sample *smp, void *private)
1720{
1721 struct stktable *t;
1722 struct stktable_key *key;
1723 struct stksess *ts;
1724 void *ptr;
1725 unsigned int idx;
1726
1727 idx = arg_p[0].data.sint;
1728
1729 t = arg_p[1].data.t;
1730
1731 key = smp_to_stkey(smp, t);
1732 if (!key)
1733 return 0;
1734
1735 ts = stktable_lookup_key(t, key);
1736
1737 smp->flags = SMP_F_VOL_TEST;
1738 smp->data.type = SMP_T_SINT;
1739 smp->data.u.sint = 0;
1740
1741 if (!ts) /* key not present */
1742 return 1;
1743
1744 ptr = stktable_data_ptr_idx(t, ts, STKTABLE_DT_GPC_RATE, idx);
1745 if (ptr)
1746 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
1747 t->data_arg[STKTABLE_DT_GPC_RATE].u);
1748
1749 stktable_release(t, ts);
1750 return !!ptr;
1751}
1752
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001753/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001754 * it up into this table. Returns the value of the GPC0 counter for the key
1755 * if the key is present in the table, otherwise zero, so that comparisons can
1756 * be easily performed. If the inspected parameter is not stored in the table,
1757 * <not found> is returned.
1758 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001759static int sample_conv_table_gpc0(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001760{
1761 struct stktable *t;
1762 struct stktable_key *key;
1763 struct stksess *ts;
1764 void *ptr;
1765
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001766 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001767
1768 key = smp_to_stkey(smp, t);
1769 if (!key)
1770 return 0;
1771
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001772 ts = stktable_lookup_key(t, key);
1773
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001774 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001775 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001776 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001777
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001778 if (!ts) /* key not present */
1779 return 1;
1780
1781 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPC0);
Emeric Brun726783d2021-06-30 19:06:43 +02001782 if (!ptr) {
1783 /* fallback on the gpc array */
1784 ptr = stktable_data_ptr_idx(t, ts, STKTABLE_DT_GPC, 0);
1785 }
1786
Daniel Corbett3e60b112018-05-27 09:47:12 -04001787 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001788 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001789
Daniel Corbett3e60b112018-05-27 09:47:12 -04001790 stktable_release(t, ts);
1791 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001792}
1793
1794/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1795 * it up into this table. Returns the event rate of the GPC0 counter for the key
1796 * if the key is present in the table, otherwise zero, so that comparisons can
1797 * be easily performed. If the inspected parameter is not stored in the table,
1798 * <not found> is returned.
1799 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001800static int sample_conv_table_gpc0_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001801{
1802 struct stktable *t;
1803 struct stktable_key *key;
1804 struct stksess *ts;
1805 void *ptr;
1806
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001807 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001808
1809 key = smp_to_stkey(smp, t);
1810 if (!key)
1811 return 0;
1812
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001813 ts = stktable_lookup_key(t, key);
1814
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001815 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001816 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001817 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001818
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001819 if (!ts) /* key not present */
1820 return 1;
1821
1822 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPC0_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001823 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001824 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Daniel Corbett3e60b112018-05-27 09:47:12 -04001825 t->data_arg[STKTABLE_DT_GPC0_RATE].u);
Emeric Brun726783d2021-06-30 19:06:43 +02001826 else {
1827 /* fallback on the gpc array */
1828 ptr = stktable_data_ptr_idx(t, ts, STKTABLE_DT_GPC_RATE, 0);
1829 if (ptr)
1830 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
1831 t->data_arg[STKTABLE_DT_GPC_RATE].u);
1832 }
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001833
Daniel Corbett3e60b112018-05-27 09:47:12 -04001834 stktable_release(t, ts);
1835 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001836}
1837
1838/* 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 +01001839 * it up into this table. Returns the value of the GPC1 counter for the key
1840 * if the key is present in the table, otherwise zero, so that comparisons can
1841 * be easily performed. If the inspected parameter is not stored in the table,
1842 * <not found> is returned.
1843 */
1844static int sample_conv_table_gpc1(const struct arg *arg_p, struct sample *smp, void *private)
1845{
1846 struct stktable *t;
1847 struct stktable_key *key;
1848 struct stksess *ts;
1849 void *ptr;
1850
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001851 t = arg_p[0].data.t;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001852
1853 key = smp_to_stkey(smp, t);
1854 if (!key)
1855 return 0;
1856
1857 ts = stktable_lookup_key(t, key);
1858
1859 smp->flags = SMP_F_VOL_TEST;
1860 smp->data.type = SMP_T_SINT;
1861 smp->data.u.sint = 0;
1862
1863 if (!ts) /* key not present */
1864 return 1;
1865
1866 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPC1);
Emeric Brun726783d2021-06-30 19:06:43 +02001867 if (!ptr) {
1868 /* fallback on the gpc array */
1869 ptr = stktable_data_ptr_idx(t, ts, STKTABLE_DT_GPC, 1);
1870 }
1871
Daniel Corbett3e60b112018-05-27 09:47:12 -04001872 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001873 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001874
Daniel Corbett3e60b112018-05-27 09:47:12 -04001875 stktable_release(t, ts);
1876 return !!ptr;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001877}
1878
1879/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1880 * it up into this table. Returns the event rate of the GPC1 counter for the key
1881 * if the key is present in the table, otherwise zero, so that comparisons can
1882 * be easily performed. If the inspected parameter is not stored in the table,
1883 * <not found> is returned.
1884 */
1885static int sample_conv_table_gpc1_rate(const struct arg *arg_p, struct sample *smp, void *private)
1886{
1887 struct stktable *t;
1888 struct stktable_key *key;
1889 struct stksess *ts;
1890 void *ptr;
1891
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001892 t = arg_p[0].data.t;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001893
1894 key = smp_to_stkey(smp, t);
1895 if (!key)
1896 return 0;
1897
1898 ts = stktable_lookup_key(t, key);
1899
1900 smp->flags = SMP_F_VOL_TEST;
1901 smp->data.type = SMP_T_SINT;
1902 smp->data.u.sint = 0;
1903
1904 if (!ts) /* key not present */
1905 return 1;
1906
1907 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPC1_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001908 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001909 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Daniel Corbett3e60b112018-05-27 09:47:12 -04001910 t->data_arg[STKTABLE_DT_GPC1_RATE].u);
Emeric Brun726783d2021-06-30 19:06:43 +02001911 else {
1912 /* fallback on the gpc array */
1913 ptr = stktable_data_ptr_idx(t, ts, STKTABLE_DT_GPC_RATE, 1);
1914 if (ptr)
1915 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
1916 t->data_arg[STKTABLE_DT_GPC_RATE].u);
1917 }
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001918
Daniel Corbett3e60b112018-05-27 09:47:12 -04001919 stktable_release(t, ts);
1920 return !!ptr;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001921}
1922
1923/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001924 * it up into this table. Returns the cumulated number of HTTP request errors
1925 * for the key if the key is present in the table, otherwise zero, so that
1926 * comparisons can be easily performed. If the inspected parameter is not stored
1927 * in the table, <not found> is returned.
1928 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001929static int sample_conv_table_http_err_cnt(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001930{
1931 struct stktable *t;
1932 struct stktable_key *key;
1933 struct stksess *ts;
1934 void *ptr;
1935
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001936 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001937
1938 key = smp_to_stkey(smp, t);
1939 if (!key)
1940 return 0;
1941
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001942 ts = stktable_lookup_key(t, key);
1943
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001944 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001945 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001946 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001947
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001948 if (!ts) /* key not present */
1949 return 1;
1950
1951 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_ERR_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001952 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001953 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001954
Daniel Corbett3e60b112018-05-27 09:47:12 -04001955 stktable_release(t, ts);
1956 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001957}
1958
1959/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1960 * it up into this table. Returns the HTTP request error rate the key
1961 * if the key is present in the table, otherwise zero, so that comparisons can
1962 * be easily performed. If the inspected parameter is not stored in the table,
1963 * <not found> is returned.
1964 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001965static int sample_conv_table_http_err_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001966{
1967 struct stktable *t;
1968 struct stktable_key *key;
1969 struct stksess *ts;
1970 void *ptr;
1971
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001972 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001973
1974 key = smp_to_stkey(smp, t);
1975 if (!key)
1976 return 0;
1977
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001978 ts = stktable_lookup_key(t, key);
1979
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001980 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001981 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001982 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001983
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001984 if (!ts) /* key not present */
1985 return 1;
1986
1987 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_ERR_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001988 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001989 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Daniel Corbett3e60b112018-05-27 09:47:12 -04001990 t->data_arg[STKTABLE_DT_HTTP_ERR_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001991
Daniel Corbett3e60b112018-05-27 09:47:12 -04001992 stktable_release(t, ts);
1993 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001994}
1995
1996/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Willy Tarreau826f3ab2021-02-10 12:07:15 +01001997 * it up into this table. Returns the cumulated number of HTTP response failures
1998 * for the key if the key is present in the table, otherwise zero, so that
1999 * comparisons can be easily performed. If the inspected parameter is not stored
2000 * in the table, <not found> is returned.
2001 */
2002static int sample_conv_table_http_fail_cnt(const struct arg *arg_p, struct sample *smp, void *private)
2003{
2004 struct stktable *t;
2005 struct stktable_key *key;
2006 struct stksess *ts;
2007 void *ptr;
2008
2009 t = arg_p[0].data.t;
2010
2011 key = smp_to_stkey(smp, t);
2012 if (!key)
2013 return 0;
2014
2015 ts = stktable_lookup_key(t, key);
2016
2017 smp->flags = SMP_F_VOL_TEST;
2018 smp->data.type = SMP_T_SINT;
2019 smp->data.u.sint = 0;
2020
2021 if (!ts) /* key not present */
2022 return 1;
2023
2024 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_FAIL_CNT);
2025 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002026 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Willy Tarreau826f3ab2021-02-10 12:07:15 +01002027
2028 stktable_release(t, ts);
2029 return !!ptr;
2030}
2031
2032/* Casts sample <smp> to the type of the table specified in arg(0), and looks
2033 * it up into this table. Returns the HTTP response failure rate for the key
2034 * if the key is present in the table, otherwise zero, so that comparisons can
2035 * be easily performed. If the inspected parameter is not stored in the table,
2036 * <not found> is returned.
2037 */
2038static int sample_conv_table_http_fail_rate(const struct arg *arg_p, struct sample *smp, void *private)
2039{
2040 struct stktable *t;
2041 struct stktable_key *key;
2042 struct stksess *ts;
2043 void *ptr;
2044
2045 t = arg_p[0].data.t;
2046
2047 key = smp_to_stkey(smp, t);
2048 if (!key)
2049 return 0;
2050
2051 ts = stktable_lookup_key(t, key);
2052
2053 smp->flags = SMP_F_VOL_TEST;
2054 smp->data.type = SMP_T_SINT;
2055 smp->data.u.sint = 0;
2056
2057 if (!ts) /* key not present */
2058 return 1;
2059
2060 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_FAIL_RATE);
2061 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002062 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Willy Tarreau826f3ab2021-02-10 12:07:15 +01002063 t->data_arg[STKTABLE_DT_HTTP_FAIL_RATE].u);
2064
2065 stktable_release(t, ts);
2066 return !!ptr;
2067}
2068
2069/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002070 * it up into this table. Returns the cumulated number of HTTP request for the
2071 * key if the key is present in the table, otherwise zero, so that comparisons
2072 * can be easily performed. If the inspected parameter is not stored in the
2073 * table, <not found> is returned.
2074 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02002075static int sample_conv_table_http_req_cnt(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002076{
2077 struct stktable *t;
2078 struct stktable_key *key;
2079 struct stksess *ts;
2080 void *ptr;
2081
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002082 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002083
2084 key = smp_to_stkey(smp, t);
2085 if (!key)
2086 return 0;
2087
Willy Tarreauf0c730a2016-05-25 17:07:56 +02002088 ts = stktable_lookup_key(t, key);
2089
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002090 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02002091 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02002092 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002093
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002094 if (!ts) /* key not present */
2095 return 1;
2096
2097 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_REQ_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04002098 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002099 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002100
Daniel Corbett3e60b112018-05-27 09:47:12 -04002101 stktable_release(t, ts);
2102 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002103}
2104
2105/* Casts sample <smp> to the type of the table specified in arg(0), and looks
2106 * it up into this table. Returns the HTTP request rate the key if the key is
2107 * present in the table, otherwise zero, so that comparisons can be easily
2108 * performed. If the inspected parameter is not stored in the table, <not found>
2109 * is returned.
2110 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02002111static int sample_conv_table_http_req_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002112{
2113 struct stktable *t;
2114 struct stktable_key *key;
2115 struct stksess *ts;
2116 void *ptr;
2117
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002118 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002119
2120 key = smp_to_stkey(smp, t);
2121 if (!key)
2122 return 0;
2123
Willy Tarreauf0c730a2016-05-25 17:07:56 +02002124 ts = stktable_lookup_key(t, key);
2125
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002126 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02002127 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02002128 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002129
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002130 if (!ts) /* key not present */
2131 return 1;
2132
2133 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_REQ_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04002134 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002135 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Daniel Corbett3e60b112018-05-27 09:47:12 -04002136 t->data_arg[STKTABLE_DT_HTTP_REQ_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002137
Daniel Corbett3e60b112018-05-27 09:47:12 -04002138 stktable_release(t, ts);
2139 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002140}
2141
2142/* Casts sample <smp> to the type of the table specified in arg(0), and looks
2143 * it up into this table. Returns the volume of datareceived from clients in kbytes
2144 * if the key is present in the table, otherwise zero, so that comparisons can
2145 * be easily performed. If the inspected parameter is not stored in the table,
2146 * <not found> is returned.
2147 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02002148static int sample_conv_table_kbytes_in(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002149{
2150 struct stktable *t;
2151 struct stktable_key *key;
2152 struct stksess *ts;
2153 void *ptr;
2154
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002155 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002156
2157 key = smp_to_stkey(smp, t);
2158 if (!key)
2159 return 0;
2160
Willy Tarreauf0c730a2016-05-25 17:07:56 +02002161 ts = stktable_lookup_key(t, key);
2162
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002163 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02002164 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02002165 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002166
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002167 if (!ts) /* key not present */
2168 return 1;
2169
2170 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_IN_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04002171 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002172 smp->data.u.sint = stktable_data_cast(ptr, std_t_ull) >> 10;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002173
Daniel Corbett3e60b112018-05-27 09:47:12 -04002174 stktable_release(t, ts);
2175 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002176}
2177
2178/* Casts sample <smp> to the type of the table specified in arg(0), and looks
2179 * it up into this table. Returns the volume of data sent to clients in kbytes
2180 * if the key is present in the table, otherwise zero, so that comparisons can
2181 * be easily performed. If the inspected parameter is not stored in the table,
2182 * <not found> is returned.
2183 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02002184static int sample_conv_table_kbytes_out(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002185{
2186 struct stktable *t;
2187 struct stktable_key *key;
2188 struct stksess *ts;
2189 void *ptr;
2190
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002191 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002192
2193 key = smp_to_stkey(smp, t);
2194 if (!key)
2195 return 0;
2196
Willy Tarreauf0c730a2016-05-25 17:07:56 +02002197 ts = stktable_lookup_key(t, key);
2198
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002199 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02002200 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02002201 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002202
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002203 if (!ts) /* key not present */
2204 return 1;
2205
2206 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_OUT_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04002207 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002208 smp->data.u.sint = stktable_data_cast(ptr, std_t_ull) >> 10;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002209
Daniel Corbett3e60b112018-05-27 09:47:12 -04002210 stktable_release(t, ts);
2211 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002212}
2213
2214/* Casts sample <smp> to the type of the table specified in arg(0), and looks
2215 * it up into this table. Returns the server ID associated with the key if the
2216 * key is present in the table, otherwise zero, so that comparisons can be
2217 * easily performed. If the inspected parameter is not stored in the table,
2218 * <not found> is returned.
2219 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02002220static int sample_conv_table_server_id(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002221{
2222 struct stktable *t;
2223 struct stktable_key *key;
2224 struct stksess *ts;
2225 void *ptr;
2226
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002227 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002228
2229 key = smp_to_stkey(smp, t);
2230 if (!key)
2231 return 0;
2232
Willy Tarreauf0c730a2016-05-25 17:07:56 +02002233 ts = stktable_lookup_key(t, key);
2234
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002235 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02002236 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02002237 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002238
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002239 if (!ts) /* key not present */
2240 return 1;
2241
2242 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_SERVER_ID);
Daniel Corbett3e60b112018-05-27 09:47:12 -04002243 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002244 smp->data.u.sint = stktable_data_cast(ptr, std_t_sint);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002245
Daniel Corbett3e60b112018-05-27 09:47:12 -04002246 stktable_release(t, ts);
2247 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002248}
2249
2250/* Casts sample <smp> to the type of the table specified in arg(0), and looks
2251 * it up into this table. Returns the cumulated number of sessions for the
2252 * key if the key is present in the table, otherwise zero, so that comparisons
2253 * can be easily performed. If the inspected parameter is not stored in the
2254 * table, <not found> is returned.
2255 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02002256static int sample_conv_table_sess_cnt(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002257{
2258 struct stktable *t;
2259 struct stktable_key *key;
2260 struct stksess *ts;
2261 void *ptr;
2262
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002263 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002264
2265 key = smp_to_stkey(smp, t);
2266 if (!key)
2267 return 0;
2268
Willy Tarreauf0c730a2016-05-25 17:07:56 +02002269 ts = stktable_lookup_key(t, key);
2270
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002271 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02002272 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02002273 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002274
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002275 if (!ts) /* key not present */
2276 return 1;
2277
2278 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_SESS_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04002279 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002280 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002281
Daniel Corbett3e60b112018-05-27 09:47:12 -04002282 stktable_release(t, ts);
2283 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002284}
2285
2286/* Casts sample <smp> to the type of the table specified in arg(0), and looks
2287 * it up into this table. Returns the session rate the key if the key is
2288 * present in the table, otherwise zero, so that comparisons can be easily
2289 * performed. If the inspected parameter is not stored in the table, <not found>
2290 * is returned.
2291 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02002292static int sample_conv_table_sess_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002293{
2294 struct stktable *t;
2295 struct stktable_key *key;
2296 struct stksess *ts;
2297 void *ptr;
2298
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002299 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002300
2301 key = smp_to_stkey(smp, t);
2302 if (!key)
2303 return 0;
2304
Willy Tarreauf0c730a2016-05-25 17:07:56 +02002305 ts = stktable_lookup_key(t, key);
2306
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002307 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02002308 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02002309 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002310
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002311 if (!ts) /* key not present */
2312 return 1;
2313
2314 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_SESS_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04002315 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002316 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Daniel Corbett3e60b112018-05-27 09:47:12 -04002317 t->data_arg[STKTABLE_DT_SESS_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002318
Daniel Corbett3e60b112018-05-27 09:47:12 -04002319 stktable_release(t, ts);
2320 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002321}
2322
2323/* Casts sample <smp> to the type of the table specified in arg(0), and looks
2324 * it up into this table. Returns the amount of concurrent connections tracking
2325 * the same key if the key is present in the table, otherwise zero, so that
2326 * comparisons can be easily performed. If the inspected parameter is not
2327 * stored in the table, <not found> is returned.
2328 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02002329static int sample_conv_table_trackers(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002330{
2331 struct stktable *t;
2332 struct stktable_key *key;
2333 struct stksess *ts;
2334
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002335 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002336
2337 key = smp_to_stkey(smp, t);
2338 if (!key)
2339 return 0;
2340
Willy Tarreauf0c730a2016-05-25 17:07:56 +02002341 ts = stktable_lookup_key(t, key);
2342
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002343 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02002344 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02002345 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002346
Tim Duesterhus65189c12018-06-26 15:57:29 +02002347 if (!ts)
2348 return 1;
2349
2350 smp->data.u.sint = ts->ref_cnt;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002351
Daniel Corbett3e60b112018-05-27 09:47:12 -04002352 stktable_release(t, ts);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002353 return 1;
2354}
2355
Emeric Brun4d7ada82021-06-30 19:04:16 +02002356/* This function increments the gpc counter at index 'rule->arg.gpc.idx' of the
2357 * array on the tracksc counter of index 'rule->arg.gpc.sc' stored into the
2358 * <stream> or directly in the session <sess> if <stream> is set to NULL
2359 *
2360 * This function always returns ACT_RET_CONT and parameter flags is unused.
2361 */
2362static enum act_return action_inc_gpc(struct act_rule *rule, struct proxy *px,
2363 struct session *sess, struct stream *s, int flags)
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002364{
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002365 struct stksess *ts;
2366 struct stkctr *stkctr;
2367
2368 /* Extract the stksess, return OK if no stksess available. */
2369 if (s)
2370 stkctr = &s->stkctr[rule->arg.gpc.sc];
2371 else
2372 stkctr = &sess->stkctr[rule->arg.gpc.sc];
Willy Tarreau79c1e912016-01-25 14:54:45 +01002373
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002374 ts = stkctr_entry(stkctr);
Willy Tarreau79c1e912016-01-25 14:54:45 +01002375 if (ts) {
2376 void *ptr1, *ptr2;
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002377
Emeric Brun4d7ada82021-06-30 19:04:16 +02002378 /* First, update gpc_rate if it's tracked. Second, update its gpc if tracked. */
2379 ptr1 = stktable_data_ptr_idx(stkctr->table, ts, STKTABLE_DT_GPC_RATE, rule->arg.gpc.idx);
2380 ptr2 = stktable_data_ptr_idx(stkctr->table, ts, STKTABLE_DT_GPC, rule->arg.gpc.idx);
2381
Emeric Brun819fc6f2017-06-13 19:37:32 +02002382 if (ptr1 || ptr2) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002383 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002384
2385 if (ptr1)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002386 update_freq_ctr_period(&stktable_data_cast(ptr1, std_t_frqp),
Emeric Brun4d7ada82021-06-30 19:04:16 +02002387 stkctr->table->data_arg[STKTABLE_DT_GPC_RATE].u, 1);
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002388
Emeric Brun819fc6f2017-06-13 19:37:32 +02002389 if (ptr2)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002390 stktable_data_cast(ptr2, std_t_uint)++;
Willy Tarreau79c1e912016-01-25 14:54:45 +01002391
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002392 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002393
2394 /* If data was modified, we need to touch to re-schedule sync */
2395 stktable_touch_local(stkctr->table, ts, 0);
2396 }
Willy Tarreau79c1e912016-01-25 14:54:45 +01002397 }
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002398 return ACT_RET_CONT;
2399}
2400
Emeric Brun4d7ada82021-06-30 19:04:16 +02002401/* Same as action_inc_gpc() but for gpc0 only */
2402static enum act_return action_inc_gpc0(struct act_rule *rule, struct proxy *px,
2403 struct session *sess, struct stream *s, int flags)
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002404{
Emeric Brun4d7ada82021-06-30 19:04:16 +02002405 struct stksess *ts;
2406 struct stkctr *stkctr;
Willy Tarreau5b654ad2021-07-06 18:51:12 +02002407 unsigned int period = 0;
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002408
Emeric Brun4d7ada82021-06-30 19:04:16 +02002409 /* Extract the stksess, return OK if no stksess available. */
2410 if (s)
2411 stkctr = &s->stkctr[rule->arg.gpc.sc];
2412 else
2413 stkctr = &sess->stkctr[rule->arg.gpc.sc];
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002414
Emeric Brun4d7ada82021-06-30 19:04:16 +02002415 ts = stkctr_entry(stkctr);
2416 if (ts) {
2417 void *ptr1, *ptr2;
2418
2419 /* First, update gpc0_rate if it's tracked. Second, update its gpc0 if tracked. */
2420 ptr1 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC0_RATE);
Emeric Brun726783d2021-06-30 19:06:43 +02002421 if (ptr1) {
2422 period = stkctr->table->data_arg[STKTABLE_DT_GPC0_RATE].u;
2423 }
2424 else {
2425 /* fallback on the gpc array */
2426 ptr1 = stktable_data_ptr_idx(stkctr->table, ts, STKTABLE_DT_GPC_RATE, 0);
2427 if (ptr1)
2428 period = stkctr->table->data_arg[STKTABLE_DT_GPC_RATE].u;
2429 }
2430
Emeric Brun4d7ada82021-06-30 19:04:16 +02002431 ptr2 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC0);
Emeric Brun726783d2021-06-30 19:06:43 +02002432 if (!ptr2) {
2433 /* fallback on the gpc array */
2434 ptr2 = stktable_data_ptr_idx(stkctr->table, ts, STKTABLE_DT_GPC, 0);
2435 }
2436
Emeric Brun4d7ada82021-06-30 19:04:16 +02002437 if (ptr1 || ptr2) {
2438 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
2439
2440 if (ptr1)
2441 update_freq_ctr_period(&stktable_data_cast(ptr1, std_t_frqp),
Emeric Brun726783d2021-06-30 19:06:43 +02002442 period, 1);
Emeric Brun4d7ada82021-06-30 19:04:16 +02002443
2444 if (ptr2)
2445 stktable_data_cast(ptr2, std_t_uint)++;
2446
2447 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
2448
2449 /* If data was modified, we need to touch to re-schedule sync */
2450 stktable_touch_local(stkctr->table, ts, 0);
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002451 }
2452 }
Emeric Brun4d7ada82021-06-30 19:04:16 +02002453 return ACT_RET_CONT;
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002454}
2455
Emeric Brun4d7ada82021-06-30 19:04:16 +02002456/* Same as action_inc_gpc() but for gpc1 only */
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002457static enum act_return action_inc_gpc1(struct act_rule *rule, struct proxy *px,
2458 struct session *sess, struct stream *s, int flags)
2459{
2460 struct stksess *ts;
2461 struct stkctr *stkctr;
Willy Tarreau5b654ad2021-07-06 18:51:12 +02002462 unsigned int period = 0;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002463
2464 /* Extract the stksess, return OK if no stksess available. */
2465 if (s)
2466 stkctr = &s->stkctr[rule->arg.gpc.sc];
2467 else
2468 stkctr = &sess->stkctr[rule->arg.gpc.sc];
2469
2470 ts = stkctr_entry(stkctr);
2471 if (ts) {
2472 void *ptr1, *ptr2;
2473
2474 /* First, update gpc1_rate if it's tracked. Second, update its gpc1 if tracked. */
2475 ptr1 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC1_RATE);
Emeric Brun726783d2021-06-30 19:06:43 +02002476 if (ptr1) {
2477 period = stkctr->table->data_arg[STKTABLE_DT_GPC1_RATE].u;
2478 }
2479 else {
2480 /* fallback on the gpc array */
2481 ptr1 = stktable_data_ptr_idx(stkctr->table, ts, STKTABLE_DT_GPC_RATE, 1);
2482 if (ptr1)
2483 period = stkctr->table->data_arg[STKTABLE_DT_GPC_RATE].u;
2484 }
2485
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002486 ptr2 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC1);
Emeric Brun726783d2021-06-30 19:06:43 +02002487 if (!ptr2) {
2488 /* fallback on the gpc array */
2489 ptr2 = stktable_data_ptr_idx(stkctr->table, ts, STKTABLE_DT_GPC, 1);
2490 }
2491
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002492 if (ptr1 || ptr2) {
2493 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
2494
2495 if (ptr1)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002496 update_freq_ctr_period(&stktable_data_cast(ptr1, std_t_frqp),
Emeric Brun726783d2021-06-30 19:06:43 +02002497 period, 1);
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002498
2499 if (ptr2)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002500 stktable_data_cast(ptr2, std_t_uint)++;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002501
2502 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
2503
2504 /* If data was modified, we need to touch to re-schedule sync */
2505 stktable_touch_local(stkctr->table, ts, 0);
2506 }
2507 }
2508 return ACT_RET_CONT;
2509}
2510
Emeric Brun4d7ada82021-06-30 19:04:16 +02002511/* This function is a common parser for actions incrementing the GPC
2512 * (General Purpose Counters). It understands the formats:
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002513 *
Emeric Brun4d7ada82021-06-30 19:04:16 +02002514 * sc-inc-gpc(<gpc IDX>,<track ID>)
2515 * sc-inc-gpc0([<track ID>])
2516 * sc-inc-gpc1([<track ID>])
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002517 *
Emeric Brun4d7ada82021-06-30 19:04:16 +02002518 * It returns ACT_RET_PRS_ERR if fails and <err> is filled with an error
2519 * message. Otherwise it returns ACT_RET_PRS_OK.
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002520 */
Emeric Brun4d7ada82021-06-30 19:04:16 +02002521static enum act_parse_ret parse_inc_gpc(const char **args, int *arg, struct proxy *px,
2522 struct act_rule *rule, char **err)
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002523{
2524 const char *cmd_name = args[*arg-1];
2525 char *error;
2526
Emeric Brun4d7ada82021-06-30 19:04:16 +02002527 cmd_name += strlen("sc-inc-gpc");
2528 if (*cmd_name == '(') {
2529 cmd_name++; /* skip the '(' */
2530 rule->arg.gpc.idx = strtoul(cmd_name, &error, 10); /* Convert stick table id. */
2531 if (*error != ',') {
2532 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 +01002533 return ACT_RET_PRS_ERR;
2534 }
Emeric Brun4d7ada82021-06-30 19:04:16 +02002535 else {
2536 cmd_name = error + 1; /* skip the ',' */
2537 rule->arg.gpc.sc = strtol(cmd_name, &error, 10); /* Convert stick table id. */
2538 if (*error != ')') {
2539 memprintf(err, "invalid stick table track ID '%s'. Expects sc-inc-gpc(<GPC ID>,<Track ID>)", args[*arg-1]);
2540 return ACT_RET_PRS_ERR;
2541 }
2542
2543 if (rule->arg.gpc.sc >= MAX_SESS_STKCTR) {
2544 memprintf(err, "invalid stick table track ID '%s'. The max allowed ID is %d",
2545 args[*arg-1], MAX_SESS_STKCTR-1);
2546 return ACT_RET_PRS_ERR;
2547 }
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002548 }
Emeric Brun4d7ada82021-06-30 19:04:16 +02002549 rule->action_ptr = action_inc_gpc;
2550 }
2551 else if (*cmd_name == '0' ||*cmd_name == '1') {
2552 char c = *cmd_name;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002553
Emeric Brun4d7ada82021-06-30 19:04:16 +02002554 cmd_name++;
2555 if (*cmd_name == '\0') {
2556 /* default stick table id. */
2557 rule->arg.gpc.sc = 0;
2558 } else {
2559 /* parse the stick table id. */
2560 if (*cmd_name != '(') {
2561 memprintf(err, "invalid stick table track ID. Expects %s(<Track ID>)", args[*arg-1]);
2562 return ACT_RET_PRS_ERR;
2563 }
2564 cmd_name++; /* jump the '(' */
2565 rule->arg.gpc.sc = strtol(cmd_name, &error, 10); /* Convert stick table id. */
2566 if (*error != ')') {
2567 memprintf(err, "invalid stick table track ID. Expects %s(<Track ID>)", args[*arg-1]);
2568 return ACT_RET_PRS_ERR;
2569 }
2570
2571 if (rule->arg.gpc.sc >= MAX_SESS_STKCTR) {
2572 memprintf(err, "invalid stick table track ID. The max allowed ID is %d",
2573 MAX_SESS_STKCTR-1);
2574 return ACT_RET_PRS_ERR;
2575 }
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002576 }
Emeric Brun4d7ada82021-06-30 19:04:16 +02002577 if (c == '1')
2578 rule->action_ptr = action_inc_gpc1;
2579 else
2580 rule->action_ptr = action_inc_gpc0;
2581 }
2582 else {
2583 /* default stick table id. */
2584 memprintf(err, "invalid gpc ID '%s'. Expects sc-set-gpc(<GPC ID>,<Track ID>)", args[*arg-1]);
2585 return ACT_RET_PRS_ERR;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002586 }
2587 rule->action = ACT_CUSTOM;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002588 return ACT_RET_PRS_OK;
2589}
2590
Emeric Brun877b0b52021-06-30 18:57:49 +02002591/* This function sets the gpt at index 'rule->arg.gpt.idx' of the array on the
2592 * tracksc counter of index 'rule->arg.gpt.sc' stored into the <stream> or
2593 * directly in the session <sess> if <stream> is set to NULL. This gpt is
2594 * set to the value computed by the expression 'rule->arg.gpt.expr' or if
2595 * 'rule->arg.gpt.expr' is null directly to the value of 'rule->arg.gpt.value'.
2596 *
2597 * This function always returns ACT_RET_CONT and parameter flags is unused.
2598 */
2599static enum act_return action_set_gpt(struct act_rule *rule, struct proxy *px,
2600 struct session *sess, struct stream *s, int flags)
2601{
2602 void *ptr;
2603 struct stksess *ts;
2604 struct stkctr *stkctr;
2605 unsigned int value = 0;
2606 struct sample *smp;
2607 int smp_opt_dir;
2608
2609 /* Extract the stksess, return OK if no stksess available. */
2610 if (s)
2611 stkctr = &s->stkctr[rule->arg.gpt.sc];
2612 else
2613 stkctr = &sess->stkctr[rule->arg.gpt.sc];
2614
2615 ts = stkctr_entry(stkctr);
2616 if (!ts)
2617 return ACT_RET_CONT;
2618
2619 /* Store the sample in the required sc, and ignore errors. */
2620 ptr = stktable_data_ptr_idx(stkctr->table, ts, STKTABLE_DT_GPT, rule->arg.gpt.idx);
2621 if (ptr) {
2622
2623 if (!rule->arg.gpt.expr)
2624 value = (unsigned int)(rule->arg.gpt.value);
2625 else {
2626 switch (rule->from) {
2627 case ACT_F_TCP_REQ_SES: smp_opt_dir = SMP_OPT_DIR_REQ; break;
2628 case ACT_F_TCP_REQ_CNT: smp_opt_dir = SMP_OPT_DIR_REQ; break;
2629 case ACT_F_TCP_RES_CNT: smp_opt_dir = SMP_OPT_DIR_RES; break;
2630 case ACT_F_HTTP_REQ: smp_opt_dir = SMP_OPT_DIR_REQ; break;
2631 case ACT_F_HTTP_RES: smp_opt_dir = SMP_OPT_DIR_RES; break;
2632 default:
2633 send_log(px, LOG_ERR, "stick table: internal error while setting gpt%u.", rule->arg.gpt.idx);
2634 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))
2635 ha_alert("stick table: internal error while executing setting gpt%u.\n", rule->arg.gpt.idx);
2636 return ACT_RET_CONT;
2637 }
2638
2639 /* Fetch and cast the expression. */
2640 smp = sample_fetch_as_type(px, sess, s, smp_opt_dir|SMP_OPT_FINAL, rule->arg.gpt.expr, SMP_T_SINT);
2641 if (!smp) {
2642 send_log(px, LOG_WARNING, "stick table: invalid expression or data type while setting gpt%u.", rule->arg.gpt.idx);
2643 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))
2644 ha_alert("stick table: invalid expression or data type while setting gpt%u.\n", rule->arg.gpt.idx);
2645 return ACT_RET_CONT;
2646 }
2647 value = (unsigned int)(smp->data.u.sint);
2648 }
2649
2650 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
2651
2652 stktable_data_cast(ptr, std_t_uint) = value;
2653
2654 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
2655
2656 stktable_touch_local(stkctr->table, ts, 0);
2657 }
2658
2659 return ACT_RET_CONT;
2660}
2661
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002662/* Always returns 1. */
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002663static enum act_return action_set_gpt0(struct act_rule *rule, struct proxy *px,
Willy Tarreau658b85b2015-09-27 10:00:49 +02002664 struct session *sess, struct stream *s, int flags)
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002665{
2666 void *ptr;
2667 struct stksess *ts;
2668 struct stkctr *stkctr;
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002669 unsigned int value = 0;
2670 struct sample *smp;
2671 int smp_opt_dir;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002672
2673 /* Extract the stksess, return OK if no stksess available. */
2674 if (s)
2675 stkctr = &s->stkctr[rule->arg.gpt.sc];
2676 else
2677 stkctr = &sess->stkctr[rule->arg.gpt.sc];
Willy Tarreau79c1e912016-01-25 14:54:45 +01002678
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002679 ts = stkctr_entry(stkctr);
2680 if (!ts)
2681 return ACT_RET_CONT;
2682
2683 /* Store the sample in the required sc, and ignore errors. */
2684 ptr = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPT0);
Emeric Brunf7ab0bf2021-06-30 18:58:22 +02002685 if (!ptr)
2686 ptr = stktable_data_ptr_idx(stkctr->table, ts, STKTABLE_DT_GPT, 0);
2687
Willy Tarreau79c1e912016-01-25 14:54:45 +01002688 if (ptr) {
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002689 if (!rule->arg.gpt.expr)
2690 value = (unsigned int)(rule->arg.gpt.value);
2691 else {
2692 switch (rule->from) {
2693 case ACT_F_TCP_REQ_SES: smp_opt_dir = SMP_OPT_DIR_REQ; break;
2694 case ACT_F_TCP_REQ_CNT: smp_opt_dir = SMP_OPT_DIR_REQ; break;
2695 case ACT_F_TCP_RES_CNT: smp_opt_dir = SMP_OPT_DIR_RES; break;
2696 case ACT_F_HTTP_REQ: smp_opt_dir = SMP_OPT_DIR_REQ; break;
2697 case ACT_F_HTTP_RES: smp_opt_dir = SMP_OPT_DIR_RES; break;
2698 default:
2699 send_log(px, LOG_ERR, "stick table: internal error while setting gpt0.");
2700 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))
2701 ha_alert("stick table: internal error while executing setting gpt0.\n");
2702 return ACT_RET_CONT;
2703 }
2704
2705 /* Fetch and cast the expression. */
2706 smp = sample_fetch_as_type(px, sess, s, smp_opt_dir|SMP_OPT_FINAL, rule->arg.gpt.expr, SMP_T_SINT);
2707 if (!smp) {
2708 send_log(px, LOG_WARNING, "stick table: invalid expression or data type while setting gpt0.");
2709 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))
2710 ha_alert("stick table: invalid expression or data type while setting gpt0.\n");
2711 return ACT_RET_CONT;
2712 }
2713 value = (unsigned int)(smp->data.u.sint);
2714 }
2715
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002716 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002717
Emeric Brun0e3457b2021-06-30 17:18:28 +02002718 stktable_data_cast(ptr, std_t_uint) = value;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002719
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002720 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002721
2722 stktable_touch_local(stkctr->table, ts, 0);
Willy Tarreau79c1e912016-01-25 14:54:45 +01002723 }
2724
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002725 return ACT_RET_CONT;
2726}
2727
Emeric Brun877b0b52021-06-30 18:57:49 +02002728/* This function is a parser for the "sc-set-gpt" and "sc-set-gpt0" actions.
2729 * It understands the formats:
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002730 *
Emeric Brun877b0b52021-06-30 18:57:49 +02002731 * sc-set-gpt(<gpt IDX>,<track ID>) <expression>
2732 * sc-set-gpt0(<track ID>) <expression>
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002733 *
Emeric Brun877b0b52021-06-30 18:57:49 +02002734 * It returns ACT_RET_PRS_ERR if fails and <err> is filled with an error message.
2735 * Otherwise, it returns ACT_RET_PRS_OK and the variable 'rule->arg.gpt.expr'
2736 * is filled with the pointer to the expression to execute or NULL if the arg
2737 * is directly an integer stored into 'rule->arg.gpt.value'.
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002738 */
Emeric Brun877b0b52021-06-30 18:57:49 +02002739static enum act_parse_ret parse_set_gpt(const char **args, int *arg, struct proxy *px,
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002740 struct act_rule *rule, char **err)
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002741{
2742 const char *cmd_name = args[*arg-1];
2743 char *error;
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002744 int smp_val;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002745
Emeric Brun877b0b52021-06-30 18:57:49 +02002746 cmd_name += strlen("sc-set-gpt");
2747 if (*cmd_name == '(') {
2748 cmd_name++; /* skip the '(' */
2749 rule->arg.gpt.idx = strtoul(cmd_name, &error, 10); /* Convert stick table id. */
2750 if (*error != ',') {
2751 memprintf(err, "Missing gpt ID '%s'. Expects sc-set-gpt(<GPT ID>,<Track ID>)", args[*arg-1]);
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002752 return ACT_RET_PRS_ERR;
2753 }
Emeric Brun877b0b52021-06-30 18:57:49 +02002754 else {
2755 cmd_name = error + 1; /* skip the ',' */
2756 rule->arg.gpt.sc = strtol(cmd_name, &error, 10); /* Convert stick table id. */
2757 if (*error != ')') {
2758 memprintf(err, "invalid stick table track ID '%s'. Expects sc-set-gpt(<GPT ID>,<Track ID>)", args[*arg-1]);
2759 return ACT_RET_PRS_ERR;
2760 }
2761
2762 if (rule->arg.gpt.sc >= MAX_SESS_STKCTR) {
2763 memprintf(err, "invalid stick table track ID '%s'. The max allowed ID is %d",
2764 args[*arg-1], MAX_SESS_STKCTR-1);
2765 return ACT_RET_PRS_ERR;
2766 }
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002767 }
Emeric Brun877b0b52021-06-30 18:57:49 +02002768 rule->action_ptr = action_set_gpt;
2769 }
2770 else if (*cmd_name == '0') {
2771 cmd_name++;
2772 if (*cmd_name == '\0') {
2773 /* default stick table id. */
2774 rule->arg.gpt.sc = 0;
2775 } else {
2776 /* parse the stick table id. */
2777 if (*cmd_name != '(') {
2778 memprintf(err, "invalid stick table track ID '%s'. Expects sc-set-gpt0(<Track ID>)", args[*arg-1]);
2779 return ACT_RET_PRS_ERR;
2780 }
2781 cmd_name++; /* jump the '(' */
2782 rule->arg.gpt.sc = strtol(cmd_name, &error, 10); /* Convert stick table id. */
2783 if (*error != ')') {
2784 memprintf(err, "invalid stick table track ID '%s'. Expects sc-set-gpt0(<Track ID>)", args[*arg-1]);
2785 return ACT_RET_PRS_ERR;
2786 }
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002787
Emeric Brun877b0b52021-06-30 18:57:49 +02002788 if (rule->arg.gpt.sc >= MAX_SESS_STKCTR) {
2789 memprintf(err, "invalid stick table track ID '%s'. The max allowed ID is %d",
2790 args[*arg-1], MAX_SESS_STKCTR-1);
2791 return ACT_RET_PRS_ERR;
2792 }
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002793 }
Emeric Brun877b0b52021-06-30 18:57:49 +02002794 rule->action_ptr = action_set_gpt0;
2795 }
2796 else {
2797 /* default stick table id. */
2798 memprintf(err, "invalid gpt ID '%s'. Expects sc-set-gpt(<GPT ID>,<Track ID>)", args[*arg-1]);
2799 return ACT_RET_PRS_ERR;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002800 }
2801
Willy Tarreauece4c4a2021-08-24 14:57:28 +02002802 /* value may be either an integer or an expression */
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002803 rule->arg.gpt.expr = NULL;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002804 rule->arg.gpt.value = strtol(args[*arg], &error, 10);
Willy Tarreauece4c4a2021-08-24 14:57:28 +02002805 if (*error == '\0') {
2806 /* valid integer, skip it */
2807 (*arg)++;
2808 } else {
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002809 rule->arg.gpt.expr = sample_parse_expr((char **)args, arg, px->conf.args.file,
Willy Tarreaue3b57bf2020-02-14 16:50:14 +01002810 px->conf.args.line, err, &px->conf.args, NULL);
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002811 if (!rule->arg.gpt.expr)
2812 return ACT_RET_PRS_ERR;
2813
2814 switch (rule->from) {
2815 case ACT_F_TCP_REQ_SES: smp_val = SMP_VAL_FE_SES_ACC; break;
2816 case ACT_F_TCP_REQ_CNT: smp_val = SMP_VAL_FE_REQ_CNT; break;
2817 case ACT_F_TCP_RES_CNT: smp_val = SMP_VAL_BE_RES_CNT; break;
2818 case ACT_F_HTTP_REQ: smp_val = SMP_VAL_FE_HRQ_HDR; break;
2819 case ACT_F_HTTP_RES: smp_val = SMP_VAL_BE_HRS_HDR; break;
2820 default:
2821 memprintf(err, "internal error, unexpected rule->from=%d, please report this bug!", rule->from);
2822 return ACT_RET_PRS_ERR;
2823 }
2824 if (!(rule->arg.gpt.expr->fetch->val & smp_val)) {
2825 memprintf(err, "fetch method '%s' extracts information from '%s', none of which is available here", args[*arg-1],
2826 sample_src_names(rule->arg.gpt.expr->fetch->use));
2827 free(rule->arg.gpt.expr);
2828 return ACT_RET_PRS_ERR;
2829 }
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002830 }
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002831
Thierry FOURNIER42148732015-09-02 17:17:33 +02002832 rule->action = ACT_CUSTOM;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002833
2834 return ACT_RET_PRS_OK;
2835}
2836
Willy Tarreau7d562212016-11-25 16:10:05 +01002837/* set temp integer to the number of used entries in the table pointed to by expr.
2838 * Accepts exactly 1 argument of type table.
2839 */
2840static int
2841smp_fetch_table_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
2842{
2843 smp->flags = SMP_F_VOL_TEST;
2844 smp->data.type = SMP_T_SINT;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002845 smp->data.u.sint = args->data.t->current;
Willy Tarreau7d562212016-11-25 16:10:05 +01002846 return 1;
2847}
2848
2849/* set temp integer to the number of free entries in the table pointed to by expr.
2850 * Accepts exactly 1 argument of type table.
2851 */
2852static int
2853smp_fetch_table_avl(const struct arg *args, struct sample *smp, const char *kw, void *private)
2854{
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002855 struct stktable *t;
Willy Tarreau7d562212016-11-25 16:10:05 +01002856
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002857 t = args->data.t;
Willy Tarreau7d562212016-11-25 16:10:05 +01002858 smp->flags = SMP_F_VOL_TEST;
2859 smp->data.type = SMP_T_SINT;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002860 smp->data.u.sint = t->size - t->current;
Willy Tarreau7d562212016-11-25 16:10:05 +01002861 return 1;
2862}
2863
2864/* Returns a pointer to a stkctr depending on the fetch keyword name.
2865 * It is designed to be called as sc[0-9]_* sc_* or src_* exclusively.
2866 * sc[0-9]_* will return a pointer to the respective field in the
2867 * stream <l4>. sc_* requires an UINT argument specifying the stick
2868 * counter number. src_* will fill a locally allocated structure with
2869 * the table and entry corresponding to what is specified with src_*.
2870 * NULL may be returned if the designated stkctr is not tracked. For
2871 * the sc_* and sc[0-9]_* forms, an optional table argument may be
2872 * passed. When present, the currently tracked key is then looked up
2873 * in the specified table instead of the current table. The purpose is
Ilya Shipitsin47d17182020-06-21 21:42:57 +05002874 * to be able to convert multiple values per key (eg: have gpc0 from
Willy Tarreau7d562212016-11-25 16:10:05 +01002875 * multiple tables). <strm> is allowed to be NULL, in which case only
2876 * the session will be consulted.
2877 */
2878struct stkctr *
Emeric Brun819fc6f2017-06-13 19:37:32 +02002879smp_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 +01002880{
Willy Tarreau7d562212016-11-25 16:10:05 +01002881 struct stkctr *stkptr;
2882 struct stksess *stksess;
2883 unsigned int num = kw[2] - '0';
2884 int arg = 0;
2885
2886 if (num == '_' - '0') {
2887 /* sc_* variant, args[0] = ctr# (mandatory) */
2888 num = args[arg++].data.sint;
Willy Tarreau7d562212016-11-25 16:10:05 +01002889 }
2890 else if (num > 9) { /* src_* variant, args[0] = table */
2891 struct stktable_key *key;
2892 struct connection *conn = objt_conn(sess->origin);
2893 struct sample smp;
2894
2895 if (!conn)
2896 return NULL;
2897
Joseph Herlant5662fa42018-11-15 13:43:28 -08002898 /* Fetch source address in a sample. */
Willy Tarreau7d562212016-11-25 16:10:05 +01002899 smp.px = NULL;
2900 smp.sess = sess;
2901 smp.strm = strm;
Amaury Denoyellec460c702021-05-12 10:17:47 +02002902 if (!smp_fetch_src || !smp_fetch_src(empty_arg_list, &smp, "src", NULL))
Willy Tarreau7d562212016-11-25 16:10:05 +01002903 return NULL;
2904
2905 /* Converts into key. */
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002906 key = smp_to_stkey(&smp, args->data.t);
Willy Tarreau7d562212016-11-25 16:10:05 +01002907 if (!key)
2908 return NULL;
2909
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002910 stkctr->table = args->data.t;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002911 stkctr_set_entry(stkctr, stktable_lookup_key(stkctr->table, key));
2912 return stkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002913 }
2914
2915 /* Here, <num> contains the counter number from 0 to 9 for
2916 * the sc[0-9]_ form, or even higher using sc_(num) if needed.
2917 * args[arg] is the first optional argument. We first lookup the
2918 * ctr form the stream, then from the session if it was not there.
Christopher Fauleta9fa88a2019-10-21 10:53:34 +02002919 * But we must be sure the counter does not exceed MAX_SESS_STKCTR.
Willy Tarreau7d562212016-11-25 16:10:05 +01002920 */
Christopher Fauleta9fa88a2019-10-21 10:53:34 +02002921 if (num >= MAX_SESS_STKCTR)
2922 return NULL;
Willy Tarreau7d562212016-11-25 16:10:05 +01002923
2924 if (strm)
2925 stkptr = &strm->stkctr[num];
2926 if (!strm || !stkctr_entry(stkptr)) {
2927 stkptr = &sess->stkctr[num];
2928 if (!stkctr_entry(stkptr))
2929 return NULL;
2930 }
2931
2932 stksess = stkctr_entry(stkptr);
2933 if (!stksess)
2934 return NULL;
2935
2936 if (unlikely(args[arg].type == ARGT_TAB)) {
2937 /* an alternate table was specified, let's look up the same key there */
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002938 stkctr->table = args[arg].data.t;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002939 stkctr_set_entry(stkctr, stktable_lookup(stkctr->table, stksess));
2940 return stkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002941 }
2942 return stkptr;
2943}
2944
2945/* same as smp_fetch_sc_stkctr() but dedicated to src_* and can create
2946 * the entry if it doesn't exist yet. This is needed for a few fetch
2947 * functions which need to create an entry, such as src_inc_gpc* and
2948 * src_clr_gpc*.
2949 */
2950struct stkctr *
Emeric Brun819fc6f2017-06-13 19:37:32 +02002951smp_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 +01002952{
Willy Tarreau7d562212016-11-25 16:10:05 +01002953 struct stktable_key *key;
2954 struct connection *conn = objt_conn(sess->origin);
2955 struct sample smp;
2956
2957 if (strncmp(kw, "src_", 4) != 0)
2958 return NULL;
2959
2960 if (!conn)
2961 return NULL;
2962
Joseph Herlant5662fa42018-11-15 13:43:28 -08002963 /* Fetch source address in a sample. */
Willy Tarreau7d562212016-11-25 16:10:05 +01002964 smp.px = NULL;
2965 smp.sess = sess;
2966 smp.strm = strm;
Amaury Denoyellec460c702021-05-12 10:17:47 +02002967 if (!smp_fetch_src || !smp_fetch_src(empty_arg_list, &smp, "src", NULL))
Willy Tarreau7d562212016-11-25 16:10:05 +01002968 return NULL;
2969
2970 /* Converts into key. */
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002971 key = smp_to_stkey(&smp, args->data.t);
Willy Tarreau7d562212016-11-25 16:10:05 +01002972 if (!key)
2973 return NULL;
2974
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002975 stkctr->table = args->data.t;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002976 stkctr_set_entry(stkctr, stktable_get_entry(stkctr->table, key));
2977 return stkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002978}
2979
2980/* set return a boolean indicating if the requested stream counter is
2981 * currently being tracked or not.
2982 * Supports being called as "sc[0-9]_tracked" only.
2983 */
2984static int
2985smp_fetch_sc_tracked(const struct arg *args, struct sample *smp, const char *kw, void *private)
2986{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002987 struct stkctr tmpstkctr;
2988 struct stkctr *stkctr;
2989
Willy Tarreau7d562212016-11-25 16:10:05 +01002990 smp->flags = SMP_F_VOL_TEST;
2991 smp->data.type = SMP_T_BOOL;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002992 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2993 smp->data.u.sint = !!stkctr;
2994
2995 /* release the ref count */
Dirkjan Bussinkff57f1b2018-09-14 14:31:22 +02002996 if (stkctr == &tmpstkctr)
Emeric Brun819fc6f2017-06-13 19:37:32 +02002997 stktable_release(stkctr->table, stkctr_entry(stkctr));
2998
Emeric Brun877b0b52021-06-30 18:57:49 +02002999 return 1;
3000}
3001
3002/* set <smp> to the General Purpose Tag of index set as first arg
3003 * to value from the stream's tracked frontend counters or from the src.
3004 * Supports being called as "sc_get_gpt(<gpt-idx>,<sc-idx>[,<table>])" or
3005 * "src_get_gpt(<gpt-idx>[,<table>])" only. Value zero is returned if
3006 * the key is new or gpt is not stored.
3007 */
3008static int
3009smp_fetch_sc_get_gpt(const struct arg *args, struct sample *smp, const char *kw, void *private)
3010{
3011 struct stkctr tmpstkctr;
3012 struct stkctr *stkctr;
3013 unsigned int idx;
3014
3015 idx = args[0].data.sint;
3016
3017 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args + 1, kw, &tmpstkctr);
3018 if (!stkctr)
3019 return 0;
3020
3021 smp->flags = SMP_F_VOL_TEST;
3022 smp->data.type = SMP_T_SINT;
3023 smp->data.u.sint = 0;
3024
3025 if (stkctr_entry(stkctr)) {
3026 void *ptr;
3027
3028 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPT, idx);
3029 if (!ptr) {
3030 if (stkctr == &tmpstkctr)
3031 stktable_release(stkctr->table, stkctr_entry(stkctr));
3032 return 0; /* parameter not stored */
3033 }
3034
3035 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3036
3037 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
3038
3039 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3040
3041 if (stkctr == &tmpstkctr)
3042 stktable_release(stkctr->table, stkctr_entry(stkctr));
3043 }
Willy Tarreau7d562212016-11-25 16:10:05 +01003044 return 1;
3045}
3046
3047/* set <smp> to the General Purpose Flag 0 value from the stream's tracked
3048 * frontend counters or from the src.
3049 * Supports being called as "sc[0-9]_get_gpc0" or "src_get_gpt0" only. Value
3050 * zero is returned if the key is new.
3051 */
3052static int
3053smp_fetch_sc_get_gpt0(const struct arg *args, struct sample *smp, const char *kw, void *private)
3054{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003055 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003056 struct stkctr *stkctr;
3057
Emeric Brun819fc6f2017-06-13 19:37:32 +02003058 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003059 if (!stkctr)
3060 return 0;
3061
3062 smp->flags = SMP_F_VOL_TEST;
3063 smp->data.type = SMP_T_SINT;
3064 smp->data.u.sint = 0;
3065
Emeric Brun819fc6f2017-06-13 19:37:32 +02003066 if (stkctr_entry(stkctr)) {
3067 void *ptr;
3068
3069 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPT0);
Emeric Brunf7ab0bf2021-06-30 18:58:22 +02003070 if (!ptr)
3071 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPT, 0);
3072
Emeric Brun4d7ada82021-06-30 19:04:16 +02003073 if (!ptr) {
3074 if (stkctr == &tmpstkctr)
3075 stktable_release(stkctr->table, stkctr_entry(stkctr));
3076 return 0; /* parameter not stored */
3077 }
3078
3079 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3080
3081 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
3082
3083 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3084
3085 if (stkctr == &tmpstkctr)
3086 stktable_release(stkctr->table, stkctr_entry(stkctr));
3087 }
3088 return 1;
3089}
3090
3091/* set <smp> to the GPC[args(0)]'s value from the stream's tracked
3092 * frontend counters or from the src.
3093 * Supports being called as "sc_get_gpc(<gpc-idx>,<sc-idx>[,<table>])" or
3094 * "src_get_gpc(<gpc-idx>[,<table>])" only. Value
3095 * Value zero is returned if the key is new or gpc is not stored.
3096 */
3097static int
3098smp_fetch_sc_get_gpc(const struct arg *args, struct sample *smp, const char *kw, void *private)
3099{
3100 struct stkctr tmpstkctr;
3101 struct stkctr *stkctr;
3102 unsigned int idx;
3103
3104 idx = args[0].data.sint;
3105
3106 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args + 1, kw, &tmpstkctr);
3107 if (!stkctr)
3108 return 0;
3109
3110 smp->flags = SMP_F_VOL_TEST;
3111 smp->data.type = SMP_T_SINT;
3112 smp->data.u.sint = 0;
3113
3114 if (stkctr_entry(stkctr) != NULL) {
3115 void *ptr;
3116
3117 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC, idx);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003118 if (!ptr) {
3119 if (stkctr == &tmpstkctr)
3120 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003121 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003122 }
3123
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003124 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003125
Emeric Brun0e3457b2021-06-30 17:18:28 +02003126 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003127
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003128 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003129
3130 if (stkctr == &tmpstkctr)
3131 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003132 }
3133 return 1;
3134}
3135
3136/* set <smp> to the General Purpose Counter 0 value from the stream's tracked
3137 * frontend counters or from the src.
3138 * Supports being called as "sc[0-9]_get_gpc0" or "src_get_gpc0" only. Value
3139 * zero is returned if the key is new.
3140 */
3141static int
3142smp_fetch_sc_get_gpc0(const struct arg *args, struct sample *smp, const char *kw, void *private)
3143{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003144 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003145 struct stkctr *stkctr;
3146
Emeric Brun819fc6f2017-06-13 19:37:32 +02003147 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003148 if (!stkctr)
3149 return 0;
3150
3151 smp->flags = SMP_F_VOL_TEST;
3152 smp->data.type = SMP_T_SINT;
3153 smp->data.u.sint = 0;
3154
3155 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003156 void *ptr;
3157
3158 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0);
3159 if (!ptr) {
Emeric Brun726783d2021-06-30 19:06:43 +02003160 /* fallback on the gpc array */
3161 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC, 0);
3162 }
3163
3164 if (!ptr) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003165 if (stkctr == &tmpstkctr)
3166 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003167 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003168 }
3169
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003170 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003171
Emeric Brun0e3457b2021-06-30 17:18:28 +02003172 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003173
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003174 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003175
3176 if (stkctr == &tmpstkctr)
3177 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003178 }
3179 return 1;
3180}
3181
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003182/* set <smp> to the General Purpose Counter 1 value from the stream's tracked
3183 * frontend counters or from the src.
3184 * Supports being called as "sc[0-9]_get_gpc1" or "src_get_gpc1" only. Value
3185 * zero is returned if the key is new.
3186 */
3187static int
3188smp_fetch_sc_get_gpc1(const struct arg *args, struct sample *smp, const char *kw, void *private)
3189{
3190 struct stkctr tmpstkctr;
3191 struct stkctr *stkctr;
3192
3193 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
3194 if (!stkctr)
3195 return 0;
3196
3197 smp->flags = SMP_F_VOL_TEST;
3198 smp->data.type = SMP_T_SINT;
3199 smp->data.u.sint = 0;
3200
3201 if (stkctr_entry(stkctr) != NULL) {
3202 void *ptr;
3203
3204 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1);
3205 if (!ptr) {
Emeric Brun726783d2021-06-30 19:06:43 +02003206 /* fallback on the gpc array */
3207 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC, 1);
3208 }
3209
3210 if (!ptr) {
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003211 if (stkctr == &tmpstkctr)
3212 stktable_release(stkctr->table, stkctr_entry(stkctr));
3213 return 0; /* parameter not stored */
3214 }
3215
3216 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3217
Emeric Brun0e3457b2021-06-30 17:18:28 +02003218 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003219
3220 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3221
3222 if (stkctr == &tmpstkctr)
3223 stktable_release(stkctr->table, stkctr_entry(stkctr));
3224 }
3225 return 1;
3226}
3227
Emeric Brun4d7ada82021-06-30 19:04:16 +02003228/* set <smp> to the GPC[args(0)]'s event rate from the stream's
3229 * tracked frontend counters or from the src.
3230 * Supports being called as "sc_gpc_rate(<gpc-idx>,<sc-idx>[,<table])"
3231 * or "src_gpc_rate(<gpc-idx>[,<table>])" only.
3232 * Value zero is returned if the key is new or gpc_rate is not stored.
3233 */
3234static int
3235smp_fetch_sc_gpc_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3236{
3237 struct stkctr tmpstkctr;
3238 struct stkctr *stkctr;
3239 unsigned int idx;
3240
3241 idx = args[0].data.sint;
3242
3243 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args + 1, kw, &tmpstkctr);
3244 if (!stkctr)
3245 return 0;
3246
3247 smp->flags = SMP_F_VOL_TEST;
3248 smp->data.type = SMP_T_SINT;
3249 smp->data.u.sint = 0;
3250 if (stkctr_entry(stkctr) != NULL) {
3251 void *ptr;
3252
3253 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC_RATE, idx);
3254 if (!ptr) {
3255 if (stkctr == &tmpstkctr)
3256 stktable_release(stkctr->table, stkctr_entry(stkctr));
3257 return 0; /* parameter not stored */
3258 }
3259
3260 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3261
3262 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
3263 stkctr->table->data_arg[STKTABLE_DT_GPC_RATE].u);
3264
3265 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3266
3267 if (stkctr == &tmpstkctr)
3268 stktable_release(stkctr->table, stkctr_entry(stkctr));
3269 }
3270 return 1;
3271}
3272
Willy Tarreau7d562212016-11-25 16:10:05 +01003273/* set <smp> to the General Purpose Counter 0's event rate from the stream's
3274 * tracked frontend counters or from the src.
3275 * Supports being called as "sc[0-9]_gpc0_rate" or "src_gpc0_rate" only.
3276 * Value zero is returned if the key is new.
3277 */
3278static int
3279smp_fetch_sc_gpc0_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3280{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003281 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003282 struct stkctr *stkctr;
Emeric Brun726783d2021-06-30 19:06:43 +02003283 unsigned int period;
Willy Tarreau7d562212016-11-25 16:10:05 +01003284
Emeric Brun819fc6f2017-06-13 19:37:32 +02003285 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003286 if (!stkctr)
3287 return 0;
3288
3289 smp->flags = SMP_F_VOL_TEST;
3290 smp->data.type = SMP_T_SINT;
3291 smp->data.u.sint = 0;
3292 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003293 void *ptr;
3294
3295 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0_RATE);
Emeric Brun726783d2021-06-30 19:06:43 +02003296 if (ptr) {
3297 period = stkctr->table->data_arg[STKTABLE_DT_GPC0_RATE].u;
3298 }
3299 else {
3300 /* fallback on the gpc array */
3301 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC_RATE, 0);
3302 if (ptr)
3303 period = stkctr->table->data_arg[STKTABLE_DT_GPC_RATE].u;
3304 }
3305
Emeric Brun819fc6f2017-06-13 19:37:32 +02003306 if (!ptr) {
3307 if (stkctr == &tmpstkctr)
3308 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003309 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003310 }
3311
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003312 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003313
Emeric Brun726783d2021-06-30 19:06:43 +02003314 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp), period);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003315
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003316 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003317
3318 if (stkctr == &tmpstkctr)
3319 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003320 }
3321 return 1;
3322}
3323
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003324/* set <smp> to the General Purpose Counter 1's event rate from the stream's
3325 * tracked frontend counters or from the src.
3326 * Supports being called as "sc[0-9]_gpc1_rate" or "src_gpc1_rate" only.
3327 * Value zero is returned if the key is new.
3328 */
3329static int
3330smp_fetch_sc_gpc1_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3331{
3332 struct stkctr tmpstkctr;
3333 struct stkctr *stkctr;
Emeric Brun726783d2021-06-30 19:06:43 +02003334 unsigned int period;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003335
3336 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
3337 if (!stkctr)
3338 return 0;
3339
3340 smp->flags = SMP_F_VOL_TEST;
3341 smp->data.type = SMP_T_SINT;
3342 smp->data.u.sint = 0;
3343 if (stkctr_entry(stkctr) != NULL) {
3344 void *ptr;
3345
3346 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1_RATE);
Emeric Brun726783d2021-06-30 19:06:43 +02003347 if (ptr) {
3348 period = stkctr->table->data_arg[STKTABLE_DT_GPC1_RATE].u;
3349 }
3350 else {
3351 /* fallback on the gpc array */
3352 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC_RATE, 1);
3353 if (ptr)
3354 period = stkctr->table->data_arg[STKTABLE_DT_GPC_RATE].u;
3355 }
3356
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003357 if (!ptr) {
3358 if (stkctr == &tmpstkctr)
3359 stktable_release(stkctr->table, stkctr_entry(stkctr));
3360 return 0; /* parameter not stored */
3361 }
3362
3363 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3364
Emeric Brun726783d2021-06-30 19:06:43 +02003365 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 +01003366
3367 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3368
3369 if (stkctr == &tmpstkctr)
3370 stktable_release(stkctr->table, stkctr_entry(stkctr));
3371 }
3372 return 1;
3373}
3374
Emeric Brun4d7ada82021-06-30 19:04:16 +02003375/* Increment the GPC[args(0)] value from the stream's tracked
3376 * frontend counters and return it into temp integer.
3377 * Supports being called as "sc_inc_gpc(<gpc-idx>,<sc-idx>[,<table>])"
3378 * or "src_inc_gpc(<gpc-idx>[,<table>])" only.
3379 */
3380static int
3381smp_fetch_sc_inc_gpc(const struct arg *args, struct sample *smp, const char *kw, void *private)
3382{
3383 struct stkctr tmpstkctr;
3384 struct stkctr *stkctr;
3385 unsigned int idx;
3386
3387 idx = args[0].data.sint;
3388
3389 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args + 1, kw, &tmpstkctr);
3390 if (!stkctr)
3391 return 0;
3392
3393 smp->flags = SMP_F_VOL_TEST;
3394 smp->data.type = SMP_T_SINT;
3395 smp->data.u.sint = 0;
3396
3397 if (!stkctr_entry(stkctr))
3398 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
3399
3400 if (stkctr && stkctr_entry(stkctr)) {
3401 void *ptr1,*ptr2;
3402
3403
3404 /* First, update gpc0_rate if it's tracked. Second, update its
3405 * gpc0 if tracked. Returns gpc0's value otherwise the curr_ctr.
3406 */
3407 ptr1 = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC_RATE, idx);
3408 ptr2 = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC, idx);
3409 if (ptr1 || ptr2) {
3410 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3411
3412 if (ptr1) {
3413 update_freq_ctr_period(&stktable_data_cast(ptr1, std_t_frqp),
3414 stkctr->table->data_arg[STKTABLE_DT_GPC_RATE].u, 1);
3415 smp->data.u.sint = (&stktable_data_cast(ptr1, std_t_frqp))->curr_ctr;
3416 }
3417
3418 if (ptr2)
3419 smp->data.u.sint = ++stktable_data_cast(ptr2, std_t_uint);
3420
3421 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3422
3423 /* If data was modified, we need to touch to re-schedule sync */
3424 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
3425 }
3426 else if (stkctr == &tmpstkctr)
3427 stktable_release(stkctr->table, stkctr_entry(stkctr));
3428 }
3429 return 1;
3430}
3431
Willy Tarreau7d562212016-11-25 16:10:05 +01003432/* Increment the General Purpose Counter 0 value from the stream's tracked
3433 * frontend counters and return it into temp integer.
3434 * Supports being called as "sc[0-9]_inc_gpc0" or "src_inc_gpc0" only.
3435 */
3436static int
3437smp_fetch_sc_inc_gpc0(const struct arg *args, struct sample *smp, const char *kw, void *private)
3438{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003439 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003440 struct stkctr *stkctr;
Willy Tarreau5b654ad2021-07-06 18:51:12 +02003441 unsigned int period = 0;
Willy Tarreau7d562212016-11-25 16:10:05 +01003442
Emeric Brun819fc6f2017-06-13 19:37:32 +02003443 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003444 if (!stkctr)
3445 return 0;
3446
3447 smp->flags = SMP_F_VOL_TEST;
3448 smp->data.type = SMP_T_SINT;
3449 smp->data.u.sint = 0;
3450
Emeric Brun819fc6f2017-06-13 19:37:32 +02003451 if (!stkctr_entry(stkctr))
3452 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003453
3454 if (stkctr && stkctr_entry(stkctr)) {
3455 void *ptr1,*ptr2;
3456
Emeric Brun819fc6f2017-06-13 19:37:32 +02003457
Willy Tarreau7d562212016-11-25 16:10:05 +01003458 /* First, update gpc0_rate if it's tracked. Second, update its
3459 * gpc0 if tracked. Returns gpc0's value otherwise the curr_ctr.
3460 */
3461 ptr1 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0_RATE);
Emeric Brun726783d2021-06-30 19:06:43 +02003462 if (ptr1) {
3463 period = stkctr->table->data_arg[STKTABLE_DT_GPC0_RATE].u;
3464 }
3465 else {
3466 /* fallback on the gpc array */
3467 ptr1 = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC_RATE, 0);
3468 if (ptr1)
3469 period = stkctr->table->data_arg[STKTABLE_DT_GPC_RATE].u;
3470 }
3471
Willy Tarreau7d562212016-11-25 16:10:05 +01003472 ptr2 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0);
Emeric Brun726783d2021-06-30 19:06:43 +02003473 if (!ptr2) {
3474 /* fallback on the gpc array */
3475 ptr2 = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC, 0);
3476 }
3477
Emeric Brun819fc6f2017-06-13 19:37:32 +02003478 if (ptr1 || ptr2) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003479 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Willy Tarreau7d562212016-11-25 16:10:05 +01003480
Emeric Brun819fc6f2017-06-13 19:37:32 +02003481 if (ptr1) {
Emeric Brun0e3457b2021-06-30 17:18:28 +02003482 update_freq_ctr_period(&stktable_data_cast(ptr1, std_t_frqp),
Emeric Brun726783d2021-06-30 19:06:43 +02003483 period, 1);
Emeric Brun0e3457b2021-06-30 17:18:28 +02003484 smp->data.u.sint = (&stktable_data_cast(ptr1, std_t_frqp))->curr_ctr;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003485 }
3486
3487 if (ptr2)
Emeric Brun0e3457b2021-06-30 17:18:28 +02003488 smp->data.u.sint = ++stktable_data_cast(ptr2, std_t_uint);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003489
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003490 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003491
3492 /* If data was modified, we need to touch to re-schedule sync */
3493 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
3494 }
3495 else if (stkctr == &tmpstkctr)
3496 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003497 }
3498 return 1;
3499}
3500
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003501/* Increment the General Purpose Counter 1 value from the stream's tracked
3502 * frontend counters and return it into temp integer.
3503 * Supports being called as "sc[0-9]_inc_gpc1" or "src_inc_gpc1" only.
3504 */
3505static int
3506smp_fetch_sc_inc_gpc1(const struct arg *args, struct sample *smp, const char *kw, void *private)
3507{
3508 struct stkctr tmpstkctr;
3509 struct stkctr *stkctr;
Willy Tarreau5b654ad2021-07-06 18:51:12 +02003510 unsigned int period = 0;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003511
3512 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
3513 if (!stkctr)
3514 return 0;
3515
3516 smp->flags = SMP_F_VOL_TEST;
3517 smp->data.type = SMP_T_SINT;
3518 smp->data.u.sint = 0;
3519
3520 if (!stkctr_entry(stkctr))
3521 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
3522
3523 if (stkctr && stkctr_entry(stkctr)) {
3524 void *ptr1,*ptr2;
3525
3526
3527 /* First, update gpc1_rate if it's tracked. Second, update its
3528 * gpc1 if tracked. Returns gpc1's value otherwise the curr_ctr.
3529 */
3530 ptr1 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1_RATE);
Emeric Brun726783d2021-06-30 19:06:43 +02003531 if (ptr1) {
3532 period = stkctr->table->data_arg[STKTABLE_DT_GPC1_RATE].u;
3533 }
3534 else {
3535 /* fallback on the gpc array */
3536 ptr1 = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC_RATE, 1);
3537 if (ptr1)
3538 period = stkctr->table->data_arg[STKTABLE_DT_GPC_RATE].u;
3539 }
3540
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003541 ptr2 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1);
Emeric Brun726783d2021-06-30 19:06:43 +02003542 if (!ptr2) {
3543 /* fallback on the gpc array */
3544 ptr2 = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC, 1);
3545 }
3546
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003547 if (ptr1 || ptr2) {
3548 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3549
3550 if (ptr1) {
Emeric Brun0e3457b2021-06-30 17:18:28 +02003551 update_freq_ctr_period(&stktable_data_cast(ptr1, std_t_frqp),
Emeric Brun726783d2021-06-30 19:06:43 +02003552 period, 1);
Emeric Brun0e3457b2021-06-30 17:18:28 +02003553 smp->data.u.sint = (&stktable_data_cast(ptr1, std_t_frqp))->curr_ctr;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003554 }
3555
3556 if (ptr2)
Emeric Brun0e3457b2021-06-30 17:18:28 +02003557 smp->data.u.sint = ++stktable_data_cast(ptr2, std_t_uint);
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003558
3559 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3560
3561 /* If data was modified, we need to touch to re-schedule sync */
3562 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
3563 }
3564 else if (stkctr == &tmpstkctr)
3565 stktable_release(stkctr->table, stkctr_entry(stkctr));
3566 }
3567 return 1;
3568}
3569
Emeric Brun4d7ada82021-06-30 19:04:16 +02003570/* Clear the GPC[args(0)] value from the stream's tracked
3571 * frontend counters and return its previous value into temp integer.
3572 * Supports being called as "sc_clr_gpc(<gpc-idx>,<sc-idx>[,<table>])"
3573 * or "src_clr_gpc(<gpc-idx>[,<table>])" only.
3574 */
3575static int
3576smp_fetch_sc_clr_gpc(const struct arg *args, struct sample *smp, const char *kw, void *private)
3577{
3578 struct stkctr tmpstkctr;
3579 struct stkctr *stkctr;
3580 unsigned int idx;
3581
3582 idx = args[0].data.sint;
3583
3584 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args + 1, kw, &tmpstkctr);
3585 if (!stkctr)
3586 return 0;
3587
3588 smp->flags = SMP_F_VOL_TEST;
3589 smp->data.type = SMP_T_SINT;
3590 smp->data.u.sint = 0;
3591
3592 if (!stkctr_entry(stkctr))
3593 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
3594
3595 if (stkctr && stkctr_entry(stkctr)) {
3596 void *ptr;
3597
3598 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC, idx);
3599 if (!ptr) {
3600 if (stkctr == &tmpstkctr)
3601 stktable_release(stkctr->table, stkctr_entry(stkctr));
3602 return 0; /* parameter not stored */
3603 }
3604
3605 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3606
3607 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
3608 stktable_data_cast(ptr, std_t_uint) = 0;
3609
3610 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3611
3612 /* If data was modified, we need to touch to re-schedule sync */
3613 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
3614 }
3615 return 1;
3616}
3617
Willy Tarreau7d562212016-11-25 16:10:05 +01003618/* Clear the General Purpose Counter 0 value from the stream's tracked
3619 * frontend counters and return its previous value into temp integer.
3620 * Supports being called as "sc[0-9]_clr_gpc0" or "src_clr_gpc0" only.
3621 */
3622static int
3623smp_fetch_sc_clr_gpc0(const struct arg *args, struct sample *smp, const char *kw, void *private)
3624{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003625 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003626 struct stkctr *stkctr;
3627
Emeric Brun819fc6f2017-06-13 19:37:32 +02003628 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003629 if (!stkctr)
3630 return 0;
3631
3632 smp->flags = SMP_F_VOL_TEST;
3633 smp->data.type = SMP_T_SINT;
3634 smp->data.u.sint = 0;
3635
Emeric Brun819fc6f2017-06-13 19:37:32 +02003636 if (!stkctr_entry(stkctr))
3637 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003638
Emeric Brun819fc6f2017-06-13 19:37:32 +02003639 if (stkctr && stkctr_entry(stkctr)) {
3640 void *ptr;
3641
3642 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0);
3643 if (!ptr) {
Emeric Brun726783d2021-06-30 19:06:43 +02003644 /* fallback on the gpc array */
3645 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC, 0);
3646 }
3647
3648 if (!ptr) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003649 if (stkctr == &tmpstkctr)
3650 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003651 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003652 }
3653
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003654 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003655
Emeric Brun0e3457b2021-06-30 17:18:28 +02003656 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
3657 stktable_data_cast(ptr, std_t_uint) = 0;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003658
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003659 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003660
Willy Tarreau7d562212016-11-25 16:10:05 +01003661 /* If data was modified, we need to touch to re-schedule sync */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003662 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
Willy Tarreau7d562212016-11-25 16:10:05 +01003663 }
3664 return 1;
3665}
3666
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003667/* Clear the General Purpose Counter 1 value from the stream's tracked
3668 * frontend counters and return its previous value into temp integer.
3669 * Supports being called as "sc[0-9]_clr_gpc1" or "src_clr_gpc1" only.
3670 */
3671static int
3672smp_fetch_sc_clr_gpc1(const struct arg *args, struct sample *smp, const char *kw, void *private)
3673{
3674 struct stkctr tmpstkctr;
3675 struct stkctr *stkctr;
3676
3677 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
3678 if (!stkctr)
3679 return 0;
3680
3681 smp->flags = SMP_F_VOL_TEST;
3682 smp->data.type = SMP_T_SINT;
3683 smp->data.u.sint = 0;
3684
3685 if (!stkctr_entry(stkctr))
3686 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
3687
3688 if (stkctr && stkctr_entry(stkctr)) {
3689 void *ptr;
3690
3691 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1);
3692 if (!ptr) {
Emeric Brun726783d2021-06-30 19:06:43 +02003693 /* fallback on the gpc array */
3694 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC, 1);
3695 }
3696
3697 if (!ptr) {
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003698 if (stkctr == &tmpstkctr)
3699 stktable_release(stkctr->table, stkctr_entry(stkctr));
3700 return 0; /* parameter not stored */
3701 }
3702
3703 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3704
Emeric Brun0e3457b2021-06-30 17:18:28 +02003705 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
3706 stktable_data_cast(ptr, std_t_uint) = 0;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003707
3708 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3709
3710 /* If data was modified, we need to touch to re-schedule sync */
3711 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
3712 }
3713 return 1;
3714}
3715
Willy Tarreau7d562212016-11-25 16:10:05 +01003716/* set <smp> to the cumulated number of connections from the stream's tracked
3717 * frontend counters. Supports being called as "sc[0-9]_conn_cnt" or
3718 * "src_conn_cnt" only.
3719 */
3720static int
3721smp_fetch_sc_conn_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
3722{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003723 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003724 struct stkctr *stkctr;
3725
Emeric Brun819fc6f2017-06-13 19:37:32 +02003726 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003727 if (!stkctr)
3728 return 0;
3729
3730 smp->flags = SMP_F_VOL_TEST;
3731 smp->data.type = SMP_T_SINT;
3732 smp->data.u.sint = 0;
3733 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003734 void *ptr;
3735
3736 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_CONN_CNT);
3737 if (!ptr) {
3738 if (stkctr == &tmpstkctr)
3739 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003740 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003741 }
3742
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003743 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003744
Emeric Brun0e3457b2021-06-30 17:18:28 +02003745 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003746
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003747 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003748
3749 if (stkctr == &tmpstkctr)
3750 stktable_release(stkctr->table, stkctr_entry(stkctr));
3751
3752
Willy Tarreau7d562212016-11-25 16:10:05 +01003753 }
3754 return 1;
3755}
3756
3757/* set <smp> to the connection rate from the stream's tracked frontend
3758 * counters. Supports being called as "sc[0-9]_conn_rate" or "src_conn_rate"
3759 * only.
3760 */
3761static int
3762smp_fetch_sc_conn_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3763{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003764 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003765 struct stkctr *stkctr;
3766
Emeric Brun819fc6f2017-06-13 19:37:32 +02003767 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003768 if (!stkctr)
3769 return 0;
3770
3771 smp->flags = SMP_F_VOL_TEST;
3772 smp->data.type = SMP_T_SINT;
3773 smp->data.u.sint = 0;
3774 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003775 void *ptr;
3776
3777 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_CONN_RATE);
3778 if (!ptr) {
3779 if (stkctr == &tmpstkctr)
3780 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003781 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003782 }
3783
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003784 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003785
Emeric Brun0e3457b2021-06-30 17:18:28 +02003786 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Willy Tarreau7d562212016-11-25 16:10:05 +01003787 stkctr->table->data_arg[STKTABLE_DT_CONN_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003788
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003789 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003790
3791 if (stkctr == &tmpstkctr)
3792 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003793 }
3794 return 1;
3795}
3796
3797/* set temp integer to the number of connections from the stream's source address
3798 * in the table pointed to by expr, after updating it.
3799 * Accepts exactly 1 argument of type table.
3800 */
3801static int
3802smp_fetch_src_updt_conn_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
3803{
3804 struct connection *conn = objt_conn(smp->sess->origin);
3805 struct stksess *ts;
3806 struct stktable_key *key;
3807 void *ptr;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003808 struct stktable *t;
Willy Tarreau7d562212016-11-25 16:10:05 +01003809
3810 if (!conn)
3811 return 0;
3812
Joseph Herlant5662fa42018-11-15 13:43:28 -08003813 /* Fetch source address in a sample. */
Amaury Denoyellec460c702021-05-12 10:17:47 +02003814 if (!smp_fetch_src || !smp_fetch_src(empty_arg_list, smp, "src", NULL))
Willy Tarreau7d562212016-11-25 16:10:05 +01003815 return 0;
3816
3817 /* Converts into key. */
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003818 key = smp_to_stkey(smp, args->data.t);
Willy Tarreau7d562212016-11-25 16:10:05 +01003819 if (!key)
3820 return 0;
3821
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003822 t = args->data.t;
Willy Tarreau7d562212016-11-25 16:10:05 +01003823
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003824 if ((ts = stktable_get_entry(t, key)) == NULL)
Willy Tarreau7d562212016-11-25 16:10:05 +01003825 /* entry does not exist and could not be created */
3826 return 0;
3827
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003828 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_CONN_CNT);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003829 if (!ptr) {
Willy Tarreau7d562212016-11-25 16:10:05 +01003830 return 0; /* parameter not stored in this table */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003831 }
Willy Tarreau7d562212016-11-25 16:10:05 +01003832
3833 smp->data.type = SMP_T_SINT;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003834
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003835 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003836
Emeric Brun0e3457b2021-06-30 17:18:28 +02003837 smp->data.u.sint = ++stktable_data_cast(ptr, std_t_uint);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003838
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003839 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003840
Willy Tarreau7d562212016-11-25 16:10:05 +01003841 smp->flags = SMP_F_VOL_TEST;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003842
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003843 stktable_touch_local(t, ts, 1);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003844
3845 /* Touch was previously performed by stktable_update_key */
Willy Tarreau7d562212016-11-25 16:10:05 +01003846 return 1;
3847}
3848
3849/* set <smp> to the number of concurrent connections from the stream's tracked
3850 * frontend counters. Supports being called as "sc[0-9]_conn_cur" or
3851 * "src_conn_cur" only.
3852 */
3853static int
3854smp_fetch_sc_conn_cur(const struct arg *args, struct sample *smp, const char *kw, void *private)
3855{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003856 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003857 struct stkctr *stkctr;
3858
Emeric Brun819fc6f2017-06-13 19:37:32 +02003859 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003860 if (!stkctr)
3861 return 0;
3862
3863 smp->flags = SMP_F_VOL_TEST;
3864 smp->data.type = SMP_T_SINT;
3865 smp->data.u.sint = 0;
3866 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003867 void *ptr;
3868
3869 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_CONN_CUR);
3870 if (!ptr) {
3871 if (stkctr == &tmpstkctr)
3872 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003873 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003874 }
3875
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003876 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003877
Emeric Brun0e3457b2021-06-30 17:18:28 +02003878 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003879
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003880 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003881
3882 if (stkctr == &tmpstkctr)
3883 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003884 }
3885 return 1;
3886}
3887
3888/* set <smp> to the cumulated number of streams from the stream's tracked
3889 * frontend counters. Supports being called as "sc[0-9]_sess_cnt" or
3890 * "src_sess_cnt" only.
3891 */
3892static int
3893smp_fetch_sc_sess_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
3894{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003895 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003896 struct stkctr *stkctr;
3897
Emeric Brun819fc6f2017-06-13 19:37:32 +02003898 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003899 if (!stkctr)
3900 return 0;
3901
3902 smp->flags = SMP_F_VOL_TEST;
3903 smp->data.type = SMP_T_SINT;
3904 smp->data.u.sint = 0;
3905 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003906 void *ptr;
3907
3908 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_SESS_CNT);
3909 if (!ptr) {
3910 if (stkctr == &tmpstkctr)
3911 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003912 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003913 }
3914
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003915 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003916
Emeric Brun0e3457b2021-06-30 17:18:28 +02003917 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003918
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003919 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003920
3921 if (stkctr == &tmpstkctr)
3922 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003923 }
3924 return 1;
3925}
3926
3927/* set <smp> to the stream rate from the stream's tracked frontend counters.
3928 * Supports being called as "sc[0-9]_sess_rate" or "src_sess_rate" only.
3929 */
3930static int
3931smp_fetch_sc_sess_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3932{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003933 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003934 struct stkctr *stkctr;
3935
Emeric Brun819fc6f2017-06-13 19:37:32 +02003936 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003937 if (!stkctr)
3938 return 0;
3939
3940 smp->flags = SMP_F_VOL_TEST;
3941 smp->data.type = SMP_T_SINT;
3942 smp->data.u.sint = 0;
3943 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003944 void *ptr;
3945
3946 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_SESS_RATE);
3947 if (!ptr) {
3948 if (stkctr == &tmpstkctr)
3949 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003950 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003951 }
3952
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003953 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003954
Emeric Brun0e3457b2021-06-30 17:18:28 +02003955 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Willy Tarreau7d562212016-11-25 16:10:05 +01003956 stkctr->table->data_arg[STKTABLE_DT_SESS_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003957
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003958 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003959
3960 if (stkctr == &tmpstkctr)
3961 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003962 }
3963 return 1;
3964}
3965
3966/* set <smp> to the cumulated number of HTTP requests from the stream's tracked
3967 * frontend counters. Supports being called as "sc[0-9]_http_req_cnt" or
3968 * "src_http_req_cnt" only.
3969 */
3970static int
3971smp_fetch_sc_http_req_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
3972{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003973 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003974 struct stkctr *stkctr;
3975
Emeric Brun819fc6f2017-06-13 19:37:32 +02003976 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003977 if (!stkctr)
3978 return 0;
3979
3980 smp->flags = SMP_F_VOL_TEST;
3981 smp->data.type = SMP_T_SINT;
3982 smp->data.u.sint = 0;
3983 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003984 void *ptr;
3985
3986 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_REQ_CNT);
3987 if (!ptr) {
3988 if (stkctr == &tmpstkctr)
3989 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003990 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003991 }
3992
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003993 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003994
Emeric Brun0e3457b2021-06-30 17:18:28 +02003995 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003996
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003997 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003998
3999 if (stkctr == &tmpstkctr)
4000 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004001 }
4002 return 1;
4003}
4004
4005/* set <smp> to the HTTP request rate from the stream's tracked frontend
4006 * counters. Supports being called as "sc[0-9]_http_req_rate" or
4007 * "src_http_req_rate" only.
4008 */
4009static int
4010smp_fetch_sc_http_req_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
4011{
Emeric Brun819fc6f2017-06-13 19:37:32 +02004012 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01004013 struct stkctr *stkctr;
4014
Emeric Brun819fc6f2017-06-13 19:37:32 +02004015 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01004016 if (!stkctr)
4017 return 0;
4018
4019 smp->flags = SMP_F_VOL_TEST;
4020 smp->data.type = SMP_T_SINT;
4021 smp->data.u.sint = 0;
4022 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02004023 void *ptr;
4024
4025 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_REQ_RATE);
4026 if (!ptr) {
4027 if (stkctr == &tmpstkctr)
4028 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004029 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02004030 }
4031
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004032 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004033
Emeric Brun0e3457b2021-06-30 17:18:28 +02004034 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Willy Tarreau7d562212016-11-25 16:10:05 +01004035 stkctr->table->data_arg[STKTABLE_DT_HTTP_REQ_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004036
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004037 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004038
4039 if (stkctr == &tmpstkctr)
4040 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004041 }
4042 return 1;
4043}
4044
4045/* set <smp> to the cumulated number of HTTP requests errors from the stream's
4046 * tracked frontend counters. Supports being called as "sc[0-9]_http_err_cnt" or
4047 * "src_http_err_cnt" only.
4048 */
4049static int
4050smp_fetch_sc_http_err_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
4051{
Emeric Brun819fc6f2017-06-13 19:37:32 +02004052 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01004053 struct stkctr *stkctr;
4054
Emeric Brun819fc6f2017-06-13 19:37:32 +02004055 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01004056 if (!stkctr)
4057 return 0;
4058
4059 smp->flags = SMP_F_VOL_TEST;
4060 smp->data.type = SMP_T_SINT;
4061 smp->data.u.sint = 0;
4062 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02004063 void *ptr;
4064
4065 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_ERR_CNT);
4066 if (!ptr) {
4067 if (stkctr == &tmpstkctr)
4068 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004069 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02004070 }
4071
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004072 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004073
Emeric Brun0e3457b2021-06-30 17:18:28 +02004074 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004075
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004076 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004077
4078 if (stkctr == &tmpstkctr)
4079 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004080 }
4081 return 1;
4082}
4083
4084/* set <smp> to the HTTP request error rate from the stream's tracked frontend
4085 * counters. Supports being called as "sc[0-9]_http_err_rate" or
4086 * "src_http_err_rate" only.
4087 */
4088static int
4089smp_fetch_sc_http_err_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
4090{
Emeric Brun819fc6f2017-06-13 19:37:32 +02004091 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01004092 struct stkctr *stkctr;
4093
Emeric Brun819fc6f2017-06-13 19:37:32 +02004094 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01004095 if (!stkctr)
4096 return 0;
4097
4098 smp->flags = SMP_F_VOL_TEST;
4099 smp->data.type = SMP_T_SINT;
4100 smp->data.u.sint = 0;
4101 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02004102 void *ptr;
4103
4104 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_ERR_RATE);
4105 if (!ptr) {
4106 if (stkctr == &tmpstkctr)
4107 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004108 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02004109 }
4110
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004111 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004112
Emeric Brun0e3457b2021-06-30 17:18:28 +02004113 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Willy Tarreau7d562212016-11-25 16:10:05 +01004114 stkctr->table->data_arg[STKTABLE_DT_HTTP_ERR_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004115
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004116 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004117
4118 if (stkctr == &tmpstkctr)
4119 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004120 }
4121 return 1;
4122}
4123
Willy Tarreau826f3ab2021-02-10 12:07:15 +01004124/* set <smp> to the cumulated number of HTTP response failures from the stream's
4125 * tracked frontend counters. Supports being called as "sc[0-9]_http_fail_cnt" or
4126 * "src_http_fail_cnt" only.
4127 */
4128static int
4129smp_fetch_sc_http_fail_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
4130{
4131 struct stkctr tmpstkctr;
4132 struct stkctr *stkctr;
4133
4134 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
4135 if (!stkctr)
4136 return 0;
4137
4138 smp->flags = SMP_F_VOL_TEST;
4139 smp->data.type = SMP_T_SINT;
4140 smp->data.u.sint = 0;
4141 if (stkctr_entry(stkctr) != NULL) {
4142 void *ptr;
4143
4144 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_FAIL_CNT);
4145 if (!ptr) {
4146 if (stkctr == &tmpstkctr)
4147 stktable_release(stkctr->table, stkctr_entry(stkctr));
4148 return 0; /* parameter not stored */
4149 }
4150
4151 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
4152
Emeric Brun0e3457b2021-06-30 17:18:28 +02004153 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Willy Tarreau826f3ab2021-02-10 12:07:15 +01004154
4155 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
4156
4157 if (stkctr == &tmpstkctr)
4158 stktable_release(stkctr->table, stkctr_entry(stkctr));
4159 }
4160 return 1;
4161}
4162
4163/* set <smp> to the HTTP response failure rate from the stream's tracked frontend
4164 * counters. Supports being called as "sc[0-9]_http_fail_rate" or
4165 * "src_http_fail_rate" only.
4166 */
4167static int
4168smp_fetch_sc_http_fail_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
4169{
4170 struct stkctr tmpstkctr;
4171 struct stkctr *stkctr;
4172
4173 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
4174 if (!stkctr)
4175 return 0;
4176
4177 smp->flags = SMP_F_VOL_TEST;
4178 smp->data.type = SMP_T_SINT;
4179 smp->data.u.sint = 0;
4180 if (stkctr_entry(stkctr) != NULL) {
4181 void *ptr;
4182
4183 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_FAIL_RATE);
4184 if (!ptr) {
4185 if (stkctr == &tmpstkctr)
4186 stktable_release(stkctr->table, stkctr_entry(stkctr));
4187 return 0; /* parameter not stored */
4188 }
4189
4190 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
4191
Emeric Brun0e3457b2021-06-30 17:18:28 +02004192 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Willy Tarreau826f3ab2021-02-10 12:07:15 +01004193 stkctr->table->data_arg[STKTABLE_DT_HTTP_FAIL_RATE].u);
4194
4195 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
4196
4197 if (stkctr == &tmpstkctr)
4198 stktable_release(stkctr->table, stkctr_entry(stkctr));
4199 }
4200 return 1;
4201}
4202
Willy Tarreau7d562212016-11-25 16:10:05 +01004203/* set <smp> to the number of kbytes received from clients, as found in the
4204 * stream's tracked frontend counters. Supports being called as
4205 * "sc[0-9]_kbytes_in" or "src_kbytes_in" only.
4206 */
4207static int
4208smp_fetch_sc_kbytes_in(const struct arg *args, struct sample *smp, const char *kw, void *private)
4209{
Emeric Brun819fc6f2017-06-13 19:37:32 +02004210 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01004211 struct stkctr *stkctr;
4212
Emeric Brun819fc6f2017-06-13 19:37:32 +02004213 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01004214 if (!stkctr)
4215 return 0;
4216
4217 smp->flags = SMP_F_VOL_TEST;
4218 smp->data.type = SMP_T_SINT;
4219 smp->data.u.sint = 0;
4220 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02004221 void *ptr;
4222
4223 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_IN_CNT);
4224 if (!ptr) {
4225 if (stkctr == &tmpstkctr)
4226 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004227 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02004228 }
4229
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004230 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004231
Emeric Brun0e3457b2021-06-30 17:18:28 +02004232 smp->data.u.sint = stktable_data_cast(ptr, std_t_ull) >> 10;
Emeric Brun819fc6f2017-06-13 19:37:32 +02004233
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004234 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004235
4236 if (stkctr == &tmpstkctr)
4237 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004238 }
4239 return 1;
4240}
4241
4242/* set <smp> to the data rate received from clients in bytes/s, as found
4243 * in the stream's tracked frontend counters. Supports being called as
4244 * "sc[0-9]_bytes_in_rate" or "src_bytes_in_rate" only.
4245 */
4246static int
4247smp_fetch_sc_bytes_in_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
4248{
Emeric Brun819fc6f2017-06-13 19:37:32 +02004249 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01004250 struct stkctr *stkctr;
4251
Emeric Brun819fc6f2017-06-13 19:37:32 +02004252 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01004253 if (!stkctr)
4254 return 0;
4255
4256 smp->flags = SMP_F_VOL_TEST;
4257 smp->data.type = SMP_T_SINT;
4258 smp->data.u.sint = 0;
4259 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02004260 void *ptr;
4261
4262 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_IN_RATE);
4263 if (!ptr) {
4264 if (stkctr == &tmpstkctr)
4265 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004266 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02004267 }
4268
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004269 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004270
Emeric Brun0e3457b2021-06-30 17:18:28 +02004271 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Willy Tarreau7d562212016-11-25 16:10:05 +01004272 stkctr->table->data_arg[STKTABLE_DT_BYTES_IN_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004273
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004274 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004275
4276 if (stkctr == &tmpstkctr)
4277 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004278 }
4279 return 1;
4280}
4281
4282/* set <smp> to the number of kbytes sent to clients, as found in the
4283 * stream's tracked frontend counters. Supports being called as
4284 * "sc[0-9]_kbytes_out" or "src_kbytes_out" only.
4285 */
4286static int
4287smp_fetch_sc_kbytes_out(const struct arg *args, struct sample *smp, const char *kw, void *private)
4288{
Emeric Brun819fc6f2017-06-13 19:37:32 +02004289 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01004290 struct stkctr *stkctr;
4291
Emeric Brun819fc6f2017-06-13 19:37:32 +02004292 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01004293 if (!stkctr)
4294 return 0;
4295
4296 smp->flags = SMP_F_VOL_TEST;
4297 smp->data.type = SMP_T_SINT;
4298 smp->data.u.sint = 0;
4299 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02004300 void *ptr;
4301
4302 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_OUT_CNT);
4303 if (!ptr) {
4304 if (stkctr == &tmpstkctr)
4305 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004306 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02004307 }
4308
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004309 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004310
Emeric Brun0e3457b2021-06-30 17:18:28 +02004311 smp->data.u.sint = stktable_data_cast(ptr, std_t_ull) >> 10;
Emeric Brun819fc6f2017-06-13 19:37:32 +02004312
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004313 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004314
4315 if (stkctr == &tmpstkctr)
4316 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004317 }
4318 return 1;
4319}
4320
4321/* set <smp> to the data rate sent to clients in bytes/s, as found in the
4322 * stream's tracked frontend counters. Supports being called as
4323 * "sc[0-9]_bytes_out_rate" or "src_bytes_out_rate" only.
4324 */
4325static int
4326smp_fetch_sc_bytes_out_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
4327{
Emeric Brun819fc6f2017-06-13 19:37:32 +02004328 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01004329 struct stkctr *stkctr;
4330
Emeric Brun819fc6f2017-06-13 19:37:32 +02004331 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01004332 if (!stkctr)
4333 return 0;
4334
4335 smp->flags = SMP_F_VOL_TEST;
4336 smp->data.type = SMP_T_SINT;
4337 smp->data.u.sint = 0;
4338 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02004339 void *ptr;
4340
4341 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_OUT_RATE);
4342 if (!ptr) {
4343 if (stkctr == &tmpstkctr)
4344 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004345 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02004346 }
4347
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004348 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004349
Emeric Brun0e3457b2021-06-30 17:18:28 +02004350 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Willy Tarreau7d562212016-11-25 16:10:05 +01004351 stkctr->table->data_arg[STKTABLE_DT_BYTES_OUT_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004352
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004353 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004354
4355 if (stkctr == &tmpstkctr)
4356 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004357 }
4358 return 1;
4359}
4360
4361/* set <smp> to the number of active trackers on the SC entry in the stream's
4362 * tracked frontend counters. Supports being called as "sc[0-9]_trackers" only.
4363 */
4364static int
4365smp_fetch_sc_trackers(const struct arg *args, struct sample *smp, const char *kw, void *private)
4366{
Emeric Brun819fc6f2017-06-13 19:37:32 +02004367 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01004368 struct stkctr *stkctr;
4369
Emeric Brun819fc6f2017-06-13 19:37:32 +02004370 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01004371 if (!stkctr)
4372 return 0;
4373
4374 smp->flags = SMP_F_VOL_TEST;
4375 smp->data.type = SMP_T_SINT;
Emeric Brun819fc6f2017-06-13 19:37:32 +02004376 if (stkctr == &tmpstkctr) {
4377 smp->data.u.sint = stkctr_entry(stkctr) ? (stkctr_entry(stkctr)->ref_cnt-1) : 0;
4378 stktable_release(stkctr->table, stkctr_entry(stkctr));
4379 }
4380 else {
4381 smp->data.u.sint = stkctr_entry(stkctr) ? stkctr_entry(stkctr)->ref_cnt : 0;
4382 }
4383
Willy Tarreau7d562212016-11-25 16:10:05 +01004384 return 1;
4385}
4386
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004387
4388/* The functions below are used to manipulate table contents from the CLI.
4389 * There are 3 main actions, "clear", "set" and "show". The code is shared
4390 * between all actions, and the action is encoded in the void *private in
4391 * the appctx as well as in the keyword registration, among one of the
4392 * following values.
4393 */
4394
4395enum {
4396 STK_CLI_ACT_CLR,
4397 STK_CLI_ACT_SET,
4398 STK_CLI_ACT_SHOW,
4399};
4400
Willy Tarreau4596fe22022-05-17 19:07:51 +02004401/* Dump the status of a table to a stream connector's
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004402 * read buffer. It returns 0 if the output buffer is full
4403 * and needs to be called again, otherwise non-zero.
4404 */
Willy Tarreau83061a82018-07-13 11:56:34 +02004405static int table_dump_head_to_buffer(struct buffer *msg,
Willy Tarreaud0a06d52022-05-18 15:07:19 +02004406 struct appctx *appctx,
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004407 struct stktable *t, struct stktable *target)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004408{
Willy Tarreauc12b3212022-05-27 11:08:15 +02004409 struct stream *s = __sc_strm(appctx_sc(appctx));
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004410
4411 chunk_appendf(msg, "# table: %s, type: %s, size:%d, used:%d\n",
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004412 t->id, stktable_types[t->type].kw, t->size, t->current);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004413
4414 /* any other information should be dumped here */
4415
William Lallemand07a62f72017-05-24 00:57:40 +02004416 if (target && (strm_li(s)->bind_conf->level & ACCESS_LVL_MASK) < ACCESS_LVL_OPER)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004417 chunk_appendf(msg, "# contents not dumped due to insufficient privileges\n");
4418
Willy Tarreaud0a06d52022-05-18 15:07:19 +02004419 if (applet_putchk(appctx, msg) == -1)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004420 return 0;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004421
4422 return 1;
4423}
4424
Willy Tarreau4596fe22022-05-17 19:07:51 +02004425/* Dump a table entry to a stream connector's
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004426 * read buffer. It returns 0 if the output buffer is full
4427 * and needs to be called again, otherwise non-zero.
4428 */
Willy Tarreau83061a82018-07-13 11:56:34 +02004429static int table_dump_entry_to_buffer(struct buffer *msg,
Willy Tarreaud0a06d52022-05-18 15:07:19 +02004430 struct appctx *appctx,
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004431 struct stktable *t, struct stksess *entry)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004432{
4433 int dt;
4434
4435 chunk_appendf(msg, "%p:", entry);
4436
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004437 if (t->type == SMP_T_IPV4) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004438 char addr[INET_ADDRSTRLEN];
4439 inet_ntop(AF_INET, (const void *)&entry->key.key, addr, sizeof(addr));
4440 chunk_appendf(msg, " key=%s", addr);
4441 }
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004442 else if (t->type == SMP_T_IPV6) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004443 char addr[INET6_ADDRSTRLEN];
4444 inet_ntop(AF_INET6, (const void *)&entry->key.key, addr, sizeof(addr));
4445 chunk_appendf(msg, " key=%s", addr);
4446 }
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004447 else if (t->type == SMP_T_SINT) {
Willy Tarreau6cde5d82020-02-25 09:41:22 +01004448 chunk_appendf(msg, " key=%u", read_u32(entry->key.key));
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004449 }
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004450 else if (t->type == SMP_T_STR) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004451 chunk_appendf(msg, " key=");
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004452 dump_text(msg, (const char *)entry->key.key, t->key_size);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004453 }
4454 else {
4455 chunk_appendf(msg, " key=");
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004456 dump_binary(msg, (const char *)entry->key.key, t->key_size);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004457 }
4458
Willy Tarreau16b282f2022-11-29 11:55:18 +01004459 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 +01004460
4461 for (dt = 0; dt < STKTABLE_DATA_TYPES; dt++) {
4462 void *ptr;
4463
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004464 if (t->data_ofs[dt] == 0)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004465 continue;
Emeric Brunc64a2a32021-06-30 18:01:02 +02004466 if (stktable_data_types[dt].is_array) {
4467 char tmp[16] = {};
4468 const char *name_pfx = stktable_data_types[dt].name;
4469 const char *name_sfx = NULL;
4470 unsigned int idx = 0;
4471 int i = 0;
4472
4473 /* split name to show index before first _ of the name
4474 * for example: 'gpc3_rate' if array name is 'gpc_rate'.
4475 */
4476 for (i = 0 ; i < (sizeof(tmp) - 1); i++) {
4477 if (!name_pfx[i])
4478 break;
4479 if (name_pfx[i] == '_') {
4480 name_pfx = &tmp[0];
4481 name_sfx = &stktable_data_types[dt].name[i];
4482 break;
4483 }
4484 tmp[i] = name_pfx[i];
4485 }
4486
4487 ptr = stktable_data_ptr_idx(t, entry, dt, idx);
4488 while (ptr) {
4489 if (stktable_data_types[dt].arg_type == ARG_T_DELAY)
4490 chunk_appendf(msg, " %s%u%s(%u)=", name_pfx, idx, name_sfx ? name_sfx : "", t->data_arg[dt].u);
4491 else
4492 chunk_appendf(msg, " %s%u%s=", name_pfx, idx, name_sfx ? name_sfx : "");
4493 switch (stktable_data_types[dt].std_type) {
4494 case STD_T_SINT:
4495 chunk_appendf(msg, "%d", stktable_data_cast(ptr, std_t_sint));
4496 break;
4497 case STD_T_UINT:
4498 chunk_appendf(msg, "%u", stktable_data_cast(ptr, std_t_uint));
4499 break;
4500 case STD_T_ULL:
4501 chunk_appendf(msg, "%llu", stktable_data_cast(ptr, std_t_ull));
4502 break;
4503 case STD_T_FRQP:
4504 chunk_appendf(msg, "%u",
4505 read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
4506 t->data_arg[dt].u));
4507 break;
4508 }
4509 ptr = stktable_data_ptr_idx(t, entry, dt, ++idx);
4510 }
4511 continue;
4512 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004513 if (stktable_data_types[dt].arg_type == ARG_T_DELAY)
Emeric Brun01928ae2021-06-30 16:24:04 +02004514 chunk_appendf(msg, " %s(%u)=", stktable_data_types[dt].name, t->data_arg[dt].u);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004515 else
4516 chunk_appendf(msg, " %s=", stktable_data_types[dt].name);
4517
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004518 ptr = stktable_data_ptr(t, entry, dt);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004519 switch (stktable_data_types[dt].std_type) {
4520 case STD_T_SINT:
4521 chunk_appendf(msg, "%d", stktable_data_cast(ptr, std_t_sint));
4522 break;
4523 case STD_T_UINT:
4524 chunk_appendf(msg, "%u", stktable_data_cast(ptr, std_t_uint));
4525 break;
4526 case STD_T_ULL:
Emeric Brun01928ae2021-06-30 16:24:04 +02004527 chunk_appendf(msg, "%llu", stktable_data_cast(ptr, std_t_ull));
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004528 break;
4529 case STD_T_FRQP:
Emeric Brun01928ae2021-06-30 16:24:04 +02004530 chunk_appendf(msg, "%u",
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004531 read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004532 t->data_arg[dt].u));
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004533 break;
Frédéric Lécaille16b4f542019-05-23 12:15:04 +02004534 case STD_T_DICT: {
4535 struct dict_entry *de;
4536 de = stktable_data_cast(ptr, std_t_dict);
4537 chunk_appendf(msg, "%s", de ? (char *)de->value.key : "-");
4538 break;
4539 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004540 }
4541 }
4542 chunk_appendf(msg, "\n");
4543
Willy Tarreaud0a06d52022-05-18 15:07:19 +02004544 if (applet_putchk(appctx, msg) == -1)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004545 return 0;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004546
4547 return 1;
4548}
4549
Willy Tarreau3c69e082022-05-03 11:35:07 +02004550/* appctx context used by the "show table" command */
4551struct show_table_ctx {
4552 void *target; /* table we want to dump, or NULL for all */
4553 struct stktable *t; /* table being currently dumped (first if NULL) */
4554 struct stksess *entry; /* last entry we were trying to dump (or first if NULL) */
4555 long long value[STKTABLE_FILTER_LEN]; /* value to compare against */
4556 signed char data_type[STKTABLE_FILTER_LEN]; /* type of data to compare, or -1 if none */
4557 signed char data_op[STKTABLE_FILTER_LEN]; /* operator (STD_OP_*) when data_type set */
Willy Tarreau7849d4c2022-05-03 11:45:02 +02004558 enum {
Willy Tarreau0f154ed2022-05-03 12:02:36 +02004559 STATE_NEXT = 0, /* px points to next table, entry=NULL */
Willy Tarreau7849d4c2022-05-03 11:45:02 +02004560 STATE_DUMP, /* px points to curr table, entry is valid, refcount held */
4561 STATE_DONE, /* done dumping */
4562 } state;
Willy Tarreau3c69e082022-05-03 11:35:07 +02004563 char action; /* action on the table : one of STK_CLI_ACT_* */
4564};
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004565
4566/* Processes a single table entry matching a specific key passed in argument.
4567 * returns 0 if wants to be called again, 1 if has ended processing.
4568 */
4569static int table_process_entry_per_key(struct appctx *appctx, char **args)
4570{
Willy Tarreau3c69e082022-05-03 11:35:07 +02004571 struct show_table_ctx *ctx = appctx->svcctx;
4572 struct stktable *t = ctx->target;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004573 struct stksess *ts;
4574 uint32_t uint32_key;
4575 unsigned char ip6_key[sizeof(struct in6_addr)];
4576 long long value;
4577 int data_type;
4578 int cur_arg;
4579 void *ptr;
Willy Tarreaufa1258f2021-04-10 23:00:53 +02004580 struct freq_ctr *frqp;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004581
Willy Tarreau9d008692019-08-09 11:21:01 +02004582 if (!*args[4])
4583 return cli_err(appctx, "Key value expected\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004584
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004585 switch (t->type) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004586 case SMP_T_IPV4:
4587 uint32_key = htonl(inetaddr_host(args[4]));
Christopher Fauletca20d022017-08-29 15:30:31 +02004588 static_table_key.key = &uint32_key;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004589 break;
4590 case SMP_T_IPV6:
Christopher Fauletb7c962b2021-11-15 09:17:25 +01004591 if (inet_pton(AF_INET6, args[4], ip6_key) <= 0)
4592 return cli_err(appctx, "Invalid key\n");
Christopher Fauletca20d022017-08-29 15:30:31 +02004593 static_table_key.key = &ip6_key;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004594 break;
4595 case SMP_T_SINT:
4596 {
4597 char *endptr;
4598 unsigned long val;
4599 errno = 0;
4600 val = strtoul(args[4], &endptr, 10);
4601 if ((errno == ERANGE && val == ULONG_MAX) ||
4602 (errno != 0 && val == 0) || endptr == args[4] ||
Willy Tarreau9d008692019-08-09 11:21:01 +02004603 val > 0xffffffff)
4604 return cli_err(appctx, "Invalid key\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004605 uint32_key = (uint32_t) val;
Christopher Fauletca20d022017-08-29 15:30:31 +02004606 static_table_key.key = &uint32_key;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004607 break;
4608 }
4609 break;
4610 case SMP_T_STR:
Christopher Fauletca20d022017-08-29 15:30:31 +02004611 static_table_key.key = args[4];
4612 static_table_key.key_len = strlen(args[4]);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004613 break;
4614 default:
Willy Tarreau3c69e082022-05-03 11:35:07 +02004615 switch (ctx->action) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004616 case STK_CLI_ACT_SHOW:
Willy Tarreau9d008692019-08-09 11:21:01 +02004617 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 +01004618 case STK_CLI_ACT_CLR:
Willy Tarreau9d008692019-08-09 11:21:01 +02004619 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 +01004620 case STK_CLI_ACT_SET:
Willy Tarreau9d008692019-08-09 11:21:01 +02004621 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 +01004622 default:
Willy Tarreau9d008692019-08-09 11:21:01 +02004623 return cli_err(appctx, "Unknown action\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004624 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004625 }
4626
4627 /* check permissions */
4628 if (!cli_has_level(appctx, ACCESS_LVL_OPER))
4629 return 1;
4630
Willy Tarreau3c69e082022-05-03 11:35:07 +02004631 switch (ctx->action) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004632 case STK_CLI_ACT_SHOW:
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004633 ts = stktable_lookup_key(t, &static_table_key);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004634 if (!ts)
4635 return 1;
4636 chunk_reset(&trash);
Willy Tarreaud0a06d52022-05-18 15:07:19 +02004637 if (!table_dump_head_to_buffer(&trash, appctx, t, t)) {
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004638 stktable_release(t, ts);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004639 return 0;
Emeric Brun819fc6f2017-06-13 19:37:32 +02004640 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004641 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &ts->lock);
Willy Tarreaud0a06d52022-05-18 15:07:19 +02004642 if (!table_dump_entry_to_buffer(&trash, appctx, t, ts)) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004643 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004644 stktable_release(t, ts);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004645 return 0;
Emeric Brun819fc6f2017-06-13 19:37:32 +02004646 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004647 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004648 stktable_release(t, ts);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004649 break;
4650
4651 case STK_CLI_ACT_CLR:
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004652 ts = stktable_lookup_key(t, &static_table_key);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004653 if (!ts)
4654 return 1;
Emeric Brun819fc6f2017-06-13 19:37:32 +02004655
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004656 if (!stksess_kill(t, ts, 1)) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004657 /* don't delete an entry which is currently referenced */
Willy Tarreau9d008692019-08-09 11:21:01 +02004658 return cli_err(appctx, "Entry currently in use, cannot remove\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004659 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004660 break;
4661
4662 case STK_CLI_ACT_SET:
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004663 ts = stktable_get_entry(t, &static_table_key);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004664 if (!ts) {
4665 /* don't delete an entry which is currently referenced */
Willy Tarreau9d008692019-08-09 11:21:01 +02004666 return cli_err(appctx, "Unable to allocate a new entry\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004667 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004668 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004669 for (cur_arg = 5; *args[cur_arg]; cur_arg += 2) {
4670 if (strncmp(args[cur_arg], "data.", 5) != 0) {
Willy Tarreau9d008692019-08-09 11:21:01 +02004671 cli_err(appctx, "\"data.<type>\" followed by a value expected\n");
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004672 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004673 stktable_touch_local(t, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004674 return 1;
4675 }
4676
4677 data_type = stktable_get_data_type(args[cur_arg] + 5);
4678 if (data_type < 0) {
Willy Tarreau9d008692019-08-09 11:21:01 +02004679 cli_err(appctx, "Unknown data type\n");
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004680 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004681 stktable_touch_local(t, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004682 return 1;
4683 }
4684
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004685 if (!t->data_ofs[data_type]) {
Willy Tarreau9d008692019-08-09 11:21:01 +02004686 cli_err(appctx, "Data type not stored in this table\n");
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004687 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004688 stktable_touch_local(t, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004689 return 1;
4690 }
4691
4692 if (!*args[cur_arg+1] || strl2llrc(args[cur_arg+1], strlen(args[cur_arg+1]), &value) != 0) {
Willy Tarreau9d008692019-08-09 11:21:01 +02004693 cli_err(appctx, "Require a valid integer value to store\n");
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004694 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004695 stktable_touch_local(t, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004696 return 1;
4697 }
4698
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004699 ptr = stktable_data_ptr(t, ts, data_type);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004700
4701 switch (stktable_data_types[data_type].std_type) {
4702 case STD_T_SINT:
4703 stktable_data_cast(ptr, std_t_sint) = value;
4704 break;
4705 case STD_T_UINT:
4706 stktable_data_cast(ptr, std_t_uint) = value;
4707 break;
4708 case STD_T_ULL:
4709 stktable_data_cast(ptr, std_t_ull) = value;
4710 break;
4711 case STD_T_FRQP:
4712 /* We set both the current and previous values. That way
4713 * the reported frequency is stable during all the period
4714 * then slowly fades out. This allows external tools to
4715 * push measures without having to update them too often.
4716 */
4717 frqp = &stktable_data_cast(ptr, std_t_frqp);
Willy Tarreaufa1258f2021-04-10 23:00:53 +02004718 /* First bit is reserved for the freq_ctr lock
Emeric Brunf2fc1fd2017-11-02 17:32:43 +01004719 Note: here we're still protected by the stksess lock
Willy Tarreaufa1258f2021-04-10 23:00:53 +02004720 so we don't need to update the update the freq_ctr
Emeric Brunf2fc1fd2017-11-02 17:32:43 +01004721 using its internal lock */
4722 frqp->curr_tick = now_ms & ~0x1;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004723 frqp->prev_ctr = 0;
4724 frqp->curr_ctr = value;
4725 break;
4726 }
4727 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004728 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004729 stktable_touch_local(t, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004730 break;
4731
4732 default:
Willy Tarreau9d008692019-08-09 11:21:01 +02004733 return cli_err(appctx, "Unknown action\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004734 }
4735 return 1;
4736}
4737
4738/* Prepares the appctx fields with the data-based filters from the command line.
4739 * Returns 0 if the dump can proceed, 1 if has ended processing.
4740 */
4741static int table_prepare_data_request(struct appctx *appctx, char **args)
4742{
Willy Tarreau3c69e082022-05-03 11:35:07 +02004743 struct show_table_ctx *ctx = appctx->svcctx;
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004744 int i;
Adis Nezirovicd0142e72020-01-22 16:50:27 +01004745 char *err = NULL;
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004746
Willy Tarreau3c69e082022-05-03 11:35:07 +02004747 if (ctx->action != STK_CLI_ACT_SHOW && ctx->action != STK_CLI_ACT_CLR)
Willy Tarreau9d008692019-08-09 11:21:01 +02004748 return cli_err(appctx, "content-based lookup is only supported with the \"show\" and \"clear\" actions\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004749
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004750 for (i = 0; i < STKTABLE_FILTER_LEN; i++) {
4751 if (i > 0 && !*args[3+3*i]) // number of filter entries can be less than STKTABLE_FILTER_LEN
4752 break;
4753 /* condition on stored data value */
Willy Tarreau3c69e082022-05-03 11:35:07 +02004754 ctx->data_type[i] = stktable_get_data_type(args[3+3*i] + 5);
4755 if (ctx->data_type[i] < 0)
Adis Nezirovicd0142e72020-01-22 16:50:27 +01004756 return cli_dynerr(appctx, memprintf(&err, "Filter entry #%i: Unknown data type\n", i + 1));
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004757
Willy Tarreau3c69e082022-05-03 11:35:07 +02004758 if (!((struct stktable *)ctx->target)->data_ofs[ctx->data_type[i]])
Adis Nezirovicd0142e72020-01-22 16:50:27 +01004759 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 +01004760
Willy Tarreau3c69e082022-05-03 11:35:07 +02004761 ctx->data_op[i] = get_std_op(args[4+3*i]);
4762 if (ctx->data_op[i] < 0)
Adis Nezirovicd0142e72020-01-22 16:50:27 +01004763 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 +01004764
Willy Tarreau3c69e082022-05-03 11:35:07 +02004765 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 +01004766 return cli_dynerr(appctx, memprintf(&err, "Filter entry #%i: Require a valid integer value to compare against\n", i + 1));
4767 }
4768
4769 if (*args[3+3*i]) {
4770 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 +01004771 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004772
4773 /* OK we're done, all the fields are set */
4774 return 0;
4775}
4776
4777/* returns 0 if wants to be called, 1 if has ended processing */
Aurélien Nephtaliabbf6072018-04-18 13:26:46 +02004778static int cli_parse_table_req(char **args, char *payload, struct appctx *appctx, void *private)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004779{
Willy Tarreau3c69e082022-05-03 11:35:07 +02004780 struct show_table_ctx *ctx = applet_reserve_svcctx(appctx, sizeof(*ctx));
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004781 int i;
4782
4783 for (i = 0; i < STKTABLE_FILTER_LEN; i++)
Willy Tarreau3c69e082022-05-03 11:35:07 +02004784 ctx->data_type[i] = -1;
4785 ctx->target = NULL;
4786 ctx->entry = NULL;
4787 ctx->action = (long)private; // keyword argument, one of STK_CLI_ACT_*
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004788
4789 if (*args[2]) {
Willy Tarreau0f154ed2022-05-03 12:02:36 +02004790 ctx->t = ctx->target = stktable_find_by_name(args[2]);
Willy Tarreau3c69e082022-05-03 11:35:07 +02004791 if (!ctx->target)
Willy Tarreau9d008692019-08-09 11:21:01 +02004792 return cli_err(appctx, "No such table\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004793 }
4794 else {
Willy Tarreau0f154ed2022-05-03 12:02:36 +02004795 ctx->t = stktables_list;
Willy Tarreau3c69e082022-05-03 11:35:07 +02004796 if (ctx->action != STK_CLI_ACT_SHOW)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004797 goto err_args;
4798 return 0;
4799 }
4800
4801 if (strcmp(args[3], "key") == 0)
4802 return table_process_entry_per_key(appctx, args);
4803 else if (strncmp(args[3], "data.", 5) == 0)
4804 return table_prepare_data_request(appctx, args);
4805 else if (*args[3])
4806 goto err_args;
4807
4808 return 0;
4809
4810err_args:
Willy Tarreau3c69e082022-05-03 11:35:07 +02004811 switch (ctx->action) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004812 case STK_CLI_ACT_SHOW:
Willy Tarreau9d008692019-08-09 11:21:01 +02004813 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 +01004814 case STK_CLI_ACT_CLR:
Willy Tarreau9d008692019-08-09 11:21:01 +02004815 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 +01004816 case STK_CLI_ACT_SET:
Willy Tarreau9d008692019-08-09 11:21:01 +02004817 return cli_err(appctx, "Required arguments: <table> key <key> [data.<store_data_type> <value>]*\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004818 default:
Willy Tarreau9d008692019-08-09 11:21:01 +02004819 return cli_err(appctx, "Unknown action\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004820 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004821}
4822
4823/* This function is used to deal with table operations (dump or clear depending
4824 * on the action stored in appctx->private). It returns 0 if the output buffer is
4825 * full and it needs to be called again, otherwise non-zero.
4826 */
4827static int cli_io_handler_table(struct appctx *appctx)
4828{
Willy Tarreau3c69e082022-05-03 11:35:07 +02004829 struct show_table_ctx *ctx = appctx->svcctx;
Willy Tarreauc12b3212022-05-27 11:08:15 +02004830 struct stconn *sc = appctx_sc(appctx);
Willy Tarreau475e4632022-05-27 10:26:46 +02004831 struct stream *s = __sc_strm(sc);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004832 struct ebmb_node *eb;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004833 int skip_entry;
Willy Tarreau3c69e082022-05-03 11:35:07 +02004834 int show = ctx->action == STK_CLI_ACT_SHOW;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004835
4836 /*
Willy Tarreau0f154ed2022-05-03 12:02:36 +02004837 * We have 3 possible states in ctx->state :
Willy Tarreau7849d4c2022-05-03 11:45:02 +02004838 * - STATE_NEXT : the proxy pointer points to the next table to
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004839 * dump, the entry pointer is NULL ;
Willy Tarreau7849d4c2022-05-03 11:45:02 +02004840 * - STATE_DUMP : the proxy pointer points to the current table
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004841 * and the entry pointer points to the next entry to be dumped,
4842 * and the refcount on the next entry is held ;
Willy Tarreau7849d4c2022-05-03 11:45:02 +02004843 * - STATE_DONE : nothing left to dump, the buffer may contain some
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004844 * data though.
4845 */
4846
Willy Tarreau475e4632022-05-27 10:26:46 +02004847 if (unlikely(sc_ic(sc)->flags & (CF_WRITE_ERROR|CF_SHUTW))) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004848 /* in case of abort, remove any refcount we might have set on an entry */
Willy Tarreau7849d4c2022-05-03 11:45:02 +02004849 if (ctx->state == STATE_DUMP) {
Willy Tarreau3c69e082022-05-03 11:35:07 +02004850 stksess_kill_if_expired(ctx->t, ctx->entry, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004851 }
4852 return 1;
4853 }
4854
4855 chunk_reset(&trash);
4856
Willy Tarreau7849d4c2022-05-03 11:45:02 +02004857 while (ctx->state != STATE_DONE) {
4858 switch (ctx->state) {
Willy Tarreau7849d4c2022-05-03 11:45:02 +02004859 case STATE_NEXT:
Willy Tarreau3c69e082022-05-03 11:35:07 +02004860 if (!ctx->t ||
4861 (ctx->target &&
4862 ctx->t != ctx->target)) {
Willy Tarreau7849d4c2022-05-03 11:45:02 +02004863 ctx->state = STATE_DONE;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004864 break;
4865 }
4866
Willy Tarreau3c69e082022-05-03 11:35:07 +02004867 if (ctx->t->size) {
Willy Tarreaud0a06d52022-05-18 15:07:19 +02004868 if (show && !table_dump_head_to_buffer(&trash, appctx, ctx->t, ctx->target))
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004869 return 0;
4870
Willy Tarreau3c69e082022-05-03 11:35:07 +02004871 if (ctx->target &&
William Lallemand07a62f72017-05-24 00:57:40 +02004872 (strm_li(s)->bind_conf->level & ACCESS_LVL_MASK) >= ACCESS_LVL_OPER) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004873 /* dump entries only if table explicitly requested */
Willy Tarreau76642222022-10-11 12:02:50 +02004874 HA_RWLOCK_WRLOCK(STK_TABLE_LOCK, &ctx->t->lock);
Willy Tarreau3c69e082022-05-03 11:35:07 +02004875 eb = ebmb_first(&ctx->t->keys);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004876 if (eb) {
Willy Tarreau3c69e082022-05-03 11:35:07 +02004877 ctx->entry = ebmb_entry(eb, struct stksess, key);
4878 ctx->entry->ref_cnt++;
Willy Tarreau7849d4c2022-05-03 11:45:02 +02004879 ctx->state = STATE_DUMP;
Willy Tarreau76642222022-10-11 12:02:50 +02004880 HA_RWLOCK_WRUNLOCK(STK_TABLE_LOCK, &ctx->t->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004881 break;
4882 }
Willy Tarreau76642222022-10-11 12:02:50 +02004883 HA_RWLOCK_WRUNLOCK(STK_TABLE_LOCK, &ctx->t->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004884 }
4885 }
Willy Tarreau3c69e082022-05-03 11:35:07 +02004886 ctx->t = ctx->t->next;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004887 break;
4888
Willy Tarreau7849d4c2022-05-03 11:45:02 +02004889 case STATE_DUMP:
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004890 skip_entry = 0;
4891
Willy Tarreau3c69e082022-05-03 11:35:07 +02004892 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &ctx->entry->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004893
Willy Tarreau3c69e082022-05-03 11:35:07 +02004894 if (ctx->data_type[0] >= 0) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004895 /* we're filtering on some data contents */
4896 void *ptr;
Willy Tarreau2b64a352020-01-22 17:09:47 +01004897 int dt, i;
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004898 signed char op;
4899 long long data, value;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004900
Emeric Brun819fc6f2017-06-13 19:37:32 +02004901
Willy Tarreau2b64a352020-01-22 17:09:47 +01004902 for (i = 0; i < STKTABLE_FILTER_LEN; i++) {
Willy Tarreau3c69e082022-05-03 11:35:07 +02004903 if (ctx->data_type[i] == -1)
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004904 break;
Willy Tarreau3c69e082022-05-03 11:35:07 +02004905 dt = ctx->data_type[i];
4906 ptr = stktable_data_ptr(ctx->t,
4907 ctx->entry,
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004908 dt);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004909
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004910 data = 0;
4911 switch (stktable_data_types[dt].std_type) {
4912 case STD_T_SINT:
4913 data = stktable_data_cast(ptr, std_t_sint);
4914 break;
4915 case STD_T_UINT:
4916 data = stktable_data_cast(ptr, std_t_uint);
4917 break;
4918 case STD_T_ULL:
4919 data = stktable_data_cast(ptr, std_t_ull);
4920 break;
4921 case STD_T_FRQP:
4922 data = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Willy Tarreau3c69e082022-05-03 11:35:07 +02004923 ctx->t->data_arg[dt].u);
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004924 break;
4925 }
4926
Willy Tarreau3c69e082022-05-03 11:35:07 +02004927 op = ctx->data_op[i];
4928 value = ctx->value[i];
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004929
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004930 /* skip the entry if the data does not match the test and the value */
4931 if ((data < value &&
4932 (op == STD_OP_EQ || op == STD_OP_GT || op == STD_OP_GE)) ||
4933 (data == value &&
4934 (op == STD_OP_NE || op == STD_OP_GT || op == STD_OP_LT)) ||
4935 (data > value &&
4936 (op == STD_OP_EQ || op == STD_OP_LT || op == STD_OP_LE))) {
4937 skip_entry = 1;
4938 break;
4939 }
4940 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004941 }
4942
4943 if (show && !skip_entry &&
Willy Tarreaud0a06d52022-05-18 15:07:19 +02004944 !table_dump_entry_to_buffer(&trash, appctx, ctx->t, ctx->entry)) {
Willy Tarreau3c69e082022-05-03 11:35:07 +02004945 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &ctx->entry->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004946 return 0;
4947 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004948
Willy Tarreau3c69e082022-05-03 11:35:07 +02004949 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &ctx->entry->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004950
Willy Tarreau76642222022-10-11 12:02:50 +02004951 HA_RWLOCK_WRLOCK(STK_TABLE_LOCK, &ctx->t->lock);
Willy Tarreau3c69e082022-05-03 11:35:07 +02004952 ctx->entry->ref_cnt--;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004953
Willy Tarreau3c69e082022-05-03 11:35:07 +02004954 eb = ebmb_next(&ctx->entry->key);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004955 if (eb) {
Willy Tarreau3c69e082022-05-03 11:35:07 +02004956 struct stksess *old = ctx->entry;
4957 ctx->entry = ebmb_entry(eb, struct stksess, key);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004958 if (show)
Willy Tarreau3c69e082022-05-03 11:35:07 +02004959 __stksess_kill_if_expired(ctx->t, old);
4960 else if (!skip_entry && !ctx->entry->ref_cnt)
4961 __stksess_kill(ctx->t, old);
4962 ctx->entry->ref_cnt++;
Willy Tarreau76642222022-10-11 12:02:50 +02004963 HA_RWLOCK_WRUNLOCK(STK_TABLE_LOCK, &ctx->t->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004964 break;
4965 }
4966
4967
4968 if (show)
Willy Tarreau3c69e082022-05-03 11:35:07 +02004969 __stksess_kill_if_expired(ctx->t, ctx->entry);
4970 else if (!skip_entry && !ctx->entry->ref_cnt)
4971 __stksess_kill(ctx->t, ctx->entry);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004972
Willy Tarreau76642222022-10-11 12:02:50 +02004973 HA_RWLOCK_WRUNLOCK(STK_TABLE_LOCK, &ctx->t->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004974
Willy Tarreau3c69e082022-05-03 11:35:07 +02004975 ctx->t = ctx->t->next;
Willy Tarreau7849d4c2022-05-03 11:45:02 +02004976 ctx->state = STATE_NEXT;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004977 break;
4978
Willy Tarreau7849d4c2022-05-03 11:45:02 +02004979 default:
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004980 break;
4981 }
4982 }
4983 return 1;
4984}
4985
4986static void cli_release_show_table(struct appctx *appctx)
4987{
Willy Tarreau3c69e082022-05-03 11:35:07 +02004988 struct show_table_ctx *ctx = appctx->svcctx;
4989
Willy Tarreau7849d4c2022-05-03 11:45:02 +02004990 if (ctx->state == STATE_DUMP) {
Willy Tarreau3c69e082022-05-03 11:35:07 +02004991 stksess_kill_if_expired(ctx->t, ctx->entry, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004992 }
4993}
4994
Willy Tarreau478331d2020-08-28 11:31:31 +02004995static void stkt_late_init(void)
4996{
4997 struct sample_fetch *f;
4998
4999 f = find_sample_fetch("src", strlen("src"));
5000 if (f)
5001 smp_fetch_src = f->process;
5002}
5003
5004INITCALL0(STG_INIT, stkt_late_init);
5005
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01005006/* register cli keywords */
5007static struct cli_kw_list cli_kws = {{ },{
Willy Tarreaub205bfd2021-05-07 11:38:37 +02005008 { { "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 },
5009 { { "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 },
5010 { { "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 +01005011 {{},}
5012}};
5013
Willy Tarreau0108d902018-11-25 19:14:37 +01005014INITCALL1(STG_REGISTER, cli_register_kw, &cli_kws);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01005015
Thierry FOURNIER236657b2015-08-19 08:25:14 +02005016static struct action_kw_list tcp_conn_kws = { { }, {
Emeric Brun4d7ada82021-06-30 19:04:16 +02005017 { "sc-inc-gpc", parse_inc_gpc, KWF_MATCH_PREFIX },
5018 { "sc-inc-gpc0", parse_inc_gpc, KWF_MATCH_PREFIX },
5019 { "sc-inc-gpc1", parse_inc_gpc, KWF_MATCH_PREFIX },
Emeric Brun877b0b52021-06-30 18:57:49 +02005020 { "sc-set-gpt", parse_set_gpt, KWF_MATCH_PREFIX },
5021 { "sc-set-gpt0", parse_set_gpt, KWF_MATCH_PREFIX },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02005022 { /* END */ }
5023}};
5024
Willy Tarreau0108d902018-11-25 19:14:37 +01005025INITCALL1(STG_REGISTER, tcp_req_conn_keywords_register, &tcp_conn_kws);
5026
Willy Tarreau620408f2016-10-21 16:37:51 +02005027static struct action_kw_list tcp_sess_kws = { { }, {
Emeric Brun4d7ada82021-06-30 19:04:16 +02005028 { "sc-inc-gpc", parse_inc_gpc, KWF_MATCH_PREFIX },
5029 { "sc-inc-gpc0", parse_inc_gpc, KWF_MATCH_PREFIX },
5030 { "sc-inc-gpc1", parse_inc_gpc, KWF_MATCH_PREFIX },
Emeric Brun877b0b52021-06-30 18:57:49 +02005031 { "sc-set-gpt", parse_set_gpt, KWF_MATCH_PREFIX },
5032 { "sc-set-gpt0", parse_set_gpt, KWF_MATCH_PREFIX },
Willy Tarreau620408f2016-10-21 16:37:51 +02005033 { /* END */ }
5034}};
5035
Willy Tarreau0108d902018-11-25 19:14:37 +01005036INITCALL1(STG_REGISTER, tcp_req_sess_keywords_register, &tcp_sess_kws);
5037
Thierry FOURNIER236657b2015-08-19 08:25:14 +02005038static struct action_kw_list tcp_req_kws = { { }, {
Emeric Brun4d7ada82021-06-30 19:04:16 +02005039 { "sc-inc-gpc", parse_inc_gpc, KWF_MATCH_PREFIX },
5040 { "sc-inc-gpc0", parse_inc_gpc, KWF_MATCH_PREFIX },
5041 { "sc-inc-gpc1", parse_inc_gpc, KWF_MATCH_PREFIX },
Emeric Brun877b0b52021-06-30 18:57:49 +02005042 { "sc-set-gpt", parse_set_gpt, KWF_MATCH_PREFIX },
5043 { "sc-set-gpt0", parse_set_gpt, KWF_MATCH_PREFIX },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02005044 { /* END */ }
5045}};
5046
Willy Tarreau0108d902018-11-25 19:14:37 +01005047INITCALL1(STG_REGISTER, tcp_req_cont_keywords_register, &tcp_req_kws);
5048
Thierry FOURNIER236657b2015-08-19 08:25:14 +02005049static struct action_kw_list tcp_res_kws = { { }, {
Emeric Brun4d7ada82021-06-30 19:04:16 +02005050 { "sc-inc-gpc", parse_inc_gpc, KWF_MATCH_PREFIX },
5051 { "sc-inc-gpc0", parse_inc_gpc, KWF_MATCH_PREFIX },
5052 { "sc-inc-gpc1", parse_inc_gpc, KWF_MATCH_PREFIX },
Emeric Brun877b0b52021-06-30 18:57:49 +02005053 { "sc-set-gpt", parse_set_gpt, KWF_MATCH_PREFIX },
5054 { "sc-set-gpt0", parse_set_gpt, KWF_MATCH_PREFIX },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02005055 { /* END */ }
5056}};
5057
Willy Tarreau0108d902018-11-25 19:14:37 +01005058INITCALL1(STG_REGISTER, tcp_res_cont_keywords_register, &tcp_res_kws);
5059
Thierry FOURNIER236657b2015-08-19 08:25:14 +02005060static struct action_kw_list http_req_kws = { { }, {
Emeric Brun4d7ada82021-06-30 19:04:16 +02005061 { "sc-inc-gpc", parse_inc_gpc, KWF_MATCH_PREFIX },
5062 { "sc-inc-gpc0", parse_inc_gpc, KWF_MATCH_PREFIX },
5063 { "sc-inc-gpc1", parse_inc_gpc, KWF_MATCH_PREFIX },
Emeric Brun877b0b52021-06-30 18:57:49 +02005064 { "sc-set-gpt", parse_set_gpt, KWF_MATCH_PREFIX },
5065 { "sc-set-gpt0", parse_set_gpt, KWF_MATCH_PREFIX },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02005066 { /* END */ }
5067}};
5068
Willy Tarreau0108d902018-11-25 19:14:37 +01005069INITCALL1(STG_REGISTER, http_req_keywords_register, &http_req_kws);
5070
Thierry FOURNIER236657b2015-08-19 08:25:14 +02005071static struct action_kw_list http_res_kws = { { }, {
Emeric Brun4d7ada82021-06-30 19:04:16 +02005072 { "sc-inc-gpc", parse_inc_gpc, KWF_MATCH_PREFIX },
5073 { "sc-inc-gpc0", parse_inc_gpc, KWF_MATCH_PREFIX },
5074 { "sc-inc-gpc1", parse_inc_gpc, KWF_MATCH_PREFIX },
Emeric Brun877b0b52021-06-30 18:57:49 +02005075 { "sc-set-gpt", parse_set_gpt, KWF_MATCH_PREFIX },
5076 { "sc-set-gpt0", parse_set_gpt, KWF_MATCH_PREFIX },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02005077 { /* END */ }
5078}};
5079
Willy Tarreau0108d902018-11-25 19:14:37 +01005080INITCALL1(STG_REGISTER, http_res_keywords_register, &http_res_kws);
5081
Willy Tarreau7d562212016-11-25 16:10:05 +01005082/* Note: must not be declared <const> as its list will be overwritten.
5083 * Please take care of keeping this list alphabetically sorted.
5084 */
5085static struct sample_fetch_kw_list smp_fetch_keywords = {ILH, {
5086 { "sc_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5087 { "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 +02005088 { "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 +01005089 { "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 +01005090 { "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 +01005091 { "sc_conn_cnt", smp_fetch_sc_conn_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5092 { "sc_conn_cur", smp_fetch_sc_conn_cur, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5093 { "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 +02005094 { "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 +01005095 { "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 +02005096 { "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 +01005097 { "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 +01005098 { "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 +02005099 { "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 +01005100 { "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 +01005101 { "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 +01005102 { "sc_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5103 { "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 +01005104 { "sc_http_fail_cnt", smp_fetch_sc_http_fail_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5105 { "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 +01005106 { "sc_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5107 { "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 +02005108 { "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 +01005109 { "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 +01005110 { "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 +01005111 { "sc_kbytes_in", smp_fetch_sc_kbytes_in, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5112 { "sc_kbytes_out", smp_fetch_sc_kbytes_out, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5113 { "sc_sess_cnt", smp_fetch_sc_sess_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5114 { "sc_sess_rate", smp_fetch_sc_sess_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5115 { "sc_tracked", smp_fetch_sc_tracked, ARG2(1,SINT,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
5116 { "sc_trackers", smp_fetch_sc_trackers, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5117 { "sc0_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5118 { "sc0_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5119 { "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 +01005120 { "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 +01005121 { "sc0_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5122 { "sc0_conn_cur", smp_fetch_sc_conn_cur, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5123 { "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 +01005124 { "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 +01005125 { "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 +01005126 { "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 +01005127 { "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 +01005128 { "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 +01005129 { "sc0_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5130 { "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 +01005131 { "sc0_http_fail_cnt", smp_fetch_sc_http_fail_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5132 { "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 +01005133 { "sc0_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5134 { "sc0_http_req_rate", smp_fetch_sc_http_req_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5135 { "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 +01005136 { "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 +01005137 { "sc0_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5138 { "sc0_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5139 { "sc0_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5140 { "sc0_sess_rate", smp_fetch_sc_sess_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5141 { "sc0_tracked", smp_fetch_sc_tracked, ARG1(0,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
5142 { "sc0_trackers", smp_fetch_sc_trackers, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5143 { "sc1_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5144 { "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 +02005145 { "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 +01005146 { "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 +01005147 { "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 +01005148 { "sc1_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5149 { "sc1_conn_cur", smp_fetch_sc_conn_cur, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5150 { "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 +01005151 { "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 +01005152 { "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 +01005153 { "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 +01005154 { "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 +01005155 { "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 +01005156 { "sc1_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5157 { "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 +01005158 { "sc1_http_fail_cnt", smp_fetch_sc_http_fail_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5159 { "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 +01005160 { "sc1_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5161 { "sc1_http_req_rate", smp_fetch_sc_http_req_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5162 { "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 +01005163 { "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 +01005164 { "sc1_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5165 { "sc1_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5166 { "sc1_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5167 { "sc1_sess_rate", smp_fetch_sc_sess_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5168 { "sc1_tracked", smp_fetch_sc_tracked, ARG1(0,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
5169 { "sc1_trackers", smp_fetch_sc_trackers, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5170 { "sc2_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5171 { "sc2_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5172 { "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 +01005173 { "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 +01005174 { "sc2_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5175 { "sc2_conn_cur", smp_fetch_sc_conn_cur, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5176 { "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 +01005177 { "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 +01005178 { "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 +01005179 { "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 +01005180 { "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 +01005181 { "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 +01005182 { "sc2_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5183 { "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 +01005184 { "sc2_http_fail_cnt", smp_fetch_sc_http_fail_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5185 { "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 +01005186 { "sc2_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5187 { "sc2_http_req_rate", smp_fetch_sc_http_req_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5188 { "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 +01005189 { "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 +01005190 { "sc2_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5191 { "sc2_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5192 { "sc2_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5193 { "sc2_sess_rate", smp_fetch_sc_sess_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5194 { "sc2_tracked", smp_fetch_sc_tracked, ARG1(0,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
5195 { "sc2_trackers", smp_fetch_sc_trackers, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5196 { "src_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5197 { "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 +02005198 { "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 +01005199 { "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 +01005200 { "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 +01005201 { "src_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5202 { "src_conn_cur", smp_fetch_sc_conn_cur, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5203 { "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 +02005204 { "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 +01005205 { "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 +02005206 { "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 +01005207 { "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 +01005208 { "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 +02005209 { "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 +01005210 { "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 +01005211 { "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 +01005212 { "src_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5213 { "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 +01005214 { "src_http_fail_cnt", smp_fetch_sc_http_fail_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5215 { "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 +01005216 { "src_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5217 { "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 +02005218 { "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 +01005219 { "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 +01005220 { "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 +01005221 { "src_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5222 { "src_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5223 { "src_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5224 { "src_sess_rate", smp_fetch_sc_sess_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5225 { "src_updt_conn_cnt", smp_fetch_src_updt_conn_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5226 { "table_avl", smp_fetch_table_avl, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5227 { "table_cnt", smp_fetch_table_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5228 { /* END */ },
5229}};
5230
Willy Tarreau0108d902018-11-25 19:14:37 +01005231INITCALL1(STG_REGISTER, sample_register_fetches, &smp_fetch_keywords);
Willy Tarreau7d562212016-11-25 16:10:05 +01005232
Willy Tarreaud9f316a2014-07-10 14:03:38 +02005233/* Note: must not be declared <const> as its list will be overwritten */
5234static struct sample_conv_kw_list sample_conv_kws = {ILH, {
Willy Tarreau2d17db52016-05-25 17:16:38 +02005235 { "in_table", sample_conv_in_table, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_BOOL },
5236 { "table_bytes_in_rate", sample_conv_table_bytes_in_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5237 { "table_bytes_out_rate", sample_conv_table_bytes_out_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5238 { "table_conn_cnt", sample_conv_table_conn_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5239 { "table_conn_cur", sample_conv_table_conn_cur, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5240 { "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 +02005241 { "table_expire", sample_conv_table_expire, ARG2(1,TAB,SINT), NULL, SMP_T_ANY, SMP_T_SINT },
Emeric Brun877b0b52021-06-30 18:57:49 +02005242 { "table_gpt", sample_conv_table_gpt, ARG2(2,SINT,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
Willy Tarreau2d17db52016-05-25 17:16:38 +02005243 { "table_gpt0", sample_conv_table_gpt0, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
Emeric Brun4d7ada82021-06-30 19:04:16 +02005244 { "table_gpc", sample_conv_table_gpc, ARG2(2,SINT,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
Willy Tarreau2d17db52016-05-25 17:16:38 +02005245 { "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 +01005246 { "table_gpc1", sample_conv_table_gpc1, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
Emeric Brun4d7ada82021-06-30 19:04:16 +02005247 { "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 +02005248 { "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 +01005249 { "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 +02005250 { "table_http_err_cnt", sample_conv_table_http_err_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5251 { "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 +01005252 { "table_http_fail_cnt", sample_conv_table_http_fail_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5253 { "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 +02005254 { "table_http_req_cnt", sample_conv_table_http_req_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5255 { "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 +02005256 { "table_idle", sample_conv_table_idle, ARG2(1,TAB,SINT), NULL, SMP_T_ANY, SMP_T_SINT },
Willy Tarreau2d17db52016-05-25 17:16:38 +02005257 { "table_kbytes_in", sample_conv_table_kbytes_in, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5258 { "table_kbytes_out", sample_conv_table_kbytes_out, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5259 { "table_server_id", sample_conv_table_server_id, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5260 { "table_sess_cnt", sample_conv_table_sess_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5261 { "table_sess_rate", sample_conv_table_sess_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5262 { "table_trackers", sample_conv_table_trackers, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
Willy Tarreaud9f316a2014-07-10 14:03:38 +02005263 { /* END */ },
5264}};
5265
Willy Tarreau0108d902018-11-25 19:14:37 +01005266INITCALL1(STG_REGISTER, sample_register_convs, &sample_conv_kws);