blob: 1820da3d9dfd87008c50d376d703f723d90ec16c [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>
Frédéric Lécaille36d15652022-10-17 14:58:19 +020020#include <import/xxhash.h>
Willy Tarreaub2551052020-06-09 09:07:15 +020021
Willy Tarreau4c7e4b72020-05-27 12:58:42 +020022#include <haproxy/api.h>
Willy Tarreau3c69e082022-05-03 11:35:07 +020023#include <haproxy/applet.h>
Willy Tarreaub2551052020-06-09 09:07:15 +020024#include <haproxy/arg.h>
Willy Tarreau6be78492020-06-05 00:00:29 +020025#include <haproxy/cfgparse.h>
Willy Tarreau83487a82020-06-04 20:19:54 +020026#include <haproxy/cli.h>
Thayne McCombs92149f92020-11-20 01:28:26 -070027#include <haproxy/dict.h>
Willy Tarreau36979d92020-06-05 17:27:29 +020028#include <haproxy/errors.h>
Willy Tarreauf268ee82020-06-04 17:05:57 +020029#include <haproxy/global.h>
Willy Tarreauc761f842020-06-04 11:40:28 +020030#include <haproxy/http_rules.h>
Willy Tarreau853b2972020-05-27 18:01:47 +020031#include <haproxy/list.h>
Willy Tarreauaeed4a82020-06-04 22:01:04 +020032#include <haproxy/log.h>
Willy Tarreau6131d6a2020-06-02 16:48:09 +020033#include <haproxy/net_helper.h>
Willy Tarreau3c2a7c22020-06-04 18:38:21 +020034#include <haproxy/peers.h>
Willy Tarreaub2551052020-06-09 09:07:15 +020035#include <haproxy/pool.h>
36#include <haproxy/proto_tcp.h>
Willy Tarreaua264d962020-06-04 22:29:18 +020037#include <haproxy/proxy.h>
Willy Tarreaub2551052020-06-09 09:07:15 +020038#include <haproxy/sample.h>
Willy Tarreau5edca2f2022-05-27 09:25:10 +020039#include <haproxy/sc_strm.h>
Willy Tarreau2eec9b52020-06-04 19:58:55 +020040#include <haproxy/stats-t.h>
Willy Tarreaucb086c62022-05-27 09:47:12 +020041#include <haproxy/stconn.h>
Willy Tarreaub2551052020-06-09 09:07:15 +020042#include <haproxy/stick_table.h>
Willy Tarreaudfd3de82020-06-04 23:46:14 +020043#include <haproxy/stream.h>
Willy Tarreaucea0e1b2020-06-04 17:25:40 +020044#include <haproxy/task.h>
Willy Tarreau8b550af2020-06-04 17:42:48 +020045#include <haproxy/tcp_rules.h>
Willy Tarreau9310f482021-10-06 16:18:40 +020046#include <haproxy/ticks.h>
Willy Tarreaub2551052020-06-09 09:07:15 +020047#include <haproxy/tools.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{
167 struct buffer *buf;
168 size_t keylen;
169
170 /* Copy the stick-table id into <buf> */
171 buf = get_trash_chunk();
172 memcpy(b_tail(buf), t->id, t->idlen);
173 b_add(buf, t->idlen);
174 /* Copy the key into <buf> */
175 if (t->type == SMP_T_STR)
176 keylen = key->key_len;
177 else
178 keylen = t->key_size;
179 memcpy(b_tail(buf), key->key, keylen);
180 b_add(buf, keylen);
181
182 return XXH64(b_head(buf), b_data(buf), 0);
183}
Emeric Brun3bd697e2010-01-04 15:23:48 +0100184
185/*
Frédéric Lécaille36d15652022-10-17 14:58:19 +0200186 * Set the shard for <key> key of <ts> sticky session attached to <t> stick table.
187 * Do nothing for stick-table without peers synchronisation.
188 */
189static void stksess_setkey_shard(struct stktable *t, struct stksess *ts,
190 struct stktable_key *key)
191{
192 if (!t->peers.p)
193 /* This stick-table is not attached to any peers section */
194 return;
195
196 if (!t->peers.p->nb_shards)
197 ts->shard = 0;
198 else
199 ts->shard = stksess_getkey_hash(t, ts, key) % t->peers.p->nb_shards + 1;
200}
201
202/*
Willy Tarreau393379c2010-06-06 12:11:37 +0200203 * Init sticky session <ts> of table <t>. The data parts are cleared and <ts>
204 * is returned.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100205 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200206static struct stksess *__stksess_init(struct stktable *t, struct stksess * ts)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100207{
Willy Tarreau393379c2010-06-06 12:11:37 +0200208 memset((void *)ts - t->data_size, 0, t->data_size);
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200209 ts->ref_cnt = 0;
Willy Tarreau86257dc2010-06-06 12:57:10 +0200210 ts->key.node.leaf_p = NULL;
211 ts->exp.node.leaf_p = NULL;
Emeric Brun85e77c72010-09-23 18:16:52 +0200212 ts->upd.node.leaf_p = NULL;
Emeric Brun819fc6f2017-06-13 19:37:32 +0200213 ts->expire = tick_add(now_ms, MS_TO_TICKS(t->expire));
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100214 HA_RWLOCK_INIT(&ts->lock);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100215 return ts;
216}
217
218/*
Willy Tarreauaea940e2010-06-06 11:56:36 +0200219 * Trash oldest <to_batch> sticky sessions from table <t>
Willy Tarreaudfe79252020-11-03 17:47:41 +0100220 * Returns number of trashed sticky sessions. It may actually trash less
221 * than expected if finding these requires too long a search time (e.g.
222 * most of them have ts->ref_cnt>0).
Emeric Brun3bd697e2010-01-04 15:23:48 +0100223 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200224int __stktable_trash_oldest(struct stktable *t, int to_batch)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100225{
226 struct stksess *ts;
227 struct eb32_node *eb;
Willy Tarreaudfe79252020-11-03 17:47:41 +0100228 int max_search = to_batch * 2; // no more than 50% misses
Emeric Brun3bd697e2010-01-04 15:23:48 +0100229 int batched = 0;
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200230 int looped = 0;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100231
232 eb = eb32_lookup_ge(&t->exps, now_ms - TIMER_LOOK_BACK);
233
234 while (batched < to_batch) {
235
236 if (unlikely(!eb)) {
237 /* we might have reached the end of the tree, typically because
238 * <now_ms> is in the first half and we're first scanning the last
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200239 * half. Let's loop back to the beginning of the tree now if we
240 * have not yet visited it.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100241 */
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200242 if (looped)
243 break;
244 looped = 1;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100245 eb = eb32_first(&t->exps);
246 if (likely(!eb))
247 break;
248 }
249
Willy Tarreaudfe79252020-11-03 17:47:41 +0100250 if (--max_search < 0)
251 break;
252
Emeric Brun3bd697e2010-01-04 15:23:48 +0100253 /* timer looks expired, detach it from the queue */
Willy Tarreau86257dc2010-06-06 12:57:10 +0200254 ts = eb32_entry(eb, struct stksess, exp);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100255 eb = eb32_next(eb);
256
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200257 /* don't delete an entry which is currently referenced */
258 if (ts->ref_cnt)
259 continue;
260
Willy Tarreau86257dc2010-06-06 12:57:10 +0200261 eb32_delete(&ts->exp);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100262
Willy Tarreau86257dc2010-06-06 12:57:10 +0200263 if (ts->expire != ts->exp.key) {
Emeric Brun3bd697e2010-01-04 15:23:48 +0100264 if (!tick_isset(ts->expire))
265 continue;
266
Willy Tarreau86257dc2010-06-06 12:57:10 +0200267 ts->exp.key = ts->expire;
268 eb32_insert(&t->exps, &ts->exp);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100269
Willy Tarreau86257dc2010-06-06 12:57:10 +0200270 if (!eb || eb->key > ts->exp.key)
271 eb = &ts->exp;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100272
273 continue;
274 }
Emeric Brun3bd697e2010-01-04 15:23:48 +0100275
Willy Tarreauaea940e2010-06-06 11:56:36 +0200276 /* session expired, trash it */
Willy Tarreau86257dc2010-06-06 12:57:10 +0200277 ebmb_delete(&ts->key);
Emeric Brun85e77c72010-09-23 18:16:52 +0200278 eb32_delete(&ts->upd);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200279 __stksess_free(t, ts);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100280 batched++;
281 }
282
283 return batched;
284}
285
286/*
Emeric Brun819fc6f2017-06-13 19:37:32 +0200287 * Trash oldest <to_batch> sticky sessions from table <t>
288 * Returns number of trashed sticky sessions.
289 * This function locks the table
290 */
291int stktable_trash_oldest(struct stktable *t, int to_batch)
292{
293 int ret;
294
Willy Tarreau76642222022-10-11 12:02:50 +0200295 HA_RWLOCK_WRLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200296 ret = __stktable_trash_oldest(t, to_batch);
Willy Tarreau76642222022-10-11 12:02:50 +0200297 HA_RWLOCK_WRUNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200298
299 return ret;
300}
301/*
Willy Tarreauaea940e2010-06-06 11:56:36 +0200302 * Allocate and initialise a new sticky session.
303 * The new sticky session is returned or NULL in case of lack of memory.
304 * Sticky sessions should only be allocated this way, and must be freed using
Willy Tarreaua7b46b52013-04-11 16:55:37 +0200305 * stksess_free(). Table <t>'s sticky session counter is increased. If <key>
Willy Tarreau996f1a52022-10-11 16:19:35 +0200306 * is not NULL, it is assigned to the new session. It must be called unlocked
307 * as it may rely on a lock to trash older entries.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100308 */
Willy Tarreau996f1a52022-10-11 16:19:35 +0200309struct stksess *stksess_new(struct stktable *t, struct stktable_key *key)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100310{
311 struct stksess *ts;
Willy Tarreau996f1a52022-10-11 16:19:35 +0200312 unsigned int current;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100313
Willy Tarreau996f1a52022-10-11 16:19:35 +0200314 current = HA_ATOMIC_FETCH_ADD(&t->current, 1);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100315
Willy Tarreau996f1a52022-10-11 16:19:35 +0200316 if (unlikely(current >= t->size)) {
317 /* the table was already full, we may have to purge entries */
318 if (t->nopurge || !stktable_trash_oldest(t, (t->size >> 8) + 1)) {
319 HA_ATOMIC_DEC(&t->current);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100320 return NULL;
Willy Tarreau996f1a52022-10-11 16:19:35 +0200321 }
Emeric Brun3bd697e2010-01-04 15:23:48 +0100322 }
323
Willy Tarreaubafbe012017-11-24 17:34:44 +0100324 ts = pool_alloc(t->pool);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100325 if (ts) {
Olivier Houchard52dabbc2018-11-14 17:54:36 +0100326 ts = (void *)ts + round_ptr_size(t->data_size);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200327 __stksess_init(t, ts);
Frédéric Lécaille36d15652022-10-17 14:58:19 +0200328 if (key) {
Willy Tarreaua7b46b52013-04-11 16:55:37 +0200329 stksess_setkey(t, ts, key);
Frédéric Lécaille36d15652022-10-17 14:58:19 +0200330 stksess_setkey_shard(t, ts, key);
331 }
Emeric Brun3bd697e2010-01-04 15:23:48 +0100332 }
333
334 return ts;
335}
336
337/*
Willy Tarreauf16d2b82010-06-06 15:38:59 +0200338 * Looks in table <t> for a sticky session matching key <key>.
Willy Tarreauaea940e2010-06-06 11:56:36 +0200339 * Returns pointer on requested sticky session or NULL if none was found.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100340 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200341struct stksess *__stktable_lookup_key(struct stktable *t, struct stktable_key *key)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100342{
343 struct ebmb_node *eb;
344
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200345 if (t->type == SMP_T_STR)
Emeric Brun485479d2010-09-23 18:02:19 +0200346 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 +0100347 else
348 eb = ebmb_lookup(&t->keys, key->key, t->key_size);
349
350 if (unlikely(!eb)) {
351 /* no session found */
352 return NULL;
353 }
354
Willy Tarreau86257dc2010-06-06 12:57:10 +0200355 return ebmb_entry(eb, struct stksess, key);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100356}
357
Emeric Brun819fc6f2017-06-13 19:37:32 +0200358/*
359 * Looks in table <t> for a sticky session matching key <key>.
360 * Returns pointer on requested sticky session or NULL if none was found.
361 * The refcount of the found entry is increased and this function
362 * is protected using the table lock
Willy Tarreau1f7e9252010-06-20 12:27:21 +0200363 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200364struct stksess *stktable_lookup_key(struct stktable *t, struct stktable_key *key)
Willy Tarreau1f7e9252010-06-20 12:27:21 +0200365{
366 struct stksess *ts;
367
Willy Tarreaua7d6a132022-10-11 15:42:54 +0200368 HA_RWLOCK_RDLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200369 ts = __stktable_lookup_key(t, key);
370 if (ts)
Willy Tarreaua7d6a132022-10-11 15:42:54 +0200371 HA_ATOMIC_INC(&ts->ref_cnt);
372 HA_RWLOCK_RDUNLOCK(STK_TABLE_LOCK, &t->lock);
Willy Tarreau1f7e9252010-06-20 12:27:21 +0200373
Willy Tarreau1f7e9252010-06-20 12:27:21 +0200374 return ts;
375}
376
Willy Tarreauf16d2b82010-06-06 15:38:59 +0200377/*
378 * Looks in table <t> for a sticky session with same key as <ts>.
379 * Returns pointer on requested sticky session or NULL if none was found.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100380 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200381struct stksess *__stktable_lookup(struct stktable *t, struct stksess *ts)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100382{
Emeric Brun3bd697e2010-01-04 15:23:48 +0100383 struct ebmb_node *eb;
384
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200385 if (t->type == SMP_T_STR)
Willy Tarreau86257dc2010-06-06 12:57:10 +0200386 eb = ebst_lookup(&(t->keys), (char *)ts->key.key);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100387 else
Willy Tarreau86257dc2010-06-06 12:57:10 +0200388 eb = ebmb_lookup(&(t->keys), ts->key.key, t->key_size);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100389
Willy Tarreauf16d2b82010-06-06 15:38:59 +0200390 if (unlikely(!eb))
391 return NULL;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100392
Willy Tarreauf16d2b82010-06-06 15:38:59 +0200393 return ebmb_entry(eb, struct stksess, key);
394}
Emeric Brun3bd697e2010-01-04 15:23:48 +0100395
Emeric Brun819fc6f2017-06-13 19:37:32 +0200396/*
397 * Looks in table <t> for a sticky session with same key as <ts>.
398 * Returns pointer on requested sticky session or NULL if none was found.
399 * The refcount of the found entry is increased and this function
400 * is protected using the table lock
401 */
402struct stksess *stktable_lookup(struct stktable *t, struct stksess *ts)
403{
404 struct stksess *lts;
405
Willy Tarreaua7d6a132022-10-11 15:42:54 +0200406 HA_RWLOCK_RDLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200407 lts = __stktable_lookup(t, ts);
408 if (lts)
Willy Tarreaua7d6a132022-10-11 15:42:54 +0200409 HA_ATOMIC_INC(&lts->ref_cnt);
410 HA_RWLOCK_RDUNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200411
412 return lts;
413}
414
Willy Tarreaucb183642010-06-06 17:58:34 +0200415/* Update the expiration timer for <ts> but do not touch its expiration node.
416 * The table's expiration timer is updated if set.
Emeric Brun819fc6f2017-06-13 19:37:32 +0200417 * The node will be also inserted into the update tree if needed, at a position
Willy Tarreau9f5cb432022-10-11 18:17:58 +0000418 * depending if the update is a local or coming from a remote node.
419 * If <decrefcnt> is set, the ts entry's ref_cnt will be decremented. The table's
420 * write lock may be taken.
Willy Tarreaucb183642010-06-06 17:58:34 +0200421 */
Willy Tarreau9f5cb432022-10-11 18:17:58 +0000422void stktable_touch_with_exp(struct stktable *t, struct stksess *ts, int local, int expire, int decrefcnt)
Willy Tarreaucb183642010-06-06 17:58:34 +0200423{
Emeric Brun85e77c72010-09-23 18:16:52 +0200424 struct eb32_node * eb;
Willy Tarreaua7536ef2022-10-11 18:31:04 +0000425 int locked = 0;
Willy Tarreau9f5cb432022-10-11 18:17:58 +0000426
Willy Tarreaua7536ef2022-10-11 18:31:04 +0000427 if (expire != HA_ATOMIC_LOAD(&ts->expire)) {
428 /* we'll need to set the expiration and to wake up the expiration timer .*/
429 HA_ATOMIC_STORE(&ts->expire, expire);
Willy Tarreaudbae89e2022-10-12 10:00:50 +0000430 stktable_requeue_exp(t, ts);
Willy Tarreaucb183642010-06-06 17:58:34 +0200431 }
Emeric Brun85e77c72010-09-23 18:16:52 +0200432
Emeric Brun819fc6f2017-06-13 19:37:32 +0200433 /* If sync is enabled */
434 if (t->sync_task) {
435 if (local) {
436 /* If this entry is not in the tree
Willy Tarreaua7536ef2022-10-11 18:31:04 +0000437 * or not scheduled for at least one peer.
438 */
439 if (!locked++)
440 HA_RWLOCK_WRLOCK(STK_TABLE_LOCK, &t->lock);
441
Emeric Brun819fc6f2017-06-13 19:37:32 +0200442 if (!ts->upd.node.leaf_p
443 || (int)(t->commitupdate - ts->upd.key) >= 0
444 || (int)(ts->upd.key - t->localupdate) >= 0) {
445 ts->upd.key = ++t->update;
446 t->localupdate = t->update;
447 eb32_delete(&ts->upd);
448 eb = eb32_insert(&t->updates, &ts->upd);
449 if (eb != &ts->upd) {
450 eb32_delete(eb);
451 eb32_insert(&t->updates, &ts->upd);
452 }
Emeric Brunaaf58602015-06-15 17:23:30 +0200453 }
Emeric Brun819fc6f2017-06-13 19:37:32 +0200454 task_wakeup(t->sync_task, TASK_WOKEN_MSG);
Emeric Brun85e77c72010-09-23 18:16:52 +0200455 }
Emeric Brun819fc6f2017-06-13 19:37:32 +0200456 else {
457 /* If this entry is not in the tree */
Willy Tarreaua7536ef2022-10-11 18:31:04 +0000458 if (!locked++)
459 HA_RWLOCK_WRLOCK(STK_TABLE_LOCK, &t->lock);
460
Emeric Brun819fc6f2017-06-13 19:37:32 +0200461 if (!ts->upd.node.leaf_p) {
462 ts->upd.key= (++t->update)+(2147483648U);
463 eb = eb32_insert(&t->updates, &ts->upd);
464 if (eb != &ts->upd) {
465 eb32_delete(eb);
466 eb32_insert(&t->updates, &ts->upd);
467 }
468 }
469 }
Emeric Brun85e77c72010-09-23 18:16:52 +0200470 }
Willy Tarreau9f5cb432022-10-11 18:17:58 +0000471
Willy Tarreaua7536ef2022-10-11 18:31:04 +0000472 if (decrefcnt) {
473 if (locked)
474 ts->ref_cnt--;
475 else {
476 HA_RWLOCK_RDLOCK(STK_TABLE_LOCK, &t->lock);
477 HA_ATOMIC_DEC(&ts->ref_cnt);
478 HA_RWLOCK_RDUNLOCK(STK_TABLE_LOCK, &t->lock);
479 }
480 }
481
482 if (locked)
483 HA_RWLOCK_WRUNLOCK(STK_TABLE_LOCK, &t->lock);
Willy Tarreaucb183642010-06-06 17:58:34 +0200484}
485
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200486/* Update the expiration timer for <ts> but do not touch its expiration node.
Emeric Brun819fc6f2017-06-13 19:37:32 +0200487 * The table's expiration timer is updated using the date of expiration coming from
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200488 * <t> stick-table configuration.
Emeric Brun819fc6f2017-06-13 19:37:32 +0200489 * The node will be also inserted into the update tree if needed, at a position
490 * considering the update is coming from a remote node
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200491 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200492void stktable_touch_remote(struct stktable *t, struct stksess *ts, int decrefcnt)
493{
Willy Tarreau9f5cb432022-10-11 18:17:58 +0000494 stktable_touch_with_exp(t, ts, 0, ts->expire, decrefcnt);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200495}
496
497/* Update the expiration timer for <ts> but do not touch its expiration node.
498 * The table's expiration timer is updated using the date of expiration coming from
499 * <t> stick-table configuration.
500 * The node will be also inserted into the update tree if needed, at a position
501 * considering the update was made locally
502 */
503void stktable_touch_local(struct stktable *t, struct stksess *ts, int decrefcnt)
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200504{
505 int expire = tick_add(now_ms, MS_TO_TICKS(t->expire));
506
Willy Tarreau9f5cb432022-10-11 18:17:58 +0000507 stktable_touch_with_exp(t, ts, 1, expire, decrefcnt);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200508}
Willy Tarreau4be073b2022-10-11 18:10:27 +0000509/* Just decrease the ref_cnt of the current session. Does nothing if <ts> is NULL.
510 * Note that we still need to take the read lock because a number of other places
511 * (including in Lua and peers) update the ref_cnt non-atomically under the write
512 * lock.
513 */
Willy Tarreau43e90352018-06-27 06:25:57 +0200514static void stktable_release(struct stktable *t, struct stksess *ts)
Emeric Brun819fc6f2017-06-13 19:37:32 +0200515{
Willy Tarreau43e90352018-06-27 06:25:57 +0200516 if (!ts)
517 return;
Willy Tarreau4be073b2022-10-11 18:10:27 +0000518 HA_RWLOCK_RDLOCK(STK_TABLE_LOCK, &t->lock);
519 HA_ATOMIC_DEC(&ts->ref_cnt);
520 HA_RWLOCK_RDUNLOCK(STK_TABLE_LOCK, &t->lock);
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200521}
522
Willy Tarreauf16d2b82010-06-06 15:38:59 +0200523/* Insert new sticky session <ts> in the table. It is assumed that it does not
524 * yet exist (the caller must check this). The table's timeout is updated if it
Willy Tarreaud2d3fd92022-10-11 15:09:46 +0200525 * is set. <ts> is returned if properly inserted, otherwise the one already
526 * present if any.
Willy Tarreauf16d2b82010-06-06 15:38:59 +0200527 */
Willy Tarreaud2d3fd92022-10-11 15:09:46 +0200528struct stksess *__stktable_store(struct stktable *t, struct stksess *ts)
Willy Tarreauf16d2b82010-06-06 15:38:59 +0200529{
Willy Tarreaud2d3fd92022-10-11 15:09:46 +0200530 struct ebmb_node *eb;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100531
Willy Tarreaud2d3fd92022-10-11 15:09:46 +0200532 eb = ebmb_insert(&t->keys, &ts->key, t->key_size);
533 if (likely(eb == &ts->key)) {
534 ts->exp.key = ts->expire;
535 eb32_insert(&t->exps, &ts->exp);
536 }
Willy Tarreaud2d3fd92022-10-11 15:09:46 +0200537 return ebmb_entry(eb, struct stksess, key); // most commonly this is <ts>
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200538}
539
Willy Tarreaueb23e3e2022-10-12 09:56:08 +0000540/* requeues the table's expiration task to take the recently added <ts> into
541 * account. This is performed atomically and doesn't require any lock.
542 */
Willy Tarreaudbae89e2022-10-12 10:00:50 +0000543void stktable_requeue_exp(struct stktable *t, const struct stksess *ts)
Willy Tarreaueb23e3e2022-10-12 09:56:08 +0000544{
Willy Tarreaudbae89e2022-10-12 10:00:50 +0000545 int old_exp, new_exp;
546 int expire = ts->expire;
547
Willy Tarreaueb23e3e2022-10-12 09:56:08 +0000548 if (!t->expire)
549 return;
Willy Tarreaudbae89e2022-10-12 10:00:50 +0000550
Willy Tarreau63427142022-11-14 17:33:02 +0100551 /* set the task's expire to the newest expiration date. */
Willy Tarreaudbae89e2022-10-12 10:00:50 +0000552 old_exp = HA_ATOMIC_LOAD(&t->exp_task->expire);
Willy Tarreau3238f792022-11-14 17:54:07 +0100553 new_exp = tick_first(expire, old_exp);
554
555 /* let's not go further if we're already up to date */
556 if (new_exp == old_exp)
557 return;
558
559 while (new_exp != old_exp &&
560 !HA_ATOMIC_CAS(&t->exp_task->expire, &old_exp, new_exp)) {
561 __ha_cpu_relax();
Willy Tarreau63427142022-11-14 17:33:02 +0100562 new_exp = tick_first(expire, old_exp);
Willy Tarreau3238f792022-11-14 17:54:07 +0100563 }
Willy Tarreaudbae89e2022-10-12 10:00:50 +0000564
Willy Tarreaueb23e3e2022-10-12 09:56:08 +0000565 task_queue(t->exp_task);
566}
567
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200568/* Returns a valid or initialized stksess for the specified stktable_key in the
569 * specified table, or NULL if the key was NULL, or if no entry was found nor
Willy Tarreau47f22972022-10-11 15:22:42 +0200570 * could be created. The entry's expiration is updated. This function locks the
571 * table, and the refcount of the entry is increased.
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200572 */
Willy Tarreau47f22972022-10-11 15:22:42 +0200573struct stksess *stktable_get_entry(struct stktable *table, struct stktable_key *key)
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200574{
Willy Tarreau175aa062022-10-11 15:13:46 +0200575 struct stksess *ts, *ts2;
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200576
577 if (!key)
578 return NULL;
579
Willy Tarreau47f22972022-10-11 15:22:42 +0200580 ts = stktable_lookup_key(table, key);
581 if (ts)
582 return ts;
Emeric Brun819fc6f2017-06-13 19:37:32 +0200583
Willy Tarreau996f1a52022-10-11 16:19:35 +0200584 /* No such entry exists, let's try to create a new one. this doesn't
585 * require locking yet.
586 */
587
588 ts = stksess_new(table, key);
589 if (!ts)
590 return NULL;
591
592 /* Now we're certain to have a ts. We need to store it. For this we'll
Willy Tarreau47f22972022-10-11 15:22:42 +0200593 * need an exclusive access. We don't need an atomic upgrade, this is
594 * rare and an unlock+lock sequence will do the job fine. Given that
595 * this will not be atomic, the missing entry might appear in the mean
596 * tome so we have to be careful that the one we try to insert is the
597 * one we find.
598 */
Willy Tarreau47f22972022-10-11 15:22:42 +0200599
Willy Tarreau996f1a52022-10-11 16:19:35 +0200600 HA_RWLOCK_WRLOCK(STK_TABLE_LOCK, &table->lock);
Willy Tarreau47f22972022-10-11 15:22:42 +0200601
602 ts2 = __stktable_store(table, ts);
603 if (unlikely(ts2 != ts)) {
604 /* another entry was added in the mean time, let's
605 * switch to it.
606 */
607 __stksess_free(table, ts);
608 ts = ts2;
609 }
610
611 HA_ATOMIC_INC(&ts->ref_cnt);
Willy Tarreau76642222022-10-11 12:02:50 +0200612 HA_RWLOCK_WRUNLOCK(STK_TABLE_LOCK, &table->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200613
Willy Tarreaucbdb5282022-10-12 10:04:01 +0000614 stktable_requeue_exp(table, ts);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200615 return ts;
616}
617
618/* Lookup for an entry with the same key and store the submitted
Willy Tarreaue6288522022-10-12 09:13:14 +0000619 * stksess if not found. This function locks the table either shared or
620 * exclusively, and the refcount of the entry is increased.
Emeric Brun819fc6f2017-06-13 19:37:32 +0200621 */
Willy Tarreaue6288522022-10-12 09:13:14 +0000622struct stksess *stktable_set_entry(struct stktable *table, struct stksess *nts)
Emeric Brun819fc6f2017-06-13 19:37:32 +0200623{
624 struct stksess *ts;
625
Willy Tarreaue6288522022-10-12 09:13:14 +0000626 HA_RWLOCK_RDLOCK(STK_TABLE_LOCK, &table->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200627 ts = __stktable_lookup(table, nts);
Willy Tarreaue6288522022-10-12 09:13:14 +0000628 if (ts) {
629 HA_ATOMIC_INC(&ts->ref_cnt);
630 HA_RWLOCK_RDUNLOCK(STK_TABLE_LOCK, &table->lock);
631 return ts;
Emeric Brun819fc6f2017-06-13 19:37:32 +0200632 }
Willy Tarreaue6288522022-10-12 09:13:14 +0000633 ts = nts;
Emeric Brun819fc6f2017-06-13 19:37:32 +0200634
Willy Tarreaue6288522022-10-12 09:13:14 +0000635 /* let's increment it before switching to exclusive */
636 HA_ATOMIC_INC(&ts->ref_cnt);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200637
Willy Tarreaue6288522022-10-12 09:13:14 +0000638 if (HA_RWLOCK_TRYRDTOSK(STK_TABLE_LOCK, &table->lock) != 0) {
639 /* upgrade to seek lock failed, let's drop and take */
640 HA_RWLOCK_RDUNLOCK(STK_TABLE_LOCK, &table->lock);
641 HA_RWLOCK_WRLOCK(STK_TABLE_LOCK, &table->lock);
642 }
643 else
644 HA_RWLOCK_SKTOWR(STK_TABLE_LOCK, &table->lock);
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200645
Willy Tarreaue6288522022-10-12 09:13:14 +0000646 /* now we're write-locked */
647
648 __stktable_store(table, ts);
649 HA_RWLOCK_WRUNLOCK(STK_TABLE_LOCK, &table->lock);
Willy Tarreaucbdb5282022-10-12 10:04:01 +0000650
651 stktable_requeue_exp(table, ts);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200652 return ts;
653}
Willy Tarreaue6288522022-10-12 09:13:14 +0000654
Emeric Brun3bd697e2010-01-04 15:23:48 +0100655/*
Willy Tarreauaea940e2010-06-06 11:56:36 +0200656 * Trash expired sticky sessions from table <t>. The next expiration date is
657 * returned.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100658 */
659static int stktable_trash_expired(struct stktable *t)
660{
661 struct stksess *ts;
662 struct eb32_node *eb;
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200663 int looped = 0;
Willy Tarreau63427142022-11-14 17:33:02 +0100664 int exp_next;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100665
Willy Tarreau76642222022-10-11 12:02:50 +0200666 HA_RWLOCK_WRLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100667 eb = eb32_lookup_ge(&t->exps, now_ms - TIMER_LOOK_BACK);
668
669 while (1) {
670 if (unlikely(!eb)) {
671 /* we might have reached the end of the tree, typically because
672 * <now_ms> is in the first half and we're first scanning the last
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200673 * half. Let's loop back to the beginning of the tree now if we
674 * have not yet visited it.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100675 */
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200676 if (looped)
677 break;
678 looped = 1;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100679 eb = eb32_first(&t->exps);
680 if (likely(!eb))
681 break;
682 }
683
684 if (likely(tick_is_lt(now_ms, eb->key))) {
685 /* timer not expired yet, revisit it later */
Willy Tarreau63427142022-11-14 17:33:02 +0100686 exp_next = eb->key;
Willy Tarreau4d5f13c2017-11-05 11:04:47 +0100687 goto out_unlock;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100688 }
689
690 /* timer looks expired, detach it from the queue */
Willy Tarreau86257dc2010-06-06 12:57:10 +0200691 ts = eb32_entry(eb, struct stksess, exp);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100692 eb = eb32_next(eb);
693
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200694 /* don't delete an entry which is currently referenced */
695 if (ts->ref_cnt)
696 continue;
697
Willy Tarreau86257dc2010-06-06 12:57:10 +0200698 eb32_delete(&ts->exp);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100699
700 if (!tick_is_expired(ts->expire, now_ms)) {
701 if (!tick_isset(ts->expire))
702 continue;
703
Willy Tarreau86257dc2010-06-06 12:57:10 +0200704 ts->exp.key = ts->expire;
705 eb32_insert(&t->exps, &ts->exp);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100706
Willy Tarreau86257dc2010-06-06 12:57:10 +0200707 if (!eb || eb->key > ts->exp.key)
708 eb = &ts->exp;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100709 continue;
710 }
711
712 /* session expired, trash it */
Willy Tarreau86257dc2010-06-06 12:57:10 +0200713 ebmb_delete(&ts->key);
Emeric Brun85e77c72010-09-23 18:16:52 +0200714 eb32_delete(&ts->upd);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200715 __stksess_free(t, ts);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100716 }
717
718 /* We have found no task to expire in any tree */
Willy Tarreau63427142022-11-14 17:33:02 +0100719 exp_next = TICK_ETERNITY;
Willy Tarreau4d5f13c2017-11-05 11:04:47 +0100720out_unlock:
Willy Tarreau76642222022-10-11 12:02:50 +0200721 HA_RWLOCK_WRUNLOCK(STK_TABLE_LOCK, &t->lock);
Willy Tarreau63427142022-11-14 17:33:02 +0100722 return exp_next;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100723}
724
725/*
Willy Tarreauaea940e2010-06-06 11:56:36 +0200726 * Task processing function to trash expired sticky sessions. A pointer to the
727 * task itself is returned since it never dies.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100728 */
Willy Tarreau144f84a2021-03-02 16:09:26 +0100729struct task *process_table_expire(struct task *task, void *context, unsigned int state)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100730{
Olivier Houchard9f6af332018-05-25 14:04:04 +0200731 struct stktable *t = context;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100732
733 task->expire = stktable_trash_expired(t);
734 return task;
735}
736
Willy Tarreauaea940e2010-06-06 11:56:36 +0200737/* Perform minimal stick table intializations, report 0 in case of error, 1 if OK. */
Emeric Brun3bd697e2010-01-04 15:23:48 +0100738int stktable_init(struct stktable *t)
739{
Remi Tricot-Le Breton208ff012021-05-12 17:39:04 +0200740 int peers_retval = 0;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100741 if (t->size) {
Emeric Brun819fc6f2017-06-13 19:37:32 +0200742 t->keys = EB_ROOT_UNIQUE;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100743 memset(&t->exps, 0, sizeof(t->exps));
Emeric Brun1c6235d2015-12-16 15:28:12 +0100744 t->updates = EB_ROOT_UNIQUE;
Amaury Denoyelle3e064882022-10-12 16:47:59 +0200745 HA_RWLOCK_INIT(&t->lock);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100746
Olivier Houchard52dabbc2018-11-14 17:54:36 +0100747 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 +0100748
Emeric Brun3bd697e2010-01-04 15:23:48 +0100749 if ( t->expire ) {
Willy Tarreaubeeabf52021-10-01 18:23:30 +0200750 t->exp_task = task_new_anywhere();
Willy Tarreau848522f2018-10-15 11:12:15 +0200751 if (!t->exp_task)
752 return 0;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100753 t->exp_task->process = process_table_expire;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100754 t->exp_task->context = (void *)t;
755 }
Christopher Fauletdfd10ab2021-10-06 14:24:19 +0200756 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 +0200757 peers_retval = peers_register_table(t->peers.p, t);
Emeric Brun32da3c42010-09-23 18:39:19 +0200758 }
759
Remi Tricot-Le Breton208ff012021-05-12 17:39:04 +0200760 return (t->pool != NULL) && !peers_retval;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100761 }
762 return 1;
763}
764
765/*
766 * Configuration keywords of known table types
767 */
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200768struct stktable_type stktable_types[SMP_TYPES] = {
769 [SMP_T_SINT] = { "integer", 0, 4 },
770 [SMP_T_IPV4] = { "ip", 0, 4 },
771 [SMP_T_IPV6] = { "ipv6", 0, 16 },
772 [SMP_T_STR] = { "string", STK_F_CUSTOM_KEYSIZE, 32 },
773 [SMP_T_BIN] = { "binary", STK_F_CUSTOM_KEYSIZE, 32 }
774};
Emeric Brun3bd697e2010-01-04 15:23:48 +0100775
776/*
777 * Parse table type configuration.
778 * Returns 0 on successful parsing, else 1.
779 * <myidx> is set at next configuration <args> index.
780 */
781int stktable_parse_type(char **args, int *myidx, unsigned long *type, size_t *key_size)
782{
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200783 for (*type = 0; *type < SMP_TYPES; (*type)++) {
784 if (!stktable_types[*type].kw)
785 continue;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100786 if (strcmp(args[*myidx], stktable_types[*type].kw) != 0)
787 continue;
788
789 *key_size = stktable_types[*type].default_size;
790 (*myidx)++;
791
Willy Tarreauaea940e2010-06-06 11:56:36 +0200792 if (stktable_types[*type].flags & STK_F_CUSTOM_KEYSIZE) {
Emeric Brun3bd697e2010-01-04 15:23:48 +0100793 if (strcmp("len", args[*myidx]) == 0) {
794 (*myidx)++;
795 *key_size = atol(args[*myidx]);
Emeric Brun485479d2010-09-23 18:02:19 +0200796 if (!*key_size)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100797 break;
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200798 if (*type == SMP_T_STR) {
Emeric Brun485479d2010-09-23 18:02:19 +0200799 /* null terminated string needs +1 for '\0'. */
800 (*key_size)++;
801 }
Emeric Brun3bd697e2010-01-04 15:23:48 +0100802 (*myidx)++;
803 }
804 }
805 return 0;
806 }
807 return 1;
808}
809
Emeric Brunc64a2a32021-06-30 18:01:02 +0200810/* reserve some space for data type <type>, there is 2 optionnals
811 * argument at <sa> and <sa2> to configure this data type and
812 * they can be NULL if unused for a given type.
813 * Returns PE_NONE (0) if OK or an error code among :
Willy Tarreau3b63ca22021-05-08 14:10:42 +0200814 * - PE_ENUM_OOR if <type> does not exist
815 * - PE_EXIST if <type> is already registered
Emeric Brunc64a2a32021-06-30 18:01:02 +0200816 * - PE_ARG_NOT_USE if <sa>/<sa2> was provided but not expected
817 * - PE_ARG_MISSING if <sa>/<sa2> was expected but not provided
818 * - PE_ARG_VALUE_OOR if type is an array and <sa> it out of array size range.
Willy Tarreau3b63ca22021-05-08 14:10:42 +0200819 */
Emeric Brunc64a2a32021-06-30 18:01:02 +0200820int stktable_alloc_data_type(struct stktable *t, int type, const char *sa, const char *sa2)
821
Willy Tarreau3b63ca22021-05-08 14:10:42 +0200822{
823 if (type >= STKTABLE_DATA_TYPES)
824 return PE_ENUM_OOR;
825
826 if (t->data_ofs[type])
827 /* already allocated */
828 return PE_EXIST;
829
Emeric Brunc64a2a32021-06-30 18:01:02 +0200830 t->data_nbelem[type] = 1;
831 if (stktable_data_types[type].is_array) {
832 /* arrays take their element count on first argument */
833 if (!sa)
834 return PE_ARG_MISSING;
835 t->data_nbelem[type] = atoi(sa);
836 if (!t->data_nbelem[type] || (t->data_nbelem[type] > STKTABLE_MAX_DT_ARRAY_SIZE))
837 return PE_ARG_VALUE_OOR;
838 sa = sa2;
839 }
840
Willy Tarreau3b63ca22021-05-08 14:10:42 +0200841 switch (stktable_data_types[type].arg_type) {
842 case ARG_T_NONE:
843 if (sa)
844 return PE_ARG_NOT_USED;
845 break;
846 case ARG_T_INT:
847 if (!sa)
848 return PE_ARG_MISSING;
849 t->data_arg[type].i = atoi(sa);
850 break;
851 case ARG_T_DELAY:
852 if (!sa)
853 return PE_ARG_MISSING;
854 sa = parse_time_err(sa, &t->data_arg[type].u, TIME_UNIT_MS);
855 if (sa)
856 return PE_ARG_INVC; /* invalid char */
857 break;
858 }
859
Emeric Brunc64a2a32021-06-30 18:01:02 +0200860 t->data_size += t->data_nbelem[type] * stktable_type_size(stktable_data_types[type].std_type);
Willy Tarreau3b63ca22021-05-08 14:10:42 +0200861 t->data_ofs[type] = -t->data_size;
862 return PE_NONE;
863}
864
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100865/*
Frédéric Lécaillec02766a2019-03-20 15:06:55 +0100866 * Parse a line with <linenum> as number in <file> configuration file to configure
867 * the stick-table with <t> as address and <id> as ID.
868 * <peers> provides the "peers" section pointer only if this function is called
869 * from a "peers" section.
870 * <nid> is the stick-table name which is sent over the network. It must be equal
871 * to <id> if this stick-table is parsed from a proxy section, and prefixed by <peers>
872 * "peers" section name followed by a '/' character if parsed from a "peers" section.
Ilya Shipitsind4259502020-04-08 01:07:56 +0500873 * This is the responsibility of the caller to check this.
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100874 * Return an error status with ERR_* flags set if required, 0 if no error was encountered.
875 */
876int parse_stick_table(const char *file, int linenum, char **args,
Frédéric Lécaillec02766a2019-03-20 15:06:55 +0100877 struct stktable *t, char *id, char *nid, struct peers *peers)
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100878{
879 int err_code = 0;
880 int idx = 1;
881 unsigned int val;
882
883 if (!id || !*id) {
884 ha_alert("parsing [%s:%d] : %s: ID not provided.\n", file, linenum, args[0]);
885 err_code |= ERR_ALERT | ERR_ABORT;
886 goto out;
887 }
888
889 /* Store the "peers" section if this function is called from a "peers" section. */
890 if (peers) {
891 t->peers.p = peers;
892 idx++;
893 }
894
895 t->id = id;
Frédéric Lécaille36d15652022-10-17 14:58:19 +0200896 t->idlen = strlen(id);
Frédéric Lécaillec02766a2019-03-20 15:06:55 +0100897 t->nid = nid;
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100898 t->type = (unsigned int)-1;
899 t->conf.file = file;
900 t->conf.line = linenum;
901
902 while (*args[idx]) {
903 const char *err;
904
905 if (strcmp(args[idx], "size") == 0) {
906 idx++;
907 if (!*(args[idx])) {
908 ha_alert("parsing [%s:%d] : %s: missing argument after '%s'.\n",
909 file, linenum, args[0], args[idx-1]);
910 err_code |= ERR_ALERT | ERR_FATAL;
911 goto out;
912 }
913 if ((err = parse_size_err(args[idx], &t->size))) {
914 ha_alert("parsing [%s:%d] : %s: unexpected character '%c' in argument of '%s'.\n",
915 file, linenum, args[0], *err, args[idx-1]);
916 err_code |= ERR_ALERT | ERR_FATAL;
917 goto out;
918 }
919 idx++;
920 }
921 /* This argument does not exit in "peers" section. */
922 else if (!peers && strcmp(args[idx], "peers") == 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 t->peers.name = strdup(args[idx++]);
931 }
932 else if (strcmp(args[idx], "expire") == 0) {
933 idx++;
934 if (!*(args[idx])) {
935 ha_alert("parsing [%s:%d] : %s: missing argument after '%s'.\n",
936 file, linenum, args[0], args[idx-1]);
937 err_code |= ERR_ALERT | ERR_FATAL;
938 goto out;
939 }
940 err = parse_time_err(args[idx], &val, TIME_UNIT_MS);
Willy Tarreau9faebe32019-06-07 19:00:37 +0200941 if (err == PARSE_TIME_OVER) {
942 ha_alert("parsing [%s:%d]: %s: timer overflow in argument <%s> to <%s>, maximum value is 2147483647 ms (~24.8 days).\n",
943 file, linenum, args[0], args[idx], args[idx-1]);
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100944 err_code |= ERR_ALERT | ERR_FATAL;
945 goto out;
946 }
Willy Tarreau9faebe32019-06-07 19:00:37 +0200947 else if (err == PARSE_TIME_UNDER) {
948 ha_alert("parsing [%s:%d]: %s: timer underflow in argument <%s> to <%s>, minimum non-null value is 1 ms.\n",
949 file, linenum, args[0], args[idx], args[idx-1]);
950 err_code |= ERR_ALERT | ERR_FATAL;
951 goto out;
952 }
953 else if (err) {
954 ha_alert("parsing [%s:%d] : %s: unexpected character '%c' in argument of '%s'.\n",
955 file, linenum, args[0], *err, args[idx-1]);
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100956 err_code |= ERR_ALERT | ERR_FATAL;
957 goto out;
958 }
959 t->expire = val;
960 idx++;
961 }
962 else if (strcmp(args[idx], "nopurge") == 0) {
963 t->nopurge = 1;
964 idx++;
965 }
966 else if (strcmp(args[idx], "type") == 0) {
967 idx++;
968 if (stktable_parse_type(args, &idx, &t->type, &t->key_size) != 0) {
969 ha_alert("parsing [%s:%d] : %s: unknown type '%s'.\n",
970 file, linenum, args[0], args[idx]);
971 err_code |= ERR_ALERT | ERR_FATAL;
972 goto out;
973 }
974 /* idx already points to next arg */
975 }
976 else if (strcmp(args[idx], "store") == 0) {
977 int type, err;
Emeric Brunc64a2a32021-06-30 18:01:02 +0200978 char *cw, *nw, *sa, *sa2;
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100979
980 idx++;
981 nw = args[idx];
982 while (*nw) {
983 /* the "store" keyword supports a comma-separated list */
984 cw = nw;
985 sa = NULL; /* store arg */
Emeric Brunc64a2a32021-06-30 18:01:02 +0200986 sa2 = NULL;
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100987 while (*nw && *nw != ',') {
988 if (*nw == '(') {
989 *nw = 0;
990 sa = ++nw;
991 while (*nw != ')') {
992 if (!*nw) {
993 ha_alert("parsing [%s:%d] : %s: missing closing parenthesis after store option '%s'.\n",
994 file, linenum, args[0], cw);
995 err_code |= ERR_ALERT | ERR_FATAL;
996 goto out;
997 }
Emeric Brunc64a2a32021-06-30 18:01:02 +0200998 if (*nw == ',') {
999 *nw = '\0';
1000 sa2 = nw + 1;
1001 }
Frédéric Lécailled456aa42019-03-08 14:47:00 +01001002 nw++;
1003 }
1004 *nw = '\0';
1005 }
1006 nw++;
1007 }
1008 if (*nw)
1009 *nw++ = '\0';
1010 type = stktable_get_data_type(cw);
1011 if (type < 0) {
1012 ha_alert("parsing [%s:%d] : %s: unknown store option '%s'.\n",
1013 file, linenum, args[0], cw);
1014 err_code |= ERR_ALERT | ERR_FATAL;
1015 goto out;
1016 }
1017
Emeric Brunc64a2a32021-06-30 18:01:02 +02001018 err = stktable_alloc_data_type(t, type, sa, sa2);
Frédéric Lécailled456aa42019-03-08 14:47:00 +01001019 switch (err) {
1020 case PE_NONE: break;
1021 case PE_EXIST:
1022 ha_warning("parsing [%s:%d]: %s: store option '%s' already enabled, ignored.\n",
1023 file, linenum, args[0], cw);
1024 err_code |= ERR_WARN;
1025 break;
1026
1027 case PE_ARG_MISSING:
1028 ha_alert("parsing [%s:%d] : %s: missing argument to store option '%s'.\n",
1029 file, linenum, args[0], cw);
1030 err_code |= ERR_ALERT | ERR_FATAL;
1031 goto out;
1032
1033 case PE_ARG_NOT_USED:
1034 ha_alert("parsing [%s:%d] : %s: unexpected argument to store option '%s'.\n",
1035 file, linenum, args[0], cw);
1036 err_code |= ERR_ALERT | ERR_FATAL;
1037 goto out;
Emeric Brunc64a2a32021-06-30 18:01:02 +02001038 case PE_ARG_VALUE_OOR:
1039 ha_alert("parsing [%s:%d] : %s: array size is out of allowed range (1-%d) for store option '%s'.\n",
1040 file, linenum, args[0], STKTABLE_MAX_DT_ARRAY_SIZE, cw);
1041 err_code |= ERR_ALERT | ERR_FATAL;
1042 goto out;
Frédéric Lécailled456aa42019-03-08 14:47:00 +01001043
1044 default:
1045 ha_alert("parsing [%s:%d] : %s: error when processing store option '%s'.\n",
1046 file, linenum, args[0], cw);
1047 err_code |= ERR_ALERT | ERR_FATAL;
1048 goto out;
1049 }
1050 }
1051 idx++;
Emeric Brunf7ab0bf2021-06-30 18:58:22 +02001052 if (t->data_ofs[STKTABLE_DT_GPT] && t->data_ofs[STKTABLE_DT_GPT0]) {
1053 ha_alert("parsing [%s:%d] : %s: simultaneous usage of 'gpt' and 'gpt0' in a same table is not permitted as 'gpt' overrides 'gpt0'.\n",
1054 file, linenum, args[0]);
1055 err_code |= ERR_ALERT | ERR_FATAL;
1056 goto out;
1057 }
Emeric Brun726783d2021-06-30 19:06:43 +02001058 else if (t->data_ofs[STKTABLE_DT_GPC] && (t->data_ofs[STKTABLE_DT_GPC0] || t->data_ofs[STKTABLE_DT_GPC1])) {
1059 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",
1060 file, linenum, args[0]);
1061 err_code |= ERR_ALERT | ERR_FATAL;
1062 goto out;
1063 }
1064 else if (t->data_ofs[STKTABLE_DT_GPC_RATE] && (t->data_ofs[STKTABLE_DT_GPC0_RATE] || t->data_ofs[STKTABLE_DT_GPC1_RATE])) {
1065 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",
1066 file, linenum, args[0]);
1067 err_code |= ERR_ALERT | ERR_FATAL;
1068 goto out;
1069 }
Frédéric Lécailled456aa42019-03-08 14:47:00 +01001070 }
Thayne McCombs92149f92020-11-20 01:28:26 -07001071 else if (strcmp(args[idx], "srvkey") == 0) {
1072 char *keytype;
1073 idx++;
1074 keytype = args[idx];
1075 if (strcmp(keytype, "name") == 0) {
1076 t->server_key_type = STKTABLE_SRV_NAME;
1077 }
1078 else if (strcmp(keytype, "addr") == 0) {
1079 t->server_key_type = STKTABLE_SRV_ADDR;
1080 }
1081 else {
1082 ha_alert("parsing [%s:%d] : %s : unknown server key type '%s'.\n",
1083 file, linenum, args[0], keytype);
1084 err_code |= ERR_ALERT | ERR_FATAL;
1085 goto out;
1086
1087 }
1088 idx++;
1089 }
Frédéric Lécailled456aa42019-03-08 14:47:00 +01001090 else {
1091 ha_alert("parsing [%s:%d] : %s: unknown argument '%s'.\n",
1092 file, linenum, args[0], args[idx]);
1093 err_code |= ERR_ALERT | ERR_FATAL;
1094 goto out;
1095 }
1096 }
1097
1098 if (!t->size) {
1099 ha_alert("parsing [%s:%d] : %s: missing size.\n",
1100 file, linenum, args[0]);
1101 err_code |= ERR_ALERT | ERR_FATAL;
1102 goto out;
1103 }
1104
1105 if (t->type == (unsigned int)-1) {
1106 ha_alert("parsing [%s:%d] : %s: missing type.\n",
1107 file, linenum, args[0]);
1108 err_code |= ERR_ALERT | ERR_FATAL;
1109 goto out;
1110 }
1111
1112 out:
1113 return err_code;
1114}
1115
Willy Tarreau8fed9032014-07-03 17:02:46 +02001116/* Prepares a stktable_key from a sample <smp> to search into table <t>.
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001117 * Note that the sample *is* modified and that the returned key may point
1118 * to it, so the sample must not be modified afterwards before the lookup.
Willy Tarreau8fed9032014-07-03 17:02:46 +02001119 * Returns NULL if the sample could not be converted (eg: no matching type),
1120 * otherwise a pointer to the static stktable_key filled with what is needed
1121 * for the lookup.
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001122 */
Willy Tarreau8fed9032014-07-03 17:02:46 +02001123struct stktable_key *smp_to_stkey(struct sample *smp, struct stktable *t)
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001124{
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001125 /* Convert sample. */
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +02001126 if (!sample_convert(smp, t->type))
Willy Tarreau7fc1c6e2012-04-26 11:03:17 +02001127 return NULL;
1128
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001129 /* Fill static_table_key. */
1130 switch (t->type) {
Emeric Brun485479d2010-09-23 18:02:19 +02001131
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +02001132 case SMP_T_IPV4:
Christopher Fauletca20d022017-08-29 15:30:31 +02001133 static_table_key.key = &smp->data.u.ipv4;
1134 static_table_key.key_len = 4;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001135 break;
Emeric Brun485479d2010-09-23 18:02:19 +02001136
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +02001137 case SMP_T_IPV6:
Christopher Fauletca20d022017-08-29 15:30:31 +02001138 static_table_key.key = &smp->data.u.ipv6;
1139 static_table_key.key_len = 16;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001140 break;
Emeric Brun485479d2010-09-23 18:02:19 +02001141
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +02001142 case SMP_T_SINT:
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001143 /* The stick table require a 32bit unsigned int, "sint" is a
1144 * signed 64 it, so we can convert it inplace.
1145 */
Willy Tarreau28c63c12019-10-23 06:21:05 +02001146 smp->data.u.sint = (unsigned int)smp->data.u.sint;
Christopher Fauletca20d022017-08-29 15:30:31 +02001147 static_table_key.key = &smp->data.u.sint;
1148 static_table_key.key_len = 4;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001149 break;
1150
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +02001151 case SMP_T_STR:
Willy Tarreauce6955e2016-08-09 11:59:12 +02001152 if (!smp_make_safe(smp))
1153 return NULL;
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001154 static_table_key.key = smp->data.u.str.area;
1155 static_table_key.key_len = smp->data.u.str.data;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001156 break;
Emeric Brun485479d2010-09-23 18:02:19 +02001157
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +02001158 case SMP_T_BIN:
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001159 if (smp->data.u.str.data < t->key_size) {
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001160 /* This type needs padding with 0. */
Willy Tarreauf65c6c02016-08-09 12:08:41 +02001161 if (!smp_make_rw(smp))
1162 return NULL;
1163
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001164 if (smp->data.u.str.size < t->key_size)
1165 if (!smp_dup(smp))
1166 return NULL;
1167 if (smp->data.u.str.size < t->key_size)
1168 return NULL;
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001169 memset(smp->data.u.str.area + smp->data.u.str.data, 0,
1170 t->key_size - smp->data.u.str.data);
1171 smp->data.u.str.data = t->key_size;
Emeric Brun485479d2010-09-23 18:02:19 +02001172 }
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001173 static_table_key.key = smp->data.u.str.area;
1174 static_table_key.key_len = smp->data.u.str.data;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001175 break;
Emeric Brun485479d2010-09-23 18:02:19 +02001176
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001177 default: /* impossible case. */
1178 return NULL;
Emeric Brun485479d2010-09-23 18:02:19 +02001179 }
1180
Christopher Fauletca20d022017-08-29 15:30:31 +02001181 return &static_table_key;
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001182}
1183
1184/*
Willy Tarreau8fed9032014-07-03 17:02:46 +02001185 * Process a fetch + format conversion as defined by the sample expression <expr>
1186 * on request or response considering the <opt> parameter. Returns either NULL if
1187 * no key could be extracted, or a pointer to the converted result stored in
1188 * static_table_key in format <table_type>. If <smp> is not NULL, it will be reset
1189 * and its flags will be initialized so that the caller gets a copy of the input
Willy Tarreau6bcb0a82014-07-30 08:56:35 +02001190 * sample, and knows why it was not accepted (eg: SMP_F_MAY_CHANGE is present
1191 * without SMP_OPT_FINAL). The output will be usable like this :
1192 *
1193 * return MAY_CHANGE FINAL Meaning for the sample
1194 * NULL 0 * Not present and will never be (eg: header)
1195 * NULL 1 0 Not present or unstable, could change (eg: req_len)
1196 * NULL 1 1 Not present, will not change anymore
1197 * smp 0 * Present and will not change (eg: header)
1198 * smp 1 0 not possible
1199 * smp 1 1 Present, last known value (eg: request length)
Willy Tarreau8fed9032014-07-03 17:02:46 +02001200 */
Willy Tarreau192252e2015-04-04 01:47:55 +02001201struct stktable_key *stktable_fetch_key(struct stktable *t, struct proxy *px, struct session *sess, struct stream *strm,
Willy Tarreau8fed9032014-07-03 17:02:46 +02001202 unsigned int opt, struct sample_expr *expr, struct sample *smp)
1203{
1204 if (smp)
1205 memset(smp, 0, sizeof(*smp));
1206
Willy Tarreau192252e2015-04-04 01:47:55 +02001207 smp = sample_process(px, sess, strm, opt, expr, smp);
Willy Tarreau8fed9032014-07-03 17:02:46 +02001208 if (!smp)
1209 return NULL;
1210
1211 if ((smp->flags & SMP_F_MAY_CHANGE) && !(opt & SMP_OPT_FINAL))
1212 return NULL; /* we can only use stable samples */
1213
1214 return smp_to_stkey(smp, t);
1215}
1216
1217/*
Willy Tarreau12785782012-04-27 21:37:17 +02001218 * Returns 1 if sample expression <expr> result can be converted to table key of
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001219 * type <table_type>, otherwise zero. Used in configuration check.
1220 */
Willy Tarreau12785782012-04-27 21:37:17 +02001221int stktable_compatible_sample(struct sample_expr *expr, unsigned long table_type)
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001222{
Thierry FOURNIERf73eb8f2013-11-27 15:30:55 +01001223 int out_type;
1224
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +02001225 if (table_type >= SMP_TYPES || !stktable_types[table_type].kw)
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001226 return 0;
1227
Thierry FOURNIERf73eb8f2013-11-27 15:30:55 +01001228 out_type = smp_expr_output_type(expr);
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001229
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001230 /* Convert sample. */
1231 if (!sample_casts[out_type][table_type])
Thierry FOURNIERf73eb8f2013-11-27 15:30:55 +01001232 return 0;
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001233
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001234 return 1;
1235}
Emeric Brun3bd697e2010-01-04 15:23:48 +01001236
Willy Tarreauedee1d62014-07-15 16:44:27 +02001237/* Extra data types processing : after the last one, some room may remain
1238 * before STKTABLE_DATA_TYPES that may be used to register extra data types
1239 * at run time.
1240 */
Willy Tarreau08d5f982010-06-06 13:34:54 +02001241struct stktable_data_type stktable_data_types[STKTABLE_DATA_TYPES] = {
Willy Tarreau3b9c6e02010-07-18 08:04:30 +02001242 [STKTABLE_DT_SERVER_ID] = { .name = "server_id", .std_type = STD_T_SINT },
Thierry FOURNIER3cf11112015-07-28 08:57:05 +02001243 [STKTABLE_DT_GPT0] = { .name = "gpt0", .std_type = STD_T_UINT },
Willy Tarreau3b9c6e02010-07-18 08:04:30 +02001244 [STKTABLE_DT_GPC0] = { .name = "gpc0", .std_type = STD_T_UINT },
Willy Tarreauba2ffd12013-05-29 15:54:14 +02001245 [STKTABLE_DT_GPC0_RATE] = { .name = "gpc0_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
Willy Tarreau3b9c6e02010-07-18 08:04:30 +02001246 [STKTABLE_DT_CONN_CNT] = { .name = "conn_cnt", .std_type = STD_T_UINT },
1247 [STKTABLE_DT_CONN_RATE] = { .name = "conn_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
Willy Tarreaudb2ab822021-10-08 17:53:12 +02001248 [STKTABLE_DT_CONN_CUR] = { .name = "conn_cur", .std_type = STD_T_UINT, .is_local = 1 },
Willy Tarreau3b9c6e02010-07-18 08:04:30 +02001249 [STKTABLE_DT_SESS_CNT] = { .name = "sess_cnt", .std_type = STD_T_UINT },
1250 [STKTABLE_DT_SESS_RATE] = { .name = "sess_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
1251 [STKTABLE_DT_HTTP_REQ_CNT] = { .name = "http_req_cnt", .std_type = STD_T_UINT },
1252 [STKTABLE_DT_HTTP_REQ_RATE] = { .name = "http_req_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
1253 [STKTABLE_DT_HTTP_ERR_CNT] = { .name = "http_err_cnt", .std_type = STD_T_UINT },
1254 [STKTABLE_DT_HTTP_ERR_RATE] = { .name = "http_err_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
1255 [STKTABLE_DT_BYTES_IN_CNT] = { .name = "bytes_in_cnt", .std_type = STD_T_ULL },
1256 [STKTABLE_DT_BYTES_IN_RATE] = { .name = "bytes_in_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
1257 [STKTABLE_DT_BYTES_OUT_CNT] = { .name = "bytes_out_cnt", .std_type = STD_T_ULL },
1258 [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 +01001259 [STKTABLE_DT_GPC1] = { .name = "gpc1", .std_type = STD_T_UINT },
1260 [STKTABLE_DT_GPC1_RATE] = { .name = "gpc1_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
Thayne McCombs92149f92020-11-20 01:28:26 -07001261 [STKTABLE_DT_SERVER_KEY] = { .name = "server_key", .std_type = STD_T_DICT },
Willy Tarreau826f3ab2021-02-10 12:07:15 +01001262 [STKTABLE_DT_HTTP_FAIL_CNT] = { .name = "http_fail_cnt", .std_type = STD_T_UINT },
1263 [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 +02001264 [STKTABLE_DT_GPT] = { .name = "gpt", .std_type = STD_T_UINT, .is_array = 1 },
Emeric Brun4d7ada82021-06-30 19:04:16 +02001265 [STKTABLE_DT_GPC] = { .name = "gpc", .std_type = STD_T_UINT, .is_array = 1 },
1266 [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 +02001267};
1268
Willy Tarreauedee1d62014-07-15 16:44:27 +02001269/* Registers stick-table extra data type with index <idx>, name <name>, type
1270 * <std_type> and arg type <arg_type>. If the index is negative, the next free
1271 * index is automatically allocated. The allocated index is returned, or -1 if
1272 * no free index was found or <name> was already registered. The <name> is used
1273 * directly as a pointer, so if it's not stable, the caller must allocate it.
1274 */
1275int stktable_register_data_store(int idx, const char *name, int std_type, int arg_type)
1276{
1277 if (idx < 0) {
1278 for (idx = 0; idx < STKTABLE_DATA_TYPES; idx++) {
1279 if (!stktable_data_types[idx].name)
1280 break;
1281
1282 if (strcmp(stktable_data_types[idx].name, name) == 0)
1283 return -1;
1284 }
1285 }
1286
1287 if (idx >= STKTABLE_DATA_TYPES)
1288 return -1;
1289
1290 if (stktable_data_types[idx].name != NULL)
1291 return -1;
1292
1293 stktable_data_types[idx].name = name;
1294 stktable_data_types[idx].std_type = std_type;
1295 stktable_data_types[idx].arg_type = arg_type;
1296 return idx;
1297}
1298
Willy Tarreau08d5f982010-06-06 13:34:54 +02001299/*
1300 * Returns the data type number for the stktable_data_type whose name is <name>,
1301 * or <0 if not found.
1302 */
1303int stktable_get_data_type(char *name)
1304{
1305 int type;
1306
1307 for (type = 0; type < STKTABLE_DATA_TYPES; type++) {
Willy Tarreauedee1d62014-07-15 16:44:27 +02001308 if (!stktable_data_types[type].name)
1309 continue;
Willy Tarreau08d5f982010-06-06 13:34:54 +02001310 if (strcmp(name, stktable_data_types[type].name) == 0)
1311 return type;
1312 }
Thayne McCombs92149f92020-11-20 01:28:26 -07001313 /* For backwards compatibility */
1314 if (strcmp(name, "server_name") == 0)
1315 return STKTABLE_DT_SERVER_KEY;
Willy Tarreau08d5f982010-06-06 13:34:54 +02001316 return -1;
1317}
1318
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001319/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1320 * it up into this table. Returns true if found, false otherwise. The input
1321 * type is STR so that input samples are converted to string (since all types
1322 * can be converted to strings), then the function casts the string again into
1323 * the table's type. This is a double conversion, but in the future we might
1324 * support automatic input types to perform the cast on the fly.
1325 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001326static int sample_conv_in_table(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001327{
1328 struct stktable *t;
1329 struct stktable_key *key;
1330 struct stksess *ts;
1331
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001332 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001333
1334 key = smp_to_stkey(smp, t);
1335 if (!key)
1336 return 0;
1337
1338 ts = stktable_lookup_key(t, key);
1339
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001340 smp->data.type = SMP_T_BOOL;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001341 smp->data.u.sint = !!ts;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001342 smp->flags = SMP_F_VOL_TEST;
Willy Tarreau43e90352018-06-27 06:25:57 +02001343 stktable_release(t, ts);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001344 return 1;
1345}
1346
1347/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1348 * it up into this table. Returns the data rate received from clients in bytes/s
1349 * if the key is present in the table, otherwise zero, so that comparisons can
1350 * be easily performed. If the inspected parameter is not stored in the table,
1351 * <not found> is returned.
1352 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001353static int sample_conv_table_bytes_in_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001354{
1355 struct stktable *t;
1356 struct stktable_key *key;
1357 struct stksess *ts;
1358 void *ptr;
1359
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001360 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001361
1362 key = smp_to_stkey(smp, t);
1363 if (!key)
1364 return 0;
1365
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001366 ts = stktable_lookup_key(t, key);
1367
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001368 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001369 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001370 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001371
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001372 if (!ts) /* key not present */
1373 return 1;
1374
1375 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_IN_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001376 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001377 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Daniel Corbett3e60b112018-05-27 09:47:12 -04001378 t->data_arg[STKTABLE_DT_BYTES_IN_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001379
Daniel Corbett3e60b112018-05-27 09:47:12 -04001380 stktable_release(t, ts);
1381 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001382}
1383
1384/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1385 * it up into this table. Returns the cumulated number of connections for the key
1386 * if the key is present in the table, otherwise zero, so that comparisons can
1387 * be easily performed. If the inspected parameter is not stored in the table,
1388 * <not found> is returned.
1389 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001390static int sample_conv_table_conn_cnt(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001391{
1392 struct stktable *t;
1393 struct stktable_key *key;
1394 struct stksess *ts;
1395 void *ptr;
1396
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001397 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001398
1399 key = smp_to_stkey(smp, t);
1400 if (!key)
1401 return 0;
1402
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001403 ts = stktable_lookup_key(t, key);
1404
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001405 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001406 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001407 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001408
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001409 if (!ts) /* key not present */
1410 return 1;
1411
1412 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_CONN_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001413 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001414 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001415
Daniel Corbett3e60b112018-05-27 09:47:12 -04001416 stktable_release(t, ts);
1417 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001418}
1419
1420/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1421 * it up into this table. Returns the number of concurrent connections for the
1422 * key if the key is present in the table, otherwise zero, so that comparisons
1423 * can be easily performed. If the inspected parameter is not stored in the
1424 * table, <not found> is returned.
1425 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001426static int sample_conv_table_conn_cur(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001427{
1428 struct stktable *t;
1429 struct stktable_key *key;
1430 struct stksess *ts;
1431 void *ptr;
1432
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001433 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001434
1435 key = smp_to_stkey(smp, t);
1436 if (!key)
1437 return 0;
1438
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001439 ts = stktable_lookup_key(t, key);
1440
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001441 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001442 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001443 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001444
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001445 if (!ts) /* key not present */
1446 return 1;
1447
1448 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_CONN_CUR);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001449 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001450 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001451
Daniel Corbett3e60b112018-05-27 09:47:12 -04001452 stktable_release(t, ts);
1453 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001454}
1455
1456/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1457 * it up into this table. Returns the rate of incoming connections from the key
1458 * if the key is present in the table, otherwise zero, so that comparisons can
1459 * be easily performed. If the inspected parameter is not stored in the table,
1460 * <not found> is returned.
1461 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001462static int sample_conv_table_conn_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001463{
1464 struct stktable *t;
1465 struct stktable_key *key;
1466 struct stksess *ts;
1467 void *ptr;
1468
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001469 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001470
1471 key = smp_to_stkey(smp, t);
1472 if (!key)
1473 return 0;
1474
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001475 ts = stktable_lookup_key(t, key);
1476
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001477 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001478 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001479 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001480
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001481 if (!ts) /* key not present */
1482 return 1;
1483
1484 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_CONN_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001485 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001486 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Daniel Corbett3e60b112018-05-27 09:47:12 -04001487 t->data_arg[STKTABLE_DT_CONN_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001488
Daniel Corbett3e60b112018-05-27 09:47:12 -04001489 stktable_release(t, ts);
1490 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001491}
1492
1493/* 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 +02001494 * it up into this table. Returns the expiration delay for the key if the key is
1495 * present in the table, otherwise the default value provided as second argument
1496 * if any, if not (no default value), <not found> is returned.
1497 */
1498static int sample_conv_table_expire(const struct arg *arg_p, struct sample *smp, void *private)
1499{
1500 struct stktable *t;
1501 struct stktable_key *key;
1502 struct stksess *ts;
1503
1504 t = arg_p[0].data.t;
1505
1506 key = smp_to_stkey(smp, t);
1507 if (!key)
1508 return 0;
1509
1510 ts = stktable_lookup_key(t, key);
1511
1512 smp->flags = SMP_F_VOL_TEST;
1513 smp->data.type = SMP_T_SINT;
1514 smp->data.u.sint = 0;
1515
1516 if (!ts) { /* key not present */
1517 if (arg_p[1].type == ARGT_STOP)
1518 return 0;
1519
1520 /* default value */
1521 smp->data.u.sint = arg_p[1].data.sint;
1522 return 1;
1523 }
1524
1525 smp->data.u.sint = tick_remain(now_ms, ts->expire);
1526
1527 stktable_release(t, ts);
1528 return 1;
1529}
1530
1531/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1532 * it up into this table. Returns the time the key remains unused if the key is
1533 * present in the table, otherwise the default value provided as second argument
1534 * if any, if not (no default value), <not found> is returned.
1535 */
1536static int sample_conv_table_idle(const struct arg *arg_p, struct sample *smp, void *private)
1537{
1538 struct stktable *t;
1539 struct stktable_key *key;
1540 struct stksess *ts;
1541
1542 t = arg_p[0].data.t;
1543
1544 key = smp_to_stkey(smp, t);
1545 if (!key)
1546 return 0;
1547
1548 ts = stktable_lookup_key(t, key);
1549
1550 smp->flags = SMP_F_VOL_TEST;
1551 smp->data.type = SMP_T_SINT;
1552 smp->data.u.sint = 0;
1553
1554 if (!ts) { /* key not present */
1555 if (arg_p[1].type == ARGT_STOP)
1556 return 0;
1557
1558 /* default value */
1559 smp->data.u.sint = arg_p[1].data.sint;
1560 return 1;
1561 }
1562
1563 smp->data.u.sint = tick_remain(tick_remain(now_ms, ts->expire), t->expire);
1564
1565 stktable_release(t, ts);
1566 return 1;
1567}
1568
1569/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001570 * it up into this table. Returns the data rate sent to clients in bytes/s
1571 * if the key is present in the table, otherwise zero, so that comparisons can
1572 * be easily performed. If the inspected parameter is not stored in the table,
1573 * <not found> is returned.
1574 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001575static int sample_conv_table_bytes_out_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001576{
1577 struct stktable *t;
1578 struct stktable_key *key;
1579 struct stksess *ts;
1580 void *ptr;
1581
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001582 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001583
1584 key = smp_to_stkey(smp, t);
1585 if (!key)
1586 return 0;
1587
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001588 ts = stktable_lookup_key(t, key);
1589
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001590 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001591 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001592 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001593
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001594 if (!ts) /* key not present */
1595 return 1;
1596
1597 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_OUT_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001598 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001599 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Daniel Corbett3e60b112018-05-27 09:47:12 -04001600 t->data_arg[STKTABLE_DT_BYTES_OUT_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001601
Daniel Corbett3e60b112018-05-27 09:47:12 -04001602 stktable_release(t, ts);
1603 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001604}
1605
Emeric Brun877b0b52021-06-30 18:57:49 +02001606/* Casts sample <smp> to the type of the table specified in arg_p(1), and looks
1607 * it up into this table. Returns the value of the GPT[arg_p(0)] tag for the key
1608 * if the key is present in the table, otherwise false, so that comparisons can
1609 * be easily performed. If the inspected parameter is not stored in the table,
1610 * <not found> is returned.
1611 */
1612static int sample_conv_table_gpt(const struct arg *arg_p, struct sample *smp, void *private)
1613{
1614 struct stktable *t;
1615 struct stktable_key *key;
1616 struct stksess *ts;
1617 void *ptr;
1618 unsigned int idx;
1619
1620 idx = arg_p[0].data.sint;
1621
1622 t = arg_p[1].data.t;
1623
1624 key = smp_to_stkey(smp, t);
1625 if (!key)
1626 return 0;
1627
1628 ts = stktable_lookup_key(t, key);
1629
1630 smp->flags = SMP_F_VOL_TEST;
1631 smp->data.type = SMP_T_SINT;
1632 smp->data.u.sint = 0;
1633
1634 if (!ts) /* key not present */
1635 return 1;
1636
1637 ptr = stktable_data_ptr_idx(t, ts, STKTABLE_DT_GPT, idx);
1638 if (ptr)
1639 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
1640
1641 stktable_release(t, ts);
1642 return !!ptr;
1643}
1644
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001645/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001646 * it up into this table. Returns the value of the GPT0 tag for the key
1647 * if the key is present in the table, otherwise false, so that comparisons can
1648 * be easily performed. If the inspected parameter is not stored in the table,
1649 * <not found> is returned.
1650 */
1651static int sample_conv_table_gpt0(const struct arg *arg_p, struct sample *smp, void *private)
1652{
1653 struct stktable *t;
1654 struct stktable_key *key;
1655 struct stksess *ts;
1656 void *ptr;
1657
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001658 t = arg_p[0].data.t;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001659
1660 key = smp_to_stkey(smp, t);
1661 if (!key)
1662 return 0;
1663
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001664 ts = stktable_lookup_key(t, key);
1665
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001666 smp->flags = SMP_F_VOL_TEST;
1667 smp->data.type = SMP_T_SINT;
1668 smp->data.u.sint = 0;
1669
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001670 if (!ts) /* key not present */
1671 return 1;
1672
1673 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPT0);
Emeric Brunf7ab0bf2021-06-30 18:58:22 +02001674 if (!ptr)
1675 ptr = stktable_data_ptr_idx(t, ts, STKTABLE_DT_GPT, 0);
1676
Daniel Corbett3e60b112018-05-27 09:47:12 -04001677 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001678 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001679
Daniel Corbett3e60b112018-05-27 09:47:12 -04001680 stktable_release(t, ts);
1681 return !!ptr;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001682}
1683
Emeric Brun4d7ada82021-06-30 19:04:16 +02001684/* Casts sample <smp> to the type of the table specified in arg_p(1), and looks
1685 * it up into this table. Returns the value of the GPC[arg_p(0)] counter for the key
1686 * if the key is present in the table, otherwise zero, so that comparisons can
1687 * be easily performed. If the inspected parameter is not stored in the table,
1688 * <not found> is returned.
1689 */
1690static int sample_conv_table_gpc(const struct arg *arg_p, struct sample *smp, void *private)
1691{
1692 struct stktable *t;
1693 struct stktable_key *key;
1694 struct stksess *ts;
1695 void *ptr;
1696 unsigned int idx;
1697
1698 idx = arg_p[0].data.sint;
1699
1700 t = arg_p[1].data.t;
1701
1702 key = smp_to_stkey(smp, t);
1703 if (!key)
1704 return 0;
1705
1706 ts = stktable_lookup_key(t, key);
1707
1708 smp->flags = SMP_F_VOL_TEST;
1709 smp->data.type = SMP_T_SINT;
1710 smp->data.u.sint = 0;
1711
1712 if (!ts) /* key not present */
1713 return 1;
1714
1715 ptr = stktable_data_ptr_idx(t, ts, STKTABLE_DT_GPC, idx);
1716 if (ptr)
1717 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
1718
1719 stktable_release(t, ts);
1720 return !!ptr;
1721}
1722
1723/* Casts sample <smp> to the type of the table specified in arg_p(1), and looks
1724 * it up into this table. Returns the event rate of the GPC[arg_p(0)] counter
1725 * for the key if the key is present in the table, otherwise zero, so that
1726 * comparisons can be easily performed. If the inspected parameter is not
1727 * stored in the table, <not found> is returned.
1728 */
1729static int sample_conv_table_gpc_rate(const struct arg *arg_p, struct sample *smp, void *private)
1730{
1731 struct stktable *t;
1732 struct stktable_key *key;
1733 struct stksess *ts;
1734 void *ptr;
1735 unsigned int idx;
1736
1737 idx = arg_p[0].data.sint;
1738
1739 t = arg_p[1].data.t;
1740
1741 key = smp_to_stkey(smp, t);
1742 if (!key)
1743 return 0;
1744
1745 ts = stktable_lookup_key(t, key);
1746
1747 smp->flags = SMP_F_VOL_TEST;
1748 smp->data.type = SMP_T_SINT;
1749 smp->data.u.sint = 0;
1750
1751 if (!ts) /* key not present */
1752 return 1;
1753
1754 ptr = stktable_data_ptr_idx(t, ts, STKTABLE_DT_GPC_RATE, idx);
1755 if (ptr)
1756 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
1757 t->data_arg[STKTABLE_DT_GPC_RATE].u);
1758
1759 stktable_release(t, ts);
1760 return !!ptr;
1761}
1762
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001763/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001764 * it up into this table. Returns the value of the GPC0 counter for the key
1765 * if the key is present in the table, otherwise zero, so that comparisons can
1766 * be easily performed. If the inspected parameter is not stored in the table,
1767 * <not found> is returned.
1768 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001769static int sample_conv_table_gpc0(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001770{
1771 struct stktable *t;
1772 struct stktable_key *key;
1773 struct stksess *ts;
1774 void *ptr;
1775
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001776 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001777
1778 key = smp_to_stkey(smp, t);
1779 if (!key)
1780 return 0;
1781
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001782 ts = stktable_lookup_key(t, key);
1783
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001784 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001785 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001786 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001787
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001788 if (!ts) /* key not present */
1789 return 1;
1790
1791 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPC0);
Emeric Brun726783d2021-06-30 19:06:43 +02001792 if (!ptr) {
1793 /* fallback on the gpc array */
1794 ptr = stktable_data_ptr_idx(t, ts, STKTABLE_DT_GPC, 0);
1795 }
1796
Daniel Corbett3e60b112018-05-27 09:47:12 -04001797 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001798 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001799
Daniel Corbett3e60b112018-05-27 09:47:12 -04001800 stktable_release(t, ts);
1801 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001802}
1803
1804/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1805 * it up into this table. Returns the event rate of the GPC0 counter for the key
1806 * if the key is present in the table, otherwise zero, so that comparisons can
1807 * be easily performed. If the inspected parameter is not stored in the table,
1808 * <not found> is returned.
1809 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001810static int sample_conv_table_gpc0_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001811{
1812 struct stktable *t;
1813 struct stktable_key *key;
1814 struct stksess *ts;
1815 void *ptr;
1816
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001817 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001818
1819 key = smp_to_stkey(smp, t);
1820 if (!key)
1821 return 0;
1822
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001823 ts = stktable_lookup_key(t, key);
1824
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001825 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001826 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001827 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001828
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001829 if (!ts) /* key not present */
1830 return 1;
1831
1832 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPC0_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001833 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001834 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Daniel Corbett3e60b112018-05-27 09:47:12 -04001835 t->data_arg[STKTABLE_DT_GPC0_RATE].u);
Emeric Brun726783d2021-06-30 19:06:43 +02001836 else {
1837 /* fallback on the gpc array */
1838 ptr = stktable_data_ptr_idx(t, ts, STKTABLE_DT_GPC_RATE, 0);
1839 if (ptr)
1840 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
1841 t->data_arg[STKTABLE_DT_GPC_RATE].u);
1842 }
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001843
Daniel Corbett3e60b112018-05-27 09:47:12 -04001844 stktable_release(t, ts);
1845 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001846}
1847
1848/* 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 +01001849 * it up into this table. Returns the value of the GPC1 counter for the key
1850 * if the key is present in the table, otherwise zero, so that comparisons can
1851 * be easily performed. If the inspected parameter is not stored in the table,
1852 * <not found> is returned.
1853 */
1854static int sample_conv_table_gpc1(const struct arg *arg_p, struct sample *smp, void *private)
1855{
1856 struct stktable *t;
1857 struct stktable_key *key;
1858 struct stksess *ts;
1859 void *ptr;
1860
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001861 t = arg_p[0].data.t;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001862
1863 key = smp_to_stkey(smp, t);
1864 if (!key)
1865 return 0;
1866
1867 ts = stktable_lookup_key(t, key);
1868
1869 smp->flags = SMP_F_VOL_TEST;
1870 smp->data.type = SMP_T_SINT;
1871 smp->data.u.sint = 0;
1872
1873 if (!ts) /* key not present */
1874 return 1;
1875
1876 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPC1);
Emeric Brun726783d2021-06-30 19:06:43 +02001877 if (!ptr) {
1878 /* fallback on the gpc array */
1879 ptr = stktable_data_ptr_idx(t, ts, STKTABLE_DT_GPC, 1);
1880 }
1881
Daniel Corbett3e60b112018-05-27 09:47:12 -04001882 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001883 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001884
Daniel Corbett3e60b112018-05-27 09:47:12 -04001885 stktable_release(t, ts);
1886 return !!ptr;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001887}
1888
1889/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1890 * it up into this table. Returns the event rate of the GPC1 counter for the key
1891 * if the key is present in the table, otherwise zero, so that comparisons can
1892 * be easily performed. If the inspected parameter is not stored in the table,
1893 * <not found> is returned.
1894 */
1895static int sample_conv_table_gpc1_rate(const struct arg *arg_p, struct sample *smp, void *private)
1896{
1897 struct stktable *t;
1898 struct stktable_key *key;
1899 struct stksess *ts;
1900 void *ptr;
1901
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001902 t = arg_p[0].data.t;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001903
1904 key = smp_to_stkey(smp, t);
1905 if (!key)
1906 return 0;
1907
1908 ts = stktable_lookup_key(t, key);
1909
1910 smp->flags = SMP_F_VOL_TEST;
1911 smp->data.type = SMP_T_SINT;
1912 smp->data.u.sint = 0;
1913
1914 if (!ts) /* key not present */
1915 return 1;
1916
1917 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPC1_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001918 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001919 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Daniel Corbett3e60b112018-05-27 09:47:12 -04001920 t->data_arg[STKTABLE_DT_GPC1_RATE].u);
Emeric Brun726783d2021-06-30 19:06:43 +02001921 else {
1922 /* fallback on the gpc array */
1923 ptr = stktable_data_ptr_idx(t, ts, STKTABLE_DT_GPC_RATE, 1);
1924 if (ptr)
1925 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
1926 t->data_arg[STKTABLE_DT_GPC_RATE].u);
1927 }
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001928
Daniel Corbett3e60b112018-05-27 09:47:12 -04001929 stktable_release(t, ts);
1930 return !!ptr;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001931}
1932
1933/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001934 * it up into this table. Returns the cumulated number of HTTP request errors
1935 * for the key if the key is present in the table, otherwise zero, so that
1936 * comparisons can be easily performed. If the inspected parameter is not stored
1937 * in the table, <not found> is returned.
1938 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001939static int sample_conv_table_http_err_cnt(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001940{
1941 struct stktable *t;
1942 struct stktable_key *key;
1943 struct stksess *ts;
1944 void *ptr;
1945
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001946 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001947
1948 key = smp_to_stkey(smp, t);
1949 if (!key)
1950 return 0;
1951
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001952 ts = stktable_lookup_key(t, key);
1953
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001954 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001955 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001956 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001957
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001958 if (!ts) /* key not present */
1959 return 1;
1960
1961 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_ERR_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001962 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001963 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001964
Daniel Corbett3e60b112018-05-27 09:47:12 -04001965 stktable_release(t, ts);
1966 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001967}
1968
1969/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1970 * it up into this table. Returns the HTTP request error rate the key
1971 * if the key is present in the table, otherwise zero, so that comparisons can
1972 * be easily performed. If the inspected parameter is not stored in the table,
1973 * <not found> is returned.
1974 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001975static int sample_conv_table_http_err_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001976{
1977 struct stktable *t;
1978 struct stktable_key *key;
1979 struct stksess *ts;
1980 void *ptr;
1981
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001982 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001983
1984 key = smp_to_stkey(smp, t);
1985 if (!key)
1986 return 0;
1987
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001988 ts = stktable_lookup_key(t, key);
1989
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001990 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001991 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001992 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001993
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001994 if (!ts) /* key not present */
1995 return 1;
1996
1997 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_ERR_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001998 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001999 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Daniel Corbett3e60b112018-05-27 09:47:12 -04002000 t->data_arg[STKTABLE_DT_HTTP_ERR_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002001
Daniel Corbett3e60b112018-05-27 09:47:12 -04002002 stktable_release(t, ts);
2003 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002004}
2005
2006/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Willy Tarreau826f3ab2021-02-10 12:07:15 +01002007 * it up into this table. Returns the cumulated number of HTTP response failures
2008 * for the key if the key is present in the table, otherwise zero, so that
2009 * comparisons can be easily performed. If the inspected parameter is not stored
2010 * in the table, <not found> is returned.
2011 */
2012static int sample_conv_table_http_fail_cnt(const struct arg *arg_p, struct sample *smp, void *private)
2013{
2014 struct stktable *t;
2015 struct stktable_key *key;
2016 struct stksess *ts;
2017 void *ptr;
2018
2019 t = arg_p[0].data.t;
2020
2021 key = smp_to_stkey(smp, t);
2022 if (!key)
2023 return 0;
2024
2025 ts = stktable_lookup_key(t, key);
2026
2027 smp->flags = SMP_F_VOL_TEST;
2028 smp->data.type = SMP_T_SINT;
2029 smp->data.u.sint = 0;
2030
2031 if (!ts) /* key not present */
2032 return 1;
2033
2034 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_FAIL_CNT);
2035 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002036 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Willy Tarreau826f3ab2021-02-10 12:07:15 +01002037
2038 stktable_release(t, ts);
2039 return !!ptr;
2040}
2041
2042/* Casts sample <smp> to the type of the table specified in arg(0), and looks
2043 * it up into this table. Returns the HTTP response failure rate for the key
2044 * if the key is present in the table, otherwise zero, so that comparisons can
2045 * be easily performed. If the inspected parameter is not stored in the table,
2046 * <not found> is returned.
2047 */
2048static int sample_conv_table_http_fail_rate(const struct arg *arg_p, struct sample *smp, void *private)
2049{
2050 struct stktable *t;
2051 struct stktable_key *key;
2052 struct stksess *ts;
2053 void *ptr;
2054
2055 t = arg_p[0].data.t;
2056
2057 key = smp_to_stkey(smp, t);
2058 if (!key)
2059 return 0;
2060
2061 ts = stktable_lookup_key(t, key);
2062
2063 smp->flags = SMP_F_VOL_TEST;
2064 smp->data.type = SMP_T_SINT;
2065 smp->data.u.sint = 0;
2066
2067 if (!ts) /* key not present */
2068 return 1;
2069
2070 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_FAIL_RATE);
2071 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002072 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Willy Tarreau826f3ab2021-02-10 12:07:15 +01002073 t->data_arg[STKTABLE_DT_HTTP_FAIL_RATE].u);
2074
2075 stktable_release(t, ts);
2076 return !!ptr;
2077}
2078
2079/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002080 * it up into this table. Returns the cumulated number of HTTP request for the
2081 * key if the key is present in the table, otherwise zero, so that comparisons
2082 * can be easily performed. If the inspected parameter is not stored in the
2083 * table, <not found> is returned.
2084 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02002085static int sample_conv_table_http_req_cnt(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002086{
2087 struct stktable *t;
2088 struct stktable_key *key;
2089 struct stksess *ts;
2090 void *ptr;
2091
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002092 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002093
2094 key = smp_to_stkey(smp, t);
2095 if (!key)
2096 return 0;
2097
Willy Tarreauf0c730a2016-05-25 17:07:56 +02002098 ts = stktable_lookup_key(t, key);
2099
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002100 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02002101 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02002102 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002103
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002104 if (!ts) /* key not present */
2105 return 1;
2106
2107 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_REQ_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04002108 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002109 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002110
Daniel Corbett3e60b112018-05-27 09:47:12 -04002111 stktable_release(t, ts);
2112 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002113}
2114
2115/* Casts sample <smp> to the type of the table specified in arg(0), and looks
2116 * it up into this table. Returns the HTTP request rate the key if the key is
2117 * present in the table, otherwise zero, so that comparisons can be easily
2118 * performed. If the inspected parameter is not stored in the table, <not found>
2119 * is returned.
2120 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02002121static int sample_conv_table_http_req_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002122{
2123 struct stktable *t;
2124 struct stktable_key *key;
2125 struct stksess *ts;
2126 void *ptr;
2127
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002128 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002129
2130 key = smp_to_stkey(smp, t);
2131 if (!key)
2132 return 0;
2133
Willy Tarreauf0c730a2016-05-25 17:07:56 +02002134 ts = stktable_lookup_key(t, key);
2135
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002136 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02002137 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02002138 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002139
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002140 if (!ts) /* key not present */
2141 return 1;
2142
2143 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_REQ_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04002144 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002145 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Daniel Corbett3e60b112018-05-27 09:47:12 -04002146 t->data_arg[STKTABLE_DT_HTTP_REQ_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002147
Daniel Corbett3e60b112018-05-27 09:47:12 -04002148 stktable_release(t, ts);
2149 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002150}
2151
2152/* Casts sample <smp> to the type of the table specified in arg(0), and looks
2153 * it up into this table. Returns the volume of datareceived from clients in kbytes
2154 * if the key is present in the table, otherwise zero, so that comparisons can
2155 * be easily performed. If the inspected parameter is not stored in the table,
2156 * <not found> is returned.
2157 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02002158static int sample_conv_table_kbytes_in(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002159{
2160 struct stktable *t;
2161 struct stktable_key *key;
2162 struct stksess *ts;
2163 void *ptr;
2164
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002165 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002166
2167 key = smp_to_stkey(smp, t);
2168 if (!key)
2169 return 0;
2170
Willy Tarreauf0c730a2016-05-25 17:07:56 +02002171 ts = stktable_lookup_key(t, key);
2172
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002173 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02002174 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02002175 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002176
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002177 if (!ts) /* key not present */
2178 return 1;
2179
2180 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_IN_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04002181 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002182 smp->data.u.sint = stktable_data_cast(ptr, std_t_ull) >> 10;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002183
Daniel Corbett3e60b112018-05-27 09:47:12 -04002184 stktable_release(t, ts);
2185 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002186}
2187
2188/* Casts sample <smp> to the type of the table specified in arg(0), and looks
2189 * it up into this table. Returns the volume of data sent to clients in kbytes
2190 * if the key is present in the table, otherwise zero, so that comparisons can
2191 * be easily performed. If the inspected parameter is not stored in the table,
2192 * <not found> is returned.
2193 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02002194static int sample_conv_table_kbytes_out(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002195{
2196 struct stktable *t;
2197 struct stktable_key *key;
2198 struct stksess *ts;
2199 void *ptr;
2200
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002201 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002202
2203 key = smp_to_stkey(smp, t);
2204 if (!key)
2205 return 0;
2206
Willy Tarreauf0c730a2016-05-25 17:07:56 +02002207 ts = stktable_lookup_key(t, key);
2208
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002209 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02002210 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02002211 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002212
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002213 if (!ts) /* key not present */
2214 return 1;
2215
2216 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_OUT_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04002217 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002218 smp->data.u.sint = stktable_data_cast(ptr, std_t_ull) >> 10;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002219
Daniel Corbett3e60b112018-05-27 09:47:12 -04002220 stktable_release(t, ts);
2221 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002222}
2223
2224/* Casts sample <smp> to the type of the table specified in arg(0), and looks
2225 * it up into this table. Returns the server ID associated with the key if the
2226 * key is present in the table, otherwise zero, so that comparisons can be
2227 * easily performed. If the inspected parameter is not stored in the table,
2228 * <not found> is returned.
2229 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02002230static int sample_conv_table_server_id(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002231{
2232 struct stktable *t;
2233 struct stktable_key *key;
2234 struct stksess *ts;
2235 void *ptr;
2236
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002237 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002238
2239 key = smp_to_stkey(smp, t);
2240 if (!key)
2241 return 0;
2242
Willy Tarreauf0c730a2016-05-25 17:07:56 +02002243 ts = stktable_lookup_key(t, key);
2244
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002245 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02002246 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02002247 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002248
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002249 if (!ts) /* key not present */
2250 return 1;
2251
2252 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_SERVER_ID);
Daniel Corbett3e60b112018-05-27 09:47:12 -04002253 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002254 smp->data.u.sint = stktable_data_cast(ptr, std_t_sint);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002255
Daniel Corbett3e60b112018-05-27 09:47:12 -04002256 stktable_release(t, ts);
2257 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002258}
2259
2260/* Casts sample <smp> to the type of the table specified in arg(0), and looks
2261 * it up into this table. Returns the cumulated number of sessions for the
2262 * key if the key is present in the table, otherwise zero, so that comparisons
2263 * can be easily performed. If the inspected parameter is not stored in the
2264 * table, <not found> is returned.
2265 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02002266static int sample_conv_table_sess_cnt(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002267{
2268 struct stktable *t;
2269 struct stktable_key *key;
2270 struct stksess *ts;
2271 void *ptr;
2272
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002273 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002274
2275 key = smp_to_stkey(smp, t);
2276 if (!key)
2277 return 0;
2278
Willy Tarreauf0c730a2016-05-25 17:07:56 +02002279 ts = stktable_lookup_key(t, key);
2280
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002281 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02002282 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02002283 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002284
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002285 if (!ts) /* key not present */
2286 return 1;
2287
2288 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_SESS_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04002289 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002290 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002291
Daniel Corbett3e60b112018-05-27 09:47:12 -04002292 stktable_release(t, ts);
2293 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002294}
2295
2296/* Casts sample <smp> to the type of the table specified in arg(0), and looks
2297 * it up into this table. Returns the session rate the key if the key is
2298 * present in the table, otherwise zero, so that comparisons can be easily
2299 * performed. If the inspected parameter is not stored in the table, <not found>
2300 * is returned.
2301 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02002302static int sample_conv_table_sess_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002303{
2304 struct stktable *t;
2305 struct stktable_key *key;
2306 struct stksess *ts;
2307 void *ptr;
2308
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002309 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002310
2311 key = smp_to_stkey(smp, t);
2312 if (!key)
2313 return 0;
2314
Willy Tarreauf0c730a2016-05-25 17:07:56 +02002315 ts = stktable_lookup_key(t, key);
2316
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002317 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02002318 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02002319 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002320
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002321 if (!ts) /* key not present */
2322 return 1;
2323
2324 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_SESS_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04002325 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002326 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Daniel Corbett3e60b112018-05-27 09:47:12 -04002327 t->data_arg[STKTABLE_DT_SESS_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002328
Daniel Corbett3e60b112018-05-27 09:47:12 -04002329 stktable_release(t, ts);
2330 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002331}
2332
2333/* Casts sample <smp> to the type of the table specified in arg(0), and looks
2334 * it up into this table. Returns the amount of concurrent connections tracking
2335 * the same key if the key is present in the table, otherwise zero, so that
2336 * comparisons can be easily performed. If the inspected parameter is not
2337 * stored in the table, <not found> is returned.
2338 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02002339static int sample_conv_table_trackers(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002340{
2341 struct stktable *t;
2342 struct stktable_key *key;
2343 struct stksess *ts;
2344
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002345 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002346
2347 key = smp_to_stkey(smp, t);
2348 if (!key)
2349 return 0;
2350
Willy Tarreauf0c730a2016-05-25 17:07:56 +02002351 ts = stktable_lookup_key(t, key);
2352
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002353 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02002354 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02002355 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002356
Tim Duesterhus65189c12018-06-26 15:57:29 +02002357 if (!ts)
2358 return 1;
2359
2360 smp->data.u.sint = ts->ref_cnt;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002361
Daniel Corbett3e60b112018-05-27 09:47:12 -04002362 stktable_release(t, ts);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002363 return 1;
2364}
2365
Emeric Brun4d7ada82021-06-30 19:04:16 +02002366/* This function increments the gpc counter at index 'rule->arg.gpc.idx' of the
2367 * array on the tracksc counter of index 'rule->arg.gpc.sc' stored into the
2368 * <stream> or directly in the session <sess> if <stream> is set to NULL
2369 *
2370 * This function always returns ACT_RET_CONT and parameter flags is unused.
2371 */
2372static enum act_return action_inc_gpc(struct act_rule *rule, struct proxy *px,
2373 struct session *sess, struct stream *s, int flags)
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002374{
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002375 struct stksess *ts;
2376 struct stkctr *stkctr;
2377
2378 /* Extract the stksess, return OK if no stksess available. */
2379 if (s)
2380 stkctr = &s->stkctr[rule->arg.gpc.sc];
2381 else
2382 stkctr = &sess->stkctr[rule->arg.gpc.sc];
Willy Tarreau79c1e912016-01-25 14:54:45 +01002383
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002384 ts = stkctr_entry(stkctr);
Willy Tarreau79c1e912016-01-25 14:54:45 +01002385 if (ts) {
2386 void *ptr1, *ptr2;
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002387
Emeric Brun4d7ada82021-06-30 19:04:16 +02002388 /* First, update gpc_rate if it's tracked. Second, update its gpc if tracked. */
2389 ptr1 = stktable_data_ptr_idx(stkctr->table, ts, STKTABLE_DT_GPC_RATE, rule->arg.gpc.idx);
2390 ptr2 = stktable_data_ptr_idx(stkctr->table, ts, STKTABLE_DT_GPC, rule->arg.gpc.idx);
2391
Emeric Brun819fc6f2017-06-13 19:37:32 +02002392 if (ptr1 || ptr2) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002393 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002394
2395 if (ptr1)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002396 update_freq_ctr_period(&stktable_data_cast(ptr1, std_t_frqp),
Emeric Brun4d7ada82021-06-30 19:04:16 +02002397 stkctr->table->data_arg[STKTABLE_DT_GPC_RATE].u, 1);
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002398
Emeric Brun819fc6f2017-06-13 19:37:32 +02002399 if (ptr2)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002400 stktable_data_cast(ptr2, std_t_uint)++;
Willy Tarreau79c1e912016-01-25 14:54:45 +01002401
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002402 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002403
2404 /* If data was modified, we need to touch to re-schedule sync */
2405 stktable_touch_local(stkctr->table, ts, 0);
2406 }
Willy Tarreau79c1e912016-01-25 14:54:45 +01002407 }
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002408 return ACT_RET_CONT;
2409}
2410
Emeric Brun4d7ada82021-06-30 19:04:16 +02002411/* Same as action_inc_gpc() but for gpc0 only */
2412static enum act_return action_inc_gpc0(struct act_rule *rule, struct proxy *px,
2413 struct session *sess, struct stream *s, int flags)
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002414{
Emeric Brun4d7ada82021-06-30 19:04:16 +02002415 struct stksess *ts;
2416 struct stkctr *stkctr;
Willy Tarreau5b654ad2021-07-06 18:51:12 +02002417 unsigned int period = 0;
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002418
Emeric Brun4d7ada82021-06-30 19:04:16 +02002419 /* Extract the stksess, return OK if no stksess available. */
2420 if (s)
2421 stkctr = &s->stkctr[rule->arg.gpc.sc];
2422 else
2423 stkctr = &sess->stkctr[rule->arg.gpc.sc];
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002424
Emeric Brun4d7ada82021-06-30 19:04:16 +02002425 ts = stkctr_entry(stkctr);
2426 if (ts) {
2427 void *ptr1, *ptr2;
2428
2429 /* First, update gpc0_rate if it's tracked. Second, update its gpc0 if tracked. */
2430 ptr1 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC0_RATE);
Emeric Brun726783d2021-06-30 19:06:43 +02002431 if (ptr1) {
2432 period = stkctr->table->data_arg[STKTABLE_DT_GPC0_RATE].u;
2433 }
2434 else {
2435 /* fallback on the gpc array */
2436 ptr1 = stktable_data_ptr_idx(stkctr->table, ts, STKTABLE_DT_GPC_RATE, 0);
2437 if (ptr1)
2438 period = stkctr->table->data_arg[STKTABLE_DT_GPC_RATE].u;
2439 }
2440
Emeric Brun4d7ada82021-06-30 19:04:16 +02002441 ptr2 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC0);
Emeric Brun726783d2021-06-30 19:06:43 +02002442 if (!ptr2) {
2443 /* fallback on the gpc array */
2444 ptr2 = stktable_data_ptr_idx(stkctr->table, ts, STKTABLE_DT_GPC, 0);
2445 }
2446
Emeric Brun4d7ada82021-06-30 19:04:16 +02002447 if (ptr1 || ptr2) {
2448 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
2449
2450 if (ptr1)
2451 update_freq_ctr_period(&stktable_data_cast(ptr1, std_t_frqp),
Emeric Brun726783d2021-06-30 19:06:43 +02002452 period, 1);
Emeric Brun4d7ada82021-06-30 19:04:16 +02002453
2454 if (ptr2)
2455 stktable_data_cast(ptr2, std_t_uint)++;
2456
2457 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
2458
2459 /* If data was modified, we need to touch to re-schedule sync */
2460 stktable_touch_local(stkctr->table, ts, 0);
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002461 }
2462 }
Emeric Brun4d7ada82021-06-30 19:04:16 +02002463 return ACT_RET_CONT;
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002464}
2465
Emeric Brun4d7ada82021-06-30 19:04:16 +02002466/* Same as action_inc_gpc() but for gpc1 only */
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002467static enum act_return action_inc_gpc1(struct act_rule *rule, struct proxy *px,
2468 struct session *sess, struct stream *s, int flags)
2469{
2470 struct stksess *ts;
2471 struct stkctr *stkctr;
Willy Tarreau5b654ad2021-07-06 18:51:12 +02002472 unsigned int period = 0;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002473
2474 /* Extract the stksess, return OK if no stksess available. */
2475 if (s)
2476 stkctr = &s->stkctr[rule->arg.gpc.sc];
2477 else
2478 stkctr = &sess->stkctr[rule->arg.gpc.sc];
2479
2480 ts = stkctr_entry(stkctr);
2481 if (ts) {
2482 void *ptr1, *ptr2;
2483
2484 /* First, update gpc1_rate if it's tracked. Second, update its gpc1 if tracked. */
2485 ptr1 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC1_RATE);
Emeric Brun726783d2021-06-30 19:06:43 +02002486 if (ptr1) {
2487 period = stkctr->table->data_arg[STKTABLE_DT_GPC1_RATE].u;
2488 }
2489 else {
2490 /* fallback on the gpc array */
2491 ptr1 = stktable_data_ptr_idx(stkctr->table, ts, STKTABLE_DT_GPC_RATE, 1);
2492 if (ptr1)
2493 period = stkctr->table->data_arg[STKTABLE_DT_GPC_RATE].u;
2494 }
2495
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002496 ptr2 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC1);
Emeric Brun726783d2021-06-30 19:06:43 +02002497 if (!ptr2) {
2498 /* fallback on the gpc array */
2499 ptr2 = stktable_data_ptr_idx(stkctr->table, ts, STKTABLE_DT_GPC, 1);
2500 }
2501
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002502 if (ptr1 || ptr2) {
2503 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
2504
2505 if (ptr1)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002506 update_freq_ctr_period(&stktable_data_cast(ptr1, std_t_frqp),
Emeric Brun726783d2021-06-30 19:06:43 +02002507 period, 1);
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002508
2509 if (ptr2)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002510 stktable_data_cast(ptr2, std_t_uint)++;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002511
2512 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
2513
2514 /* If data was modified, we need to touch to re-schedule sync */
2515 stktable_touch_local(stkctr->table, ts, 0);
2516 }
2517 }
2518 return ACT_RET_CONT;
2519}
2520
Emeric Brun4d7ada82021-06-30 19:04:16 +02002521/* This function is a common parser for actions incrementing the GPC
2522 * (General Purpose Counters). It understands the formats:
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002523 *
Emeric Brun4d7ada82021-06-30 19:04:16 +02002524 * sc-inc-gpc(<gpc IDX>,<track ID>)
2525 * sc-inc-gpc0([<track ID>])
2526 * sc-inc-gpc1([<track ID>])
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002527 *
Emeric Brun4d7ada82021-06-30 19:04:16 +02002528 * It returns ACT_RET_PRS_ERR if fails and <err> is filled with an error
2529 * message. Otherwise it returns ACT_RET_PRS_OK.
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002530 */
Emeric Brun4d7ada82021-06-30 19:04:16 +02002531static enum act_parse_ret parse_inc_gpc(const char **args, int *arg, struct proxy *px,
2532 struct act_rule *rule, char **err)
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002533{
2534 const char *cmd_name = args[*arg-1];
2535 char *error;
2536
Emeric Brun4d7ada82021-06-30 19:04:16 +02002537 cmd_name += strlen("sc-inc-gpc");
2538 if (*cmd_name == '(') {
2539 cmd_name++; /* skip the '(' */
2540 rule->arg.gpc.idx = strtoul(cmd_name, &error, 10); /* Convert stick table id. */
2541 if (*error != ',') {
2542 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 +01002543 return ACT_RET_PRS_ERR;
2544 }
Emeric Brun4d7ada82021-06-30 19:04:16 +02002545 else {
2546 cmd_name = error + 1; /* skip the ',' */
2547 rule->arg.gpc.sc = strtol(cmd_name, &error, 10); /* Convert stick table id. */
2548 if (*error != ')') {
2549 memprintf(err, "invalid stick table track ID '%s'. Expects sc-inc-gpc(<GPC ID>,<Track ID>)", args[*arg-1]);
2550 return ACT_RET_PRS_ERR;
2551 }
2552
2553 if (rule->arg.gpc.sc >= MAX_SESS_STKCTR) {
2554 memprintf(err, "invalid stick table track ID '%s'. The max allowed ID is %d",
2555 args[*arg-1], MAX_SESS_STKCTR-1);
2556 return ACT_RET_PRS_ERR;
2557 }
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002558 }
Emeric Brun4d7ada82021-06-30 19:04:16 +02002559 rule->action_ptr = action_inc_gpc;
2560 }
2561 else if (*cmd_name == '0' ||*cmd_name == '1') {
2562 char c = *cmd_name;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002563
Emeric Brun4d7ada82021-06-30 19:04:16 +02002564 cmd_name++;
2565 if (*cmd_name == '\0') {
2566 /* default stick table id. */
2567 rule->arg.gpc.sc = 0;
2568 } else {
2569 /* parse the stick table id. */
2570 if (*cmd_name != '(') {
2571 memprintf(err, "invalid stick table track ID. Expects %s(<Track ID>)", args[*arg-1]);
2572 return ACT_RET_PRS_ERR;
2573 }
2574 cmd_name++; /* jump the '(' */
2575 rule->arg.gpc.sc = strtol(cmd_name, &error, 10); /* Convert stick table id. */
2576 if (*error != ')') {
2577 memprintf(err, "invalid stick table track ID. Expects %s(<Track ID>)", args[*arg-1]);
2578 return ACT_RET_PRS_ERR;
2579 }
2580
2581 if (rule->arg.gpc.sc >= MAX_SESS_STKCTR) {
2582 memprintf(err, "invalid stick table track ID. The max allowed ID is %d",
2583 MAX_SESS_STKCTR-1);
2584 return ACT_RET_PRS_ERR;
2585 }
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002586 }
Emeric Brun4d7ada82021-06-30 19:04:16 +02002587 if (c == '1')
2588 rule->action_ptr = action_inc_gpc1;
2589 else
2590 rule->action_ptr = action_inc_gpc0;
2591 }
2592 else {
2593 /* default stick table id. */
2594 memprintf(err, "invalid gpc ID '%s'. Expects sc-set-gpc(<GPC ID>,<Track ID>)", args[*arg-1]);
2595 return ACT_RET_PRS_ERR;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002596 }
2597 rule->action = ACT_CUSTOM;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002598 return ACT_RET_PRS_OK;
2599}
2600
Emeric Brun877b0b52021-06-30 18:57:49 +02002601/* This function sets the gpt at index 'rule->arg.gpt.idx' of the array on the
2602 * tracksc counter of index 'rule->arg.gpt.sc' stored into the <stream> or
2603 * directly in the session <sess> if <stream> is set to NULL. This gpt is
2604 * set to the value computed by the expression 'rule->arg.gpt.expr' or if
2605 * 'rule->arg.gpt.expr' is null directly to the value of 'rule->arg.gpt.value'.
2606 *
2607 * This function always returns ACT_RET_CONT and parameter flags is unused.
2608 */
2609static enum act_return action_set_gpt(struct act_rule *rule, struct proxy *px,
2610 struct session *sess, struct stream *s, int flags)
2611{
2612 void *ptr;
2613 struct stksess *ts;
2614 struct stkctr *stkctr;
2615 unsigned int value = 0;
2616 struct sample *smp;
2617 int smp_opt_dir;
2618
2619 /* Extract the stksess, return OK if no stksess available. */
2620 if (s)
2621 stkctr = &s->stkctr[rule->arg.gpt.sc];
2622 else
2623 stkctr = &sess->stkctr[rule->arg.gpt.sc];
2624
2625 ts = stkctr_entry(stkctr);
2626 if (!ts)
2627 return ACT_RET_CONT;
2628
2629 /* Store the sample in the required sc, and ignore errors. */
2630 ptr = stktable_data_ptr_idx(stkctr->table, ts, STKTABLE_DT_GPT, rule->arg.gpt.idx);
2631 if (ptr) {
2632
2633 if (!rule->arg.gpt.expr)
2634 value = (unsigned int)(rule->arg.gpt.value);
2635 else {
2636 switch (rule->from) {
2637 case ACT_F_TCP_REQ_SES: smp_opt_dir = SMP_OPT_DIR_REQ; break;
2638 case ACT_F_TCP_REQ_CNT: smp_opt_dir = SMP_OPT_DIR_REQ; break;
2639 case ACT_F_TCP_RES_CNT: smp_opt_dir = SMP_OPT_DIR_RES; break;
2640 case ACT_F_HTTP_REQ: smp_opt_dir = SMP_OPT_DIR_REQ; break;
2641 case ACT_F_HTTP_RES: smp_opt_dir = SMP_OPT_DIR_RES; break;
2642 default:
2643 send_log(px, LOG_ERR, "stick table: internal error while setting gpt%u.", rule->arg.gpt.idx);
2644 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))
2645 ha_alert("stick table: internal error while executing setting gpt%u.\n", rule->arg.gpt.idx);
2646 return ACT_RET_CONT;
2647 }
2648
2649 /* Fetch and cast the expression. */
2650 smp = sample_fetch_as_type(px, sess, s, smp_opt_dir|SMP_OPT_FINAL, rule->arg.gpt.expr, SMP_T_SINT);
2651 if (!smp) {
2652 send_log(px, LOG_WARNING, "stick table: invalid expression or data type while setting gpt%u.", rule->arg.gpt.idx);
2653 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))
2654 ha_alert("stick table: invalid expression or data type while setting gpt%u.\n", rule->arg.gpt.idx);
2655 return ACT_RET_CONT;
2656 }
2657 value = (unsigned int)(smp->data.u.sint);
2658 }
2659
2660 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
2661
2662 stktable_data_cast(ptr, std_t_uint) = value;
2663
2664 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
2665
2666 stktable_touch_local(stkctr->table, ts, 0);
2667 }
2668
2669 return ACT_RET_CONT;
2670}
2671
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002672/* Always returns 1. */
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002673static enum act_return action_set_gpt0(struct act_rule *rule, struct proxy *px,
Willy Tarreau658b85b2015-09-27 10:00:49 +02002674 struct session *sess, struct stream *s, int flags)
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002675{
2676 void *ptr;
2677 struct stksess *ts;
2678 struct stkctr *stkctr;
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002679 unsigned int value = 0;
2680 struct sample *smp;
2681 int smp_opt_dir;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002682
2683 /* Extract the stksess, return OK if no stksess available. */
2684 if (s)
2685 stkctr = &s->stkctr[rule->arg.gpt.sc];
2686 else
2687 stkctr = &sess->stkctr[rule->arg.gpt.sc];
Willy Tarreau79c1e912016-01-25 14:54:45 +01002688
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002689 ts = stkctr_entry(stkctr);
2690 if (!ts)
2691 return ACT_RET_CONT;
2692
2693 /* Store the sample in the required sc, and ignore errors. */
2694 ptr = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPT0);
Emeric Brunf7ab0bf2021-06-30 18:58:22 +02002695 if (!ptr)
2696 ptr = stktable_data_ptr_idx(stkctr->table, ts, STKTABLE_DT_GPT, 0);
2697
Willy Tarreau79c1e912016-01-25 14:54:45 +01002698 if (ptr) {
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002699 if (!rule->arg.gpt.expr)
2700 value = (unsigned int)(rule->arg.gpt.value);
2701 else {
2702 switch (rule->from) {
2703 case ACT_F_TCP_REQ_SES: smp_opt_dir = SMP_OPT_DIR_REQ; break;
2704 case ACT_F_TCP_REQ_CNT: smp_opt_dir = SMP_OPT_DIR_REQ; break;
2705 case ACT_F_TCP_RES_CNT: smp_opt_dir = SMP_OPT_DIR_RES; break;
2706 case ACT_F_HTTP_REQ: smp_opt_dir = SMP_OPT_DIR_REQ; break;
2707 case ACT_F_HTTP_RES: smp_opt_dir = SMP_OPT_DIR_RES; break;
2708 default:
2709 send_log(px, LOG_ERR, "stick table: internal error while setting gpt0.");
2710 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))
2711 ha_alert("stick table: internal error while executing setting gpt0.\n");
2712 return ACT_RET_CONT;
2713 }
2714
2715 /* Fetch and cast the expression. */
2716 smp = sample_fetch_as_type(px, sess, s, smp_opt_dir|SMP_OPT_FINAL, rule->arg.gpt.expr, SMP_T_SINT);
2717 if (!smp) {
2718 send_log(px, LOG_WARNING, "stick table: invalid expression or data type while setting gpt0.");
2719 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))
2720 ha_alert("stick table: invalid expression or data type while setting gpt0.\n");
2721 return ACT_RET_CONT;
2722 }
2723 value = (unsigned int)(smp->data.u.sint);
2724 }
2725
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002726 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002727
Emeric Brun0e3457b2021-06-30 17:18:28 +02002728 stktable_data_cast(ptr, std_t_uint) = value;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002729
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002730 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002731
2732 stktable_touch_local(stkctr->table, ts, 0);
Willy Tarreau79c1e912016-01-25 14:54:45 +01002733 }
2734
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002735 return ACT_RET_CONT;
2736}
2737
Emeric Brun877b0b52021-06-30 18:57:49 +02002738/* This function is a parser for the "sc-set-gpt" and "sc-set-gpt0" actions.
2739 * It understands the formats:
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002740 *
Emeric Brun877b0b52021-06-30 18:57:49 +02002741 * sc-set-gpt(<gpt IDX>,<track ID>) <expression>
2742 * sc-set-gpt0(<track ID>) <expression>
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002743 *
Emeric Brun877b0b52021-06-30 18:57:49 +02002744 * It returns ACT_RET_PRS_ERR if fails and <err> is filled with an error message.
2745 * Otherwise, it returns ACT_RET_PRS_OK and the variable 'rule->arg.gpt.expr'
2746 * is filled with the pointer to the expression to execute or NULL if the arg
2747 * is directly an integer stored into 'rule->arg.gpt.value'.
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002748 */
Emeric Brun877b0b52021-06-30 18:57:49 +02002749static enum act_parse_ret parse_set_gpt(const char **args, int *arg, struct proxy *px,
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002750 struct act_rule *rule, char **err)
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002751{
2752 const char *cmd_name = args[*arg-1];
2753 char *error;
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002754 int smp_val;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002755
Emeric Brun877b0b52021-06-30 18:57:49 +02002756 cmd_name += strlen("sc-set-gpt");
2757 if (*cmd_name == '(') {
2758 cmd_name++; /* skip the '(' */
2759 rule->arg.gpt.idx = strtoul(cmd_name, &error, 10); /* Convert stick table id. */
2760 if (*error != ',') {
2761 memprintf(err, "Missing gpt ID '%s'. Expects sc-set-gpt(<GPT ID>,<Track ID>)", args[*arg-1]);
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002762 return ACT_RET_PRS_ERR;
2763 }
Emeric Brun877b0b52021-06-30 18:57:49 +02002764 else {
2765 cmd_name = error + 1; /* skip the ',' */
2766 rule->arg.gpt.sc = strtol(cmd_name, &error, 10); /* Convert stick table id. */
2767 if (*error != ')') {
2768 memprintf(err, "invalid stick table track ID '%s'. Expects sc-set-gpt(<GPT ID>,<Track ID>)", args[*arg-1]);
2769 return ACT_RET_PRS_ERR;
2770 }
2771
2772 if (rule->arg.gpt.sc >= MAX_SESS_STKCTR) {
2773 memprintf(err, "invalid stick table track ID '%s'. The max allowed ID is %d",
2774 args[*arg-1], MAX_SESS_STKCTR-1);
2775 return ACT_RET_PRS_ERR;
2776 }
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002777 }
Emeric Brun877b0b52021-06-30 18:57:49 +02002778 rule->action_ptr = action_set_gpt;
2779 }
2780 else if (*cmd_name == '0') {
2781 cmd_name++;
2782 if (*cmd_name == '\0') {
2783 /* default stick table id. */
2784 rule->arg.gpt.sc = 0;
2785 } else {
2786 /* parse the stick table id. */
2787 if (*cmd_name != '(') {
2788 memprintf(err, "invalid stick table track ID '%s'. Expects sc-set-gpt0(<Track ID>)", args[*arg-1]);
2789 return ACT_RET_PRS_ERR;
2790 }
2791 cmd_name++; /* jump the '(' */
2792 rule->arg.gpt.sc = strtol(cmd_name, &error, 10); /* Convert stick table id. */
2793 if (*error != ')') {
2794 memprintf(err, "invalid stick table track ID '%s'. Expects sc-set-gpt0(<Track ID>)", args[*arg-1]);
2795 return ACT_RET_PRS_ERR;
2796 }
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002797
Emeric Brun877b0b52021-06-30 18:57:49 +02002798 if (rule->arg.gpt.sc >= MAX_SESS_STKCTR) {
2799 memprintf(err, "invalid stick table track ID '%s'. The max allowed ID is %d",
2800 args[*arg-1], MAX_SESS_STKCTR-1);
2801 return ACT_RET_PRS_ERR;
2802 }
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002803 }
Emeric Brun877b0b52021-06-30 18:57:49 +02002804 rule->action_ptr = action_set_gpt0;
2805 }
2806 else {
2807 /* default stick table id. */
2808 memprintf(err, "invalid gpt ID '%s'. Expects sc-set-gpt(<GPT ID>,<Track ID>)", args[*arg-1]);
2809 return ACT_RET_PRS_ERR;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002810 }
2811
Willy Tarreauece4c4a2021-08-24 14:57:28 +02002812 /* value may be either an integer or an expression */
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002813 rule->arg.gpt.expr = NULL;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002814 rule->arg.gpt.value = strtol(args[*arg], &error, 10);
Willy Tarreauece4c4a2021-08-24 14:57:28 +02002815 if (*error == '\0') {
2816 /* valid integer, skip it */
2817 (*arg)++;
2818 } else {
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002819 rule->arg.gpt.expr = sample_parse_expr((char **)args, arg, px->conf.args.file,
Willy Tarreaue3b57bf2020-02-14 16:50:14 +01002820 px->conf.args.line, err, &px->conf.args, NULL);
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002821 if (!rule->arg.gpt.expr)
2822 return ACT_RET_PRS_ERR;
2823
2824 switch (rule->from) {
2825 case ACT_F_TCP_REQ_SES: smp_val = SMP_VAL_FE_SES_ACC; break;
2826 case ACT_F_TCP_REQ_CNT: smp_val = SMP_VAL_FE_REQ_CNT; break;
2827 case ACT_F_TCP_RES_CNT: smp_val = SMP_VAL_BE_RES_CNT; break;
2828 case ACT_F_HTTP_REQ: smp_val = SMP_VAL_FE_HRQ_HDR; break;
2829 case ACT_F_HTTP_RES: smp_val = SMP_VAL_BE_HRS_HDR; break;
2830 default:
2831 memprintf(err, "internal error, unexpected rule->from=%d, please report this bug!", rule->from);
2832 return ACT_RET_PRS_ERR;
2833 }
2834 if (!(rule->arg.gpt.expr->fetch->val & smp_val)) {
2835 memprintf(err, "fetch method '%s' extracts information from '%s', none of which is available here", args[*arg-1],
2836 sample_src_names(rule->arg.gpt.expr->fetch->use));
2837 free(rule->arg.gpt.expr);
2838 return ACT_RET_PRS_ERR;
2839 }
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002840 }
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002841
Thierry FOURNIER42148732015-09-02 17:17:33 +02002842 rule->action = ACT_CUSTOM;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002843
2844 return ACT_RET_PRS_OK;
2845}
2846
Willy Tarreau7d562212016-11-25 16:10:05 +01002847/* set temp integer to the number of used entries in the table pointed to by expr.
2848 * Accepts exactly 1 argument of type table.
2849 */
2850static int
2851smp_fetch_table_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
2852{
2853 smp->flags = SMP_F_VOL_TEST;
2854 smp->data.type = SMP_T_SINT;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002855 smp->data.u.sint = args->data.t->current;
Willy Tarreau7d562212016-11-25 16:10:05 +01002856 return 1;
2857}
2858
2859/* set temp integer to the number of free entries in the table pointed to by expr.
2860 * Accepts exactly 1 argument of type table.
2861 */
2862static int
2863smp_fetch_table_avl(const struct arg *args, struct sample *smp, const char *kw, void *private)
2864{
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002865 struct stktable *t;
Willy Tarreau7d562212016-11-25 16:10:05 +01002866
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002867 t = args->data.t;
Willy Tarreau7d562212016-11-25 16:10:05 +01002868 smp->flags = SMP_F_VOL_TEST;
2869 smp->data.type = SMP_T_SINT;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002870 smp->data.u.sint = t->size - t->current;
Willy Tarreau7d562212016-11-25 16:10:05 +01002871 return 1;
2872}
2873
2874/* Returns a pointer to a stkctr depending on the fetch keyword name.
2875 * It is designed to be called as sc[0-9]_* sc_* or src_* exclusively.
2876 * sc[0-9]_* will return a pointer to the respective field in the
2877 * stream <l4>. sc_* requires an UINT argument specifying the stick
2878 * counter number. src_* will fill a locally allocated structure with
2879 * the table and entry corresponding to what is specified with src_*.
2880 * NULL may be returned if the designated stkctr is not tracked. For
2881 * the sc_* and sc[0-9]_* forms, an optional table argument may be
2882 * passed. When present, the currently tracked key is then looked up
2883 * in the specified table instead of the current table. The purpose is
Ilya Shipitsin47d17182020-06-21 21:42:57 +05002884 * to be able to convert multiple values per key (eg: have gpc0 from
Willy Tarreau7d562212016-11-25 16:10:05 +01002885 * multiple tables). <strm> is allowed to be NULL, in which case only
2886 * the session will be consulted.
2887 */
2888struct stkctr *
Emeric Brun819fc6f2017-06-13 19:37:32 +02002889smp_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 +01002890{
Willy Tarreau7d562212016-11-25 16:10:05 +01002891 struct stkctr *stkptr;
2892 struct stksess *stksess;
2893 unsigned int num = kw[2] - '0';
2894 int arg = 0;
2895
2896 if (num == '_' - '0') {
2897 /* sc_* variant, args[0] = ctr# (mandatory) */
2898 num = args[arg++].data.sint;
Willy Tarreau7d562212016-11-25 16:10:05 +01002899 }
2900 else if (num > 9) { /* src_* variant, args[0] = table */
2901 struct stktable_key *key;
2902 struct connection *conn = objt_conn(sess->origin);
2903 struct sample smp;
2904
2905 if (!conn)
2906 return NULL;
2907
Joseph Herlant5662fa42018-11-15 13:43:28 -08002908 /* Fetch source address in a sample. */
Willy Tarreau7d562212016-11-25 16:10:05 +01002909 smp.px = NULL;
2910 smp.sess = sess;
2911 smp.strm = strm;
Amaury Denoyellec460c702021-05-12 10:17:47 +02002912 if (!smp_fetch_src || !smp_fetch_src(empty_arg_list, &smp, "src", NULL))
Willy Tarreau7d562212016-11-25 16:10:05 +01002913 return NULL;
2914
2915 /* Converts into key. */
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002916 key = smp_to_stkey(&smp, args->data.t);
Willy Tarreau7d562212016-11-25 16:10:05 +01002917 if (!key)
2918 return NULL;
2919
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002920 stkctr->table = args->data.t;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002921 stkctr_set_entry(stkctr, stktable_lookup_key(stkctr->table, key));
2922 return stkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002923 }
2924
2925 /* Here, <num> contains the counter number from 0 to 9 for
2926 * the sc[0-9]_ form, or even higher using sc_(num) if needed.
2927 * args[arg] is the first optional argument. We first lookup the
2928 * ctr form the stream, then from the session if it was not there.
Christopher Fauleta9fa88a2019-10-21 10:53:34 +02002929 * But we must be sure the counter does not exceed MAX_SESS_STKCTR.
Willy Tarreau7d562212016-11-25 16:10:05 +01002930 */
Christopher Fauleta9fa88a2019-10-21 10:53:34 +02002931 if (num >= MAX_SESS_STKCTR)
2932 return NULL;
Willy Tarreau7d562212016-11-25 16:10:05 +01002933
2934 if (strm)
2935 stkptr = &strm->stkctr[num];
2936 if (!strm || !stkctr_entry(stkptr)) {
2937 stkptr = &sess->stkctr[num];
2938 if (!stkctr_entry(stkptr))
2939 return NULL;
2940 }
2941
2942 stksess = stkctr_entry(stkptr);
2943 if (!stksess)
2944 return NULL;
2945
2946 if (unlikely(args[arg].type == ARGT_TAB)) {
2947 /* an alternate table was specified, let's look up the same key there */
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002948 stkctr->table = args[arg].data.t;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002949 stkctr_set_entry(stkctr, stktable_lookup(stkctr->table, stksess));
2950 return stkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002951 }
2952 return stkptr;
2953}
2954
2955/* same as smp_fetch_sc_stkctr() but dedicated to src_* and can create
2956 * the entry if it doesn't exist yet. This is needed for a few fetch
2957 * functions which need to create an entry, such as src_inc_gpc* and
2958 * src_clr_gpc*.
2959 */
2960struct stkctr *
Emeric Brun819fc6f2017-06-13 19:37:32 +02002961smp_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 +01002962{
Willy Tarreau7d562212016-11-25 16:10:05 +01002963 struct stktable_key *key;
2964 struct connection *conn = objt_conn(sess->origin);
2965 struct sample smp;
2966
2967 if (strncmp(kw, "src_", 4) != 0)
2968 return NULL;
2969
2970 if (!conn)
2971 return NULL;
2972
Joseph Herlant5662fa42018-11-15 13:43:28 -08002973 /* Fetch source address in a sample. */
Willy Tarreau7d562212016-11-25 16:10:05 +01002974 smp.px = NULL;
2975 smp.sess = sess;
2976 smp.strm = strm;
Amaury Denoyellec460c702021-05-12 10:17:47 +02002977 if (!smp_fetch_src || !smp_fetch_src(empty_arg_list, &smp, "src", NULL))
Willy Tarreau7d562212016-11-25 16:10:05 +01002978 return NULL;
2979
2980 /* Converts into key. */
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002981 key = smp_to_stkey(&smp, args->data.t);
Willy Tarreau7d562212016-11-25 16:10:05 +01002982 if (!key)
2983 return NULL;
2984
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002985 stkctr->table = args->data.t;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002986 stkctr_set_entry(stkctr, stktable_get_entry(stkctr->table, key));
2987 return stkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002988}
2989
2990/* set return a boolean indicating if the requested stream counter is
2991 * currently being tracked or not.
2992 * Supports being called as "sc[0-9]_tracked" only.
2993 */
2994static int
2995smp_fetch_sc_tracked(const struct arg *args, struct sample *smp, const char *kw, void *private)
2996{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002997 struct stkctr tmpstkctr;
2998 struct stkctr *stkctr;
2999
Willy Tarreau7d562212016-11-25 16:10:05 +01003000 smp->flags = SMP_F_VOL_TEST;
3001 smp->data.type = SMP_T_BOOL;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003002 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
3003 smp->data.u.sint = !!stkctr;
3004
3005 /* release the ref count */
Dirkjan Bussinkff57f1b2018-09-14 14:31:22 +02003006 if (stkctr == &tmpstkctr)
Emeric Brun819fc6f2017-06-13 19:37:32 +02003007 stktable_release(stkctr->table, stkctr_entry(stkctr));
3008
Emeric Brun877b0b52021-06-30 18:57:49 +02003009 return 1;
3010}
3011
3012/* set <smp> to the General Purpose Tag of index set as first arg
3013 * to value from the stream's tracked frontend counters or from the src.
3014 * Supports being called as "sc_get_gpt(<gpt-idx>,<sc-idx>[,<table>])" or
3015 * "src_get_gpt(<gpt-idx>[,<table>])" only. Value zero is returned if
3016 * the key is new or gpt is not stored.
3017 */
3018static int
3019smp_fetch_sc_get_gpt(const struct arg *args, struct sample *smp, const char *kw, void *private)
3020{
3021 struct stkctr tmpstkctr;
3022 struct stkctr *stkctr;
3023 unsigned int idx;
3024
3025 idx = args[0].data.sint;
3026
3027 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args + 1, kw, &tmpstkctr);
3028 if (!stkctr)
3029 return 0;
3030
3031 smp->flags = SMP_F_VOL_TEST;
3032 smp->data.type = SMP_T_SINT;
3033 smp->data.u.sint = 0;
3034
3035 if (stkctr_entry(stkctr)) {
3036 void *ptr;
3037
3038 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPT, idx);
3039 if (!ptr) {
3040 if (stkctr == &tmpstkctr)
3041 stktable_release(stkctr->table, stkctr_entry(stkctr));
3042 return 0; /* parameter not stored */
3043 }
3044
3045 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3046
3047 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
3048
3049 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3050
3051 if (stkctr == &tmpstkctr)
3052 stktable_release(stkctr->table, stkctr_entry(stkctr));
3053 }
Willy Tarreau7d562212016-11-25 16:10:05 +01003054 return 1;
3055}
3056
3057/* set <smp> to the General Purpose Flag 0 value from the stream's tracked
3058 * frontend counters or from the src.
3059 * Supports being called as "sc[0-9]_get_gpc0" or "src_get_gpt0" only. Value
3060 * zero is returned if the key is new.
3061 */
3062static int
3063smp_fetch_sc_get_gpt0(const struct arg *args, struct sample *smp, const char *kw, void *private)
3064{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003065 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003066 struct stkctr *stkctr;
3067
Emeric Brun819fc6f2017-06-13 19:37:32 +02003068 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003069 if (!stkctr)
3070 return 0;
3071
3072 smp->flags = SMP_F_VOL_TEST;
3073 smp->data.type = SMP_T_SINT;
3074 smp->data.u.sint = 0;
3075
Emeric Brun819fc6f2017-06-13 19:37:32 +02003076 if (stkctr_entry(stkctr)) {
3077 void *ptr;
3078
3079 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPT0);
Emeric Brunf7ab0bf2021-06-30 18:58:22 +02003080 if (!ptr)
3081 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPT, 0);
3082
Emeric Brun4d7ada82021-06-30 19:04:16 +02003083 if (!ptr) {
3084 if (stkctr == &tmpstkctr)
3085 stktable_release(stkctr->table, stkctr_entry(stkctr));
3086 return 0; /* parameter not stored */
3087 }
3088
3089 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3090
3091 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
3092
3093 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3094
3095 if (stkctr == &tmpstkctr)
3096 stktable_release(stkctr->table, stkctr_entry(stkctr));
3097 }
3098 return 1;
3099}
3100
3101/* set <smp> to the GPC[args(0)]'s value from the stream's tracked
3102 * frontend counters or from the src.
3103 * Supports being called as "sc_get_gpc(<gpc-idx>,<sc-idx>[,<table>])" or
3104 * "src_get_gpc(<gpc-idx>[,<table>])" only. Value
3105 * Value zero is returned if the key is new or gpc is not stored.
3106 */
3107static int
3108smp_fetch_sc_get_gpc(const struct arg *args, struct sample *smp, const char *kw, void *private)
3109{
3110 struct stkctr tmpstkctr;
3111 struct stkctr *stkctr;
3112 unsigned int idx;
3113
3114 idx = args[0].data.sint;
3115
3116 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args + 1, kw, &tmpstkctr);
3117 if (!stkctr)
3118 return 0;
3119
3120 smp->flags = SMP_F_VOL_TEST;
3121 smp->data.type = SMP_T_SINT;
3122 smp->data.u.sint = 0;
3123
3124 if (stkctr_entry(stkctr) != NULL) {
3125 void *ptr;
3126
3127 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC, idx);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003128 if (!ptr) {
3129 if (stkctr == &tmpstkctr)
3130 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003131 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003132 }
3133
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003134 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003135
Emeric Brun0e3457b2021-06-30 17:18:28 +02003136 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003137
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003138 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003139
3140 if (stkctr == &tmpstkctr)
3141 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003142 }
3143 return 1;
3144}
3145
3146/* set <smp> to the General Purpose Counter 0 value from the stream's tracked
3147 * frontend counters or from the src.
3148 * Supports being called as "sc[0-9]_get_gpc0" or "src_get_gpc0" only. Value
3149 * zero is returned if the key is new.
3150 */
3151static int
3152smp_fetch_sc_get_gpc0(const struct arg *args, struct sample *smp, const char *kw, void *private)
3153{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003154 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003155 struct stkctr *stkctr;
3156
Emeric Brun819fc6f2017-06-13 19:37:32 +02003157 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003158 if (!stkctr)
3159 return 0;
3160
3161 smp->flags = SMP_F_VOL_TEST;
3162 smp->data.type = SMP_T_SINT;
3163 smp->data.u.sint = 0;
3164
3165 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003166 void *ptr;
3167
3168 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0);
3169 if (!ptr) {
Emeric Brun726783d2021-06-30 19:06:43 +02003170 /* fallback on the gpc array */
3171 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC, 0);
3172 }
3173
3174 if (!ptr) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003175 if (stkctr == &tmpstkctr)
3176 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003177 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003178 }
3179
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003180 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003181
Emeric Brun0e3457b2021-06-30 17:18:28 +02003182 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003183
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003184 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003185
3186 if (stkctr == &tmpstkctr)
3187 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003188 }
3189 return 1;
3190}
3191
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003192/* set <smp> to the General Purpose Counter 1 value from the stream's tracked
3193 * frontend counters or from the src.
3194 * Supports being called as "sc[0-9]_get_gpc1" or "src_get_gpc1" only. Value
3195 * zero is returned if the key is new.
3196 */
3197static int
3198smp_fetch_sc_get_gpc1(const struct arg *args, struct sample *smp, const char *kw, void *private)
3199{
3200 struct stkctr tmpstkctr;
3201 struct stkctr *stkctr;
3202
3203 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
3204 if (!stkctr)
3205 return 0;
3206
3207 smp->flags = SMP_F_VOL_TEST;
3208 smp->data.type = SMP_T_SINT;
3209 smp->data.u.sint = 0;
3210
3211 if (stkctr_entry(stkctr) != NULL) {
3212 void *ptr;
3213
3214 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1);
3215 if (!ptr) {
Emeric Brun726783d2021-06-30 19:06:43 +02003216 /* fallback on the gpc array */
3217 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC, 1);
3218 }
3219
3220 if (!ptr) {
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003221 if (stkctr == &tmpstkctr)
3222 stktable_release(stkctr->table, stkctr_entry(stkctr));
3223 return 0; /* parameter not stored */
3224 }
3225
3226 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3227
Emeric Brun0e3457b2021-06-30 17:18:28 +02003228 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003229
3230 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3231
3232 if (stkctr == &tmpstkctr)
3233 stktable_release(stkctr->table, stkctr_entry(stkctr));
3234 }
3235 return 1;
3236}
3237
Emeric Brun4d7ada82021-06-30 19:04:16 +02003238/* set <smp> to the GPC[args(0)]'s event rate from the stream's
3239 * tracked frontend counters or from the src.
3240 * Supports being called as "sc_gpc_rate(<gpc-idx>,<sc-idx>[,<table])"
3241 * or "src_gpc_rate(<gpc-idx>[,<table>])" only.
3242 * Value zero is returned if the key is new or gpc_rate is not stored.
3243 */
3244static int
3245smp_fetch_sc_gpc_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3246{
3247 struct stkctr tmpstkctr;
3248 struct stkctr *stkctr;
3249 unsigned int idx;
3250
3251 idx = args[0].data.sint;
3252
3253 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args + 1, kw, &tmpstkctr);
3254 if (!stkctr)
3255 return 0;
3256
3257 smp->flags = SMP_F_VOL_TEST;
3258 smp->data.type = SMP_T_SINT;
3259 smp->data.u.sint = 0;
3260 if (stkctr_entry(stkctr) != NULL) {
3261 void *ptr;
3262
3263 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC_RATE, idx);
3264 if (!ptr) {
3265 if (stkctr == &tmpstkctr)
3266 stktable_release(stkctr->table, stkctr_entry(stkctr));
3267 return 0; /* parameter not stored */
3268 }
3269
3270 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3271
3272 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
3273 stkctr->table->data_arg[STKTABLE_DT_GPC_RATE].u);
3274
3275 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3276
3277 if (stkctr == &tmpstkctr)
3278 stktable_release(stkctr->table, stkctr_entry(stkctr));
3279 }
3280 return 1;
3281}
3282
Willy Tarreau7d562212016-11-25 16:10:05 +01003283/* set <smp> to the General Purpose Counter 0's event rate from the stream's
3284 * tracked frontend counters or from the src.
3285 * Supports being called as "sc[0-9]_gpc0_rate" or "src_gpc0_rate" only.
3286 * Value zero is returned if the key is new.
3287 */
3288static int
3289smp_fetch_sc_gpc0_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3290{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003291 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003292 struct stkctr *stkctr;
Emeric Brun726783d2021-06-30 19:06:43 +02003293 unsigned int period;
Willy Tarreau7d562212016-11-25 16:10:05 +01003294
Emeric Brun819fc6f2017-06-13 19:37:32 +02003295 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003296 if (!stkctr)
3297 return 0;
3298
3299 smp->flags = SMP_F_VOL_TEST;
3300 smp->data.type = SMP_T_SINT;
3301 smp->data.u.sint = 0;
3302 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003303 void *ptr;
3304
3305 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0_RATE);
Emeric Brun726783d2021-06-30 19:06:43 +02003306 if (ptr) {
3307 period = stkctr->table->data_arg[STKTABLE_DT_GPC0_RATE].u;
3308 }
3309 else {
3310 /* fallback on the gpc array */
3311 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC_RATE, 0);
3312 if (ptr)
3313 period = stkctr->table->data_arg[STKTABLE_DT_GPC_RATE].u;
3314 }
3315
Emeric Brun819fc6f2017-06-13 19:37:32 +02003316 if (!ptr) {
3317 if (stkctr == &tmpstkctr)
3318 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003319 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003320 }
3321
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003322 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003323
Emeric Brun726783d2021-06-30 19:06:43 +02003324 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp), period);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003325
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003326 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003327
3328 if (stkctr == &tmpstkctr)
3329 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003330 }
3331 return 1;
3332}
3333
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003334/* set <smp> to the General Purpose Counter 1's event rate from the stream's
3335 * tracked frontend counters or from the src.
3336 * Supports being called as "sc[0-9]_gpc1_rate" or "src_gpc1_rate" only.
3337 * Value zero is returned if the key is new.
3338 */
3339static int
3340smp_fetch_sc_gpc1_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3341{
3342 struct stkctr tmpstkctr;
3343 struct stkctr *stkctr;
Emeric Brun726783d2021-06-30 19:06:43 +02003344 unsigned int period;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003345
3346 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
3347 if (!stkctr)
3348 return 0;
3349
3350 smp->flags = SMP_F_VOL_TEST;
3351 smp->data.type = SMP_T_SINT;
3352 smp->data.u.sint = 0;
3353 if (stkctr_entry(stkctr) != NULL) {
3354 void *ptr;
3355
3356 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1_RATE);
Emeric Brun726783d2021-06-30 19:06:43 +02003357 if (ptr) {
3358 period = stkctr->table->data_arg[STKTABLE_DT_GPC1_RATE].u;
3359 }
3360 else {
3361 /* fallback on the gpc array */
3362 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC_RATE, 1);
3363 if (ptr)
3364 period = stkctr->table->data_arg[STKTABLE_DT_GPC_RATE].u;
3365 }
3366
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003367 if (!ptr) {
3368 if (stkctr == &tmpstkctr)
3369 stktable_release(stkctr->table, stkctr_entry(stkctr));
3370 return 0; /* parameter not stored */
3371 }
3372
3373 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3374
Emeric Brun726783d2021-06-30 19:06:43 +02003375 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 +01003376
3377 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3378
3379 if (stkctr == &tmpstkctr)
3380 stktable_release(stkctr->table, stkctr_entry(stkctr));
3381 }
3382 return 1;
3383}
3384
Emeric Brun4d7ada82021-06-30 19:04:16 +02003385/* Increment the GPC[args(0)] value from the stream's tracked
3386 * frontend counters and return it into temp integer.
3387 * Supports being called as "sc_inc_gpc(<gpc-idx>,<sc-idx>[,<table>])"
3388 * or "src_inc_gpc(<gpc-idx>[,<table>])" only.
3389 */
3390static int
3391smp_fetch_sc_inc_gpc(const struct arg *args, struct sample *smp, const char *kw, void *private)
3392{
3393 struct stkctr tmpstkctr;
3394 struct stkctr *stkctr;
3395 unsigned int idx;
3396
3397 idx = args[0].data.sint;
3398
3399 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args + 1, kw, &tmpstkctr);
3400 if (!stkctr)
3401 return 0;
3402
3403 smp->flags = SMP_F_VOL_TEST;
3404 smp->data.type = SMP_T_SINT;
3405 smp->data.u.sint = 0;
3406
3407 if (!stkctr_entry(stkctr))
3408 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
3409
3410 if (stkctr && stkctr_entry(stkctr)) {
3411 void *ptr1,*ptr2;
3412
3413
3414 /* First, update gpc0_rate if it's tracked. Second, update its
3415 * gpc0 if tracked. Returns gpc0's value otherwise the curr_ctr.
3416 */
3417 ptr1 = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC_RATE, idx);
3418 ptr2 = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC, idx);
3419 if (ptr1 || ptr2) {
3420 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3421
3422 if (ptr1) {
3423 update_freq_ctr_period(&stktable_data_cast(ptr1, std_t_frqp),
3424 stkctr->table->data_arg[STKTABLE_DT_GPC_RATE].u, 1);
3425 smp->data.u.sint = (&stktable_data_cast(ptr1, std_t_frqp))->curr_ctr;
3426 }
3427
3428 if (ptr2)
3429 smp->data.u.sint = ++stktable_data_cast(ptr2, std_t_uint);
3430
3431 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3432
3433 /* If data was modified, we need to touch to re-schedule sync */
3434 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
3435 }
3436 else if (stkctr == &tmpstkctr)
3437 stktable_release(stkctr->table, stkctr_entry(stkctr));
3438 }
3439 return 1;
3440}
3441
Willy Tarreau7d562212016-11-25 16:10:05 +01003442/* Increment the General Purpose Counter 0 value from the stream's tracked
3443 * frontend counters and return it into temp integer.
3444 * Supports being called as "sc[0-9]_inc_gpc0" or "src_inc_gpc0" only.
3445 */
3446static int
3447smp_fetch_sc_inc_gpc0(const struct arg *args, struct sample *smp, const char *kw, void *private)
3448{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003449 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003450 struct stkctr *stkctr;
Willy Tarreau5b654ad2021-07-06 18:51:12 +02003451 unsigned int period = 0;
Willy Tarreau7d562212016-11-25 16:10:05 +01003452
Emeric Brun819fc6f2017-06-13 19:37:32 +02003453 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003454 if (!stkctr)
3455 return 0;
3456
3457 smp->flags = SMP_F_VOL_TEST;
3458 smp->data.type = SMP_T_SINT;
3459 smp->data.u.sint = 0;
3460
Emeric Brun819fc6f2017-06-13 19:37:32 +02003461 if (!stkctr_entry(stkctr))
3462 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003463
3464 if (stkctr && stkctr_entry(stkctr)) {
3465 void *ptr1,*ptr2;
3466
Emeric Brun819fc6f2017-06-13 19:37:32 +02003467
Willy Tarreau7d562212016-11-25 16:10:05 +01003468 /* First, update gpc0_rate if it's tracked. Second, update its
3469 * gpc0 if tracked. Returns gpc0's value otherwise the curr_ctr.
3470 */
3471 ptr1 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0_RATE);
Emeric Brun726783d2021-06-30 19:06:43 +02003472 if (ptr1) {
3473 period = stkctr->table->data_arg[STKTABLE_DT_GPC0_RATE].u;
3474 }
3475 else {
3476 /* fallback on the gpc array */
3477 ptr1 = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC_RATE, 0);
3478 if (ptr1)
3479 period = stkctr->table->data_arg[STKTABLE_DT_GPC_RATE].u;
3480 }
3481
Willy Tarreau7d562212016-11-25 16:10:05 +01003482 ptr2 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0);
Emeric Brun726783d2021-06-30 19:06:43 +02003483 if (!ptr2) {
3484 /* fallback on the gpc array */
3485 ptr2 = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC, 0);
3486 }
3487
Emeric Brun819fc6f2017-06-13 19:37:32 +02003488 if (ptr1 || ptr2) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003489 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Willy Tarreau7d562212016-11-25 16:10:05 +01003490
Emeric Brun819fc6f2017-06-13 19:37:32 +02003491 if (ptr1) {
Emeric Brun0e3457b2021-06-30 17:18:28 +02003492 update_freq_ctr_period(&stktable_data_cast(ptr1, std_t_frqp),
Emeric Brun726783d2021-06-30 19:06:43 +02003493 period, 1);
Emeric Brun0e3457b2021-06-30 17:18:28 +02003494 smp->data.u.sint = (&stktable_data_cast(ptr1, std_t_frqp))->curr_ctr;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003495 }
3496
3497 if (ptr2)
Emeric Brun0e3457b2021-06-30 17:18:28 +02003498 smp->data.u.sint = ++stktable_data_cast(ptr2, std_t_uint);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003499
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003500 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003501
3502 /* If data was modified, we need to touch to re-schedule sync */
3503 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
3504 }
3505 else if (stkctr == &tmpstkctr)
3506 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003507 }
3508 return 1;
3509}
3510
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003511/* Increment the General Purpose Counter 1 value from the stream's tracked
3512 * frontend counters and return it into temp integer.
3513 * Supports being called as "sc[0-9]_inc_gpc1" or "src_inc_gpc1" only.
3514 */
3515static int
3516smp_fetch_sc_inc_gpc1(const struct arg *args, struct sample *smp, const char *kw, void *private)
3517{
3518 struct stkctr tmpstkctr;
3519 struct stkctr *stkctr;
Willy Tarreau5b654ad2021-07-06 18:51:12 +02003520 unsigned int period = 0;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003521
3522 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
3523 if (!stkctr)
3524 return 0;
3525
3526 smp->flags = SMP_F_VOL_TEST;
3527 smp->data.type = SMP_T_SINT;
3528 smp->data.u.sint = 0;
3529
3530 if (!stkctr_entry(stkctr))
3531 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
3532
3533 if (stkctr && stkctr_entry(stkctr)) {
3534 void *ptr1,*ptr2;
3535
3536
3537 /* First, update gpc1_rate if it's tracked. Second, update its
3538 * gpc1 if tracked. Returns gpc1's value otherwise the curr_ctr.
3539 */
3540 ptr1 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1_RATE);
Emeric Brun726783d2021-06-30 19:06:43 +02003541 if (ptr1) {
3542 period = stkctr->table->data_arg[STKTABLE_DT_GPC1_RATE].u;
3543 }
3544 else {
3545 /* fallback on the gpc array */
3546 ptr1 = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC_RATE, 1);
3547 if (ptr1)
3548 period = stkctr->table->data_arg[STKTABLE_DT_GPC_RATE].u;
3549 }
3550
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003551 ptr2 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1);
Emeric Brun726783d2021-06-30 19:06:43 +02003552 if (!ptr2) {
3553 /* fallback on the gpc array */
3554 ptr2 = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC, 1);
3555 }
3556
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003557 if (ptr1 || ptr2) {
3558 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3559
3560 if (ptr1) {
Emeric Brun0e3457b2021-06-30 17:18:28 +02003561 update_freq_ctr_period(&stktable_data_cast(ptr1, std_t_frqp),
Emeric Brun726783d2021-06-30 19:06:43 +02003562 period, 1);
Emeric Brun0e3457b2021-06-30 17:18:28 +02003563 smp->data.u.sint = (&stktable_data_cast(ptr1, std_t_frqp))->curr_ctr;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003564 }
3565
3566 if (ptr2)
Emeric Brun0e3457b2021-06-30 17:18:28 +02003567 smp->data.u.sint = ++stktable_data_cast(ptr2, std_t_uint);
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003568
3569 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3570
3571 /* If data was modified, we need to touch to re-schedule sync */
3572 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
3573 }
3574 else if (stkctr == &tmpstkctr)
3575 stktable_release(stkctr->table, stkctr_entry(stkctr));
3576 }
3577 return 1;
3578}
3579
Emeric Brun4d7ada82021-06-30 19:04:16 +02003580/* Clear the GPC[args(0)] value from the stream's tracked
3581 * frontend counters and return its previous value into temp integer.
3582 * Supports being called as "sc_clr_gpc(<gpc-idx>,<sc-idx>[,<table>])"
3583 * or "src_clr_gpc(<gpc-idx>[,<table>])" only.
3584 */
3585static int
3586smp_fetch_sc_clr_gpc(const struct arg *args, struct sample *smp, const char *kw, void *private)
3587{
3588 struct stkctr tmpstkctr;
3589 struct stkctr *stkctr;
3590 unsigned int idx;
3591
3592 idx = args[0].data.sint;
3593
3594 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args + 1, kw, &tmpstkctr);
3595 if (!stkctr)
3596 return 0;
3597
3598 smp->flags = SMP_F_VOL_TEST;
3599 smp->data.type = SMP_T_SINT;
3600 smp->data.u.sint = 0;
3601
3602 if (!stkctr_entry(stkctr))
3603 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
3604
3605 if (stkctr && stkctr_entry(stkctr)) {
3606 void *ptr;
3607
3608 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC, idx);
3609 if (!ptr) {
3610 if (stkctr == &tmpstkctr)
3611 stktable_release(stkctr->table, stkctr_entry(stkctr));
3612 return 0; /* parameter not stored */
3613 }
3614
3615 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3616
3617 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
3618 stktable_data_cast(ptr, std_t_uint) = 0;
3619
3620 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3621
3622 /* If data was modified, we need to touch to re-schedule sync */
3623 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
3624 }
3625 return 1;
3626}
3627
Willy Tarreau7d562212016-11-25 16:10:05 +01003628/* Clear the General Purpose Counter 0 value from the stream's tracked
3629 * frontend counters and return its previous value into temp integer.
3630 * Supports being called as "sc[0-9]_clr_gpc0" or "src_clr_gpc0" only.
3631 */
3632static int
3633smp_fetch_sc_clr_gpc0(const struct arg *args, struct sample *smp, const char *kw, void *private)
3634{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003635 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003636 struct stkctr *stkctr;
3637
Emeric Brun819fc6f2017-06-13 19:37:32 +02003638 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003639 if (!stkctr)
3640 return 0;
3641
3642 smp->flags = SMP_F_VOL_TEST;
3643 smp->data.type = SMP_T_SINT;
3644 smp->data.u.sint = 0;
3645
Emeric Brun819fc6f2017-06-13 19:37:32 +02003646 if (!stkctr_entry(stkctr))
3647 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003648
Emeric Brun819fc6f2017-06-13 19:37:32 +02003649 if (stkctr && stkctr_entry(stkctr)) {
3650 void *ptr;
3651
3652 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0);
3653 if (!ptr) {
Emeric Brun726783d2021-06-30 19:06:43 +02003654 /* fallback on the gpc array */
3655 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC, 0);
3656 }
3657
3658 if (!ptr) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003659 if (stkctr == &tmpstkctr)
3660 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003661 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003662 }
3663
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003664 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003665
Emeric Brun0e3457b2021-06-30 17:18:28 +02003666 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
3667 stktable_data_cast(ptr, std_t_uint) = 0;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003668
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003669 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003670
Willy Tarreau7d562212016-11-25 16:10:05 +01003671 /* If data was modified, we need to touch to re-schedule sync */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003672 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
Willy Tarreau7d562212016-11-25 16:10:05 +01003673 }
3674 return 1;
3675}
3676
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003677/* Clear the General Purpose Counter 1 value from the stream's tracked
3678 * frontend counters and return its previous value into temp integer.
3679 * Supports being called as "sc[0-9]_clr_gpc1" or "src_clr_gpc1" only.
3680 */
3681static int
3682smp_fetch_sc_clr_gpc1(const struct arg *args, struct sample *smp, const char *kw, void *private)
3683{
3684 struct stkctr tmpstkctr;
3685 struct stkctr *stkctr;
3686
3687 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
3688 if (!stkctr)
3689 return 0;
3690
3691 smp->flags = SMP_F_VOL_TEST;
3692 smp->data.type = SMP_T_SINT;
3693 smp->data.u.sint = 0;
3694
3695 if (!stkctr_entry(stkctr))
3696 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
3697
3698 if (stkctr && stkctr_entry(stkctr)) {
3699 void *ptr;
3700
3701 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1);
3702 if (!ptr) {
Emeric Brun726783d2021-06-30 19:06:43 +02003703 /* fallback on the gpc array */
3704 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC, 1);
3705 }
3706
3707 if (!ptr) {
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003708 if (stkctr == &tmpstkctr)
3709 stktable_release(stkctr->table, stkctr_entry(stkctr));
3710 return 0; /* parameter not stored */
3711 }
3712
3713 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3714
Emeric Brun0e3457b2021-06-30 17:18:28 +02003715 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
3716 stktable_data_cast(ptr, std_t_uint) = 0;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003717
3718 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3719
3720 /* If data was modified, we need to touch to re-schedule sync */
3721 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
3722 }
3723 return 1;
3724}
3725
Willy Tarreau7d562212016-11-25 16:10:05 +01003726/* set <smp> to the cumulated number of connections from the stream's tracked
3727 * frontend counters. Supports being called as "sc[0-9]_conn_cnt" or
3728 * "src_conn_cnt" only.
3729 */
3730static int
3731smp_fetch_sc_conn_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
3732{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003733 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003734 struct stkctr *stkctr;
3735
Emeric Brun819fc6f2017-06-13 19:37:32 +02003736 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003737 if (!stkctr)
3738 return 0;
3739
3740 smp->flags = SMP_F_VOL_TEST;
3741 smp->data.type = SMP_T_SINT;
3742 smp->data.u.sint = 0;
3743 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003744 void *ptr;
3745
3746 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_CONN_CNT);
3747 if (!ptr) {
3748 if (stkctr == &tmpstkctr)
3749 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003750 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003751 }
3752
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003753 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003754
Emeric Brun0e3457b2021-06-30 17:18:28 +02003755 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003756
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003757 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003758
3759 if (stkctr == &tmpstkctr)
3760 stktable_release(stkctr->table, stkctr_entry(stkctr));
3761
3762
Willy Tarreau7d562212016-11-25 16:10:05 +01003763 }
3764 return 1;
3765}
3766
3767/* set <smp> to the connection rate from the stream's tracked frontend
3768 * counters. Supports being called as "sc[0-9]_conn_rate" or "src_conn_rate"
3769 * only.
3770 */
3771static int
3772smp_fetch_sc_conn_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3773{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003774 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003775 struct stkctr *stkctr;
3776
Emeric Brun819fc6f2017-06-13 19:37:32 +02003777 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003778 if (!stkctr)
3779 return 0;
3780
3781 smp->flags = SMP_F_VOL_TEST;
3782 smp->data.type = SMP_T_SINT;
3783 smp->data.u.sint = 0;
3784 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003785 void *ptr;
3786
3787 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_CONN_RATE);
3788 if (!ptr) {
3789 if (stkctr == &tmpstkctr)
3790 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003791 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003792 }
3793
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003794 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003795
Emeric Brun0e3457b2021-06-30 17:18:28 +02003796 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Willy Tarreau7d562212016-11-25 16:10:05 +01003797 stkctr->table->data_arg[STKTABLE_DT_CONN_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003798
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003799 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003800
3801 if (stkctr == &tmpstkctr)
3802 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003803 }
3804 return 1;
3805}
3806
3807/* set temp integer to the number of connections from the stream's source address
3808 * in the table pointed to by expr, after updating it.
3809 * Accepts exactly 1 argument of type table.
3810 */
3811static int
3812smp_fetch_src_updt_conn_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
3813{
3814 struct connection *conn = objt_conn(smp->sess->origin);
3815 struct stksess *ts;
3816 struct stktable_key *key;
3817 void *ptr;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003818 struct stktable *t;
Willy Tarreau7d562212016-11-25 16:10:05 +01003819
3820 if (!conn)
3821 return 0;
3822
Joseph Herlant5662fa42018-11-15 13:43:28 -08003823 /* Fetch source address in a sample. */
Amaury Denoyellec460c702021-05-12 10:17:47 +02003824 if (!smp_fetch_src || !smp_fetch_src(empty_arg_list, smp, "src", NULL))
Willy Tarreau7d562212016-11-25 16:10:05 +01003825 return 0;
3826
3827 /* Converts into key. */
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003828 key = smp_to_stkey(smp, args->data.t);
Willy Tarreau7d562212016-11-25 16:10:05 +01003829 if (!key)
3830 return 0;
3831
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003832 t = args->data.t;
Willy Tarreau7d562212016-11-25 16:10:05 +01003833
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003834 if ((ts = stktable_get_entry(t, key)) == NULL)
Willy Tarreau7d562212016-11-25 16:10:05 +01003835 /* entry does not exist and could not be created */
3836 return 0;
3837
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003838 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_CONN_CNT);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003839 if (!ptr) {
Willy Tarreau7d562212016-11-25 16:10:05 +01003840 return 0; /* parameter not stored in this table */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003841 }
Willy Tarreau7d562212016-11-25 16:10:05 +01003842
3843 smp->data.type = SMP_T_SINT;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003844
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003845 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003846
Emeric Brun0e3457b2021-06-30 17:18:28 +02003847 smp->data.u.sint = ++stktable_data_cast(ptr, std_t_uint);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003848
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003849 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003850
Willy Tarreau7d562212016-11-25 16:10:05 +01003851 smp->flags = SMP_F_VOL_TEST;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003852
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003853 stktable_touch_local(t, ts, 1);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003854
3855 /* Touch was previously performed by stktable_update_key */
Willy Tarreau7d562212016-11-25 16:10:05 +01003856 return 1;
3857}
3858
3859/* set <smp> to the number of concurrent connections from the stream's tracked
3860 * frontend counters. Supports being called as "sc[0-9]_conn_cur" or
3861 * "src_conn_cur" only.
3862 */
3863static int
3864smp_fetch_sc_conn_cur(const struct arg *args, struct sample *smp, const char *kw, void *private)
3865{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003866 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003867 struct stkctr *stkctr;
3868
Emeric Brun819fc6f2017-06-13 19:37:32 +02003869 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003870 if (!stkctr)
3871 return 0;
3872
3873 smp->flags = SMP_F_VOL_TEST;
3874 smp->data.type = SMP_T_SINT;
3875 smp->data.u.sint = 0;
3876 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003877 void *ptr;
3878
3879 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_CONN_CUR);
3880 if (!ptr) {
3881 if (stkctr == &tmpstkctr)
3882 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003883 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003884 }
3885
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003886 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003887
Emeric Brun0e3457b2021-06-30 17:18:28 +02003888 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003889
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003890 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003891
3892 if (stkctr == &tmpstkctr)
3893 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003894 }
3895 return 1;
3896}
3897
3898/* set <smp> to the cumulated number of streams from the stream's tracked
3899 * frontend counters. Supports being called as "sc[0-9]_sess_cnt" or
3900 * "src_sess_cnt" only.
3901 */
3902static int
3903smp_fetch_sc_sess_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
3904{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003905 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003906 struct stkctr *stkctr;
3907
Emeric Brun819fc6f2017-06-13 19:37:32 +02003908 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003909 if (!stkctr)
3910 return 0;
3911
3912 smp->flags = SMP_F_VOL_TEST;
3913 smp->data.type = SMP_T_SINT;
3914 smp->data.u.sint = 0;
3915 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003916 void *ptr;
3917
3918 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_SESS_CNT);
3919 if (!ptr) {
3920 if (stkctr == &tmpstkctr)
3921 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003922 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003923 }
3924
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003925 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003926
Emeric Brun0e3457b2021-06-30 17:18:28 +02003927 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003928
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003929 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003930
3931 if (stkctr == &tmpstkctr)
3932 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003933 }
3934 return 1;
3935}
3936
3937/* set <smp> to the stream rate from the stream's tracked frontend counters.
3938 * Supports being called as "sc[0-9]_sess_rate" or "src_sess_rate" only.
3939 */
3940static int
3941smp_fetch_sc_sess_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3942{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003943 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003944 struct stkctr *stkctr;
3945
Emeric Brun819fc6f2017-06-13 19:37:32 +02003946 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003947 if (!stkctr)
3948 return 0;
3949
3950 smp->flags = SMP_F_VOL_TEST;
3951 smp->data.type = SMP_T_SINT;
3952 smp->data.u.sint = 0;
3953 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003954 void *ptr;
3955
3956 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_SESS_RATE);
3957 if (!ptr) {
3958 if (stkctr == &tmpstkctr)
3959 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003960 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003961 }
3962
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003963 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003964
Emeric Brun0e3457b2021-06-30 17:18:28 +02003965 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Willy Tarreau7d562212016-11-25 16:10:05 +01003966 stkctr->table->data_arg[STKTABLE_DT_SESS_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003967
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003968 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003969
3970 if (stkctr == &tmpstkctr)
3971 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003972 }
3973 return 1;
3974}
3975
3976/* set <smp> to the cumulated number of HTTP requests from the stream's tracked
3977 * frontend counters. Supports being called as "sc[0-9]_http_req_cnt" or
3978 * "src_http_req_cnt" only.
3979 */
3980static int
3981smp_fetch_sc_http_req_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
3982{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003983 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003984 struct stkctr *stkctr;
3985
Emeric Brun819fc6f2017-06-13 19:37:32 +02003986 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003987 if (!stkctr)
3988 return 0;
3989
3990 smp->flags = SMP_F_VOL_TEST;
3991 smp->data.type = SMP_T_SINT;
3992 smp->data.u.sint = 0;
3993 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003994 void *ptr;
3995
3996 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_REQ_CNT);
3997 if (!ptr) {
3998 if (stkctr == &tmpstkctr)
3999 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004000 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02004001 }
4002
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004003 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004004
Emeric Brun0e3457b2021-06-30 17:18:28 +02004005 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004006
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004007 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004008
4009 if (stkctr == &tmpstkctr)
4010 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004011 }
4012 return 1;
4013}
4014
4015/* set <smp> to the HTTP request rate from the stream's tracked frontend
4016 * counters. Supports being called as "sc[0-9]_http_req_rate" or
4017 * "src_http_req_rate" only.
4018 */
4019static int
4020smp_fetch_sc_http_req_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
4021{
Emeric Brun819fc6f2017-06-13 19:37:32 +02004022 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01004023 struct stkctr *stkctr;
4024
Emeric Brun819fc6f2017-06-13 19:37:32 +02004025 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01004026 if (!stkctr)
4027 return 0;
4028
4029 smp->flags = SMP_F_VOL_TEST;
4030 smp->data.type = SMP_T_SINT;
4031 smp->data.u.sint = 0;
4032 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02004033 void *ptr;
4034
4035 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_REQ_RATE);
4036 if (!ptr) {
4037 if (stkctr == &tmpstkctr)
4038 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004039 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02004040 }
4041
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004042 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004043
Emeric Brun0e3457b2021-06-30 17:18:28 +02004044 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Willy Tarreau7d562212016-11-25 16:10:05 +01004045 stkctr->table->data_arg[STKTABLE_DT_HTTP_REQ_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004046
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004047 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004048
4049 if (stkctr == &tmpstkctr)
4050 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004051 }
4052 return 1;
4053}
4054
4055/* set <smp> to the cumulated number of HTTP requests errors from the stream's
4056 * tracked frontend counters. Supports being called as "sc[0-9]_http_err_cnt" or
4057 * "src_http_err_cnt" only.
4058 */
4059static int
4060smp_fetch_sc_http_err_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
4061{
Emeric Brun819fc6f2017-06-13 19:37:32 +02004062 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01004063 struct stkctr *stkctr;
4064
Emeric Brun819fc6f2017-06-13 19:37:32 +02004065 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01004066 if (!stkctr)
4067 return 0;
4068
4069 smp->flags = SMP_F_VOL_TEST;
4070 smp->data.type = SMP_T_SINT;
4071 smp->data.u.sint = 0;
4072 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02004073 void *ptr;
4074
4075 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_ERR_CNT);
4076 if (!ptr) {
4077 if (stkctr == &tmpstkctr)
4078 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004079 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02004080 }
4081
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004082 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004083
Emeric Brun0e3457b2021-06-30 17:18:28 +02004084 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004085
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004086 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004087
4088 if (stkctr == &tmpstkctr)
4089 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004090 }
4091 return 1;
4092}
4093
4094/* set <smp> to the HTTP request error rate from the stream's tracked frontend
4095 * counters. Supports being called as "sc[0-9]_http_err_rate" or
4096 * "src_http_err_rate" only.
4097 */
4098static int
4099smp_fetch_sc_http_err_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
4100{
Emeric Brun819fc6f2017-06-13 19:37:32 +02004101 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01004102 struct stkctr *stkctr;
4103
Emeric Brun819fc6f2017-06-13 19:37:32 +02004104 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01004105 if (!stkctr)
4106 return 0;
4107
4108 smp->flags = SMP_F_VOL_TEST;
4109 smp->data.type = SMP_T_SINT;
4110 smp->data.u.sint = 0;
4111 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02004112 void *ptr;
4113
4114 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_ERR_RATE);
4115 if (!ptr) {
4116 if (stkctr == &tmpstkctr)
4117 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004118 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02004119 }
4120
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004121 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004122
Emeric Brun0e3457b2021-06-30 17:18:28 +02004123 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Willy Tarreau7d562212016-11-25 16:10:05 +01004124 stkctr->table->data_arg[STKTABLE_DT_HTTP_ERR_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004125
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004126 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004127
4128 if (stkctr == &tmpstkctr)
4129 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004130 }
4131 return 1;
4132}
4133
Willy Tarreau826f3ab2021-02-10 12:07:15 +01004134/* set <smp> to the cumulated number of HTTP response failures from the stream's
4135 * tracked frontend counters. Supports being called as "sc[0-9]_http_fail_cnt" or
4136 * "src_http_fail_cnt" only.
4137 */
4138static int
4139smp_fetch_sc_http_fail_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
4140{
4141 struct stkctr tmpstkctr;
4142 struct stkctr *stkctr;
4143
4144 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
4145 if (!stkctr)
4146 return 0;
4147
4148 smp->flags = SMP_F_VOL_TEST;
4149 smp->data.type = SMP_T_SINT;
4150 smp->data.u.sint = 0;
4151 if (stkctr_entry(stkctr) != NULL) {
4152 void *ptr;
4153
4154 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_FAIL_CNT);
4155 if (!ptr) {
4156 if (stkctr == &tmpstkctr)
4157 stktable_release(stkctr->table, stkctr_entry(stkctr));
4158 return 0; /* parameter not stored */
4159 }
4160
4161 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
4162
Emeric Brun0e3457b2021-06-30 17:18:28 +02004163 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Willy Tarreau826f3ab2021-02-10 12:07:15 +01004164
4165 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
4166
4167 if (stkctr == &tmpstkctr)
4168 stktable_release(stkctr->table, stkctr_entry(stkctr));
4169 }
4170 return 1;
4171}
4172
4173/* set <smp> to the HTTP response failure rate from the stream's tracked frontend
4174 * counters. Supports being called as "sc[0-9]_http_fail_rate" or
4175 * "src_http_fail_rate" only.
4176 */
4177static int
4178smp_fetch_sc_http_fail_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
4179{
4180 struct stkctr tmpstkctr;
4181 struct stkctr *stkctr;
4182
4183 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
4184 if (!stkctr)
4185 return 0;
4186
4187 smp->flags = SMP_F_VOL_TEST;
4188 smp->data.type = SMP_T_SINT;
4189 smp->data.u.sint = 0;
4190 if (stkctr_entry(stkctr) != NULL) {
4191 void *ptr;
4192
4193 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_FAIL_RATE);
4194 if (!ptr) {
4195 if (stkctr == &tmpstkctr)
4196 stktable_release(stkctr->table, stkctr_entry(stkctr));
4197 return 0; /* parameter not stored */
4198 }
4199
4200 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
4201
Emeric Brun0e3457b2021-06-30 17:18:28 +02004202 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Willy Tarreau826f3ab2021-02-10 12:07:15 +01004203 stkctr->table->data_arg[STKTABLE_DT_HTTP_FAIL_RATE].u);
4204
4205 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
4206
4207 if (stkctr == &tmpstkctr)
4208 stktable_release(stkctr->table, stkctr_entry(stkctr));
4209 }
4210 return 1;
4211}
4212
Willy Tarreau7d562212016-11-25 16:10:05 +01004213/* set <smp> to the number of kbytes received from clients, as found in the
4214 * stream's tracked frontend counters. Supports being called as
4215 * "sc[0-9]_kbytes_in" or "src_kbytes_in" only.
4216 */
4217static int
4218smp_fetch_sc_kbytes_in(const struct arg *args, struct sample *smp, const char *kw, void *private)
4219{
Emeric Brun819fc6f2017-06-13 19:37:32 +02004220 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01004221 struct stkctr *stkctr;
4222
Emeric Brun819fc6f2017-06-13 19:37:32 +02004223 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01004224 if (!stkctr)
4225 return 0;
4226
4227 smp->flags = SMP_F_VOL_TEST;
4228 smp->data.type = SMP_T_SINT;
4229 smp->data.u.sint = 0;
4230 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02004231 void *ptr;
4232
4233 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_IN_CNT);
4234 if (!ptr) {
4235 if (stkctr == &tmpstkctr)
4236 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004237 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02004238 }
4239
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004240 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004241
Emeric Brun0e3457b2021-06-30 17:18:28 +02004242 smp->data.u.sint = stktable_data_cast(ptr, std_t_ull) >> 10;
Emeric Brun819fc6f2017-06-13 19:37:32 +02004243
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004244 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004245
4246 if (stkctr == &tmpstkctr)
4247 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004248 }
4249 return 1;
4250}
4251
4252/* set <smp> to the data rate received from clients in bytes/s, as found
4253 * in the stream's tracked frontend counters. Supports being called as
4254 * "sc[0-9]_bytes_in_rate" or "src_bytes_in_rate" only.
4255 */
4256static int
4257smp_fetch_sc_bytes_in_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
4258{
Emeric Brun819fc6f2017-06-13 19:37:32 +02004259 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01004260 struct stkctr *stkctr;
4261
Emeric Brun819fc6f2017-06-13 19:37:32 +02004262 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01004263 if (!stkctr)
4264 return 0;
4265
4266 smp->flags = SMP_F_VOL_TEST;
4267 smp->data.type = SMP_T_SINT;
4268 smp->data.u.sint = 0;
4269 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02004270 void *ptr;
4271
4272 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_IN_RATE);
4273 if (!ptr) {
4274 if (stkctr == &tmpstkctr)
4275 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004276 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02004277 }
4278
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004279 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004280
Emeric Brun0e3457b2021-06-30 17:18:28 +02004281 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Willy Tarreau7d562212016-11-25 16:10:05 +01004282 stkctr->table->data_arg[STKTABLE_DT_BYTES_IN_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004283
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004284 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004285
4286 if (stkctr == &tmpstkctr)
4287 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004288 }
4289 return 1;
4290}
4291
4292/* set <smp> to the number of kbytes sent to clients, as found in the
4293 * stream's tracked frontend counters. Supports being called as
4294 * "sc[0-9]_kbytes_out" or "src_kbytes_out" only.
4295 */
4296static int
4297smp_fetch_sc_kbytes_out(const struct arg *args, struct sample *smp, const char *kw, void *private)
4298{
Emeric Brun819fc6f2017-06-13 19:37:32 +02004299 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01004300 struct stkctr *stkctr;
4301
Emeric Brun819fc6f2017-06-13 19:37:32 +02004302 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01004303 if (!stkctr)
4304 return 0;
4305
4306 smp->flags = SMP_F_VOL_TEST;
4307 smp->data.type = SMP_T_SINT;
4308 smp->data.u.sint = 0;
4309 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02004310 void *ptr;
4311
4312 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_OUT_CNT);
4313 if (!ptr) {
4314 if (stkctr == &tmpstkctr)
4315 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004316 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02004317 }
4318
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004319 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004320
Emeric Brun0e3457b2021-06-30 17:18:28 +02004321 smp->data.u.sint = stktable_data_cast(ptr, std_t_ull) >> 10;
Emeric Brun819fc6f2017-06-13 19:37:32 +02004322
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004323 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004324
4325 if (stkctr == &tmpstkctr)
4326 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004327 }
4328 return 1;
4329}
4330
4331/* set <smp> to the data rate sent to clients in bytes/s, as found in the
4332 * stream's tracked frontend counters. Supports being called as
4333 * "sc[0-9]_bytes_out_rate" or "src_bytes_out_rate" only.
4334 */
4335static int
4336smp_fetch_sc_bytes_out_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
4337{
Emeric Brun819fc6f2017-06-13 19:37:32 +02004338 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01004339 struct stkctr *stkctr;
4340
Emeric Brun819fc6f2017-06-13 19:37:32 +02004341 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01004342 if (!stkctr)
4343 return 0;
4344
4345 smp->flags = SMP_F_VOL_TEST;
4346 smp->data.type = SMP_T_SINT;
4347 smp->data.u.sint = 0;
4348 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02004349 void *ptr;
4350
4351 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_OUT_RATE);
4352 if (!ptr) {
4353 if (stkctr == &tmpstkctr)
4354 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004355 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02004356 }
4357
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004358 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004359
Emeric Brun0e3457b2021-06-30 17:18:28 +02004360 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Willy Tarreau7d562212016-11-25 16:10:05 +01004361 stkctr->table->data_arg[STKTABLE_DT_BYTES_OUT_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004362
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004363 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004364
4365 if (stkctr == &tmpstkctr)
4366 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004367 }
4368 return 1;
4369}
4370
4371/* set <smp> to the number of active trackers on the SC entry in the stream's
4372 * tracked frontend counters. Supports being called as "sc[0-9]_trackers" only.
4373 */
4374static int
4375smp_fetch_sc_trackers(const struct arg *args, struct sample *smp, const char *kw, void *private)
4376{
Emeric Brun819fc6f2017-06-13 19:37:32 +02004377 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01004378 struct stkctr *stkctr;
4379
Emeric Brun819fc6f2017-06-13 19:37:32 +02004380 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01004381 if (!stkctr)
4382 return 0;
4383
4384 smp->flags = SMP_F_VOL_TEST;
4385 smp->data.type = SMP_T_SINT;
Emeric Brun819fc6f2017-06-13 19:37:32 +02004386 if (stkctr == &tmpstkctr) {
4387 smp->data.u.sint = stkctr_entry(stkctr) ? (stkctr_entry(stkctr)->ref_cnt-1) : 0;
4388 stktable_release(stkctr->table, stkctr_entry(stkctr));
4389 }
4390 else {
4391 smp->data.u.sint = stkctr_entry(stkctr) ? stkctr_entry(stkctr)->ref_cnt : 0;
4392 }
4393
Willy Tarreau7d562212016-11-25 16:10:05 +01004394 return 1;
4395}
4396
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004397
4398/* The functions below are used to manipulate table contents from the CLI.
4399 * There are 3 main actions, "clear", "set" and "show". The code is shared
4400 * between all actions, and the action is encoded in the void *private in
4401 * the appctx as well as in the keyword registration, among one of the
4402 * following values.
4403 */
4404
4405enum {
4406 STK_CLI_ACT_CLR,
4407 STK_CLI_ACT_SET,
4408 STK_CLI_ACT_SHOW,
4409};
4410
Willy Tarreau4596fe22022-05-17 19:07:51 +02004411/* Dump the status of a table to a stream connector's
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004412 * read buffer. It returns 0 if the output buffer is full
4413 * and needs to be called again, otherwise non-zero.
4414 */
Willy Tarreau83061a82018-07-13 11:56:34 +02004415static int table_dump_head_to_buffer(struct buffer *msg,
Willy Tarreaud0a06d52022-05-18 15:07:19 +02004416 struct appctx *appctx,
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004417 struct stktable *t, struct stktable *target)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004418{
Willy Tarreauc12b3212022-05-27 11:08:15 +02004419 struct stream *s = __sc_strm(appctx_sc(appctx));
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004420
4421 chunk_appendf(msg, "# table: %s, type: %s, size:%d, used:%d\n",
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004422 t->id, stktable_types[t->type].kw, t->size, t->current);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004423
4424 /* any other information should be dumped here */
4425
William Lallemand07a62f72017-05-24 00:57:40 +02004426 if (target && (strm_li(s)->bind_conf->level & ACCESS_LVL_MASK) < ACCESS_LVL_OPER)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004427 chunk_appendf(msg, "# contents not dumped due to insufficient privileges\n");
4428
Willy Tarreaud0a06d52022-05-18 15:07:19 +02004429 if (applet_putchk(appctx, msg) == -1)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004430 return 0;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004431
4432 return 1;
4433}
4434
Willy Tarreau4596fe22022-05-17 19:07:51 +02004435/* Dump a table entry to a stream connector's
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004436 * read buffer. It returns 0 if the output buffer is full
4437 * and needs to be called again, otherwise non-zero.
4438 */
Willy Tarreau83061a82018-07-13 11:56:34 +02004439static int table_dump_entry_to_buffer(struct buffer *msg,
Willy Tarreaud0a06d52022-05-18 15:07:19 +02004440 struct appctx *appctx,
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004441 struct stktable *t, struct stksess *entry)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004442{
4443 int dt;
4444
4445 chunk_appendf(msg, "%p:", entry);
4446
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004447 if (t->type == SMP_T_IPV4) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004448 char addr[INET_ADDRSTRLEN];
4449 inet_ntop(AF_INET, (const void *)&entry->key.key, addr, sizeof(addr));
4450 chunk_appendf(msg, " key=%s", addr);
4451 }
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004452 else if (t->type == SMP_T_IPV6) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004453 char addr[INET6_ADDRSTRLEN];
4454 inet_ntop(AF_INET6, (const void *)&entry->key.key, addr, sizeof(addr));
4455 chunk_appendf(msg, " key=%s", addr);
4456 }
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004457 else if (t->type == SMP_T_SINT) {
Willy Tarreau6cde5d82020-02-25 09:41:22 +01004458 chunk_appendf(msg, " key=%u", read_u32(entry->key.key));
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004459 }
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004460 else if (t->type == SMP_T_STR) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004461 chunk_appendf(msg, " key=");
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004462 dump_text(msg, (const char *)entry->key.key, t->key_size);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004463 }
4464 else {
4465 chunk_appendf(msg, " key=");
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004466 dump_binary(msg, (const char *)entry->key.key, t->key_size);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004467 }
4468
4469 chunk_appendf(msg, " use=%d exp=%d", entry->ref_cnt - 1, tick_remain(now_ms, entry->expire));
4470
4471 for (dt = 0; dt < STKTABLE_DATA_TYPES; dt++) {
4472 void *ptr;
4473
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004474 if (t->data_ofs[dt] == 0)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004475 continue;
Emeric Brunc64a2a32021-06-30 18:01:02 +02004476 if (stktable_data_types[dt].is_array) {
4477 char tmp[16] = {};
4478 const char *name_pfx = stktable_data_types[dt].name;
4479 const char *name_sfx = NULL;
4480 unsigned int idx = 0;
4481 int i = 0;
4482
4483 /* split name to show index before first _ of the name
4484 * for example: 'gpc3_rate' if array name is 'gpc_rate'.
4485 */
4486 for (i = 0 ; i < (sizeof(tmp) - 1); i++) {
4487 if (!name_pfx[i])
4488 break;
4489 if (name_pfx[i] == '_') {
4490 name_pfx = &tmp[0];
4491 name_sfx = &stktable_data_types[dt].name[i];
4492 break;
4493 }
4494 tmp[i] = name_pfx[i];
4495 }
4496
4497 ptr = stktable_data_ptr_idx(t, entry, dt, idx);
4498 while (ptr) {
4499 if (stktable_data_types[dt].arg_type == ARG_T_DELAY)
4500 chunk_appendf(msg, " %s%u%s(%u)=", name_pfx, idx, name_sfx ? name_sfx : "", t->data_arg[dt].u);
4501 else
4502 chunk_appendf(msg, " %s%u%s=", name_pfx, idx, name_sfx ? name_sfx : "");
4503 switch (stktable_data_types[dt].std_type) {
4504 case STD_T_SINT:
4505 chunk_appendf(msg, "%d", stktable_data_cast(ptr, std_t_sint));
4506 break;
4507 case STD_T_UINT:
4508 chunk_appendf(msg, "%u", stktable_data_cast(ptr, std_t_uint));
4509 break;
4510 case STD_T_ULL:
4511 chunk_appendf(msg, "%llu", stktable_data_cast(ptr, std_t_ull));
4512 break;
4513 case STD_T_FRQP:
4514 chunk_appendf(msg, "%u",
4515 read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
4516 t->data_arg[dt].u));
4517 break;
4518 }
4519 ptr = stktable_data_ptr_idx(t, entry, dt, ++idx);
4520 }
4521 continue;
4522 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004523 if (stktable_data_types[dt].arg_type == ARG_T_DELAY)
Emeric Brun01928ae2021-06-30 16:24:04 +02004524 chunk_appendf(msg, " %s(%u)=", stktable_data_types[dt].name, t->data_arg[dt].u);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004525 else
4526 chunk_appendf(msg, " %s=", stktable_data_types[dt].name);
4527
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004528 ptr = stktable_data_ptr(t, entry, dt);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004529 switch (stktable_data_types[dt].std_type) {
4530 case STD_T_SINT:
4531 chunk_appendf(msg, "%d", stktable_data_cast(ptr, std_t_sint));
4532 break;
4533 case STD_T_UINT:
4534 chunk_appendf(msg, "%u", stktable_data_cast(ptr, std_t_uint));
4535 break;
4536 case STD_T_ULL:
Emeric Brun01928ae2021-06-30 16:24:04 +02004537 chunk_appendf(msg, "%llu", stktable_data_cast(ptr, std_t_ull));
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004538 break;
4539 case STD_T_FRQP:
Emeric Brun01928ae2021-06-30 16:24:04 +02004540 chunk_appendf(msg, "%u",
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004541 read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004542 t->data_arg[dt].u));
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004543 break;
Frédéric Lécaille16b4f542019-05-23 12:15:04 +02004544 case STD_T_DICT: {
4545 struct dict_entry *de;
4546 de = stktable_data_cast(ptr, std_t_dict);
4547 chunk_appendf(msg, "%s", de ? (char *)de->value.key : "-");
4548 break;
4549 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004550 }
4551 }
4552 chunk_appendf(msg, "\n");
4553
Willy Tarreaud0a06d52022-05-18 15:07:19 +02004554 if (applet_putchk(appctx, msg) == -1)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004555 return 0;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004556
4557 return 1;
4558}
4559
Willy Tarreau3c69e082022-05-03 11:35:07 +02004560/* appctx context used by the "show table" command */
4561struct show_table_ctx {
4562 void *target; /* table we want to dump, or NULL for all */
4563 struct stktable *t; /* table being currently dumped (first if NULL) */
4564 struct stksess *entry; /* last entry we were trying to dump (or first if NULL) */
4565 long long value[STKTABLE_FILTER_LEN]; /* value to compare against */
4566 signed char data_type[STKTABLE_FILTER_LEN]; /* type of data to compare, or -1 if none */
4567 signed char data_op[STKTABLE_FILTER_LEN]; /* operator (STD_OP_*) when data_type set */
Willy Tarreau7849d4c2022-05-03 11:45:02 +02004568 enum {
Willy Tarreau0f154ed2022-05-03 12:02:36 +02004569 STATE_NEXT = 0, /* px points to next table, entry=NULL */
Willy Tarreau7849d4c2022-05-03 11:45:02 +02004570 STATE_DUMP, /* px points to curr table, entry is valid, refcount held */
4571 STATE_DONE, /* done dumping */
4572 } state;
Willy Tarreau3c69e082022-05-03 11:35:07 +02004573 char action; /* action on the table : one of STK_CLI_ACT_* */
4574};
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004575
4576/* Processes a single table entry matching a specific key passed in argument.
4577 * returns 0 if wants to be called again, 1 if has ended processing.
4578 */
4579static int table_process_entry_per_key(struct appctx *appctx, char **args)
4580{
Willy Tarreau3c69e082022-05-03 11:35:07 +02004581 struct show_table_ctx *ctx = appctx->svcctx;
4582 struct stktable *t = ctx->target;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004583 struct stksess *ts;
4584 uint32_t uint32_key;
4585 unsigned char ip6_key[sizeof(struct in6_addr)];
4586 long long value;
4587 int data_type;
4588 int cur_arg;
4589 void *ptr;
Willy Tarreaufa1258f2021-04-10 23:00:53 +02004590 struct freq_ctr *frqp;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004591
Willy Tarreau9d008692019-08-09 11:21:01 +02004592 if (!*args[4])
4593 return cli_err(appctx, "Key value expected\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004594
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004595 switch (t->type) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004596 case SMP_T_IPV4:
4597 uint32_key = htonl(inetaddr_host(args[4]));
Christopher Fauletca20d022017-08-29 15:30:31 +02004598 static_table_key.key = &uint32_key;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004599 break;
4600 case SMP_T_IPV6:
Christopher Fauletb7c962b2021-11-15 09:17:25 +01004601 if (inet_pton(AF_INET6, args[4], ip6_key) <= 0)
4602 return cli_err(appctx, "Invalid key\n");
Christopher Fauletca20d022017-08-29 15:30:31 +02004603 static_table_key.key = &ip6_key;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004604 break;
4605 case SMP_T_SINT:
4606 {
4607 char *endptr;
4608 unsigned long val;
4609 errno = 0;
4610 val = strtoul(args[4], &endptr, 10);
4611 if ((errno == ERANGE && val == ULONG_MAX) ||
4612 (errno != 0 && val == 0) || endptr == args[4] ||
Willy Tarreau9d008692019-08-09 11:21:01 +02004613 val > 0xffffffff)
4614 return cli_err(appctx, "Invalid key\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004615 uint32_key = (uint32_t) val;
Christopher Fauletca20d022017-08-29 15:30:31 +02004616 static_table_key.key = &uint32_key;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004617 break;
4618 }
4619 break;
4620 case SMP_T_STR:
Christopher Fauletca20d022017-08-29 15:30:31 +02004621 static_table_key.key = args[4];
4622 static_table_key.key_len = strlen(args[4]);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004623 break;
4624 default:
Willy Tarreau3c69e082022-05-03 11:35:07 +02004625 switch (ctx->action) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004626 case STK_CLI_ACT_SHOW:
Willy Tarreau9d008692019-08-09 11:21:01 +02004627 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 +01004628 case STK_CLI_ACT_CLR:
Willy Tarreau9d008692019-08-09 11:21:01 +02004629 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 +01004630 case STK_CLI_ACT_SET:
Willy Tarreau9d008692019-08-09 11:21:01 +02004631 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 +01004632 default:
Willy Tarreau9d008692019-08-09 11:21:01 +02004633 return cli_err(appctx, "Unknown action\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004634 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004635 }
4636
4637 /* check permissions */
4638 if (!cli_has_level(appctx, ACCESS_LVL_OPER))
4639 return 1;
4640
Willy Tarreau3c69e082022-05-03 11:35:07 +02004641 switch (ctx->action) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004642 case STK_CLI_ACT_SHOW:
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004643 ts = stktable_lookup_key(t, &static_table_key);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004644 if (!ts)
4645 return 1;
4646 chunk_reset(&trash);
Willy Tarreaud0a06d52022-05-18 15:07:19 +02004647 if (!table_dump_head_to_buffer(&trash, appctx, t, t)) {
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004648 stktable_release(t, ts);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004649 return 0;
Emeric Brun819fc6f2017-06-13 19:37:32 +02004650 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004651 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &ts->lock);
Willy Tarreaud0a06d52022-05-18 15:07:19 +02004652 if (!table_dump_entry_to_buffer(&trash, appctx, t, ts)) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004653 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004654 stktable_release(t, ts);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004655 return 0;
Emeric Brun819fc6f2017-06-13 19:37:32 +02004656 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004657 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004658 stktable_release(t, ts);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004659 break;
4660
4661 case STK_CLI_ACT_CLR:
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004662 ts = stktable_lookup_key(t, &static_table_key);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004663 if (!ts)
4664 return 1;
Emeric Brun819fc6f2017-06-13 19:37:32 +02004665
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004666 if (!stksess_kill(t, ts, 1)) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004667 /* don't delete an entry which is currently referenced */
Willy Tarreau9d008692019-08-09 11:21:01 +02004668 return cli_err(appctx, "Entry currently in use, cannot remove\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004669 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004670 break;
4671
4672 case STK_CLI_ACT_SET:
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004673 ts = stktable_get_entry(t, &static_table_key);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004674 if (!ts) {
4675 /* don't delete an entry which is currently referenced */
Willy Tarreau9d008692019-08-09 11:21:01 +02004676 return cli_err(appctx, "Unable to allocate a new entry\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004677 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004678 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004679 for (cur_arg = 5; *args[cur_arg]; cur_arg += 2) {
4680 if (strncmp(args[cur_arg], "data.", 5) != 0) {
Willy Tarreau9d008692019-08-09 11:21:01 +02004681 cli_err(appctx, "\"data.<type>\" followed by a value expected\n");
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004682 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004683 stktable_touch_local(t, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004684 return 1;
4685 }
4686
4687 data_type = stktable_get_data_type(args[cur_arg] + 5);
4688 if (data_type < 0) {
Willy Tarreau9d008692019-08-09 11:21:01 +02004689 cli_err(appctx, "Unknown data type\n");
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004690 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004691 stktable_touch_local(t, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004692 return 1;
4693 }
4694
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004695 if (!t->data_ofs[data_type]) {
Willy Tarreau9d008692019-08-09 11:21:01 +02004696 cli_err(appctx, "Data type not stored in this table\n");
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004697 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004698 stktable_touch_local(t, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004699 return 1;
4700 }
4701
4702 if (!*args[cur_arg+1] || strl2llrc(args[cur_arg+1], strlen(args[cur_arg+1]), &value) != 0) {
Willy Tarreau9d008692019-08-09 11:21:01 +02004703 cli_err(appctx, "Require a valid integer value to store\n");
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004704 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004705 stktable_touch_local(t, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004706 return 1;
4707 }
4708
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004709 ptr = stktable_data_ptr(t, ts, data_type);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004710
4711 switch (stktable_data_types[data_type].std_type) {
4712 case STD_T_SINT:
4713 stktable_data_cast(ptr, std_t_sint) = value;
4714 break;
4715 case STD_T_UINT:
4716 stktable_data_cast(ptr, std_t_uint) = value;
4717 break;
4718 case STD_T_ULL:
4719 stktable_data_cast(ptr, std_t_ull) = value;
4720 break;
4721 case STD_T_FRQP:
4722 /* We set both the current and previous values. That way
4723 * the reported frequency is stable during all the period
4724 * then slowly fades out. This allows external tools to
4725 * push measures without having to update them too often.
4726 */
4727 frqp = &stktable_data_cast(ptr, std_t_frqp);
Willy Tarreaufa1258f2021-04-10 23:00:53 +02004728 /* First bit is reserved for the freq_ctr lock
Emeric Brunf2fc1fd2017-11-02 17:32:43 +01004729 Note: here we're still protected by the stksess lock
Willy Tarreaufa1258f2021-04-10 23:00:53 +02004730 so we don't need to update the update the freq_ctr
Emeric Brunf2fc1fd2017-11-02 17:32:43 +01004731 using its internal lock */
4732 frqp->curr_tick = now_ms & ~0x1;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004733 frqp->prev_ctr = 0;
4734 frqp->curr_ctr = value;
4735 break;
4736 }
4737 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004738 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004739 stktable_touch_local(t, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004740 break;
4741
4742 default:
Willy Tarreau9d008692019-08-09 11:21:01 +02004743 return cli_err(appctx, "Unknown action\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004744 }
4745 return 1;
4746}
4747
4748/* Prepares the appctx fields with the data-based filters from the command line.
4749 * Returns 0 if the dump can proceed, 1 if has ended processing.
4750 */
4751static int table_prepare_data_request(struct appctx *appctx, char **args)
4752{
Willy Tarreau3c69e082022-05-03 11:35:07 +02004753 struct show_table_ctx *ctx = appctx->svcctx;
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004754 int i;
Adis Nezirovicd0142e72020-01-22 16:50:27 +01004755 char *err = NULL;
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004756
Willy Tarreau3c69e082022-05-03 11:35:07 +02004757 if (ctx->action != STK_CLI_ACT_SHOW && ctx->action != STK_CLI_ACT_CLR)
Willy Tarreau9d008692019-08-09 11:21:01 +02004758 return cli_err(appctx, "content-based lookup is only supported with the \"show\" and \"clear\" actions\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004759
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004760 for (i = 0; i < STKTABLE_FILTER_LEN; i++) {
4761 if (i > 0 && !*args[3+3*i]) // number of filter entries can be less than STKTABLE_FILTER_LEN
4762 break;
4763 /* condition on stored data value */
Willy Tarreau3c69e082022-05-03 11:35:07 +02004764 ctx->data_type[i] = stktable_get_data_type(args[3+3*i] + 5);
4765 if (ctx->data_type[i] < 0)
Adis Nezirovicd0142e72020-01-22 16:50:27 +01004766 return cli_dynerr(appctx, memprintf(&err, "Filter entry #%i: Unknown data type\n", i + 1));
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004767
Willy Tarreau3c69e082022-05-03 11:35:07 +02004768 if (!((struct stktable *)ctx->target)->data_ofs[ctx->data_type[i]])
Adis Nezirovicd0142e72020-01-22 16:50:27 +01004769 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 +01004770
Willy Tarreau3c69e082022-05-03 11:35:07 +02004771 ctx->data_op[i] = get_std_op(args[4+3*i]);
4772 if (ctx->data_op[i] < 0)
Adis Nezirovicd0142e72020-01-22 16:50:27 +01004773 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 +01004774
Willy Tarreau3c69e082022-05-03 11:35:07 +02004775 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 +01004776 return cli_dynerr(appctx, memprintf(&err, "Filter entry #%i: Require a valid integer value to compare against\n", i + 1));
4777 }
4778
4779 if (*args[3+3*i]) {
4780 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 +01004781 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004782
4783 /* OK we're done, all the fields are set */
4784 return 0;
4785}
4786
4787/* returns 0 if wants to be called, 1 if has ended processing */
Aurélien Nephtaliabbf6072018-04-18 13:26:46 +02004788static int cli_parse_table_req(char **args, char *payload, struct appctx *appctx, void *private)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004789{
Willy Tarreau3c69e082022-05-03 11:35:07 +02004790 struct show_table_ctx *ctx = applet_reserve_svcctx(appctx, sizeof(*ctx));
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004791 int i;
4792
4793 for (i = 0; i < STKTABLE_FILTER_LEN; i++)
Willy Tarreau3c69e082022-05-03 11:35:07 +02004794 ctx->data_type[i] = -1;
4795 ctx->target = NULL;
4796 ctx->entry = NULL;
4797 ctx->action = (long)private; // keyword argument, one of STK_CLI_ACT_*
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004798
4799 if (*args[2]) {
Willy Tarreau0f154ed2022-05-03 12:02:36 +02004800 ctx->t = ctx->target = stktable_find_by_name(args[2]);
Willy Tarreau3c69e082022-05-03 11:35:07 +02004801 if (!ctx->target)
Willy Tarreau9d008692019-08-09 11:21:01 +02004802 return cli_err(appctx, "No such table\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004803 }
4804 else {
Willy Tarreau0f154ed2022-05-03 12:02:36 +02004805 ctx->t = stktables_list;
Willy Tarreau3c69e082022-05-03 11:35:07 +02004806 if (ctx->action != STK_CLI_ACT_SHOW)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004807 goto err_args;
4808 return 0;
4809 }
4810
4811 if (strcmp(args[3], "key") == 0)
4812 return table_process_entry_per_key(appctx, args);
4813 else if (strncmp(args[3], "data.", 5) == 0)
4814 return table_prepare_data_request(appctx, args);
4815 else if (*args[3])
4816 goto err_args;
4817
4818 return 0;
4819
4820err_args:
Willy Tarreau3c69e082022-05-03 11:35:07 +02004821 switch (ctx->action) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004822 case STK_CLI_ACT_SHOW:
Willy Tarreau9d008692019-08-09 11:21:01 +02004823 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 +01004824 case STK_CLI_ACT_CLR:
Willy Tarreau9d008692019-08-09 11:21:01 +02004825 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 +01004826 case STK_CLI_ACT_SET:
Willy Tarreau9d008692019-08-09 11:21:01 +02004827 return cli_err(appctx, "Required arguments: <table> key <key> [data.<store_data_type> <value>]*\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004828 default:
Willy Tarreau9d008692019-08-09 11:21:01 +02004829 return cli_err(appctx, "Unknown action\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004830 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004831}
4832
4833/* This function is used to deal with table operations (dump or clear depending
4834 * on the action stored in appctx->private). It returns 0 if the output buffer is
4835 * full and it needs to be called again, otherwise non-zero.
4836 */
4837static int cli_io_handler_table(struct appctx *appctx)
4838{
Willy Tarreau3c69e082022-05-03 11:35:07 +02004839 struct show_table_ctx *ctx = appctx->svcctx;
Willy Tarreauc12b3212022-05-27 11:08:15 +02004840 struct stconn *sc = appctx_sc(appctx);
Willy Tarreau475e4632022-05-27 10:26:46 +02004841 struct stream *s = __sc_strm(sc);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004842 struct ebmb_node *eb;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004843 int skip_entry;
Willy Tarreau3c69e082022-05-03 11:35:07 +02004844 int show = ctx->action == STK_CLI_ACT_SHOW;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004845
4846 /*
Willy Tarreau0f154ed2022-05-03 12:02:36 +02004847 * We have 3 possible states in ctx->state :
Willy Tarreau7849d4c2022-05-03 11:45:02 +02004848 * - STATE_NEXT : the proxy pointer points to the next table to
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004849 * dump, the entry pointer is NULL ;
Willy Tarreau7849d4c2022-05-03 11:45:02 +02004850 * - STATE_DUMP : the proxy pointer points to the current table
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004851 * and the entry pointer points to the next entry to be dumped,
4852 * and the refcount on the next entry is held ;
Willy Tarreau7849d4c2022-05-03 11:45:02 +02004853 * - STATE_DONE : nothing left to dump, the buffer may contain some
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004854 * data though.
4855 */
4856
Willy Tarreau475e4632022-05-27 10:26:46 +02004857 if (unlikely(sc_ic(sc)->flags & (CF_WRITE_ERROR|CF_SHUTW))) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004858 /* in case of abort, remove any refcount we might have set on an entry */
Willy Tarreau7849d4c2022-05-03 11:45:02 +02004859 if (ctx->state == STATE_DUMP) {
Willy Tarreau3c69e082022-05-03 11:35:07 +02004860 stksess_kill_if_expired(ctx->t, ctx->entry, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004861 }
4862 return 1;
4863 }
4864
4865 chunk_reset(&trash);
4866
Willy Tarreau7849d4c2022-05-03 11:45:02 +02004867 while (ctx->state != STATE_DONE) {
4868 switch (ctx->state) {
Willy Tarreau7849d4c2022-05-03 11:45:02 +02004869 case STATE_NEXT:
Willy Tarreau3c69e082022-05-03 11:35:07 +02004870 if (!ctx->t ||
4871 (ctx->target &&
4872 ctx->t != ctx->target)) {
Willy Tarreau7849d4c2022-05-03 11:45:02 +02004873 ctx->state = STATE_DONE;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004874 break;
4875 }
4876
Willy Tarreau3c69e082022-05-03 11:35:07 +02004877 if (ctx->t->size) {
Willy Tarreaud0a06d52022-05-18 15:07:19 +02004878 if (show && !table_dump_head_to_buffer(&trash, appctx, ctx->t, ctx->target))
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004879 return 0;
4880
Willy Tarreau3c69e082022-05-03 11:35:07 +02004881 if (ctx->target &&
William Lallemand07a62f72017-05-24 00:57:40 +02004882 (strm_li(s)->bind_conf->level & ACCESS_LVL_MASK) >= ACCESS_LVL_OPER) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004883 /* dump entries only if table explicitly requested */
Willy Tarreau76642222022-10-11 12:02:50 +02004884 HA_RWLOCK_WRLOCK(STK_TABLE_LOCK, &ctx->t->lock);
Willy Tarreau3c69e082022-05-03 11:35:07 +02004885 eb = ebmb_first(&ctx->t->keys);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004886 if (eb) {
Willy Tarreau3c69e082022-05-03 11:35:07 +02004887 ctx->entry = ebmb_entry(eb, struct stksess, key);
4888 ctx->entry->ref_cnt++;
Willy Tarreau7849d4c2022-05-03 11:45:02 +02004889 ctx->state = STATE_DUMP;
Willy Tarreau76642222022-10-11 12:02:50 +02004890 HA_RWLOCK_WRUNLOCK(STK_TABLE_LOCK, &ctx->t->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004891 break;
4892 }
Willy Tarreau76642222022-10-11 12:02:50 +02004893 HA_RWLOCK_WRUNLOCK(STK_TABLE_LOCK, &ctx->t->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004894 }
4895 }
Willy Tarreau3c69e082022-05-03 11:35:07 +02004896 ctx->t = ctx->t->next;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004897 break;
4898
Willy Tarreau7849d4c2022-05-03 11:45:02 +02004899 case STATE_DUMP:
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004900 skip_entry = 0;
4901
Willy Tarreau3c69e082022-05-03 11:35:07 +02004902 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &ctx->entry->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004903
Willy Tarreau3c69e082022-05-03 11:35:07 +02004904 if (ctx->data_type[0] >= 0) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004905 /* we're filtering on some data contents */
4906 void *ptr;
Willy Tarreau2b64a352020-01-22 17:09:47 +01004907 int dt, i;
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004908 signed char op;
4909 long long data, value;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004910
Emeric Brun819fc6f2017-06-13 19:37:32 +02004911
Willy Tarreau2b64a352020-01-22 17:09:47 +01004912 for (i = 0; i < STKTABLE_FILTER_LEN; i++) {
Willy Tarreau3c69e082022-05-03 11:35:07 +02004913 if (ctx->data_type[i] == -1)
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004914 break;
Willy Tarreau3c69e082022-05-03 11:35:07 +02004915 dt = ctx->data_type[i];
4916 ptr = stktable_data_ptr(ctx->t,
4917 ctx->entry,
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004918 dt);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004919
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004920 data = 0;
4921 switch (stktable_data_types[dt].std_type) {
4922 case STD_T_SINT:
4923 data = stktable_data_cast(ptr, std_t_sint);
4924 break;
4925 case STD_T_UINT:
4926 data = stktable_data_cast(ptr, std_t_uint);
4927 break;
4928 case STD_T_ULL:
4929 data = stktable_data_cast(ptr, std_t_ull);
4930 break;
4931 case STD_T_FRQP:
4932 data = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Willy Tarreau3c69e082022-05-03 11:35:07 +02004933 ctx->t->data_arg[dt].u);
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004934 break;
4935 }
4936
Willy Tarreau3c69e082022-05-03 11:35:07 +02004937 op = ctx->data_op[i];
4938 value = ctx->value[i];
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004939
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004940 /* skip the entry if the data does not match the test and the value */
4941 if ((data < value &&
4942 (op == STD_OP_EQ || op == STD_OP_GT || op == STD_OP_GE)) ||
4943 (data == value &&
4944 (op == STD_OP_NE || op == STD_OP_GT || op == STD_OP_LT)) ||
4945 (data > value &&
4946 (op == STD_OP_EQ || op == STD_OP_LT || op == STD_OP_LE))) {
4947 skip_entry = 1;
4948 break;
4949 }
4950 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004951 }
4952
4953 if (show && !skip_entry &&
Willy Tarreaud0a06d52022-05-18 15:07:19 +02004954 !table_dump_entry_to_buffer(&trash, appctx, ctx->t, ctx->entry)) {
Willy Tarreau3c69e082022-05-03 11:35:07 +02004955 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &ctx->entry->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004956 return 0;
4957 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004958
Willy Tarreau3c69e082022-05-03 11:35:07 +02004959 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &ctx->entry->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004960
Willy Tarreau76642222022-10-11 12:02:50 +02004961 HA_RWLOCK_WRLOCK(STK_TABLE_LOCK, &ctx->t->lock);
Willy Tarreau3c69e082022-05-03 11:35:07 +02004962 ctx->entry->ref_cnt--;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004963
Willy Tarreau3c69e082022-05-03 11:35:07 +02004964 eb = ebmb_next(&ctx->entry->key);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004965 if (eb) {
Willy Tarreau3c69e082022-05-03 11:35:07 +02004966 struct stksess *old = ctx->entry;
4967 ctx->entry = ebmb_entry(eb, struct stksess, key);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004968 if (show)
Willy Tarreau3c69e082022-05-03 11:35:07 +02004969 __stksess_kill_if_expired(ctx->t, old);
4970 else if (!skip_entry && !ctx->entry->ref_cnt)
4971 __stksess_kill(ctx->t, old);
4972 ctx->entry->ref_cnt++;
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 break;
4975 }
4976
4977
4978 if (show)
Willy Tarreau3c69e082022-05-03 11:35:07 +02004979 __stksess_kill_if_expired(ctx->t, ctx->entry);
4980 else if (!skip_entry && !ctx->entry->ref_cnt)
4981 __stksess_kill(ctx->t, ctx->entry);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004982
Willy Tarreau76642222022-10-11 12:02:50 +02004983 HA_RWLOCK_WRUNLOCK(STK_TABLE_LOCK, &ctx->t->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004984
Willy Tarreau3c69e082022-05-03 11:35:07 +02004985 ctx->t = ctx->t->next;
Willy Tarreau7849d4c2022-05-03 11:45:02 +02004986 ctx->state = STATE_NEXT;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004987 break;
4988
Willy Tarreau7849d4c2022-05-03 11:45:02 +02004989 default:
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004990 break;
4991 }
4992 }
4993 return 1;
4994}
4995
4996static void cli_release_show_table(struct appctx *appctx)
4997{
Willy Tarreau3c69e082022-05-03 11:35:07 +02004998 struct show_table_ctx *ctx = appctx->svcctx;
4999
Willy Tarreau7849d4c2022-05-03 11:45:02 +02005000 if (ctx->state == STATE_DUMP) {
Willy Tarreau3c69e082022-05-03 11:35:07 +02005001 stksess_kill_if_expired(ctx->t, ctx->entry, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01005002 }
5003}
5004
Willy Tarreau478331d2020-08-28 11:31:31 +02005005static void stkt_late_init(void)
5006{
5007 struct sample_fetch *f;
5008
5009 f = find_sample_fetch("src", strlen("src"));
5010 if (f)
5011 smp_fetch_src = f->process;
5012}
5013
5014INITCALL0(STG_INIT, stkt_late_init);
5015
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01005016/* register cli keywords */
5017static struct cli_kw_list cli_kws = {{ },{
Willy Tarreaub205bfd2021-05-07 11:38:37 +02005018 { { "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 },
5019 { { "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 },
5020 { { "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 +01005021 {{},}
5022}};
5023
Willy Tarreau0108d902018-11-25 19:14:37 +01005024INITCALL1(STG_REGISTER, cli_register_kw, &cli_kws);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01005025
Thierry FOURNIER236657b2015-08-19 08:25:14 +02005026static struct action_kw_list tcp_conn_kws = { { }, {
Emeric Brun4d7ada82021-06-30 19:04:16 +02005027 { "sc-inc-gpc", parse_inc_gpc, KWF_MATCH_PREFIX },
5028 { "sc-inc-gpc0", parse_inc_gpc, KWF_MATCH_PREFIX },
5029 { "sc-inc-gpc1", parse_inc_gpc, KWF_MATCH_PREFIX },
Emeric Brun877b0b52021-06-30 18:57:49 +02005030 { "sc-set-gpt", parse_set_gpt, KWF_MATCH_PREFIX },
5031 { "sc-set-gpt0", parse_set_gpt, KWF_MATCH_PREFIX },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02005032 { /* END */ }
5033}};
5034
Willy Tarreau0108d902018-11-25 19:14:37 +01005035INITCALL1(STG_REGISTER, tcp_req_conn_keywords_register, &tcp_conn_kws);
5036
Willy Tarreau620408f2016-10-21 16:37:51 +02005037static struct action_kw_list tcp_sess_kws = { { }, {
Emeric Brun4d7ada82021-06-30 19:04:16 +02005038 { "sc-inc-gpc", parse_inc_gpc, KWF_MATCH_PREFIX },
5039 { "sc-inc-gpc0", parse_inc_gpc, KWF_MATCH_PREFIX },
5040 { "sc-inc-gpc1", parse_inc_gpc, KWF_MATCH_PREFIX },
Emeric Brun877b0b52021-06-30 18:57:49 +02005041 { "sc-set-gpt", parse_set_gpt, KWF_MATCH_PREFIX },
5042 { "sc-set-gpt0", parse_set_gpt, KWF_MATCH_PREFIX },
Willy Tarreau620408f2016-10-21 16:37:51 +02005043 { /* END */ }
5044}};
5045
Willy Tarreau0108d902018-11-25 19:14:37 +01005046INITCALL1(STG_REGISTER, tcp_req_sess_keywords_register, &tcp_sess_kws);
5047
Thierry FOURNIER236657b2015-08-19 08:25:14 +02005048static struct action_kw_list tcp_req_kws = { { }, {
Emeric Brun4d7ada82021-06-30 19:04:16 +02005049 { "sc-inc-gpc", parse_inc_gpc, KWF_MATCH_PREFIX },
5050 { "sc-inc-gpc0", parse_inc_gpc, KWF_MATCH_PREFIX },
5051 { "sc-inc-gpc1", parse_inc_gpc, KWF_MATCH_PREFIX },
Emeric Brun877b0b52021-06-30 18:57:49 +02005052 { "sc-set-gpt", parse_set_gpt, KWF_MATCH_PREFIX },
5053 { "sc-set-gpt0", parse_set_gpt, KWF_MATCH_PREFIX },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02005054 { /* END */ }
5055}};
5056
Willy Tarreau0108d902018-11-25 19:14:37 +01005057INITCALL1(STG_REGISTER, tcp_req_cont_keywords_register, &tcp_req_kws);
5058
Thierry FOURNIER236657b2015-08-19 08:25:14 +02005059static struct action_kw_list tcp_res_kws = { { }, {
Emeric Brun4d7ada82021-06-30 19:04:16 +02005060 { "sc-inc-gpc", parse_inc_gpc, KWF_MATCH_PREFIX },
5061 { "sc-inc-gpc0", parse_inc_gpc, KWF_MATCH_PREFIX },
5062 { "sc-inc-gpc1", parse_inc_gpc, KWF_MATCH_PREFIX },
Emeric Brun877b0b52021-06-30 18:57:49 +02005063 { "sc-set-gpt", parse_set_gpt, KWF_MATCH_PREFIX },
5064 { "sc-set-gpt0", parse_set_gpt, KWF_MATCH_PREFIX },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02005065 { /* END */ }
5066}};
5067
Willy Tarreau0108d902018-11-25 19:14:37 +01005068INITCALL1(STG_REGISTER, tcp_res_cont_keywords_register, &tcp_res_kws);
5069
Thierry FOURNIER236657b2015-08-19 08:25:14 +02005070static struct action_kw_list http_req_kws = { { }, {
Emeric Brun4d7ada82021-06-30 19:04:16 +02005071 { "sc-inc-gpc", parse_inc_gpc, KWF_MATCH_PREFIX },
5072 { "sc-inc-gpc0", parse_inc_gpc, KWF_MATCH_PREFIX },
5073 { "sc-inc-gpc1", parse_inc_gpc, KWF_MATCH_PREFIX },
Emeric Brun877b0b52021-06-30 18:57:49 +02005074 { "sc-set-gpt", parse_set_gpt, KWF_MATCH_PREFIX },
5075 { "sc-set-gpt0", parse_set_gpt, KWF_MATCH_PREFIX },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02005076 { /* END */ }
5077}};
5078
Willy Tarreau0108d902018-11-25 19:14:37 +01005079INITCALL1(STG_REGISTER, http_req_keywords_register, &http_req_kws);
5080
Thierry FOURNIER236657b2015-08-19 08:25:14 +02005081static struct action_kw_list http_res_kws = { { }, {
Emeric Brun4d7ada82021-06-30 19:04:16 +02005082 { "sc-inc-gpc", parse_inc_gpc, KWF_MATCH_PREFIX },
5083 { "sc-inc-gpc0", parse_inc_gpc, KWF_MATCH_PREFIX },
5084 { "sc-inc-gpc1", parse_inc_gpc, KWF_MATCH_PREFIX },
Emeric Brun877b0b52021-06-30 18:57:49 +02005085 { "sc-set-gpt", parse_set_gpt, KWF_MATCH_PREFIX },
5086 { "sc-set-gpt0", parse_set_gpt, KWF_MATCH_PREFIX },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02005087 { /* END */ }
5088}};
5089
Willy Tarreau0108d902018-11-25 19:14:37 +01005090INITCALL1(STG_REGISTER, http_res_keywords_register, &http_res_kws);
5091
Willy Tarreau7d562212016-11-25 16:10:05 +01005092/* Note: must not be declared <const> as its list will be overwritten.
5093 * Please take care of keeping this list alphabetically sorted.
5094 */
5095static struct sample_fetch_kw_list smp_fetch_keywords = {ILH, {
5096 { "sc_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5097 { "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 +02005098 { "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 +01005099 { "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 +01005100 { "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 +01005101 { "sc_conn_cnt", smp_fetch_sc_conn_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5102 { "sc_conn_cur", smp_fetch_sc_conn_cur, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5103 { "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 +02005104 { "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 +01005105 { "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 +02005106 { "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 +01005107 { "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 +01005108 { "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 +02005109 { "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 +01005110 { "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 +01005111 { "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 +01005112 { "sc_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5113 { "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 +01005114 { "sc_http_fail_cnt", smp_fetch_sc_http_fail_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5115 { "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 +01005116 { "sc_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5117 { "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 +02005118 { "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 +01005119 { "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 +01005120 { "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 +01005121 { "sc_kbytes_in", smp_fetch_sc_kbytes_in, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5122 { "sc_kbytes_out", smp_fetch_sc_kbytes_out, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5123 { "sc_sess_cnt", smp_fetch_sc_sess_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5124 { "sc_sess_rate", smp_fetch_sc_sess_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5125 { "sc_tracked", smp_fetch_sc_tracked, ARG2(1,SINT,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
5126 { "sc_trackers", smp_fetch_sc_trackers, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5127 { "sc0_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5128 { "sc0_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5129 { "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 +01005130 { "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 +01005131 { "sc0_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5132 { "sc0_conn_cur", smp_fetch_sc_conn_cur, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5133 { "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 +01005134 { "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 +01005135 { "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 +01005136 { "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 +01005137 { "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 +01005138 { "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 +01005139 { "sc0_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5140 { "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 +01005141 { "sc0_http_fail_cnt", smp_fetch_sc_http_fail_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5142 { "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 +01005143 { "sc0_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5144 { "sc0_http_req_rate", smp_fetch_sc_http_req_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5145 { "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 +01005146 { "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 +01005147 { "sc0_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5148 { "sc0_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5149 { "sc0_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5150 { "sc0_sess_rate", smp_fetch_sc_sess_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5151 { "sc0_tracked", smp_fetch_sc_tracked, ARG1(0,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
5152 { "sc0_trackers", smp_fetch_sc_trackers, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5153 { "sc1_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5154 { "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 +02005155 { "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 +01005156 { "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 +01005157 { "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 +01005158 { "sc1_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5159 { "sc1_conn_cur", smp_fetch_sc_conn_cur, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5160 { "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 +01005161 { "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 +01005162 { "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 +01005163 { "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 +01005164 { "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 +01005165 { "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 +01005166 { "sc1_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5167 { "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 +01005168 { "sc1_http_fail_cnt", smp_fetch_sc_http_fail_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5169 { "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 +01005170 { "sc1_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5171 { "sc1_http_req_rate", smp_fetch_sc_http_req_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5172 { "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 +01005173 { "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 +01005174 { "sc1_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5175 { "sc1_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5176 { "sc1_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5177 { "sc1_sess_rate", smp_fetch_sc_sess_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5178 { "sc1_tracked", smp_fetch_sc_tracked, ARG1(0,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
5179 { "sc1_trackers", smp_fetch_sc_trackers, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5180 { "sc2_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5181 { "sc2_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5182 { "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 +01005183 { "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 +01005184 { "sc2_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5185 { "sc2_conn_cur", smp_fetch_sc_conn_cur, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5186 { "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 +01005187 { "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 +01005188 { "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 +01005189 { "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 +01005190 { "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 +01005191 { "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 +01005192 { "sc2_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5193 { "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 +01005194 { "sc2_http_fail_cnt", smp_fetch_sc_http_fail_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5195 { "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 +01005196 { "sc2_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5197 { "sc2_http_req_rate", smp_fetch_sc_http_req_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5198 { "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 +01005199 { "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 +01005200 { "sc2_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5201 { "sc2_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5202 { "sc2_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5203 { "sc2_sess_rate", smp_fetch_sc_sess_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5204 { "sc2_tracked", smp_fetch_sc_tracked, ARG1(0,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
5205 { "sc2_trackers", smp_fetch_sc_trackers, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5206 { "src_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5207 { "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 +02005208 { "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 +01005209 { "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 +01005210 { "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 +01005211 { "src_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5212 { "src_conn_cur", smp_fetch_sc_conn_cur, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5213 { "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 +02005214 { "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 +01005215 { "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 +02005216 { "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 +01005217 { "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 +01005218 { "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 +02005219 { "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 +01005220 { "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 +01005221 { "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 +01005222 { "src_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5223 { "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 +01005224 { "src_http_fail_cnt", smp_fetch_sc_http_fail_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5225 { "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 +01005226 { "src_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5227 { "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 +02005228 { "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 +01005229 { "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 +01005230 { "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 +01005231 { "src_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5232 { "src_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5233 { "src_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5234 { "src_sess_rate", smp_fetch_sc_sess_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5235 { "src_updt_conn_cnt", smp_fetch_src_updt_conn_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5236 { "table_avl", smp_fetch_table_avl, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5237 { "table_cnt", smp_fetch_table_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5238 { /* END */ },
5239}};
5240
Willy Tarreau0108d902018-11-25 19:14:37 +01005241INITCALL1(STG_REGISTER, sample_register_fetches, &smp_fetch_keywords);
Willy Tarreau7d562212016-11-25 16:10:05 +01005242
Willy Tarreaud9f316a2014-07-10 14:03:38 +02005243/* Note: must not be declared <const> as its list will be overwritten */
5244static struct sample_conv_kw_list sample_conv_kws = {ILH, {
Willy Tarreau2d17db52016-05-25 17:16:38 +02005245 { "in_table", sample_conv_in_table, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_BOOL },
5246 { "table_bytes_in_rate", sample_conv_table_bytes_in_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5247 { "table_bytes_out_rate", sample_conv_table_bytes_out_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5248 { "table_conn_cnt", sample_conv_table_conn_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5249 { "table_conn_cur", sample_conv_table_conn_cur, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5250 { "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 +02005251 { "table_expire", sample_conv_table_expire, ARG2(1,TAB,SINT), NULL, SMP_T_ANY, SMP_T_SINT },
Emeric Brun877b0b52021-06-30 18:57:49 +02005252 { "table_gpt", sample_conv_table_gpt, ARG2(2,SINT,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
Willy Tarreau2d17db52016-05-25 17:16:38 +02005253 { "table_gpt0", sample_conv_table_gpt0, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
Emeric Brun4d7ada82021-06-30 19:04:16 +02005254 { "table_gpc", sample_conv_table_gpc, ARG2(2,SINT,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
Willy Tarreau2d17db52016-05-25 17:16:38 +02005255 { "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 +01005256 { "table_gpc1", sample_conv_table_gpc1, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
Emeric Brun4d7ada82021-06-30 19:04:16 +02005257 { "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 +02005258 { "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 +01005259 { "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 +02005260 { "table_http_err_cnt", sample_conv_table_http_err_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5261 { "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 +01005262 { "table_http_fail_cnt", sample_conv_table_http_fail_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5263 { "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 +02005264 { "table_http_req_cnt", sample_conv_table_http_req_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5265 { "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 +02005266 { "table_idle", sample_conv_table_idle, ARG2(1,TAB,SINT), NULL, SMP_T_ANY, SMP_T_SINT },
Willy Tarreau2d17db52016-05-25 17:16:38 +02005267 { "table_kbytes_in", sample_conv_table_kbytes_in, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5268 { "table_kbytes_out", sample_conv_table_kbytes_out, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5269 { "table_server_id", sample_conv_table_server_id, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5270 { "table_sess_cnt", sample_conv_table_sess_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5271 { "table_sess_rate", sample_conv_table_sess_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5272 { "table_trackers", sample_conv_table_trackers, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
Willy Tarreaud9f316a2014-07-10 14:03:38 +02005273 { /* END */ },
5274}};
5275
Willy Tarreau0108d902018-11-25 19:14:37 +01005276INITCALL1(STG_REGISTER, sample_register_convs, &sample_conv_kws);