blob: 958618c9f8ec7e3c018cae86eae2d4f08b875d4a [file] [log] [blame]
Emeric Brun3bd697e2010-01-04 15:23:48 +01001/*
2 * Stick tables management functions.
3 *
4 * Copyright 2009-2010 EXCELIANCE, Emeric Brun <ebrun@exceliance.fr>
Willy Tarreau08d5f982010-06-06 13:34:54 +02005 * Copyright (C) 2010 Willy Tarreau <w@1wt.eu>
Emeric Brun3bd697e2010-01-04 15:23:48 +01006 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version
10 * 2 of the License, or (at your option) any later version.
11 *
12 */
13
14#include <string.h>
Willy Tarreauf13ebdf2016-11-22 18:00:53 +010015#include <errno.h>
Emeric Brun3bd697e2010-01-04 15:23:48 +010016
Willy Tarreaub2551052020-06-09 09:07:15 +020017#include <import/ebmbtree.h>
18#include <import/ebsttree.h>
19#include <import/ebistree.h>
Frédéric Lécaille36d15652022-10-17 14:58:19 +020020#include <import/xxhash.h>
Willy Tarreaub2551052020-06-09 09:07:15 +020021
Willy Tarreau4c7e4b72020-05-27 12:58:42 +020022#include <haproxy/api.h>
Willy Tarreau3c69e082022-05-03 11:35:07 +020023#include <haproxy/applet.h>
Willy Tarreaub2551052020-06-09 09:07:15 +020024#include <haproxy/arg.h>
Willy Tarreau6be78492020-06-05 00:00:29 +020025#include <haproxy/cfgparse.h>
Willy Tarreau83487a82020-06-04 20:19:54 +020026#include <haproxy/cli.h>
Thayne McCombs92149f92020-11-20 01:28:26 -070027#include <haproxy/dict.h>
Willy Tarreau36979d92020-06-05 17:27:29 +020028#include <haproxy/errors.h>
Willy Tarreauf268ee82020-06-04 17:05:57 +020029#include <haproxy/global.h>
Willy Tarreauc761f842020-06-04 11:40:28 +020030#include <haproxy/http_rules.h>
Willy Tarreau853b2972020-05-27 18:01:47 +020031#include <haproxy/list.h>
Willy Tarreauaeed4a82020-06-04 22:01:04 +020032#include <haproxy/log.h>
Willy Tarreau6131d6a2020-06-02 16:48:09 +020033#include <haproxy/net_helper.h>
Willy Tarreau3c2a7c22020-06-04 18:38:21 +020034#include <haproxy/peers.h>
Willy Tarreaub2551052020-06-09 09:07:15 +020035#include <haproxy/pool.h>
36#include <haproxy/proto_tcp.h>
Willy Tarreaua264d962020-06-04 22:29:18 +020037#include <haproxy/proxy.h>
Willy Tarreaub2551052020-06-09 09:07:15 +020038#include <haproxy/sample.h>
Willy Tarreau5edca2f2022-05-27 09:25:10 +020039#include <haproxy/sc_strm.h>
Willy Tarreau2eec9b52020-06-04 19:58:55 +020040#include <haproxy/stats-t.h>
Willy Tarreaucb086c62022-05-27 09:47:12 +020041#include <haproxy/stconn.h>
Willy Tarreaub2551052020-06-09 09:07:15 +020042#include <haproxy/stick_table.h>
Willy Tarreaudfd3de82020-06-04 23:46:14 +020043#include <haproxy/stream.h>
Willy Tarreaucea0e1b2020-06-04 17:25:40 +020044#include <haproxy/task.h>
Willy Tarreau8b550af2020-06-04 17:42:48 +020045#include <haproxy/tcp_rules.h>
Willy Tarreau9310f482021-10-06 16:18:40 +020046#include <haproxy/ticks.h>
Willy Tarreaub2551052020-06-09 09:07:15 +020047#include <haproxy/tools.h>
Emeric Brun3bd697e2010-01-04 15:23:48 +010048
Emeric Brun3bd697e2010-01-04 15:23:48 +010049
Willy Tarreau12785782012-04-27 21:37:17 +020050/* structure used to return a table key built from a sample */
Emeric Brun819fc6f2017-06-13 19:37:32 +020051static THREAD_LOCAL struct stktable_key static_table_key;
Willy Tarreau478331d2020-08-28 11:31:31 +020052static int (*smp_fetch_src)(const struct arg *, struct sample *, const char *, void *);
Willy Tarreauf0b38bf2010-06-06 13:22:23 +020053
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +010054struct stktable *stktables_list;
55struct eb_root stktable_by_name = EB_ROOT;
56
Olivier Houchard52dabbc2018-11-14 17:54:36 +010057#define round_ptr_size(i) (((i) + (sizeof(void *) - 1)) &~ (sizeof(void *) - 1))
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +010058
59/* This function inserts stktable <t> into the tree of known stick-table.
60 * The stick-table ID is used as the storing key so it must already have
61 * been initialized.
62 */
63void stktable_store_name(struct stktable *t)
64{
65 t->name.key = t->id;
66 ebis_insert(&stktable_by_name, &t->name);
67}
68
69struct stktable *stktable_find_by_name(const char *name)
70{
71 struct ebpt_node *node;
72 struct stktable *t;
73
74 node = ebis_lookup(&stktable_by_name, name);
75 if (node) {
76 t = container_of(node, struct stktable, name);
Tim Duesterhuse5ff1412021-01-02 22:31:53 +010077 if (strcmp(t->id, name) == 0)
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +010078 return t;
79 }
80
81 return NULL;
82}
83
Emeric Brun3bd697e2010-01-04 15:23:48 +010084/*
Willy Tarreauaea940e2010-06-06 11:56:36 +020085 * Free an allocated sticky session <ts>, and decrease sticky sessions counter
Willy Tarreau996f1a52022-10-11 16:19:35 +020086 * in table <t>. It's safe to call it under or out of a lock.
Emeric Brun3bd697e2010-01-04 15:23:48 +010087 */
Emeric Brun819fc6f2017-06-13 19:37:32 +020088void __stksess_free(struct stktable *t, struct stksess *ts)
Emeric Brun3bd697e2010-01-04 15:23:48 +010089{
Willy Tarreau996f1a52022-10-11 16:19:35 +020090 HA_ATOMIC_DEC(&t->current);
Olivier Houchard52dabbc2018-11-14 17:54:36 +010091 pool_free(t->pool, (void *)ts - round_ptr_size(t->data_size));
Emeric Brun3bd697e2010-01-04 15:23:48 +010092}
93
94/*
Emeric Brun819fc6f2017-06-13 19:37:32 +020095 * Free an allocated sticky session <ts>, and decrease sticky sessions counter
96 * in table <t>.
97 * This function locks the table
98 */
99void stksess_free(struct stktable *t, struct stksess *ts)
100{
Thayne McCombs92149f92020-11-20 01:28:26 -0700101 void *data;
102 data = stktable_data_ptr(t, ts, STKTABLE_DT_SERVER_KEY);
103 if (data) {
Emeric Brun0e3457b2021-06-30 17:18:28 +0200104 dict_entry_unref(&server_key_dict, stktable_data_cast(data, std_t_dict));
105 stktable_data_cast(data, std_t_dict) = NULL;
Thayne McCombs92149f92020-11-20 01:28:26 -0700106 }
Willy Tarreau8d3c3332022-10-11 18:50:22 +0000107 HA_RWLOCK_RDLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200108 __stksess_free(t, ts);
Willy Tarreau8d3c3332022-10-11 18:50:22 +0000109 HA_RWLOCK_RDUNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200110}
111
112/*
Willy Tarreauf6efda12010-08-03 20:34:06 +0200113 * Kill an stksess (only if its ref_cnt is zero).
114 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200115int __stksess_kill(struct stktable *t, struct stksess *ts)
Willy Tarreauf6efda12010-08-03 20:34:06 +0200116{
117 if (ts->ref_cnt)
Emeric Brun819fc6f2017-06-13 19:37:32 +0200118 return 0;
Willy Tarreauf6efda12010-08-03 20:34:06 +0200119
120 eb32_delete(&ts->exp);
Emeric Brun85e77c72010-09-23 18:16:52 +0200121 eb32_delete(&ts->upd);
Willy Tarreauf6efda12010-08-03 20:34:06 +0200122 ebmb_delete(&ts->key);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200123 __stksess_free(t, ts);
124 return 1;
Willy Tarreauf6efda12010-08-03 20:34:06 +0200125}
126
127/*
Emeric Brun819fc6f2017-06-13 19:37:32 +0200128 * Decrease the refcount if decrefcnt is not 0.
129 * and try to kill the stksess
130 * This function locks the table
131 */
132int stksess_kill(struct stktable *t, struct stksess *ts, int decrefcnt)
133{
134 int ret;
135
Willy Tarreau76642222022-10-11 12:02:50 +0200136 HA_RWLOCK_WRLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200137 if (decrefcnt)
138 ts->ref_cnt--;
139 ret = __stksess_kill(t, ts);
Willy Tarreau76642222022-10-11 12:02:50 +0200140 HA_RWLOCK_WRUNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200141
142 return ret;
143}
144
145/*
Willy Tarreauaea940e2010-06-06 11:56:36 +0200146 * Initialize or update the key in the sticky session <ts> present in table <t>
147 * from the value present in <key>.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100148 */
Willy Tarreau393379c2010-06-06 12:11:37 +0200149void stksess_setkey(struct stktable *t, struct stksess *ts, struct stktable_key *key)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100150{
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200151 if (t->type != SMP_T_STR)
Willy Tarreau86257dc2010-06-06 12:57:10 +0200152 memcpy(ts->key.key, key->key, t->key_size);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100153 else {
Willy Tarreau86257dc2010-06-06 12:57:10 +0200154 memcpy(ts->key.key, key->key, MIN(t->key_size - 1, key->key_len));
155 ts->key.key[MIN(t->key_size - 1, key->key_len)] = 0;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100156 }
157}
158
Frédéric Lécaille36d15652022-10-17 14:58:19 +0200159/*
160 * Initialize or update the key hash in the sticky session <ts> present in table <t>
161 * from the value present in <key>.
162 */
163static unsigned long long stksess_getkey_hash(struct stktable *t,
164 struct stksess *ts,
165 struct stktable_key *key)
166{
167 struct buffer *buf;
168 size_t keylen;
169
170 /* Copy the stick-table id into <buf> */
171 buf = get_trash_chunk();
172 memcpy(b_tail(buf), t->id, t->idlen);
173 b_add(buf, t->idlen);
174 /* Copy the key into <buf> */
175 if (t->type == SMP_T_STR)
176 keylen = key->key_len;
177 else
178 keylen = t->key_size;
179 memcpy(b_tail(buf), key->key, keylen);
180 b_add(buf, keylen);
181
182 return XXH64(b_head(buf), b_data(buf), 0);
183}
Emeric Brun3bd697e2010-01-04 15:23:48 +0100184
185/*
Frédéric Lécaille36d15652022-10-17 14:58:19 +0200186 * Set the shard for <key> key of <ts> sticky session attached to <t> stick table.
187 * Do nothing for stick-table without peers synchronisation.
188 */
189static void stksess_setkey_shard(struct stktable *t, struct stksess *ts,
190 struct stktable_key *key)
191{
192 if (!t->peers.p)
193 /* This stick-table is not attached to any peers section */
194 return;
195
196 if (!t->peers.p->nb_shards)
197 ts->shard = 0;
198 else
199 ts->shard = stksess_getkey_hash(t, ts, key) % t->peers.p->nb_shards + 1;
200}
201
202/*
Willy Tarreau393379c2010-06-06 12:11:37 +0200203 * Init sticky session <ts> of table <t>. The data parts are cleared and <ts>
204 * is returned.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100205 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200206static struct stksess *__stksess_init(struct stktable *t, struct stksess * ts)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100207{
Willy Tarreau393379c2010-06-06 12:11:37 +0200208 memset((void *)ts - t->data_size, 0, t->data_size);
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200209 ts->ref_cnt = 0;
Willy Tarreau86257dc2010-06-06 12:57:10 +0200210 ts->key.node.leaf_p = NULL;
211 ts->exp.node.leaf_p = NULL;
Emeric Brun85e77c72010-09-23 18:16:52 +0200212 ts->upd.node.leaf_p = NULL;
Emeric Brun819fc6f2017-06-13 19:37:32 +0200213 ts->expire = tick_add(now_ms, MS_TO_TICKS(t->expire));
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100214 HA_RWLOCK_INIT(&ts->lock);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100215 return ts;
216}
217
218/*
Willy Tarreauaea940e2010-06-06 11:56:36 +0200219 * Trash oldest <to_batch> sticky sessions from table <t>
Willy Tarreaudfe79252020-11-03 17:47:41 +0100220 * Returns number of trashed sticky sessions. It may actually trash less
221 * than expected if finding these requires too long a search time (e.g.
222 * most of them have ts->ref_cnt>0).
Emeric Brun3bd697e2010-01-04 15:23:48 +0100223 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200224int __stktable_trash_oldest(struct stktable *t, int to_batch)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100225{
226 struct stksess *ts;
227 struct eb32_node *eb;
Willy Tarreaudfe79252020-11-03 17:47:41 +0100228 int max_search = to_batch * 2; // no more than 50% misses
Emeric Brun3bd697e2010-01-04 15:23:48 +0100229 int batched = 0;
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200230 int looped = 0;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100231
232 eb = eb32_lookup_ge(&t->exps, now_ms - TIMER_LOOK_BACK);
233
234 while (batched < to_batch) {
235
236 if (unlikely(!eb)) {
237 /* we might have reached the end of the tree, typically because
238 * <now_ms> is in the first half and we're first scanning the last
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200239 * half. Let's loop back to the beginning of the tree now if we
240 * have not yet visited it.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100241 */
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200242 if (looped)
243 break;
244 looped = 1;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100245 eb = eb32_first(&t->exps);
246 if (likely(!eb))
247 break;
248 }
249
Willy Tarreaudfe79252020-11-03 17:47:41 +0100250 if (--max_search < 0)
251 break;
252
Emeric Brun3bd697e2010-01-04 15:23:48 +0100253 /* timer looks expired, detach it from the queue */
Willy Tarreau86257dc2010-06-06 12:57:10 +0200254 ts = eb32_entry(eb, struct stksess, exp);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100255 eb = eb32_next(eb);
256
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200257 /* don't delete an entry which is currently referenced */
258 if (ts->ref_cnt)
259 continue;
260
Willy Tarreau86257dc2010-06-06 12:57:10 +0200261 eb32_delete(&ts->exp);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100262
Willy Tarreau86257dc2010-06-06 12:57:10 +0200263 if (ts->expire != ts->exp.key) {
Emeric Brun3bd697e2010-01-04 15:23:48 +0100264 if (!tick_isset(ts->expire))
265 continue;
266
Willy Tarreau86257dc2010-06-06 12:57:10 +0200267 ts->exp.key = ts->expire;
268 eb32_insert(&t->exps, &ts->exp);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100269
Willy Tarreau86257dc2010-06-06 12:57:10 +0200270 if (!eb || eb->key > ts->exp.key)
271 eb = &ts->exp;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100272
273 continue;
274 }
Emeric Brun3bd697e2010-01-04 15:23:48 +0100275
Willy Tarreauaea940e2010-06-06 11:56:36 +0200276 /* session expired, trash it */
Willy Tarreau86257dc2010-06-06 12:57:10 +0200277 ebmb_delete(&ts->key);
Emeric Brun85e77c72010-09-23 18:16:52 +0200278 eb32_delete(&ts->upd);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200279 __stksess_free(t, ts);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100280 batched++;
281 }
282
283 return batched;
284}
285
286/*
Emeric Brun819fc6f2017-06-13 19:37:32 +0200287 * Trash oldest <to_batch> sticky sessions from table <t>
288 * Returns number of trashed sticky sessions.
289 * This function locks the table
290 */
291int stktable_trash_oldest(struct stktable *t, int to_batch)
292{
293 int ret;
294
Willy Tarreau76642222022-10-11 12:02:50 +0200295 HA_RWLOCK_WRLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200296 ret = __stktable_trash_oldest(t, to_batch);
Willy Tarreau76642222022-10-11 12:02:50 +0200297 HA_RWLOCK_WRUNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200298
299 return ret;
300}
301/*
Willy Tarreauaea940e2010-06-06 11:56:36 +0200302 * Allocate and initialise a new sticky session.
303 * The new sticky session is returned or NULL in case of lack of memory.
304 * Sticky sessions should only be allocated this way, and must be freed using
Willy Tarreaua7b46b52013-04-11 16:55:37 +0200305 * stksess_free(). Table <t>'s sticky session counter is increased. If <key>
Willy Tarreau996f1a52022-10-11 16:19:35 +0200306 * is not NULL, it is assigned to the new session. It must be called unlocked
307 * as it may rely on a lock to trash older entries.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100308 */
Willy Tarreau996f1a52022-10-11 16:19:35 +0200309struct stksess *stksess_new(struct stktable *t, struct stktable_key *key)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100310{
311 struct stksess *ts;
Willy Tarreau996f1a52022-10-11 16:19:35 +0200312 unsigned int current;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100313
Willy Tarreau996f1a52022-10-11 16:19:35 +0200314 current = HA_ATOMIC_FETCH_ADD(&t->current, 1);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100315
Willy Tarreau996f1a52022-10-11 16:19:35 +0200316 if (unlikely(current >= t->size)) {
317 /* the table was already full, we may have to purge entries */
318 if (t->nopurge || !stktable_trash_oldest(t, (t->size >> 8) + 1)) {
319 HA_ATOMIC_DEC(&t->current);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100320 return NULL;
Willy Tarreau996f1a52022-10-11 16:19:35 +0200321 }
Emeric Brun3bd697e2010-01-04 15:23:48 +0100322 }
323
Willy Tarreaubafbe012017-11-24 17:34:44 +0100324 ts = pool_alloc(t->pool);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100325 if (ts) {
Olivier Houchard52dabbc2018-11-14 17:54:36 +0100326 ts = (void *)ts + round_ptr_size(t->data_size);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200327 __stksess_init(t, ts);
Frédéric Lécaille36d15652022-10-17 14:58:19 +0200328 if (key) {
Willy Tarreaua7b46b52013-04-11 16:55:37 +0200329 stksess_setkey(t, ts, key);
Frédéric Lécaille36d15652022-10-17 14:58:19 +0200330 stksess_setkey_shard(t, ts, key);
331 }
Emeric Brun3bd697e2010-01-04 15:23:48 +0100332 }
333
334 return ts;
335}
336
337/*
Willy Tarreauf16d2b82010-06-06 15:38:59 +0200338 * Looks in table <t> for a sticky session matching key <key>.
Willy Tarreauaea940e2010-06-06 11:56:36 +0200339 * Returns pointer on requested sticky session or NULL if none was found.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100340 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200341struct stksess *__stktable_lookup_key(struct stktable *t, struct stktable_key *key)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100342{
343 struct ebmb_node *eb;
344
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200345 if (t->type == SMP_T_STR)
Emeric Brun485479d2010-09-23 18:02:19 +0200346 eb = ebst_lookup_len(&t->keys, key->key, key->key_len+1 < t->key_size ? key->key_len : t->key_size-1);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100347 else
348 eb = ebmb_lookup(&t->keys, key->key, t->key_size);
349
350 if (unlikely(!eb)) {
351 /* no session found */
352 return NULL;
353 }
354
Willy Tarreau86257dc2010-06-06 12:57:10 +0200355 return ebmb_entry(eb, struct stksess, key);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100356}
357
Emeric Brun819fc6f2017-06-13 19:37:32 +0200358/*
359 * Looks in table <t> for a sticky session matching key <key>.
360 * Returns pointer on requested sticky session or NULL if none was found.
361 * The refcount of the found entry is increased and this function
362 * is protected using the table lock
Willy Tarreau1f7e9252010-06-20 12:27:21 +0200363 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200364struct stksess *stktable_lookup_key(struct stktable *t, struct stktable_key *key)
Willy Tarreau1f7e9252010-06-20 12:27:21 +0200365{
366 struct stksess *ts;
367
Willy Tarreaua7d6a132022-10-11 15:42:54 +0200368 HA_RWLOCK_RDLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200369 ts = __stktable_lookup_key(t, key);
370 if (ts)
Willy Tarreaua7d6a132022-10-11 15:42:54 +0200371 HA_ATOMIC_INC(&ts->ref_cnt);
372 HA_RWLOCK_RDUNLOCK(STK_TABLE_LOCK, &t->lock);
Willy Tarreau1f7e9252010-06-20 12:27:21 +0200373
Willy Tarreau1f7e9252010-06-20 12:27:21 +0200374 return ts;
375}
376
Willy Tarreauf16d2b82010-06-06 15:38:59 +0200377/*
378 * Looks in table <t> for a sticky session with same key as <ts>.
379 * Returns pointer on requested sticky session or NULL if none was found.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100380 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200381struct stksess *__stktable_lookup(struct stktable *t, struct stksess *ts)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100382{
Emeric Brun3bd697e2010-01-04 15:23:48 +0100383 struct ebmb_node *eb;
384
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200385 if (t->type == SMP_T_STR)
Willy Tarreau86257dc2010-06-06 12:57:10 +0200386 eb = ebst_lookup(&(t->keys), (char *)ts->key.key);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100387 else
Willy Tarreau86257dc2010-06-06 12:57:10 +0200388 eb = ebmb_lookup(&(t->keys), ts->key.key, t->key_size);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100389
Willy Tarreauf16d2b82010-06-06 15:38:59 +0200390 if (unlikely(!eb))
391 return NULL;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100392
Willy Tarreauf16d2b82010-06-06 15:38:59 +0200393 return ebmb_entry(eb, struct stksess, key);
394}
Emeric Brun3bd697e2010-01-04 15:23:48 +0100395
Emeric Brun819fc6f2017-06-13 19:37:32 +0200396/*
397 * Looks in table <t> for a sticky session with same key as <ts>.
398 * Returns pointer on requested sticky session or NULL if none was found.
399 * The refcount of the found entry is increased and this function
400 * is protected using the table lock
401 */
402struct stksess *stktable_lookup(struct stktable *t, struct stksess *ts)
403{
404 struct stksess *lts;
405
Willy Tarreaua7d6a132022-10-11 15:42:54 +0200406 HA_RWLOCK_RDLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200407 lts = __stktable_lookup(t, ts);
408 if (lts)
Willy Tarreaua7d6a132022-10-11 15:42:54 +0200409 HA_ATOMIC_INC(&lts->ref_cnt);
410 HA_RWLOCK_RDUNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200411
412 return lts;
413}
414
Willy Tarreaucb183642010-06-06 17:58:34 +0200415/* Update the expiration timer for <ts> but do not touch its expiration node.
416 * The table's expiration timer is updated if set.
Emeric Brun819fc6f2017-06-13 19:37:32 +0200417 * The node will be also inserted into the update tree if needed, at a position
Willy Tarreau9f5cb432022-10-11 18:17:58 +0000418 * depending if the update is a local or coming from a remote node.
419 * If <decrefcnt> is set, the ts entry's ref_cnt will be decremented. The table's
420 * write lock may be taken.
Willy Tarreaucb183642010-06-06 17:58:34 +0200421 */
Willy Tarreau9f5cb432022-10-11 18:17:58 +0000422void stktable_touch_with_exp(struct stktable *t, struct stksess *ts, int local, int expire, int decrefcnt)
Willy Tarreaucb183642010-06-06 17:58:34 +0200423{
Emeric Brun85e77c72010-09-23 18:16:52 +0200424 struct eb32_node * eb;
Willy Tarreaua7536ef2022-10-11 18:31:04 +0000425 int locked = 0;
Willy Tarreau9f5cb432022-10-11 18:17:58 +0000426
Willy Tarreaua7536ef2022-10-11 18:31:04 +0000427 if (expire != HA_ATOMIC_LOAD(&ts->expire)) {
428 /* we'll need to set the expiration and to wake up the expiration timer .*/
429 HA_ATOMIC_STORE(&ts->expire, expire);
Willy Tarreaudbae89e2022-10-12 10:00:50 +0000430 stktable_requeue_exp(t, ts);
Willy Tarreaucb183642010-06-06 17:58:34 +0200431 }
Emeric Brun85e77c72010-09-23 18:16:52 +0200432
Emeric Brun819fc6f2017-06-13 19:37:32 +0200433 /* If sync is enabled */
434 if (t->sync_task) {
435 if (local) {
436 /* If this entry is not in the tree
Willy Tarreaua7536ef2022-10-11 18:31:04 +0000437 * or not scheduled for at least one peer.
438 */
439 if (!locked++)
440 HA_RWLOCK_WRLOCK(STK_TABLE_LOCK, &t->lock);
441
Emeric Brun819fc6f2017-06-13 19:37:32 +0200442 if (!ts->upd.node.leaf_p
443 || (int)(t->commitupdate - ts->upd.key) >= 0
444 || (int)(ts->upd.key - t->localupdate) >= 0) {
445 ts->upd.key = ++t->update;
446 t->localupdate = t->update;
447 eb32_delete(&ts->upd);
448 eb = eb32_insert(&t->updates, &ts->upd);
449 if (eb != &ts->upd) {
450 eb32_delete(eb);
451 eb32_insert(&t->updates, &ts->upd);
452 }
Emeric Brunaaf58602015-06-15 17:23:30 +0200453 }
Emeric Brun819fc6f2017-06-13 19:37:32 +0200454 task_wakeup(t->sync_task, TASK_WOKEN_MSG);
Emeric Brun85e77c72010-09-23 18:16:52 +0200455 }
Emeric Brun819fc6f2017-06-13 19:37:32 +0200456 else {
457 /* If this entry is not in the tree */
Willy Tarreaua7536ef2022-10-11 18:31:04 +0000458 if (!locked++)
459 HA_RWLOCK_WRLOCK(STK_TABLE_LOCK, &t->lock);
460
Emeric Brun819fc6f2017-06-13 19:37:32 +0200461 if (!ts->upd.node.leaf_p) {
462 ts->upd.key= (++t->update)+(2147483648U);
463 eb = eb32_insert(&t->updates, &ts->upd);
464 if (eb != &ts->upd) {
465 eb32_delete(eb);
466 eb32_insert(&t->updates, &ts->upd);
467 }
468 }
469 }
Emeric Brun85e77c72010-09-23 18:16:52 +0200470 }
Willy Tarreau9f5cb432022-10-11 18:17:58 +0000471
Willy Tarreaua7536ef2022-10-11 18:31:04 +0000472 if (decrefcnt) {
473 if (locked)
474 ts->ref_cnt--;
475 else {
476 HA_RWLOCK_RDLOCK(STK_TABLE_LOCK, &t->lock);
477 HA_ATOMIC_DEC(&ts->ref_cnt);
478 HA_RWLOCK_RDUNLOCK(STK_TABLE_LOCK, &t->lock);
479 }
480 }
481
482 if (locked)
483 HA_RWLOCK_WRUNLOCK(STK_TABLE_LOCK, &t->lock);
Willy Tarreaucb183642010-06-06 17:58:34 +0200484}
485
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200486/* Update the expiration timer for <ts> but do not touch its expiration node.
Emeric Brun819fc6f2017-06-13 19:37:32 +0200487 * The table's expiration timer is updated using the date of expiration coming from
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200488 * <t> stick-table configuration.
Emeric Brun819fc6f2017-06-13 19:37:32 +0200489 * The node will be also inserted into the update tree if needed, at a position
490 * considering the update is coming from a remote node
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200491 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200492void stktable_touch_remote(struct stktable *t, struct stksess *ts, int decrefcnt)
493{
Willy Tarreau9f5cb432022-10-11 18:17:58 +0000494 stktable_touch_with_exp(t, ts, 0, ts->expire, decrefcnt);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200495}
496
497/* Update the expiration timer for <ts> but do not touch its expiration node.
498 * The table's expiration timer is updated using the date of expiration coming from
499 * <t> stick-table configuration.
500 * The node will be also inserted into the update tree if needed, at a position
501 * considering the update was made locally
502 */
503void stktable_touch_local(struct stktable *t, struct stksess *ts, int decrefcnt)
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200504{
505 int expire = tick_add(now_ms, MS_TO_TICKS(t->expire));
506
Willy Tarreau9f5cb432022-10-11 18:17:58 +0000507 stktable_touch_with_exp(t, ts, 1, expire, decrefcnt);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200508}
Willy Tarreau4be073b2022-10-11 18:10:27 +0000509/* Just decrease the ref_cnt of the current session. Does nothing if <ts> is NULL.
510 * Note that we still need to take the read lock because a number of other places
511 * (including in Lua and peers) update the ref_cnt non-atomically under the write
512 * lock.
513 */
Willy Tarreau43e90352018-06-27 06:25:57 +0200514static void stktable_release(struct stktable *t, struct stksess *ts)
Emeric Brun819fc6f2017-06-13 19:37:32 +0200515{
Willy Tarreau43e90352018-06-27 06:25:57 +0200516 if (!ts)
517 return;
Willy Tarreau4be073b2022-10-11 18:10:27 +0000518 HA_RWLOCK_RDLOCK(STK_TABLE_LOCK, &t->lock);
519 HA_ATOMIC_DEC(&ts->ref_cnt);
520 HA_RWLOCK_RDUNLOCK(STK_TABLE_LOCK, &t->lock);
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200521}
522
Willy Tarreauf16d2b82010-06-06 15:38:59 +0200523/* Insert new sticky session <ts> in the table. It is assumed that it does not
524 * yet exist (the caller must check this). The table's timeout is updated if it
Willy Tarreaud2d3fd92022-10-11 15:09:46 +0200525 * is set. <ts> is returned if properly inserted, otherwise the one already
526 * present if any.
Willy Tarreauf16d2b82010-06-06 15:38:59 +0200527 */
Willy Tarreaud2d3fd92022-10-11 15:09:46 +0200528struct stksess *__stktable_store(struct stktable *t, struct stksess *ts)
Willy Tarreauf16d2b82010-06-06 15:38:59 +0200529{
Willy Tarreaud2d3fd92022-10-11 15:09:46 +0200530 struct ebmb_node *eb;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100531
Willy Tarreaud2d3fd92022-10-11 15:09:46 +0200532 eb = ebmb_insert(&t->keys, &ts->key, t->key_size);
533 if (likely(eb == &ts->key)) {
534 ts->exp.key = ts->expire;
535 eb32_insert(&t->exps, &ts->exp);
536 }
Willy Tarreaud2d3fd92022-10-11 15:09:46 +0200537 return ebmb_entry(eb, struct stksess, key); // most commonly this is <ts>
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200538}
539
Willy Tarreaueb23e3e2022-10-12 09:56:08 +0000540/* requeues the table's expiration task to take the recently added <ts> into
541 * account. This is performed atomically and doesn't require any lock.
542 */
Willy Tarreaudbae89e2022-10-12 10:00:50 +0000543void stktable_requeue_exp(struct stktable *t, const struct stksess *ts)
Willy Tarreaueb23e3e2022-10-12 09:56:08 +0000544{
Willy Tarreaudbae89e2022-10-12 10:00:50 +0000545 int old_exp, new_exp;
546 int expire = ts->expire;
547
Willy Tarreaueb23e3e2022-10-12 09:56:08 +0000548 if (!t->expire)
549 return;
Willy Tarreaudbae89e2022-10-12 10:00:50 +0000550
Willy Tarreau63427142022-11-14 17:33:02 +0100551 /* set the task's expire to the newest expiration date. */
Willy Tarreaudbae89e2022-10-12 10:00:50 +0000552 old_exp = HA_ATOMIC_LOAD(&t->exp_task->expire);
Willy Tarreau3238f792022-11-14 17:54:07 +0100553 new_exp = tick_first(expire, old_exp);
554
555 /* let's not go further if we're already up to date */
556 if (new_exp == old_exp)
557 return;
558
Willy Tarreaufbb934d2022-11-14 18:02:44 +0100559 HA_RWLOCK_WRLOCK(STK_TABLE_LOCK, &t->lock);
560
Willy Tarreau3238f792022-11-14 17:54:07 +0100561 while (new_exp != old_exp &&
562 !HA_ATOMIC_CAS(&t->exp_task->expire, &old_exp, new_exp)) {
563 __ha_cpu_relax();
Willy Tarreau63427142022-11-14 17:33:02 +0100564 new_exp = tick_first(expire, old_exp);
Willy Tarreau3238f792022-11-14 17:54:07 +0100565 }
Willy Tarreaudbae89e2022-10-12 10:00:50 +0000566
Willy Tarreaueb23e3e2022-10-12 09:56:08 +0000567 task_queue(t->exp_task);
Willy Tarreaufbb934d2022-11-14 18:02:44 +0100568
569 HA_RWLOCK_WRUNLOCK(STK_TABLE_LOCK, &t->lock);
Willy Tarreaueb23e3e2022-10-12 09:56:08 +0000570}
571
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200572/* Returns a valid or initialized stksess for the specified stktable_key in the
573 * specified table, or NULL if the key was NULL, or if no entry was found nor
Willy Tarreau47f22972022-10-11 15:22:42 +0200574 * could be created. The entry's expiration is updated. This function locks the
575 * table, and the refcount of the entry is increased.
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200576 */
Willy Tarreau47f22972022-10-11 15:22:42 +0200577struct stksess *stktable_get_entry(struct stktable *table, struct stktable_key *key)
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200578{
Willy Tarreau175aa062022-10-11 15:13:46 +0200579 struct stksess *ts, *ts2;
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200580
581 if (!key)
582 return NULL;
583
Willy Tarreau47f22972022-10-11 15:22:42 +0200584 ts = stktable_lookup_key(table, key);
585 if (ts)
586 return ts;
Emeric Brun819fc6f2017-06-13 19:37:32 +0200587
Willy Tarreau996f1a52022-10-11 16:19:35 +0200588 /* No such entry exists, let's try to create a new one. this doesn't
589 * require locking yet.
590 */
591
592 ts = stksess_new(table, key);
593 if (!ts)
594 return NULL;
595
596 /* Now we're certain to have a ts. We need to store it. For this we'll
Willy Tarreau47f22972022-10-11 15:22:42 +0200597 * need an exclusive access. We don't need an atomic upgrade, this is
598 * rare and an unlock+lock sequence will do the job fine. Given that
599 * this will not be atomic, the missing entry might appear in the mean
600 * tome so we have to be careful that the one we try to insert is the
601 * one we find.
602 */
Willy Tarreau47f22972022-10-11 15:22:42 +0200603
Willy Tarreau996f1a52022-10-11 16:19:35 +0200604 HA_RWLOCK_WRLOCK(STK_TABLE_LOCK, &table->lock);
Willy Tarreau47f22972022-10-11 15:22:42 +0200605
606 ts2 = __stktable_store(table, ts);
607 if (unlikely(ts2 != ts)) {
608 /* another entry was added in the mean time, let's
609 * switch to it.
610 */
611 __stksess_free(table, ts);
612 ts = ts2;
613 }
614
615 HA_ATOMIC_INC(&ts->ref_cnt);
Willy Tarreau76642222022-10-11 12:02:50 +0200616 HA_RWLOCK_WRUNLOCK(STK_TABLE_LOCK, &table->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200617
Willy Tarreaucbdb5282022-10-12 10:04:01 +0000618 stktable_requeue_exp(table, ts);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200619 return ts;
620}
621
622/* Lookup for an entry with the same key and store the submitted
Willy Tarreaue6288522022-10-12 09:13:14 +0000623 * stksess if not found. This function locks the table either shared or
624 * exclusively, and the refcount of the entry is increased.
Emeric Brun819fc6f2017-06-13 19:37:32 +0200625 */
Willy Tarreaue6288522022-10-12 09:13:14 +0000626struct stksess *stktable_set_entry(struct stktable *table, struct stksess *nts)
Emeric Brun819fc6f2017-06-13 19:37:32 +0200627{
628 struct stksess *ts;
629
Willy Tarreaue6288522022-10-12 09:13:14 +0000630 HA_RWLOCK_RDLOCK(STK_TABLE_LOCK, &table->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200631 ts = __stktable_lookup(table, nts);
Willy Tarreaue6288522022-10-12 09:13:14 +0000632 if (ts) {
633 HA_ATOMIC_INC(&ts->ref_cnt);
634 HA_RWLOCK_RDUNLOCK(STK_TABLE_LOCK, &table->lock);
635 return ts;
Emeric Brun819fc6f2017-06-13 19:37:32 +0200636 }
Willy Tarreaue6288522022-10-12 09:13:14 +0000637 ts = nts;
Emeric Brun819fc6f2017-06-13 19:37:32 +0200638
Willy Tarreaue6288522022-10-12 09:13:14 +0000639 /* let's increment it before switching to exclusive */
640 HA_ATOMIC_INC(&ts->ref_cnt);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200641
Willy Tarreaue6288522022-10-12 09:13:14 +0000642 if (HA_RWLOCK_TRYRDTOSK(STK_TABLE_LOCK, &table->lock) != 0) {
643 /* upgrade to seek lock failed, let's drop and take */
644 HA_RWLOCK_RDUNLOCK(STK_TABLE_LOCK, &table->lock);
645 HA_RWLOCK_WRLOCK(STK_TABLE_LOCK, &table->lock);
646 }
647 else
648 HA_RWLOCK_SKTOWR(STK_TABLE_LOCK, &table->lock);
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200649
Willy Tarreaue6288522022-10-12 09:13:14 +0000650 /* now we're write-locked */
651
652 __stktable_store(table, ts);
653 HA_RWLOCK_WRUNLOCK(STK_TABLE_LOCK, &table->lock);
Willy Tarreaucbdb5282022-10-12 10:04:01 +0000654
655 stktable_requeue_exp(table, ts);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200656 return ts;
657}
Willy Tarreaue6288522022-10-12 09:13:14 +0000658
Emeric Brun3bd697e2010-01-04 15:23:48 +0100659/*
Willy Tarreaufbb934d2022-11-14 18:02:44 +0100660 * Task processing function to trash expired sticky sessions. A pointer to the
661 * task itself is returned since it never dies.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100662 */
Willy Tarreaufbb934d2022-11-14 18:02:44 +0100663struct task *process_table_expire(struct task *task, void *context, unsigned int state)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100664{
Willy Tarreaufbb934d2022-11-14 18:02:44 +0100665 struct stktable *t = context;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100666 struct stksess *ts;
667 struct eb32_node *eb;
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200668 int looped = 0;
Willy Tarreau63427142022-11-14 17:33:02 +0100669 int exp_next;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100670
Willy Tarreau76642222022-10-11 12:02:50 +0200671 HA_RWLOCK_WRLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100672 eb = eb32_lookup_ge(&t->exps, now_ms - TIMER_LOOK_BACK);
673
674 while (1) {
675 if (unlikely(!eb)) {
676 /* we might have reached the end of the tree, typically because
677 * <now_ms> is in the first half and we're first scanning the last
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200678 * half. Let's loop back to the beginning of the tree now if we
679 * have not yet visited it.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100680 */
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200681 if (looped)
682 break;
683 looped = 1;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100684 eb = eb32_first(&t->exps);
685 if (likely(!eb))
686 break;
687 }
688
689 if (likely(tick_is_lt(now_ms, eb->key))) {
690 /* timer not expired yet, revisit it later */
Willy Tarreau63427142022-11-14 17:33:02 +0100691 exp_next = eb->key;
Willy Tarreau4d5f13c2017-11-05 11:04:47 +0100692 goto out_unlock;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100693 }
694
695 /* timer looks expired, detach it from the queue */
Willy Tarreau86257dc2010-06-06 12:57:10 +0200696 ts = eb32_entry(eb, struct stksess, exp);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100697 eb = eb32_next(eb);
698
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200699 /* don't delete an entry which is currently referenced */
700 if (ts->ref_cnt)
701 continue;
702
Willy Tarreau86257dc2010-06-06 12:57:10 +0200703 eb32_delete(&ts->exp);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100704
705 if (!tick_is_expired(ts->expire, now_ms)) {
706 if (!tick_isset(ts->expire))
707 continue;
708
Willy Tarreau86257dc2010-06-06 12:57:10 +0200709 ts->exp.key = ts->expire;
710 eb32_insert(&t->exps, &ts->exp);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100711
Willy Tarreau86257dc2010-06-06 12:57:10 +0200712 if (!eb || eb->key > ts->exp.key)
713 eb = &ts->exp;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100714 continue;
715 }
716
717 /* session expired, trash it */
Willy Tarreau86257dc2010-06-06 12:57:10 +0200718 ebmb_delete(&ts->key);
Emeric Brun85e77c72010-09-23 18:16:52 +0200719 eb32_delete(&ts->upd);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200720 __stksess_free(t, ts);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100721 }
722
723 /* We have found no task to expire in any tree */
Willy Tarreau63427142022-11-14 17:33:02 +0100724 exp_next = TICK_ETERNITY;
Willy Tarreaufbb934d2022-11-14 18:02:44 +0100725
Willy Tarreau4d5f13c2017-11-05 11:04:47 +0100726out_unlock:
Willy Tarreaufbb934d2022-11-14 18:02:44 +0100727 task->expire = exp_next;
Willy Tarreau76642222022-10-11 12:02:50 +0200728 HA_RWLOCK_WRUNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100729 return task;
730}
731
Willy Tarreauaea940e2010-06-06 11:56:36 +0200732/* Perform minimal stick table intializations, report 0 in case of error, 1 if OK. */
Emeric Brun3bd697e2010-01-04 15:23:48 +0100733int stktable_init(struct stktable *t)
734{
Remi Tricot-Le Breton208ff012021-05-12 17:39:04 +0200735 int peers_retval = 0;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100736 if (t->size) {
Emeric Brun819fc6f2017-06-13 19:37:32 +0200737 t->keys = EB_ROOT_UNIQUE;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100738 memset(&t->exps, 0, sizeof(t->exps));
Emeric Brun1c6235d2015-12-16 15:28:12 +0100739 t->updates = EB_ROOT_UNIQUE;
Amaury Denoyelle3e064882022-10-12 16:47:59 +0200740 HA_RWLOCK_INIT(&t->lock);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100741
Olivier Houchard52dabbc2018-11-14 17:54:36 +0100742 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 +0100743
Emeric Brun3bd697e2010-01-04 15:23:48 +0100744 if ( t->expire ) {
Willy Tarreaubeeabf52021-10-01 18:23:30 +0200745 t->exp_task = task_new_anywhere();
Willy Tarreau848522f2018-10-15 11:12:15 +0200746 if (!t->exp_task)
747 return 0;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100748 t->exp_task->process = process_table_expire;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100749 t->exp_task->context = (void *)t;
750 }
Christopher Fauletdfd10ab2021-10-06 14:24:19 +0200751 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 +0200752 peers_retval = peers_register_table(t->peers.p, t);
Emeric Brun32da3c42010-09-23 18:39:19 +0200753 }
754
Remi Tricot-Le Breton208ff012021-05-12 17:39:04 +0200755 return (t->pool != NULL) && !peers_retval;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100756 }
757 return 1;
758}
759
760/*
761 * Configuration keywords of known table types
762 */
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200763struct stktable_type stktable_types[SMP_TYPES] = {
764 [SMP_T_SINT] = { "integer", 0, 4 },
765 [SMP_T_IPV4] = { "ip", 0, 4 },
766 [SMP_T_IPV6] = { "ipv6", 0, 16 },
767 [SMP_T_STR] = { "string", STK_F_CUSTOM_KEYSIZE, 32 },
768 [SMP_T_BIN] = { "binary", STK_F_CUSTOM_KEYSIZE, 32 }
769};
Emeric Brun3bd697e2010-01-04 15:23:48 +0100770
771/*
772 * Parse table type configuration.
773 * Returns 0 on successful parsing, else 1.
774 * <myidx> is set at next configuration <args> index.
775 */
776int stktable_parse_type(char **args, int *myidx, unsigned long *type, size_t *key_size)
777{
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200778 for (*type = 0; *type < SMP_TYPES; (*type)++) {
779 if (!stktable_types[*type].kw)
780 continue;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100781 if (strcmp(args[*myidx], stktable_types[*type].kw) != 0)
782 continue;
783
784 *key_size = stktable_types[*type].default_size;
785 (*myidx)++;
786
Willy Tarreauaea940e2010-06-06 11:56:36 +0200787 if (stktable_types[*type].flags & STK_F_CUSTOM_KEYSIZE) {
Emeric Brun3bd697e2010-01-04 15:23:48 +0100788 if (strcmp("len", args[*myidx]) == 0) {
789 (*myidx)++;
790 *key_size = atol(args[*myidx]);
Emeric Brun485479d2010-09-23 18:02:19 +0200791 if (!*key_size)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100792 break;
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200793 if (*type == SMP_T_STR) {
Emeric Brun485479d2010-09-23 18:02:19 +0200794 /* null terminated string needs +1 for '\0'. */
795 (*key_size)++;
796 }
Emeric Brun3bd697e2010-01-04 15:23:48 +0100797 (*myidx)++;
798 }
799 }
800 return 0;
801 }
802 return 1;
803}
804
Emeric Brunc64a2a32021-06-30 18:01:02 +0200805/* reserve some space for data type <type>, there is 2 optionnals
806 * argument at <sa> and <sa2> to configure this data type and
807 * they can be NULL if unused for a given type.
808 * Returns PE_NONE (0) if OK or an error code among :
Willy Tarreau3b63ca22021-05-08 14:10:42 +0200809 * - PE_ENUM_OOR if <type> does not exist
810 * - PE_EXIST if <type> is already registered
Emeric Brunc64a2a32021-06-30 18:01:02 +0200811 * - PE_ARG_NOT_USE if <sa>/<sa2> was provided but not expected
812 * - PE_ARG_MISSING if <sa>/<sa2> was expected but not provided
813 * - PE_ARG_VALUE_OOR if type is an array and <sa> it out of array size range.
Willy Tarreau3b63ca22021-05-08 14:10:42 +0200814 */
Emeric Brunc64a2a32021-06-30 18:01:02 +0200815int stktable_alloc_data_type(struct stktable *t, int type, const char *sa, const char *sa2)
816
Willy Tarreau3b63ca22021-05-08 14:10:42 +0200817{
818 if (type >= STKTABLE_DATA_TYPES)
819 return PE_ENUM_OOR;
820
821 if (t->data_ofs[type])
822 /* already allocated */
823 return PE_EXIST;
824
Emeric Brunc64a2a32021-06-30 18:01:02 +0200825 t->data_nbelem[type] = 1;
826 if (stktable_data_types[type].is_array) {
827 /* arrays take their element count on first argument */
828 if (!sa)
829 return PE_ARG_MISSING;
830 t->data_nbelem[type] = atoi(sa);
831 if (!t->data_nbelem[type] || (t->data_nbelem[type] > STKTABLE_MAX_DT_ARRAY_SIZE))
832 return PE_ARG_VALUE_OOR;
833 sa = sa2;
834 }
835
Willy Tarreau3b63ca22021-05-08 14:10:42 +0200836 switch (stktable_data_types[type].arg_type) {
837 case ARG_T_NONE:
838 if (sa)
839 return PE_ARG_NOT_USED;
840 break;
841 case ARG_T_INT:
842 if (!sa)
843 return PE_ARG_MISSING;
844 t->data_arg[type].i = atoi(sa);
845 break;
846 case ARG_T_DELAY:
847 if (!sa)
848 return PE_ARG_MISSING;
849 sa = parse_time_err(sa, &t->data_arg[type].u, TIME_UNIT_MS);
850 if (sa)
851 return PE_ARG_INVC; /* invalid char */
852 break;
853 }
854
Emeric Brunc64a2a32021-06-30 18:01:02 +0200855 t->data_size += t->data_nbelem[type] * stktable_type_size(stktable_data_types[type].std_type);
Willy Tarreau3b63ca22021-05-08 14:10:42 +0200856 t->data_ofs[type] = -t->data_size;
857 return PE_NONE;
858}
859
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100860/*
Frédéric Lécaillec02766a2019-03-20 15:06:55 +0100861 * Parse a line with <linenum> as number in <file> configuration file to configure
862 * the stick-table with <t> as address and <id> as ID.
863 * <peers> provides the "peers" section pointer only if this function is called
864 * from a "peers" section.
865 * <nid> is the stick-table name which is sent over the network. It must be equal
866 * to <id> if this stick-table is parsed from a proxy section, and prefixed by <peers>
867 * "peers" section name followed by a '/' character if parsed from a "peers" section.
Ilya Shipitsind4259502020-04-08 01:07:56 +0500868 * This is the responsibility of the caller to check this.
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100869 * Return an error status with ERR_* flags set if required, 0 if no error was encountered.
870 */
871int parse_stick_table(const char *file, int linenum, char **args,
Frédéric Lécaillec02766a2019-03-20 15:06:55 +0100872 struct stktable *t, char *id, char *nid, struct peers *peers)
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100873{
874 int err_code = 0;
875 int idx = 1;
876 unsigned int val;
877
878 if (!id || !*id) {
879 ha_alert("parsing [%s:%d] : %s: ID not provided.\n", file, linenum, args[0]);
880 err_code |= ERR_ALERT | ERR_ABORT;
881 goto out;
882 }
883
884 /* Store the "peers" section if this function is called from a "peers" section. */
885 if (peers) {
886 t->peers.p = peers;
887 idx++;
888 }
889
890 t->id = id;
Frédéric Lécaille36d15652022-10-17 14:58:19 +0200891 t->idlen = strlen(id);
Frédéric Lécaillec02766a2019-03-20 15:06:55 +0100892 t->nid = nid;
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100893 t->type = (unsigned int)-1;
894 t->conf.file = file;
895 t->conf.line = linenum;
896
897 while (*args[idx]) {
898 const char *err;
899
900 if (strcmp(args[idx], "size") == 0) {
901 idx++;
902 if (!*(args[idx])) {
903 ha_alert("parsing [%s:%d] : %s: missing argument after '%s'.\n",
904 file, linenum, args[0], args[idx-1]);
905 err_code |= ERR_ALERT | ERR_FATAL;
906 goto out;
907 }
908 if ((err = parse_size_err(args[idx], &t->size))) {
909 ha_alert("parsing [%s:%d] : %s: unexpected character '%c' in argument of '%s'.\n",
910 file, linenum, args[0], *err, args[idx-1]);
911 err_code |= ERR_ALERT | ERR_FATAL;
912 goto out;
913 }
914 idx++;
915 }
916 /* This argument does not exit in "peers" section. */
917 else if (!peers && strcmp(args[idx], "peers") == 0) {
918 idx++;
919 if (!*(args[idx])) {
920 ha_alert("parsing [%s:%d] : %s: missing argument after '%s'.\n",
921 file, linenum, args[0], args[idx-1]);
922 err_code |= ERR_ALERT | ERR_FATAL;
923 goto out;
924 }
925 t->peers.name = strdup(args[idx++]);
926 }
927 else if (strcmp(args[idx], "expire") == 0) {
928 idx++;
929 if (!*(args[idx])) {
930 ha_alert("parsing [%s:%d] : %s: missing argument after '%s'.\n",
931 file, linenum, args[0], args[idx-1]);
932 err_code |= ERR_ALERT | ERR_FATAL;
933 goto out;
934 }
935 err = parse_time_err(args[idx], &val, TIME_UNIT_MS);
Willy Tarreau9faebe32019-06-07 19:00:37 +0200936 if (err == PARSE_TIME_OVER) {
937 ha_alert("parsing [%s:%d]: %s: timer overflow in argument <%s> to <%s>, maximum value is 2147483647 ms (~24.8 days).\n",
938 file, linenum, args[0], args[idx], args[idx-1]);
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100939 err_code |= ERR_ALERT | ERR_FATAL;
940 goto out;
941 }
Willy Tarreau9faebe32019-06-07 19:00:37 +0200942 else if (err == PARSE_TIME_UNDER) {
943 ha_alert("parsing [%s:%d]: %s: timer underflow in argument <%s> to <%s>, minimum non-null value is 1 ms.\n",
944 file, linenum, args[0], args[idx], args[idx-1]);
945 err_code |= ERR_ALERT | ERR_FATAL;
946 goto out;
947 }
948 else if (err) {
949 ha_alert("parsing [%s:%d] : %s: unexpected character '%c' in argument of '%s'.\n",
950 file, linenum, args[0], *err, args[idx-1]);
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100951 err_code |= ERR_ALERT | ERR_FATAL;
952 goto out;
953 }
954 t->expire = val;
955 idx++;
956 }
957 else if (strcmp(args[idx], "nopurge") == 0) {
958 t->nopurge = 1;
959 idx++;
960 }
961 else if (strcmp(args[idx], "type") == 0) {
962 idx++;
963 if (stktable_parse_type(args, &idx, &t->type, &t->key_size) != 0) {
964 ha_alert("parsing [%s:%d] : %s: unknown type '%s'.\n",
965 file, linenum, args[0], args[idx]);
966 err_code |= ERR_ALERT | ERR_FATAL;
967 goto out;
968 }
969 /* idx already points to next arg */
970 }
971 else if (strcmp(args[idx], "store") == 0) {
972 int type, err;
Emeric Brunc64a2a32021-06-30 18:01:02 +0200973 char *cw, *nw, *sa, *sa2;
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100974
975 idx++;
976 nw = args[idx];
977 while (*nw) {
978 /* the "store" keyword supports a comma-separated list */
979 cw = nw;
980 sa = NULL; /* store arg */
Emeric Brunc64a2a32021-06-30 18:01:02 +0200981 sa2 = NULL;
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100982 while (*nw && *nw != ',') {
983 if (*nw == '(') {
984 *nw = 0;
985 sa = ++nw;
986 while (*nw != ')') {
987 if (!*nw) {
988 ha_alert("parsing [%s:%d] : %s: missing closing parenthesis after store option '%s'.\n",
989 file, linenum, args[0], cw);
990 err_code |= ERR_ALERT | ERR_FATAL;
991 goto out;
992 }
Emeric Brunc64a2a32021-06-30 18:01:02 +0200993 if (*nw == ',') {
994 *nw = '\0';
995 sa2 = nw + 1;
996 }
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100997 nw++;
998 }
999 *nw = '\0';
1000 }
1001 nw++;
1002 }
1003 if (*nw)
1004 *nw++ = '\0';
1005 type = stktable_get_data_type(cw);
1006 if (type < 0) {
1007 ha_alert("parsing [%s:%d] : %s: unknown store option '%s'.\n",
1008 file, linenum, args[0], cw);
1009 err_code |= ERR_ALERT | ERR_FATAL;
1010 goto out;
1011 }
1012
Emeric Brunc64a2a32021-06-30 18:01:02 +02001013 err = stktable_alloc_data_type(t, type, sa, sa2);
Frédéric Lécailled456aa42019-03-08 14:47:00 +01001014 switch (err) {
1015 case PE_NONE: break;
1016 case PE_EXIST:
1017 ha_warning("parsing [%s:%d]: %s: store option '%s' already enabled, ignored.\n",
1018 file, linenum, args[0], cw);
1019 err_code |= ERR_WARN;
1020 break;
1021
1022 case PE_ARG_MISSING:
1023 ha_alert("parsing [%s:%d] : %s: missing argument to store option '%s'.\n",
1024 file, linenum, args[0], cw);
1025 err_code |= ERR_ALERT | ERR_FATAL;
1026 goto out;
1027
1028 case PE_ARG_NOT_USED:
1029 ha_alert("parsing [%s:%d] : %s: unexpected argument to store option '%s'.\n",
1030 file, linenum, args[0], cw);
1031 err_code |= ERR_ALERT | ERR_FATAL;
1032 goto out;
Emeric Brunc64a2a32021-06-30 18:01:02 +02001033 case PE_ARG_VALUE_OOR:
1034 ha_alert("parsing [%s:%d] : %s: array size is out of allowed range (1-%d) for store option '%s'.\n",
1035 file, linenum, args[0], STKTABLE_MAX_DT_ARRAY_SIZE, cw);
1036 err_code |= ERR_ALERT | ERR_FATAL;
1037 goto out;
Frédéric Lécailled456aa42019-03-08 14:47:00 +01001038
1039 default:
1040 ha_alert("parsing [%s:%d] : %s: error when processing store option '%s'.\n",
1041 file, linenum, args[0], cw);
1042 err_code |= ERR_ALERT | ERR_FATAL;
1043 goto out;
1044 }
1045 }
1046 idx++;
Emeric Brunf7ab0bf2021-06-30 18:58:22 +02001047 if (t->data_ofs[STKTABLE_DT_GPT] && t->data_ofs[STKTABLE_DT_GPT0]) {
1048 ha_alert("parsing [%s:%d] : %s: simultaneous usage of 'gpt' and 'gpt0' in a same table is not permitted as 'gpt' overrides 'gpt0'.\n",
1049 file, linenum, args[0]);
1050 err_code |= ERR_ALERT | ERR_FATAL;
1051 goto out;
1052 }
Emeric Brun726783d2021-06-30 19:06:43 +02001053 else if (t->data_ofs[STKTABLE_DT_GPC] && (t->data_ofs[STKTABLE_DT_GPC0] || t->data_ofs[STKTABLE_DT_GPC1])) {
1054 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",
1055 file, linenum, args[0]);
1056 err_code |= ERR_ALERT | ERR_FATAL;
1057 goto out;
1058 }
1059 else if (t->data_ofs[STKTABLE_DT_GPC_RATE] && (t->data_ofs[STKTABLE_DT_GPC0_RATE] || t->data_ofs[STKTABLE_DT_GPC1_RATE])) {
1060 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",
1061 file, linenum, args[0]);
1062 err_code |= ERR_ALERT | ERR_FATAL;
1063 goto out;
1064 }
Frédéric Lécailled456aa42019-03-08 14:47:00 +01001065 }
Thayne McCombs92149f92020-11-20 01:28:26 -07001066 else if (strcmp(args[idx], "srvkey") == 0) {
1067 char *keytype;
1068 idx++;
1069 keytype = args[idx];
1070 if (strcmp(keytype, "name") == 0) {
1071 t->server_key_type = STKTABLE_SRV_NAME;
1072 }
1073 else if (strcmp(keytype, "addr") == 0) {
1074 t->server_key_type = STKTABLE_SRV_ADDR;
1075 }
1076 else {
1077 ha_alert("parsing [%s:%d] : %s : unknown server key type '%s'.\n",
1078 file, linenum, args[0], keytype);
1079 err_code |= ERR_ALERT | ERR_FATAL;
1080 goto out;
1081
1082 }
1083 idx++;
1084 }
Frédéric Lécailled456aa42019-03-08 14:47:00 +01001085 else {
1086 ha_alert("parsing [%s:%d] : %s: unknown argument '%s'.\n",
1087 file, linenum, args[0], args[idx]);
1088 err_code |= ERR_ALERT | ERR_FATAL;
1089 goto out;
1090 }
1091 }
1092
1093 if (!t->size) {
1094 ha_alert("parsing [%s:%d] : %s: missing size.\n",
1095 file, linenum, args[0]);
1096 err_code |= ERR_ALERT | ERR_FATAL;
1097 goto out;
1098 }
1099
1100 if (t->type == (unsigned int)-1) {
1101 ha_alert("parsing [%s:%d] : %s: missing type.\n",
1102 file, linenum, args[0]);
1103 err_code |= ERR_ALERT | ERR_FATAL;
1104 goto out;
1105 }
1106
1107 out:
1108 return err_code;
1109}
1110
Willy Tarreau8fed9032014-07-03 17:02:46 +02001111/* Prepares a stktable_key from a sample <smp> to search into table <t>.
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001112 * Note that the sample *is* modified and that the returned key may point
1113 * to it, so the sample must not be modified afterwards before the lookup.
Willy Tarreau8fed9032014-07-03 17:02:46 +02001114 * Returns NULL if the sample could not be converted (eg: no matching type),
1115 * otherwise a pointer to the static stktable_key filled with what is needed
1116 * for the lookup.
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001117 */
Willy Tarreau8fed9032014-07-03 17:02:46 +02001118struct stktable_key *smp_to_stkey(struct sample *smp, struct stktable *t)
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001119{
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001120 /* Convert sample. */
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +02001121 if (!sample_convert(smp, t->type))
Willy Tarreau7fc1c6e2012-04-26 11:03:17 +02001122 return NULL;
1123
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001124 /* Fill static_table_key. */
1125 switch (t->type) {
Emeric Brun485479d2010-09-23 18:02:19 +02001126
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +02001127 case SMP_T_IPV4:
Christopher Fauletca20d022017-08-29 15:30:31 +02001128 static_table_key.key = &smp->data.u.ipv4;
1129 static_table_key.key_len = 4;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001130 break;
Emeric Brun485479d2010-09-23 18:02:19 +02001131
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +02001132 case SMP_T_IPV6:
Christopher Fauletca20d022017-08-29 15:30:31 +02001133 static_table_key.key = &smp->data.u.ipv6;
1134 static_table_key.key_len = 16;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001135 break;
Emeric Brun485479d2010-09-23 18:02:19 +02001136
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +02001137 case SMP_T_SINT:
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001138 /* The stick table require a 32bit unsigned int, "sint" is a
1139 * signed 64 it, so we can convert it inplace.
1140 */
Willy Tarreau28c63c12019-10-23 06:21:05 +02001141 smp->data.u.sint = (unsigned int)smp->data.u.sint;
Christopher Fauletca20d022017-08-29 15:30:31 +02001142 static_table_key.key = &smp->data.u.sint;
1143 static_table_key.key_len = 4;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001144 break;
1145
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +02001146 case SMP_T_STR:
Willy Tarreauce6955e2016-08-09 11:59:12 +02001147 if (!smp_make_safe(smp))
1148 return NULL;
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001149 static_table_key.key = smp->data.u.str.area;
1150 static_table_key.key_len = smp->data.u.str.data;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001151 break;
Emeric Brun485479d2010-09-23 18:02:19 +02001152
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +02001153 case SMP_T_BIN:
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001154 if (smp->data.u.str.data < t->key_size) {
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001155 /* This type needs padding with 0. */
Willy Tarreauf65c6c02016-08-09 12:08:41 +02001156 if (!smp_make_rw(smp))
1157 return NULL;
1158
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001159 if (smp->data.u.str.size < t->key_size)
1160 if (!smp_dup(smp))
1161 return NULL;
1162 if (smp->data.u.str.size < t->key_size)
1163 return NULL;
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001164 memset(smp->data.u.str.area + smp->data.u.str.data, 0,
1165 t->key_size - smp->data.u.str.data);
1166 smp->data.u.str.data = t->key_size;
Emeric Brun485479d2010-09-23 18:02:19 +02001167 }
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001168 static_table_key.key = smp->data.u.str.area;
1169 static_table_key.key_len = smp->data.u.str.data;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001170 break;
Emeric Brun485479d2010-09-23 18:02:19 +02001171
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001172 default: /* impossible case. */
1173 return NULL;
Emeric Brun485479d2010-09-23 18:02:19 +02001174 }
1175
Christopher Fauletca20d022017-08-29 15:30:31 +02001176 return &static_table_key;
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001177}
1178
1179/*
Willy Tarreau8fed9032014-07-03 17:02:46 +02001180 * Process a fetch + format conversion as defined by the sample expression <expr>
1181 * on request or response considering the <opt> parameter. Returns either NULL if
1182 * no key could be extracted, or a pointer to the converted result stored in
1183 * static_table_key in format <table_type>. If <smp> is not NULL, it will be reset
1184 * and its flags will be initialized so that the caller gets a copy of the input
Willy Tarreau6bcb0a82014-07-30 08:56:35 +02001185 * sample, and knows why it was not accepted (eg: SMP_F_MAY_CHANGE is present
1186 * without SMP_OPT_FINAL). The output will be usable like this :
1187 *
1188 * return MAY_CHANGE FINAL Meaning for the sample
1189 * NULL 0 * Not present and will never be (eg: header)
1190 * NULL 1 0 Not present or unstable, could change (eg: req_len)
1191 * NULL 1 1 Not present, will not change anymore
1192 * smp 0 * Present and will not change (eg: header)
1193 * smp 1 0 not possible
1194 * smp 1 1 Present, last known value (eg: request length)
Willy Tarreau8fed9032014-07-03 17:02:46 +02001195 */
Willy Tarreau192252e2015-04-04 01:47:55 +02001196struct stktable_key *stktable_fetch_key(struct stktable *t, struct proxy *px, struct session *sess, struct stream *strm,
Willy Tarreau8fed9032014-07-03 17:02:46 +02001197 unsigned int opt, struct sample_expr *expr, struct sample *smp)
1198{
1199 if (smp)
1200 memset(smp, 0, sizeof(*smp));
1201
Willy Tarreau192252e2015-04-04 01:47:55 +02001202 smp = sample_process(px, sess, strm, opt, expr, smp);
Willy Tarreau8fed9032014-07-03 17:02:46 +02001203 if (!smp)
1204 return NULL;
1205
1206 if ((smp->flags & SMP_F_MAY_CHANGE) && !(opt & SMP_OPT_FINAL))
1207 return NULL; /* we can only use stable samples */
1208
1209 return smp_to_stkey(smp, t);
1210}
1211
1212/*
Willy Tarreau12785782012-04-27 21:37:17 +02001213 * Returns 1 if sample expression <expr> result can be converted to table key of
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001214 * type <table_type>, otherwise zero. Used in configuration check.
1215 */
Willy Tarreau12785782012-04-27 21:37:17 +02001216int stktable_compatible_sample(struct sample_expr *expr, unsigned long table_type)
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001217{
Thierry FOURNIERf73eb8f2013-11-27 15:30:55 +01001218 int out_type;
1219
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +02001220 if (table_type >= SMP_TYPES || !stktable_types[table_type].kw)
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001221 return 0;
1222
Thierry FOURNIERf73eb8f2013-11-27 15:30:55 +01001223 out_type = smp_expr_output_type(expr);
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001224
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001225 /* Convert sample. */
1226 if (!sample_casts[out_type][table_type])
Thierry FOURNIERf73eb8f2013-11-27 15:30:55 +01001227 return 0;
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001228
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001229 return 1;
1230}
Emeric Brun3bd697e2010-01-04 15:23:48 +01001231
Willy Tarreauedee1d62014-07-15 16:44:27 +02001232/* Extra data types processing : after the last one, some room may remain
1233 * before STKTABLE_DATA_TYPES that may be used to register extra data types
1234 * at run time.
1235 */
Willy Tarreau08d5f982010-06-06 13:34:54 +02001236struct stktable_data_type stktable_data_types[STKTABLE_DATA_TYPES] = {
Willy Tarreau3b9c6e02010-07-18 08:04:30 +02001237 [STKTABLE_DT_SERVER_ID] = { .name = "server_id", .std_type = STD_T_SINT },
Thierry FOURNIER3cf11112015-07-28 08:57:05 +02001238 [STKTABLE_DT_GPT0] = { .name = "gpt0", .std_type = STD_T_UINT },
Willy Tarreau3b9c6e02010-07-18 08:04:30 +02001239 [STKTABLE_DT_GPC0] = { .name = "gpc0", .std_type = STD_T_UINT },
Willy Tarreauba2ffd12013-05-29 15:54:14 +02001240 [STKTABLE_DT_GPC0_RATE] = { .name = "gpc0_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
Willy Tarreau3b9c6e02010-07-18 08:04:30 +02001241 [STKTABLE_DT_CONN_CNT] = { .name = "conn_cnt", .std_type = STD_T_UINT },
1242 [STKTABLE_DT_CONN_RATE] = { .name = "conn_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
Willy Tarreaudb2ab822021-10-08 17:53:12 +02001243 [STKTABLE_DT_CONN_CUR] = { .name = "conn_cur", .std_type = STD_T_UINT, .is_local = 1 },
Willy Tarreau3b9c6e02010-07-18 08:04:30 +02001244 [STKTABLE_DT_SESS_CNT] = { .name = "sess_cnt", .std_type = STD_T_UINT },
1245 [STKTABLE_DT_SESS_RATE] = { .name = "sess_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
1246 [STKTABLE_DT_HTTP_REQ_CNT] = { .name = "http_req_cnt", .std_type = STD_T_UINT },
1247 [STKTABLE_DT_HTTP_REQ_RATE] = { .name = "http_req_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
1248 [STKTABLE_DT_HTTP_ERR_CNT] = { .name = "http_err_cnt", .std_type = STD_T_UINT },
1249 [STKTABLE_DT_HTTP_ERR_RATE] = { .name = "http_err_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
1250 [STKTABLE_DT_BYTES_IN_CNT] = { .name = "bytes_in_cnt", .std_type = STD_T_ULL },
1251 [STKTABLE_DT_BYTES_IN_RATE] = { .name = "bytes_in_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
1252 [STKTABLE_DT_BYTES_OUT_CNT] = { .name = "bytes_out_cnt", .std_type = STD_T_ULL },
1253 [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 +01001254 [STKTABLE_DT_GPC1] = { .name = "gpc1", .std_type = STD_T_UINT },
1255 [STKTABLE_DT_GPC1_RATE] = { .name = "gpc1_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
Thayne McCombs92149f92020-11-20 01:28:26 -07001256 [STKTABLE_DT_SERVER_KEY] = { .name = "server_key", .std_type = STD_T_DICT },
Willy Tarreau826f3ab2021-02-10 12:07:15 +01001257 [STKTABLE_DT_HTTP_FAIL_CNT] = { .name = "http_fail_cnt", .std_type = STD_T_UINT },
1258 [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 +02001259 [STKTABLE_DT_GPT] = { .name = "gpt", .std_type = STD_T_UINT, .is_array = 1 },
Emeric Brun4d7ada82021-06-30 19:04:16 +02001260 [STKTABLE_DT_GPC] = { .name = "gpc", .std_type = STD_T_UINT, .is_array = 1 },
1261 [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 +02001262};
1263
Willy Tarreauedee1d62014-07-15 16:44:27 +02001264/* Registers stick-table extra data type with index <idx>, name <name>, type
1265 * <std_type> and arg type <arg_type>. If the index is negative, the next free
1266 * index is automatically allocated. The allocated index is returned, or -1 if
1267 * no free index was found or <name> was already registered. The <name> is used
1268 * directly as a pointer, so if it's not stable, the caller must allocate it.
1269 */
1270int stktable_register_data_store(int idx, const char *name, int std_type, int arg_type)
1271{
1272 if (idx < 0) {
1273 for (idx = 0; idx < STKTABLE_DATA_TYPES; idx++) {
1274 if (!stktable_data_types[idx].name)
1275 break;
1276
1277 if (strcmp(stktable_data_types[idx].name, name) == 0)
1278 return -1;
1279 }
1280 }
1281
1282 if (idx >= STKTABLE_DATA_TYPES)
1283 return -1;
1284
1285 if (stktable_data_types[idx].name != NULL)
1286 return -1;
1287
1288 stktable_data_types[idx].name = name;
1289 stktable_data_types[idx].std_type = std_type;
1290 stktable_data_types[idx].arg_type = arg_type;
1291 return idx;
1292}
1293
Willy Tarreau08d5f982010-06-06 13:34:54 +02001294/*
1295 * Returns the data type number for the stktable_data_type whose name is <name>,
1296 * or <0 if not found.
1297 */
1298int stktable_get_data_type(char *name)
1299{
1300 int type;
1301
1302 for (type = 0; type < STKTABLE_DATA_TYPES; type++) {
Willy Tarreauedee1d62014-07-15 16:44:27 +02001303 if (!stktable_data_types[type].name)
1304 continue;
Willy Tarreau08d5f982010-06-06 13:34:54 +02001305 if (strcmp(name, stktable_data_types[type].name) == 0)
1306 return type;
1307 }
Thayne McCombs92149f92020-11-20 01:28:26 -07001308 /* For backwards compatibility */
1309 if (strcmp(name, "server_name") == 0)
1310 return STKTABLE_DT_SERVER_KEY;
Willy Tarreau08d5f982010-06-06 13:34:54 +02001311 return -1;
1312}
1313
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001314/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1315 * it up into this table. Returns true if found, false otherwise. The input
1316 * type is STR so that input samples are converted to string (since all types
1317 * can be converted to strings), then the function casts the string again into
1318 * the table's type. This is a double conversion, but in the future we might
1319 * support automatic input types to perform the cast on the fly.
1320 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001321static int sample_conv_in_table(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001322{
1323 struct stktable *t;
1324 struct stktable_key *key;
1325 struct stksess *ts;
1326
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001327 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001328
1329 key = smp_to_stkey(smp, t);
1330 if (!key)
1331 return 0;
1332
1333 ts = stktable_lookup_key(t, key);
1334
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001335 smp->data.type = SMP_T_BOOL;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001336 smp->data.u.sint = !!ts;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001337 smp->flags = SMP_F_VOL_TEST;
Willy Tarreau43e90352018-06-27 06:25:57 +02001338 stktable_release(t, ts);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001339 return 1;
1340}
1341
1342/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1343 * it up into this table. Returns the data rate received from clients in bytes/s
1344 * if the key is present in the table, otherwise zero, so that comparisons can
1345 * be easily performed. If the inspected parameter is not stored in the table,
1346 * <not found> is returned.
1347 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001348static int sample_conv_table_bytes_in_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001349{
1350 struct stktable *t;
1351 struct stktable_key *key;
1352 struct stksess *ts;
1353 void *ptr;
1354
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001355 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001356
1357 key = smp_to_stkey(smp, t);
1358 if (!key)
1359 return 0;
1360
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001361 ts = stktable_lookup_key(t, key);
1362
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001363 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001364 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001365 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001366
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001367 if (!ts) /* key not present */
1368 return 1;
1369
1370 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_IN_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001371 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001372 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Daniel Corbett3e60b112018-05-27 09:47:12 -04001373 t->data_arg[STKTABLE_DT_BYTES_IN_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001374
Daniel Corbett3e60b112018-05-27 09:47:12 -04001375 stktable_release(t, ts);
1376 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001377}
1378
1379/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1380 * it up into this table. Returns the cumulated number of connections for the key
1381 * if the key is present in the table, otherwise zero, so that comparisons can
1382 * be easily performed. If the inspected parameter is not stored in the table,
1383 * <not found> is returned.
1384 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001385static int sample_conv_table_conn_cnt(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001386{
1387 struct stktable *t;
1388 struct stktable_key *key;
1389 struct stksess *ts;
1390 void *ptr;
1391
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001392 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001393
1394 key = smp_to_stkey(smp, t);
1395 if (!key)
1396 return 0;
1397
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001398 ts = stktable_lookup_key(t, key);
1399
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001400 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001401 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001402 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001403
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001404 if (!ts) /* key not present */
1405 return 1;
1406
1407 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_CONN_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001408 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001409 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001410
Daniel Corbett3e60b112018-05-27 09:47:12 -04001411 stktable_release(t, ts);
1412 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001413}
1414
1415/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1416 * it up into this table. Returns the number of concurrent connections for the
1417 * key if the key is present in the table, otherwise zero, so that comparisons
1418 * can be easily performed. If the inspected parameter is not stored in the
1419 * table, <not found> is returned.
1420 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001421static int sample_conv_table_conn_cur(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001422{
1423 struct stktable *t;
1424 struct stktable_key *key;
1425 struct stksess *ts;
1426 void *ptr;
1427
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001428 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001429
1430 key = smp_to_stkey(smp, t);
1431 if (!key)
1432 return 0;
1433
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001434 ts = stktable_lookup_key(t, key);
1435
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001436 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001437 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001438 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001439
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001440 if (!ts) /* key not present */
1441 return 1;
1442
1443 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_CONN_CUR);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001444 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001445 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001446
Daniel Corbett3e60b112018-05-27 09:47:12 -04001447 stktable_release(t, ts);
1448 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001449}
1450
1451/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1452 * it up into this table. Returns the rate of incoming connections from the key
1453 * if the key is present in the table, otherwise zero, so that comparisons can
1454 * be easily performed. If the inspected parameter is not stored in the table,
1455 * <not found> is returned.
1456 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001457static int sample_conv_table_conn_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001458{
1459 struct stktable *t;
1460 struct stktable_key *key;
1461 struct stksess *ts;
1462 void *ptr;
1463
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001464 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001465
1466 key = smp_to_stkey(smp, t);
1467 if (!key)
1468 return 0;
1469
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001470 ts = stktable_lookup_key(t, key);
1471
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001472 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001473 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001474 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001475
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001476 if (!ts) /* key not present */
1477 return 1;
1478
1479 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_CONN_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001480 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001481 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Daniel Corbett3e60b112018-05-27 09:47:12 -04001482 t->data_arg[STKTABLE_DT_CONN_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001483
Daniel Corbett3e60b112018-05-27 09:47:12 -04001484 stktable_release(t, ts);
1485 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001486}
1487
1488/* 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 +02001489 * it up into this table. Returns the expiration delay for the key if the key is
1490 * present in the table, otherwise the default value provided as second argument
1491 * if any, if not (no default value), <not found> is returned.
1492 */
1493static int sample_conv_table_expire(const struct arg *arg_p, struct sample *smp, void *private)
1494{
1495 struct stktable *t;
1496 struct stktable_key *key;
1497 struct stksess *ts;
1498
1499 t = arg_p[0].data.t;
1500
1501 key = smp_to_stkey(smp, t);
1502 if (!key)
1503 return 0;
1504
1505 ts = stktable_lookup_key(t, key);
1506
1507 smp->flags = SMP_F_VOL_TEST;
1508 smp->data.type = SMP_T_SINT;
1509 smp->data.u.sint = 0;
1510
1511 if (!ts) { /* key not present */
1512 if (arg_p[1].type == ARGT_STOP)
1513 return 0;
1514
1515 /* default value */
1516 smp->data.u.sint = arg_p[1].data.sint;
1517 return 1;
1518 }
1519
1520 smp->data.u.sint = tick_remain(now_ms, ts->expire);
1521
1522 stktable_release(t, ts);
1523 return 1;
1524}
1525
1526/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1527 * it up into this table. Returns the time the key remains unused if the key is
1528 * present in the table, otherwise the default value provided as second argument
1529 * if any, if not (no default value), <not found> is returned.
1530 */
1531static int sample_conv_table_idle(const struct arg *arg_p, struct sample *smp, void *private)
1532{
1533 struct stktable *t;
1534 struct stktable_key *key;
1535 struct stksess *ts;
1536
1537 t = arg_p[0].data.t;
1538
1539 key = smp_to_stkey(smp, t);
1540 if (!key)
1541 return 0;
1542
1543 ts = stktable_lookup_key(t, key);
1544
1545 smp->flags = SMP_F_VOL_TEST;
1546 smp->data.type = SMP_T_SINT;
1547 smp->data.u.sint = 0;
1548
1549 if (!ts) { /* key not present */
1550 if (arg_p[1].type == ARGT_STOP)
1551 return 0;
1552
1553 /* default value */
1554 smp->data.u.sint = arg_p[1].data.sint;
1555 return 1;
1556 }
1557
1558 smp->data.u.sint = tick_remain(tick_remain(now_ms, ts->expire), t->expire);
1559
1560 stktable_release(t, ts);
1561 return 1;
1562}
1563
1564/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001565 * it up into this table. Returns the data rate sent to clients in bytes/s
1566 * if the key is present in the table, otherwise zero, so that comparisons can
1567 * be easily performed. If the inspected parameter is not stored in the table,
1568 * <not found> is returned.
1569 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001570static int sample_conv_table_bytes_out_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001571{
1572 struct stktable *t;
1573 struct stktable_key *key;
1574 struct stksess *ts;
1575 void *ptr;
1576
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001577 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001578
1579 key = smp_to_stkey(smp, t);
1580 if (!key)
1581 return 0;
1582
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001583 ts = stktable_lookup_key(t, key);
1584
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001585 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001586 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001587 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001588
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001589 if (!ts) /* key not present */
1590 return 1;
1591
1592 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_OUT_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001593 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001594 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Daniel Corbett3e60b112018-05-27 09:47:12 -04001595 t->data_arg[STKTABLE_DT_BYTES_OUT_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001596
Daniel Corbett3e60b112018-05-27 09:47:12 -04001597 stktable_release(t, ts);
1598 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001599}
1600
Emeric Brun877b0b52021-06-30 18:57:49 +02001601/* Casts sample <smp> to the type of the table specified in arg_p(1), and looks
1602 * it up into this table. Returns the value of the GPT[arg_p(0)] tag for the key
1603 * if the key is present in the table, otherwise false, so that comparisons can
1604 * be easily performed. If the inspected parameter is not stored in the table,
1605 * <not found> is returned.
1606 */
1607static int sample_conv_table_gpt(const struct arg *arg_p, struct sample *smp, void *private)
1608{
1609 struct stktable *t;
1610 struct stktable_key *key;
1611 struct stksess *ts;
1612 void *ptr;
1613 unsigned int idx;
1614
1615 idx = arg_p[0].data.sint;
1616
1617 t = arg_p[1].data.t;
1618
1619 key = smp_to_stkey(smp, t);
1620 if (!key)
1621 return 0;
1622
1623 ts = stktable_lookup_key(t, key);
1624
1625 smp->flags = SMP_F_VOL_TEST;
1626 smp->data.type = SMP_T_SINT;
1627 smp->data.u.sint = 0;
1628
1629 if (!ts) /* key not present */
1630 return 1;
1631
1632 ptr = stktable_data_ptr_idx(t, ts, STKTABLE_DT_GPT, idx);
1633 if (ptr)
1634 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
1635
1636 stktable_release(t, ts);
1637 return !!ptr;
1638}
1639
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001640/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001641 * it up into this table. Returns the value of the GPT0 tag for the key
1642 * if the key is present in the table, otherwise false, so that comparisons can
1643 * be easily performed. If the inspected parameter is not stored in the table,
1644 * <not found> is returned.
1645 */
1646static int sample_conv_table_gpt0(const struct arg *arg_p, struct sample *smp, void *private)
1647{
1648 struct stktable *t;
1649 struct stktable_key *key;
1650 struct stksess *ts;
1651 void *ptr;
1652
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001653 t = arg_p[0].data.t;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001654
1655 key = smp_to_stkey(smp, t);
1656 if (!key)
1657 return 0;
1658
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001659 ts = stktable_lookup_key(t, key);
1660
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001661 smp->flags = SMP_F_VOL_TEST;
1662 smp->data.type = SMP_T_SINT;
1663 smp->data.u.sint = 0;
1664
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001665 if (!ts) /* key not present */
1666 return 1;
1667
1668 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPT0);
Emeric Brunf7ab0bf2021-06-30 18:58:22 +02001669 if (!ptr)
1670 ptr = stktable_data_ptr_idx(t, ts, STKTABLE_DT_GPT, 0);
1671
Daniel Corbett3e60b112018-05-27 09:47:12 -04001672 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001673 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001674
Daniel Corbett3e60b112018-05-27 09:47:12 -04001675 stktable_release(t, ts);
1676 return !!ptr;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001677}
1678
Emeric Brun4d7ada82021-06-30 19:04:16 +02001679/* Casts sample <smp> to the type of the table specified in arg_p(1), and looks
1680 * it up into this table. Returns the value of the GPC[arg_p(0)] counter for the key
1681 * if the key is present in the table, otherwise zero, so that comparisons can
1682 * be easily performed. If the inspected parameter is not stored in the table,
1683 * <not found> is returned.
1684 */
1685static int sample_conv_table_gpc(const struct arg *arg_p, struct sample *smp, void *private)
1686{
1687 struct stktable *t;
1688 struct stktable_key *key;
1689 struct stksess *ts;
1690 void *ptr;
1691 unsigned int idx;
1692
1693 idx = arg_p[0].data.sint;
1694
1695 t = arg_p[1].data.t;
1696
1697 key = smp_to_stkey(smp, t);
1698 if (!key)
1699 return 0;
1700
1701 ts = stktable_lookup_key(t, key);
1702
1703 smp->flags = SMP_F_VOL_TEST;
1704 smp->data.type = SMP_T_SINT;
1705 smp->data.u.sint = 0;
1706
1707 if (!ts) /* key not present */
1708 return 1;
1709
1710 ptr = stktable_data_ptr_idx(t, ts, STKTABLE_DT_GPC, idx);
1711 if (ptr)
1712 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
1713
1714 stktable_release(t, ts);
1715 return !!ptr;
1716}
1717
1718/* Casts sample <smp> to the type of the table specified in arg_p(1), and looks
1719 * it up into this table. Returns the event rate of the GPC[arg_p(0)] counter
1720 * for the key if the key is present in the table, otherwise zero, so that
1721 * comparisons can be easily performed. If the inspected parameter is not
1722 * stored in the table, <not found> is returned.
1723 */
1724static int sample_conv_table_gpc_rate(const struct arg *arg_p, struct sample *smp, void *private)
1725{
1726 struct stktable *t;
1727 struct stktable_key *key;
1728 struct stksess *ts;
1729 void *ptr;
1730 unsigned int idx;
1731
1732 idx = arg_p[0].data.sint;
1733
1734 t = arg_p[1].data.t;
1735
1736 key = smp_to_stkey(smp, t);
1737 if (!key)
1738 return 0;
1739
1740 ts = stktable_lookup_key(t, key);
1741
1742 smp->flags = SMP_F_VOL_TEST;
1743 smp->data.type = SMP_T_SINT;
1744 smp->data.u.sint = 0;
1745
1746 if (!ts) /* key not present */
1747 return 1;
1748
1749 ptr = stktable_data_ptr_idx(t, ts, STKTABLE_DT_GPC_RATE, idx);
1750 if (ptr)
1751 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
1752 t->data_arg[STKTABLE_DT_GPC_RATE].u);
1753
1754 stktable_release(t, ts);
1755 return !!ptr;
1756}
1757
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001758/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001759 * it up into this table. Returns the value of the GPC0 counter for the key
1760 * if the key is present in the table, otherwise zero, so that comparisons can
1761 * be easily performed. If the inspected parameter is not stored in the table,
1762 * <not found> is returned.
1763 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001764static int sample_conv_table_gpc0(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001765{
1766 struct stktable *t;
1767 struct stktable_key *key;
1768 struct stksess *ts;
1769 void *ptr;
1770
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001771 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001772
1773 key = smp_to_stkey(smp, t);
1774 if (!key)
1775 return 0;
1776
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001777 ts = stktable_lookup_key(t, key);
1778
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001779 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001780 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001781 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001782
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001783 if (!ts) /* key not present */
1784 return 1;
1785
1786 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPC0);
Emeric Brun726783d2021-06-30 19:06:43 +02001787 if (!ptr) {
1788 /* fallback on the gpc array */
1789 ptr = stktable_data_ptr_idx(t, ts, STKTABLE_DT_GPC, 0);
1790 }
1791
Daniel Corbett3e60b112018-05-27 09:47:12 -04001792 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001793 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001794
Daniel Corbett3e60b112018-05-27 09:47:12 -04001795 stktable_release(t, ts);
1796 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001797}
1798
1799/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1800 * it up into this table. Returns the event rate of the GPC0 counter for the key
1801 * if the key is present in the table, otherwise zero, so that comparisons can
1802 * be easily performed. If the inspected parameter is not stored in the table,
1803 * <not found> is returned.
1804 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001805static int sample_conv_table_gpc0_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001806{
1807 struct stktable *t;
1808 struct stktable_key *key;
1809 struct stksess *ts;
1810 void *ptr;
1811
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001812 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001813
1814 key = smp_to_stkey(smp, t);
1815 if (!key)
1816 return 0;
1817
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001818 ts = stktable_lookup_key(t, key);
1819
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001820 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001821 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001822 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001823
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001824 if (!ts) /* key not present */
1825 return 1;
1826
1827 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPC0_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001828 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001829 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Daniel Corbett3e60b112018-05-27 09:47:12 -04001830 t->data_arg[STKTABLE_DT_GPC0_RATE].u);
Emeric Brun726783d2021-06-30 19:06:43 +02001831 else {
1832 /* fallback on the gpc array */
1833 ptr = stktable_data_ptr_idx(t, ts, STKTABLE_DT_GPC_RATE, 0);
1834 if (ptr)
1835 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
1836 t->data_arg[STKTABLE_DT_GPC_RATE].u);
1837 }
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001838
Daniel Corbett3e60b112018-05-27 09:47:12 -04001839 stktable_release(t, ts);
1840 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001841}
1842
1843/* 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 +01001844 * it up into this table. Returns the value of the GPC1 counter for the key
1845 * if the key is present in the table, otherwise zero, so that comparisons can
1846 * be easily performed. If the inspected parameter is not stored in the table,
1847 * <not found> is returned.
1848 */
1849static int sample_conv_table_gpc1(const struct arg *arg_p, struct sample *smp, void *private)
1850{
1851 struct stktable *t;
1852 struct stktable_key *key;
1853 struct stksess *ts;
1854 void *ptr;
1855
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001856 t = arg_p[0].data.t;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001857
1858 key = smp_to_stkey(smp, t);
1859 if (!key)
1860 return 0;
1861
1862 ts = stktable_lookup_key(t, key);
1863
1864 smp->flags = SMP_F_VOL_TEST;
1865 smp->data.type = SMP_T_SINT;
1866 smp->data.u.sint = 0;
1867
1868 if (!ts) /* key not present */
1869 return 1;
1870
1871 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPC1);
Emeric Brun726783d2021-06-30 19:06:43 +02001872 if (!ptr) {
1873 /* fallback on the gpc array */
1874 ptr = stktable_data_ptr_idx(t, ts, STKTABLE_DT_GPC, 1);
1875 }
1876
Daniel Corbett3e60b112018-05-27 09:47:12 -04001877 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001878 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001879
Daniel Corbett3e60b112018-05-27 09:47:12 -04001880 stktable_release(t, ts);
1881 return !!ptr;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001882}
1883
1884/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1885 * it up into this table. Returns the event rate of the GPC1 counter for the key
1886 * if the key is present in the table, otherwise zero, so that comparisons can
1887 * be easily performed. If the inspected parameter is not stored in the table,
1888 * <not found> is returned.
1889 */
1890static int sample_conv_table_gpc1_rate(const struct arg *arg_p, struct sample *smp, void *private)
1891{
1892 struct stktable *t;
1893 struct stktable_key *key;
1894 struct stksess *ts;
1895 void *ptr;
1896
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001897 t = arg_p[0].data.t;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001898
1899 key = smp_to_stkey(smp, t);
1900 if (!key)
1901 return 0;
1902
1903 ts = stktable_lookup_key(t, key);
1904
1905 smp->flags = SMP_F_VOL_TEST;
1906 smp->data.type = SMP_T_SINT;
1907 smp->data.u.sint = 0;
1908
1909 if (!ts) /* key not present */
1910 return 1;
1911
1912 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPC1_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001913 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001914 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Daniel Corbett3e60b112018-05-27 09:47:12 -04001915 t->data_arg[STKTABLE_DT_GPC1_RATE].u);
Emeric Brun726783d2021-06-30 19:06:43 +02001916 else {
1917 /* fallback on the gpc array */
1918 ptr = stktable_data_ptr_idx(t, ts, STKTABLE_DT_GPC_RATE, 1);
1919 if (ptr)
1920 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
1921 t->data_arg[STKTABLE_DT_GPC_RATE].u);
1922 }
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001923
Daniel Corbett3e60b112018-05-27 09:47:12 -04001924 stktable_release(t, ts);
1925 return !!ptr;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001926}
1927
1928/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001929 * it up into this table. Returns the cumulated number of HTTP request errors
1930 * for the key if the key is present in the table, otherwise zero, so that
1931 * comparisons can be easily performed. If the inspected parameter is not stored
1932 * in the table, <not found> is returned.
1933 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001934static int sample_conv_table_http_err_cnt(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001935{
1936 struct stktable *t;
1937 struct stktable_key *key;
1938 struct stksess *ts;
1939 void *ptr;
1940
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001941 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001942
1943 key = smp_to_stkey(smp, t);
1944 if (!key)
1945 return 0;
1946
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001947 ts = stktable_lookup_key(t, key);
1948
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001949 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001950 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001951 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001952
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001953 if (!ts) /* key not present */
1954 return 1;
1955
1956 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_ERR_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001957 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001958 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001959
Daniel Corbett3e60b112018-05-27 09:47:12 -04001960 stktable_release(t, ts);
1961 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001962}
1963
1964/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1965 * it up into this table. Returns the HTTP request error rate the key
1966 * if the key is present in the table, otherwise zero, so that comparisons can
1967 * be easily performed. If the inspected parameter is not stored in the table,
1968 * <not found> is returned.
1969 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001970static int sample_conv_table_http_err_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001971{
1972 struct stktable *t;
1973 struct stktable_key *key;
1974 struct stksess *ts;
1975 void *ptr;
1976
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001977 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001978
1979 key = smp_to_stkey(smp, t);
1980 if (!key)
1981 return 0;
1982
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001983 ts = stktable_lookup_key(t, key);
1984
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001985 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001986 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001987 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001988
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001989 if (!ts) /* key not present */
1990 return 1;
1991
1992 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_ERR_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001993 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001994 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Daniel Corbett3e60b112018-05-27 09:47:12 -04001995 t->data_arg[STKTABLE_DT_HTTP_ERR_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001996
Daniel Corbett3e60b112018-05-27 09:47:12 -04001997 stktable_release(t, ts);
1998 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001999}
2000
2001/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Willy Tarreau826f3ab2021-02-10 12:07:15 +01002002 * it up into this table. Returns the cumulated number of HTTP response failures
2003 * for the key if the key is present in the table, otherwise zero, so that
2004 * comparisons can be easily performed. If the inspected parameter is not stored
2005 * in the table, <not found> is returned.
2006 */
2007static int sample_conv_table_http_fail_cnt(const struct arg *arg_p, struct sample *smp, void *private)
2008{
2009 struct stktable *t;
2010 struct stktable_key *key;
2011 struct stksess *ts;
2012 void *ptr;
2013
2014 t = arg_p[0].data.t;
2015
2016 key = smp_to_stkey(smp, t);
2017 if (!key)
2018 return 0;
2019
2020 ts = stktable_lookup_key(t, key);
2021
2022 smp->flags = SMP_F_VOL_TEST;
2023 smp->data.type = SMP_T_SINT;
2024 smp->data.u.sint = 0;
2025
2026 if (!ts) /* key not present */
2027 return 1;
2028
2029 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_FAIL_CNT);
2030 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002031 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Willy Tarreau826f3ab2021-02-10 12:07:15 +01002032
2033 stktable_release(t, ts);
2034 return !!ptr;
2035}
2036
2037/* Casts sample <smp> to the type of the table specified in arg(0), and looks
2038 * it up into this table. Returns the HTTP response failure rate for the key
2039 * if the key is present in the table, otherwise zero, so that comparisons can
2040 * be easily performed. If the inspected parameter is not stored in the table,
2041 * <not found> is returned.
2042 */
2043static int sample_conv_table_http_fail_rate(const struct arg *arg_p, struct sample *smp, void *private)
2044{
2045 struct stktable *t;
2046 struct stktable_key *key;
2047 struct stksess *ts;
2048 void *ptr;
2049
2050 t = arg_p[0].data.t;
2051
2052 key = smp_to_stkey(smp, t);
2053 if (!key)
2054 return 0;
2055
2056 ts = stktable_lookup_key(t, key);
2057
2058 smp->flags = SMP_F_VOL_TEST;
2059 smp->data.type = SMP_T_SINT;
2060 smp->data.u.sint = 0;
2061
2062 if (!ts) /* key not present */
2063 return 1;
2064
2065 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_FAIL_RATE);
2066 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002067 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Willy Tarreau826f3ab2021-02-10 12:07:15 +01002068 t->data_arg[STKTABLE_DT_HTTP_FAIL_RATE].u);
2069
2070 stktable_release(t, ts);
2071 return !!ptr;
2072}
2073
2074/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002075 * it up into this table. Returns the cumulated number of HTTP request for the
2076 * key if the key is present in the table, otherwise zero, so that comparisons
2077 * can be easily performed. If the inspected parameter is not stored in the
2078 * table, <not found> is returned.
2079 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02002080static int sample_conv_table_http_req_cnt(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002081{
2082 struct stktable *t;
2083 struct stktable_key *key;
2084 struct stksess *ts;
2085 void *ptr;
2086
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002087 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002088
2089 key = smp_to_stkey(smp, t);
2090 if (!key)
2091 return 0;
2092
Willy Tarreauf0c730a2016-05-25 17:07:56 +02002093 ts = stktable_lookup_key(t, key);
2094
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002095 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02002096 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02002097 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002098
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002099 if (!ts) /* key not present */
2100 return 1;
2101
2102 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_REQ_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04002103 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002104 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002105
Daniel Corbett3e60b112018-05-27 09:47:12 -04002106 stktable_release(t, ts);
2107 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002108}
2109
2110/* Casts sample <smp> to the type of the table specified in arg(0), and looks
2111 * it up into this table. Returns the HTTP request rate the key if the key is
2112 * present in the table, otherwise zero, so that comparisons can be easily
2113 * performed. If the inspected parameter is not stored in the table, <not found>
2114 * is returned.
2115 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02002116static int sample_conv_table_http_req_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002117{
2118 struct stktable *t;
2119 struct stktable_key *key;
2120 struct stksess *ts;
2121 void *ptr;
2122
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002123 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002124
2125 key = smp_to_stkey(smp, t);
2126 if (!key)
2127 return 0;
2128
Willy Tarreauf0c730a2016-05-25 17:07:56 +02002129 ts = stktable_lookup_key(t, key);
2130
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002131 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02002132 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02002133 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002134
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002135 if (!ts) /* key not present */
2136 return 1;
2137
2138 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_REQ_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04002139 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002140 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Daniel Corbett3e60b112018-05-27 09:47:12 -04002141 t->data_arg[STKTABLE_DT_HTTP_REQ_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002142
Daniel Corbett3e60b112018-05-27 09:47:12 -04002143 stktable_release(t, ts);
2144 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002145}
2146
2147/* Casts sample <smp> to the type of the table specified in arg(0), and looks
2148 * it up into this table. Returns the volume of datareceived from clients in kbytes
2149 * if the key is present in the table, otherwise zero, so that comparisons can
2150 * be easily performed. If the inspected parameter is not stored in the table,
2151 * <not found> is returned.
2152 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02002153static int sample_conv_table_kbytes_in(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002154{
2155 struct stktable *t;
2156 struct stktable_key *key;
2157 struct stksess *ts;
2158 void *ptr;
2159
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002160 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002161
2162 key = smp_to_stkey(smp, t);
2163 if (!key)
2164 return 0;
2165
Willy Tarreauf0c730a2016-05-25 17:07:56 +02002166 ts = stktable_lookup_key(t, key);
2167
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002168 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02002169 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02002170 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002171
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002172 if (!ts) /* key not present */
2173 return 1;
2174
2175 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_IN_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04002176 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002177 smp->data.u.sint = stktable_data_cast(ptr, std_t_ull) >> 10;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002178
Daniel Corbett3e60b112018-05-27 09:47:12 -04002179 stktable_release(t, ts);
2180 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002181}
2182
2183/* Casts sample <smp> to the type of the table specified in arg(0), and looks
2184 * it up into this table. Returns the volume of data sent to clients in kbytes
2185 * if the key is present in the table, otherwise zero, so that comparisons can
2186 * be easily performed. If the inspected parameter is not stored in the table,
2187 * <not found> is returned.
2188 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02002189static int sample_conv_table_kbytes_out(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002190{
2191 struct stktable *t;
2192 struct stktable_key *key;
2193 struct stksess *ts;
2194 void *ptr;
2195
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002196 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002197
2198 key = smp_to_stkey(smp, t);
2199 if (!key)
2200 return 0;
2201
Willy Tarreauf0c730a2016-05-25 17:07:56 +02002202 ts = stktable_lookup_key(t, key);
2203
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002204 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02002205 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02002206 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002207
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002208 if (!ts) /* key not present */
2209 return 1;
2210
2211 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_OUT_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04002212 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002213 smp->data.u.sint = stktable_data_cast(ptr, std_t_ull) >> 10;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002214
Daniel Corbett3e60b112018-05-27 09:47:12 -04002215 stktable_release(t, ts);
2216 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002217}
2218
2219/* Casts sample <smp> to the type of the table specified in arg(0), and looks
2220 * it up into this table. Returns the server ID associated with the key if the
2221 * key is present in the table, otherwise zero, so that comparisons can be
2222 * easily performed. If the inspected parameter is not stored in the table,
2223 * <not found> is returned.
2224 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02002225static int sample_conv_table_server_id(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002226{
2227 struct stktable *t;
2228 struct stktable_key *key;
2229 struct stksess *ts;
2230 void *ptr;
2231
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002232 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002233
2234 key = smp_to_stkey(smp, t);
2235 if (!key)
2236 return 0;
2237
Willy Tarreauf0c730a2016-05-25 17:07:56 +02002238 ts = stktable_lookup_key(t, key);
2239
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002240 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02002241 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02002242 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002243
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002244 if (!ts) /* key not present */
2245 return 1;
2246
2247 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_SERVER_ID);
Daniel Corbett3e60b112018-05-27 09:47:12 -04002248 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002249 smp->data.u.sint = stktable_data_cast(ptr, std_t_sint);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002250
Daniel Corbett3e60b112018-05-27 09:47:12 -04002251 stktable_release(t, ts);
2252 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002253}
2254
2255/* Casts sample <smp> to the type of the table specified in arg(0), and looks
2256 * it up into this table. Returns the cumulated number of sessions for the
2257 * key if the key is present in the table, otherwise zero, so that comparisons
2258 * can be easily performed. If the inspected parameter is not stored in the
2259 * table, <not found> is returned.
2260 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02002261static int sample_conv_table_sess_cnt(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002262{
2263 struct stktable *t;
2264 struct stktable_key *key;
2265 struct stksess *ts;
2266 void *ptr;
2267
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002268 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002269
2270 key = smp_to_stkey(smp, t);
2271 if (!key)
2272 return 0;
2273
Willy Tarreauf0c730a2016-05-25 17:07:56 +02002274 ts = stktable_lookup_key(t, key);
2275
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002276 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02002277 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02002278 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002279
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002280 if (!ts) /* key not present */
2281 return 1;
2282
2283 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_SESS_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04002284 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002285 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002286
Daniel Corbett3e60b112018-05-27 09:47:12 -04002287 stktable_release(t, ts);
2288 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002289}
2290
2291/* Casts sample <smp> to the type of the table specified in arg(0), and looks
2292 * it up into this table. Returns the session rate the key if the key is
2293 * present in the table, otherwise zero, so that comparisons can be easily
2294 * performed. If the inspected parameter is not stored in the table, <not found>
2295 * is returned.
2296 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02002297static int sample_conv_table_sess_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002298{
2299 struct stktable *t;
2300 struct stktable_key *key;
2301 struct stksess *ts;
2302 void *ptr;
2303
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002304 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002305
2306 key = smp_to_stkey(smp, t);
2307 if (!key)
2308 return 0;
2309
Willy Tarreauf0c730a2016-05-25 17:07:56 +02002310 ts = stktable_lookup_key(t, key);
2311
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002312 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02002313 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02002314 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002315
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002316 if (!ts) /* key not present */
2317 return 1;
2318
2319 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_SESS_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04002320 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002321 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Daniel Corbett3e60b112018-05-27 09:47:12 -04002322 t->data_arg[STKTABLE_DT_SESS_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002323
Daniel Corbett3e60b112018-05-27 09:47:12 -04002324 stktable_release(t, ts);
2325 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002326}
2327
2328/* Casts sample <smp> to the type of the table specified in arg(0), and looks
2329 * it up into this table. Returns the amount of concurrent connections tracking
2330 * the same key if the key is present in the table, otherwise zero, so that
2331 * comparisons can be easily performed. If the inspected parameter is not
2332 * stored in the table, <not found> is returned.
2333 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02002334static int sample_conv_table_trackers(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002335{
2336 struct stktable *t;
2337 struct stktable_key *key;
2338 struct stksess *ts;
2339
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002340 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002341
2342 key = smp_to_stkey(smp, t);
2343 if (!key)
2344 return 0;
2345
Willy Tarreauf0c730a2016-05-25 17:07:56 +02002346 ts = stktable_lookup_key(t, key);
2347
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002348 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02002349 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02002350 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002351
Tim Duesterhus65189c12018-06-26 15:57:29 +02002352 if (!ts)
2353 return 1;
2354
2355 smp->data.u.sint = ts->ref_cnt;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002356
Daniel Corbett3e60b112018-05-27 09:47:12 -04002357 stktable_release(t, ts);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002358 return 1;
2359}
2360
Emeric Brun4d7ada82021-06-30 19:04:16 +02002361/* This function increments the gpc counter at index 'rule->arg.gpc.idx' of the
2362 * array on the tracksc counter of index 'rule->arg.gpc.sc' stored into the
2363 * <stream> or directly in the session <sess> if <stream> is set to NULL
2364 *
2365 * This function always returns ACT_RET_CONT and parameter flags is unused.
2366 */
2367static enum act_return action_inc_gpc(struct act_rule *rule, struct proxy *px,
2368 struct session *sess, struct stream *s, int flags)
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002369{
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002370 struct stksess *ts;
2371 struct stkctr *stkctr;
2372
2373 /* Extract the stksess, return OK if no stksess available. */
2374 if (s)
2375 stkctr = &s->stkctr[rule->arg.gpc.sc];
2376 else
2377 stkctr = &sess->stkctr[rule->arg.gpc.sc];
Willy Tarreau79c1e912016-01-25 14:54:45 +01002378
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002379 ts = stkctr_entry(stkctr);
Willy Tarreau79c1e912016-01-25 14:54:45 +01002380 if (ts) {
2381 void *ptr1, *ptr2;
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002382
Emeric Brun4d7ada82021-06-30 19:04:16 +02002383 /* First, update gpc_rate if it's tracked. Second, update its gpc if tracked. */
2384 ptr1 = stktable_data_ptr_idx(stkctr->table, ts, STKTABLE_DT_GPC_RATE, rule->arg.gpc.idx);
2385 ptr2 = stktable_data_ptr_idx(stkctr->table, ts, STKTABLE_DT_GPC, rule->arg.gpc.idx);
2386
Emeric Brun819fc6f2017-06-13 19:37:32 +02002387 if (ptr1 || ptr2) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002388 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002389
2390 if (ptr1)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002391 update_freq_ctr_period(&stktable_data_cast(ptr1, std_t_frqp),
Emeric Brun4d7ada82021-06-30 19:04:16 +02002392 stkctr->table->data_arg[STKTABLE_DT_GPC_RATE].u, 1);
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002393
Emeric Brun819fc6f2017-06-13 19:37:32 +02002394 if (ptr2)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002395 stktable_data_cast(ptr2, std_t_uint)++;
Willy Tarreau79c1e912016-01-25 14:54:45 +01002396
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002397 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002398
2399 /* If data was modified, we need to touch to re-schedule sync */
2400 stktable_touch_local(stkctr->table, ts, 0);
2401 }
Willy Tarreau79c1e912016-01-25 14:54:45 +01002402 }
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002403 return ACT_RET_CONT;
2404}
2405
Emeric Brun4d7ada82021-06-30 19:04:16 +02002406/* Same as action_inc_gpc() but for gpc0 only */
2407static enum act_return action_inc_gpc0(struct act_rule *rule, struct proxy *px,
2408 struct session *sess, struct stream *s, int flags)
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002409{
Emeric Brun4d7ada82021-06-30 19:04:16 +02002410 struct stksess *ts;
2411 struct stkctr *stkctr;
Willy Tarreau5b654ad2021-07-06 18:51:12 +02002412 unsigned int period = 0;
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002413
Emeric Brun4d7ada82021-06-30 19:04:16 +02002414 /* Extract the stksess, return OK if no stksess available. */
2415 if (s)
2416 stkctr = &s->stkctr[rule->arg.gpc.sc];
2417 else
2418 stkctr = &sess->stkctr[rule->arg.gpc.sc];
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002419
Emeric Brun4d7ada82021-06-30 19:04:16 +02002420 ts = stkctr_entry(stkctr);
2421 if (ts) {
2422 void *ptr1, *ptr2;
2423
2424 /* First, update gpc0_rate if it's tracked. Second, update its gpc0 if tracked. */
2425 ptr1 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC0_RATE);
Emeric Brun726783d2021-06-30 19:06:43 +02002426 if (ptr1) {
2427 period = stkctr->table->data_arg[STKTABLE_DT_GPC0_RATE].u;
2428 }
2429 else {
2430 /* fallback on the gpc array */
2431 ptr1 = stktable_data_ptr_idx(stkctr->table, ts, STKTABLE_DT_GPC_RATE, 0);
2432 if (ptr1)
2433 period = stkctr->table->data_arg[STKTABLE_DT_GPC_RATE].u;
2434 }
2435
Emeric Brun4d7ada82021-06-30 19:04:16 +02002436 ptr2 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC0);
Emeric Brun726783d2021-06-30 19:06:43 +02002437 if (!ptr2) {
2438 /* fallback on the gpc array */
2439 ptr2 = stktable_data_ptr_idx(stkctr->table, ts, STKTABLE_DT_GPC, 0);
2440 }
2441
Emeric Brun4d7ada82021-06-30 19:04:16 +02002442 if (ptr1 || ptr2) {
2443 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
2444
2445 if (ptr1)
2446 update_freq_ctr_period(&stktable_data_cast(ptr1, std_t_frqp),
Emeric Brun726783d2021-06-30 19:06:43 +02002447 period, 1);
Emeric Brun4d7ada82021-06-30 19:04:16 +02002448
2449 if (ptr2)
2450 stktable_data_cast(ptr2, std_t_uint)++;
2451
2452 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
2453
2454 /* If data was modified, we need to touch to re-schedule sync */
2455 stktable_touch_local(stkctr->table, ts, 0);
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002456 }
2457 }
Emeric Brun4d7ada82021-06-30 19:04:16 +02002458 return ACT_RET_CONT;
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002459}
2460
Emeric Brun4d7ada82021-06-30 19:04:16 +02002461/* Same as action_inc_gpc() but for gpc1 only */
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002462static enum act_return action_inc_gpc1(struct act_rule *rule, struct proxy *px,
2463 struct session *sess, struct stream *s, int flags)
2464{
2465 struct stksess *ts;
2466 struct stkctr *stkctr;
Willy Tarreau5b654ad2021-07-06 18:51:12 +02002467 unsigned int period = 0;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002468
2469 /* Extract the stksess, return OK if no stksess available. */
2470 if (s)
2471 stkctr = &s->stkctr[rule->arg.gpc.sc];
2472 else
2473 stkctr = &sess->stkctr[rule->arg.gpc.sc];
2474
2475 ts = stkctr_entry(stkctr);
2476 if (ts) {
2477 void *ptr1, *ptr2;
2478
2479 /* First, update gpc1_rate if it's tracked. Second, update its gpc1 if tracked. */
2480 ptr1 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC1_RATE);
Emeric Brun726783d2021-06-30 19:06:43 +02002481 if (ptr1) {
2482 period = stkctr->table->data_arg[STKTABLE_DT_GPC1_RATE].u;
2483 }
2484 else {
2485 /* fallback on the gpc array */
2486 ptr1 = stktable_data_ptr_idx(stkctr->table, ts, STKTABLE_DT_GPC_RATE, 1);
2487 if (ptr1)
2488 period = stkctr->table->data_arg[STKTABLE_DT_GPC_RATE].u;
2489 }
2490
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002491 ptr2 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC1);
Emeric Brun726783d2021-06-30 19:06:43 +02002492 if (!ptr2) {
2493 /* fallback on the gpc array */
2494 ptr2 = stktable_data_ptr_idx(stkctr->table, ts, STKTABLE_DT_GPC, 1);
2495 }
2496
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002497 if (ptr1 || ptr2) {
2498 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
2499
2500 if (ptr1)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002501 update_freq_ctr_period(&stktable_data_cast(ptr1, std_t_frqp),
Emeric Brun726783d2021-06-30 19:06:43 +02002502 period, 1);
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002503
2504 if (ptr2)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002505 stktable_data_cast(ptr2, std_t_uint)++;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002506
2507 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
2508
2509 /* If data was modified, we need to touch to re-schedule sync */
2510 stktable_touch_local(stkctr->table, ts, 0);
2511 }
2512 }
2513 return ACT_RET_CONT;
2514}
2515
Emeric Brun4d7ada82021-06-30 19:04:16 +02002516/* This function is a common parser for actions incrementing the GPC
2517 * (General Purpose Counters). It understands the formats:
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002518 *
Emeric Brun4d7ada82021-06-30 19:04:16 +02002519 * sc-inc-gpc(<gpc IDX>,<track ID>)
2520 * sc-inc-gpc0([<track ID>])
2521 * sc-inc-gpc1([<track ID>])
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002522 *
Emeric Brun4d7ada82021-06-30 19:04:16 +02002523 * It returns ACT_RET_PRS_ERR if fails and <err> is filled with an error
2524 * message. Otherwise it returns ACT_RET_PRS_OK.
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002525 */
Emeric Brun4d7ada82021-06-30 19:04:16 +02002526static enum act_parse_ret parse_inc_gpc(const char **args, int *arg, struct proxy *px,
2527 struct act_rule *rule, char **err)
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002528{
2529 const char *cmd_name = args[*arg-1];
2530 char *error;
2531
Emeric Brun4d7ada82021-06-30 19:04:16 +02002532 cmd_name += strlen("sc-inc-gpc");
2533 if (*cmd_name == '(') {
2534 cmd_name++; /* skip the '(' */
2535 rule->arg.gpc.idx = strtoul(cmd_name, &error, 10); /* Convert stick table id. */
2536 if (*error != ',') {
2537 memprintf(err, "Missing gpc ID '%s'. Expects sc-inc-gpc(<GPC ID>,<Track ID>)", args[*arg-1]);
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002538 return ACT_RET_PRS_ERR;
2539 }
Emeric Brun4d7ada82021-06-30 19:04:16 +02002540 else {
2541 cmd_name = error + 1; /* skip the ',' */
2542 rule->arg.gpc.sc = strtol(cmd_name, &error, 10); /* Convert stick table id. */
2543 if (*error != ')') {
2544 memprintf(err, "invalid stick table track ID '%s'. Expects sc-inc-gpc(<GPC ID>,<Track ID>)", args[*arg-1]);
2545 return ACT_RET_PRS_ERR;
2546 }
2547
2548 if (rule->arg.gpc.sc >= MAX_SESS_STKCTR) {
2549 memprintf(err, "invalid stick table track ID '%s'. The max allowed ID is %d",
2550 args[*arg-1], MAX_SESS_STKCTR-1);
2551 return ACT_RET_PRS_ERR;
2552 }
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002553 }
Emeric Brun4d7ada82021-06-30 19:04:16 +02002554 rule->action_ptr = action_inc_gpc;
2555 }
2556 else if (*cmd_name == '0' ||*cmd_name == '1') {
2557 char c = *cmd_name;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002558
Emeric Brun4d7ada82021-06-30 19:04:16 +02002559 cmd_name++;
2560 if (*cmd_name == '\0') {
2561 /* default stick table id. */
2562 rule->arg.gpc.sc = 0;
2563 } else {
2564 /* parse the stick table id. */
2565 if (*cmd_name != '(') {
2566 memprintf(err, "invalid stick table track ID. Expects %s(<Track ID>)", args[*arg-1]);
2567 return ACT_RET_PRS_ERR;
2568 }
2569 cmd_name++; /* jump the '(' */
2570 rule->arg.gpc.sc = strtol(cmd_name, &error, 10); /* Convert stick table id. */
2571 if (*error != ')') {
2572 memprintf(err, "invalid stick table track ID. Expects %s(<Track ID>)", args[*arg-1]);
2573 return ACT_RET_PRS_ERR;
2574 }
2575
2576 if (rule->arg.gpc.sc >= MAX_SESS_STKCTR) {
2577 memprintf(err, "invalid stick table track ID. The max allowed ID is %d",
2578 MAX_SESS_STKCTR-1);
2579 return ACT_RET_PRS_ERR;
2580 }
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002581 }
Emeric Brun4d7ada82021-06-30 19:04:16 +02002582 if (c == '1')
2583 rule->action_ptr = action_inc_gpc1;
2584 else
2585 rule->action_ptr = action_inc_gpc0;
2586 }
2587 else {
2588 /* default stick table id. */
2589 memprintf(err, "invalid gpc ID '%s'. Expects sc-set-gpc(<GPC ID>,<Track ID>)", args[*arg-1]);
2590 return ACT_RET_PRS_ERR;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002591 }
2592 rule->action = ACT_CUSTOM;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002593 return ACT_RET_PRS_OK;
2594}
2595
Emeric Brun877b0b52021-06-30 18:57:49 +02002596/* This function sets the gpt at index 'rule->arg.gpt.idx' of the array on the
2597 * tracksc counter of index 'rule->arg.gpt.sc' stored into the <stream> or
2598 * directly in the session <sess> if <stream> is set to NULL. This gpt is
2599 * set to the value computed by the expression 'rule->arg.gpt.expr' or if
2600 * 'rule->arg.gpt.expr' is null directly to the value of 'rule->arg.gpt.value'.
2601 *
2602 * This function always returns ACT_RET_CONT and parameter flags is unused.
2603 */
2604static enum act_return action_set_gpt(struct act_rule *rule, struct proxy *px,
2605 struct session *sess, struct stream *s, int flags)
2606{
2607 void *ptr;
2608 struct stksess *ts;
2609 struct stkctr *stkctr;
2610 unsigned int value = 0;
2611 struct sample *smp;
2612 int smp_opt_dir;
2613
2614 /* Extract the stksess, return OK if no stksess available. */
2615 if (s)
2616 stkctr = &s->stkctr[rule->arg.gpt.sc];
2617 else
2618 stkctr = &sess->stkctr[rule->arg.gpt.sc];
2619
2620 ts = stkctr_entry(stkctr);
2621 if (!ts)
2622 return ACT_RET_CONT;
2623
2624 /* Store the sample in the required sc, and ignore errors. */
2625 ptr = stktable_data_ptr_idx(stkctr->table, ts, STKTABLE_DT_GPT, rule->arg.gpt.idx);
2626 if (ptr) {
2627
2628 if (!rule->arg.gpt.expr)
2629 value = (unsigned int)(rule->arg.gpt.value);
2630 else {
2631 switch (rule->from) {
2632 case ACT_F_TCP_REQ_SES: smp_opt_dir = SMP_OPT_DIR_REQ; break;
2633 case ACT_F_TCP_REQ_CNT: smp_opt_dir = SMP_OPT_DIR_REQ; break;
2634 case ACT_F_TCP_RES_CNT: smp_opt_dir = SMP_OPT_DIR_RES; break;
2635 case ACT_F_HTTP_REQ: smp_opt_dir = SMP_OPT_DIR_REQ; break;
2636 case ACT_F_HTTP_RES: smp_opt_dir = SMP_OPT_DIR_RES; break;
2637 default:
2638 send_log(px, LOG_ERR, "stick table: internal error while setting gpt%u.", rule->arg.gpt.idx);
2639 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))
2640 ha_alert("stick table: internal error while executing setting gpt%u.\n", rule->arg.gpt.idx);
2641 return ACT_RET_CONT;
2642 }
2643
2644 /* Fetch and cast the expression. */
2645 smp = sample_fetch_as_type(px, sess, s, smp_opt_dir|SMP_OPT_FINAL, rule->arg.gpt.expr, SMP_T_SINT);
2646 if (!smp) {
2647 send_log(px, LOG_WARNING, "stick table: invalid expression or data type while setting gpt%u.", rule->arg.gpt.idx);
2648 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))
2649 ha_alert("stick table: invalid expression or data type while setting gpt%u.\n", rule->arg.gpt.idx);
2650 return ACT_RET_CONT;
2651 }
2652 value = (unsigned int)(smp->data.u.sint);
2653 }
2654
2655 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
2656
2657 stktable_data_cast(ptr, std_t_uint) = value;
2658
2659 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
2660
2661 stktable_touch_local(stkctr->table, ts, 0);
2662 }
2663
2664 return ACT_RET_CONT;
2665}
2666
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002667/* Always returns 1. */
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002668static enum act_return action_set_gpt0(struct act_rule *rule, struct proxy *px,
Willy Tarreau658b85b2015-09-27 10:00:49 +02002669 struct session *sess, struct stream *s, int flags)
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002670{
2671 void *ptr;
2672 struct stksess *ts;
2673 struct stkctr *stkctr;
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002674 unsigned int value = 0;
2675 struct sample *smp;
2676 int smp_opt_dir;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002677
2678 /* Extract the stksess, return OK if no stksess available. */
2679 if (s)
2680 stkctr = &s->stkctr[rule->arg.gpt.sc];
2681 else
2682 stkctr = &sess->stkctr[rule->arg.gpt.sc];
Willy Tarreau79c1e912016-01-25 14:54:45 +01002683
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002684 ts = stkctr_entry(stkctr);
2685 if (!ts)
2686 return ACT_RET_CONT;
2687
2688 /* Store the sample in the required sc, and ignore errors. */
2689 ptr = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPT0);
Emeric Brunf7ab0bf2021-06-30 18:58:22 +02002690 if (!ptr)
2691 ptr = stktable_data_ptr_idx(stkctr->table, ts, STKTABLE_DT_GPT, 0);
2692
Willy Tarreau79c1e912016-01-25 14:54:45 +01002693 if (ptr) {
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002694 if (!rule->arg.gpt.expr)
2695 value = (unsigned int)(rule->arg.gpt.value);
2696 else {
2697 switch (rule->from) {
2698 case ACT_F_TCP_REQ_SES: smp_opt_dir = SMP_OPT_DIR_REQ; break;
2699 case ACT_F_TCP_REQ_CNT: smp_opt_dir = SMP_OPT_DIR_REQ; break;
2700 case ACT_F_TCP_RES_CNT: smp_opt_dir = SMP_OPT_DIR_RES; break;
2701 case ACT_F_HTTP_REQ: smp_opt_dir = SMP_OPT_DIR_REQ; break;
2702 case ACT_F_HTTP_RES: smp_opt_dir = SMP_OPT_DIR_RES; break;
2703 default:
2704 send_log(px, LOG_ERR, "stick table: internal error while setting gpt0.");
2705 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))
2706 ha_alert("stick table: internal error while executing setting gpt0.\n");
2707 return ACT_RET_CONT;
2708 }
2709
2710 /* Fetch and cast the expression. */
2711 smp = sample_fetch_as_type(px, sess, s, smp_opt_dir|SMP_OPT_FINAL, rule->arg.gpt.expr, SMP_T_SINT);
2712 if (!smp) {
2713 send_log(px, LOG_WARNING, "stick table: invalid expression or data type while setting gpt0.");
2714 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))
2715 ha_alert("stick table: invalid expression or data type while setting gpt0.\n");
2716 return ACT_RET_CONT;
2717 }
2718 value = (unsigned int)(smp->data.u.sint);
2719 }
2720
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002721 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002722
Emeric Brun0e3457b2021-06-30 17:18:28 +02002723 stktable_data_cast(ptr, std_t_uint) = value;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002724
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002725 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002726
2727 stktable_touch_local(stkctr->table, ts, 0);
Willy Tarreau79c1e912016-01-25 14:54:45 +01002728 }
2729
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002730 return ACT_RET_CONT;
2731}
2732
Emeric Brun877b0b52021-06-30 18:57:49 +02002733/* This function is a parser for the "sc-set-gpt" and "sc-set-gpt0" actions.
2734 * It understands the formats:
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002735 *
Emeric Brun877b0b52021-06-30 18:57:49 +02002736 * sc-set-gpt(<gpt IDX>,<track ID>) <expression>
2737 * sc-set-gpt0(<track ID>) <expression>
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002738 *
Emeric Brun877b0b52021-06-30 18:57:49 +02002739 * It returns ACT_RET_PRS_ERR if fails and <err> is filled with an error message.
2740 * Otherwise, it returns ACT_RET_PRS_OK and the variable 'rule->arg.gpt.expr'
2741 * is filled with the pointer to the expression to execute or NULL if the arg
2742 * is directly an integer stored into 'rule->arg.gpt.value'.
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002743 */
Emeric Brun877b0b52021-06-30 18:57:49 +02002744static enum act_parse_ret parse_set_gpt(const char **args, int *arg, struct proxy *px,
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002745 struct act_rule *rule, char **err)
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002746{
2747 const char *cmd_name = args[*arg-1];
2748 char *error;
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002749 int smp_val;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002750
Emeric Brun877b0b52021-06-30 18:57:49 +02002751 cmd_name += strlen("sc-set-gpt");
2752 if (*cmd_name == '(') {
2753 cmd_name++; /* skip the '(' */
2754 rule->arg.gpt.idx = strtoul(cmd_name, &error, 10); /* Convert stick table id. */
2755 if (*error != ',') {
2756 memprintf(err, "Missing gpt ID '%s'. Expects sc-set-gpt(<GPT ID>,<Track ID>)", args[*arg-1]);
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002757 return ACT_RET_PRS_ERR;
2758 }
Emeric Brun877b0b52021-06-30 18:57:49 +02002759 else {
2760 cmd_name = error + 1; /* skip the ',' */
2761 rule->arg.gpt.sc = strtol(cmd_name, &error, 10); /* Convert stick table id. */
2762 if (*error != ')') {
2763 memprintf(err, "invalid stick table track ID '%s'. Expects sc-set-gpt(<GPT ID>,<Track ID>)", args[*arg-1]);
2764 return ACT_RET_PRS_ERR;
2765 }
2766
2767 if (rule->arg.gpt.sc >= MAX_SESS_STKCTR) {
2768 memprintf(err, "invalid stick table track ID '%s'. The max allowed ID is %d",
2769 args[*arg-1], MAX_SESS_STKCTR-1);
2770 return ACT_RET_PRS_ERR;
2771 }
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002772 }
Emeric Brun877b0b52021-06-30 18:57:49 +02002773 rule->action_ptr = action_set_gpt;
2774 }
2775 else if (*cmd_name == '0') {
2776 cmd_name++;
2777 if (*cmd_name == '\0') {
2778 /* default stick table id. */
2779 rule->arg.gpt.sc = 0;
2780 } else {
2781 /* parse the stick table id. */
2782 if (*cmd_name != '(') {
2783 memprintf(err, "invalid stick table track ID '%s'. Expects sc-set-gpt0(<Track ID>)", args[*arg-1]);
2784 return ACT_RET_PRS_ERR;
2785 }
2786 cmd_name++; /* jump the '(' */
2787 rule->arg.gpt.sc = strtol(cmd_name, &error, 10); /* Convert stick table id. */
2788 if (*error != ')') {
2789 memprintf(err, "invalid stick table track ID '%s'. Expects sc-set-gpt0(<Track ID>)", args[*arg-1]);
2790 return ACT_RET_PRS_ERR;
2791 }
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002792
Emeric Brun877b0b52021-06-30 18:57:49 +02002793 if (rule->arg.gpt.sc >= MAX_SESS_STKCTR) {
2794 memprintf(err, "invalid stick table track ID '%s'. The max allowed ID is %d",
2795 args[*arg-1], MAX_SESS_STKCTR-1);
2796 return ACT_RET_PRS_ERR;
2797 }
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002798 }
Emeric Brun877b0b52021-06-30 18:57:49 +02002799 rule->action_ptr = action_set_gpt0;
2800 }
2801 else {
2802 /* default stick table id. */
2803 memprintf(err, "invalid gpt ID '%s'. Expects sc-set-gpt(<GPT ID>,<Track ID>)", args[*arg-1]);
2804 return ACT_RET_PRS_ERR;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002805 }
2806
Willy Tarreauece4c4a2021-08-24 14:57:28 +02002807 /* value may be either an integer or an expression */
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002808 rule->arg.gpt.expr = NULL;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002809 rule->arg.gpt.value = strtol(args[*arg], &error, 10);
Willy Tarreauece4c4a2021-08-24 14:57:28 +02002810 if (*error == '\0') {
2811 /* valid integer, skip it */
2812 (*arg)++;
2813 } else {
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002814 rule->arg.gpt.expr = sample_parse_expr((char **)args, arg, px->conf.args.file,
Willy Tarreaue3b57bf2020-02-14 16:50:14 +01002815 px->conf.args.line, err, &px->conf.args, NULL);
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002816 if (!rule->arg.gpt.expr)
2817 return ACT_RET_PRS_ERR;
2818
2819 switch (rule->from) {
2820 case ACT_F_TCP_REQ_SES: smp_val = SMP_VAL_FE_SES_ACC; break;
2821 case ACT_F_TCP_REQ_CNT: smp_val = SMP_VAL_FE_REQ_CNT; break;
2822 case ACT_F_TCP_RES_CNT: smp_val = SMP_VAL_BE_RES_CNT; break;
2823 case ACT_F_HTTP_REQ: smp_val = SMP_VAL_FE_HRQ_HDR; break;
2824 case ACT_F_HTTP_RES: smp_val = SMP_VAL_BE_HRS_HDR; break;
2825 default:
2826 memprintf(err, "internal error, unexpected rule->from=%d, please report this bug!", rule->from);
2827 return ACT_RET_PRS_ERR;
2828 }
2829 if (!(rule->arg.gpt.expr->fetch->val & smp_val)) {
2830 memprintf(err, "fetch method '%s' extracts information from '%s', none of which is available here", args[*arg-1],
2831 sample_src_names(rule->arg.gpt.expr->fetch->use));
2832 free(rule->arg.gpt.expr);
2833 return ACT_RET_PRS_ERR;
2834 }
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002835 }
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002836
Thierry FOURNIER42148732015-09-02 17:17:33 +02002837 rule->action = ACT_CUSTOM;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002838
2839 return ACT_RET_PRS_OK;
2840}
2841
Willy Tarreau7d562212016-11-25 16:10:05 +01002842/* set temp integer to the number of used entries in the table pointed to by expr.
2843 * Accepts exactly 1 argument of type table.
2844 */
2845static int
2846smp_fetch_table_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
2847{
2848 smp->flags = SMP_F_VOL_TEST;
2849 smp->data.type = SMP_T_SINT;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002850 smp->data.u.sint = args->data.t->current;
Willy Tarreau7d562212016-11-25 16:10:05 +01002851 return 1;
2852}
2853
2854/* set temp integer to the number of free entries in the table pointed to by expr.
2855 * Accepts exactly 1 argument of type table.
2856 */
2857static int
2858smp_fetch_table_avl(const struct arg *args, struct sample *smp, const char *kw, void *private)
2859{
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002860 struct stktable *t;
Willy Tarreau7d562212016-11-25 16:10:05 +01002861
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002862 t = args->data.t;
Willy Tarreau7d562212016-11-25 16:10:05 +01002863 smp->flags = SMP_F_VOL_TEST;
2864 smp->data.type = SMP_T_SINT;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002865 smp->data.u.sint = t->size - t->current;
Willy Tarreau7d562212016-11-25 16:10:05 +01002866 return 1;
2867}
2868
2869/* Returns a pointer to a stkctr depending on the fetch keyword name.
2870 * It is designed to be called as sc[0-9]_* sc_* or src_* exclusively.
2871 * sc[0-9]_* will return a pointer to the respective field in the
2872 * stream <l4>. sc_* requires an UINT argument specifying the stick
2873 * counter number. src_* will fill a locally allocated structure with
2874 * the table and entry corresponding to what is specified with src_*.
2875 * NULL may be returned if the designated stkctr is not tracked. For
2876 * the sc_* and sc[0-9]_* forms, an optional table argument may be
2877 * passed. When present, the currently tracked key is then looked up
2878 * in the specified table instead of the current table. The purpose is
Ilya Shipitsin47d17182020-06-21 21:42:57 +05002879 * to be able to convert multiple values per key (eg: have gpc0 from
Willy Tarreau7d562212016-11-25 16:10:05 +01002880 * multiple tables). <strm> is allowed to be NULL, in which case only
2881 * the session will be consulted.
2882 */
2883struct stkctr *
Emeric Brun819fc6f2017-06-13 19:37:32 +02002884smp_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 +01002885{
Willy Tarreau7d562212016-11-25 16:10:05 +01002886 struct stkctr *stkptr;
2887 struct stksess *stksess;
2888 unsigned int num = kw[2] - '0';
2889 int arg = 0;
2890
2891 if (num == '_' - '0') {
2892 /* sc_* variant, args[0] = ctr# (mandatory) */
2893 num = args[arg++].data.sint;
Willy Tarreau7d562212016-11-25 16:10:05 +01002894 }
2895 else if (num > 9) { /* src_* variant, args[0] = table */
2896 struct stktable_key *key;
2897 struct connection *conn = objt_conn(sess->origin);
2898 struct sample smp;
2899
2900 if (!conn)
2901 return NULL;
2902
Joseph Herlant5662fa42018-11-15 13:43:28 -08002903 /* Fetch source address in a sample. */
Willy Tarreau7d562212016-11-25 16:10:05 +01002904 smp.px = NULL;
2905 smp.sess = sess;
2906 smp.strm = strm;
Amaury Denoyellec460c702021-05-12 10:17:47 +02002907 if (!smp_fetch_src || !smp_fetch_src(empty_arg_list, &smp, "src", NULL))
Willy Tarreau7d562212016-11-25 16:10:05 +01002908 return NULL;
2909
2910 /* Converts into key. */
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002911 key = smp_to_stkey(&smp, args->data.t);
Willy Tarreau7d562212016-11-25 16:10:05 +01002912 if (!key)
2913 return NULL;
2914
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002915 stkctr->table = args->data.t;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002916 stkctr_set_entry(stkctr, stktable_lookup_key(stkctr->table, key));
2917 return stkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002918 }
2919
2920 /* Here, <num> contains the counter number from 0 to 9 for
2921 * the sc[0-9]_ form, or even higher using sc_(num) if needed.
2922 * args[arg] is the first optional argument. We first lookup the
2923 * ctr form the stream, then from the session if it was not there.
Christopher Fauleta9fa88a2019-10-21 10:53:34 +02002924 * But we must be sure the counter does not exceed MAX_SESS_STKCTR.
Willy Tarreau7d562212016-11-25 16:10:05 +01002925 */
Christopher Fauleta9fa88a2019-10-21 10:53:34 +02002926 if (num >= MAX_SESS_STKCTR)
2927 return NULL;
Willy Tarreau7d562212016-11-25 16:10:05 +01002928
2929 if (strm)
2930 stkptr = &strm->stkctr[num];
2931 if (!strm || !stkctr_entry(stkptr)) {
2932 stkptr = &sess->stkctr[num];
2933 if (!stkctr_entry(stkptr))
2934 return NULL;
2935 }
2936
2937 stksess = stkctr_entry(stkptr);
2938 if (!stksess)
2939 return NULL;
2940
2941 if (unlikely(args[arg].type == ARGT_TAB)) {
2942 /* an alternate table was specified, let's look up the same key there */
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002943 stkctr->table = args[arg].data.t;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002944 stkctr_set_entry(stkctr, stktable_lookup(stkctr->table, stksess));
2945 return stkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002946 }
2947 return stkptr;
2948}
2949
2950/* same as smp_fetch_sc_stkctr() but dedicated to src_* and can create
2951 * the entry if it doesn't exist yet. This is needed for a few fetch
2952 * functions which need to create an entry, such as src_inc_gpc* and
2953 * src_clr_gpc*.
2954 */
2955struct stkctr *
Emeric Brun819fc6f2017-06-13 19:37:32 +02002956smp_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 +01002957{
Willy Tarreau7d562212016-11-25 16:10:05 +01002958 struct stktable_key *key;
2959 struct connection *conn = objt_conn(sess->origin);
2960 struct sample smp;
2961
2962 if (strncmp(kw, "src_", 4) != 0)
2963 return NULL;
2964
2965 if (!conn)
2966 return NULL;
2967
Joseph Herlant5662fa42018-11-15 13:43:28 -08002968 /* Fetch source address in a sample. */
Willy Tarreau7d562212016-11-25 16:10:05 +01002969 smp.px = NULL;
2970 smp.sess = sess;
2971 smp.strm = strm;
Amaury Denoyellec460c702021-05-12 10:17:47 +02002972 if (!smp_fetch_src || !smp_fetch_src(empty_arg_list, &smp, "src", NULL))
Willy Tarreau7d562212016-11-25 16:10:05 +01002973 return NULL;
2974
2975 /* Converts into key. */
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002976 key = smp_to_stkey(&smp, args->data.t);
Willy Tarreau7d562212016-11-25 16:10:05 +01002977 if (!key)
2978 return NULL;
2979
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002980 stkctr->table = args->data.t;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002981 stkctr_set_entry(stkctr, stktable_get_entry(stkctr->table, key));
2982 return stkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002983}
2984
2985/* set return a boolean indicating if the requested stream counter is
2986 * currently being tracked or not.
2987 * Supports being called as "sc[0-9]_tracked" only.
2988 */
2989static int
2990smp_fetch_sc_tracked(const struct arg *args, struct sample *smp, const char *kw, void *private)
2991{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002992 struct stkctr tmpstkctr;
2993 struct stkctr *stkctr;
2994
Willy Tarreau7d562212016-11-25 16:10:05 +01002995 smp->flags = SMP_F_VOL_TEST;
2996 smp->data.type = SMP_T_BOOL;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002997 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2998 smp->data.u.sint = !!stkctr;
2999
3000 /* release the ref count */
Dirkjan Bussinkff57f1b2018-09-14 14:31:22 +02003001 if (stkctr == &tmpstkctr)
Emeric Brun819fc6f2017-06-13 19:37:32 +02003002 stktable_release(stkctr->table, stkctr_entry(stkctr));
3003
Emeric Brun877b0b52021-06-30 18:57:49 +02003004 return 1;
3005}
3006
3007/* set <smp> to the General Purpose Tag of index set as first arg
3008 * to value from the stream's tracked frontend counters or from the src.
3009 * Supports being called as "sc_get_gpt(<gpt-idx>,<sc-idx>[,<table>])" or
3010 * "src_get_gpt(<gpt-idx>[,<table>])" only. Value zero is returned if
3011 * the key is new or gpt is not stored.
3012 */
3013static int
3014smp_fetch_sc_get_gpt(const struct arg *args, struct sample *smp, const char *kw, void *private)
3015{
3016 struct stkctr tmpstkctr;
3017 struct stkctr *stkctr;
3018 unsigned int idx;
3019
3020 idx = args[0].data.sint;
3021
3022 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args + 1, kw, &tmpstkctr);
3023 if (!stkctr)
3024 return 0;
3025
3026 smp->flags = SMP_F_VOL_TEST;
3027 smp->data.type = SMP_T_SINT;
3028 smp->data.u.sint = 0;
3029
3030 if (stkctr_entry(stkctr)) {
3031 void *ptr;
3032
3033 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPT, idx);
3034 if (!ptr) {
3035 if (stkctr == &tmpstkctr)
3036 stktable_release(stkctr->table, stkctr_entry(stkctr));
3037 return 0; /* parameter not stored */
3038 }
3039
3040 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3041
3042 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
3043
3044 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3045
3046 if (stkctr == &tmpstkctr)
3047 stktable_release(stkctr->table, stkctr_entry(stkctr));
3048 }
Willy Tarreau7d562212016-11-25 16:10:05 +01003049 return 1;
3050}
3051
3052/* set <smp> to the General Purpose Flag 0 value from the stream's tracked
3053 * frontend counters or from the src.
3054 * Supports being called as "sc[0-9]_get_gpc0" or "src_get_gpt0" only. Value
3055 * zero is returned if the key is new.
3056 */
3057static int
3058smp_fetch_sc_get_gpt0(const struct arg *args, struct sample *smp, const char *kw, void *private)
3059{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003060 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003061 struct stkctr *stkctr;
3062
Emeric Brun819fc6f2017-06-13 19:37:32 +02003063 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003064 if (!stkctr)
3065 return 0;
3066
3067 smp->flags = SMP_F_VOL_TEST;
3068 smp->data.type = SMP_T_SINT;
3069 smp->data.u.sint = 0;
3070
Emeric Brun819fc6f2017-06-13 19:37:32 +02003071 if (stkctr_entry(stkctr)) {
3072 void *ptr;
3073
3074 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPT0);
Emeric Brunf7ab0bf2021-06-30 18:58:22 +02003075 if (!ptr)
3076 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPT, 0);
3077
Emeric Brun4d7ada82021-06-30 19:04:16 +02003078 if (!ptr) {
3079 if (stkctr == &tmpstkctr)
3080 stktable_release(stkctr->table, stkctr_entry(stkctr));
3081 return 0; /* parameter not stored */
3082 }
3083
3084 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3085
3086 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
3087
3088 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3089
3090 if (stkctr == &tmpstkctr)
3091 stktable_release(stkctr->table, stkctr_entry(stkctr));
3092 }
3093 return 1;
3094}
3095
3096/* set <smp> to the GPC[args(0)]'s value from the stream's tracked
3097 * frontend counters or from the src.
3098 * Supports being called as "sc_get_gpc(<gpc-idx>,<sc-idx>[,<table>])" or
3099 * "src_get_gpc(<gpc-idx>[,<table>])" only. Value
3100 * Value zero is returned if the key is new or gpc is not stored.
3101 */
3102static int
3103smp_fetch_sc_get_gpc(const struct arg *args, struct sample *smp, const char *kw, void *private)
3104{
3105 struct stkctr tmpstkctr;
3106 struct stkctr *stkctr;
3107 unsigned int idx;
3108
3109 idx = args[0].data.sint;
3110
3111 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args + 1, kw, &tmpstkctr);
3112 if (!stkctr)
3113 return 0;
3114
3115 smp->flags = SMP_F_VOL_TEST;
3116 smp->data.type = SMP_T_SINT;
3117 smp->data.u.sint = 0;
3118
3119 if (stkctr_entry(stkctr) != NULL) {
3120 void *ptr;
3121
3122 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC, idx);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003123 if (!ptr) {
3124 if (stkctr == &tmpstkctr)
3125 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003126 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003127 }
3128
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003129 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003130
Emeric Brun0e3457b2021-06-30 17:18:28 +02003131 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003132
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003133 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003134
3135 if (stkctr == &tmpstkctr)
3136 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003137 }
3138 return 1;
3139}
3140
3141/* set <smp> to the General Purpose Counter 0 value from the stream's tracked
3142 * frontend counters or from the src.
3143 * Supports being called as "sc[0-9]_get_gpc0" or "src_get_gpc0" only. Value
3144 * zero is returned if the key is new.
3145 */
3146static int
3147smp_fetch_sc_get_gpc0(const struct arg *args, struct sample *smp, const char *kw, void *private)
3148{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003149 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003150 struct stkctr *stkctr;
3151
Emeric Brun819fc6f2017-06-13 19:37:32 +02003152 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003153 if (!stkctr)
3154 return 0;
3155
3156 smp->flags = SMP_F_VOL_TEST;
3157 smp->data.type = SMP_T_SINT;
3158 smp->data.u.sint = 0;
3159
3160 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003161 void *ptr;
3162
3163 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0);
3164 if (!ptr) {
Emeric Brun726783d2021-06-30 19:06:43 +02003165 /* fallback on the gpc array */
3166 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC, 0);
3167 }
3168
3169 if (!ptr) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003170 if (stkctr == &tmpstkctr)
3171 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003172 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003173 }
3174
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003175 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003176
Emeric Brun0e3457b2021-06-30 17:18:28 +02003177 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003178
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003179 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003180
3181 if (stkctr == &tmpstkctr)
3182 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003183 }
3184 return 1;
3185}
3186
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003187/* set <smp> to the General Purpose Counter 1 value from the stream's tracked
3188 * frontend counters or from the src.
3189 * Supports being called as "sc[0-9]_get_gpc1" or "src_get_gpc1" only. Value
3190 * zero is returned if the key is new.
3191 */
3192static int
3193smp_fetch_sc_get_gpc1(const struct arg *args, struct sample *smp, const char *kw, void *private)
3194{
3195 struct stkctr tmpstkctr;
3196 struct stkctr *stkctr;
3197
3198 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
3199 if (!stkctr)
3200 return 0;
3201
3202 smp->flags = SMP_F_VOL_TEST;
3203 smp->data.type = SMP_T_SINT;
3204 smp->data.u.sint = 0;
3205
3206 if (stkctr_entry(stkctr) != NULL) {
3207 void *ptr;
3208
3209 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1);
3210 if (!ptr) {
Emeric Brun726783d2021-06-30 19:06:43 +02003211 /* fallback on the gpc array */
3212 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC, 1);
3213 }
3214
3215 if (!ptr) {
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003216 if (stkctr == &tmpstkctr)
3217 stktable_release(stkctr->table, stkctr_entry(stkctr));
3218 return 0; /* parameter not stored */
3219 }
3220
3221 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3222
Emeric Brun0e3457b2021-06-30 17:18:28 +02003223 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003224
3225 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3226
3227 if (stkctr == &tmpstkctr)
3228 stktable_release(stkctr->table, stkctr_entry(stkctr));
3229 }
3230 return 1;
3231}
3232
Emeric Brun4d7ada82021-06-30 19:04:16 +02003233/* set <smp> to the GPC[args(0)]'s event rate from the stream's
3234 * tracked frontend counters or from the src.
3235 * Supports being called as "sc_gpc_rate(<gpc-idx>,<sc-idx>[,<table])"
3236 * or "src_gpc_rate(<gpc-idx>[,<table>])" only.
3237 * Value zero is returned if the key is new or gpc_rate is not stored.
3238 */
3239static int
3240smp_fetch_sc_gpc_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3241{
3242 struct stkctr tmpstkctr;
3243 struct stkctr *stkctr;
3244 unsigned int idx;
3245
3246 idx = args[0].data.sint;
3247
3248 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args + 1, kw, &tmpstkctr);
3249 if (!stkctr)
3250 return 0;
3251
3252 smp->flags = SMP_F_VOL_TEST;
3253 smp->data.type = SMP_T_SINT;
3254 smp->data.u.sint = 0;
3255 if (stkctr_entry(stkctr) != NULL) {
3256 void *ptr;
3257
3258 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC_RATE, idx);
3259 if (!ptr) {
3260 if (stkctr == &tmpstkctr)
3261 stktable_release(stkctr->table, stkctr_entry(stkctr));
3262 return 0; /* parameter not stored */
3263 }
3264
3265 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3266
3267 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
3268 stkctr->table->data_arg[STKTABLE_DT_GPC_RATE].u);
3269
3270 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3271
3272 if (stkctr == &tmpstkctr)
3273 stktable_release(stkctr->table, stkctr_entry(stkctr));
3274 }
3275 return 1;
3276}
3277
Willy Tarreau7d562212016-11-25 16:10:05 +01003278/* set <smp> to the General Purpose Counter 0's event rate from the stream's
3279 * tracked frontend counters or from the src.
3280 * Supports being called as "sc[0-9]_gpc0_rate" or "src_gpc0_rate" only.
3281 * Value zero is returned if the key is new.
3282 */
3283static int
3284smp_fetch_sc_gpc0_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3285{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003286 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003287 struct stkctr *stkctr;
Emeric Brun726783d2021-06-30 19:06:43 +02003288 unsigned int period;
Willy Tarreau7d562212016-11-25 16:10:05 +01003289
Emeric Brun819fc6f2017-06-13 19:37:32 +02003290 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003291 if (!stkctr)
3292 return 0;
3293
3294 smp->flags = SMP_F_VOL_TEST;
3295 smp->data.type = SMP_T_SINT;
3296 smp->data.u.sint = 0;
3297 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003298 void *ptr;
3299
3300 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0_RATE);
Emeric Brun726783d2021-06-30 19:06:43 +02003301 if (ptr) {
3302 period = stkctr->table->data_arg[STKTABLE_DT_GPC0_RATE].u;
3303 }
3304 else {
3305 /* fallback on the gpc array */
3306 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC_RATE, 0);
3307 if (ptr)
3308 period = stkctr->table->data_arg[STKTABLE_DT_GPC_RATE].u;
3309 }
3310
Emeric Brun819fc6f2017-06-13 19:37:32 +02003311 if (!ptr) {
3312 if (stkctr == &tmpstkctr)
3313 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003314 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003315 }
3316
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003317 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003318
Emeric Brun726783d2021-06-30 19:06:43 +02003319 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp), period);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003320
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003321 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003322
3323 if (stkctr == &tmpstkctr)
3324 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003325 }
3326 return 1;
3327}
3328
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003329/* set <smp> to the General Purpose Counter 1's event rate from the stream's
3330 * tracked frontend counters or from the src.
3331 * Supports being called as "sc[0-9]_gpc1_rate" or "src_gpc1_rate" only.
3332 * Value zero is returned if the key is new.
3333 */
3334static int
3335smp_fetch_sc_gpc1_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3336{
3337 struct stkctr tmpstkctr;
3338 struct stkctr *stkctr;
Emeric Brun726783d2021-06-30 19:06:43 +02003339 unsigned int period;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003340
3341 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
3342 if (!stkctr)
3343 return 0;
3344
3345 smp->flags = SMP_F_VOL_TEST;
3346 smp->data.type = SMP_T_SINT;
3347 smp->data.u.sint = 0;
3348 if (stkctr_entry(stkctr) != NULL) {
3349 void *ptr;
3350
3351 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1_RATE);
Emeric Brun726783d2021-06-30 19:06:43 +02003352 if (ptr) {
3353 period = stkctr->table->data_arg[STKTABLE_DT_GPC1_RATE].u;
3354 }
3355 else {
3356 /* fallback on the gpc array */
3357 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC_RATE, 1);
3358 if (ptr)
3359 period = stkctr->table->data_arg[STKTABLE_DT_GPC_RATE].u;
3360 }
3361
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003362 if (!ptr) {
3363 if (stkctr == &tmpstkctr)
3364 stktable_release(stkctr->table, stkctr_entry(stkctr));
3365 return 0; /* parameter not stored */
3366 }
3367
3368 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3369
Emeric Brun726783d2021-06-30 19:06:43 +02003370 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 +01003371
3372 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3373
3374 if (stkctr == &tmpstkctr)
3375 stktable_release(stkctr->table, stkctr_entry(stkctr));
3376 }
3377 return 1;
3378}
3379
Emeric Brun4d7ada82021-06-30 19:04:16 +02003380/* Increment the GPC[args(0)] value from the stream's tracked
3381 * frontend counters and return it into temp integer.
3382 * Supports being called as "sc_inc_gpc(<gpc-idx>,<sc-idx>[,<table>])"
3383 * or "src_inc_gpc(<gpc-idx>[,<table>])" only.
3384 */
3385static int
3386smp_fetch_sc_inc_gpc(const struct arg *args, struct sample *smp, const char *kw, void *private)
3387{
3388 struct stkctr tmpstkctr;
3389 struct stkctr *stkctr;
3390 unsigned int idx;
3391
3392 idx = args[0].data.sint;
3393
3394 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args + 1, kw, &tmpstkctr);
3395 if (!stkctr)
3396 return 0;
3397
3398 smp->flags = SMP_F_VOL_TEST;
3399 smp->data.type = SMP_T_SINT;
3400 smp->data.u.sint = 0;
3401
3402 if (!stkctr_entry(stkctr))
3403 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
3404
3405 if (stkctr && stkctr_entry(stkctr)) {
3406 void *ptr1,*ptr2;
3407
3408
3409 /* First, update gpc0_rate if it's tracked. Second, update its
3410 * gpc0 if tracked. Returns gpc0's value otherwise the curr_ctr.
3411 */
3412 ptr1 = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC_RATE, idx);
3413 ptr2 = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC, idx);
3414 if (ptr1 || ptr2) {
3415 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3416
3417 if (ptr1) {
3418 update_freq_ctr_period(&stktable_data_cast(ptr1, std_t_frqp),
3419 stkctr->table->data_arg[STKTABLE_DT_GPC_RATE].u, 1);
3420 smp->data.u.sint = (&stktable_data_cast(ptr1, std_t_frqp))->curr_ctr;
3421 }
3422
3423 if (ptr2)
3424 smp->data.u.sint = ++stktable_data_cast(ptr2, std_t_uint);
3425
3426 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3427
3428 /* If data was modified, we need to touch to re-schedule sync */
3429 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
3430 }
3431 else if (stkctr == &tmpstkctr)
3432 stktable_release(stkctr->table, stkctr_entry(stkctr));
3433 }
3434 return 1;
3435}
3436
Willy Tarreau7d562212016-11-25 16:10:05 +01003437/* Increment the General Purpose Counter 0 value from the stream's tracked
3438 * frontend counters and return it into temp integer.
3439 * Supports being called as "sc[0-9]_inc_gpc0" or "src_inc_gpc0" only.
3440 */
3441static int
3442smp_fetch_sc_inc_gpc0(const struct arg *args, struct sample *smp, const char *kw, void *private)
3443{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003444 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003445 struct stkctr *stkctr;
Willy Tarreau5b654ad2021-07-06 18:51:12 +02003446 unsigned int period = 0;
Willy Tarreau7d562212016-11-25 16:10:05 +01003447
Emeric Brun819fc6f2017-06-13 19:37:32 +02003448 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003449 if (!stkctr)
3450 return 0;
3451
3452 smp->flags = SMP_F_VOL_TEST;
3453 smp->data.type = SMP_T_SINT;
3454 smp->data.u.sint = 0;
3455
Emeric Brun819fc6f2017-06-13 19:37:32 +02003456 if (!stkctr_entry(stkctr))
3457 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003458
3459 if (stkctr && stkctr_entry(stkctr)) {
3460 void *ptr1,*ptr2;
3461
Emeric Brun819fc6f2017-06-13 19:37:32 +02003462
Willy Tarreau7d562212016-11-25 16:10:05 +01003463 /* First, update gpc0_rate if it's tracked. Second, update its
3464 * gpc0 if tracked. Returns gpc0's value otherwise the curr_ctr.
3465 */
3466 ptr1 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0_RATE);
Emeric Brun726783d2021-06-30 19:06:43 +02003467 if (ptr1) {
3468 period = stkctr->table->data_arg[STKTABLE_DT_GPC0_RATE].u;
3469 }
3470 else {
3471 /* fallback on the gpc array */
3472 ptr1 = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC_RATE, 0);
3473 if (ptr1)
3474 period = stkctr->table->data_arg[STKTABLE_DT_GPC_RATE].u;
3475 }
3476
Willy Tarreau7d562212016-11-25 16:10:05 +01003477 ptr2 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0);
Emeric Brun726783d2021-06-30 19:06:43 +02003478 if (!ptr2) {
3479 /* fallback on the gpc array */
3480 ptr2 = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC, 0);
3481 }
3482
Emeric Brun819fc6f2017-06-13 19:37:32 +02003483 if (ptr1 || ptr2) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003484 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Willy Tarreau7d562212016-11-25 16:10:05 +01003485
Emeric Brun819fc6f2017-06-13 19:37:32 +02003486 if (ptr1) {
Emeric Brun0e3457b2021-06-30 17:18:28 +02003487 update_freq_ctr_period(&stktable_data_cast(ptr1, std_t_frqp),
Emeric Brun726783d2021-06-30 19:06:43 +02003488 period, 1);
Emeric Brun0e3457b2021-06-30 17:18:28 +02003489 smp->data.u.sint = (&stktable_data_cast(ptr1, std_t_frqp))->curr_ctr;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003490 }
3491
3492 if (ptr2)
Emeric Brun0e3457b2021-06-30 17:18:28 +02003493 smp->data.u.sint = ++stktable_data_cast(ptr2, std_t_uint);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003494
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003495 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003496
3497 /* If data was modified, we need to touch to re-schedule sync */
3498 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
3499 }
3500 else if (stkctr == &tmpstkctr)
3501 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003502 }
3503 return 1;
3504}
3505
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003506/* Increment the General Purpose Counter 1 value from the stream's tracked
3507 * frontend counters and return it into temp integer.
3508 * Supports being called as "sc[0-9]_inc_gpc1" or "src_inc_gpc1" only.
3509 */
3510static int
3511smp_fetch_sc_inc_gpc1(const struct arg *args, struct sample *smp, const char *kw, void *private)
3512{
3513 struct stkctr tmpstkctr;
3514 struct stkctr *stkctr;
Willy Tarreau5b654ad2021-07-06 18:51:12 +02003515 unsigned int period = 0;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003516
3517 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
3518 if (!stkctr)
3519 return 0;
3520
3521 smp->flags = SMP_F_VOL_TEST;
3522 smp->data.type = SMP_T_SINT;
3523 smp->data.u.sint = 0;
3524
3525 if (!stkctr_entry(stkctr))
3526 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
3527
3528 if (stkctr && stkctr_entry(stkctr)) {
3529 void *ptr1,*ptr2;
3530
3531
3532 /* First, update gpc1_rate if it's tracked. Second, update its
3533 * gpc1 if tracked. Returns gpc1's value otherwise the curr_ctr.
3534 */
3535 ptr1 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1_RATE);
Emeric Brun726783d2021-06-30 19:06:43 +02003536 if (ptr1) {
3537 period = stkctr->table->data_arg[STKTABLE_DT_GPC1_RATE].u;
3538 }
3539 else {
3540 /* fallback on the gpc array */
3541 ptr1 = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC_RATE, 1);
3542 if (ptr1)
3543 period = stkctr->table->data_arg[STKTABLE_DT_GPC_RATE].u;
3544 }
3545
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003546 ptr2 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1);
Emeric Brun726783d2021-06-30 19:06:43 +02003547 if (!ptr2) {
3548 /* fallback on the gpc array */
3549 ptr2 = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC, 1);
3550 }
3551
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003552 if (ptr1 || ptr2) {
3553 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3554
3555 if (ptr1) {
Emeric Brun0e3457b2021-06-30 17:18:28 +02003556 update_freq_ctr_period(&stktable_data_cast(ptr1, std_t_frqp),
Emeric Brun726783d2021-06-30 19:06:43 +02003557 period, 1);
Emeric Brun0e3457b2021-06-30 17:18:28 +02003558 smp->data.u.sint = (&stktable_data_cast(ptr1, std_t_frqp))->curr_ctr;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003559 }
3560
3561 if (ptr2)
Emeric Brun0e3457b2021-06-30 17:18:28 +02003562 smp->data.u.sint = ++stktable_data_cast(ptr2, std_t_uint);
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003563
3564 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3565
3566 /* If data was modified, we need to touch to re-schedule sync */
3567 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
3568 }
3569 else if (stkctr == &tmpstkctr)
3570 stktable_release(stkctr->table, stkctr_entry(stkctr));
3571 }
3572 return 1;
3573}
3574
Emeric Brun4d7ada82021-06-30 19:04:16 +02003575/* Clear the GPC[args(0)] value from the stream's tracked
3576 * frontend counters and return its previous value into temp integer.
3577 * Supports being called as "sc_clr_gpc(<gpc-idx>,<sc-idx>[,<table>])"
3578 * or "src_clr_gpc(<gpc-idx>[,<table>])" only.
3579 */
3580static int
3581smp_fetch_sc_clr_gpc(const struct arg *args, struct sample *smp, const char *kw, void *private)
3582{
3583 struct stkctr tmpstkctr;
3584 struct stkctr *stkctr;
3585 unsigned int idx;
3586
3587 idx = args[0].data.sint;
3588
3589 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args + 1, kw, &tmpstkctr);
3590 if (!stkctr)
3591 return 0;
3592
3593 smp->flags = SMP_F_VOL_TEST;
3594 smp->data.type = SMP_T_SINT;
3595 smp->data.u.sint = 0;
3596
3597 if (!stkctr_entry(stkctr))
3598 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
3599
3600 if (stkctr && stkctr_entry(stkctr)) {
3601 void *ptr;
3602
3603 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC, idx);
3604 if (!ptr) {
3605 if (stkctr == &tmpstkctr)
3606 stktable_release(stkctr->table, stkctr_entry(stkctr));
3607 return 0; /* parameter not stored */
3608 }
3609
3610 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3611
3612 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
3613 stktable_data_cast(ptr, std_t_uint) = 0;
3614
3615 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3616
3617 /* If data was modified, we need to touch to re-schedule sync */
3618 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
3619 }
3620 return 1;
3621}
3622
Willy Tarreau7d562212016-11-25 16:10:05 +01003623/* Clear the General Purpose Counter 0 value from the stream's tracked
3624 * frontend counters and return its previous value into temp integer.
3625 * Supports being called as "sc[0-9]_clr_gpc0" or "src_clr_gpc0" only.
3626 */
3627static int
3628smp_fetch_sc_clr_gpc0(const struct arg *args, struct sample *smp, const char *kw, void *private)
3629{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003630 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003631 struct stkctr *stkctr;
3632
Emeric Brun819fc6f2017-06-13 19:37:32 +02003633 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003634 if (!stkctr)
3635 return 0;
3636
3637 smp->flags = SMP_F_VOL_TEST;
3638 smp->data.type = SMP_T_SINT;
3639 smp->data.u.sint = 0;
3640
Emeric Brun819fc6f2017-06-13 19:37:32 +02003641 if (!stkctr_entry(stkctr))
3642 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003643
Emeric Brun819fc6f2017-06-13 19:37:32 +02003644 if (stkctr && stkctr_entry(stkctr)) {
3645 void *ptr;
3646
3647 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0);
3648 if (!ptr) {
Emeric Brun726783d2021-06-30 19:06:43 +02003649 /* fallback on the gpc array */
3650 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC, 0);
3651 }
3652
3653 if (!ptr) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003654 if (stkctr == &tmpstkctr)
3655 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003656 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003657 }
3658
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003659 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003660
Emeric Brun0e3457b2021-06-30 17:18:28 +02003661 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
3662 stktable_data_cast(ptr, std_t_uint) = 0;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003663
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003664 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003665
Willy Tarreau7d562212016-11-25 16:10:05 +01003666 /* If data was modified, we need to touch to re-schedule sync */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003667 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
Willy Tarreau7d562212016-11-25 16:10:05 +01003668 }
3669 return 1;
3670}
3671
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003672/* Clear the General Purpose Counter 1 value from the stream's tracked
3673 * frontend counters and return its previous value into temp integer.
3674 * Supports being called as "sc[0-9]_clr_gpc1" or "src_clr_gpc1" only.
3675 */
3676static int
3677smp_fetch_sc_clr_gpc1(const struct arg *args, struct sample *smp, const char *kw, void *private)
3678{
3679 struct stkctr tmpstkctr;
3680 struct stkctr *stkctr;
3681
3682 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
3683 if (!stkctr)
3684 return 0;
3685
3686 smp->flags = SMP_F_VOL_TEST;
3687 smp->data.type = SMP_T_SINT;
3688 smp->data.u.sint = 0;
3689
3690 if (!stkctr_entry(stkctr))
3691 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
3692
3693 if (stkctr && stkctr_entry(stkctr)) {
3694 void *ptr;
3695
3696 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1);
3697 if (!ptr) {
Emeric Brun726783d2021-06-30 19:06:43 +02003698 /* fallback on the gpc array */
3699 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC, 1);
3700 }
3701
3702 if (!ptr) {
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003703 if (stkctr == &tmpstkctr)
3704 stktable_release(stkctr->table, stkctr_entry(stkctr));
3705 return 0; /* parameter not stored */
3706 }
3707
3708 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3709
Emeric Brun0e3457b2021-06-30 17:18:28 +02003710 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
3711 stktable_data_cast(ptr, std_t_uint) = 0;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003712
3713 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3714
3715 /* If data was modified, we need to touch to re-schedule sync */
3716 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
3717 }
3718 return 1;
3719}
3720
Willy Tarreau7d562212016-11-25 16:10:05 +01003721/* set <smp> to the cumulated number of connections from the stream's tracked
3722 * frontend counters. Supports being called as "sc[0-9]_conn_cnt" or
3723 * "src_conn_cnt" only.
3724 */
3725static int
3726smp_fetch_sc_conn_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
3727{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003728 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003729 struct stkctr *stkctr;
3730
Emeric Brun819fc6f2017-06-13 19:37:32 +02003731 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003732 if (!stkctr)
3733 return 0;
3734
3735 smp->flags = SMP_F_VOL_TEST;
3736 smp->data.type = SMP_T_SINT;
3737 smp->data.u.sint = 0;
3738 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003739 void *ptr;
3740
3741 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_CONN_CNT);
3742 if (!ptr) {
3743 if (stkctr == &tmpstkctr)
3744 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003745 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003746 }
3747
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003748 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003749
Emeric Brun0e3457b2021-06-30 17:18:28 +02003750 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003751
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003752 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003753
3754 if (stkctr == &tmpstkctr)
3755 stktable_release(stkctr->table, stkctr_entry(stkctr));
3756
3757
Willy Tarreau7d562212016-11-25 16:10:05 +01003758 }
3759 return 1;
3760}
3761
3762/* set <smp> to the connection rate from the stream's tracked frontend
3763 * counters. Supports being called as "sc[0-9]_conn_rate" or "src_conn_rate"
3764 * only.
3765 */
3766static int
3767smp_fetch_sc_conn_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3768{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003769 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003770 struct stkctr *stkctr;
3771
Emeric Brun819fc6f2017-06-13 19:37:32 +02003772 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003773 if (!stkctr)
3774 return 0;
3775
3776 smp->flags = SMP_F_VOL_TEST;
3777 smp->data.type = SMP_T_SINT;
3778 smp->data.u.sint = 0;
3779 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003780 void *ptr;
3781
3782 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_CONN_RATE);
3783 if (!ptr) {
3784 if (stkctr == &tmpstkctr)
3785 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003786 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003787 }
3788
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003789 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003790
Emeric Brun0e3457b2021-06-30 17:18:28 +02003791 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Willy Tarreau7d562212016-11-25 16:10:05 +01003792 stkctr->table->data_arg[STKTABLE_DT_CONN_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003793
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003794 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003795
3796 if (stkctr == &tmpstkctr)
3797 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003798 }
3799 return 1;
3800}
3801
3802/* set temp integer to the number of connections from the stream's source address
3803 * in the table pointed to by expr, after updating it.
3804 * Accepts exactly 1 argument of type table.
3805 */
3806static int
3807smp_fetch_src_updt_conn_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
3808{
3809 struct connection *conn = objt_conn(smp->sess->origin);
3810 struct stksess *ts;
3811 struct stktable_key *key;
3812 void *ptr;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003813 struct stktable *t;
Willy Tarreau7d562212016-11-25 16:10:05 +01003814
3815 if (!conn)
3816 return 0;
3817
Joseph Herlant5662fa42018-11-15 13:43:28 -08003818 /* Fetch source address in a sample. */
Amaury Denoyellec460c702021-05-12 10:17:47 +02003819 if (!smp_fetch_src || !smp_fetch_src(empty_arg_list, smp, "src", NULL))
Willy Tarreau7d562212016-11-25 16:10:05 +01003820 return 0;
3821
3822 /* Converts into key. */
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003823 key = smp_to_stkey(smp, args->data.t);
Willy Tarreau7d562212016-11-25 16:10:05 +01003824 if (!key)
3825 return 0;
3826
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003827 t = args->data.t;
Willy Tarreau7d562212016-11-25 16:10:05 +01003828
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003829 if ((ts = stktable_get_entry(t, key)) == NULL)
Willy Tarreau7d562212016-11-25 16:10:05 +01003830 /* entry does not exist and could not be created */
3831 return 0;
3832
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003833 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_CONN_CNT);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003834 if (!ptr) {
Willy Tarreau7d562212016-11-25 16:10:05 +01003835 return 0; /* parameter not stored in this table */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003836 }
Willy Tarreau7d562212016-11-25 16:10:05 +01003837
3838 smp->data.type = SMP_T_SINT;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003839
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003840 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003841
Emeric Brun0e3457b2021-06-30 17:18:28 +02003842 smp->data.u.sint = ++stktable_data_cast(ptr, std_t_uint);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003843
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003844 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003845
Willy Tarreau7d562212016-11-25 16:10:05 +01003846 smp->flags = SMP_F_VOL_TEST;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003847
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003848 stktable_touch_local(t, ts, 1);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003849
3850 /* Touch was previously performed by stktable_update_key */
Willy Tarreau7d562212016-11-25 16:10:05 +01003851 return 1;
3852}
3853
3854/* set <smp> to the number of concurrent connections from the stream's tracked
3855 * frontend counters. Supports being called as "sc[0-9]_conn_cur" or
3856 * "src_conn_cur" only.
3857 */
3858static int
3859smp_fetch_sc_conn_cur(const struct arg *args, struct sample *smp, const char *kw, void *private)
3860{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003861 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003862 struct stkctr *stkctr;
3863
Emeric Brun819fc6f2017-06-13 19:37:32 +02003864 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003865 if (!stkctr)
3866 return 0;
3867
3868 smp->flags = SMP_F_VOL_TEST;
3869 smp->data.type = SMP_T_SINT;
3870 smp->data.u.sint = 0;
3871 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003872 void *ptr;
3873
3874 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_CONN_CUR);
3875 if (!ptr) {
3876 if (stkctr == &tmpstkctr)
3877 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003878 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003879 }
3880
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003881 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003882
Emeric Brun0e3457b2021-06-30 17:18:28 +02003883 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003884
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003885 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003886
3887 if (stkctr == &tmpstkctr)
3888 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003889 }
3890 return 1;
3891}
3892
3893/* set <smp> to the cumulated number of streams from the stream's tracked
3894 * frontend counters. Supports being called as "sc[0-9]_sess_cnt" or
3895 * "src_sess_cnt" only.
3896 */
3897static int
3898smp_fetch_sc_sess_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
3899{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003900 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003901 struct stkctr *stkctr;
3902
Emeric Brun819fc6f2017-06-13 19:37:32 +02003903 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003904 if (!stkctr)
3905 return 0;
3906
3907 smp->flags = SMP_F_VOL_TEST;
3908 smp->data.type = SMP_T_SINT;
3909 smp->data.u.sint = 0;
3910 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003911 void *ptr;
3912
3913 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_SESS_CNT);
3914 if (!ptr) {
3915 if (stkctr == &tmpstkctr)
3916 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003917 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003918 }
3919
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003920 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003921
Emeric Brun0e3457b2021-06-30 17:18:28 +02003922 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003923
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003924 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003925
3926 if (stkctr == &tmpstkctr)
3927 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003928 }
3929 return 1;
3930}
3931
3932/* set <smp> to the stream rate from the stream's tracked frontend counters.
3933 * Supports being called as "sc[0-9]_sess_rate" or "src_sess_rate" only.
3934 */
3935static int
3936smp_fetch_sc_sess_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3937{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003938 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003939 struct stkctr *stkctr;
3940
Emeric Brun819fc6f2017-06-13 19:37:32 +02003941 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003942 if (!stkctr)
3943 return 0;
3944
3945 smp->flags = SMP_F_VOL_TEST;
3946 smp->data.type = SMP_T_SINT;
3947 smp->data.u.sint = 0;
3948 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003949 void *ptr;
3950
3951 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_SESS_RATE);
3952 if (!ptr) {
3953 if (stkctr == &tmpstkctr)
3954 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003955 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003956 }
3957
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003958 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003959
Emeric Brun0e3457b2021-06-30 17:18:28 +02003960 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Willy Tarreau7d562212016-11-25 16:10:05 +01003961 stkctr->table->data_arg[STKTABLE_DT_SESS_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003962
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003963 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003964
3965 if (stkctr == &tmpstkctr)
3966 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003967 }
3968 return 1;
3969}
3970
3971/* set <smp> to the cumulated number of HTTP requests from the stream's tracked
3972 * frontend counters. Supports being called as "sc[0-9]_http_req_cnt" or
3973 * "src_http_req_cnt" only.
3974 */
3975static int
3976smp_fetch_sc_http_req_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
3977{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003978 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003979 struct stkctr *stkctr;
3980
Emeric Brun819fc6f2017-06-13 19:37:32 +02003981 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003982 if (!stkctr)
3983 return 0;
3984
3985 smp->flags = SMP_F_VOL_TEST;
3986 smp->data.type = SMP_T_SINT;
3987 smp->data.u.sint = 0;
3988 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003989 void *ptr;
3990
3991 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_REQ_CNT);
3992 if (!ptr) {
3993 if (stkctr == &tmpstkctr)
3994 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003995 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003996 }
3997
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003998 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003999
Emeric Brun0e3457b2021-06-30 17:18:28 +02004000 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004001
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004002 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004003
4004 if (stkctr == &tmpstkctr)
4005 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004006 }
4007 return 1;
4008}
4009
4010/* set <smp> to the HTTP request rate from the stream's tracked frontend
4011 * counters. Supports being called as "sc[0-9]_http_req_rate" or
4012 * "src_http_req_rate" only.
4013 */
4014static int
4015smp_fetch_sc_http_req_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
4016{
Emeric Brun819fc6f2017-06-13 19:37:32 +02004017 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01004018 struct stkctr *stkctr;
4019
Emeric Brun819fc6f2017-06-13 19:37:32 +02004020 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01004021 if (!stkctr)
4022 return 0;
4023
4024 smp->flags = SMP_F_VOL_TEST;
4025 smp->data.type = SMP_T_SINT;
4026 smp->data.u.sint = 0;
4027 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02004028 void *ptr;
4029
4030 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_REQ_RATE);
4031 if (!ptr) {
4032 if (stkctr == &tmpstkctr)
4033 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004034 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02004035 }
4036
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004037 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004038
Emeric Brun0e3457b2021-06-30 17:18:28 +02004039 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Willy Tarreau7d562212016-11-25 16:10:05 +01004040 stkctr->table->data_arg[STKTABLE_DT_HTTP_REQ_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004041
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004042 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004043
4044 if (stkctr == &tmpstkctr)
4045 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004046 }
4047 return 1;
4048}
4049
4050/* set <smp> to the cumulated number of HTTP requests errors from the stream's
4051 * tracked frontend counters. Supports being called as "sc[0-9]_http_err_cnt" or
4052 * "src_http_err_cnt" only.
4053 */
4054static int
4055smp_fetch_sc_http_err_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
4056{
Emeric Brun819fc6f2017-06-13 19:37:32 +02004057 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01004058 struct stkctr *stkctr;
4059
Emeric Brun819fc6f2017-06-13 19:37:32 +02004060 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01004061 if (!stkctr)
4062 return 0;
4063
4064 smp->flags = SMP_F_VOL_TEST;
4065 smp->data.type = SMP_T_SINT;
4066 smp->data.u.sint = 0;
4067 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02004068 void *ptr;
4069
4070 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_ERR_CNT);
4071 if (!ptr) {
4072 if (stkctr == &tmpstkctr)
4073 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004074 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02004075 }
4076
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004077 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004078
Emeric Brun0e3457b2021-06-30 17:18:28 +02004079 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004080
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004081 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004082
4083 if (stkctr == &tmpstkctr)
4084 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004085 }
4086 return 1;
4087}
4088
4089/* set <smp> to the HTTP request error rate from the stream's tracked frontend
4090 * counters. Supports being called as "sc[0-9]_http_err_rate" or
4091 * "src_http_err_rate" only.
4092 */
4093static int
4094smp_fetch_sc_http_err_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
4095{
Emeric Brun819fc6f2017-06-13 19:37:32 +02004096 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01004097 struct stkctr *stkctr;
4098
Emeric Brun819fc6f2017-06-13 19:37:32 +02004099 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01004100 if (!stkctr)
4101 return 0;
4102
4103 smp->flags = SMP_F_VOL_TEST;
4104 smp->data.type = SMP_T_SINT;
4105 smp->data.u.sint = 0;
4106 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02004107 void *ptr;
4108
4109 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_ERR_RATE);
4110 if (!ptr) {
4111 if (stkctr == &tmpstkctr)
4112 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004113 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02004114 }
4115
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004116 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004117
Emeric Brun0e3457b2021-06-30 17:18:28 +02004118 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Willy Tarreau7d562212016-11-25 16:10:05 +01004119 stkctr->table->data_arg[STKTABLE_DT_HTTP_ERR_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004120
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004121 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004122
4123 if (stkctr == &tmpstkctr)
4124 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004125 }
4126 return 1;
4127}
4128
Willy Tarreau826f3ab2021-02-10 12:07:15 +01004129/* set <smp> to the cumulated number of HTTP response failures from the stream's
4130 * tracked frontend counters. Supports being called as "sc[0-9]_http_fail_cnt" or
4131 * "src_http_fail_cnt" only.
4132 */
4133static int
4134smp_fetch_sc_http_fail_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
4135{
4136 struct stkctr tmpstkctr;
4137 struct stkctr *stkctr;
4138
4139 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
4140 if (!stkctr)
4141 return 0;
4142
4143 smp->flags = SMP_F_VOL_TEST;
4144 smp->data.type = SMP_T_SINT;
4145 smp->data.u.sint = 0;
4146 if (stkctr_entry(stkctr) != NULL) {
4147 void *ptr;
4148
4149 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_FAIL_CNT);
4150 if (!ptr) {
4151 if (stkctr == &tmpstkctr)
4152 stktable_release(stkctr->table, stkctr_entry(stkctr));
4153 return 0; /* parameter not stored */
4154 }
4155
4156 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
4157
Emeric Brun0e3457b2021-06-30 17:18:28 +02004158 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Willy Tarreau826f3ab2021-02-10 12:07:15 +01004159
4160 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
4161
4162 if (stkctr == &tmpstkctr)
4163 stktable_release(stkctr->table, stkctr_entry(stkctr));
4164 }
4165 return 1;
4166}
4167
4168/* set <smp> to the HTTP response failure rate from the stream's tracked frontend
4169 * counters. Supports being called as "sc[0-9]_http_fail_rate" or
4170 * "src_http_fail_rate" only.
4171 */
4172static int
4173smp_fetch_sc_http_fail_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
4174{
4175 struct stkctr tmpstkctr;
4176 struct stkctr *stkctr;
4177
4178 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
4179 if (!stkctr)
4180 return 0;
4181
4182 smp->flags = SMP_F_VOL_TEST;
4183 smp->data.type = SMP_T_SINT;
4184 smp->data.u.sint = 0;
4185 if (stkctr_entry(stkctr) != NULL) {
4186 void *ptr;
4187
4188 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_FAIL_RATE);
4189 if (!ptr) {
4190 if (stkctr == &tmpstkctr)
4191 stktable_release(stkctr->table, stkctr_entry(stkctr));
4192 return 0; /* parameter not stored */
4193 }
4194
4195 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
4196
Emeric Brun0e3457b2021-06-30 17:18:28 +02004197 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Willy Tarreau826f3ab2021-02-10 12:07:15 +01004198 stkctr->table->data_arg[STKTABLE_DT_HTTP_FAIL_RATE].u);
4199
4200 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
4201
4202 if (stkctr == &tmpstkctr)
4203 stktable_release(stkctr->table, stkctr_entry(stkctr));
4204 }
4205 return 1;
4206}
4207
Willy Tarreau7d562212016-11-25 16:10:05 +01004208/* set <smp> to the number of kbytes received from clients, as found in the
4209 * stream's tracked frontend counters. Supports being called as
4210 * "sc[0-9]_kbytes_in" or "src_kbytes_in" only.
4211 */
4212static int
4213smp_fetch_sc_kbytes_in(const struct arg *args, struct sample *smp, const char *kw, void *private)
4214{
Emeric Brun819fc6f2017-06-13 19:37:32 +02004215 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01004216 struct stkctr *stkctr;
4217
Emeric Brun819fc6f2017-06-13 19:37:32 +02004218 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01004219 if (!stkctr)
4220 return 0;
4221
4222 smp->flags = SMP_F_VOL_TEST;
4223 smp->data.type = SMP_T_SINT;
4224 smp->data.u.sint = 0;
4225 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02004226 void *ptr;
4227
4228 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_IN_CNT);
4229 if (!ptr) {
4230 if (stkctr == &tmpstkctr)
4231 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004232 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02004233 }
4234
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004235 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004236
Emeric Brun0e3457b2021-06-30 17:18:28 +02004237 smp->data.u.sint = stktable_data_cast(ptr, std_t_ull) >> 10;
Emeric Brun819fc6f2017-06-13 19:37:32 +02004238
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004239 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004240
4241 if (stkctr == &tmpstkctr)
4242 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004243 }
4244 return 1;
4245}
4246
4247/* set <smp> to the data rate received from clients in bytes/s, as found
4248 * in the stream's tracked frontend counters. Supports being called as
4249 * "sc[0-9]_bytes_in_rate" or "src_bytes_in_rate" only.
4250 */
4251static int
4252smp_fetch_sc_bytes_in_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
4253{
Emeric Brun819fc6f2017-06-13 19:37:32 +02004254 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01004255 struct stkctr *stkctr;
4256
Emeric Brun819fc6f2017-06-13 19:37:32 +02004257 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01004258 if (!stkctr)
4259 return 0;
4260
4261 smp->flags = SMP_F_VOL_TEST;
4262 smp->data.type = SMP_T_SINT;
4263 smp->data.u.sint = 0;
4264 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02004265 void *ptr;
4266
4267 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_IN_RATE);
4268 if (!ptr) {
4269 if (stkctr == &tmpstkctr)
4270 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004271 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02004272 }
4273
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004274 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004275
Emeric Brun0e3457b2021-06-30 17:18:28 +02004276 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Willy Tarreau7d562212016-11-25 16:10:05 +01004277 stkctr->table->data_arg[STKTABLE_DT_BYTES_IN_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004278
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004279 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004280
4281 if (stkctr == &tmpstkctr)
4282 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004283 }
4284 return 1;
4285}
4286
4287/* set <smp> to the number of kbytes sent to clients, as found in the
4288 * stream's tracked frontend counters. Supports being called as
4289 * "sc[0-9]_kbytes_out" or "src_kbytes_out" only.
4290 */
4291static int
4292smp_fetch_sc_kbytes_out(const struct arg *args, struct sample *smp, const char *kw, void *private)
4293{
Emeric Brun819fc6f2017-06-13 19:37:32 +02004294 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01004295 struct stkctr *stkctr;
4296
Emeric Brun819fc6f2017-06-13 19:37:32 +02004297 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01004298 if (!stkctr)
4299 return 0;
4300
4301 smp->flags = SMP_F_VOL_TEST;
4302 smp->data.type = SMP_T_SINT;
4303 smp->data.u.sint = 0;
4304 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02004305 void *ptr;
4306
4307 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_OUT_CNT);
4308 if (!ptr) {
4309 if (stkctr == &tmpstkctr)
4310 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004311 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02004312 }
4313
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004314 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004315
Emeric Brun0e3457b2021-06-30 17:18:28 +02004316 smp->data.u.sint = stktable_data_cast(ptr, std_t_ull) >> 10;
Emeric Brun819fc6f2017-06-13 19:37:32 +02004317
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004318 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004319
4320 if (stkctr == &tmpstkctr)
4321 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004322 }
4323 return 1;
4324}
4325
4326/* set <smp> to the data rate sent to clients in bytes/s, as found in the
4327 * stream's tracked frontend counters. Supports being called as
4328 * "sc[0-9]_bytes_out_rate" or "src_bytes_out_rate" only.
4329 */
4330static int
4331smp_fetch_sc_bytes_out_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
4332{
Emeric Brun819fc6f2017-06-13 19:37:32 +02004333 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01004334 struct stkctr *stkctr;
4335
Emeric Brun819fc6f2017-06-13 19:37:32 +02004336 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01004337 if (!stkctr)
4338 return 0;
4339
4340 smp->flags = SMP_F_VOL_TEST;
4341 smp->data.type = SMP_T_SINT;
4342 smp->data.u.sint = 0;
4343 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02004344 void *ptr;
4345
4346 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_OUT_RATE);
4347 if (!ptr) {
4348 if (stkctr == &tmpstkctr)
4349 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004350 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02004351 }
4352
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004353 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004354
Emeric Brun0e3457b2021-06-30 17:18:28 +02004355 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Willy Tarreau7d562212016-11-25 16:10:05 +01004356 stkctr->table->data_arg[STKTABLE_DT_BYTES_OUT_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004357
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004358 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004359
4360 if (stkctr == &tmpstkctr)
4361 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004362 }
4363 return 1;
4364}
4365
4366/* set <smp> to the number of active trackers on the SC entry in the stream's
4367 * tracked frontend counters. Supports being called as "sc[0-9]_trackers" only.
4368 */
4369static int
4370smp_fetch_sc_trackers(const struct arg *args, struct sample *smp, const char *kw, void *private)
4371{
Emeric Brun819fc6f2017-06-13 19:37:32 +02004372 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01004373 struct stkctr *stkctr;
4374
Emeric Brun819fc6f2017-06-13 19:37:32 +02004375 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01004376 if (!stkctr)
4377 return 0;
4378
4379 smp->flags = SMP_F_VOL_TEST;
4380 smp->data.type = SMP_T_SINT;
Emeric Brun819fc6f2017-06-13 19:37:32 +02004381 if (stkctr == &tmpstkctr) {
4382 smp->data.u.sint = stkctr_entry(stkctr) ? (stkctr_entry(stkctr)->ref_cnt-1) : 0;
4383 stktable_release(stkctr->table, stkctr_entry(stkctr));
4384 }
4385 else {
4386 smp->data.u.sint = stkctr_entry(stkctr) ? stkctr_entry(stkctr)->ref_cnt : 0;
4387 }
4388
Willy Tarreau7d562212016-11-25 16:10:05 +01004389 return 1;
4390}
4391
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004392
4393/* The functions below are used to manipulate table contents from the CLI.
4394 * There are 3 main actions, "clear", "set" and "show". The code is shared
4395 * between all actions, and the action is encoded in the void *private in
4396 * the appctx as well as in the keyword registration, among one of the
4397 * following values.
4398 */
4399
4400enum {
4401 STK_CLI_ACT_CLR,
4402 STK_CLI_ACT_SET,
4403 STK_CLI_ACT_SHOW,
4404};
4405
Willy Tarreau4596fe22022-05-17 19:07:51 +02004406/* Dump the status of a table to a stream connector's
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004407 * read buffer. It returns 0 if the output buffer is full
4408 * and needs to be called again, otherwise non-zero.
4409 */
Willy Tarreau83061a82018-07-13 11:56:34 +02004410static int table_dump_head_to_buffer(struct buffer *msg,
Willy Tarreaud0a06d52022-05-18 15:07:19 +02004411 struct appctx *appctx,
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004412 struct stktable *t, struct stktable *target)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004413{
Willy Tarreauc12b3212022-05-27 11:08:15 +02004414 struct stream *s = __sc_strm(appctx_sc(appctx));
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004415
4416 chunk_appendf(msg, "# table: %s, type: %s, size:%d, used:%d\n",
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004417 t->id, stktable_types[t->type].kw, t->size, t->current);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004418
4419 /* any other information should be dumped here */
4420
William Lallemand07a62f72017-05-24 00:57:40 +02004421 if (target && (strm_li(s)->bind_conf->level & ACCESS_LVL_MASK) < ACCESS_LVL_OPER)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004422 chunk_appendf(msg, "# contents not dumped due to insufficient privileges\n");
4423
Willy Tarreaud0a06d52022-05-18 15:07:19 +02004424 if (applet_putchk(appctx, msg) == -1)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004425 return 0;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004426
4427 return 1;
4428}
4429
Willy Tarreau4596fe22022-05-17 19:07:51 +02004430/* Dump a table entry to a stream connector's
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004431 * read buffer. It returns 0 if the output buffer is full
4432 * and needs to be called again, otherwise non-zero.
4433 */
Willy Tarreau83061a82018-07-13 11:56:34 +02004434static int table_dump_entry_to_buffer(struct buffer *msg,
Willy Tarreaud0a06d52022-05-18 15:07:19 +02004435 struct appctx *appctx,
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004436 struct stktable *t, struct stksess *entry)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004437{
4438 int dt;
4439
4440 chunk_appendf(msg, "%p:", entry);
4441
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004442 if (t->type == SMP_T_IPV4) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004443 char addr[INET_ADDRSTRLEN];
4444 inet_ntop(AF_INET, (const void *)&entry->key.key, addr, sizeof(addr));
4445 chunk_appendf(msg, " key=%s", addr);
4446 }
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004447 else if (t->type == SMP_T_IPV6) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004448 char addr[INET6_ADDRSTRLEN];
4449 inet_ntop(AF_INET6, (const void *)&entry->key.key, addr, sizeof(addr));
4450 chunk_appendf(msg, " key=%s", addr);
4451 }
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004452 else if (t->type == SMP_T_SINT) {
Willy Tarreau6cde5d82020-02-25 09:41:22 +01004453 chunk_appendf(msg, " key=%u", read_u32(entry->key.key));
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004454 }
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004455 else if (t->type == SMP_T_STR) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004456 chunk_appendf(msg, " key=");
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004457 dump_text(msg, (const char *)entry->key.key, t->key_size);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004458 }
4459 else {
4460 chunk_appendf(msg, " key=");
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004461 dump_binary(msg, (const char *)entry->key.key, t->key_size);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004462 }
4463
4464 chunk_appendf(msg, " use=%d exp=%d", entry->ref_cnt - 1, tick_remain(now_ms, entry->expire));
4465
4466 for (dt = 0; dt < STKTABLE_DATA_TYPES; dt++) {
4467 void *ptr;
4468
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004469 if (t->data_ofs[dt] == 0)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004470 continue;
Emeric Brunc64a2a32021-06-30 18:01:02 +02004471 if (stktable_data_types[dt].is_array) {
4472 char tmp[16] = {};
4473 const char *name_pfx = stktable_data_types[dt].name;
4474 const char *name_sfx = NULL;
4475 unsigned int idx = 0;
4476 int i = 0;
4477
4478 /* split name to show index before first _ of the name
4479 * for example: 'gpc3_rate' if array name is 'gpc_rate'.
4480 */
4481 for (i = 0 ; i < (sizeof(tmp) - 1); i++) {
4482 if (!name_pfx[i])
4483 break;
4484 if (name_pfx[i] == '_') {
4485 name_pfx = &tmp[0];
4486 name_sfx = &stktable_data_types[dt].name[i];
4487 break;
4488 }
4489 tmp[i] = name_pfx[i];
4490 }
4491
4492 ptr = stktable_data_ptr_idx(t, entry, dt, idx);
4493 while (ptr) {
4494 if (stktable_data_types[dt].arg_type == ARG_T_DELAY)
4495 chunk_appendf(msg, " %s%u%s(%u)=", name_pfx, idx, name_sfx ? name_sfx : "", t->data_arg[dt].u);
4496 else
4497 chunk_appendf(msg, " %s%u%s=", name_pfx, idx, name_sfx ? name_sfx : "");
4498 switch (stktable_data_types[dt].std_type) {
4499 case STD_T_SINT:
4500 chunk_appendf(msg, "%d", stktable_data_cast(ptr, std_t_sint));
4501 break;
4502 case STD_T_UINT:
4503 chunk_appendf(msg, "%u", stktable_data_cast(ptr, std_t_uint));
4504 break;
4505 case STD_T_ULL:
4506 chunk_appendf(msg, "%llu", stktable_data_cast(ptr, std_t_ull));
4507 break;
4508 case STD_T_FRQP:
4509 chunk_appendf(msg, "%u",
4510 read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
4511 t->data_arg[dt].u));
4512 break;
4513 }
4514 ptr = stktable_data_ptr_idx(t, entry, dt, ++idx);
4515 }
4516 continue;
4517 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004518 if (stktable_data_types[dt].arg_type == ARG_T_DELAY)
Emeric Brun01928ae2021-06-30 16:24:04 +02004519 chunk_appendf(msg, " %s(%u)=", stktable_data_types[dt].name, t->data_arg[dt].u);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004520 else
4521 chunk_appendf(msg, " %s=", stktable_data_types[dt].name);
4522
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004523 ptr = stktable_data_ptr(t, entry, dt);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004524 switch (stktable_data_types[dt].std_type) {
4525 case STD_T_SINT:
4526 chunk_appendf(msg, "%d", stktable_data_cast(ptr, std_t_sint));
4527 break;
4528 case STD_T_UINT:
4529 chunk_appendf(msg, "%u", stktable_data_cast(ptr, std_t_uint));
4530 break;
4531 case STD_T_ULL:
Emeric Brun01928ae2021-06-30 16:24:04 +02004532 chunk_appendf(msg, "%llu", stktable_data_cast(ptr, std_t_ull));
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004533 break;
4534 case STD_T_FRQP:
Emeric Brun01928ae2021-06-30 16:24:04 +02004535 chunk_appendf(msg, "%u",
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004536 read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004537 t->data_arg[dt].u));
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004538 break;
Frédéric Lécaille16b4f542019-05-23 12:15:04 +02004539 case STD_T_DICT: {
4540 struct dict_entry *de;
4541 de = stktable_data_cast(ptr, std_t_dict);
4542 chunk_appendf(msg, "%s", de ? (char *)de->value.key : "-");
4543 break;
4544 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004545 }
4546 }
4547 chunk_appendf(msg, "\n");
4548
Willy Tarreaud0a06d52022-05-18 15:07:19 +02004549 if (applet_putchk(appctx, msg) == -1)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004550 return 0;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004551
4552 return 1;
4553}
4554
Willy Tarreau3c69e082022-05-03 11:35:07 +02004555/* appctx context used by the "show table" command */
4556struct show_table_ctx {
4557 void *target; /* table we want to dump, or NULL for all */
4558 struct stktable *t; /* table being currently dumped (first if NULL) */
4559 struct stksess *entry; /* last entry we were trying to dump (or first if NULL) */
4560 long long value[STKTABLE_FILTER_LEN]; /* value to compare against */
4561 signed char data_type[STKTABLE_FILTER_LEN]; /* type of data to compare, or -1 if none */
4562 signed char data_op[STKTABLE_FILTER_LEN]; /* operator (STD_OP_*) when data_type set */
Willy Tarreau7849d4c2022-05-03 11:45:02 +02004563 enum {
Willy Tarreau0f154ed2022-05-03 12:02:36 +02004564 STATE_NEXT = 0, /* px points to next table, entry=NULL */
Willy Tarreau7849d4c2022-05-03 11:45:02 +02004565 STATE_DUMP, /* px points to curr table, entry is valid, refcount held */
4566 STATE_DONE, /* done dumping */
4567 } state;
Willy Tarreau3c69e082022-05-03 11:35:07 +02004568 char action; /* action on the table : one of STK_CLI_ACT_* */
4569};
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004570
4571/* Processes a single table entry matching a specific key passed in argument.
4572 * returns 0 if wants to be called again, 1 if has ended processing.
4573 */
4574static int table_process_entry_per_key(struct appctx *appctx, char **args)
4575{
Willy Tarreau3c69e082022-05-03 11:35:07 +02004576 struct show_table_ctx *ctx = appctx->svcctx;
4577 struct stktable *t = ctx->target;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004578 struct stksess *ts;
4579 uint32_t uint32_key;
4580 unsigned char ip6_key[sizeof(struct in6_addr)];
4581 long long value;
4582 int data_type;
4583 int cur_arg;
4584 void *ptr;
Willy Tarreaufa1258f2021-04-10 23:00:53 +02004585 struct freq_ctr *frqp;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004586
Willy Tarreau9d008692019-08-09 11:21:01 +02004587 if (!*args[4])
4588 return cli_err(appctx, "Key value expected\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004589
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004590 switch (t->type) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004591 case SMP_T_IPV4:
4592 uint32_key = htonl(inetaddr_host(args[4]));
Christopher Fauletca20d022017-08-29 15:30:31 +02004593 static_table_key.key = &uint32_key;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004594 break;
4595 case SMP_T_IPV6:
Christopher Fauletb7c962b2021-11-15 09:17:25 +01004596 if (inet_pton(AF_INET6, args[4], ip6_key) <= 0)
4597 return cli_err(appctx, "Invalid key\n");
Christopher Fauletca20d022017-08-29 15:30:31 +02004598 static_table_key.key = &ip6_key;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004599 break;
4600 case SMP_T_SINT:
4601 {
4602 char *endptr;
4603 unsigned long val;
4604 errno = 0;
4605 val = strtoul(args[4], &endptr, 10);
4606 if ((errno == ERANGE && val == ULONG_MAX) ||
4607 (errno != 0 && val == 0) || endptr == args[4] ||
Willy Tarreau9d008692019-08-09 11:21:01 +02004608 val > 0xffffffff)
4609 return cli_err(appctx, "Invalid key\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004610 uint32_key = (uint32_t) val;
Christopher Fauletca20d022017-08-29 15:30:31 +02004611 static_table_key.key = &uint32_key;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004612 break;
4613 }
4614 break;
4615 case SMP_T_STR:
Christopher Fauletca20d022017-08-29 15:30:31 +02004616 static_table_key.key = args[4];
4617 static_table_key.key_len = strlen(args[4]);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004618 break;
4619 default:
Willy Tarreau3c69e082022-05-03 11:35:07 +02004620 switch (ctx->action) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004621 case STK_CLI_ACT_SHOW:
Willy Tarreau9d008692019-08-09 11:21:01 +02004622 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 +01004623 case STK_CLI_ACT_CLR:
Willy Tarreau9d008692019-08-09 11:21:01 +02004624 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 +01004625 case STK_CLI_ACT_SET:
Willy Tarreau9d008692019-08-09 11:21:01 +02004626 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 +01004627 default:
Willy Tarreau9d008692019-08-09 11:21:01 +02004628 return cli_err(appctx, "Unknown action\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004629 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004630 }
4631
4632 /* check permissions */
4633 if (!cli_has_level(appctx, ACCESS_LVL_OPER))
4634 return 1;
4635
Willy Tarreau3c69e082022-05-03 11:35:07 +02004636 switch (ctx->action) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004637 case STK_CLI_ACT_SHOW:
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004638 ts = stktable_lookup_key(t, &static_table_key);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004639 if (!ts)
4640 return 1;
4641 chunk_reset(&trash);
Willy Tarreaud0a06d52022-05-18 15:07:19 +02004642 if (!table_dump_head_to_buffer(&trash, appctx, t, t)) {
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004643 stktable_release(t, ts);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004644 return 0;
Emeric Brun819fc6f2017-06-13 19:37:32 +02004645 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004646 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &ts->lock);
Willy Tarreaud0a06d52022-05-18 15:07:19 +02004647 if (!table_dump_entry_to_buffer(&trash, appctx, t, ts)) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004648 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004649 stktable_release(t, ts);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004650 return 0;
Emeric Brun819fc6f2017-06-13 19:37:32 +02004651 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004652 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004653 stktable_release(t, ts);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004654 break;
4655
4656 case STK_CLI_ACT_CLR:
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004657 ts = stktable_lookup_key(t, &static_table_key);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004658 if (!ts)
4659 return 1;
Emeric Brun819fc6f2017-06-13 19:37:32 +02004660
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004661 if (!stksess_kill(t, ts, 1)) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004662 /* don't delete an entry which is currently referenced */
Willy Tarreau9d008692019-08-09 11:21:01 +02004663 return cli_err(appctx, "Entry currently in use, cannot remove\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004664 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004665 break;
4666
4667 case STK_CLI_ACT_SET:
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004668 ts = stktable_get_entry(t, &static_table_key);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004669 if (!ts) {
4670 /* don't delete an entry which is currently referenced */
Willy Tarreau9d008692019-08-09 11:21:01 +02004671 return cli_err(appctx, "Unable to allocate a new entry\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004672 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004673 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004674 for (cur_arg = 5; *args[cur_arg]; cur_arg += 2) {
4675 if (strncmp(args[cur_arg], "data.", 5) != 0) {
Willy Tarreau9d008692019-08-09 11:21:01 +02004676 cli_err(appctx, "\"data.<type>\" followed by a value expected\n");
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004677 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004678 stktable_touch_local(t, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004679 return 1;
4680 }
4681
4682 data_type = stktable_get_data_type(args[cur_arg] + 5);
4683 if (data_type < 0) {
Willy Tarreau9d008692019-08-09 11:21:01 +02004684 cli_err(appctx, "Unknown data type\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
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004690 if (!t->data_ofs[data_type]) {
Willy Tarreau9d008692019-08-09 11:21:01 +02004691 cli_err(appctx, "Data type not stored in this table\n");
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004692 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004693 stktable_touch_local(t, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004694 return 1;
4695 }
4696
4697 if (!*args[cur_arg+1] || strl2llrc(args[cur_arg+1], strlen(args[cur_arg+1]), &value) != 0) {
Willy Tarreau9d008692019-08-09 11:21:01 +02004698 cli_err(appctx, "Require a valid integer value to store\n");
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004699 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004700 stktable_touch_local(t, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004701 return 1;
4702 }
4703
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004704 ptr = stktable_data_ptr(t, ts, data_type);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004705
4706 switch (stktable_data_types[data_type].std_type) {
4707 case STD_T_SINT:
4708 stktable_data_cast(ptr, std_t_sint) = value;
4709 break;
4710 case STD_T_UINT:
4711 stktable_data_cast(ptr, std_t_uint) = value;
4712 break;
4713 case STD_T_ULL:
4714 stktable_data_cast(ptr, std_t_ull) = value;
4715 break;
4716 case STD_T_FRQP:
4717 /* We set both the current and previous values. That way
4718 * the reported frequency is stable during all the period
4719 * then slowly fades out. This allows external tools to
4720 * push measures without having to update them too often.
4721 */
4722 frqp = &stktable_data_cast(ptr, std_t_frqp);
Willy Tarreaufa1258f2021-04-10 23:00:53 +02004723 /* First bit is reserved for the freq_ctr lock
Emeric Brunf2fc1fd2017-11-02 17:32:43 +01004724 Note: here we're still protected by the stksess lock
Willy Tarreaufa1258f2021-04-10 23:00:53 +02004725 so we don't need to update the update the freq_ctr
Emeric Brunf2fc1fd2017-11-02 17:32:43 +01004726 using its internal lock */
4727 frqp->curr_tick = now_ms & ~0x1;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004728 frqp->prev_ctr = 0;
4729 frqp->curr_ctr = value;
4730 break;
4731 }
4732 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004733 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004734 stktable_touch_local(t, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004735 break;
4736
4737 default:
Willy Tarreau9d008692019-08-09 11:21:01 +02004738 return cli_err(appctx, "Unknown action\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004739 }
4740 return 1;
4741}
4742
4743/* Prepares the appctx fields with the data-based filters from the command line.
4744 * Returns 0 if the dump can proceed, 1 if has ended processing.
4745 */
4746static int table_prepare_data_request(struct appctx *appctx, char **args)
4747{
Willy Tarreau3c69e082022-05-03 11:35:07 +02004748 struct show_table_ctx *ctx = appctx->svcctx;
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004749 int i;
Adis Nezirovicd0142e72020-01-22 16:50:27 +01004750 char *err = NULL;
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004751
Willy Tarreau3c69e082022-05-03 11:35:07 +02004752 if (ctx->action != STK_CLI_ACT_SHOW && ctx->action != STK_CLI_ACT_CLR)
Willy Tarreau9d008692019-08-09 11:21:01 +02004753 return cli_err(appctx, "content-based lookup is only supported with the \"show\" and \"clear\" actions\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004754
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004755 for (i = 0; i < STKTABLE_FILTER_LEN; i++) {
4756 if (i > 0 && !*args[3+3*i]) // number of filter entries can be less than STKTABLE_FILTER_LEN
4757 break;
4758 /* condition on stored data value */
Willy Tarreau3c69e082022-05-03 11:35:07 +02004759 ctx->data_type[i] = stktable_get_data_type(args[3+3*i] + 5);
4760 if (ctx->data_type[i] < 0)
Adis Nezirovicd0142e72020-01-22 16:50:27 +01004761 return cli_dynerr(appctx, memprintf(&err, "Filter entry #%i: Unknown data type\n", i + 1));
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004762
Willy Tarreau3c69e082022-05-03 11:35:07 +02004763 if (!((struct stktable *)ctx->target)->data_ofs[ctx->data_type[i]])
Adis Nezirovicd0142e72020-01-22 16:50:27 +01004764 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 +01004765
Willy Tarreau3c69e082022-05-03 11:35:07 +02004766 ctx->data_op[i] = get_std_op(args[4+3*i]);
4767 if (ctx->data_op[i] < 0)
Adis Nezirovicd0142e72020-01-22 16:50:27 +01004768 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 +01004769
Willy Tarreau3c69e082022-05-03 11:35:07 +02004770 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 +01004771 return cli_dynerr(appctx, memprintf(&err, "Filter entry #%i: Require a valid integer value to compare against\n", i + 1));
4772 }
4773
4774 if (*args[3+3*i]) {
4775 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 +01004776 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004777
4778 /* OK we're done, all the fields are set */
4779 return 0;
4780}
4781
4782/* returns 0 if wants to be called, 1 if has ended processing */
Aurélien Nephtaliabbf6072018-04-18 13:26:46 +02004783static int cli_parse_table_req(char **args, char *payload, struct appctx *appctx, void *private)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004784{
Willy Tarreau3c69e082022-05-03 11:35:07 +02004785 struct show_table_ctx *ctx = applet_reserve_svcctx(appctx, sizeof(*ctx));
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004786 int i;
4787
4788 for (i = 0; i < STKTABLE_FILTER_LEN; i++)
Willy Tarreau3c69e082022-05-03 11:35:07 +02004789 ctx->data_type[i] = -1;
4790 ctx->target = NULL;
4791 ctx->entry = NULL;
4792 ctx->action = (long)private; // keyword argument, one of STK_CLI_ACT_*
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004793
4794 if (*args[2]) {
Willy Tarreau0f154ed2022-05-03 12:02:36 +02004795 ctx->t = ctx->target = stktable_find_by_name(args[2]);
Willy Tarreau3c69e082022-05-03 11:35:07 +02004796 if (!ctx->target)
Willy Tarreau9d008692019-08-09 11:21:01 +02004797 return cli_err(appctx, "No such table\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004798 }
4799 else {
Willy Tarreau0f154ed2022-05-03 12:02:36 +02004800 ctx->t = stktables_list;
Willy Tarreau3c69e082022-05-03 11:35:07 +02004801 if (ctx->action != STK_CLI_ACT_SHOW)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004802 goto err_args;
4803 return 0;
4804 }
4805
4806 if (strcmp(args[3], "key") == 0)
4807 return table_process_entry_per_key(appctx, args);
4808 else if (strncmp(args[3], "data.", 5) == 0)
4809 return table_prepare_data_request(appctx, args);
4810 else if (*args[3])
4811 goto err_args;
4812
4813 return 0;
4814
4815err_args:
Willy Tarreau3c69e082022-05-03 11:35:07 +02004816 switch (ctx->action) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004817 case STK_CLI_ACT_SHOW:
Willy Tarreau9d008692019-08-09 11:21:01 +02004818 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 +01004819 case STK_CLI_ACT_CLR:
Willy Tarreau9d008692019-08-09 11:21:01 +02004820 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 +01004821 case STK_CLI_ACT_SET:
Willy Tarreau9d008692019-08-09 11:21:01 +02004822 return cli_err(appctx, "Required arguments: <table> key <key> [data.<store_data_type> <value>]*\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004823 default:
Willy Tarreau9d008692019-08-09 11:21:01 +02004824 return cli_err(appctx, "Unknown action\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004825 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004826}
4827
4828/* This function is used to deal with table operations (dump or clear depending
4829 * on the action stored in appctx->private). It returns 0 if the output buffer is
4830 * full and it needs to be called again, otherwise non-zero.
4831 */
4832static int cli_io_handler_table(struct appctx *appctx)
4833{
Willy Tarreau3c69e082022-05-03 11:35:07 +02004834 struct show_table_ctx *ctx = appctx->svcctx;
Willy Tarreauc12b3212022-05-27 11:08:15 +02004835 struct stconn *sc = appctx_sc(appctx);
Willy Tarreau475e4632022-05-27 10:26:46 +02004836 struct stream *s = __sc_strm(sc);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004837 struct ebmb_node *eb;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004838 int skip_entry;
Willy Tarreau3c69e082022-05-03 11:35:07 +02004839 int show = ctx->action == STK_CLI_ACT_SHOW;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004840
4841 /*
Willy Tarreau0f154ed2022-05-03 12:02:36 +02004842 * We have 3 possible states in ctx->state :
Willy Tarreau7849d4c2022-05-03 11:45:02 +02004843 * - STATE_NEXT : the proxy pointer points to the next table to
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004844 * dump, the entry pointer is NULL ;
Willy Tarreau7849d4c2022-05-03 11:45:02 +02004845 * - STATE_DUMP : the proxy pointer points to the current table
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004846 * and the entry pointer points to the next entry to be dumped,
4847 * and the refcount on the next entry is held ;
Willy Tarreau7849d4c2022-05-03 11:45:02 +02004848 * - STATE_DONE : nothing left to dump, the buffer may contain some
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004849 * data though.
4850 */
4851
Willy Tarreau475e4632022-05-27 10:26:46 +02004852 if (unlikely(sc_ic(sc)->flags & (CF_WRITE_ERROR|CF_SHUTW))) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004853 /* in case of abort, remove any refcount we might have set on an entry */
Willy Tarreau7849d4c2022-05-03 11:45:02 +02004854 if (ctx->state == STATE_DUMP) {
Willy Tarreau3c69e082022-05-03 11:35:07 +02004855 stksess_kill_if_expired(ctx->t, ctx->entry, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004856 }
4857 return 1;
4858 }
4859
4860 chunk_reset(&trash);
4861
Willy Tarreau7849d4c2022-05-03 11:45:02 +02004862 while (ctx->state != STATE_DONE) {
4863 switch (ctx->state) {
Willy Tarreau7849d4c2022-05-03 11:45:02 +02004864 case STATE_NEXT:
Willy Tarreau3c69e082022-05-03 11:35:07 +02004865 if (!ctx->t ||
4866 (ctx->target &&
4867 ctx->t != ctx->target)) {
Willy Tarreau7849d4c2022-05-03 11:45:02 +02004868 ctx->state = STATE_DONE;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004869 break;
4870 }
4871
Willy Tarreau3c69e082022-05-03 11:35:07 +02004872 if (ctx->t->size) {
Willy Tarreaud0a06d52022-05-18 15:07:19 +02004873 if (show && !table_dump_head_to_buffer(&trash, appctx, ctx->t, ctx->target))
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004874 return 0;
4875
Willy Tarreau3c69e082022-05-03 11:35:07 +02004876 if (ctx->target &&
William Lallemand07a62f72017-05-24 00:57:40 +02004877 (strm_li(s)->bind_conf->level & ACCESS_LVL_MASK) >= ACCESS_LVL_OPER) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004878 /* dump entries only if table explicitly requested */
Willy Tarreau76642222022-10-11 12:02:50 +02004879 HA_RWLOCK_WRLOCK(STK_TABLE_LOCK, &ctx->t->lock);
Willy Tarreau3c69e082022-05-03 11:35:07 +02004880 eb = ebmb_first(&ctx->t->keys);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004881 if (eb) {
Willy Tarreau3c69e082022-05-03 11:35:07 +02004882 ctx->entry = ebmb_entry(eb, struct stksess, key);
4883 ctx->entry->ref_cnt++;
Willy Tarreau7849d4c2022-05-03 11:45:02 +02004884 ctx->state = STATE_DUMP;
Willy Tarreau76642222022-10-11 12:02:50 +02004885 HA_RWLOCK_WRUNLOCK(STK_TABLE_LOCK, &ctx->t->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004886 break;
4887 }
Willy Tarreau76642222022-10-11 12:02:50 +02004888 HA_RWLOCK_WRUNLOCK(STK_TABLE_LOCK, &ctx->t->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004889 }
4890 }
Willy Tarreau3c69e082022-05-03 11:35:07 +02004891 ctx->t = ctx->t->next;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004892 break;
4893
Willy Tarreau7849d4c2022-05-03 11:45:02 +02004894 case STATE_DUMP:
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004895 skip_entry = 0;
4896
Willy Tarreau3c69e082022-05-03 11:35:07 +02004897 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &ctx->entry->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004898
Willy Tarreau3c69e082022-05-03 11:35:07 +02004899 if (ctx->data_type[0] >= 0) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004900 /* we're filtering on some data contents */
4901 void *ptr;
Willy Tarreau2b64a352020-01-22 17:09:47 +01004902 int dt, i;
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004903 signed char op;
4904 long long data, value;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004905
Emeric Brun819fc6f2017-06-13 19:37:32 +02004906
Willy Tarreau2b64a352020-01-22 17:09:47 +01004907 for (i = 0; i < STKTABLE_FILTER_LEN; i++) {
Willy Tarreau3c69e082022-05-03 11:35:07 +02004908 if (ctx->data_type[i] == -1)
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004909 break;
Willy Tarreau3c69e082022-05-03 11:35:07 +02004910 dt = ctx->data_type[i];
4911 ptr = stktable_data_ptr(ctx->t,
4912 ctx->entry,
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004913 dt);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004914
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004915 data = 0;
4916 switch (stktable_data_types[dt].std_type) {
4917 case STD_T_SINT:
4918 data = stktable_data_cast(ptr, std_t_sint);
4919 break;
4920 case STD_T_UINT:
4921 data = stktable_data_cast(ptr, std_t_uint);
4922 break;
4923 case STD_T_ULL:
4924 data = stktable_data_cast(ptr, std_t_ull);
4925 break;
4926 case STD_T_FRQP:
4927 data = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Willy Tarreau3c69e082022-05-03 11:35:07 +02004928 ctx->t->data_arg[dt].u);
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004929 break;
4930 }
4931
Willy Tarreau3c69e082022-05-03 11:35:07 +02004932 op = ctx->data_op[i];
4933 value = ctx->value[i];
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004934
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004935 /* skip the entry if the data does not match the test and the value */
4936 if ((data < value &&
4937 (op == STD_OP_EQ || op == STD_OP_GT || op == STD_OP_GE)) ||
4938 (data == value &&
4939 (op == STD_OP_NE || op == STD_OP_GT || op == STD_OP_LT)) ||
4940 (data > value &&
4941 (op == STD_OP_EQ || op == STD_OP_LT || op == STD_OP_LE))) {
4942 skip_entry = 1;
4943 break;
4944 }
4945 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004946 }
4947
4948 if (show && !skip_entry &&
Willy Tarreaud0a06d52022-05-18 15:07:19 +02004949 !table_dump_entry_to_buffer(&trash, appctx, ctx->t, ctx->entry)) {
Willy Tarreau3c69e082022-05-03 11:35:07 +02004950 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &ctx->entry->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004951 return 0;
4952 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004953
Willy Tarreau3c69e082022-05-03 11:35:07 +02004954 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &ctx->entry->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004955
Willy Tarreau76642222022-10-11 12:02:50 +02004956 HA_RWLOCK_WRLOCK(STK_TABLE_LOCK, &ctx->t->lock);
Willy Tarreau3c69e082022-05-03 11:35:07 +02004957 ctx->entry->ref_cnt--;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004958
Willy Tarreau3c69e082022-05-03 11:35:07 +02004959 eb = ebmb_next(&ctx->entry->key);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004960 if (eb) {
Willy Tarreau3c69e082022-05-03 11:35:07 +02004961 struct stksess *old = ctx->entry;
4962 ctx->entry = ebmb_entry(eb, struct stksess, key);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004963 if (show)
Willy Tarreau3c69e082022-05-03 11:35:07 +02004964 __stksess_kill_if_expired(ctx->t, old);
4965 else if (!skip_entry && !ctx->entry->ref_cnt)
4966 __stksess_kill(ctx->t, old);
4967 ctx->entry->ref_cnt++;
Willy Tarreau76642222022-10-11 12:02:50 +02004968 HA_RWLOCK_WRUNLOCK(STK_TABLE_LOCK, &ctx->t->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004969 break;
4970 }
4971
4972
4973 if (show)
Willy Tarreau3c69e082022-05-03 11:35:07 +02004974 __stksess_kill_if_expired(ctx->t, ctx->entry);
4975 else if (!skip_entry && !ctx->entry->ref_cnt)
4976 __stksess_kill(ctx->t, ctx->entry);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004977
Willy Tarreau76642222022-10-11 12:02:50 +02004978 HA_RWLOCK_WRUNLOCK(STK_TABLE_LOCK, &ctx->t->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004979
Willy Tarreau3c69e082022-05-03 11:35:07 +02004980 ctx->t = ctx->t->next;
Willy Tarreau7849d4c2022-05-03 11:45:02 +02004981 ctx->state = STATE_NEXT;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004982 break;
4983
Willy Tarreau7849d4c2022-05-03 11:45:02 +02004984 default:
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004985 break;
4986 }
4987 }
4988 return 1;
4989}
4990
4991static void cli_release_show_table(struct appctx *appctx)
4992{
Willy Tarreau3c69e082022-05-03 11:35:07 +02004993 struct show_table_ctx *ctx = appctx->svcctx;
4994
Willy Tarreau7849d4c2022-05-03 11:45:02 +02004995 if (ctx->state == STATE_DUMP) {
Willy Tarreau3c69e082022-05-03 11:35:07 +02004996 stksess_kill_if_expired(ctx->t, ctx->entry, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004997 }
4998}
4999
Willy Tarreau478331d2020-08-28 11:31:31 +02005000static void stkt_late_init(void)
5001{
5002 struct sample_fetch *f;
5003
5004 f = find_sample_fetch("src", strlen("src"));
5005 if (f)
5006 smp_fetch_src = f->process;
5007}
5008
5009INITCALL0(STG_INIT, stkt_late_init);
5010
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01005011/* register cli keywords */
5012static struct cli_kw_list cli_kws = {{ },{
Willy Tarreaub205bfd2021-05-07 11:38:37 +02005013 { { "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 },
5014 { { "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 },
5015 { { "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 +01005016 {{},}
5017}};
5018
Willy Tarreau0108d902018-11-25 19:14:37 +01005019INITCALL1(STG_REGISTER, cli_register_kw, &cli_kws);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01005020
Thierry FOURNIER236657b2015-08-19 08:25:14 +02005021static struct action_kw_list tcp_conn_kws = { { }, {
Emeric Brun4d7ada82021-06-30 19:04:16 +02005022 { "sc-inc-gpc", parse_inc_gpc, KWF_MATCH_PREFIX },
5023 { "sc-inc-gpc0", parse_inc_gpc, KWF_MATCH_PREFIX },
5024 { "sc-inc-gpc1", parse_inc_gpc, KWF_MATCH_PREFIX },
Emeric Brun877b0b52021-06-30 18:57:49 +02005025 { "sc-set-gpt", parse_set_gpt, KWF_MATCH_PREFIX },
5026 { "sc-set-gpt0", parse_set_gpt, KWF_MATCH_PREFIX },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02005027 { /* END */ }
5028}};
5029
Willy Tarreau0108d902018-11-25 19:14:37 +01005030INITCALL1(STG_REGISTER, tcp_req_conn_keywords_register, &tcp_conn_kws);
5031
Willy Tarreau620408f2016-10-21 16:37:51 +02005032static struct action_kw_list tcp_sess_kws = { { }, {
Emeric Brun4d7ada82021-06-30 19:04:16 +02005033 { "sc-inc-gpc", parse_inc_gpc, KWF_MATCH_PREFIX },
5034 { "sc-inc-gpc0", parse_inc_gpc, KWF_MATCH_PREFIX },
5035 { "sc-inc-gpc1", parse_inc_gpc, KWF_MATCH_PREFIX },
Emeric Brun877b0b52021-06-30 18:57:49 +02005036 { "sc-set-gpt", parse_set_gpt, KWF_MATCH_PREFIX },
5037 { "sc-set-gpt0", parse_set_gpt, KWF_MATCH_PREFIX },
Willy Tarreau620408f2016-10-21 16:37:51 +02005038 { /* END */ }
5039}};
5040
Willy Tarreau0108d902018-11-25 19:14:37 +01005041INITCALL1(STG_REGISTER, tcp_req_sess_keywords_register, &tcp_sess_kws);
5042
Thierry FOURNIER236657b2015-08-19 08:25:14 +02005043static struct action_kw_list tcp_req_kws = { { }, {
Emeric Brun4d7ada82021-06-30 19:04:16 +02005044 { "sc-inc-gpc", parse_inc_gpc, KWF_MATCH_PREFIX },
5045 { "sc-inc-gpc0", parse_inc_gpc, KWF_MATCH_PREFIX },
5046 { "sc-inc-gpc1", parse_inc_gpc, KWF_MATCH_PREFIX },
Emeric Brun877b0b52021-06-30 18:57:49 +02005047 { "sc-set-gpt", parse_set_gpt, KWF_MATCH_PREFIX },
5048 { "sc-set-gpt0", parse_set_gpt, KWF_MATCH_PREFIX },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02005049 { /* END */ }
5050}};
5051
Willy Tarreau0108d902018-11-25 19:14:37 +01005052INITCALL1(STG_REGISTER, tcp_req_cont_keywords_register, &tcp_req_kws);
5053
Thierry FOURNIER236657b2015-08-19 08:25:14 +02005054static struct action_kw_list tcp_res_kws = { { }, {
Emeric Brun4d7ada82021-06-30 19:04:16 +02005055 { "sc-inc-gpc", parse_inc_gpc, KWF_MATCH_PREFIX },
5056 { "sc-inc-gpc0", parse_inc_gpc, KWF_MATCH_PREFIX },
5057 { "sc-inc-gpc1", parse_inc_gpc, KWF_MATCH_PREFIX },
Emeric Brun877b0b52021-06-30 18:57:49 +02005058 { "sc-set-gpt", parse_set_gpt, KWF_MATCH_PREFIX },
5059 { "sc-set-gpt0", parse_set_gpt, KWF_MATCH_PREFIX },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02005060 { /* END */ }
5061}};
5062
Willy Tarreau0108d902018-11-25 19:14:37 +01005063INITCALL1(STG_REGISTER, tcp_res_cont_keywords_register, &tcp_res_kws);
5064
Thierry FOURNIER236657b2015-08-19 08:25:14 +02005065static struct action_kw_list http_req_kws = { { }, {
Emeric Brun4d7ada82021-06-30 19:04:16 +02005066 { "sc-inc-gpc", parse_inc_gpc, KWF_MATCH_PREFIX },
5067 { "sc-inc-gpc0", parse_inc_gpc, KWF_MATCH_PREFIX },
5068 { "sc-inc-gpc1", parse_inc_gpc, KWF_MATCH_PREFIX },
Emeric Brun877b0b52021-06-30 18:57:49 +02005069 { "sc-set-gpt", parse_set_gpt, KWF_MATCH_PREFIX },
5070 { "sc-set-gpt0", parse_set_gpt, KWF_MATCH_PREFIX },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02005071 { /* END */ }
5072}};
5073
Willy Tarreau0108d902018-11-25 19:14:37 +01005074INITCALL1(STG_REGISTER, http_req_keywords_register, &http_req_kws);
5075
Thierry FOURNIER236657b2015-08-19 08:25:14 +02005076static struct action_kw_list http_res_kws = { { }, {
Emeric Brun4d7ada82021-06-30 19:04:16 +02005077 { "sc-inc-gpc", parse_inc_gpc, KWF_MATCH_PREFIX },
5078 { "sc-inc-gpc0", parse_inc_gpc, KWF_MATCH_PREFIX },
5079 { "sc-inc-gpc1", parse_inc_gpc, KWF_MATCH_PREFIX },
Emeric Brun877b0b52021-06-30 18:57:49 +02005080 { "sc-set-gpt", parse_set_gpt, KWF_MATCH_PREFIX },
5081 { "sc-set-gpt0", parse_set_gpt, KWF_MATCH_PREFIX },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02005082 { /* END */ }
5083}};
5084
Willy Tarreau0108d902018-11-25 19:14:37 +01005085INITCALL1(STG_REGISTER, http_res_keywords_register, &http_res_kws);
5086
Willy Tarreau7d562212016-11-25 16:10:05 +01005087/* Note: must not be declared <const> as its list will be overwritten.
5088 * Please take care of keeping this list alphabetically sorted.
5089 */
5090static struct sample_fetch_kw_list smp_fetch_keywords = {ILH, {
5091 { "sc_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5092 { "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 +02005093 { "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 +01005094 { "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 +01005095 { "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 +01005096 { "sc_conn_cnt", smp_fetch_sc_conn_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5097 { "sc_conn_cur", smp_fetch_sc_conn_cur, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5098 { "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 +02005099 { "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 +01005100 { "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 +02005101 { "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 +01005102 { "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 +01005103 { "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 +02005104 { "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 +01005105 { "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 +01005106 { "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 +01005107 { "sc_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5108 { "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 +01005109 { "sc_http_fail_cnt", smp_fetch_sc_http_fail_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5110 { "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 +01005111 { "sc_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5112 { "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 +02005113 { "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 +01005114 { "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 +01005115 { "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 +01005116 { "sc_kbytes_in", smp_fetch_sc_kbytes_in, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5117 { "sc_kbytes_out", smp_fetch_sc_kbytes_out, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5118 { "sc_sess_cnt", smp_fetch_sc_sess_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5119 { "sc_sess_rate", smp_fetch_sc_sess_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5120 { "sc_tracked", smp_fetch_sc_tracked, ARG2(1,SINT,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
5121 { "sc_trackers", smp_fetch_sc_trackers, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5122 { "sc0_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5123 { "sc0_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5124 { "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 +01005125 { "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 +01005126 { "sc0_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5127 { "sc0_conn_cur", smp_fetch_sc_conn_cur, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5128 { "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 +01005129 { "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 +01005130 { "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 +01005131 { "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 +01005132 { "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 +01005133 { "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 +01005134 { "sc0_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5135 { "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 +01005136 { "sc0_http_fail_cnt", smp_fetch_sc_http_fail_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5137 { "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 +01005138 { "sc0_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5139 { "sc0_http_req_rate", smp_fetch_sc_http_req_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5140 { "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 +01005141 { "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 +01005142 { "sc0_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5143 { "sc0_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5144 { "sc0_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5145 { "sc0_sess_rate", smp_fetch_sc_sess_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5146 { "sc0_tracked", smp_fetch_sc_tracked, ARG1(0,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
5147 { "sc0_trackers", smp_fetch_sc_trackers, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5148 { "sc1_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5149 { "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 +02005150 { "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 +01005151 { "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 +01005152 { "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 +01005153 { "sc1_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5154 { "sc1_conn_cur", smp_fetch_sc_conn_cur, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5155 { "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 +01005156 { "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 +01005157 { "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 +01005158 { "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 +01005159 { "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 +01005160 { "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 +01005161 { "sc1_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5162 { "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 +01005163 { "sc1_http_fail_cnt", smp_fetch_sc_http_fail_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5164 { "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 +01005165 { "sc1_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5166 { "sc1_http_req_rate", smp_fetch_sc_http_req_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5167 { "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 +01005168 { "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 +01005169 { "sc1_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5170 { "sc1_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5171 { "sc1_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5172 { "sc1_sess_rate", smp_fetch_sc_sess_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5173 { "sc1_tracked", smp_fetch_sc_tracked, ARG1(0,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
5174 { "sc1_trackers", smp_fetch_sc_trackers, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5175 { "sc2_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5176 { "sc2_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5177 { "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 +01005178 { "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 +01005179 { "sc2_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5180 { "sc2_conn_cur", smp_fetch_sc_conn_cur, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5181 { "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 +01005182 { "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 +01005183 { "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 +01005184 { "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 +01005185 { "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 +01005186 { "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 +01005187 { "sc2_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5188 { "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 +01005189 { "sc2_http_fail_cnt", smp_fetch_sc_http_fail_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5190 { "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 +01005191 { "sc2_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5192 { "sc2_http_req_rate", smp_fetch_sc_http_req_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5193 { "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 +01005194 { "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 +01005195 { "sc2_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5196 { "sc2_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5197 { "sc2_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5198 { "sc2_sess_rate", smp_fetch_sc_sess_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5199 { "sc2_tracked", smp_fetch_sc_tracked, ARG1(0,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
5200 { "sc2_trackers", smp_fetch_sc_trackers, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5201 { "src_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5202 { "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 +02005203 { "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 +01005204 { "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 +01005205 { "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 +01005206 { "src_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5207 { "src_conn_cur", smp_fetch_sc_conn_cur, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5208 { "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 +02005209 { "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 +01005210 { "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 +02005211 { "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 +01005212 { "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 +01005213 { "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 +02005214 { "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 +01005215 { "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 +01005216 { "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 +01005217 { "src_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5218 { "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 +01005219 { "src_http_fail_cnt", smp_fetch_sc_http_fail_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5220 { "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 +01005221 { "src_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5222 { "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 +02005223 { "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 +01005224 { "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 +01005225 { "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 +01005226 { "src_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5227 { "src_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5228 { "src_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5229 { "src_sess_rate", smp_fetch_sc_sess_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5230 { "src_updt_conn_cnt", smp_fetch_src_updt_conn_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5231 { "table_avl", smp_fetch_table_avl, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5232 { "table_cnt", smp_fetch_table_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5233 { /* END */ },
5234}};
5235
Willy Tarreau0108d902018-11-25 19:14:37 +01005236INITCALL1(STG_REGISTER, sample_register_fetches, &smp_fetch_keywords);
Willy Tarreau7d562212016-11-25 16:10:05 +01005237
Willy Tarreaud9f316a2014-07-10 14:03:38 +02005238/* Note: must not be declared <const> as its list will be overwritten */
5239static struct sample_conv_kw_list sample_conv_kws = {ILH, {
Willy Tarreau2d17db52016-05-25 17:16:38 +02005240 { "in_table", sample_conv_in_table, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_BOOL },
5241 { "table_bytes_in_rate", sample_conv_table_bytes_in_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5242 { "table_bytes_out_rate", sample_conv_table_bytes_out_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5243 { "table_conn_cnt", sample_conv_table_conn_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5244 { "table_conn_cur", sample_conv_table_conn_cur, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5245 { "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 +02005246 { "table_expire", sample_conv_table_expire, ARG2(1,TAB,SINT), NULL, SMP_T_ANY, SMP_T_SINT },
Emeric Brun877b0b52021-06-30 18:57:49 +02005247 { "table_gpt", sample_conv_table_gpt, ARG2(2,SINT,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
Willy Tarreau2d17db52016-05-25 17:16:38 +02005248 { "table_gpt0", sample_conv_table_gpt0, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
Emeric Brun4d7ada82021-06-30 19:04:16 +02005249 { "table_gpc", sample_conv_table_gpc, ARG2(2,SINT,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
Willy Tarreau2d17db52016-05-25 17:16:38 +02005250 { "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 +01005251 { "table_gpc1", sample_conv_table_gpc1, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
Emeric Brun4d7ada82021-06-30 19:04:16 +02005252 { "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 +02005253 { "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 +01005254 { "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 +02005255 { "table_http_err_cnt", sample_conv_table_http_err_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5256 { "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 +01005257 { "table_http_fail_cnt", sample_conv_table_http_fail_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5258 { "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 +02005259 { "table_http_req_cnt", sample_conv_table_http_req_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5260 { "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 +02005261 { "table_idle", sample_conv_table_idle, ARG2(1,TAB,SINT), NULL, SMP_T_ANY, SMP_T_SINT },
Willy Tarreau2d17db52016-05-25 17:16:38 +02005262 { "table_kbytes_in", sample_conv_table_kbytes_in, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5263 { "table_kbytes_out", sample_conv_table_kbytes_out, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5264 { "table_server_id", sample_conv_table_server_id, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5265 { "table_sess_cnt", sample_conv_table_sess_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5266 { "table_sess_rate", sample_conv_table_sess_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5267 { "table_trackers", sample_conv_table_trackers, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
Willy Tarreaud9f316a2014-07-10 14:03:38 +02005268 { /* END */ },
5269}};
5270
Willy Tarreau0108d902018-11-25 19:14:37 +01005271INITCALL1(STG_REGISTER, sample_register_convs, &sample_conv_kws);