blob: 77a5ba52310143a5f04aa12edc7575706f269ad6 [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
551 /* set both t->exp_next and the task's expire to the newest
552 * expiration date.
553 */
554 old_exp = HA_ATOMIC_LOAD(&t->exp_next);
555 do {
556 new_exp = tick_first(expire, old_exp);
557 } while (new_exp != old_exp &&
558 !HA_ATOMIC_CAS(&t->exp_next, &old_exp, new_exp) &&
559 __ha_cpu_relax());
560
561 old_exp = HA_ATOMIC_LOAD(&t->exp_task->expire);
562 do {
563 new_exp = HA_ATOMIC_LOAD(&t->exp_next);
564 } while (new_exp != old_exp &&
565 !HA_ATOMIC_CAS(&t->exp_task->expire, &old_exp, new_exp) &&
566 __ha_cpu_relax());
567
Willy Tarreaueb23e3e2022-10-12 09:56:08 +0000568 task_queue(t->exp_task);
569}
570
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200571/* Returns a valid or initialized stksess for the specified stktable_key in the
572 * specified table, or NULL if the key was NULL, or if no entry was found nor
Willy Tarreau47f22972022-10-11 15:22:42 +0200573 * could be created. The entry's expiration is updated. This function locks the
574 * table, and the refcount of the entry is increased.
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200575 */
Willy Tarreau47f22972022-10-11 15:22:42 +0200576struct stksess *stktable_get_entry(struct stktable *table, struct stktable_key *key)
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200577{
Willy Tarreau175aa062022-10-11 15:13:46 +0200578 struct stksess *ts, *ts2;
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200579
580 if (!key)
581 return NULL;
582
Willy Tarreau47f22972022-10-11 15:22:42 +0200583 ts = stktable_lookup_key(table, key);
584 if (ts)
585 return ts;
Emeric Brun819fc6f2017-06-13 19:37:32 +0200586
Willy Tarreau996f1a52022-10-11 16:19:35 +0200587 /* No such entry exists, let's try to create a new one. this doesn't
588 * require locking yet.
589 */
590
591 ts = stksess_new(table, key);
592 if (!ts)
593 return NULL;
594
595 /* Now we're certain to have a ts. We need to store it. For this we'll
Willy Tarreau47f22972022-10-11 15:22:42 +0200596 * need an exclusive access. We don't need an atomic upgrade, this is
597 * rare and an unlock+lock sequence will do the job fine. Given that
598 * this will not be atomic, the missing entry might appear in the mean
599 * tome so we have to be careful that the one we try to insert is the
600 * one we find.
601 */
Willy Tarreau47f22972022-10-11 15:22:42 +0200602
Willy Tarreau996f1a52022-10-11 16:19:35 +0200603 HA_RWLOCK_WRLOCK(STK_TABLE_LOCK, &table->lock);
Willy Tarreau47f22972022-10-11 15:22:42 +0200604
605 ts2 = __stktable_store(table, ts);
606 if (unlikely(ts2 != ts)) {
607 /* another entry was added in the mean time, let's
608 * switch to it.
609 */
610 __stksess_free(table, ts);
611 ts = ts2;
612 }
613
614 HA_ATOMIC_INC(&ts->ref_cnt);
Willy Tarreau76642222022-10-11 12:02:50 +0200615 HA_RWLOCK_WRUNLOCK(STK_TABLE_LOCK, &table->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200616
Willy Tarreaucbdb5282022-10-12 10:04:01 +0000617 stktable_requeue_exp(table, ts);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200618 return ts;
619}
620
621/* Lookup for an entry with the same key and store the submitted
Willy Tarreaue6288522022-10-12 09:13:14 +0000622 * stksess if not found. This function locks the table either shared or
623 * exclusively, and the refcount of the entry is increased.
Emeric Brun819fc6f2017-06-13 19:37:32 +0200624 */
Willy Tarreaue6288522022-10-12 09:13:14 +0000625struct stksess *stktable_set_entry(struct stktable *table, struct stksess *nts)
Emeric Brun819fc6f2017-06-13 19:37:32 +0200626{
627 struct stksess *ts;
628
Willy Tarreaue6288522022-10-12 09:13:14 +0000629 HA_RWLOCK_RDLOCK(STK_TABLE_LOCK, &table->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200630 ts = __stktable_lookup(table, nts);
Willy Tarreaue6288522022-10-12 09:13:14 +0000631 if (ts) {
632 HA_ATOMIC_INC(&ts->ref_cnt);
633 HA_RWLOCK_RDUNLOCK(STK_TABLE_LOCK, &table->lock);
634 return ts;
Emeric Brun819fc6f2017-06-13 19:37:32 +0200635 }
Willy Tarreaue6288522022-10-12 09:13:14 +0000636 ts = nts;
Emeric Brun819fc6f2017-06-13 19:37:32 +0200637
Willy Tarreaue6288522022-10-12 09:13:14 +0000638 /* let's increment it before switching to exclusive */
639 HA_ATOMIC_INC(&ts->ref_cnt);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200640
Willy Tarreaue6288522022-10-12 09:13:14 +0000641 if (HA_RWLOCK_TRYRDTOSK(STK_TABLE_LOCK, &table->lock) != 0) {
642 /* upgrade to seek lock failed, let's drop and take */
643 HA_RWLOCK_RDUNLOCK(STK_TABLE_LOCK, &table->lock);
644 HA_RWLOCK_WRLOCK(STK_TABLE_LOCK, &table->lock);
645 }
646 else
647 HA_RWLOCK_SKTOWR(STK_TABLE_LOCK, &table->lock);
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200648
Willy Tarreaue6288522022-10-12 09:13:14 +0000649 /* now we're write-locked */
650
651 __stktable_store(table, ts);
652 HA_RWLOCK_WRUNLOCK(STK_TABLE_LOCK, &table->lock);
Willy Tarreaucbdb5282022-10-12 10:04:01 +0000653
654 stktable_requeue_exp(table, ts);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200655 return ts;
656}
Willy Tarreaue6288522022-10-12 09:13:14 +0000657
Emeric Brun3bd697e2010-01-04 15:23:48 +0100658/*
Willy Tarreauaea940e2010-06-06 11:56:36 +0200659 * Trash expired sticky sessions from table <t>. The next expiration date is
660 * returned.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100661 */
662static int stktable_trash_expired(struct stktable *t)
663{
664 struct stksess *ts;
665 struct eb32_node *eb;
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200666 int looped = 0;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100667
Willy Tarreau76642222022-10-11 12:02:50 +0200668 HA_RWLOCK_WRLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100669 eb = eb32_lookup_ge(&t->exps, now_ms - TIMER_LOOK_BACK);
670
671 while (1) {
672 if (unlikely(!eb)) {
673 /* we might have reached the end of the tree, typically because
674 * <now_ms> is in the first half and we're first scanning the last
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200675 * half. Let's loop back to the beginning of the tree now if we
676 * have not yet visited it.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100677 */
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200678 if (looped)
679 break;
680 looped = 1;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100681 eb = eb32_first(&t->exps);
682 if (likely(!eb))
683 break;
684 }
685
686 if (likely(tick_is_lt(now_ms, eb->key))) {
687 /* timer not expired yet, revisit it later */
688 t->exp_next = eb->key;
Willy Tarreau4d5f13c2017-11-05 11:04:47 +0100689 goto out_unlock;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100690 }
691
692 /* timer looks expired, detach it from the queue */
Willy Tarreau86257dc2010-06-06 12:57:10 +0200693 ts = eb32_entry(eb, struct stksess, exp);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100694 eb = eb32_next(eb);
695
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200696 /* don't delete an entry which is currently referenced */
697 if (ts->ref_cnt)
698 continue;
699
Willy Tarreau86257dc2010-06-06 12:57:10 +0200700 eb32_delete(&ts->exp);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100701
702 if (!tick_is_expired(ts->expire, now_ms)) {
703 if (!tick_isset(ts->expire))
704 continue;
705
Willy Tarreau86257dc2010-06-06 12:57:10 +0200706 ts->exp.key = ts->expire;
707 eb32_insert(&t->exps, &ts->exp);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100708
Willy Tarreau86257dc2010-06-06 12:57:10 +0200709 if (!eb || eb->key > ts->exp.key)
710 eb = &ts->exp;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100711 continue;
712 }
713
714 /* session expired, trash it */
Willy Tarreau86257dc2010-06-06 12:57:10 +0200715 ebmb_delete(&ts->key);
Emeric Brun85e77c72010-09-23 18:16:52 +0200716 eb32_delete(&ts->upd);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200717 __stksess_free(t, ts);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100718 }
719
720 /* We have found no task to expire in any tree */
721 t->exp_next = TICK_ETERNITY;
Willy Tarreau4d5f13c2017-11-05 11:04:47 +0100722out_unlock:
Willy Tarreau76642222022-10-11 12:02:50 +0200723 HA_RWLOCK_WRUNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100724 return t->exp_next;
725}
726
727/*
Willy Tarreauaea940e2010-06-06 11:56:36 +0200728 * Task processing function to trash expired sticky sessions. A pointer to the
729 * task itself is returned since it never dies.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100730 */
Willy Tarreau144f84a2021-03-02 16:09:26 +0100731struct task *process_table_expire(struct task *task, void *context, unsigned int state)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100732{
Olivier Houchard9f6af332018-05-25 14:04:04 +0200733 struct stktable *t = context;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100734
735 task->expire = stktable_trash_expired(t);
736 return task;
737}
738
Willy Tarreauaea940e2010-06-06 11:56:36 +0200739/* Perform minimal stick table intializations, report 0 in case of error, 1 if OK. */
Emeric Brun3bd697e2010-01-04 15:23:48 +0100740int stktable_init(struct stktable *t)
741{
Remi Tricot-Le Breton208ff012021-05-12 17:39:04 +0200742 int peers_retval = 0;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100743 if (t->size) {
Emeric Brun819fc6f2017-06-13 19:37:32 +0200744 t->keys = EB_ROOT_UNIQUE;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100745 memset(&t->exps, 0, sizeof(t->exps));
Emeric Brun1c6235d2015-12-16 15:28:12 +0100746 t->updates = EB_ROOT_UNIQUE;
Amaury Denoyelle3e064882022-10-12 16:47:59 +0200747 HA_RWLOCK_INIT(&t->lock);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100748
Olivier Houchard52dabbc2018-11-14 17:54:36 +0100749 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 +0100750
751 t->exp_next = TICK_ETERNITY;
752 if ( t->expire ) {
Willy Tarreaubeeabf52021-10-01 18:23:30 +0200753 t->exp_task = task_new_anywhere();
Willy Tarreau848522f2018-10-15 11:12:15 +0200754 if (!t->exp_task)
755 return 0;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100756 t->exp_task->process = process_table_expire;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100757 t->exp_task->context = (void *)t;
758 }
Christopher Fauletdfd10ab2021-10-06 14:24:19 +0200759 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 +0200760 peers_retval = peers_register_table(t->peers.p, t);
Emeric Brun32da3c42010-09-23 18:39:19 +0200761 }
762
Remi Tricot-Le Breton208ff012021-05-12 17:39:04 +0200763 return (t->pool != NULL) && !peers_retval;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100764 }
765 return 1;
766}
767
768/*
769 * Configuration keywords of known table types
770 */
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200771struct stktable_type stktable_types[SMP_TYPES] = {
772 [SMP_T_SINT] = { "integer", 0, 4 },
773 [SMP_T_IPV4] = { "ip", 0, 4 },
774 [SMP_T_IPV6] = { "ipv6", 0, 16 },
775 [SMP_T_STR] = { "string", STK_F_CUSTOM_KEYSIZE, 32 },
776 [SMP_T_BIN] = { "binary", STK_F_CUSTOM_KEYSIZE, 32 }
777};
Emeric Brun3bd697e2010-01-04 15:23:48 +0100778
779/*
780 * Parse table type configuration.
781 * Returns 0 on successful parsing, else 1.
782 * <myidx> is set at next configuration <args> index.
783 */
784int stktable_parse_type(char **args, int *myidx, unsigned long *type, size_t *key_size)
785{
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200786 for (*type = 0; *type < SMP_TYPES; (*type)++) {
787 if (!stktable_types[*type].kw)
788 continue;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100789 if (strcmp(args[*myidx], stktable_types[*type].kw) != 0)
790 continue;
791
792 *key_size = stktable_types[*type].default_size;
793 (*myidx)++;
794
Willy Tarreauaea940e2010-06-06 11:56:36 +0200795 if (stktable_types[*type].flags & STK_F_CUSTOM_KEYSIZE) {
Emeric Brun3bd697e2010-01-04 15:23:48 +0100796 if (strcmp("len", args[*myidx]) == 0) {
797 (*myidx)++;
798 *key_size = atol(args[*myidx]);
Emeric Brun485479d2010-09-23 18:02:19 +0200799 if (!*key_size)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100800 break;
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200801 if (*type == SMP_T_STR) {
Emeric Brun485479d2010-09-23 18:02:19 +0200802 /* null terminated string needs +1 for '\0'. */
803 (*key_size)++;
804 }
Emeric Brun3bd697e2010-01-04 15:23:48 +0100805 (*myidx)++;
806 }
807 }
808 return 0;
809 }
810 return 1;
811}
812
Emeric Brunc64a2a32021-06-30 18:01:02 +0200813/* reserve some space for data type <type>, there is 2 optionnals
814 * argument at <sa> and <sa2> to configure this data type and
815 * they can be NULL if unused for a given type.
816 * Returns PE_NONE (0) if OK or an error code among :
Willy Tarreau3b63ca22021-05-08 14:10:42 +0200817 * - PE_ENUM_OOR if <type> does not exist
818 * - PE_EXIST if <type> is already registered
Emeric Brunc64a2a32021-06-30 18:01:02 +0200819 * - PE_ARG_NOT_USE if <sa>/<sa2> was provided but not expected
820 * - PE_ARG_MISSING if <sa>/<sa2> was expected but not provided
821 * - PE_ARG_VALUE_OOR if type is an array and <sa> it out of array size range.
Willy Tarreau3b63ca22021-05-08 14:10:42 +0200822 */
Emeric Brunc64a2a32021-06-30 18:01:02 +0200823int stktable_alloc_data_type(struct stktable *t, int type, const char *sa, const char *sa2)
824
Willy Tarreau3b63ca22021-05-08 14:10:42 +0200825{
826 if (type >= STKTABLE_DATA_TYPES)
827 return PE_ENUM_OOR;
828
829 if (t->data_ofs[type])
830 /* already allocated */
831 return PE_EXIST;
832
Emeric Brunc64a2a32021-06-30 18:01:02 +0200833 t->data_nbelem[type] = 1;
834 if (stktable_data_types[type].is_array) {
835 /* arrays take their element count on first argument */
836 if (!sa)
837 return PE_ARG_MISSING;
838 t->data_nbelem[type] = atoi(sa);
839 if (!t->data_nbelem[type] || (t->data_nbelem[type] > STKTABLE_MAX_DT_ARRAY_SIZE))
840 return PE_ARG_VALUE_OOR;
841 sa = sa2;
842 }
843
Willy Tarreau3b63ca22021-05-08 14:10:42 +0200844 switch (stktable_data_types[type].arg_type) {
845 case ARG_T_NONE:
846 if (sa)
847 return PE_ARG_NOT_USED;
848 break;
849 case ARG_T_INT:
850 if (!sa)
851 return PE_ARG_MISSING;
852 t->data_arg[type].i = atoi(sa);
853 break;
854 case ARG_T_DELAY:
855 if (!sa)
856 return PE_ARG_MISSING;
857 sa = parse_time_err(sa, &t->data_arg[type].u, TIME_UNIT_MS);
858 if (sa)
859 return PE_ARG_INVC; /* invalid char */
860 break;
861 }
862
Emeric Brunc64a2a32021-06-30 18:01:02 +0200863 t->data_size += t->data_nbelem[type] * stktable_type_size(stktable_data_types[type].std_type);
Willy Tarreau3b63ca22021-05-08 14:10:42 +0200864 t->data_ofs[type] = -t->data_size;
865 return PE_NONE;
866}
867
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100868/*
Frédéric Lécaillec02766a2019-03-20 15:06:55 +0100869 * Parse a line with <linenum> as number in <file> configuration file to configure
870 * the stick-table with <t> as address and <id> as ID.
871 * <peers> provides the "peers" section pointer only if this function is called
872 * from a "peers" section.
873 * <nid> is the stick-table name which is sent over the network. It must be equal
874 * to <id> if this stick-table is parsed from a proxy section, and prefixed by <peers>
875 * "peers" section name followed by a '/' character if parsed from a "peers" section.
Ilya Shipitsind4259502020-04-08 01:07:56 +0500876 * This is the responsibility of the caller to check this.
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100877 * Return an error status with ERR_* flags set if required, 0 if no error was encountered.
878 */
879int parse_stick_table(const char *file, int linenum, char **args,
Frédéric Lécaillec02766a2019-03-20 15:06:55 +0100880 struct stktable *t, char *id, char *nid, struct peers *peers)
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100881{
882 int err_code = 0;
883 int idx = 1;
884 unsigned int val;
885
886 if (!id || !*id) {
887 ha_alert("parsing [%s:%d] : %s: ID not provided.\n", file, linenum, args[0]);
888 err_code |= ERR_ALERT | ERR_ABORT;
889 goto out;
890 }
891
892 /* Store the "peers" section if this function is called from a "peers" section. */
893 if (peers) {
894 t->peers.p = peers;
895 idx++;
896 }
897
898 t->id = id;
Frédéric Lécaille36d15652022-10-17 14:58:19 +0200899 t->idlen = strlen(id);
Frédéric Lécaillec02766a2019-03-20 15:06:55 +0100900 t->nid = nid;
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100901 t->type = (unsigned int)-1;
902 t->conf.file = file;
903 t->conf.line = linenum;
904
905 while (*args[idx]) {
906 const char *err;
907
908 if (strcmp(args[idx], "size") == 0) {
909 idx++;
910 if (!*(args[idx])) {
911 ha_alert("parsing [%s:%d] : %s: missing argument after '%s'.\n",
912 file, linenum, args[0], args[idx-1]);
913 err_code |= ERR_ALERT | ERR_FATAL;
914 goto out;
915 }
916 if ((err = parse_size_err(args[idx], &t->size))) {
917 ha_alert("parsing [%s:%d] : %s: unexpected character '%c' in argument of '%s'.\n",
918 file, linenum, args[0], *err, args[idx-1]);
919 err_code |= ERR_ALERT | ERR_FATAL;
920 goto out;
921 }
922 idx++;
923 }
924 /* This argument does not exit in "peers" section. */
925 else if (!peers && strcmp(args[idx], "peers") == 0) {
926 idx++;
927 if (!*(args[idx])) {
928 ha_alert("parsing [%s:%d] : %s: missing argument after '%s'.\n",
929 file, linenum, args[0], args[idx-1]);
930 err_code |= ERR_ALERT | ERR_FATAL;
931 goto out;
932 }
933 t->peers.name = strdup(args[idx++]);
934 }
935 else if (strcmp(args[idx], "expire") == 0) {
936 idx++;
937 if (!*(args[idx])) {
938 ha_alert("parsing [%s:%d] : %s: missing argument after '%s'.\n",
939 file, linenum, args[0], args[idx-1]);
940 err_code |= ERR_ALERT | ERR_FATAL;
941 goto out;
942 }
943 err = parse_time_err(args[idx], &val, TIME_UNIT_MS);
Willy Tarreau9faebe32019-06-07 19:00:37 +0200944 if (err == PARSE_TIME_OVER) {
945 ha_alert("parsing [%s:%d]: %s: timer overflow in argument <%s> to <%s>, maximum value is 2147483647 ms (~24.8 days).\n",
946 file, linenum, args[0], args[idx], args[idx-1]);
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100947 err_code |= ERR_ALERT | ERR_FATAL;
948 goto out;
949 }
Willy Tarreau9faebe32019-06-07 19:00:37 +0200950 else if (err == PARSE_TIME_UNDER) {
951 ha_alert("parsing [%s:%d]: %s: timer underflow in argument <%s> to <%s>, minimum non-null value is 1 ms.\n",
952 file, linenum, args[0], args[idx], args[idx-1]);
953 err_code |= ERR_ALERT | ERR_FATAL;
954 goto out;
955 }
956 else if (err) {
957 ha_alert("parsing [%s:%d] : %s: unexpected character '%c' in argument of '%s'.\n",
958 file, linenum, args[0], *err, args[idx-1]);
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100959 err_code |= ERR_ALERT | ERR_FATAL;
960 goto out;
961 }
962 t->expire = val;
963 idx++;
964 }
965 else if (strcmp(args[idx], "nopurge") == 0) {
966 t->nopurge = 1;
967 idx++;
968 }
969 else if (strcmp(args[idx], "type") == 0) {
970 idx++;
971 if (stktable_parse_type(args, &idx, &t->type, &t->key_size) != 0) {
972 ha_alert("parsing [%s:%d] : %s: unknown type '%s'.\n",
973 file, linenum, args[0], args[idx]);
974 err_code |= ERR_ALERT | ERR_FATAL;
975 goto out;
976 }
977 /* idx already points to next arg */
978 }
979 else if (strcmp(args[idx], "store") == 0) {
980 int type, err;
Emeric Brunc64a2a32021-06-30 18:01:02 +0200981 char *cw, *nw, *sa, *sa2;
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100982
983 idx++;
984 nw = args[idx];
985 while (*nw) {
986 /* the "store" keyword supports a comma-separated list */
987 cw = nw;
988 sa = NULL; /* store arg */
Emeric Brunc64a2a32021-06-30 18:01:02 +0200989 sa2 = NULL;
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100990 while (*nw && *nw != ',') {
991 if (*nw == '(') {
992 *nw = 0;
993 sa = ++nw;
994 while (*nw != ')') {
995 if (!*nw) {
996 ha_alert("parsing [%s:%d] : %s: missing closing parenthesis after store option '%s'.\n",
997 file, linenum, args[0], cw);
998 err_code |= ERR_ALERT | ERR_FATAL;
999 goto out;
1000 }
Emeric Brunc64a2a32021-06-30 18:01:02 +02001001 if (*nw == ',') {
1002 *nw = '\0';
1003 sa2 = nw + 1;
1004 }
Frédéric Lécailled456aa42019-03-08 14:47:00 +01001005 nw++;
1006 }
1007 *nw = '\0';
1008 }
1009 nw++;
1010 }
1011 if (*nw)
1012 *nw++ = '\0';
1013 type = stktable_get_data_type(cw);
1014 if (type < 0) {
1015 ha_alert("parsing [%s:%d] : %s: unknown store option '%s'.\n",
1016 file, linenum, args[0], cw);
1017 err_code |= ERR_ALERT | ERR_FATAL;
1018 goto out;
1019 }
1020
Emeric Brunc64a2a32021-06-30 18:01:02 +02001021 err = stktable_alloc_data_type(t, type, sa, sa2);
Frédéric Lécailled456aa42019-03-08 14:47:00 +01001022 switch (err) {
1023 case PE_NONE: break;
1024 case PE_EXIST:
1025 ha_warning("parsing [%s:%d]: %s: store option '%s' already enabled, ignored.\n",
1026 file, linenum, args[0], cw);
1027 err_code |= ERR_WARN;
1028 break;
1029
1030 case PE_ARG_MISSING:
1031 ha_alert("parsing [%s:%d] : %s: missing argument to store option '%s'.\n",
1032 file, linenum, args[0], cw);
1033 err_code |= ERR_ALERT | ERR_FATAL;
1034 goto out;
1035
1036 case PE_ARG_NOT_USED:
1037 ha_alert("parsing [%s:%d] : %s: unexpected argument to store option '%s'.\n",
1038 file, linenum, args[0], cw);
1039 err_code |= ERR_ALERT | ERR_FATAL;
1040 goto out;
Emeric Brunc64a2a32021-06-30 18:01:02 +02001041 case PE_ARG_VALUE_OOR:
1042 ha_alert("parsing [%s:%d] : %s: array size is out of allowed range (1-%d) for store option '%s'.\n",
1043 file, linenum, args[0], STKTABLE_MAX_DT_ARRAY_SIZE, cw);
1044 err_code |= ERR_ALERT | ERR_FATAL;
1045 goto out;
Frédéric Lécailled456aa42019-03-08 14:47:00 +01001046
1047 default:
1048 ha_alert("parsing [%s:%d] : %s: error when processing store option '%s'.\n",
1049 file, linenum, args[0], cw);
1050 err_code |= ERR_ALERT | ERR_FATAL;
1051 goto out;
1052 }
1053 }
1054 idx++;
Emeric Brunf7ab0bf2021-06-30 18:58:22 +02001055 if (t->data_ofs[STKTABLE_DT_GPT] && t->data_ofs[STKTABLE_DT_GPT0]) {
1056 ha_alert("parsing [%s:%d] : %s: simultaneous usage of 'gpt' and 'gpt0' in a same table is not permitted as 'gpt' overrides 'gpt0'.\n",
1057 file, linenum, args[0]);
1058 err_code |= ERR_ALERT | ERR_FATAL;
1059 goto out;
1060 }
Emeric Brun726783d2021-06-30 19:06:43 +02001061 else if (t->data_ofs[STKTABLE_DT_GPC] && (t->data_ofs[STKTABLE_DT_GPC0] || t->data_ofs[STKTABLE_DT_GPC1])) {
1062 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",
1063 file, linenum, args[0]);
1064 err_code |= ERR_ALERT | ERR_FATAL;
1065 goto out;
1066 }
1067 else if (t->data_ofs[STKTABLE_DT_GPC_RATE] && (t->data_ofs[STKTABLE_DT_GPC0_RATE] || t->data_ofs[STKTABLE_DT_GPC1_RATE])) {
1068 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",
1069 file, linenum, args[0]);
1070 err_code |= ERR_ALERT | ERR_FATAL;
1071 goto out;
1072 }
Frédéric Lécailled456aa42019-03-08 14:47:00 +01001073 }
Thayne McCombs92149f92020-11-20 01:28:26 -07001074 else if (strcmp(args[idx], "srvkey") == 0) {
1075 char *keytype;
1076 idx++;
1077 keytype = args[idx];
1078 if (strcmp(keytype, "name") == 0) {
1079 t->server_key_type = STKTABLE_SRV_NAME;
1080 }
1081 else if (strcmp(keytype, "addr") == 0) {
1082 t->server_key_type = STKTABLE_SRV_ADDR;
1083 }
1084 else {
1085 ha_alert("parsing [%s:%d] : %s : unknown server key type '%s'.\n",
1086 file, linenum, args[0], keytype);
1087 err_code |= ERR_ALERT | ERR_FATAL;
1088 goto out;
1089
1090 }
1091 idx++;
1092 }
Frédéric Lécailled456aa42019-03-08 14:47:00 +01001093 else {
1094 ha_alert("parsing [%s:%d] : %s: unknown argument '%s'.\n",
1095 file, linenum, args[0], args[idx]);
1096 err_code |= ERR_ALERT | ERR_FATAL;
1097 goto out;
1098 }
1099 }
1100
1101 if (!t->size) {
1102 ha_alert("parsing [%s:%d] : %s: missing size.\n",
1103 file, linenum, args[0]);
1104 err_code |= ERR_ALERT | ERR_FATAL;
1105 goto out;
1106 }
1107
1108 if (t->type == (unsigned int)-1) {
1109 ha_alert("parsing [%s:%d] : %s: missing type.\n",
1110 file, linenum, args[0]);
1111 err_code |= ERR_ALERT | ERR_FATAL;
1112 goto out;
1113 }
1114
1115 out:
1116 return err_code;
1117}
1118
Willy Tarreau8fed9032014-07-03 17:02:46 +02001119/* Prepares a stktable_key from a sample <smp> to search into table <t>.
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001120 * Note that the sample *is* modified and that the returned key may point
1121 * to it, so the sample must not be modified afterwards before the lookup.
Willy Tarreau8fed9032014-07-03 17:02:46 +02001122 * Returns NULL if the sample could not be converted (eg: no matching type),
1123 * otherwise a pointer to the static stktable_key filled with what is needed
1124 * for the lookup.
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001125 */
Willy Tarreau8fed9032014-07-03 17:02:46 +02001126struct stktable_key *smp_to_stkey(struct sample *smp, struct stktable *t)
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001127{
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001128 /* Convert sample. */
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +02001129 if (!sample_convert(smp, t->type))
Willy Tarreau7fc1c6e2012-04-26 11:03:17 +02001130 return NULL;
1131
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001132 /* Fill static_table_key. */
1133 switch (t->type) {
Emeric Brun485479d2010-09-23 18:02:19 +02001134
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +02001135 case SMP_T_IPV4:
Christopher Fauletca20d022017-08-29 15:30:31 +02001136 static_table_key.key = &smp->data.u.ipv4;
1137 static_table_key.key_len = 4;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001138 break;
Emeric Brun485479d2010-09-23 18:02:19 +02001139
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +02001140 case SMP_T_IPV6:
Christopher Fauletca20d022017-08-29 15:30:31 +02001141 static_table_key.key = &smp->data.u.ipv6;
1142 static_table_key.key_len = 16;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001143 break;
Emeric Brun485479d2010-09-23 18:02:19 +02001144
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +02001145 case SMP_T_SINT:
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001146 /* The stick table require a 32bit unsigned int, "sint" is a
1147 * signed 64 it, so we can convert it inplace.
1148 */
Willy Tarreau28c63c12019-10-23 06:21:05 +02001149 smp->data.u.sint = (unsigned int)smp->data.u.sint;
Christopher Fauletca20d022017-08-29 15:30:31 +02001150 static_table_key.key = &smp->data.u.sint;
1151 static_table_key.key_len = 4;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001152 break;
1153
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +02001154 case SMP_T_STR:
Willy Tarreauce6955e2016-08-09 11:59:12 +02001155 if (!smp_make_safe(smp))
1156 return NULL;
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001157 static_table_key.key = smp->data.u.str.area;
1158 static_table_key.key_len = smp->data.u.str.data;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001159 break;
Emeric Brun485479d2010-09-23 18:02:19 +02001160
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +02001161 case SMP_T_BIN:
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001162 if (smp->data.u.str.data < t->key_size) {
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001163 /* This type needs padding with 0. */
Willy Tarreauf65c6c02016-08-09 12:08:41 +02001164 if (!smp_make_rw(smp))
1165 return NULL;
1166
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001167 if (smp->data.u.str.size < t->key_size)
1168 if (!smp_dup(smp))
1169 return NULL;
1170 if (smp->data.u.str.size < t->key_size)
1171 return NULL;
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001172 memset(smp->data.u.str.area + smp->data.u.str.data, 0,
1173 t->key_size - smp->data.u.str.data);
1174 smp->data.u.str.data = t->key_size;
Emeric Brun485479d2010-09-23 18:02:19 +02001175 }
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001176 static_table_key.key = smp->data.u.str.area;
1177 static_table_key.key_len = smp->data.u.str.data;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001178 break;
Emeric Brun485479d2010-09-23 18:02:19 +02001179
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001180 default: /* impossible case. */
1181 return NULL;
Emeric Brun485479d2010-09-23 18:02:19 +02001182 }
1183
Christopher Fauletca20d022017-08-29 15:30:31 +02001184 return &static_table_key;
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001185}
1186
1187/*
Willy Tarreau8fed9032014-07-03 17:02:46 +02001188 * Process a fetch + format conversion as defined by the sample expression <expr>
1189 * on request or response considering the <opt> parameter. Returns either NULL if
1190 * no key could be extracted, or a pointer to the converted result stored in
1191 * static_table_key in format <table_type>. If <smp> is not NULL, it will be reset
1192 * and its flags will be initialized so that the caller gets a copy of the input
Willy Tarreau6bcb0a82014-07-30 08:56:35 +02001193 * sample, and knows why it was not accepted (eg: SMP_F_MAY_CHANGE is present
1194 * without SMP_OPT_FINAL). The output will be usable like this :
1195 *
1196 * return MAY_CHANGE FINAL Meaning for the sample
1197 * NULL 0 * Not present and will never be (eg: header)
1198 * NULL 1 0 Not present or unstable, could change (eg: req_len)
1199 * NULL 1 1 Not present, will not change anymore
1200 * smp 0 * Present and will not change (eg: header)
1201 * smp 1 0 not possible
1202 * smp 1 1 Present, last known value (eg: request length)
Willy Tarreau8fed9032014-07-03 17:02:46 +02001203 */
Willy Tarreau192252e2015-04-04 01:47:55 +02001204struct stktable_key *stktable_fetch_key(struct stktable *t, struct proxy *px, struct session *sess, struct stream *strm,
Willy Tarreau8fed9032014-07-03 17:02:46 +02001205 unsigned int opt, struct sample_expr *expr, struct sample *smp)
1206{
1207 if (smp)
1208 memset(smp, 0, sizeof(*smp));
1209
Willy Tarreau192252e2015-04-04 01:47:55 +02001210 smp = sample_process(px, sess, strm, opt, expr, smp);
Willy Tarreau8fed9032014-07-03 17:02:46 +02001211 if (!smp)
1212 return NULL;
1213
1214 if ((smp->flags & SMP_F_MAY_CHANGE) && !(opt & SMP_OPT_FINAL))
1215 return NULL; /* we can only use stable samples */
1216
1217 return smp_to_stkey(smp, t);
1218}
1219
1220/*
Willy Tarreau12785782012-04-27 21:37:17 +02001221 * Returns 1 if sample expression <expr> result can be converted to table key of
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001222 * type <table_type>, otherwise zero. Used in configuration check.
1223 */
Willy Tarreau12785782012-04-27 21:37:17 +02001224int stktable_compatible_sample(struct sample_expr *expr, unsigned long table_type)
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001225{
Thierry FOURNIERf73eb8f2013-11-27 15:30:55 +01001226 int out_type;
1227
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +02001228 if (table_type >= SMP_TYPES || !stktable_types[table_type].kw)
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001229 return 0;
1230
Thierry FOURNIERf73eb8f2013-11-27 15:30:55 +01001231 out_type = smp_expr_output_type(expr);
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001232
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001233 /* Convert sample. */
1234 if (!sample_casts[out_type][table_type])
Thierry FOURNIERf73eb8f2013-11-27 15:30:55 +01001235 return 0;
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001236
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001237 return 1;
1238}
Emeric Brun3bd697e2010-01-04 15:23:48 +01001239
Willy Tarreauedee1d62014-07-15 16:44:27 +02001240/* Extra data types processing : after the last one, some room may remain
1241 * before STKTABLE_DATA_TYPES that may be used to register extra data types
1242 * at run time.
1243 */
Willy Tarreau08d5f982010-06-06 13:34:54 +02001244struct stktable_data_type stktable_data_types[STKTABLE_DATA_TYPES] = {
Willy Tarreau3b9c6e02010-07-18 08:04:30 +02001245 [STKTABLE_DT_SERVER_ID] = { .name = "server_id", .std_type = STD_T_SINT },
Thierry FOURNIER3cf11112015-07-28 08:57:05 +02001246 [STKTABLE_DT_GPT0] = { .name = "gpt0", .std_type = STD_T_UINT },
Willy Tarreau3b9c6e02010-07-18 08:04:30 +02001247 [STKTABLE_DT_GPC0] = { .name = "gpc0", .std_type = STD_T_UINT },
Willy Tarreauba2ffd12013-05-29 15:54:14 +02001248 [STKTABLE_DT_GPC0_RATE] = { .name = "gpc0_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
Willy Tarreau3b9c6e02010-07-18 08:04:30 +02001249 [STKTABLE_DT_CONN_CNT] = { .name = "conn_cnt", .std_type = STD_T_UINT },
1250 [STKTABLE_DT_CONN_RATE] = { .name = "conn_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
Willy Tarreaudb2ab822021-10-08 17:53:12 +02001251 [STKTABLE_DT_CONN_CUR] = { .name = "conn_cur", .std_type = STD_T_UINT, .is_local = 1 },
Willy Tarreau3b9c6e02010-07-18 08:04:30 +02001252 [STKTABLE_DT_SESS_CNT] = { .name = "sess_cnt", .std_type = STD_T_UINT },
1253 [STKTABLE_DT_SESS_RATE] = { .name = "sess_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
1254 [STKTABLE_DT_HTTP_REQ_CNT] = { .name = "http_req_cnt", .std_type = STD_T_UINT },
1255 [STKTABLE_DT_HTTP_REQ_RATE] = { .name = "http_req_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
1256 [STKTABLE_DT_HTTP_ERR_CNT] = { .name = "http_err_cnt", .std_type = STD_T_UINT },
1257 [STKTABLE_DT_HTTP_ERR_RATE] = { .name = "http_err_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
1258 [STKTABLE_DT_BYTES_IN_CNT] = { .name = "bytes_in_cnt", .std_type = STD_T_ULL },
1259 [STKTABLE_DT_BYTES_IN_RATE] = { .name = "bytes_in_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
1260 [STKTABLE_DT_BYTES_OUT_CNT] = { .name = "bytes_out_cnt", .std_type = STD_T_ULL },
1261 [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 +01001262 [STKTABLE_DT_GPC1] = { .name = "gpc1", .std_type = STD_T_UINT },
1263 [STKTABLE_DT_GPC1_RATE] = { .name = "gpc1_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
Thayne McCombs92149f92020-11-20 01:28:26 -07001264 [STKTABLE_DT_SERVER_KEY] = { .name = "server_key", .std_type = STD_T_DICT },
Willy Tarreau826f3ab2021-02-10 12:07:15 +01001265 [STKTABLE_DT_HTTP_FAIL_CNT] = { .name = "http_fail_cnt", .std_type = STD_T_UINT },
1266 [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 +02001267 [STKTABLE_DT_GPT] = { .name = "gpt", .std_type = STD_T_UINT, .is_array = 1 },
Emeric Brun4d7ada82021-06-30 19:04:16 +02001268 [STKTABLE_DT_GPC] = { .name = "gpc", .std_type = STD_T_UINT, .is_array = 1 },
1269 [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 +02001270};
1271
Willy Tarreauedee1d62014-07-15 16:44:27 +02001272/* Registers stick-table extra data type with index <idx>, name <name>, type
1273 * <std_type> and arg type <arg_type>. If the index is negative, the next free
1274 * index is automatically allocated. The allocated index is returned, or -1 if
1275 * no free index was found or <name> was already registered. The <name> is used
1276 * directly as a pointer, so if it's not stable, the caller must allocate it.
1277 */
1278int stktable_register_data_store(int idx, const char *name, int std_type, int arg_type)
1279{
1280 if (idx < 0) {
1281 for (idx = 0; idx < STKTABLE_DATA_TYPES; idx++) {
1282 if (!stktable_data_types[idx].name)
1283 break;
1284
1285 if (strcmp(stktable_data_types[idx].name, name) == 0)
1286 return -1;
1287 }
1288 }
1289
1290 if (idx >= STKTABLE_DATA_TYPES)
1291 return -1;
1292
1293 if (stktable_data_types[idx].name != NULL)
1294 return -1;
1295
1296 stktable_data_types[idx].name = name;
1297 stktable_data_types[idx].std_type = std_type;
1298 stktable_data_types[idx].arg_type = arg_type;
1299 return idx;
1300}
1301
Willy Tarreau08d5f982010-06-06 13:34:54 +02001302/*
1303 * Returns the data type number for the stktable_data_type whose name is <name>,
1304 * or <0 if not found.
1305 */
1306int stktable_get_data_type(char *name)
1307{
1308 int type;
1309
1310 for (type = 0; type < STKTABLE_DATA_TYPES; type++) {
Willy Tarreauedee1d62014-07-15 16:44:27 +02001311 if (!stktable_data_types[type].name)
1312 continue;
Willy Tarreau08d5f982010-06-06 13:34:54 +02001313 if (strcmp(name, stktable_data_types[type].name) == 0)
1314 return type;
1315 }
Thayne McCombs92149f92020-11-20 01:28:26 -07001316 /* For backwards compatibility */
1317 if (strcmp(name, "server_name") == 0)
1318 return STKTABLE_DT_SERVER_KEY;
Willy Tarreau08d5f982010-06-06 13:34:54 +02001319 return -1;
1320}
1321
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001322/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1323 * it up into this table. Returns true if found, false otherwise. The input
1324 * type is STR so that input samples are converted to string (since all types
1325 * can be converted to strings), then the function casts the string again into
1326 * the table's type. This is a double conversion, but in the future we might
1327 * support automatic input types to perform the cast on the fly.
1328 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001329static int sample_conv_in_table(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001330{
1331 struct stktable *t;
1332 struct stktable_key *key;
1333 struct stksess *ts;
1334
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001335 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001336
1337 key = smp_to_stkey(smp, t);
1338 if (!key)
1339 return 0;
1340
1341 ts = stktable_lookup_key(t, key);
1342
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001343 smp->data.type = SMP_T_BOOL;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001344 smp->data.u.sint = !!ts;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001345 smp->flags = SMP_F_VOL_TEST;
Willy Tarreau43e90352018-06-27 06:25:57 +02001346 stktable_release(t, ts);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001347 return 1;
1348}
1349
1350/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1351 * it up into this table. Returns the data rate received from clients in bytes/s
1352 * if the key is present in the table, otherwise zero, so that comparisons can
1353 * be easily performed. If the inspected parameter is not stored in the table,
1354 * <not found> is returned.
1355 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001356static int sample_conv_table_bytes_in_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001357{
1358 struct stktable *t;
1359 struct stktable_key *key;
1360 struct stksess *ts;
1361 void *ptr;
1362
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001363 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001364
1365 key = smp_to_stkey(smp, t);
1366 if (!key)
1367 return 0;
1368
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001369 ts = stktable_lookup_key(t, key);
1370
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001371 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001372 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001373 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001374
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001375 if (!ts) /* key not present */
1376 return 1;
1377
1378 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_IN_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001379 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001380 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Daniel Corbett3e60b112018-05-27 09:47:12 -04001381 t->data_arg[STKTABLE_DT_BYTES_IN_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001382
Daniel Corbett3e60b112018-05-27 09:47:12 -04001383 stktable_release(t, ts);
1384 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001385}
1386
1387/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1388 * it up into this table. Returns the cumulated number of connections for the key
1389 * if the key is present in the table, otherwise zero, so that comparisons can
1390 * be easily performed. If the inspected parameter is not stored in the table,
1391 * <not found> is returned.
1392 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001393static int sample_conv_table_conn_cnt(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001394{
1395 struct stktable *t;
1396 struct stktable_key *key;
1397 struct stksess *ts;
1398 void *ptr;
1399
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001400 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001401
1402 key = smp_to_stkey(smp, t);
1403 if (!key)
1404 return 0;
1405
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001406 ts = stktable_lookup_key(t, key);
1407
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001408 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001409 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001410 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001411
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001412 if (!ts) /* key not present */
1413 return 1;
1414
1415 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_CONN_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001416 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001417 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001418
Daniel Corbett3e60b112018-05-27 09:47:12 -04001419 stktable_release(t, ts);
1420 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001421}
1422
1423/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1424 * it up into this table. Returns the number of concurrent connections for the
1425 * key if the key is present in the table, otherwise zero, so that comparisons
1426 * can be easily performed. If the inspected parameter is not stored in the
1427 * table, <not found> is returned.
1428 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001429static int sample_conv_table_conn_cur(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001430{
1431 struct stktable *t;
1432 struct stktable_key *key;
1433 struct stksess *ts;
1434 void *ptr;
1435
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001436 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001437
1438 key = smp_to_stkey(smp, t);
1439 if (!key)
1440 return 0;
1441
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001442 ts = stktable_lookup_key(t, key);
1443
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001444 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001445 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001446 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001447
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001448 if (!ts) /* key not present */
1449 return 1;
1450
1451 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_CONN_CUR);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001452 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001453 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001454
Daniel Corbett3e60b112018-05-27 09:47:12 -04001455 stktable_release(t, ts);
1456 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001457}
1458
1459/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1460 * it up into this table. Returns the rate of incoming connections from the key
1461 * if the key is present in the table, otherwise zero, so that comparisons can
1462 * be easily performed. If the inspected parameter is not stored in the table,
1463 * <not found> is returned.
1464 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001465static int sample_conv_table_conn_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001466{
1467 struct stktable *t;
1468 struct stktable_key *key;
1469 struct stksess *ts;
1470 void *ptr;
1471
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001472 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001473
1474 key = smp_to_stkey(smp, t);
1475 if (!key)
1476 return 0;
1477
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001478 ts = stktable_lookup_key(t, key);
1479
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001480 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001481 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001482 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001483
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001484 if (!ts) /* key not present */
1485 return 1;
1486
1487 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_CONN_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001488 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001489 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Daniel Corbett3e60b112018-05-27 09:47:12 -04001490 t->data_arg[STKTABLE_DT_CONN_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001491
Daniel Corbett3e60b112018-05-27 09:47:12 -04001492 stktable_release(t, ts);
1493 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001494}
1495
1496/* 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 +02001497 * it up into this table. Returns the expiration delay for the key if the key is
1498 * present in the table, otherwise the default value provided as second argument
1499 * if any, if not (no default value), <not found> is returned.
1500 */
1501static int sample_conv_table_expire(const struct arg *arg_p, struct sample *smp, void *private)
1502{
1503 struct stktable *t;
1504 struct stktable_key *key;
1505 struct stksess *ts;
1506
1507 t = arg_p[0].data.t;
1508
1509 key = smp_to_stkey(smp, t);
1510 if (!key)
1511 return 0;
1512
1513 ts = stktable_lookup_key(t, key);
1514
1515 smp->flags = SMP_F_VOL_TEST;
1516 smp->data.type = SMP_T_SINT;
1517 smp->data.u.sint = 0;
1518
1519 if (!ts) { /* key not present */
1520 if (arg_p[1].type == ARGT_STOP)
1521 return 0;
1522
1523 /* default value */
1524 smp->data.u.sint = arg_p[1].data.sint;
1525 return 1;
1526 }
1527
1528 smp->data.u.sint = tick_remain(now_ms, ts->expire);
1529
1530 stktable_release(t, ts);
1531 return 1;
1532}
1533
1534/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1535 * it up into this table. Returns the time the key remains unused if the key is
1536 * present in the table, otherwise the default value provided as second argument
1537 * if any, if not (no default value), <not found> is returned.
1538 */
1539static int sample_conv_table_idle(const struct arg *arg_p, struct sample *smp, void *private)
1540{
1541 struct stktable *t;
1542 struct stktable_key *key;
1543 struct stksess *ts;
1544
1545 t = arg_p[0].data.t;
1546
1547 key = smp_to_stkey(smp, t);
1548 if (!key)
1549 return 0;
1550
1551 ts = stktable_lookup_key(t, key);
1552
1553 smp->flags = SMP_F_VOL_TEST;
1554 smp->data.type = SMP_T_SINT;
1555 smp->data.u.sint = 0;
1556
1557 if (!ts) { /* key not present */
1558 if (arg_p[1].type == ARGT_STOP)
1559 return 0;
1560
1561 /* default value */
1562 smp->data.u.sint = arg_p[1].data.sint;
1563 return 1;
1564 }
1565
1566 smp->data.u.sint = tick_remain(tick_remain(now_ms, ts->expire), t->expire);
1567
1568 stktable_release(t, ts);
1569 return 1;
1570}
1571
1572/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001573 * it up into this table. Returns the data rate sent to clients in bytes/s
1574 * if the key is present in the table, otherwise zero, so that comparisons can
1575 * be easily performed. If the inspected parameter is not stored in the table,
1576 * <not found> is returned.
1577 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001578static int sample_conv_table_bytes_out_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001579{
1580 struct stktable *t;
1581 struct stktable_key *key;
1582 struct stksess *ts;
1583 void *ptr;
1584
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001585 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001586
1587 key = smp_to_stkey(smp, t);
1588 if (!key)
1589 return 0;
1590
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001591 ts = stktable_lookup_key(t, key);
1592
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001593 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001594 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001595 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001596
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001597 if (!ts) /* key not present */
1598 return 1;
1599
1600 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_OUT_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001601 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001602 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Daniel Corbett3e60b112018-05-27 09:47:12 -04001603 t->data_arg[STKTABLE_DT_BYTES_OUT_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001604
Daniel Corbett3e60b112018-05-27 09:47:12 -04001605 stktable_release(t, ts);
1606 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001607}
1608
Emeric Brun877b0b52021-06-30 18:57:49 +02001609/* Casts sample <smp> to the type of the table specified in arg_p(1), and looks
1610 * it up into this table. Returns the value of the GPT[arg_p(0)] tag for the key
1611 * if the key is present in the table, otherwise false, so that comparisons can
1612 * be easily performed. If the inspected parameter is not stored in the table,
1613 * <not found> is returned.
1614 */
1615static int sample_conv_table_gpt(const struct arg *arg_p, struct sample *smp, void *private)
1616{
1617 struct stktable *t;
1618 struct stktable_key *key;
1619 struct stksess *ts;
1620 void *ptr;
1621 unsigned int idx;
1622
1623 idx = arg_p[0].data.sint;
1624
1625 t = arg_p[1].data.t;
1626
1627 key = smp_to_stkey(smp, t);
1628 if (!key)
1629 return 0;
1630
1631 ts = stktable_lookup_key(t, key);
1632
1633 smp->flags = SMP_F_VOL_TEST;
1634 smp->data.type = SMP_T_SINT;
1635 smp->data.u.sint = 0;
1636
1637 if (!ts) /* key not present */
1638 return 1;
1639
1640 ptr = stktable_data_ptr_idx(t, ts, STKTABLE_DT_GPT, idx);
1641 if (ptr)
1642 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
1643
1644 stktable_release(t, ts);
1645 return !!ptr;
1646}
1647
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001648/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001649 * it up into this table. Returns the value of the GPT0 tag for the key
1650 * if the key is present in the table, otherwise false, so that comparisons can
1651 * be easily performed. If the inspected parameter is not stored in the table,
1652 * <not found> is returned.
1653 */
1654static int sample_conv_table_gpt0(const struct arg *arg_p, struct sample *smp, void *private)
1655{
1656 struct stktable *t;
1657 struct stktable_key *key;
1658 struct stksess *ts;
1659 void *ptr;
1660
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001661 t = arg_p[0].data.t;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001662
1663 key = smp_to_stkey(smp, t);
1664 if (!key)
1665 return 0;
1666
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001667 ts = stktable_lookup_key(t, key);
1668
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001669 smp->flags = SMP_F_VOL_TEST;
1670 smp->data.type = SMP_T_SINT;
1671 smp->data.u.sint = 0;
1672
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001673 if (!ts) /* key not present */
1674 return 1;
1675
1676 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPT0);
Emeric Brunf7ab0bf2021-06-30 18:58:22 +02001677 if (!ptr)
1678 ptr = stktable_data_ptr_idx(t, ts, STKTABLE_DT_GPT, 0);
1679
Daniel Corbett3e60b112018-05-27 09:47:12 -04001680 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001681 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001682
Daniel Corbett3e60b112018-05-27 09:47:12 -04001683 stktable_release(t, ts);
1684 return !!ptr;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001685}
1686
Emeric Brun4d7ada82021-06-30 19:04:16 +02001687/* Casts sample <smp> to the type of the table specified in arg_p(1), and looks
1688 * it up into this table. Returns the value of the GPC[arg_p(0)] counter for the key
1689 * if the key is present in the table, otherwise zero, so that comparisons can
1690 * be easily performed. If the inspected parameter is not stored in the table,
1691 * <not found> is returned.
1692 */
1693static int sample_conv_table_gpc(const struct arg *arg_p, struct sample *smp, void *private)
1694{
1695 struct stktable *t;
1696 struct stktable_key *key;
1697 struct stksess *ts;
1698 void *ptr;
1699 unsigned int idx;
1700
1701 idx = arg_p[0].data.sint;
1702
1703 t = arg_p[1].data.t;
1704
1705 key = smp_to_stkey(smp, t);
1706 if (!key)
1707 return 0;
1708
1709 ts = stktable_lookup_key(t, key);
1710
1711 smp->flags = SMP_F_VOL_TEST;
1712 smp->data.type = SMP_T_SINT;
1713 smp->data.u.sint = 0;
1714
1715 if (!ts) /* key not present */
1716 return 1;
1717
1718 ptr = stktable_data_ptr_idx(t, ts, STKTABLE_DT_GPC, idx);
1719 if (ptr)
1720 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
1721
1722 stktable_release(t, ts);
1723 return !!ptr;
1724}
1725
1726/* Casts sample <smp> to the type of the table specified in arg_p(1), and looks
1727 * it up into this table. Returns the event rate of the GPC[arg_p(0)] counter
1728 * for the key if the key is present in the table, otherwise zero, so that
1729 * comparisons can be easily performed. If the inspected parameter is not
1730 * stored in the table, <not found> is returned.
1731 */
1732static int sample_conv_table_gpc_rate(const struct arg *arg_p, struct sample *smp, void *private)
1733{
1734 struct stktable *t;
1735 struct stktable_key *key;
1736 struct stksess *ts;
1737 void *ptr;
1738 unsigned int idx;
1739
1740 idx = arg_p[0].data.sint;
1741
1742 t = arg_p[1].data.t;
1743
1744 key = smp_to_stkey(smp, t);
1745 if (!key)
1746 return 0;
1747
1748 ts = stktable_lookup_key(t, key);
1749
1750 smp->flags = SMP_F_VOL_TEST;
1751 smp->data.type = SMP_T_SINT;
1752 smp->data.u.sint = 0;
1753
1754 if (!ts) /* key not present */
1755 return 1;
1756
1757 ptr = stktable_data_ptr_idx(t, ts, STKTABLE_DT_GPC_RATE, idx);
1758 if (ptr)
1759 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
1760 t->data_arg[STKTABLE_DT_GPC_RATE].u);
1761
1762 stktable_release(t, ts);
1763 return !!ptr;
1764}
1765
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001766/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001767 * it up into this table. Returns the value of the GPC0 counter for the key
1768 * if the key is present in the table, otherwise zero, so that comparisons can
1769 * be easily performed. If the inspected parameter is not stored in the table,
1770 * <not found> is returned.
1771 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001772static int sample_conv_table_gpc0(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001773{
1774 struct stktable *t;
1775 struct stktable_key *key;
1776 struct stksess *ts;
1777 void *ptr;
1778
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001779 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001780
1781 key = smp_to_stkey(smp, t);
1782 if (!key)
1783 return 0;
1784
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001785 ts = stktable_lookup_key(t, key);
1786
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001787 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001788 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001789 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001790
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001791 if (!ts) /* key not present */
1792 return 1;
1793
1794 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPC0);
Emeric Brun726783d2021-06-30 19:06:43 +02001795 if (!ptr) {
1796 /* fallback on the gpc array */
1797 ptr = stktable_data_ptr_idx(t, ts, STKTABLE_DT_GPC, 0);
1798 }
1799
Daniel Corbett3e60b112018-05-27 09:47:12 -04001800 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001801 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001802
Daniel Corbett3e60b112018-05-27 09:47:12 -04001803 stktable_release(t, ts);
1804 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001805}
1806
1807/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1808 * it up into this table. Returns the event rate of the GPC0 counter for the key
1809 * if the key is present in the table, otherwise zero, so that comparisons can
1810 * be easily performed. If the inspected parameter is not stored in the table,
1811 * <not found> is returned.
1812 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001813static int sample_conv_table_gpc0_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001814{
1815 struct stktable *t;
1816 struct stktable_key *key;
1817 struct stksess *ts;
1818 void *ptr;
1819
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001820 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001821
1822 key = smp_to_stkey(smp, t);
1823 if (!key)
1824 return 0;
1825
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001826 ts = stktable_lookup_key(t, key);
1827
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001828 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001829 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001830 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001831
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001832 if (!ts) /* key not present */
1833 return 1;
1834
1835 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPC0_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001836 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001837 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Daniel Corbett3e60b112018-05-27 09:47:12 -04001838 t->data_arg[STKTABLE_DT_GPC0_RATE].u);
Emeric Brun726783d2021-06-30 19:06:43 +02001839 else {
1840 /* fallback on the gpc array */
1841 ptr = stktable_data_ptr_idx(t, ts, STKTABLE_DT_GPC_RATE, 0);
1842 if (ptr)
1843 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
1844 t->data_arg[STKTABLE_DT_GPC_RATE].u);
1845 }
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001846
Daniel Corbett3e60b112018-05-27 09:47:12 -04001847 stktable_release(t, ts);
1848 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001849}
1850
1851/* 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 +01001852 * it up into this table. Returns the value of the GPC1 counter for the key
1853 * if the key is present in the table, otherwise zero, so that comparisons can
1854 * be easily performed. If the inspected parameter is not stored in the table,
1855 * <not found> is returned.
1856 */
1857static int sample_conv_table_gpc1(const struct arg *arg_p, struct sample *smp, void *private)
1858{
1859 struct stktable *t;
1860 struct stktable_key *key;
1861 struct stksess *ts;
1862 void *ptr;
1863
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001864 t = arg_p[0].data.t;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001865
1866 key = smp_to_stkey(smp, t);
1867 if (!key)
1868 return 0;
1869
1870 ts = stktable_lookup_key(t, key);
1871
1872 smp->flags = SMP_F_VOL_TEST;
1873 smp->data.type = SMP_T_SINT;
1874 smp->data.u.sint = 0;
1875
1876 if (!ts) /* key not present */
1877 return 1;
1878
1879 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPC1);
Emeric Brun726783d2021-06-30 19:06:43 +02001880 if (!ptr) {
1881 /* fallback on the gpc array */
1882 ptr = stktable_data_ptr_idx(t, ts, STKTABLE_DT_GPC, 1);
1883 }
1884
Daniel Corbett3e60b112018-05-27 09:47:12 -04001885 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001886 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001887
Daniel Corbett3e60b112018-05-27 09:47:12 -04001888 stktable_release(t, ts);
1889 return !!ptr;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001890}
1891
1892/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1893 * it up into this table. Returns the event rate of the GPC1 counter for the key
1894 * if the key is present in the table, otherwise zero, so that comparisons can
1895 * be easily performed. If the inspected parameter is not stored in the table,
1896 * <not found> is returned.
1897 */
1898static int sample_conv_table_gpc1_rate(const struct arg *arg_p, struct sample *smp, void *private)
1899{
1900 struct stktable *t;
1901 struct stktable_key *key;
1902 struct stksess *ts;
1903 void *ptr;
1904
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001905 t = arg_p[0].data.t;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001906
1907 key = smp_to_stkey(smp, t);
1908 if (!key)
1909 return 0;
1910
1911 ts = stktable_lookup_key(t, key);
1912
1913 smp->flags = SMP_F_VOL_TEST;
1914 smp->data.type = SMP_T_SINT;
1915 smp->data.u.sint = 0;
1916
1917 if (!ts) /* key not present */
1918 return 1;
1919
1920 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPC1_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001921 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001922 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Daniel Corbett3e60b112018-05-27 09:47:12 -04001923 t->data_arg[STKTABLE_DT_GPC1_RATE].u);
Emeric Brun726783d2021-06-30 19:06:43 +02001924 else {
1925 /* fallback on the gpc array */
1926 ptr = stktable_data_ptr_idx(t, ts, STKTABLE_DT_GPC_RATE, 1);
1927 if (ptr)
1928 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
1929 t->data_arg[STKTABLE_DT_GPC_RATE].u);
1930 }
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001931
Daniel Corbett3e60b112018-05-27 09:47:12 -04001932 stktable_release(t, ts);
1933 return !!ptr;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001934}
1935
1936/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001937 * it up into this table. Returns the cumulated number of HTTP request errors
1938 * for the key if the key is present in the table, otherwise zero, so that
1939 * comparisons can be easily performed. If the inspected parameter is not stored
1940 * in the table, <not found> is returned.
1941 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001942static int sample_conv_table_http_err_cnt(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001943{
1944 struct stktable *t;
1945 struct stktable_key *key;
1946 struct stksess *ts;
1947 void *ptr;
1948
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001949 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001950
1951 key = smp_to_stkey(smp, t);
1952 if (!key)
1953 return 0;
1954
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001955 ts = stktable_lookup_key(t, key);
1956
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001957 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001958 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001959 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001960
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001961 if (!ts) /* key not present */
1962 return 1;
1963
1964 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_ERR_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001965 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001966 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001967
Daniel Corbett3e60b112018-05-27 09:47:12 -04001968 stktable_release(t, ts);
1969 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001970}
1971
1972/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1973 * it up into this table. Returns the HTTP request error rate the key
1974 * if the key is present in the table, otherwise zero, so that comparisons can
1975 * be easily performed. If the inspected parameter is not stored in the table,
1976 * <not found> is returned.
1977 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001978static int sample_conv_table_http_err_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001979{
1980 struct stktable *t;
1981 struct stktable_key *key;
1982 struct stksess *ts;
1983 void *ptr;
1984
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001985 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001986
1987 key = smp_to_stkey(smp, t);
1988 if (!key)
1989 return 0;
1990
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001991 ts = stktable_lookup_key(t, key);
1992
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001993 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001994 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001995 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001996
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001997 if (!ts) /* key not present */
1998 return 1;
1999
2000 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_ERR_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04002001 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002002 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Daniel Corbett3e60b112018-05-27 09:47:12 -04002003 t->data_arg[STKTABLE_DT_HTTP_ERR_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002004
Daniel Corbett3e60b112018-05-27 09:47:12 -04002005 stktable_release(t, ts);
2006 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002007}
2008
2009/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Willy Tarreau826f3ab2021-02-10 12:07:15 +01002010 * it up into this table. Returns the cumulated number of HTTP response failures
2011 * for the key if the key is present in the table, otherwise zero, so that
2012 * comparisons can be easily performed. If the inspected parameter is not stored
2013 * in the table, <not found> is returned.
2014 */
2015static int sample_conv_table_http_fail_cnt(const struct arg *arg_p, struct sample *smp, void *private)
2016{
2017 struct stktable *t;
2018 struct stktable_key *key;
2019 struct stksess *ts;
2020 void *ptr;
2021
2022 t = arg_p[0].data.t;
2023
2024 key = smp_to_stkey(smp, t);
2025 if (!key)
2026 return 0;
2027
2028 ts = stktable_lookup_key(t, key);
2029
2030 smp->flags = SMP_F_VOL_TEST;
2031 smp->data.type = SMP_T_SINT;
2032 smp->data.u.sint = 0;
2033
2034 if (!ts) /* key not present */
2035 return 1;
2036
2037 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_FAIL_CNT);
2038 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002039 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Willy Tarreau826f3ab2021-02-10 12:07:15 +01002040
2041 stktable_release(t, ts);
2042 return !!ptr;
2043}
2044
2045/* Casts sample <smp> to the type of the table specified in arg(0), and looks
2046 * it up into this table. Returns the HTTP response failure rate for the key
2047 * if the key is present in the table, otherwise zero, so that comparisons can
2048 * be easily performed. If the inspected parameter is not stored in the table,
2049 * <not found> is returned.
2050 */
2051static int sample_conv_table_http_fail_rate(const struct arg *arg_p, struct sample *smp, void *private)
2052{
2053 struct stktable *t;
2054 struct stktable_key *key;
2055 struct stksess *ts;
2056 void *ptr;
2057
2058 t = arg_p[0].data.t;
2059
2060 key = smp_to_stkey(smp, t);
2061 if (!key)
2062 return 0;
2063
2064 ts = stktable_lookup_key(t, key);
2065
2066 smp->flags = SMP_F_VOL_TEST;
2067 smp->data.type = SMP_T_SINT;
2068 smp->data.u.sint = 0;
2069
2070 if (!ts) /* key not present */
2071 return 1;
2072
2073 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_FAIL_RATE);
2074 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002075 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Willy Tarreau826f3ab2021-02-10 12:07:15 +01002076 t->data_arg[STKTABLE_DT_HTTP_FAIL_RATE].u);
2077
2078 stktable_release(t, ts);
2079 return !!ptr;
2080}
2081
2082/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002083 * it up into this table. Returns the cumulated number of HTTP request for the
2084 * key if the key is present in the table, otherwise zero, so that comparisons
2085 * can be easily performed. If the inspected parameter is not stored in the
2086 * table, <not found> is returned.
2087 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02002088static int sample_conv_table_http_req_cnt(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002089{
2090 struct stktable *t;
2091 struct stktable_key *key;
2092 struct stksess *ts;
2093 void *ptr;
2094
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002095 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002096
2097 key = smp_to_stkey(smp, t);
2098 if (!key)
2099 return 0;
2100
Willy Tarreauf0c730a2016-05-25 17:07:56 +02002101 ts = stktable_lookup_key(t, key);
2102
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002103 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02002104 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02002105 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002106
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002107 if (!ts) /* key not present */
2108 return 1;
2109
2110 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_REQ_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04002111 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002112 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002113
Daniel Corbett3e60b112018-05-27 09:47:12 -04002114 stktable_release(t, ts);
2115 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002116}
2117
2118/* Casts sample <smp> to the type of the table specified in arg(0), and looks
2119 * it up into this table. Returns the HTTP request rate the key if the key is
2120 * present in the table, otherwise zero, so that comparisons can be easily
2121 * performed. If the inspected parameter is not stored in the table, <not found>
2122 * is returned.
2123 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02002124static int sample_conv_table_http_req_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002125{
2126 struct stktable *t;
2127 struct stktable_key *key;
2128 struct stksess *ts;
2129 void *ptr;
2130
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002131 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002132
2133 key = smp_to_stkey(smp, t);
2134 if (!key)
2135 return 0;
2136
Willy Tarreauf0c730a2016-05-25 17:07:56 +02002137 ts = stktable_lookup_key(t, key);
2138
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002139 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02002140 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02002141 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002142
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002143 if (!ts) /* key not present */
2144 return 1;
2145
2146 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_REQ_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04002147 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002148 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Daniel Corbett3e60b112018-05-27 09:47:12 -04002149 t->data_arg[STKTABLE_DT_HTTP_REQ_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002150
Daniel Corbett3e60b112018-05-27 09:47:12 -04002151 stktable_release(t, ts);
2152 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002153}
2154
2155/* Casts sample <smp> to the type of the table specified in arg(0), and looks
2156 * it up into this table. Returns the volume of datareceived from clients in kbytes
2157 * if the key is present in the table, otherwise zero, so that comparisons can
2158 * be easily performed. If the inspected parameter is not stored in the table,
2159 * <not found> is returned.
2160 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02002161static int sample_conv_table_kbytes_in(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002162{
2163 struct stktable *t;
2164 struct stktable_key *key;
2165 struct stksess *ts;
2166 void *ptr;
2167
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002168 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002169
2170 key = smp_to_stkey(smp, t);
2171 if (!key)
2172 return 0;
2173
Willy Tarreauf0c730a2016-05-25 17:07:56 +02002174 ts = stktable_lookup_key(t, key);
2175
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002176 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02002177 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02002178 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002179
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002180 if (!ts) /* key not present */
2181 return 1;
2182
2183 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_IN_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04002184 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002185 smp->data.u.sint = stktable_data_cast(ptr, std_t_ull) >> 10;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002186
Daniel Corbett3e60b112018-05-27 09:47:12 -04002187 stktable_release(t, ts);
2188 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002189}
2190
2191/* Casts sample <smp> to the type of the table specified in arg(0), and looks
2192 * it up into this table. Returns the volume of data sent to clients in kbytes
2193 * if the key is present in the table, otherwise zero, so that comparisons can
2194 * be easily performed. If the inspected parameter is not stored in the table,
2195 * <not found> is returned.
2196 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02002197static int sample_conv_table_kbytes_out(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002198{
2199 struct stktable *t;
2200 struct stktable_key *key;
2201 struct stksess *ts;
2202 void *ptr;
2203
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002204 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002205
2206 key = smp_to_stkey(smp, t);
2207 if (!key)
2208 return 0;
2209
Willy Tarreauf0c730a2016-05-25 17:07:56 +02002210 ts = stktable_lookup_key(t, key);
2211
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002212 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02002213 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02002214 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002215
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002216 if (!ts) /* key not present */
2217 return 1;
2218
2219 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_OUT_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04002220 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002221 smp->data.u.sint = stktable_data_cast(ptr, std_t_ull) >> 10;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002222
Daniel Corbett3e60b112018-05-27 09:47:12 -04002223 stktable_release(t, ts);
2224 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002225}
2226
2227/* Casts sample <smp> to the type of the table specified in arg(0), and looks
2228 * it up into this table. Returns the server ID associated with the key if the
2229 * key is present in the table, otherwise zero, so that comparisons can be
2230 * easily performed. If the inspected parameter is not stored in the table,
2231 * <not found> is returned.
2232 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02002233static int sample_conv_table_server_id(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002234{
2235 struct stktable *t;
2236 struct stktable_key *key;
2237 struct stksess *ts;
2238 void *ptr;
2239
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002240 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002241
2242 key = smp_to_stkey(smp, t);
2243 if (!key)
2244 return 0;
2245
Willy Tarreauf0c730a2016-05-25 17:07:56 +02002246 ts = stktable_lookup_key(t, key);
2247
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002248 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02002249 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02002250 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002251
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002252 if (!ts) /* key not present */
2253 return 1;
2254
2255 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_SERVER_ID);
Daniel Corbett3e60b112018-05-27 09:47:12 -04002256 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002257 smp->data.u.sint = stktable_data_cast(ptr, std_t_sint);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002258
Daniel Corbett3e60b112018-05-27 09:47:12 -04002259 stktable_release(t, ts);
2260 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002261}
2262
2263/* Casts sample <smp> to the type of the table specified in arg(0), and looks
2264 * it up into this table. Returns the cumulated number of sessions for the
2265 * key if the key is present in the table, otherwise zero, so that comparisons
2266 * can be easily performed. If the inspected parameter is not stored in the
2267 * table, <not found> is returned.
2268 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02002269static int sample_conv_table_sess_cnt(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002270{
2271 struct stktable *t;
2272 struct stktable_key *key;
2273 struct stksess *ts;
2274 void *ptr;
2275
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002276 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002277
2278 key = smp_to_stkey(smp, t);
2279 if (!key)
2280 return 0;
2281
Willy Tarreauf0c730a2016-05-25 17:07:56 +02002282 ts = stktable_lookup_key(t, key);
2283
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002284 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02002285 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02002286 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002287
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002288 if (!ts) /* key not present */
2289 return 1;
2290
2291 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_SESS_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04002292 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002293 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002294
Daniel Corbett3e60b112018-05-27 09:47:12 -04002295 stktable_release(t, ts);
2296 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002297}
2298
2299/* Casts sample <smp> to the type of the table specified in arg(0), and looks
2300 * it up into this table. Returns the session rate the key if the key is
2301 * present in the table, otherwise zero, so that comparisons can be easily
2302 * performed. If the inspected parameter is not stored in the table, <not found>
2303 * is returned.
2304 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02002305static int sample_conv_table_sess_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002306{
2307 struct stktable *t;
2308 struct stktable_key *key;
2309 struct stksess *ts;
2310 void *ptr;
2311
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002312 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002313
2314 key = smp_to_stkey(smp, t);
2315 if (!key)
2316 return 0;
2317
Willy Tarreauf0c730a2016-05-25 17:07:56 +02002318 ts = stktable_lookup_key(t, key);
2319
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002320 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02002321 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02002322 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002323
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002324 if (!ts) /* key not present */
2325 return 1;
2326
2327 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_SESS_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04002328 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002329 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Daniel Corbett3e60b112018-05-27 09:47:12 -04002330 t->data_arg[STKTABLE_DT_SESS_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002331
Daniel Corbett3e60b112018-05-27 09:47:12 -04002332 stktable_release(t, ts);
2333 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002334}
2335
2336/* Casts sample <smp> to the type of the table specified in arg(0), and looks
2337 * it up into this table. Returns the amount of concurrent connections tracking
2338 * the same key if the key is present in the table, otherwise zero, so that
2339 * comparisons can be easily performed. If the inspected parameter is not
2340 * stored in the table, <not found> is returned.
2341 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02002342static int sample_conv_table_trackers(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002343{
2344 struct stktable *t;
2345 struct stktable_key *key;
2346 struct stksess *ts;
2347
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002348 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002349
2350 key = smp_to_stkey(smp, t);
2351 if (!key)
2352 return 0;
2353
Willy Tarreauf0c730a2016-05-25 17:07:56 +02002354 ts = stktable_lookup_key(t, key);
2355
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002356 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02002357 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02002358 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002359
Tim Duesterhus65189c12018-06-26 15:57:29 +02002360 if (!ts)
2361 return 1;
2362
2363 smp->data.u.sint = ts->ref_cnt;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002364
Daniel Corbett3e60b112018-05-27 09:47:12 -04002365 stktable_release(t, ts);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002366 return 1;
2367}
2368
Emeric Brun4d7ada82021-06-30 19:04:16 +02002369/* This function increments the gpc counter at index 'rule->arg.gpc.idx' of the
2370 * array on the tracksc counter of index 'rule->arg.gpc.sc' stored into the
2371 * <stream> or directly in the session <sess> if <stream> is set to NULL
2372 *
2373 * This function always returns ACT_RET_CONT and parameter flags is unused.
2374 */
2375static enum act_return action_inc_gpc(struct act_rule *rule, struct proxy *px,
2376 struct session *sess, struct stream *s, int flags)
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002377{
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002378 struct stksess *ts;
2379 struct stkctr *stkctr;
2380
2381 /* Extract the stksess, return OK if no stksess available. */
2382 if (s)
2383 stkctr = &s->stkctr[rule->arg.gpc.sc];
2384 else
2385 stkctr = &sess->stkctr[rule->arg.gpc.sc];
Willy Tarreau79c1e912016-01-25 14:54:45 +01002386
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002387 ts = stkctr_entry(stkctr);
Willy Tarreau79c1e912016-01-25 14:54:45 +01002388 if (ts) {
2389 void *ptr1, *ptr2;
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002390
Emeric Brun4d7ada82021-06-30 19:04:16 +02002391 /* First, update gpc_rate if it's tracked. Second, update its gpc if tracked. */
2392 ptr1 = stktable_data_ptr_idx(stkctr->table, ts, STKTABLE_DT_GPC_RATE, rule->arg.gpc.idx);
2393 ptr2 = stktable_data_ptr_idx(stkctr->table, ts, STKTABLE_DT_GPC, rule->arg.gpc.idx);
2394
Emeric Brun819fc6f2017-06-13 19:37:32 +02002395 if (ptr1 || ptr2) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002396 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002397
2398 if (ptr1)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002399 update_freq_ctr_period(&stktable_data_cast(ptr1, std_t_frqp),
Emeric Brun4d7ada82021-06-30 19:04:16 +02002400 stkctr->table->data_arg[STKTABLE_DT_GPC_RATE].u, 1);
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002401
Emeric Brun819fc6f2017-06-13 19:37:32 +02002402 if (ptr2)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002403 stktable_data_cast(ptr2, std_t_uint)++;
Willy Tarreau79c1e912016-01-25 14:54:45 +01002404
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002405 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002406
2407 /* If data was modified, we need to touch to re-schedule sync */
2408 stktable_touch_local(stkctr->table, ts, 0);
2409 }
Willy Tarreau79c1e912016-01-25 14:54:45 +01002410 }
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002411 return ACT_RET_CONT;
2412}
2413
Emeric Brun4d7ada82021-06-30 19:04:16 +02002414/* Same as action_inc_gpc() but for gpc0 only */
2415static enum act_return action_inc_gpc0(struct act_rule *rule, struct proxy *px,
2416 struct session *sess, struct stream *s, int flags)
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002417{
Emeric Brun4d7ada82021-06-30 19:04:16 +02002418 struct stksess *ts;
2419 struct stkctr *stkctr;
Willy Tarreau5b654ad2021-07-06 18:51:12 +02002420 unsigned int period = 0;
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002421
Emeric Brun4d7ada82021-06-30 19:04:16 +02002422 /* Extract the stksess, return OK if no stksess available. */
2423 if (s)
2424 stkctr = &s->stkctr[rule->arg.gpc.sc];
2425 else
2426 stkctr = &sess->stkctr[rule->arg.gpc.sc];
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002427
Emeric Brun4d7ada82021-06-30 19:04:16 +02002428 ts = stkctr_entry(stkctr);
2429 if (ts) {
2430 void *ptr1, *ptr2;
2431
2432 /* First, update gpc0_rate if it's tracked. Second, update its gpc0 if tracked. */
2433 ptr1 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC0_RATE);
Emeric Brun726783d2021-06-30 19:06:43 +02002434 if (ptr1) {
2435 period = stkctr->table->data_arg[STKTABLE_DT_GPC0_RATE].u;
2436 }
2437 else {
2438 /* fallback on the gpc array */
2439 ptr1 = stktable_data_ptr_idx(stkctr->table, ts, STKTABLE_DT_GPC_RATE, 0);
2440 if (ptr1)
2441 period = stkctr->table->data_arg[STKTABLE_DT_GPC_RATE].u;
2442 }
2443
Emeric Brun4d7ada82021-06-30 19:04:16 +02002444 ptr2 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC0);
Emeric Brun726783d2021-06-30 19:06:43 +02002445 if (!ptr2) {
2446 /* fallback on the gpc array */
2447 ptr2 = stktable_data_ptr_idx(stkctr->table, ts, STKTABLE_DT_GPC, 0);
2448 }
2449
Emeric Brun4d7ada82021-06-30 19:04:16 +02002450 if (ptr1 || ptr2) {
2451 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
2452
2453 if (ptr1)
2454 update_freq_ctr_period(&stktable_data_cast(ptr1, std_t_frqp),
Emeric Brun726783d2021-06-30 19:06:43 +02002455 period, 1);
Emeric Brun4d7ada82021-06-30 19:04:16 +02002456
2457 if (ptr2)
2458 stktable_data_cast(ptr2, std_t_uint)++;
2459
2460 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
2461
2462 /* If data was modified, we need to touch to re-schedule sync */
2463 stktable_touch_local(stkctr->table, ts, 0);
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002464 }
2465 }
Emeric Brun4d7ada82021-06-30 19:04:16 +02002466 return ACT_RET_CONT;
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002467}
2468
Emeric Brun4d7ada82021-06-30 19:04:16 +02002469/* Same as action_inc_gpc() but for gpc1 only */
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002470static enum act_return action_inc_gpc1(struct act_rule *rule, struct proxy *px,
2471 struct session *sess, struct stream *s, int flags)
2472{
2473 struct stksess *ts;
2474 struct stkctr *stkctr;
Willy Tarreau5b654ad2021-07-06 18:51:12 +02002475 unsigned int period = 0;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002476
2477 /* Extract the stksess, return OK if no stksess available. */
2478 if (s)
2479 stkctr = &s->stkctr[rule->arg.gpc.sc];
2480 else
2481 stkctr = &sess->stkctr[rule->arg.gpc.sc];
2482
2483 ts = stkctr_entry(stkctr);
2484 if (ts) {
2485 void *ptr1, *ptr2;
2486
2487 /* First, update gpc1_rate if it's tracked. Second, update its gpc1 if tracked. */
2488 ptr1 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC1_RATE);
Emeric Brun726783d2021-06-30 19:06:43 +02002489 if (ptr1) {
2490 period = stkctr->table->data_arg[STKTABLE_DT_GPC1_RATE].u;
2491 }
2492 else {
2493 /* fallback on the gpc array */
2494 ptr1 = stktable_data_ptr_idx(stkctr->table, ts, STKTABLE_DT_GPC_RATE, 1);
2495 if (ptr1)
2496 period = stkctr->table->data_arg[STKTABLE_DT_GPC_RATE].u;
2497 }
2498
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002499 ptr2 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC1);
Emeric Brun726783d2021-06-30 19:06:43 +02002500 if (!ptr2) {
2501 /* fallback on the gpc array */
2502 ptr2 = stktable_data_ptr_idx(stkctr->table, ts, STKTABLE_DT_GPC, 1);
2503 }
2504
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002505 if (ptr1 || ptr2) {
2506 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
2507
2508 if (ptr1)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002509 update_freq_ctr_period(&stktable_data_cast(ptr1, std_t_frqp),
Emeric Brun726783d2021-06-30 19:06:43 +02002510 period, 1);
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002511
2512 if (ptr2)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002513 stktable_data_cast(ptr2, std_t_uint)++;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002514
2515 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
2516
2517 /* If data was modified, we need to touch to re-schedule sync */
2518 stktable_touch_local(stkctr->table, ts, 0);
2519 }
2520 }
2521 return ACT_RET_CONT;
2522}
2523
Emeric Brun4d7ada82021-06-30 19:04:16 +02002524/* This function is a common parser for actions incrementing the GPC
2525 * (General Purpose Counters). It understands the formats:
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002526 *
Emeric Brun4d7ada82021-06-30 19:04:16 +02002527 * sc-inc-gpc(<gpc IDX>,<track ID>)
2528 * sc-inc-gpc0([<track ID>])
2529 * sc-inc-gpc1([<track ID>])
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002530 *
Emeric Brun4d7ada82021-06-30 19:04:16 +02002531 * It returns ACT_RET_PRS_ERR if fails and <err> is filled with an error
2532 * message. Otherwise it returns ACT_RET_PRS_OK.
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002533 */
Emeric Brun4d7ada82021-06-30 19:04:16 +02002534static enum act_parse_ret parse_inc_gpc(const char **args, int *arg, struct proxy *px,
2535 struct act_rule *rule, char **err)
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002536{
2537 const char *cmd_name = args[*arg-1];
2538 char *error;
2539
Emeric Brun4d7ada82021-06-30 19:04:16 +02002540 cmd_name += strlen("sc-inc-gpc");
2541 if (*cmd_name == '(') {
2542 cmd_name++; /* skip the '(' */
2543 rule->arg.gpc.idx = strtoul(cmd_name, &error, 10); /* Convert stick table id. */
2544 if (*error != ',') {
2545 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 +01002546 return ACT_RET_PRS_ERR;
2547 }
Emeric Brun4d7ada82021-06-30 19:04:16 +02002548 else {
2549 cmd_name = error + 1; /* skip the ',' */
2550 rule->arg.gpc.sc = strtol(cmd_name, &error, 10); /* Convert stick table id. */
2551 if (*error != ')') {
2552 memprintf(err, "invalid stick table track ID '%s'. Expects sc-inc-gpc(<GPC ID>,<Track ID>)", args[*arg-1]);
2553 return ACT_RET_PRS_ERR;
2554 }
2555
2556 if (rule->arg.gpc.sc >= MAX_SESS_STKCTR) {
2557 memprintf(err, "invalid stick table track ID '%s'. The max allowed ID is %d",
2558 args[*arg-1], MAX_SESS_STKCTR-1);
2559 return ACT_RET_PRS_ERR;
2560 }
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002561 }
Emeric Brun4d7ada82021-06-30 19:04:16 +02002562 rule->action_ptr = action_inc_gpc;
2563 }
2564 else if (*cmd_name == '0' ||*cmd_name == '1') {
2565 char c = *cmd_name;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002566
Emeric Brun4d7ada82021-06-30 19:04:16 +02002567 cmd_name++;
2568 if (*cmd_name == '\0') {
2569 /* default stick table id. */
2570 rule->arg.gpc.sc = 0;
2571 } else {
2572 /* parse the stick table id. */
2573 if (*cmd_name != '(') {
2574 memprintf(err, "invalid stick table track ID. Expects %s(<Track ID>)", args[*arg-1]);
2575 return ACT_RET_PRS_ERR;
2576 }
2577 cmd_name++; /* jump the '(' */
2578 rule->arg.gpc.sc = strtol(cmd_name, &error, 10); /* Convert stick table id. */
2579 if (*error != ')') {
2580 memprintf(err, "invalid stick table track ID. Expects %s(<Track ID>)", args[*arg-1]);
2581 return ACT_RET_PRS_ERR;
2582 }
2583
2584 if (rule->arg.gpc.sc >= MAX_SESS_STKCTR) {
2585 memprintf(err, "invalid stick table track ID. The max allowed ID is %d",
2586 MAX_SESS_STKCTR-1);
2587 return ACT_RET_PRS_ERR;
2588 }
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002589 }
Emeric Brun4d7ada82021-06-30 19:04:16 +02002590 if (c == '1')
2591 rule->action_ptr = action_inc_gpc1;
2592 else
2593 rule->action_ptr = action_inc_gpc0;
2594 }
2595 else {
2596 /* default stick table id. */
2597 memprintf(err, "invalid gpc ID '%s'. Expects sc-set-gpc(<GPC ID>,<Track ID>)", args[*arg-1]);
2598 return ACT_RET_PRS_ERR;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002599 }
2600 rule->action = ACT_CUSTOM;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002601 return ACT_RET_PRS_OK;
2602}
2603
Emeric Brun877b0b52021-06-30 18:57:49 +02002604/* This function sets the gpt at index 'rule->arg.gpt.idx' of the array on the
2605 * tracksc counter of index 'rule->arg.gpt.sc' stored into the <stream> or
2606 * directly in the session <sess> if <stream> is set to NULL. This gpt is
2607 * set to the value computed by the expression 'rule->arg.gpt.expr' or if
2608 * 'rule->arg.gpt.expr' is null directly to the value of 'rule->arg.gpt.value'.
2609 *
2610 * This function always returns ACT_RET_CONT and parameter flags is unused.
2611 */
2612static enum act_return action_set_gpt(struct act_rule *rule, struct proxy *px,
2613 struct session *sess, struct stream *s, int flags)
2614{
2615 void *ptr;
2616 struct stksess *ts;
2617 struct stkctr *stkctr;
2618 unsigned int value = 0;
2619 struct sample *smp;
2620 int smp_opt_dir;
2621
2622 /* Extract the stksess, return OK if no stksess available. */
2623 if (s)
2624 stkctr = &s->stkctr[rule->arg.gpt.sc];
2625 else
2626 stkctr = &sess->stkctr[rule->arg.gpt.sc];
2627
2628 ts = stkctr_entry(stkctr);
2629 if (!ts)
2630 return ACT_RET_CONT;
2631
2632 /* Store the sample in the required sc, and ignore errors. */
2633 ptr = stktable_data_ptr_idx(stkctr->table, ts, STKTABLE_DT_GPT, rule->arg.gpt.idx);
2634 if (ptr) {
2635
2636 if (!rule->arg.gpt.expr)
2637 value = (unsigned int)(rule->arg.gpt.value);
2638 else {
2639 switch (rule->from) {
2640 case ACT_F_TCP_REQ_SES: smp_opt_dir = SMP_OPT_DIR_REQ; break;
2641 case ACT_F_TCP_REQ_CNT: smp_opt_dir = SMP_OPT_DIR_REQ; break;
2642 case ACT_F_TCP_RES_CNT: smp_opt_dir = SMP_OPT_DIR_RES; break;
2643 case ACT_F_HTTP_REQ: smp_opt_dir = SMP_OPT_DIR_REQ; break;
2644 case ACT_F_HTTP_RES: smp_opt_dir = SMP_OPT_DIR_RES; break;
2645 default:
2646 send_log(px, LOG_ERR, "stick table: internal error while setting gpt%u.", rule->arg.gpt.idx);
2647 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))
2648 ha_alert("stick table: internal error while executing setting gpt%u.\n", rule->arg.gpt.idx);
2649 return ACT_RET_CONT;
2650 }
2651
2652 /* Fetch and cast the expression. */
2653 smp = sample_fetch_as_type(px, sess, s, smp_opt_dir|SMP_OPT_FINAL, rule->arg.gpt.expr, SMP_T_SINT);
2654 if (!smp) {
2655 send_log(px, LOG_WARNING, "stick table: invalid expression or data type while setting gpt%u.", rule->arg.gpt.idx);
2656 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))
2657 ha_alert("stick table: invalid expression or data type while setting gpt%u.\n", rule->arg.gpt.idx);
2658 return ACT_RET_CONT;
2659 }
2660 value = (unsigned int)(smp->data.u.sint);
2661 }
2662
2663 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
2664
2665 stktable_data_cast(ptr, std_t_uint) = value;
2666
2667 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
2668
2669 stktable_touch_local(stkctr->table, ts, 0);
2670 }
2671
2672 return ACT_RET_CONT;
2673}
2674
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002675/* Always returns 1. */
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002676static enum act_return action_set_gpt0(struct act_rule *rule, struct proxy *px,
Willy Tarreau658b85b2015-09-27 10:00:49 +02002677 struct session *sess, struct stream *s, int flags)
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002678{
2679 void *ptr;
2680 struct stksess *ts;
2681 struct stkctr *stkctr;
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002682 unsigned int value = 0;
2683 struct sample *smp;
2684 int smp_opt_dir;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002685
2686 /* Extract the stksess, return OK if no stksess available. */
2687 if (s)
2688 stkctr = &s->stkctr[rule->arg.gpt.sc];
2689 else
2690 stkctr = &sess->stkctr[rule->arg.gpt.sc];
Willy Tarreau79c1e912016-01-25 14:54:45 +01002691
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002692 ts = stkctr_entry(stkctr);
2693 if (!ts)
2694 return ACT_RET_CONT;
2695
2696 /* Store the sample in the required sc, and ignore errors. */
2697 ptr = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPT0);
Emeric Brunf7ab0bf2021-06-30 18:58:22 +02002698 if (!ptr)
2699 ptr = stktable_data_ptr_idx(stkctr->table, ts, STKTABLE_DT_GPT, 0);
2700
Willy Tarreau79c1e912016-01-25 14:54:45 +01002701 if (ptr) {
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002702 if (!rule->arg.gpt.expr)
2703 value = (unsigned int)(rule->arg.gpt.value);
2704 else {
2705 switch (rule->from) {
2706 case ACT_F_TCP_REQ_SES: smp_opt_dir = SMP_OPT_DIR_REQ; break;
2707 case ACT_F_TCP_REQ_CNT: smp_opt_dir = SMP_OPT_DIR_REQ; break;
2708 case ACT_F_TCP_RES_CNT: smp_opt_dir = SMP_OPT_DIR_RES; break;
2709 case ACT_F_HTTP_REQ: smp_opt_dir = SMP_OPT_DIR_REQ; break;
2710 case ACT_F_HTTP_RES: smp_opt_dir = SMP_OPT_DIR_RES; break;
2711 default:
2712 send_log(px, LOG_ERR, "stick table: internal error while setting gpt0.");
2713 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))
2714 ha_alert("stick table: internal error while executing setting gpt0.\n");
2715 return ACT_RET_CONT;
2716 }
2717
2718 /* Fetch and cast the expression. */
2719 smp = sample_fetch_as_type(px, sess, s, smp_opt_dir|SMP_OPT_FINAL, rule->arg.gpt.expr, SMP_T_SINT);
2720 if (!smp) {
2721 send_log(px, LOG_WARNING, "stick table: invalid expression or data type while setting gpt0.");
2722 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))
2723 ha_alert("stick table: invalid expression or data type while setting gpt0.\n");
2724 return ACT_RET_CONT;
2725 }
2726 value = (unsigned int)(smp->data.u.sint);
2727 }
2728
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002729 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002730
Emeric Brun0e3457b2021-06-30 17:18:28 +02002731 stktable_data_cast(ptr, std_t_uint) = value;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002732
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002733 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002734
2735 stktable_touch_local(stkctr->table, ts, 0);
Willy Tarreau79c1e912016-01-25 14:54:45 +01002736 }
2737
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002738 return ACT_RET_CONT;
2739}
2740
Emeric Brun877b0b52021-06-30 18:57:49 +02002741/* This function is a parser for the "sc-set-gpt" and "sc-set-gpt0" actions.
2742 * It understands the formats:
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002743 *
Emeric Brun877b0b52021-06-30 18:57:49 +02002744 * sc-set-gpt(<gpt IDX>,<track ID>) <expression>
2745 * sc-set-gpt0(<track ID>) <expression>
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002746 *
Emeric Brun877b0b52021-06-30 18:57:49 +02002747 * It returns ACT_RET_PRS_ERR if fails and <err> is filled with an error message.
2748 * Otherwise, it returns ACT_RET_PRS_OK and the variable 'rule->arg.gpt.expr'
2749 * is filled with the pointer to the expression to execute or NULL if the arg
2750 * is directly an integer stored into 'rule->arg.gpt.value'.
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002751 */
Emeric Brun877b0b52021-06-30 18:57:49 +02002752static enum act_parse_ret parse_set_gpt(const char **args, int *arg, struct proxy *px,
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002753 struct act_rule *rule, char **err)
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002754{
2755 const char *cmd_name = args[*arg-1];
2756 char *error;
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002757 int smp_val;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002758
Emeric Brun877b0b52021-06-30 18:57:49 +02002759 cmd_name += strlen("sc-set-gpt");
2760 if (*cmd_name == '(') {
2761 cmd_name++; /* skip the '(' */
2762 rule->arg.gpt.idx = strtoul(cmd_name, &error, 10); /* Convert stick table id. */
2763 if (*error != ',') {
2764 memprintf(err, "Missing gpt ID '%s'. Expects sc-set-gpt(<GPT ID>,<Track ID>)", args[*arg-1]);
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002765 return ACT_RET_PRS_ERR;
2766 }
Emeric Brun877b0b52021-06-30 18:57:49 +02002767 else {
2768 cmd_name = error + 1; /* skip the ',' */
2769 rule->arg.gpt.sc = strtol(cmd_name, &error, 10); /* Convert stick table id. */
2770 if (*error != ')') {
2771 memprintf(err, "invalid stick table track ID '%s'. Expects sc-set-gpt(<GPT ID>,<Track ID>)", args[*arg-1]);
2772 return ACT_RET_PRS_ERR;
2773 }
2774
2775 if (rule->arg.gpt.sc >= MAX_SESS_STKCTR) {
2776 memprintf(err, "invalid stick table track ID '%s'. The max allowed ID is %d",
2777 args[*arg-1], MAX_SESS_STKCTR-1);
2778 return ACT_RET_PRS_ERR;
2779 }
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002780 }
Emeric Brun877b0b52021-06-30 18:57:49 +02002781 rule->action_ptr = action_set_gpt;
2782 }
2783 else if (*cmd_name == '0') {
2784 cmd_name++;
2785 if (*cmd_name == '\0') {
2786 /* default stick table id. */
2787 rule->arg.gpt.sc = 0;
2788 } else {
2789 /* parse the stick table id. */
2790 if (*cmd_name != '(') {
2791 memprintf(err, "invalid stick table track ID '%s'. Expects sc-set-gpt0(<Track ID>)", args[*arg-1]);
2792 return ACT_RET_PRS_ERR;
2793 }
2794 cmd_name++; /* jump the '(' */
2795 rule->arg.gpt.sc = strtol(cmd_name, &error, 10); /* Convert stick table id. */
2796 if (*error != ')') {
2797 memprintf(err, "invalid stick table track ID '%s'. Expects sc-set-gpt0(<Track ID>)", args[*arg-1]);
2798 return ACT_RET_PRS_ERR;
2799 }
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002800
Emeric Brun877b0b52021-06-30 18:57:49 +02002801 if (rule->arg.gpt.sc >= MAX_SESS_STKCTR) {
2802 memprintf(err, "invalid stick table track ID '%s'. The max allowed ID is %d",
2803 args[*arg-1], MAX_SESS_STKCTR-1);
2804 return ACT_RET_PRS_ERR;
2805 }
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002806 }
Emeric Brun877b0b52021-06-30 18:57:49 +02002807 rule->action_ptr = action_set_gpt0;
2808 }
2809 else {
2810 /* default stick table id. */
2811 memprintf(err, "invalid gpt ID '%s'. Expects sc-set-gpt(<GPT ID>,<Track ID>)", args[*arg-1]);
2812 return ACT_RET_PRS_ERR;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002813 }
2814
Willy Tarreauece4c4a2021-08-24 14:57:28 +02002815 /* value may be either an integer or an expression */
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002816 rule->arg.gpt.expr = NULL;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002817 rule->arg.gpt.value = strtol(args[*arg], &error, 10);
Willy Tarreauece4c4a2021-08-24 14:57:28 +02002818 if (*error == '\0') {
2819 /* valid integer, skip it */
2820 (*arg)++;
2821 } else {
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002822 rule->arg.gpt.expr = sample_parse_expr((char **)args, arg, px->conf.args.file,
Willy Tarreaue3b57bf2020-02-14 16:50:14 +01002823 px->conf.args.line, err, &px->conf.args, NULL);
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002824 if (!rule->arg.gpt.expr)
2825 return ACT_RET_PRS_ERR;
2826
2827 switch (rule->from) {
2828 case ACT_F_TCP_REQ_SES: smp_val = SMP_VAL_FE_SES_ACC; break;
2829 case ACT_F_TCP_REQ_CNT: smp_val = SMP_VAL_FE_REQ_CNT; break;
2830 case ACT_F_TCP_RES_CNT: smp_val = SMP_VAL_BE_RES_CNT; break;
2831 case ACT_F_HTTP_REQ: smp_val = SMP_VAL_FE_HRQ_HDR; break;
2832 case ACT_F_HTTP_RES: smp_val = SMP_VAL_BE_HRS_HDR; break;
2833 default:
2834 memprintf(err, "internal error, unexpected rule->from=%d, please report this bug!", rule->from);
2835 return ACT_RET_PRS_ERR;
2836 }
2837 if (!(rule->arg.gpt.expr->fetch->val & smp_val)) {
2838 memprintf(err, "fetch method '%s' extracts information from '%s', none of which is available here", args[*arg-1],
2839 sample_src_names(rule->arg.gpt.expr->fetch->use));
2840 free(rule->arg.gpt.expr);
2841 return ACT_RET_PRS_ERR;
2842 }
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002843 }
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002844
Thierry FOURNIER42148732015-09-02 17:17:33 +02002845 rule->action = ACT_CUSTOM;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002846
2847 return ACT_RET_PRS_OK;
2848}
2849
Willy Tarreau7d562212016-11-25 16:10:05 +01002850/* set temp integer to the number of used entries in the table pointed to by expr.
2851 * Accepts exactly 1 argument of type table.
2852 */
2853static int
2854smp_fetch_table_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
2855{
2856 smp->flags = SMP_F_VOL_TEST;
2857 smp->data.type = SMP_T_SINT;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002858 smp->data.u.sint = args->data.t->current;
Willy Tarreau7d562212016-11-25 16:10:05 +01002859 return 1;
2860}
2861
2862/* set temp integer to the number of free entries in the table pointed to by expr.
2863 * Accepts exactly 1 argument of type table.
2864 */
2865static int
2866smp_fetch_table_avl(const struct arg *args, struct sample *smp, const char *kw, void *private)
2867{
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002868 struct stktable *t;
Willy Tarreau7d562212016-11-25 16:10:05 +01002869
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002870 t = args->data.t;
Willy Tarreau7d562212016-11-25 16:10:05 +01002871 smp->flags = SMP_F_VOL_TEST;
2872 smp->data.type = SMP_T_SINT;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002873 smp->data.u.sint = t->size - t->current;
Willy Tarreau7d562212016-11-25 16:10:05 +01002874 return 1;
2875}
2876
2877/* Returns a pointer to a stkctr depending on the fetch keyword name.
2878 * It is designed to be called as sc[0-9]_* sc_* or src_* exclusively.
2879 * sc[0-9]_* will return a pointer to the respective field in the
2880 * stream <l4>. sc_* requires an UINT argument specifying the stick
2881 * counter number. src_* will fill a locally allocated structure with
2882 * the table and entry corresponding to what is specified with src_*.
2883 * NULL may be returned if the designated stkctr is not tracked. For
2884 * the sc_* and sc[0-9]_* forms, an optional table argument may be
2885 * passed. When present, the currently tracked key is then looked up
2886 * in the specified table instead of the current table. The purpose is
Ilya Shipitsin47d17182020-06-21 21:42:57 +05002887 * to be able to convert multiple values per key (eg: have gpc0 from
Willy Tarreau7d562212016-11-25 16:10:05 +01002888 * multiple tables). <strm> is allowed to be NULL, in which case only
2889 * the session will be consulted.
2890 */
2891struct stkctr *
Emeric Brun819fc6f2017-06-13 19:37:32 +02002892smp_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 +01002893{
Willy Tarreau7d562212016-11-25 16:10:05 +01002894 struct stkctr *stkptr;
2895 struct stksess *stksess;
2896 unsigned int num = kw[2] - '0';
2897 int arg = 0;
2898
2899 if (num == '_' - '0') {
2900 /* sc_* variant, args[0] = ctr# (mandatory) */
2901 num = args[arg++].data.sint;
Willy Tarreau7d562212016-11-25 16:10:05 +01002902 }
2903 else if (num > 9) { /* src_* variant, args[0] = table */
2904 struct stktable_key *key;
2905 struct connection *conn = objt_conn(sess->origin);
2906 struct sample smp;
2907
2908 if (!conn)
2909 return NULL;
2910
Joseph Herlant5662fa42018-11-15 13:43:28 -08002911 /* Fetch source address in a sample. */
Willy Tarreau7d562212016-11-25 16:10:05 +01002912 smp.px = NULL;
2913 smp.sess = sess;
2914 smp.strm = strm;
Amaury Denoyellec460c702021-05-12 10:17:47 +02002915 if (!smp_fetch_src || !smp_fetch_src(empty_arg_list, &smp, "src", NULL))
Willy Tarreau7d562212016-11-25 16:10:05 +01002916 return NULL;
2917
2918 /* Converts into key. */
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002919 key = smp_to_stkey(&smp, args->data.t);
Willy Tarreau7d562212016-11-25 16:10:05 +01002920 if (!key)
2921 return NULL;
2922
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002923 stkctr->table = args->data.t;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002924 stkctr_set_entry(stkctr, stktable_lookup_key(stkctr->table, key));
2925 return stkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002926 }
2927
2928 /* Here, <num> contains the counter number from 0 to 9 for
2929 * the sc[0-9]_ form, or even higher using sc_(num) if needed.
2930 * args[arg] is the first optional argument. We first lookup the
2931 * ctr form the stream, then from the session if it was not there.
Christopher Fauleta9fa88a2019-10-21 10:53:34 +02002932 * But we must be sure the counter does not exceed MAX_SESS_STKCTR.
Willy Tarreau7d562212016-11-25 16:10:05 +01002933 */
Christopher Fauleta9fa88a2019-10-21 10:53:34 +02002934 if (num >= MAX_SESS_STKCTR)
2935 return NULL;
Willy Tarreau7d562212016-11-25 16:10:05 +01002936
2937 if (strm)
2938 stkptr = &strm->stkctr[num];
2939 if (!strm || !stkctr_entry(stkptr)) {
2940 stkptr = &sess->stkctr[num];
2941 if (!stkctr_entry(stkptr))
2942 return NULL;
2943 }
2944
2945 stksess = stkctr_entry(stkptr);
2946 if (!stksess)
2947 return NULL;
2948
2949 if (unlikely(args[arg].type == ARGT_TAB)) {
2950 /* an alternate table was specified, let's look up the same key there */
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002951 stkctr->table = args[arg].data.t;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002952 stkctr_set_entry(stkctr, stktable_lookup(stkctr->table, stksess));
2953 return stkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002954 }
2955 return stkptr;
2956}
2957
2958/* same as smp_fetch_sc_stkctr() but dedicated to src_* and can create
2959 * the entry if it doesn't exist yet. This is needed for a few fetch
2960 * functions which need to create an entry, such as src_inc_gpc* and
2961 * src_clr_gpc*.
2962 */
2963struct stkctr *
Emeric Brun819fc6f2017-06-13 19:37:32 +02002964smp_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 +01002965{
Willy Tarreau7d562212016-11-25 16:10:05 +01002966 struct stktable_key *key;
2967 struct connection *conn = objt_conn(sess->origin);
2968 struct sample smp;
2969
2970 if (strncmp(kw, "src_", 4) != 0)
2971 return NULL;
2972
2973 if (!conn)
2974 return NULL;
2975
Joseph Herlant5662fa42018-11-15 13:43:28 -08002976 /* Fetch source address in a sample. */
Willy Tarreau7d562212016-11-25 16:10:05 +01002977 smp.px = NULL;
2978 smp.sess = sess;
2979 smp.strm = strm;
Amaury Denoyellec460c702021-05-12 10:17:47 +02002980 if (!smp_fetch_src || !smp_fetch_src(empty_arg_list, &smp, "src", NULL))
Willy Tarreau7d562212016-11-25 16:10:05 +01002981 return NULL;
2982
2983 /* Converts into key. */
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002984 key = smp_to_stkey(&smp, args->data.t);
Willy Tarreau7d562212016-11-25 16:10:05 +01002985 if (!key)
2986 return NULL;
2987
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002988 stkctr->table = args->data.t;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002989 stkctr_set_entry(stkctr, stktable_get_entry(stkctr->table, key));
2990 return stkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002991}
2992
2993/* set return a boolean indicating if the requested stream counter is
2994 * currently being tracked or not.
2995 * Supports being called as "sc[0-9]_tracked" only.
2996 */
2997static int
2998smp_fetch_sc_tracked(const struct arg *args, struct sample *smp, const char *kw, void *private)
2999{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003000 struct stkctr tmpstkctr;
3001 struct stkctr *stkctr;
3002
Willy Tarreau7d562212016-11-25 16:10:05 +01003003 smp->flags = SMP_F_VOL_TEST;
3004 smp->data.type = SMP_T_BOOL;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003005 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
3006 smp->data.u.sint = !!stkctr;
3007
3008 /* release the ref count */
Dirkjan Bussinkff57f1b2018-09-14 14:31:22 +02003009 if (stkctr == &tmpstkctr)
Emeric Brun819fc6f2017-06-13 19:37:32 +02003010 stktable_release(stkctr->table, stkctr_entry(stkctr));
3011
Emeric Brun877b0b52021-06-30 18:57:49 +02003012 return 1;
3013}
3014
3015/* set <smp> to the General Purpose Tag of index set as first arg
3016 * to value from the stream's tracked frontend counters or from the src.
3017 * Supports being called as "sc_get_gpt(<gpt-idx>,<sc-idx>[,<table>])" or
3018 * "src_get_gpt(<gpt-idx>[,<table>])" only. Value zero is returned if
3019 * the key is new or gpt is not stored.
3020 */
3021static int
3022smp_fetch_sc_get_gpt(const struct arg *args, struct sample *smp, const char *kw, void *private)
3023{
3024 struct stkctr tmpstkctr;
3025 struct stkctr *stkctr;
3026 unsigned int idx;
3027
3028 idx = args[0].data.sint;
3029
3030 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args + 1, kw, &tmpstkctr);
3031 if (!stkctr)
3032 return 0;
3033
3034 smp->flags = SMP_F_VOL_TEST;
3035 smp->data.type = SMP_T_SINT;
3036 smp->data.u.sint = 0;
3037
3038 if (stkctr_entry(stkctr)) {
3039 void *ptr;
3040
3041 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPT, idx);
3042 if (!ptr) {
3043 if (stkctr == &tmpstkctr)
3044 stktable_release(stkctr->table, stkctr_entry(stkctr));
3045 return 0; /* parameter not stored */
3046 }
3047
3048 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3049
3050 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
3051
3052 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3053
3054 if (stkctr == &tmpstkctr)
3055 stktable_release(stkctr->table, stkctr_entry(stkctr));
3056 }
Willy Tarreau7d562212016-11-25 16:10:05 +01003057 return 1;
3058}
3059
3060/* set <smp> to the General Purpose Flag 0 value from the stream's tracked
3061 * frontend counters or from the src.
3062 * Supports being called as "sc[0-9]_get_gpc0" or "src_get_gpt0" only. Value
3063 * zero is returned if the key is new.
3064 */
3065static int
3066smp_fetch_sc_get_gpt0(const struct arg *args, struct sample *smp, const char *kw, void *private)
3067{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003068 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003069 struct stkctr *stkctr;
3070
Emeric Brun819fc6f2017-06-13 19:37:32 +02003071 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003072 if (!stkctr)
3073 return 0;
3074
3075 smp->flags = SMP_F_VOL_TEST;
3076 smp->data.type = SMP_T_SINT;
3077 smp->data.u.sint = 0;
3078
Emeric Brun819fc6f2017-06-13 19:37:32 +02003079 if (stkctr_entry(stkctr)) {
3080 void *ptr;
3081
3082 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPT0);
Emeric Brunf7ab0bf2021-06-30 18:58:22 +02003083 if (!ptr)
3084 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPT, 0);
3085
Emeric Brun4d7ada82021-06-30 19:04:16 +02003086 if (!ptr) {
3087 if (stkctr == &tmpstkctr)
3088 stktable_release(stkctr->table, stkctr_entry(stkctr));
3089 return 0; /* parameter not stored */
3090 }
3091
3092 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3093
3094 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
3095
3096 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3097
3098 if (stkctr == &tmpstkctr)
3099 stktable_release(stkctr->table, stkctr_entry(stkctr));
3100 }
3101 return 1;
3102}
3103
3104/* set <smp> to the GPC[args(0)]'s value from the stream's tracked
3105 * frontend counters or from the src.
3106 * Supports being called as "sc_get_gpc(<gpc-idx>,<sc-idx>[,<table>])" or
3107 * "src_get_gpc(<gpc-idx>[,<table>])" only. Value
3108 * Value zero is returned if the key is new or gpc is not stored.
3109 */
3110static int
3111smp_fetch_sc_get_gpc(const struct arg *args, struct sample *smp, const char *kw, void *private)
3112{
3113 struct stkctr tmpstkctr;
3114 struct stkctr *stkctr;
3115 unsigned int idx;
3116
3117 idx = args[0].data.sint;
3118
3119 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args + 1, kw, &tmpstkctr);
3120 if (!stkctr)
3121 return 0;
3122
3123 smp->flags = SMP_F_VOL_TEST;
3124 smp->data.type = SMP_T_SINT;
3125 smp->data.u.sint = 0;
3126
3127 if (stkctr_entry(stkctr) != NULL) {
3128 void *ptr;
3129
3130 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC, idx);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003131 if (!ptr) {
3132 if (stkctr == &tmpstkctr)
3133 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003134 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003135 }
3136
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003137 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003138
Emeric Brun0e3457b2021-06-30 17:18:28 +02003139 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003140
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003141 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003142
3143 if (stkctr == &tmpstkctr)
3144 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003145 }
3146 return 1;
3147}
3148
3149/* set <smp> to the General Purpose Counter 0 value from the stream's tracked
3150 * frontend counters or from the src.
3151 * Supports being called as "sc[0-9]_get_gpc0" or "src_get_gpc0" only. Value
3152 * zero is returned if the key is new.
3153 */
3154static int
3155smp_fetch_sc_get_gpc0(const struct arg *args, struct sample *smp, const char *kw, void *private)
3156{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003157 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003158 struct stkctr *stkctr;
3159
Emeric Brun819fc6f2017-06-13 19:37:32 +02003160 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003161 if (!stkctr)
3162 return 0;
3163
3164 smp->flags = SMP_F_VOL_TEST;
3165 smp->data.type = SMP_T_SINT;
3166 smp->data.u.sint = 0;
3167
3168 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003169 void *ptr;
3170
3171 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0);
3172 if (!ptr) {
Emeric Brun726783d2021-06-30 19:06:43 +02003173 /* fallback on the gpc array */
3174 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC, 0);
3175 }
3176
3177 if (!ptr) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003178 if (stkctr == &tmpstkctr)
3179 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003180 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003181 }
3182
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003183 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003184
Emeric Brun0e3457b2021-06-30 17:18:28 +02003185 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003186
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003187 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003188
3189 if (stkctr == &tmpstkctr)
3190 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003191 }
3192 return 1;
3193}
3194
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003195/* set <smp> to the General Purpose Counter 1 value from the stream's tracked
3196 * frontend counters or from the src.
3197 * Supports being called as "sc[0-9]_get_gpc1" or "src_get_gpc1" only. Value
3198 * zero is returned if the key is new.
3199 */
3200static int
3201smp_fetch_sc_get_gpc1(const struct arg *args, struct sample *smp, const char *kw, void *private)
3202{
3203 struct stkctr tmpstkctr;
3204 struct stkctr *stkctr;
3205
3206 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
3207 if (!stkctr)
3208 return 0;
3209
3210 smp->flags = SMP_F_VOL_TEST;
3211 smp->data.type = SMP_T_SINT;
3212 smp->data.u.sint = 0;
3213
3214 if (stkctr_entry(stkctr) != NULL) {
3215 void *ptr;
3216
3217 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1);
3218 if (!ptr) {
Emeric Brun726783d2021-06-30 19:06:43 +02003219 /* fallback on the gpc array */
3220 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC, 1);
3221 }
3222
3223 if (!ptr) {
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003224 if (stkctr == &tmpstkctr)
3225 stktable_release(stkctr->table, stkctr_entry(stkctr));
3226 return 0; /* parameter not stored */
3227 }
3228
3229 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3230
Emeric Brun0e3457b2021-06-30 17:18:28 +02003231 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003232
3233 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3234
3235 if (stkctr == &tmpstkctr)
3236 stktable_release(stkctr->table, stkctr_entry(stkctr));
3237 }
3238 return 1;
3239}
3240
Emeric Brun4d7ada82021-06-30 19:04:16 +02003241/* set <smp> to the GPC[args(0)]'s event rate from the stream's
3242 * tracked frontend counters or from the src.
3243 * Supports being called as "sc_gpc_rate(<gpc-idx>,<sc-idx>[,<table])"
3244 * or "src_gpc_rate(<gpc-idx>[,<table>])" only.
3245 * Value zero is returned if the key is new or gpc_rate is not stored.
3246 */
3247static int
3248smp_fetch_sc_gpc_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3249{
3250 struct stkctr tmpstkctr;
3251 struct stkctr *stkctr;
3252 unsigned int idx;
3253
3254 idx = args[0].data.sint;
3255
3256 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args + 1, kw, &tmpstkctr);
3257 if (!stkctr)
3258 return 0;
3259
3260 smp->flags = SMP_F_VOL_TEST;
3261 smp->data.type = SMP_T_SINT;
3262 smp->data.u.sint = 0;
3263 if (stkctr_entry(stkctr) != NULL) {
3264 void *ptr;
3265
3266 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC_RATE, idx);
3267 if (!ptr) {
3268 if (stkctr == &tmpstkctr)
3269 stktable_release(stkctr->table, stkctr_entry(stkctr));
3270 return 0; /* parameter not stored */
3271 }
3272
3273 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3274
3275 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
3276 stkctr->table->data_arg[STKTABLE_DT_GPC_RATE].u);
3277
3278 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3279
3280 if (stkctr == &tmpstkctr)
3281 stktable_release(stkctr->table, stkctr_entry(stkctr));
3282 }
3283 return 1;
3284}
3285
Willy Tarreau7d562212016-11-25 16:10:05 +01003286/* set <smp> to the General Purpose Counter 0's event rate from the stream's
3287 * tracked frontend counters or from the src.
3288 * Supports being called as "sc[0-9]_gpc0_rate" or "src_gpc0_rate" only.
3289 * Value zero is returned if the key is new.
3290 */
3291static int
3292smp_fetch_sc_gpc0_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3293{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003294 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003295 struct stkctr *stkctr;
Emeric Brun726783d2021-06-30 19:06:43 +02003296 unsigned int period;
Willy Tarreau7d562212016-11-25 16:10:05 +01003297
Emeric Brun819fc6f2017-06-13 19:37:32 +02003298 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003299 if (!stkctr)
3300 return 0;
3301
3302 smp->flags = SMP_F_VOL_TEST;
3303 smp->data.type = SMP_T_SINT;
3304 smp->data.u.sint = 0;
3305 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003306 void *ptr;
3307
3308 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0_RATE);
Emeric Brun726783d2021-06-30 19:06:43 +02003309 if (ptr) {
3310 period = stkctr->table->data_arg[STKTABLE_DT_GPC0_RATE].u;
3311 }
3312 else {
3313 /* fallback on the gpc array */
3314 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC_RATE, 0);
3315 if (ptr)
3316 period = stkctr->table->data_arg[STKTABLE_DT_GPC_RATE].u;
3317 }
3318
Emeric Brun819fc6f2017-06-13 19:37:32 +02003319 if (!ptr) {
3320 if (stkctr == &tmpstkctr)
3321 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003322 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003323 }
3324
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003325 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003326
Emeric Brun726783d2021-06-30 19:06:43 +02003327 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp), period);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003328
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003329 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003330
3331 if (stkctr == &tmpstkctr)
3332 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003333 }
3334 return 1;
3335}
3336
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003337/* set <smp> to the General Purpose Counter 1's event rate from the stream's
3338 * tracked frontend counters or from the src.
3339 * Supports being called as "sc[0-9]_gpc1_rate" or "src_gpc1_rate" only.
3340 * Value zero is returned if the key is new.
3341 */
3342static int
3343smp_fetch_sc_gpc1_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3344{
3345 struct stkctr tmpstkctr;
3346 struct stkctr *stkctr;
Emeric Brun726783d2021-06-30 19:06:43 +02003347 unsigned int period;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003348
3349 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
3350 if (!stkctr)
3351 return 0;
3352
3353 smp->flags = SMP_F_VOL_TEST;
3354 smp->data.type = SMP_T_SINT;
3355 smp->data.u.sint = 0;
3356 if (stkctr_entry(stkctr) != NULL) {
3357 void *ptr;
3358
3359 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1_RATE);
Emeric Brun726783d2021-06-30 19:06:43 +02003360 if (ptr) {
3361 period = stkctr->table->data_arg[STKTABLE_DT_GPC1_RATE].u;
3362 }
3363 else {
3364 /* fallback on the gpc array */
3365 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC_RATE, 1);
3366 if (ptr)
3367 period = stkctr->table->data_arg[STKTABLE_DT_GPC_RATE].u;
3368 }
3369
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003370 if (!ptr) {
3371 if (stkctr == &tmpstkctr)
3372 stktable_release(stkctr->table, stkctr_entry(stkctr));
3373 return 0; /* parameter not stored */
3374 }
3375
3376 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3377
Emeric Brun726783d2021-06-30 19:06:43 +02003378 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 +01003379
3380 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3381
3382 if (stkctr == &tmpstkctr)
3383 stktable_release(stkctr->table, stkctr_entry(stkctr));
3384 }
3385 return 1;
3386}
3387
Emeric Brun4d7ada82021-06-30 19:04:16 +02003388/* Increment the GPC[args(0)] value from the stream's tracked
3389 * frontend counters and return it into temp integer.
3390 * Supports being called as "sc_inc_gpc(<gpc-idx>,<sc-idx>[,<table>])"
3391 * or "src_inc_gpc(<gpc-idx>[,<table>])" only.
3392 */
3393static int
3394smp_fetch_sc_inc_gpc(const struct arg *args, struct sample *smp, const char *kw, void *private)
3395{
3396 struct stkctr tmpstkctr;
3397 struct stkctr *stkctr;
3398 unsigned int idx;
3399
3400 idx = args[0].data.sint;
3401
3402 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args + 1, kw, &tmpstkctr);
3403 if (!stkctr)
3404 return 0;
3405
3406 smp->flags = SMP_F_VOL_TEST;
3407 smp->data.type = SMP_T_SINT;
3408 smp->data.u.sint = 0;
3409
3410 if (!stkctr_entry(stkctr))
3411 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
3412
3413 if (stkctr && stkctr_entry(stkctr)) {
3414 void *ptr1,*ptr2;
3415
3416
3417 /* First, update gpc0_rate if it's tracked. Second, update its
3418 * gpc0 if tracked. Returns gpc0's value otherwise the curr_ctr.
3419 */
3420 ptr1 = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC_RATE, idx);
3421 ptr2 = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC, idx);
3422 if (ptr1 || ptr2) {
3423 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3424
3425 if (ptr1) {
3426 update_freq_ctr_period(&stktable_data_cast(ptr1, std_t_frqp),
3427 stkctr->table->data_arg[STKTABLE_DT_GPC_RATE].u, 1);
3428 smp->data.u.sint = (&stktable_data_cast(ptr1, std_t_frqp))->curr_ctr;
3429 }
3430
3431 if (ptr2)
3432 smp->data.u.sint = ++stktable_data_cast(ptr2, std_t_uint);
3433
3434 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3435
3436 /* If data was modified, we need to touch to re-schedule sync */
3437 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
3438 }
3439 else if (stkctr == &tmpstkctr)
3440 stktable_release(stkctr->table, stkctr_entry(stkctr));
3441 }
3442 return 1;
3443}
3444
Willy Tarreau7d562212016-11-25 16:10:05 +01003445/* Increment the General Purpose Counter 0 value from the stream's tracked
3446 * frontend counters and return it into temp integer.
3447 * Supports being called as "sc[0-9]_inc_gpc0" or "src_inc_gpc0" only.
3448 */
3449static int
3450smp_fetch_sc_inc_gpc0(const struct arg *args, struct sample *smp, const char *kw, void *private)
3451{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003452 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003453 struct stkctr *stkctr;
Willy Tarreau5b654ad2021-07-06 18:51:12 +02003454 unsigned int period = 0;
Willy Tarreau7d562212016-11-25 16:10:05 +01003455
Emeric Brun819fc6f2017-06-13 19:37:32 +02003456 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003457 if (!stkctr)
3458 return 0;
3459
3460 smp->flags = SMP_F_VOL_TEST;
3461 smp->data.type = SMP_T_SINT;
3462 smp->data.u.sint = 0;
3463
Emeric Brun819fc6f2017-06-13 19:37:32 +02003464 if (!stkctr_entry(stkctr))
3465 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003466
3467 if (stkctr && stkctr_entry(stkctr)) {
3468 void *ptr1,*ptr2;
3469
Emeric Brun819fc6f2017-06-13 19:37:32 +02003470
Willy Tarreau7d562212016-11-25 16:10:05 +01003471 /* First, update gpc0_rate if it's tracked. Second, update its
3472 * gpc0 if tracked. Returns gpc0's value otherwise the curr_ctr.
3473 */
3474 ptr1 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0_RATE);
Emeric Brun726783d2021-06-30 19:06:43 +02003475 if (ptr1) {
3476 period = stkctr->table->data_arg[STKTABLE_DT_GPC0_RATE].u;
3477 }
3478 else {
3479 /* fallback on the gpc array */
3480 ptr1 = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC_RATE, 0);
3481 if (ptr1)
3482 period = stkctr->table->data_arg[STKTABLE_DT_GPC_RATE].u;
3483 }
3484
Willy Tarreau7d562212016-11-25 16:10:05 +01003485 ptr2 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0);
Emeric Brun726783d2021-06-30 19:06:43 +02003486 if (!ptr2) {
3487 /* fallback on the gpc array */
3488 ptr2 = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC, 0);
3489 }
3490
Emeric Brun819fc6f2017-06-13 19:37:32 +02003491 if (ptr1 || ptr2) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003492 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Willy Tarreau7d562212016-11-25 16:10:05 +01003493
Emeric Brun819fc6f2017-06-13 19:37:32 +02003494 if (ptr1) {
Emeric Brun0e3457b2021-06-30 17:18:28 +02003495 update_freq_ctr_period(&stktable_data_cast(ptr1, std_t_frqp),
Emeric Brun726783d2021-06-30 19:06:43 +02003496 period, 1);
Emeric Brun0e3457b2021-06-30 17:18:28 +02003497 smp->data.u.sint = (&stktable_data_cast(ptr1, std_t_frqp))->curr_ctr;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003498 }
3499
3500 if (ptr2)
Emeric Brun0e3457b2021-06-30 17:18:28 +02003501 smp->data.u.sint = ++stktable_data_cast(ptr2, std_t_uint);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003502
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003503 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003504
3505 /* If data was modified, we need to touch to re-schedule sync */
3506 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
3507 }
3508 else if (stkctr == &tmpstkctr)
3509 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003510 }
3511 return 1;
3512}
3513
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003514/* Increment the General Purpose Counter 1 value from the stream's tracked
3515 * frontend counters and return it into temp integer.
3516 * Supports being called as "sc[0-9]_inc_gpc1" or "src_inc_gpc1" only.
3517 */
3518static int
3519smp_fetch_sc_inc_gpc1(const struct arg *args, struct sample *smp, const char *kw, void *private)
3520{
3521 struct stkctr tmpstkctr;
3522 struct stkctr *stkctr;
Willy Tarreau5b654ad2021-07-06 18:51:12 +02003523 unsigned int period = 0;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003524
3525 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
3526 if (!stkctr)
3527 return 0;
3528
3529 smp->flags = SMP_F_VOL_TEST;
3530 smp->data.type = SMP_T_SINT;
3531 smp->data.u.sint = 0;
3532
3533 if (!stkctr_entry(stkctr))
3534 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
3535
3536 if (stkctr && stkctr_entry(stkctr)) {
3537 void *ptr1,*ptr2;
3538
3539
3540 /* First, update gpc1_rate if it's tracked. Second, update its
3541 * gpc1 if tracked. Returns gpc1's value otherwise the curr_ctr.
3542 */
3543 ptr1 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1_RATE);
Emeric Brun726783d2021-06-30 19:06:43 +02003544 if (ptr1) {
3545 period = stkctr->table->data_arg[STKTABLE_DT_GPC1_RATE].u;
3546 }
3547 else {
3548 /* fallback on the gpc array */
3549 ptr1 = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC_RATE, 1);
3550 if (ptr1)
3551 period = stkctr->table->data_arg[STKTABLE_DT_GPC_RATE].u;
3552 }
3553
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003554 ptr2 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1);
Emeric Brun726783d2021-06-30 19:06:43 +02003555 if (!ptr2) {
3556 /* fallback on the gpc array */
3557 ptr2 = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC, 1);
3558 }
3559
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003560 if (ptr1 || ptr2) {
3561 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3562
3563 if (ptr1) {
Emeric Brun0e3457b2021-06-30 17:18:28 +02003564 update_freq_ctr_period(&stktable_data_cast(ptr1, std_t_frqp),
Emeric Brun726783d2021-06-30 19:06:43 +02003565 period, 1);
Emeric Brun0e3457b2021-06-30 17:18:28 +02003566 smp->data.u.sint = (&stktable_data_cast(ptr1, std_t_frqp))->curr_ctr;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003567 }
3568
3569 if (ptr2)
Emeric Brun0e3457b2021-06-30 17:18:28 +02003570 smp->data.u.sint = ++stktable_data_cast(ptr2, std_t_uint);
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003571
3572 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3573
3574 /* If data was modified, we need to touch to re-schedule sync */
3575 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
3576 }
3577 else if (stkctr == &tmpstkctr)
3578 stktable_release(stkctr->table, stkctr_entry(stkctr));
3579 }
3580 return 1;
3581}
3582
Emeric Brun4d7ada82021-06-30 19:04:16 +02003583/* Clear the GPC[args(0)] value from the stream's tracked
3584 * frontend counters and return its previous value into temp integer.
3585 * Supports being called as "sc_clr_gpc(<gpc-idx>,<sc-idx>[,<table>])"
3586 * or "src_clr_gpc(<gpc-idx>[,<table>])" only.
3587 */
3588static int
3589smp_fetch_sc_clr_gpc(const struct arg *args, struct sample *smp, const char *kw, void *private)
3590{
3591 struct stkctr tmpstkctr;
3592 struct stkctr *stkctr;
3593 unsigned int idx;
3594
3595 idx = args[0].data.sint;
3596
3597 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args + 1, kw, &tmpstkctr);
3598 if (!stkctr)
3599 return 0;
3600
3601 smp->flags = SMP_F_VOL_TEST;
3602 smp->data.type = SMP_T_SINT;
3603 smp->data.u.sint = 0;
3604
3605 if (!stkctr_entry(stkctr))
3606 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
3607
3608 if (stkctr && stkctr_entry(stkctr)) {
3609 void *ptr;
3610
3611 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC, idx);
3612 if (!ptr) {
3613 if (stkctr == &tmpstkctr)
3614 stktable_release(stkctr->table, stkctr_entry(stkctr));
3615 return 0; /* parameter not stored */
3616 }
3617
3618 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3619
3620 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
3621 stktable_data_cast(ptr, std_t_uint) = 0;
3622
3623 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3624
3625 /* If data was modified, we need to touch to re-schedule sync */
3626 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
3627 }
3628 return 1;
3629}
3630
Willy Tarreau7d562212016-11-25 16:10:05 +01003631/* Clear the General Purpose Counter 0 value from the stream's tracked
3632 * frontend counters and return its previous value into temp integer.
3633 * Supports being called as "sc[0-9]_clr_gpc0" or "src_clr_gpc0" only.
3634 */
3635static int
3636smp_fetch_sc_clr_gpc0(const struct arg *args, struct sample *smp, const char *kw, void *private)
3637{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003638 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003639 struct stkctr *stkctr;
3640
Emeric Brun819fc6f2017-06-13 19:37:32 +02003641 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003642 if (!stkctr)
3643 return 0;
3644
3645 smp->flags = SMP_F_VOL_TEST;
3646 smp->data.type = SMP_T_SINT;
3647 smp->data.u.sint = 0;
3648
Emeric Brun819fc6f2017-06-13 19:37:32 +02003649 if (!stkctr_entry(stkctr))
3650 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003651
Emeric Brun819fc6f2017-06-13 19:37:32 +02003652 if (stkctr && stkctr_entry(stkctr)) {
3653 void *ptr;
3654
3655 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0);
3656 if (!ptr) {
Emeric Brun726783d2021-06-30 19:06:43 +02003657 /* fallback on the gpc array */
3658 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC, 0);
3659 }
3660
3661 if (!ptr) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003662 if (stkctr == &tmpstkctr)
3663 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003664 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003665 }
3666
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003667 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003668
Emeric Brun0e3457b2021-06-30 17:18:28 +02003669 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
3670 stktable_data_cast(ptr, std_t_uint) = 0;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003671
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003672 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003673
Willy Tarreau7d562212016-11-25 16:10:05 +01003674 /* If data was modified, we need to touch to re-schedule sync */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003675 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
Willy Tarreau7d562212016-11-25 16:10:05 +01003676 }
3677 return 1;
3678}
3679
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003680/* Clear the General Purpose Counter 1 value from the stream's tracked
3681 * frontend counters and return its previous value into temp integer.
3682 * Supports being called as "sc[0-9]_clr_gpc1" or "src_clr_gpc1" only.
3683 */
3684static int
3685smp_fetch_sc_clr_gpc1(const struct arg *args, struct sample *smp, const char *kw, void *private)
3686{
3687 struct stkctr tmpstkctr;
3688 struct stkctr *stkctr;
3689
3690 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
3691 if (!stkctr)
3692 return 0;
3693
3694 smp->flags = SMP_F_VOL_TEST;
3695 smp->data.type = SMP_T_SINT;
3696 smp->data.u.sint = 0;
3697
3698 if (!stkctr_entry(stkctr))
3699 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
3700
3701 if (stkctr && stkctr_entry(stkctr)) {
3702 void *ptr;
3703
3704 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1);
3705 if (!ptr) {
Emeric Brun726783d2021-06-30 19:06:43 +02003706 /* fallback on the gpc array */
3707 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC, 1);
3708 }
3709
3710 if (!ptr) {
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003711 if (stkctr == &tmpstkctr)
3712 stktable_release(stkctr->table, stkctr_entry(stkctr));
3713 return 0; /* parameter not stored */
3714 }
3715
3716 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3717
Emeric Brun0e3457b2021-06-30 17:18:28 +02003718 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
3719 stktable_data_cast(ptr, std_t_uint) = 0;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003720
3721 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3722
3723 /* If data was modified, we need to touch to re-schedule sync */
3724 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
3725 }
3726 return 1;
3727}
3728
Willy Tarreau7d562212016-11-25 16:10:05 +01003729/* set <smp> to the cumulated number of connections from the stream's tracked
3730 * frontend counters. Supports being called as "sc[0-9]_conn_cnt" or
3731 * "src_conn_cnt" only.
3732 */
3733static int
3734smp_fetch_sc_conn_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
3735{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003736 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003737 struct stkctr *stkctr;
3738
Emeric Brun819fc6f2017-06-13 19:37:32 +02003739 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003740 if (!stkctr)
3741 return 0;
3742
3743 smp->flags = SMP_F_VOL_TEST;
3744 smp->data.type = SMP_T_SINT;
3745 smp->data.u.sint = 0;
3746 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003747 void *ptr;
3748
3749 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_CONN_CNT);
3750 if (!ptr) {
3751 if (stkctr == &tmpstkctr)
3752 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003753 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003754 }
3755
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003756 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003757
Emeric Brun0e3457b2021-06-30 17:18:28 +02003758 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003759
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003760 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003761
3762 if (stkctr == &tmpstkctr)
3763 stktable_release(stkctr->table, stkctr_entry(stkctr));
3764
3765
Willy Tarreau7d562212016-11-25 16:10:05 +01003766 }
3767 return 1;
3768}
3769
3770/* set <smp> to the connection rate from the stream's tracked frontend
3771 * counters. Supports being called as "sc[0-9]_conn_rate" or "src_conn_rate"
3772 * only.
3773 */
3774static int
3775smp_fetch_sc_conn_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3776{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003777 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003778 struct stkctr *stkctr;
3779
Emeric Brun819fc6f2017-06-13 19:37:32 +02003780 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003781 if (!stkctr)
3782 return 0;
3783
3784 smp->flags = SMP_F_VOL_TEST;
3785 smp->data.type = SMP_T_SINT;
3786 smp->data.u.sint = 0;
3787 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003788 void *ptr;
3789
3790 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_CONN_RATE);
3791 if (!ptr) {
3792 if (stkctr == &tmpstkctr)
3793 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003794 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003795 }
3796
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003797 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003798
Emeric Brun0e3457b2021-06-30 17:18:28 +02003799 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Willy Tarreau7d562212016-11-25 16:10:05 +01003800 stkctr->table->data_arg[STKTABLE_DT_CONN_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003801
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003802 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003803
3804 if (stkctr == &tmpstkctr)
3805 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003806 }
3807 return 1;
3808}
3809
3810/* set temp integer to the number of connections from the stream's source address
3811 * in the table pointed to by expr, after updating it.
3812 * Accepts exactly 1 argument of type table.
3813 */
3814static int
3815smp_fetch_src_updt_conn_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
3816{
3817 struct connection *conn = objt_conn(smp->sess->origin);
3818 struct stksess *ts;
3819 struct stktable_key *key;
3820 void *ptr;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003821 struct stktable *t;
Willy Tarreau7d562212016-11-25 16:10:05 +01003822
3823 if (!conn)
3824 return 0;
3825
Joseph Herlant5662fa42018-11-15 13:43:28 -08003826 /* Fetch source address in a sample. */
Amaury Denoyellec460c702021-05-12 10:17:47 +02003827 if (!smp_fetch_src || !smp_fetch_src(empty_arg_list, smp, "src", NULL))
Willy Tarreau7d562212016-11-25 16:10:05 +01003828 return 0;
3829
3830 /* Converts into key. */
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003831 key = smp_to_stkey(smp, args->data.t);
Willy Tarreau7d562212016-11-25 16:10:05 +01003832 if (!key)
3833 return 0;
3834
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003835 t = args->data.t;
Willy Tarreau7d562212016-11-25 16:10:05 +01003836
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003837 if ((ts = stktable_get_entry(t, key)) == NULL)
Willy Tarreau7d562212016-11-25 16:10:05 +01003838 /* entry does not exist and could not be created */
3839 return 0;
3840
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003841 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_CONN_CNT);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003842 if (!ptr) {
Willy Tarreau7d562212016-11-25 16:10:05 +01003843 return 0; /* parameter not stored in this table */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003844 }
Willy Tarreau7d562212016-11-25 16:10:05 +01003845
3846 smp->data.type = SMP_T_SINT;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003847
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003848 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003849
Emeric Brun0e3457b2021-06-30 17:18:28 +02003850 smp->data.u.sint = ++stktable_data_cast(ptr, std_t_uint);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003851
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003852 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003853
Willy Tarreau7d562212016-11-25 16:10:05 +01003854 smp->flags = SMP_F_VOL_TEST;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003855
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003856 stktable_touch_local(t, ts, 1);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003857
3858 /* Touch was previously performed by stktable_update_key */
Willy Tarreau7d562212016-11-25 16:10:05 +01003859 return 1;
3860}
3861
3862/* set <smp> to the number of concurrent connections from the stream's tracked
3863 * frontend counters. Supports being called as "sc[0-9]_conn_cur" or
3864 * "src_conn_cur" only.
3865 */
3866static int
3867smp_fetch_sc_conn_cur(const struct arg *args, struct sample *smp, const char *kw, void *private)
3868{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003869 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003870 struct stkctr *stkctr;
3871
Emeric Brun819fc6f2017-06-13 19:37:32 +02003872 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003873 if (!stkctr)
3874 return 0;
3875
3876 smp->flags = SMP_F_VOL_TEST;
3877 smp->data.type = SMP_T_SINT;
3878 smp->data.u.sint = 0;
3879 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003880 void *ptr;
3881
3882 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_CONN_CUR);
3883 if (!ptr) {
3884 if (stkctr == &tmpstkctr)
3885 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003886 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003887 }
3888
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003889 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003890
Emeric Brun0e3457b2021-06-30 17:18:28 +02003891 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003892
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003893 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003894
3895 if (stkctr == &tmpstkctr)
3896 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003897 }
3898 return 1;
3899}
3900
3901/* set <smp> to the cumulated number of streams from the stream's tracked
3902 * frontend counters. Supports being called as "sc[0-9]_sess_cnt" or
3903 * "src_sess_cnt" only.
3904 */
3905static int
3906smp_fetch_sc_sess_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
3907{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003908 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003909 struct stkctr *stkctr;
3910
Emeric Brun819fc6f2017-06-13 19:37:32 +02003911 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003912 if (!stkctr)
3913 return 0;
3914
3915 smp->flags = SMP_F_VOL_TEST;
3916 smp->data.type = SMP_T_SINT;
3917 smp->data.u.sint = 0;
3918 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003919 void *ptr;
3920
3921 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_SESS_CNT);
3922 if (!ptr) {
3923 if (stkctr == &tmpstkctr)
3924 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003925 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003926 }
3927
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003928 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003929
Emeric Brun0e3457b2021-06-30 17:18:28 +02003930 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003931
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003932 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003933
3934 if (stkctr == &tmpstkctr)
3935 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003936 }
3937 return 1;
3938}
3939
3940/* set <smp> to the stream rate from the stream's tracked frontend counters.
3941 * Supports being called as "sc[0-9]_sess_rate" or "src_sess_rate" only.
3942 */
3943static int
3944smp_fetch_sc_sess_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3945{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003946 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003947 struct stkctr *stkctr;
3948
Emeric Brun819fc6f2017-06-13 19:37:32 +02003949 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003950 if (!stkctr)
3951 return 0;
3952
3953 smp->flags = SMP_F_VOL_TEST;
3954 smp->data.type = SMP_T_SINT;
3955 smp->data.u.sint = 0;
3956 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003957 void *ptr;
3958
3959 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_SESS_RATE);
3960 if (!ptr) {
3961 if (stkctr == &tmpstkctr)
3962 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003963 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003964 }
3965
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003966 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003967
Emeric Brun0e3457b2021-06-30 17:18:28 +02003968 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Willy Tarreau7d562212016-11-25 16:10:05 +01003969 stkctr->table->data_arg[STKTABLE_DT_SESS_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003970
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003971 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003972
3973 if (stkctr == &tmpstkctr)
3974 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003975 }
3976 return 1;
3977}
3978
3979/* set <smp> to the cumulated number of HTTP requests from the stream's tracked
3980 * frontend counters. Supports being called as "sc[0-9]_http_req_cnt" or
3981 * "src_http_req_cnt" only.
3982 */
3983static int
3984smp_fetch_sc_http_req_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
3985{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003986 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003987 struct stkctr *stkctr;
3988
Emeric Brun819fc6f2017-06-13 19:37:32 +02003989 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003990 if (!stkctr)
3991 return 0;
3992
3993 smp->flags = SMP_F_VOL_TEST;
3994 smp->data.type = SMP_T_SINT;
3995 smp->data.u.sint = 0;
3996 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003997 void *ptr;
3998
3999 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_REQ_CNT);
4000 if (!ptr) {
4001 if (stkctr == &tmpstkctr)
4002 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004003 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02004004 }
4005
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004006 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004007
Emeric Brun0e3457b2021-06-30 17:18:28 +02004008 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004009
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004010 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004011
4012 if (stkctr == &tmpstkctr)
4013 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004014 }
4015 return 1;
4016}
4017
4018/* set <smp> to the HTTP request rate from the stream's tracked frontend
4019 * counters. Supports being called as "sc[0-9]_http_req_rate" or
4020 * "src_http_req_rate" only.
4021 */
4022static int
4023smp_fetch_sc_http_req_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
4024{
Emeric Brun819fc6f2017-06-13 19:37:32 +02004025 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01004026 struct stkctr *stkctr;
4027
Emeric Brun819fc6f2017-06-13 19:37:32 +02004028 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01004029 if (!stkctr)
4030 return 0;
4031
4032 smp->flags = SMP_F_VOL_TEST;
4033 smp->data.type = SMP_T_SINT;
4034 smp->data.u.sint = 0;
4035 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02004036 void *ptr;
4037
4038 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_REQ_RATE);
4039 if (!ptr) {
4040 if (stkctr == &tmpstkctr)
4041 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004042 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02004043 }
4044
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004045 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004046
Emeric Brun0e3457b2021-06-30 17:18:28 +02004047 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Willy Tarreau7d562212016-11-25 16:10:05 +01004048 stkctr->table->data_arg[STKTABLE_DT_HTTP_REQ_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004049
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004050 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004051
4052 if (stkctr == &tmpstkctr)
4053 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004054 }
4055 return 1;
4056}
4057
4058/* set <smp> to the cumulated number of HTTP requests errors from the stream's
4059 * tracked frontend counters. Supports being called as "sc[0-9]_http_err_cnt" or
4060 * "src_http_err_cnt" only.
4061 */
4062static int
4063smp_fetch_sc_http_err_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
4064{
Emeric Brun819fc6f2017-06-13 19:37:32 +02004065 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01004066 struct stkctr *stkctr;
4067
Emeric Brun819fc6f2017-06-13 19:37:32 +02004068 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01004069 if (!stkctr)
4070 return 0;
4071
4072 smp->flags = SMP_F_VOL_TEST;
4073 smp->data.type = SMP_T_SINT;
4074 smp->data.u.sint = 0;
4075 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02004076 void *ptr;
4077
4078 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_ERR_CNT);
4079 if (!ptr) {
4080 if (stkctr == &tmpstkctr)
4081 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004082 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02004083 }
4084
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004085 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004086
Emeric Brun0e3457b2021-06-30 17:18:28 +02004087 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004088
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004089 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004090
4091 if (stkctr == &tmpstkctr)
4092 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004093 }
4094 return 1;
4095}
4096
4097/* set <smp> to the HTTP request error rate from the stream's tracked frontend
4098 * counters. Supports being called as "sc[0-9]_http_err_rate" or
4099 * "src_http_err_rate" only.
4100 */
4101static int
4102smp_fetch_sc_http_err_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
4103{
Emeric Brun819fc6f2017-06-13 19:37:32 +02004104 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01004105 struct stkctr *stkctr;
4106
Emeric Brun819fc6f2017-06-13 19:37:32 +02004107 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01004108 if (!stkctr)
4109 return 0;
4110
4111 smp->flags = SMP_F_VOL_TEST;
4112 smp->data.type = SMP_T_SINT;
4113 smp->data.u.sint = 0;
4114 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02004115 void *ptr;
4116
4117 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_ERR_RATE);
4118 if (!ptr) {
4119 if (stkctr == &tmpstkctr)
4120 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004121 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02004122 }
4123
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004124 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004125
Emeric Brun0e3457b2021-06-30 17:18:28 +02004126 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Willy Tarreau7d562212016-11-25 16:10:05 +01004127 stkctr->table->data_arg[STKTABLE_DT_HTTP_ERR_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004128
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004129 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004130
4131 if (stkctr == &tmpstkctr)
4132 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004133 }
4134 return 1;
4135}
4136
Willy Tarreau826f3ab2021-02-10 12:07:15 +01004137/* set <smp> to the cumulated number of HTTP response failures from the stream's
4138 * tracked frontend counters. Supports being called as "sc[0-9]_http_fail_cnt" or
4139 * "src_http_fail_cnt" only.
4140 */
4141static int
4142smp_fetch_sc_http_fail_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
4143{
4144 struct stkctr tmpstkctr;
4145 struct stkctr *stkctr;
4146
4147 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
4148 if (!stkctr)
4149 return 0;
4150
4151 smp->flags = SMP_F_VOL_TEST;
4152 smp->data.type = SMP_T_SINT;
4153 smp->data.u.sint = 0;
4154 if (stkctr_entry(stkctr) != NULL) {
4155 void *ptr;
4156
4157 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_FAIL_CNT);
4158 if (!ptr) {
4159 if (stkctr == &tmpstkctr)
4160 stktable_release(stkctr->table, stkctr_entry(stkctr));
4161 return 0; /* parameter not stored */
4162 }
4163
4164 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
4165
Emeric Brun0e3457b2021-06-30 17:18:28 +02004166 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Willy Tarreau826f3ab2021-02-10 12:07:15 +01004167
4168 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
4169
4170 if (stkctr == &tmpstkctr)
4171 stktable_release(stkctr->table, stkctr_entry(stkctr));
4172 }
4173 return 1;
4174}
4175
4176/* set <smp> to the HTTP response failure rate from the stream's tracked frontend
4177 * counters. Supports being called as "sc[0-9]_http_fail_rate" or
4178 * "src_http_fail_rate" only.
4179 */
4180static int
4181smp_fetch_sc_http_fail_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
4182{
4183 struct stkctr tmpstkctr;
4184 struct stkctr *stkctr;
4185
4186 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
4187 if (!stkctr)
4188 return 0;
4189
4190 smp->flags = SMP_F_VOL_TEST;
4191 smp->data.type = SMP_T_SINT;
4192 smp->data.u.sint = 0;
4193 if (stkctr_entry(stkctr) != NULL) {
4194 void *ptr;
4195
4196 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_FAIL_RATE);
4197 if (!ptr) {
4198 if (stkctr == &tmpstkctr)
4199 stktable_release(stkctr->table, stkctr_entry(stkctr));
4200 return 0; /* parameter not stored */
4201 }
4202
4203 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
4204
Emeric Brun0e3457b2021-06-30 17:18:28 +02004205 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Willy Tarreau826f3ab2021-02-10 12:07:15 +01004206 stkctr->table->data_arg[STKTABLE_DT_HTTP_FAIL_RATE].u);
4207
4208 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
4209
4210 if (stkctr == &tmpstkctr)
4211 stktable_release(stkctr->table, stkctr_entry(stkctr));
4212 }
4213 return 1;
4214}
4215
Willy Tarreau7d562212016-11-25 16:10:05 +01004216/* set <smp> to the number of kbytes received from clients, as found in the
4217 * stream's tracked frontend counters. Supports being called as
4218 * "sc[0-9]_kbytes_in" or "src_kbytes_in" only.
4219 */
4220static int
4221smp_fetch_sc_kbytes_in(const struct arg *args, struct sample *smp, const char *kw, void *private)
4222{
Emeric Brun819fc6f2017-06-13 19:37:32 +02004223 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01004224 struct stkctr *stkctr;
4225
Emeric Brun819fc6f2017-06-13 19:37:32 +02004226 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01004227 if (!stkctr)
4228 return 0;
4229
4230 smp->flags = SMP_F_VOL_TEST;
4231 smp->data.type = SMP_T_SINT;
4232 smp->data.u.sint = 0;
4233 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02004234 void *ptr;
4235
4236 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_IN_CNT);
4237 if (!ptr) {
4238 if (stkctr == &tmpstkctr)
4239 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004240 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02004241 }
4242
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004243 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004244
Emeric Brun0e3457b2021-06-30 17:18:28 +02004245 smp->data.u.sint = stktable_data_cast(ptr, std_t_ull) >> 10;
Emeric Brun819fc6f2017-06-13 19:37:32 +02004246
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004247 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004248
4249 if (stkctr == &tmpstkctr)
4250 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004251 }
4252 return 1;
4253}
4254
4255/* set <smp> to the data rate received from clients in bytes/s, as found
4256 * in the stream's tracked frontend counters. Supports being called as
4257 * "sc[0-9]_bytes_in_rate" or "src_bytes_in_rate" only.
4258 */
4259static int
4260smp_fetch_sc_bytes_in_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
4261{
Emeric Brun819fc6f2017-06-13 19:37:32 +02004262 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01004263 struct stkctr *stkctr;
4264
Emeric Brun819fc6f2017-06-13 19:37:32 +02004265 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01004266 if (!stkctr)
4267 return 0;
4268
4269 smp->flags = SMP_F_VOL_TEST;
4270 smp->data.type = SMP_T_SINT;
4271 smp->data.u.sint = 0;
4272 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02004273 void *ptr;
4274
4275 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_IN_RATE);
4276 if (!ptr) {
4277 if (stkctr == &tmpstkctr)
4278 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004279 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02004280 }
4281
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004282 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004283
Emeric Brun0e3457b2021-06-30 17:18:28 +02004284 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Willy Tarreau7d562212016-11-25 16:10:05 +01004285 stkctr->table->data_arg[STKTABLE_DT_BYTES_IN_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004286
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004287 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004288
4289 if (stkctr == &tmpstkctr)
4290 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004291 }
4292 return 1;
4293}
4294
4295/* set <smp> to the number of kbytes sent to clients, as found in the
4296 * stream's tracked frontend counters. Supports being called as
4297 * "sc[0-9]_kbytes_out" or "src_kbytes_out" only.
4298 */
4299static int
4300smp_fetch_sc_kbytes_out(const struct arg *args, struct sample *smp, const char *kw, void *private)
4301{
Emeric Brun819fc6f2017-06-13 19:37:32 +02004302 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01004303 struct stkctr *stkctr;
4304
Emeric Brun819fc6f2017-06-13 19:37:32 +02004305 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01004306 if (!stkctr)
4307 return 0;
4308
4309 smp->flags = SMP_F_VOL_TEST;
4310 smp->data.type = SMP_T_SINT;
4311 smp->data.u.sint = 0;
4312 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02004313 void *ptr;
4314
4315 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_OUT_CNT);
4316 if (!ptr) {
4317 if (stkctr == &tmpstkctr)
4318 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004319 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02004320 }
4321
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004322 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004323
Emeric Brun0e3457b2021-06-30 17:18:28 +02004324 smp->data.u.sint = stktable_data_cast(ptr, std_t_ull) >> 10;
Emeric Brun819fc6f2017-06-13 19:37:32 +02004325
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004326 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004327
4328 if (stkctr == &tmpstkctr)
4329 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004330 }
4331 return 1;
4332}
4333
4334/* set <smp> to the data rate sent to clients in bytes/s, as found in the
4335 * stream's tracked frontend counters. Supports being called as
4336 * "sc[0-9]_bytes_out_rate" or "src_bytes_out_rate" only.
4337 */
4338static int
4339smp_fetch_sc_bytes_out_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
4340{
Emeric Brun819fc6f2017-06-13 19:37:32 +02004341 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01004342 struct stkctr *stkctr;
4343
Emeric Brun819fc6f2017-06-13 19:37:32 +02004344 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01004345 if (!stkctr)
4346 return 0;
4347
4348 smp->flags = SMP_F_VOL_TEST;
4349 smp->data.type = SMP_T_SINT;
4350 smp->data.u.sint = 0;
4351 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02004352 void *ptr;
4353
4354 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_OUT_RATE);
4355 if (!ptr) {
4356 if (stkctr == &tmpstkctr)
4357 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004358 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02004359 }
4360
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004361 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004362
Emeric Brun0e3457b2021-06-30 17:18:28 +02004363 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Willy Tarreau7d562212016-11-25 16:10:05 +01004364 stkctr->table->data_arg[STKTABLE_DT_BYTES_OUT_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004365
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004366 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004367
4368 if (stkctr == &tmpstkctr)
4369 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004370 }
4371 return 1;
4372}
4373
4374/* set <smp> to the number of active trackers on the SC entry in the stream's
4375 * tracked frontend counters. Supports being called as "sc[0-9]_trackers" only.
4376 */
4377static int
4378smp_fetch_sc_trackers(const struct arg *args, struct sample *smp, const char *kw, void *private)
4379{
Emeric Brun819fc6f2017-06-13 19:37:32 +02004380 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01004381 struct stkctr *stkctr;
4382
Emeric Brun819fc6f2017-06-13 19:37:32 +02004383 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01004384 if (!stkctr)
4385 return 0;
4386
4387 smp->flags = SMP_F_VOL_TEST;
4388 smp->data.type = SMP_T_SINT;
Emeric Brun819fc6f2017-06-13 19:37:32 +02004389 if (stkctr == &tmpstkctr) {
4390 smp->data.u.sint = stkctr_entry(stkctr) ? (stkctr_entry(stkctr)->ref_cnt-1) : 0;
4391 stktable_release(stkctr->table, stkctr_entry(stkctr));
4392 }
4393 else {
4394 smp->data.u.sint = stkctr_entry(stkctr) ? stkctr_entry(stkctr)->ref_cnt : 0;
4395 }
4396
Willy Tarreau7d562212016-11-25 16:10:05 +01004397 return 1;
4398}
4399
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004400
4401/* The functions below are used to manipulate table contents from the CLI.
4402 * There are 3 main actions, "clear", "set" and "show". The code is shared
4403 * between all actions, and the action is encoded in the void *private in
4404 * the appctx as well as in the keyword registration, among one of the
4405 * following values.
4406 */
4407
4408enum {
4409 STK_CLI_ACT_CLR,
4410 STK_CLI_ACT_SET,
4411 STK_CLI_ACT_SHOW,
4412};
4413
Willy Tarreau4596fe22022-05-17 19:07:51 +02004414/* Dump the status of a table to a stream connector's
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004415 * read buffer. It returns 0 if the output buffer is full
4416 * and needs to be called again, otherwise non-zero.
4417 */
Willy Tarreau83061a82018-07-13 11:56:34 +02004418static int table_dump_head_to_buffer(struct buffer *msg,
Willy Tarreaud0a06d52022-05-18 15:07:19 +02004419 struct appctx *appctx,
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004420 struct stktable *t, struct stktable *target)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004421{
Willy Tarreauc12b3212022-05-27 11:08:15 +02004422 struct stream *s = __sc_strm(appctx_sc(appctx));
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004423
4424 chunk_appendf(msg, "# table: %s, type: %s, size:%d, used:%d\n",
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004425 t->id, stktable_types[t->type].kw, t->size, t->current);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004426
4427 /* any other information should be dumped here */
4428
William Lallemand07a62f72017-05-24 00:57:40 +02004429 if (target && (strm_li(s)->bind_conf->level & ACCESS_LVL_MASK) < ACCESS_LVL_OPER)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004430 chunk_appendf(msg, "# contents not dumped due to insufficient privileges\n");
4431
Willy Tarreaud0a06d52022-05-18 15:07:19 +02004432 if (applet_putchk(appctx, msg) == -1)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004433 return 0;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004434
4435 return 1;
4436}
4437
Willy Tarreau4596fe22022-05-17 19:07:51 +02004438/* Dump a table entry to a stream connector's
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004439 * read buffer. It returns 0 if the output buffer is full
4440 * and needs to be called again, otherwise non-zero.
4441 */
Willy Tarreau83061a82018-07-13 11:56:34 +02004442static int table_dump_entry_to_buffer(struct buffer *msg,
Willy Tarreaud0a06d52022-05-18 15:07:19 +02004443 struct appctx *appctx,
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004444 struct stktable *t, struct stksess *entry)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004445{
4446 int dt;
4447
4448 chunk_appendf(msg, "%p:", entry);
4449
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004450 if (t->type == SMP_T_IPV4) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004451 char addr[INET_ADDRSTRLEN];
4452 inet_ntop(AF_INET, (const void *)&entry->key.key, addr, sizeof(addr));
4453 chunk_appendf(msg, " key=%s", addr);
4454 }
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004455 else if (t->type == SMP_T_IPV6) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004456 char addr[INET6_ADDRSTRLEN];
4457 inet_ntop(AF_INET6, (const void *)&entry->key.key, addr, sizeof(addr));
4458 chunk_appendf(msg, " key=%s", addr);
4459 }
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004460 else if (t->type == SMP_T_SINT) {
Willy Tarreau6cde5d82020-02-25 09:41:22 +01004461 chunk_appendf(msg, " key=%u", read_u32(entry->key.key));
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004462 }
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004463 else if (t->type == SMP_T_STR) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004464 chunk_appendf(msg, " key=");
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004465 dump_text(msg, (const char *)entry->key.key, t->key_size);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004466 }
4467 else {
4468 chunk_appendf(msg, " key=");
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004469 dump_binary(msg, (const char *)entry->key.key, t->key_size);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004470 }
4471
4472 chunk_appendf(msg, " use=%d exp=%d", entry->ref_cnt - 1, tick_remain(now_ms, entry->expire));
4473
4474 for (dt = 0; dt < STKTABLE_DATA_TYPES; dt++) {
4475 void *ptr;
4476
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004477 if (t->data_ofs[dt] == 0)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004478 continue;
Emeric Brunc64a2a32021-06-30 18:01:02 +02004479 if (stktable_data_types[dt].is_array) {
4480 char tmp[16] = {};
4481 const char *name_pfx = stktable_data_types[dt].name;
4482 const char *name_sfx = NULL;
4483 unsigned int idx = 0;
4484 int i = 0;
4485
4486 /* split name to show index before first _ of the name
4487 * for example: 'gpc3_rate' if array name is 'gpc_rate'.
4488 */
4489 for (i = 0 ; i < (sizeof(tmp) - 1); i++) {
4490 if (!name_pfx[i])
4491 break;
4492 if (name_pfx[i] == '_') {
4493 name_pfx = &tmp[0];
4494 name_sfx = &stktable_data_types[dt].name[i];
4495 break;
4496 }
4497 tmp[i] = name_pfx[i];
4498 }
4499
4500 ptr = stktable_data_ptr_idx(t, entry, dt, idx);
4501 while (ptr) {
4502 if (stktable_data_types[dt].arg_type == ARG_T_DELAY)
4503 chunk_appendf(msg, " %s%u%s(%u)=", name_pfx, idx, name_sfx ? name_sfx : "", t->data_arg[dt].u);
4504 else
4505 chunk_appendf(msg, " %s%u%s=", name_pfx, idx, name_sfx ? name_sfx : "");
4506 switch (stktable_data_types[dt].std_type) {
4507 case STD_T_SINT:
4508 chunk_appendf(msg, "%d", stktable_data_cast(ptr, std_t_sint));
4509 break;
4510 case STD_T_UINT:
4511 chunk_appendf(msg, "%u", stktable_data_cast(ptr, std_t_uint));
4512 break;
4513 case STD_T_ULL:
4514 chunk_appendf(msg, "%llu", stktable_data_cast(ptr, std_t_ull));
4515 break;
4516 case STD_T_FRQP:
4517 chunk_appendf(msg, "%u",
4518 read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
4519 t->data_arg[dt].u));
4520 break;
4521 }
4522 ptr = stktable_data_ptr_idx(t, entry, dt, ++idx);
4523 }
4524 continue;
4525 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004526 if (stktable_data_types[dt].arg_type == ARG_T_DELAY)
Emeric Brun01928ae2021-06-30 16:24:04 +02004527 chunk_appendf(msg, " %s(%u)=", stktable_data_types[dt].name, t->data_arg[dt].u);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004528 else
4529 chunk_appendf(msg, " %s=", stktable_data_types[dt].name);
4530
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004531 ptr = stktable_data_ptr(t, entry, dt);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004532 switch (stktable_data_types[dt].std_type) {
4533 case STD_T_SINT:
4534 chunk_appendf(msg, "%d", stktable_data_cast(ptr, std_t_sint));
4535 break;
4536 case STD_T_UINT:
4537 chunk_appendf(msg, "%u", stktable_data_cast(ptr, std_t_uint));
4538 break;
4539 case STD_T_ULL:
Emeric Brun01928ae2021-06-30 16:24:04 +02004540 chunk_appendf(msg, "%llu", stktable_data_cast(ptr, std_t_ull));
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004541 break;
4542 case STD_T_FRQP:
Emeric Brun01928ae2021-06-30 16:24:04 +02004543 chunk_appendf(msg, "%u",
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004544 read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004545 t->data_arg[dt].u));
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004546 break;
Frédéric Lécaille16b4f542019-05-23 12:15:04 +02004547 case STD_T_DICT: {
4548 struct dict_entry *de;
4549 de = stktable_data_cast(ptr, std_t_dict);
4550 chunk_appendf(msg, "%s", de ? (char *)de->value.key : "-");
4551 break;
4552 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004553 }
4554 }
4555 chunk_appendf(msg, "\n");
4556
Willy Tarreaud0a06d52022-05-18 15:07:19 +02004557 if (applet_putchk(appctx, msg) == -1)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004558 return 0;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004559
4560 return 1;
4561}
4562
Willy Tarreau3c69e082022-05-03 11:35:07 +02004563/* appctx context used by the "show table" command */
4564struct show_table_ctx {
4565 void *target; /* table we want to dump, or NULL for all */
4566 struct stktable *t; /* table being currently dumped (first if NULL) */
4567 struct stksess *entry; /* last entry we were trying to dump (or first if NULL) */
4568 long long value[STKTABLE_FILTER_LEN]; /* value to compare against */
4569 signed char data_type[STKTABLE_FILTER_LEN]; /* type of data to compare, or -1 if none */
4570 signed char data_op[STKTABLE_FILTER_LEN]; /* operator (STD_OP_*) when data_type set */
Willy Tarreau7849d4c2022-05-03 11:45:02 +02004571 enum {
Willy Tarreau0f154ed2022-05-03 12:02:36 +02004572 STATE_NEXT = 0, /* px points to next table, entry=NULL */
Willy Tarreau7849d4c2022-05-03 11:45:02 +02004573 STATE_DUMP, /* px points to curr table, entry is valid, refcount held */
4574 STATE_DONE, /* done dumping */
4575 } state;
Willy Tarreau3c69e082022-05-03 11:35:07 +02004576 char action; /* action on the table : one of STK_CLI_ACT_* */
4577};
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004578
4579/* Processes a single table entry matching a specific key passed in argument.
4580 * returns 0 if wants to be called again, 1 if has ended processing.
4581 */
4582static int table_process_entry_per_key(struct appctx *appctx, char **args)
4583{
Willy Tarreau3c69e082022-05-03 11:35:07 +02004584 struct show_table_ctx *ctx = appctx->svcctx;
4585 struct stktable *t = ctx->target;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004586 struct stksess *ts;
4587 uint32_t uint32_key;
4588 unsigned char ip6_key[sizeof(struct in6_addr)];
4589 long long value;
4590 int data_type;
4591 int cur_arg;
4592 void *ptr;
Willy Tarreaufa1258f2021-04-10 23:00:53 +02004593 struct freq_ctr *frqp;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004594
Willy Tarreau9d008692019-08-09 11:21:01 +02004595 if (!*args[4])
4596 return cli_err(appctx, "Key value expected\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004597
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004598 switch (t->type) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004599 case SMP_T_IPV4:
4600 uint32_key = htonl(inetaddr_host(args[4]));
Christopher Fauletca20d022017-08-29 15:30:31 +02004601 static_table_key.key = &uint32_key;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004602 break;
4603 case SMP_T_IPV6:
Christopher Fauletb7c962b2021-11-15 09:17:25 +01004604 if (inet_pton(AF_INET6, args[4], ip6_key) <= 0)
4605 return cli_err(appctx, "Invalid key\n");
Christopher Fauletca20d022017-08-29 15:30:31 +02004606 static_table_key.key = &ip6_key;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004607 break;
4608 case SMP_T_SINT:
4609 {
4610 char *endptr;
4611 unsigned long val;
4612 errno = 0;
4613 val = strtoul(args[4], &endptr, 10);
4614 if ((errno == ERANGE && val == ULONG_MAX) ||
4615 (errno != 0 && val == 0) || endptr == args[4] ||
Willy Tarreau9d008692019-08-09 11:21:01 +02004616 val > 0xffffffff)
4617 return cli_err(appctx, "Invalid key\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004618 uint32_key = (uint32_t) val;
Christopher Fauletca20d022017-08-29 15:30:31 +02004619 static_table_key.key = &uint32_key;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004620 break;
4621 }
4622 break;
4623 case SMP_T_STR:
Christopher Fauletca20d022017-08-29 15:30:31 +02004624 static_table_key.key = args[4];
4625 static_table_key.key_len = strlen(args[4]);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004626 break;
4627 default:
Willy Tarreau3c69e082022-05-03 11:35:07 +02004628 switch (ctx->action) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004629 case STK_CLI_ACT_SHOW:
Willy Tarreau9d008692019-08-09 11:21:01 +02004630 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 +01004631 case STK_CLI_ACT_CLR:
Willy Tarreau9d008692019-08-09 11:21:01 +02004632 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 +01004633 case STK_CLI_ACT_SET:
Willy Tarreau9d008692019-08-09 11:21:01 +02004634 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 +01004635 default:
Willy Tarreau9d008692019-08-09 11:21:01 +02004636 return cli_err(appctx, "Unknown action\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004637 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004638 }
4639
4640 /* check permissions */
4641 if (!cli_has_level(appctx, ACCESS_LVL_OPER))
4642 return 1;
4643
Willy Tarreau3c69e082022-05-03 11:35:07 +02004644 switch (ctx->action) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004645 case STK_CLI_ACT_SHOW:
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004646 ts = stktable_lookup_key(t, &static_table_key);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004647 if (!ts)
4648 return 1;
4649 chunk_reset(&trash);
Willy Tarreaud0a06d52022-05-18 15:07:19 +02004650 if (!table_dump_head_to_buffer(&trash, appctx, t, t)) {
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004651 stktable_release(t, ts);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004652 return 0;
Emeric Brun819fc6f2017-06-13 19:37:32 +02004653 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004654 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &ts->lock);
Willy Tarreaud0a06d52022-05-18 15:07:19 +02004655 if (!table_dump_entry_to_buffer(&trash, appctx, t, ts)) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004656 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004657 stktable_release(t, ts);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004658 return 0;
Emeric Brun819fc6f2017-06-13 19:37:32 +02004659 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004660 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004661 stktable_release(t, ts);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004662 break;
4663
4664 case STK_CLI_ACT_CLR:
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004665 ts = stktable_lookup_key(t, &static_table_key);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004666 if (!ts)
4667 return 1;
Emeric Brun819fc6f2017-06-13 19:37:32 +02004668
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004669 if (!stksess_kill(t, ts, 1)) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004670 /* don't delete an entry which is currently referenced */
Willy Tarreau9d008692019-08-09 11:21:01 +02004671 return cli_err(appctx, "Entry currently in use, cannot remove\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004672 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004673 break;
4674
4675 case STK_CLI_ACT_SET:
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004676 ts = stktable_get_entry(t, &static_table_key);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004677 if (!ts) {
4678 /* don't delete an entry which is currently referenced */
Willy Tarreau9d008692019-08-09 11:21:01 +02004679 return cli_err(appctx, "Unable to allocate a new entry\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004680 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004681 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004682 for (cur_arg = 5; *args[cur_arg]; cur_arg += 2) {
4683 if (strncmp(args[cur_arg], "data.", 5) != 0) {
Willy Tarreau9d008692019-08-09 11:21:01 +02004684 cli_err(appctx, "\"data.<type>\" followed by a value expected\n");
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004685 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004686 stktable_touch_local(t, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004687 return 1;
4688 }
4689
4690 data_type = stktable_get_data_type(args[cur_arg] + 5);
4691 if (data_type < 0) {
Willy Tarreau9d008692019-08-09 11:21:01 +02004692 cli_err(appctx, "Unknown data type\n");
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004693 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004694 stktable_touch_local(t, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004695 return 1;
4696 }
4697
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004698 if (!t->data_ofs[data_type]) {
Willy Tarreau9d008692019-08-09 11:21:01 +02004699 cli_err(appctx, "Data type not stored in this table\n");
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004700 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004701 stktable_touch_local(t, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004702 return 1;
4703 }
4704
4705 if (!*args[cur_arg+1] || strl2llrc(args[cur_arg+1], strlen(args[cur_arg+1]), &value) != 0) {
Willy Tarreau9d008692019-08-09 11:21:01 +02004706 cli_err(appctx, "Require a valid integer value to store\n");
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004707 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004708 stktable_touch_local(t, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004709 return 1;
4710 }
4711
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004712 ptr = stktable_data_ptr(t, ts, data_type);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004713
4714 switch (stktable_data_types[data_type].std_type) {
4715 case STD_T_SINT:
4716 stktable_data_cast(ptr, std_t_sint) = value;
4717 break;
4718 case STD_T_UINT:
4719 stktable_data_cast(ptr, std_t_uint) = value;
4720 break;
4721 case STD_T_ULL:
4722 stktable_data_cast(ptr, std_t_ull) = value;
4723 break;
4724 case STD_T_FRQP:
4725 /* We set both the current and previous values. That way
4726 * the reported frequency is stable during all the period
4727 * then slowly fades out. This allows external tools to
4728 * push measures without having to update them too often.
4729 */
4730 frqp = &stktable_data_cast(ptr, std_t_frqp);
Willy Tarreaufa1258f2021-04-10 23:00:53 +02004731 /* First bit is reserved for the freq_ctr lock
Emeric Brunf2fc1fd2017-11-02 17:32:43 +01004732 Note: here we're still protected by the stksess lock
Willy Tarreaufa1258f2021-04-10 23:00:53 +02004733 so we don't need to update the update the freq_ctr
Emeric Brunf2fc1fd2017-11-02 17:32:43 +01004734 using its internal lock */
4735 frqp->curr_tick = now_ms & ~0x1;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004736 frqp->prev_ctr = 0;
4737 frqp->curr_ctr = value;
4738 break;
4739 }
4740 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004741 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004742 stktable_touch_local(t, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004743 break;
4744
4745 default:
Willy Tarreau9d008692019-08-09 11:21:01 +02004746 return cli_err(appctx, "Unknown action\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004747 }
4748 return 1;
4749}
4750
4751/* Prepares the appctx fields with the data-based filters from the command line.
4752 * Returns 0 if the dump can proceed, 1 if has ended processing.
4753 */
4754static int table_prepare_data_request(struct appctx *appctx, char **args)
4755{
Willy Tarreau3c69e082022-05-03 11:35:07 +02004756 struct show_table_ctx *ctx = appctx->svcctx;
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004757 int i;
Adis Nezirovicd0142e72020-01-22 16:50:27 +01004758 char *err = NULL;
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004759
Willy Tarreau3c69e082022-05-03 11:35:07 +02004760 if (ctx->action != STK_CLI_ACT_SHOW && ctx->action != STK_CLI_ACT_CLR)
Willy Tarreau9d008692019-08-09 11:21:01 +02004761 return cli_err(appctx, "content-based lookup is only supported with the \"show\" and \"clear\" actions\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004762
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004763 for (i = 0; i < STKTABLE_FILTER_LEN; i++) {
4764 if (i > 0 && !*args[3+3*i]) // number of filter entries can be less than STKTABLE_FILTER_LEN
4765 break;
4766 /* condition on stored data value */
Willy Tarreau3c69e082022-05-03 11:35:07 +02004767 ctx->data_type[i] = stktable_get_data_type(args[3+3*i] + 5);
4768 if (ctx->data_type[i] < 0)
Adis Nezirovicd0142e72020-01-22 16:50:27 +01004769 return cli_dynerr(appctx, memprintf(&err, "Filter entry #%i: Unknown data type\n", i + 1));
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004770
Willy Tarreau3c69e082022-05-03 11:35:07 +02004771 if (!((struct stktable *)ctx->target)->data_ofs[ctx->data_type[i]])
Adis Nezirovicd0142e72020-01-22 16:50:27 +01004772 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 +01004773
Willy Tarreau3c69e082022-05-03 11:35:07 +02004774 ctx->data_op[i] = get_std_op(args[4+3*i]);
4775 if (ctx->data_op[i] < 0)
Adis Nezirovicd0142e72020-01-22 16:50:27 +01004776 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 +01004777
Willy Tarreau3c69e082022-05-03 11:35:07 +02004778 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 +01004779 return cli_dynerr(appctx, memprintf(&err, "Filter entry #%i: Require a valid integer value to compare against\n", i + 1));
4780 }
4781
4782 if (*args[3+3*i]) {
4783 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 +01004784 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004785
4786 /* OK we're done, all the fields are set */
4787 return 0;
4788}
4789
4790/* returns 0 if wants to be called, 1 if has ended processing */
Aurélien Nephtaliabbf6072018-04-18 13:26:46 +02004791static int cli_parse_table_req(char **args, char *payload, struct appctx *appctx, void *private)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004792{
Willy Tarreau3c69e082022-05-03 11:35:07 +02004793 struct show_table_ctx *ctx = applet_reserve_svcctx(appctx, sizeof(*ctx));
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004794 int i;
4795
4796 for (i = 0; i < STKTABLE_FILTER_LEN; i++)
Willy Tarreau3c69e082022-05-03 11:35:07 +02004797 ctx->data_type[i] = -1;
4798 ctx->target = NULL;
4799 ctx->entry = NULL;
4800 ctx->action = (long)private; // keyword argument, one of STK_CLI_ACT_*
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004801
4802 if (*args[2]) {
Willy Tarreau0f154ed2022-05-03 12:02:36 +02004803 ctx->t = ctx->target = stktable_find_by_name(args[2]);
Willy Tarreau3c69e082022-05-03 11:35:07 +02004804 if (!ctx->target)
Willy Tarreau9d008692019-08-09 11:21:01 +02004805 return cli_err(appctx, "No such table\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004806 }
4807 else {
Willy Tarreau0f154ed2022-05-03 12:02:36 +02004808 ctx->t = stktables_list;
Willy Tarreau3c69e082022-05-03 11:35:07 +02004809 if (ctx->action != STK_CLI_ACT_SHOW)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004810 goto err_args;
4811 return 0;
4812 }
4813
4814 if (strcmp(args[3], "key") == 0)
4815 return table_process_entry_per_key(appctx, args);
4816 else if (strncmp(args[3], "data.", 5) == 0)
4817 return table_prepare_data_request(appctx, args);
4818 else if (*args[3])
4819 goto err_args;
4820
4821 return 0;
4822
4823err_args:
Willy Tarreau3c69e082022-05-03 11:35:07 +02004824 switch (ctx->action) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004825 case STK_CLI_ACT_SHOW:
Willy Tarreau9d008692019-08-09 11:21:01 +02004826 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 +01004827 case STK_CLI_ACT_CLR:
Willy Tarreau9d008692019-08-09 11:21:01 +02004828 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 +01004829 case STK_CLI_ACT_SET:
Willy Tarreau9d008692019-08-09 11:21:01 +02004830 return cli_err(appctx, "Required arguments: <table> key <key> [data.<store_data_type> <value>]*\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004831 default:
Willy Tarreau9d008692019-08-09 11:21:01 +02004832 return cli_err(appctx, "Unknown action\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004833 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004834}
4835
4836/* This function is used to deal with table operations (dump or clear depending
4837 * on the action stored in appctx->private). It returns 0 if the output buffer is
4838 * full and it needs to be called again, otherwise non-zero.
4839 */
4840static int cli_io_handler_table(struct appctx *appctx)
4841{
Willy Tarreau3c69e082022-05-03 11:35:07 +02004842 struct show_table_ctx *ctx = appctx->svcctx;
Willy Tarreauc12b3212022-05-27 11:08:15 +02004843 struct stconn *sc = appctx_sc(appctx);
Willy Tarreau475e4632022-05-27 10:26:46 +02004844 struct stream *s = __sc_strm(sc);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004845 struct ebmb_node *eb;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004846 int skip_entry;
Willy Tarreau3c69e082022-05-03 11:35:07 +02004847 int show = ctx->action == STK_CLI_ACT_SHOW;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004848
4849 /*
Willy Tarreau0f154ed2022-05-03 12:02:36 +02004850 * We have 3 possible states in ctx->state :
Willy Tarreau7849d4c2022-05-03 11:45:02 +02004851 * - STATE_NEXT : the proxy pointer points to the next table to
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004852 * dump, the entry pointer is NULL ;
Willy Tarreau7849d4c2022-05-03 11:45:02 +02004853 * - STATE_DUMP : the proxy pointer points to the current table
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004854 * and the entry pointer points to the next entry to be dumped,
4855 * and the refcount on the next entry is held ;
Willy Tarreau7849d4c2022-05-03 11:45:02 +02004856 * - STATE_DONE : nothing left to dump, the buffer may contain some
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004857 * data though.
4858 */
4859
Willy Tarreau475e4632022-05-27 10:26:46 +02004860 if (unlikely(sc_ic(sc)->flags & (CF_WRITE_ERROR|CF_SHUTW))) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004861 /* in case of abort, remove any refcount we might have set on an entry */
Willy Tarreau7849d4c2022-05-03 11:45:02 +02004862 if (ctx->state == STATE_DUMP) {
Willy Tarreau3c69e082022-05-03 11:35:07 +02004863 stksess_kill_if_expired(ctx->t, ctx->entry, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004864 }
4865 return 1;
4866 }
4867
4868 chunk_reset(&trash);
4869
Willy Tarreau7849d4c2022-05-03 11:45:02 +02004870 while (ctx->state != STATE_DONE) {
4871 switch (ctx->state) {
Willy Tarreau7849d4c2022-05-03 11:45:02 +02004872 case STATE_NEXT:
Willy Tarreau3c69e082022-05-03 11:35:07 +02004873 if (!ctx->t ||
4874 (ctx->target &&
4875 ctx->t != ctx->target)) {
Willy Tarreau7849d4c2022-05-03 11:45:02 +02004876 ctx->state = STATE_DONE;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004877 break;
4878 }
4879
Willy Tarreau3c69e082022-05-03 11:35:07 +02004880 if (ctx->t->size) {
Willy Tarreaud0a06d52022-05-18 15:07:19 +02004881 if (show && !table_dump_head_to_buffer(&trash, appctx, ctx->t, ctx->target))
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004882 return 0;
4883
Willy Tarreau3c69e082022-05-03 11:35:07 +02004884 if (ctx->target &&
William Lallemand07a62f72017-05-24 00:57:40 +02004885 (strm_li(s)->bind_conf->level & ACCESS_LVL_MASK) >= ACCESS_LVL_OPER) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004886 /* dump entries only if table explicitly requested */
Willy Tarreau76642222022-10-11 12:02:50 +02004887 HA_RWLOCK_WRLOCK(STK_TABLE_LOCK, &ctx->t->lock);
Willy Tarreau3c69e082022-05-03 11:35:07 +02004888 eb = ebmb_first(&ctx->t->keys);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004889 if (eb) {
Willy Tarreau3c69e082022-05-03 11:35:07 +02004890 ctx->entry = ebmb_entry(eb, struct stksess, key);
4891 ctx->entry->ref_cnt++;
Willy Tarreau7849d4c2022-05-03 11:45:02 +02004892 ctx->state = STATE_DUMP;
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 break;
4895 }
Willy Tarreau76642222022-10-11 12:02:50 +02004896 HA_RWLOCK_WRUNLOCK(STK_TABLE_LOCK, &ctx->t->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004897 }
4898 }
Willy Tarreau3c69e082022-05-03 11:35:07 +02004899 ctx->t = ctx->t->next;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004900 break;
4901
Willy Tarreau7849d4c2022-05-03 11:45:02 +02004902 case STATE_DUMP:
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004903 skip_entry = 0;
4904
Willy Tarreau3c69e082022-05-03 11:35:07 +02004905 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &ctx->entry->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004906
Willy Tarreau3c69e082022-05-03 11:35:07 +02004907 if (ctx->data_type[0] >= 0) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004908 /* we're filtering on some data contents */
4909 void *ptr;
Willy Tarreau2b64a352020-01-22 17:09:47 +01004910 int dt, i;
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004911 signed char op;
4912 long long data, value;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004913
Emeric Brun819fc6f2017-06-13 19:37:32 +02004914
Willy Tarreau2b64a352020-01-22 17:09:47 +01004915 for (i = 0; i < STKTABLE_FILTER_LEN; i++) {
Willy Tarreau3c69e082022-05-03 11:35:07 +02004916 if (ctx->data_type[i] == -1)
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004917 break;
Willy Tarreau3c69e082022-05-03 11:35:07 +02004918 dt = ctx->data_type[i];
4919 ptr = stktable_data_ptr(ctx->t,
4920 ctx->entry,
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004921 dt);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004922
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004923 data = 0;
4924 switch (stktable_data_types[dt].std_type) {
4925 case STD_T_SINT:
4926 data = stktable_data_cast(ptr, std_t_sint);
4927 break;
4928 case STD_T_UINT:
4929 data = stktable_data_cast(ptr, std_t_uint);
4930 break;
4931 case STD_T_ULL:
4932 data = stktable_data_cast(ptr, std_t_ull);
4933 break;
4934 case STD_T_FRQP:
4935 data = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Willy Tarreau3c69e082022-05-03 11:35:07 +02004936 ctx->t->data_arg[dt].u);
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004937 break;
4938 }
4939
Willy Tarreau3c69e082022-05-03 11:35:07 +02004940 op = ctx->data_op[i];
4941 value = ctx->value[i];
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004942
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004943 /* skip the entry if the data does not match the test and the value */
4944 if ((data < value &&
4945 (op == STD_OP_EQ || op == STD_OP_GT || op == STD_OP_GE)) ||
4946 (data == value &&
4947 (op == STD_OP_NE || op == STD_OP_GT || op == STD_OP_LT)) ||
4948 (data > value &&
4949 (op == STD_OP_EQ || op == STD_OP_LT || op == STD_OP_LE))) {
4950 skip_entry = 1;
4951 break;
4952 }
4953 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004954 }
4955
4956 if (show && !skip_entry &&
Willy Tarreaud0a06d52022-05-18 15:07:19 +02004957 !table_dump_entry_to_buffer(&trash, appctx, ctx->t, ctx->entry)) {
Willy Tarreau3c69e082022-05-03 11:35:07 +02004958 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &ctx->entry->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004959 return 0;
4960 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004961
Willy Tarreau3c69e082022-05-03 11:35:07 +02004962 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &ctx->entry->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004963
Willy Tarreau76642222022-10-11 12:02:50 +02004964 HA_RWLOCK_WRLOCK(STK_TABLE_LOCK, &ctx->t->lock);
Willy Tarreau3c69e082022-05-03 11:35:07 +02004965 ctx->entry->ref_cnt--;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004966
Willy Tarreau3c69e082022-05-03 11:35:07 +02004967 eb = ebmb_next(&ctx->entry->key);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004968 if (eb) {
Willy Tarreau3c69e082022-05-03 11:35:07 +02004969 struct stksess *old = ctx->entry;
4970 ctx->entry = ebmb_entry(eb, struct stksess, key);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004971 if (show)
Willy Tarreau3c69e082022-05-03 11:35:07 +02004972 __stksess_kill_if_expired(ctx->t, old);
4973 else if (!skip_entry && !ctx->entry->ref_cnt)
4974 __stksess_kill(ctx->t, old);
4975 ctx->entry->ref_cnt++;
Willy Tarreau76642222022-10-11 12:02:50 +02004976 HA_RWLOCK_WRUNLOCK(STK_TABLE_LOCK, &ctx->t->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004977 break;
4978 }
4979
4980
4981 if (show)
Willy Tarreau3c69e082022-05-03 11:35:07 +02004982 __stksess_kill_if_expired(ctx->t, ctx->entry);
4983 else if (!skip_entry && !ctx->entry->ref_cnt)
4984 __stksess_kill(ctx->t, ctx->entry);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004985
Willy Tarreau76642222022-10-11 12:02:50 +02004986 HA_RWLOCK_WRUNLOCK(STK_TABLE_LOCK, &ctx->t->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004987
Willy Tarreau3c69e082022-05-03 11:35:07 +02004988 ctx->t = ctx->t->next;
Willy Tarreau7849d4c2022-05-03 11:45:02 +02004989 ctx->state = STATE_NEXT;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004990 break;
4991
Willy Tarreau7849d4c2022-05-03 11:45:02 +02004992 default:
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004993 break;
4994 }
4995 }
4996 return 1;
4997}
4998
4999static void cli_release_show_table(struct appctx *appctx)
5000{
Willy Tarreau3c69e082022-05-03 11:35:07 +02005001 struct show_table_ctx *ctx = appctx->svcctx;
5002
Willy Tarreau7849d4c2022-05-03 11:45:02 +02005003 if (ctx->state == STATE_DUMP) {
Willy Tarreau3c69e082022-05-03 11:35:07 +02005004 stksess_kill_if_expired(ctx->t, ctx->entry, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01005005 }
5006}
5007
Willy Tarreau478331d2020-08-28 11:31:31 +02005008static void stkt_late_init(void)
5009{
5010 struct sample_fetch *f;
5011
5012 f = find_sample_fetch("src", strlen("src"));
5013 if (f)
5014 smp_fetch_src = f->process;
5015}
5016
5017INITCALL0(STG_INIT, stkt_late_init);
5018
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01005019/* register cli keywords */
5020static struct cli_kw_list cli_kws = {{ },{
Willy Tarreaub205bfd2021-05-07 11:38:37 +02005021 { { "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 },
5022 { { "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 },
5023 { { "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 +01005024 {{},}
5025}};
5026
Willy Tarreau0108d902018-11-25 19:14:37 +01005027INITCALL1(STG_REGISTER, cli_register_kw, &cli_kws);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01005028
Thierry FOURNIER236657b2015-08-19 08:25:14 +02005029static struct action_kw_list tcp_conn_kws = { { }, {
Emeric Brun4d7ada82021-06-30 19:04:16 +02005030 { "sc-inc-gpc", parse_inc_gpc, KWF_MATCH_PREFIX },
5031 { "sc-inc-gpc0", parse_inc_gpc, KWF_MATCH_PREFIX },
5032 { "sc-inc-gpc1", parse_inc_gpc, KWF_MATCH_PREFIX },
Emeric Brun877b0b52021-06-30 18:57:49 +02005033 { "sc-set-gpt", parse_set_gpt, KWF_MATCH_PREFIX },
5034 { "sc-set-gpt0", parse_set_gpt, KWF_MATCH_PREFIX },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02005035 { /* END */ }
5036}};
5037
Willy Tarreau0108d902018-11-25 19:14:37 +01005038INITCALL1(STG_REGISTER, tcp_req_conn_keywords_register, &tcp_conn_kws);
5039
Willy Tarreau620408f2016-10-21 16:37:51 +02005040static struct action_kw_list tcp_sess_kws = { { }, {
Emeric Brun4d7ada82021-06-30 19:04:16 +02005041 { "sc-inc-gpc", parse_inc_gpc, KWF_MATCH_PREFIX },
5042 { "sc-inc-gpc0", parse_inc_gpc, KWF_MATCH_PREFIX },
5043 { "sc-inc-gpc1", parse_inc_gpc, KWF_MATCH_PREFIX },
Emeric Brun877b0b52021-06-30 18:57:49 +02005044 { "sc-set-gpt", parse_set_gpt, KWF_MATCH_PREFIX },
5045 { "sc-set-gpt0", parse_set_gpt, KWF_MATCH_PREFIX },
Willy Tarreau620408f2016-10-21 16:37:51 +02005046 { /* END */ }
5047}};
5048
Willy Tarreau0108d902018-11-25 19:14:37 +01005049INITCALL1(STG_REGISTER, tcp_req_sess_keywords_register, &tcp_sess_kws);
5050
Thierry FOURNIER236657b2015-08-19 08:25:14 +02005051static struct action_kw_list tcp_req_kws = { { }, {
Emeric Brun4d7ada82021-06-30 19:04:16 +02005052 { "sc-inc-gpc", parse_inc_gpc, KWF_MATCH_PREFIX },
5053 { "sc-inc-gpc0", parse_inc_gpc, KWF_MATCH_PREFIX },
5054 { "sc-inc-gpc1", parse_inc_gpc, KWF_MATCH_PREFIX },
Emeric Brun877b0b52021-06-30 18:57:49 +02005055 { "sc-set-gpt", parse_set_gpt, KWF_MATCH_PREFIX },
5056 { "sc-set-gpt0", parse_set_gpt, KWF_MATCH_PREFIX },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02005057 { /* END */ }
5058}};
5059
Willy Tarreau0108d902018-11-25 19:14:37 +01005060INITCALL1(STG_REGISTER, tcp_req_cont_keywords_register, &tcp_req_kws);
5061
Thierry FOURNIER236657b2015-08-19 08:25:14 +02005062static struct action_kw_list tcp_res_kws = { { }, {
Emeric Brun4d7ada82021-06-30 19:04:16 +02005063 { "sc-inc-gpc", parse_inc_gpc, KWF_MATCH_PREFIX },
5064 { "sc-inc-gpc0", parse_inc_gpc, KWF_MATCH_PREFIX },
5065 { "sc-inc-gpc1", parse_inc_gpc, KWF_MATCH_PREFIX },
Emeric Brun877b0b52021-06-30 18:57:49 +02005066 { "sc-set-gpt", parse_set_gpt, KWF_MATCH_PREFIX },
5067 { "sc-set-gpt0", parse_set_gpt, KWF_MATCH_PREFIX },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02005068 { /* END */ }
5069}};
5070
Willy Tarreau0108d902018-11-25 19:14:37 +01005071INITCALL1(STG_REGISTER, tcp_res_cont_keywords_register, &tcp_res_kws);
5072
Thierry FOURNIER236657b2015-08-19 08:25:14 +02005073static struct action_kw_list http_req_kws = { { }, {
Emeric Brun4d7ada82021-06-30 19:04:16 +02005074 { "sc-inc-gpc", parse_inc_gpc, KWF_MATCH_PREFIX },
5075 { "sc-inc-gpc0", parse_inc_gpc, KWF_MATCH_PREFIX },
5076 { "sc-inc-gpc1", parse_inc_gpc, KWF_MATCH_PREFIX },
Emeric Brun877b0b52021-06-30 18:57:49 +02005077 { "sc-set-gpt", parse_set_gpt, KWF_MATCH_PREFIX },
5078 { "sc-set-gpt0", parse_set_gpt, KWF_MATCH_PREFIX },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02005079 { /* END */ }
5080}};
5081
Willy Tarreau0108d902018-11-25 19:14:37 +01005082INITCALL1(STG_REGISTER, http_req_keywords_register, &http_req_kws);
5083
Thierry FOURNIER236657b2015-08-19 08:25:14 +02005084static struct action_kw_list http_res_kws = { { }, {
Emeric Brun4d7ada82021-06-30 19:04:16 +02005085 { "sc-inc-gpc", parse_inc_gpc, KWF_MATCH_PREFIX },
5086 { "sc-inc-gpc0", parse_inc_gpc, KWF_MATCH_PREFIX },
5087 { "sc-inc-gpc1", parse_inc_gpc, KWF_MATCH_PREFIX },
Emeric Brun877b0b52021-06-30 18:57:49 +02005088 { "sc-set-gpt", parse_set_gpt, KWF_MATCH_PREFIX },
5089 { "sc-set-gpt0", parse_set_gpt, KWF_MATCH_PREFIX },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02005090 { /* END */ }
5091}};
5092
Willy Tarreau0108d902018-11-25 19:14:37 +01005093INITCALL1(STG_REGISTER, http_res_keywords_register, &http_res_kws);
5094
Willy Tarreau7d562212016-11-25 16:10:05 +01005095/* Note: must not be declared <const> as its list will be overwritten.
5096 * Please take care of keeping this list alphabetically sorted.
5097 */
5098static struct sample_fetch_kw_list smp_fetch_keywords = {ILH, {
5099 { "sc_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5100 { "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 +02005101 { "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 +01005102 { "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 +01005103 { "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 +01005104 { "sc_conn_cnt", smp_fetch_sc_conn_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5105 { "sc_conn_cur", smp_fetch_sc_conn_cur, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5106 { "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 +02005107 { "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 +01005108 { "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 +02005109 { "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 +01005110 { "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 +01005111 { "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 +02005112 { "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 +01005113 { "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 +01005114 { "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 +01005115 { "sc_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5116 { "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 +01005117 { "sc_http_fail_cnt", smp_fetch_sc_http_fail_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5118 { "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 +01005119 { "sc_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5120 { "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 +02005121 { "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 +01005122 { "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 +01005123 { "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 +01005124 { "sc_kbytes_in", smp_fetch_sc_kbytes_in, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5125 { "sc_kbytes_out", smp_fetch_sc_kbytes_out, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5126 { "sc_sess_cnt", smp_fetch_sc_sess_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5127 { "sc_sess_rate", smp_fetch_sc_sess_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5128 { "sc_tracked", smp_fetch_sc_tracked, ARG2(1,SINT,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
5129 { "sc_trackers", smp_fetch_sc_trackers, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5130 { "sc0_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5131 { "sc0_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5132 { "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 +01005133 { "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 +01005134 { "sc0_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5135 { "sc0_conn_cur", smp_fetch_sc_conn_cur, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5136 { "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 +01005137 { "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 +01005138 { "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 +01005139 { "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 +01005140 { "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 +01005141 { "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 +01005142 { "sc0_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5143 { "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 +01005144 { "sc0_http_fail_cnt", smp_fetch_sc_http_fail_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5145 { "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 +01005146 { "sc0_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5147 { "sc0_http_req_rate", smp_fetch_sc_http_req_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5148 { "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 +01005149 { "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 +01005150 { "sc0_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5151 { "sc0_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5152 { "sc0_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5153 { "sc0_sess_rate", smp_fetch_sc_sess_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5154 { "sc0_tracked", smp_fetch_sc_tracked, ARG1(0,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
5155 { "sc0_trackers", smp_fetch_sc_trackers, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5156 { "sc1_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5157 { "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 +02005158 { "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 +01005159 { "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 +01005160 { "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 +01005161 { "sc1_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5162 { "sc1_conn_cur", smp_fetch_sc_conn_cur, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5163 { "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 +01005164 { "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 +01005165 { "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 +01005166 { "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 +01005167 { "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 +01005168 { "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 +01005169 { "sc1_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5170 { "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 +01005171 { "sc1_http_fail_cnt", smp_fetch_sc_http_fail_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5172 { "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 +01005173 { "sc1_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5174 { "sc1_http_req_rate", smp_fetch_sc_http_req_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5175 { "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 +01005176 { "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 +01005177 { "sc1_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5178 { "sc1_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5179 { "sc1_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5180 { "sc1_sess_rate", smp_fetch_sc_sess_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5181 { "sc1_tracked", smp_fetch_sc_tracked, ARG1(0,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
5182 { "sc1_trackers", smp_fetch_sc_trackers, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5183 { "sc2_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5184 { "sc2_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5185 { "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 +01005186 { "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 +01005187 { "sc2_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5188 { "sc2_conn_cur", smp_fetch_sc_conn_cur, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5189 { "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 +01005190 { "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 +01005191 { "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 +01005192 { "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 +01005193 { "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 +01005194 { "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 +01005195 { "sc2_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5196 { "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 +01005197 { "sc2_http_fail_cnt", smp_fetch_sc_http_fail_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5198 { "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 +01005199 { "sc2_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5200 { "sc2_http_req_rate", smp_fetch_sc_http_req_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5201 { "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 +01005202 { "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 +01005203 { "sc2_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5204 { "sc2_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5205 { "sc2_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5206 { "sc2_sess_rate", smp_fetch_sc_sess_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5207 { "sc2_tracked", smp_fetch_sc_tracked, ARG1(0,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
5208 { "sc2_trackers", smp_fetch_sc_trackers, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5209 { "src_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5210 { "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 +02005211 { "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 +01005212 { "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 +01005213 { "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 +01005214 { "src_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5215 { "src_conn_cur", smp_fetch_sc_conn_cur, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5216 { "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 +02005217 { "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 +01005218 { "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 +02005219 { "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 +01005220 { "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 +01005221 { "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 +02005222 { "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 +01005223 { "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 +01005224 { "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 +01005225 { "src_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5226 { "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 +01005227 { "src_http_fail_cnt", smp_fetch_sc_http_fail_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5228 { "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 +01005229 { "src_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5230 { "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 +02005231 { "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 +01005232 { "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 +01005233 { "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 +01005234 { "src_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5235 { "src_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5236 { "src_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5237 { "src_sess_rate", smp_fetch_sc_sess_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5238 { "src_updt_conn_cnt", smp_fetch_src_updt_conn_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5239 { "table_avl", smp_fetch_table_avl, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5240 { "table_cnt", smp_fetch_table_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5241 { /* END */ },
5242}};
5243
Willy Tarreau0108d902018-11-25 19:14:37 +01005244INITCALL1(STG_REGISTER, sample_register_fetches, &smp_fetch_keywords);
Willy Tarreau7d562212016-11-25 16:10:05 +01005245
Willy Tarreaud9f316a2014-07-10 14:03:38 +02005246/* Note: must not be declared <const> as its list will be overwritten */
5247static struct sample_conv_kw_list sample_conv_kws = {ILH, {
Willy Tarreau2d17db52016-05-25 17:16:38 +02005248 { "in_table", sample_conv_in_table, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_BOOL },
5249 { "table_bytes_in_rate", sample_conv_table_bytes_in_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5250 { "table_bytes_out_rate", sample_conv_table_bytes_out_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5251 { "table_conn_cnt", sample_conv_table_conn_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5252 { "table_conn_cur", sample_conv_table_conn_cur, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5253 { "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 +02005254 { "table_expire", sample_conv_table_expire, ARG2(1,TAB,SINT), NULL, SMP_T_ANY, SMP_T_SINT },
Emeric Brun877b0b52021-06-30 18:57:49 +02005255 { "table_gpt", sample_conv_table_gpt, ARG2(2,SINT,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
Willy Tarreau2d17db52016-05-25 17:16:38 +02005256 { "table_gpt0", sample_conv_table_gpt0, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
Emeric Brun4d7ada82021-06-30 19:04:16 +02005257 { "table_gpc", sample_conv_table_gpc, ARG2(2,SINT,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
Willy Tarreau2d17db52016-05-25 17:16:38 +02005258 { "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 +01005259 { "table_gpc1", sample_conv_table_gpc1, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
Emeric Brun4d7ada82021-06-30 19:04:16 +02005260 { "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 +02005261 { "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 +01005262 { "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 +02005263 { "table_http_err_cnt", sample_conv_table_http_err_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5264 { "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 +01005265 { "table_http_fail_cnt", sample_conv_table_http_fail_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5266 { "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 +02005267 { "table_http_req_cnt", sample_conv_table_http_req_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5268 { "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 +02005269 { "table_idle", sample_conv_table_idle, ARG2(1,TAB,SINT), NULL, SMP_T_ANY, SMP_T_SINT },
Willy Tarreau2d17db52016-05-25 17:16:38 +02005270 { "table_kbytes_in", sample_conv_table_kbytes_in, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5271 { "table_kbytes_out", sample_conv_table_kbytes_out, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5272 { "table_server_id", sample_conv_table_server_id, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5273 { "table_sess_cnt", sample_conv_table_sess_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5274 { "table_sess_rate", sample_conv_table_sess_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5275 { "table_trackers", sample_conv_table_trackers, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
Willy Tarreaud9f316a2014-07-10 14:03:38 +02005276 { /* END */ },
5277}};
5278
Willy Tarreau0108d902018-11-25 19:14:37 +01005279INITCALL1(STG_REGISTER, sample_register_convs, &sample_conv_kws);