blob: 61e63b8ae68a5405f0a14f79b3267cf97be930f3 [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);
553 do {
Willy Tarreau63427142022-11-14 17:33:02 +0100554 new_exp = tick_first(expire, old_exp);
Willy Tarreaudbae89e2022-10-12 10:00:50 +0000555 } while (new_exp != old_exp &&
556 !HA_ATOMIC_CAS(&t->exp_task->expire, &old_exp, new_exp) &&
557 __ha_cpu_relax());
558
Willy Tarreaueb23e3e2022-10-12 09:56:08 +0000559 task_queue(t->exp_task);
560}
561
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200562/* Returns a valid or initialized stksess for the specified stktable_key in the
563 * specified table, or NULL if the key was NULL, or if no entry was found nor
Willy Tarreau47f22972022-10-11 15:22:42 +0200564 * could be created. The entry's expiration is updated. This function locks the
565 * table, and the refcount of the entry is increased.
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200566 */
Willy Tarreau47f22972022-10-11 15:22:42 +0200567struct stksess *stktable_get_entry(struct stktable *table, struct stktable_key *key)
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200568{
Willy Tarreau175aa062022-10-11 15:13:46 +0200569 struct stksess *ts, *ts2;
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200570
571 if (!key)
572 return NULL;
573
Willy Tarreau47f22972022-10-11 15:22:42 +0200574 ts = stktable_lookup_key(table, key);
575 if (ts)
576 return ts;
Emeric Brun819fc6f2017-06-13 19:37:32 +0200577
Willy Tarreau996f1a52022-10-11 16:19:35 +0200578 /* No such entry exists, let's try to create a new one. this doesn't
579 * require locking yet.
580 */
581
582 ts = stksess_new(table, key);
583 if (!ts)
584 return NULL;
585
586 /* Now we're certain to have a ts. We need to store it. For this we'll
Willy Tarreau47f22972022-10-11 15:22:42 +0200587 * need an exclusive access. We don't need an atomic upgrade, this is
588 * rare and an unlock+lock sequence will do the job fine. Given that
589 * this will not be atomic, the missing entry might appear in the mean
590 * tome so we have to be careful that the one we try to insert is the
591 * one we find.
592 */
Willy Tarreau47f22972022-10-11 15:22:42 +0200593
Willy Tarreau996f1a52022-10-11 16:19:35 +0200594 HA_RWLOCK_WRLOCK(STK_TABLE_LOCK, &table->lock);
Willy Tarreau47f22972022-10-11 15:22:42 +0200595
596 ts2 = __stktable_store(table, ts);
597 if (unlikely(ts2 != ts)) {
598 /* another entry was added in the mean time, let's
599 * switch to it.
600 */
601 __stksess_free(table, ts);
602 ts = ts2;
603 }
604
605 HA_ATOMIC_INC(&ts->ref_cnt);
Willy Tarreau76642222022-10-11 12:02:50 +0200606 HA_RWLOCK_WRUNLOCK(STK_TABLE_LOCK, &table->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200607
Willy Tarreaucbdb5282022-10-12 10:04:01 +0000608 stktable_requeue_exp(table, ts);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200609 return ts;
610}
611
612/* Lookup for an entry with the same key and store the submitted
Willy Tarreaue6288522022-10-12 09:13:14 +0000613 * stksess if not found. This function locks the table either shared or
614 * exclusively, and the refcount of the entry is increased.
Emeric Brun819fc6f2017-06-13 19:37:32 +0200615 */
Willy Tarreaue6288522022-10-12 09:13:14 +0000616struct stksess *stktable_set_entry(struct stktable *table, struct stksess *nts)
Emeric Brun819fc6f2017-06-13 19:37:32 +0200617{
618 struct stksess *ts;
619
Willy Tarreaue6288522022-10-12 09:13:14 +0000620 HA_RWLOCK_RDLOCK(STK_TABLE_LOCK, &table->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200621 ts = __stktable_lookup(table, nts);
Willy Tarreaue6288522022-10-12 09:13:14 +0000622 if (ts) {
623 HA_ATOMIC_INC(&ts->ref_cnt);
624 HA_RWLOCK_RDUNLOCK(STK_TABLE_LOCK, &table->lock);
625 return ts;
Emeric Brun819fc6f2017-06-13 19:37:32 +0200626 }
Willy Tarreaue6288522022-10-12 09:13:14 +0000627 ts = nts;
Emeric Brun819fc6f2017-06-13 19:37:32 +0200628
Willy Tarreaue6288522022-10-12 09:13:14 +0000629 /* let's increment it before switching to exclusive */
630 HA_ATOMIC_INC(&ts->ref_cnt);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200631
Willy Tarreaue6288522022-10-12 09:13:14 +0000632 if (HA_RWLOCK_TRYRDTOSK(STK_TABLE_LOCK, &table->lock) != 0) {
633 /* upgrade to seek lock failed, let's drop and take */
634 HA_RWLOCK_RDUNLOCK(STK_TABLE_LOCK, &table->lock);
635 HA_RWLOCK_WRLOCK(STK_TABLE_LOCK, &table->lock);
636 }
637 else
638 HA_RWLOCK_SKTOWR(STK_TABLE_LOCK, &table->lock);
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200639
Willy Tarreaue6288522022-10-12 09:13:14 +0000640 /* now we're write-locked */
641
642 __stktable_store(table, ts);
643 HA_RWLOCK_WRUNLOCK(STK_TABLE_LOCK, &table->lock);
Willy Tarreaucbdb5282022-10-12 10:04:01 +0000644
645 stktable_requeue_exp(table, ts);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200646 return ts;
647}
Willy Tarreaue6288522022-10-12 09:13:14 +0000648
Emeric Brun3bd697e2010-01-04 15:23:48 +0100649/*
Willy Tarreauaea940e2010-06-06 11:56:36 +0200650 * Trash expired sticky sessions from table <t>. The next expiration date is
651 * returned.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100652 */
653static int stktable_trash_expired(struct stktable *t)
654{
655 struct stksess *ts;
656 struct eb32_node *eb;
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200657 int looped = 0;
Willy Tarreau63427142022-11-14 17:33:02 +0100658 int exp_next;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100659
Willy Tarreau76642222022-10-11 12:02:50 +0200660 HA_RWLOCK_WRLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100661 eb = eb32_lookup_ge(&t->exps, now_ms - TIMER_LOOK_BACK);
662
663 while (1) {
664 if (unlikely(!eb)) {
665 /* we might have reached the end of the tree, typically because
666 * <now_ms> is in the first half and we're first scanning the last
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200667 * half. Let's loop back to the beginning of the tree now if we
668 * have not yet visited it.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100669 */
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200670 if (looped)
671 break;
672 looped = 1;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100673 eb = eb32_first(&t->exps);
674 if (likely(!eb))
675 break;
676 }
677
678 if (likely(tick_is_lt(now_ms, eb->key))) {
679 /* timer not expired yet, revisit it later */
Willy Tarreau63427142022-11-14 17:33:02 +0100680 exp_next = eb->key;
Willy Tarreau4d5f13c2017-11-05 11:04:47 +0100681 goto out_unlock;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100682 }
683
684 /* timer looks expired, detach it from the queue */
Willy Tarreau86257dc2010-06-06 12:57:10 +0200685 ts = eb32_entry(eb, struct stksess, exp);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100686 eb = eb32_next(eb);
687
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200688 /* don't delete an entry which is currently referenced */
689 if (ts->ref_cnt)
690 continue;
691
Willy Tarreau86257dc2010-06-06 12:57:10 +0200692 eb32_delete(&ts->exp);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100693
694 if (!tick_is_expired(ts->expire, now_ms)) {
695 if (!tick_isset(ts->expire))
696 continue;
697
Willy Tarreau86257dc2010-06-06 12:57:10 +0200698 ts->exp.key = ts->expire;
699 eb32_insert(&t->exps, &ts->exp);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100700
Willy Tarreau86257dc2010-06-06 12:57:10 +0200701 if (!eb || eb->key > ts->exp.key)
702 eb = &ts->exp;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100703 continue;
704 }
705
706 /* session expired, trash it */
Willy Tarreau86257dc2010-06-06 12:57:10 +0200707 ebmb_delete(&ts->key);
Emeric Brun85e77c72010-09-23 18:16:52 +0200708 eb32_delete(&ts->upd);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200709 __stksess_free(t, ts);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100710 }
711
712 /* We have found no task to expire in any tree */
Willy Tarreau63427142022-11-14 17:33:02 +0100713 exp_next = TICK_ETERNITY;
Willy Tarreau4d5f13c2017-11-05 11:04:47 +0100714out_unlock:
Willy Tarreau76642222022-10-11 12:02:50 +0200715 HA_RWLOCK_WRUNLOCK(STK_TABLE_LOCK, &t->lock);
Willy Tarreau63427142022-11-14 17:33:02 +0100716 return exp_next;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100717}
718
719/*
Willy Tarreauaea940e2010-06-06 11:56:36 +0200720 * Task processing function to trash expired sticky sessions. A pointer to the
721 * task itself is returned since it never dies.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100722 */
Willy Tarreau144f84a2021-03-02 16:09:26 +0100723struct task *process_table_expire(struct task *task, void *context, unsigned int state)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100724{
Olivier Houchard9f6af332018-05-25 14:04:04 +0200725 struct stktable *t = context;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100726
727 task->expire = stktable_trash_expired(t);
728 return task;
729}
730
Willy Tarreauaea940e2010-06-06 11:56:36 +0200731/* Perform minimal stick table intializations, report 0 in case of error, 1 if OK. */
Emeric Brun3bd697e2010-01-04 15:23:48 +0100732int stktable_init(struct stktable *t)
733{
Remi Tricot-Le Breton208ff012021-05-12 17:39:04 +0200734 int peers_retval = 0;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100735 if (t->size) {
Emeric Brun819fc6f2017-06-13 19:37:32 +0200736 t->keys = EB_ROOT_UNIQUE;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100737 memset(&t->exps, 0, sizeof(t->exps));
Emeric Brun1c6235d2015-12-16 15:28:12 +0100738 t->updates = EB_ROOT_UNIQUE;
Amaury Denoyelle3e064882022-10-12 16:47:59 +0200739 HA_RWLOCK_INIT(&t->lock);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100740
Olivier Houchard52dabbc2018-11-14 17:54:36 +0100741 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 +0100742
Emeric Brun3bd697e2010-01-04 15:23:48 +0100743 if ( t->expire ) {
Willy Tarreaubeeabf52021-10-01 18:23:30 +0200744 t->exp_task = task_new_anywhere();
Willy Tarreau848522f2018-10-15 11:12:15 +0200745 if (!t->exp_task)
746 return 0;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100747 t->exp_task->process = process_table_expire;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100748 t->exp_task->context = (void *)t;
749 }
Christopher Fauletdfd10ab2021-10-06 14:24:19 +0200750 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 +0200751 peers_retval = peers_register_table(t->peers.p, t);
Emeric Brun32da3c42010-09-23 18:39:19 +0200752 }
753
Remi Tricot-Le Breton208ff012021-05-12 17:39:04 +0200754 return (t->pool != NULL) && !peers_retval;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100755 }
756 return 1;
757}
758
759/*
760 * Configuration keywords of known table types
761 */
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200762struct stktable_type stktable_types[SMP_TYPES] = {
763 [SMP_T_SINT] = { "integer", 0, 4 },
764 [SMP_T_IPV4] = { "ip", 0, 4 },
765 [SMP_T_IPV6] = { "ipv6", 0, 16 },
766 [SMP_T_STR] = { "string", STK_F_CUSTOM_KEYSIZE, 32 },
767 [SMP_T_BIN] = { "binary", STK_F_CUSTOM_KEYSIZE, 32 }
768};
Emeric Brun3bd697e2010-01-04 15:23:48 +0100769
770/*
771 * Parse table type configuration.
772 * Returns 0 on successful parsing, else 1.
773 * <myidx> is set at next configuration <args> index.
774 */
775int stktable_parse_type(char **args, int *myidx, unsigned long *type, size_t *key_size)
776{
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200777 for (*type = 0; *type < SMP_TYPES; (*type)++) {
778 if (!stktable_types[*type].kw)
779 continue;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100780 if (strcmp(args[*myidx], stktable_types[*type].kw) != 0)
781 continue;
782
783 *key_size = stktable_types[*type].default_size;
784 (*myidx)++;
785
Willy Tarreauaea940e2010-06-06 11:56:36 +0200786 if (stktable_types[*type].flags & STK_F_CUSTOM_KEYSIZE) {
Emeric Brun3bd697e2010-01-04 15:23:48 +0100787 if (strcmp("len", args[*myidx]) == 0) {
788 (*myidx)++;
789 *key_size = atol(args[*myidx]);
Emeric Brun485479d2010-09-23 18:02:19 +0200790 if (!*key_size)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100791 break;
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200792 if (*type == SMP_T_STR) {
Emeric Brun485479d2010-09-23 18:02:19 +0200793 /* null terminated string needs +1 for '\0'. */
794 (*key_size)++;
795 }
Emeric Brun3bd697e2010-01-04 15:23:48 +0100796 (*myidx)++;
797 }
798 }
799 return 0;
800 }
801 return 1;
802}
803
Emeric Brunc64a2a32021-06-30 18:01:02 +0200804/* reserve some space for data type <type>, there is 2 optionnals
805 * argument at <sa> and <sa2> to configure this data type and
806 * they can be NULL if unused for a given type.
807 * Returns PE_NONE (0) if OK or an error code among :
Willy Tarreau3b63ca22021-05-08 14:10:42 +0200808 * - PE_ENUM_OOR if <type> does not exist
809 * - PE_EXIST if <type> is already registered
Emeric Brunc64a2a32021-06-30 18:01:02 +0200810 * - PE_ARG_NOT_USE if <sa>/<sa2> was provided but not expected
811 * - PE_ARG_MISSING if <sa>/<sa2> was expected but not provided
812 * - PE_ARG_VALUE_OOR if type is an array and <sa> it out of array size range.
Willy Tarreau3b63ca22021-05-08 14:10:42 +0200813 */
Emeric Brunc64a2a32021-06-30 18:01:02 +0200814int stktable_alloc_data_type(struct stktable *t, int type, const char *sa, const char *sa2)
815
Willy Tarreau3b63ca22021-05-08 14:10:42 +0200816{
817 if (type >= STKTABLE_DATA_TYPES)
818 return PE_ENUM_OOR;
819
820 if (t->data_ofs[type])
821 /* already allocated */
822 return PE_EXIST;
823
Emeric Brunc64a2a32021-06-30 18:01:02 +0200824 t->data_nbelem[type] = 1;
825 if (stktable_data_types[type].is_array) {
826 /* arrays take their element count on first argument */
827 if (!sa)
828 return PE_ARG_MISSING;
829 t->data_nbelem[type] = atoi(sa);
830 if (!t->data_nbelem[type] || (t->data_nbelem[type] > STKTABLE_MAX_DT_ARRAY_SIZE))
831 return PE_ARG_VALUE_OOR;
832 sa = sa2;
833 }
834
Willy Tarreau3b63ca22021-05-08 14:10:42 +0200835 switch (stktable_data_types[type].arg_type) {
836 case ARG_T_NONE:
837 if (sa)
838 return PE_ARG_NOT_USED;
839 break;
840 case ARG_T_INT:
841 if (!sa)
842 return PE_ARG_MISSING;
843 t->data_arg[type].i = atoi(sa);
844 break;
845 case ARG_T_DELAY:
846 if (!sa)
847 return PE_ARG_MISSING;
848 sa = parse_time_err(sa, &t->data_arg[type].u, TIME_UNIT_MS);
849 if (sa)
850 return PE_ARG_INVC; /* invalid char */
851 break;
852 }
853
Emeric Brunc64a2a32021-06-30 18:01:02 +0200854 t->data_size += t->data_nbelem[type] * stktable_type_size(stktable_data_types[type].std_type);
Willy Tarreau3b63ca22021-05-08 14:10:42 +0200855 t->data_ofs[type] = -t->data_size;
856 return PE_NONE;
857}
858
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100859/*
Frédéric Lécaillec02766a2019-03-20 15:06:55 +0100860 * Parse a line with <linenum> as number in <file> configuration file to configure
861 * the stick-table with <t> as address and <id> as ID.
862 * <peers> provides the "peers" section pointer only if this function is called
863 * from a "peers" section.
864 * <nid> is the stick-table name which is sent over the network. It must be equal
865 * to <id> if this stick-table is parsed from a proxy section, and prefixed by <peers>
866 * "peers" section name followed by a '/' character if parsed from a "peers" section.
Ilya Shipitsind4259502020-04-08 01:07:56 +0500867 * This is the responsibility of the caller to check this.
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100868 * Return an error status with ERR_* flags set if required, 0 if no error was encountered.
869 */
870int parse_stick_table(const char *file, int linenum, char **args,
Frédéric Lécaillec02766a2019-03-20 15:06:55 +0100871 struct stktable *t, char *id, char *nid, struct peers *peers)
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100872{
873 int err_code = 0;
874 int idx = 1;
875 unsigned int val;
876
877 if (!id || !*id) {
878 ha_alert("parsing [%s:%d] : %s: ID not provided.\n", file, linenum, args[0]);
879 err_code |= ERR_ALERT | ERR_ABORT;
880 goto out;
881 }
882
883 /* Store the "peers" section if this function is called from a "peers" section. */
884 if (peers) {
885 t->peers.p = peers;
886 idx++;
887 }
888
889 t->id = id;
Frédéric Lécaille36d15652022-10-17 14:58:19 +0200890 t->idlen = strlen(id);
Frédéric Lécaillec02766a2019-03-20 15:06:55 +0100891 t->nid = nid;
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100892 t->type = (unsigned int)-1;
893 t->conf.file = file;
894 t->conf.line = linenum;
895
896 while (*args[idx]) {
897 const char *err;
898
899 if (strcmp(args[idx], "size") == 0) {
900 idx++;
901 if (!*(args[idx])) {
902 ha_alert("parsing [%s:%d] : %s: missing argument after '%s'.\n",
903 file, linenum, args[0], args[idx-1]);
904 err_code |= ERR_ALERT | ERR_FATAL;
905 goto out;
906 }
907 if ((err = parse_size_err(args[idx], &t->size))) {
908 ha_alert("parsing [%s:%d] : %s: unexpected character '%c' in argument of '%s'.\n",
909 file, linenum, args[0], *err, args[idx-1]);
910 err_code |= ERR_ALERT | ERR_FATAL;
911 goto out;
912 }
913 idx++;
914 }
915 /* This argument does not exit in "peers" section. */
916 else if (!peers && strcmp(args[idx], "peers") == 0) {
917 idx++;
918 if (!*(args[idx])) {
919 ha_alert("parsing [%s:%d] : %s: missing argument after '%s'.\n",
920 file, linenum, args[0], args[idx-1]);
921 err_code |= ERR_ALERT | ERR_FATAL;
922 goto out;
923 }
924 t->peers.name = strdup(args[idx++]);
925 }
926 else if (strcmp(args[idx], "expire") == 0) {
927 idx++;
928 if (!*(args[idx])) {
929 ha_alert("parsing [%s:%d] : %s: missing argument after '%s'.\n",
930 file, linenum, args[0], args[idx-1]);
931 err_code |= ERR_ALERT | ERR_FATAL;
932 goto out;
933 }
934 err = parse_time_err(args[idx], &val, TIME_UNIT_MS);
Willy Tarreau9faebe32019-06-07 19:00:37 +0200935 if (err == PARSE_TIME_OVER) {
936 ha_alert("parsing [%s:%d]: %s: timer overflow in argument <%s> to <%s>, maximum value is 2147483647 ms (~24.8 days).\n",
937 file, linenum, args[0], args[idx], args[idx-1]);
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100938 err_code |= ERR_ALERT | ERR_FATAL;
939 goto out;
940 }
Willy Tarreau9faebe32019-06-07 19:00:37 +0200941 else if (err == PARSE_TIME_UNDER) {
942 ha_alert("parsing [%s:%d]: %s: timer underflow in argument <%s> to <%s>, minimum non-null value is 1 ms.\n",
943 file, linenum, args[0], args[idx], args[idx-1]);
944 err_code |= ERR_ALERT | ERR_FATAL;
945 goto out;
946 }
947 else if (err) {
948 ha_alert("parsing [%s:%d] : %s: unexpected character '%c' in argument of '%s'.\n",
949 file, linenum, args[0], *err, args[idx-1]);
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100950 err_code |= ERR_ALERT | ERR_FATAL;
951 goto out;
952 }
953 t->expire = val;
954 idx++;
955 }
956 else if (strcmp(args[idx], "nopurge") == 0) {
957 t->nopurge = 1;
958 idx++;
959 }
960 else if (strcmp(args[idx], "type") == 0) {
961 idx++;
962 if (stktable_parse_type(args, &idx, &t->type, &t->key_size) != 0) {
963 ha_alert("parsing [%s:%d] : %s: unknown type '%s'.\n",
964 file, linenum, args[0], args[idx]);
965 err_code |= ERR_ALERT | ERR_FATAL;
966 goto out;
967 }
968 /* idx already points to next arg */
969 }
970 else if (strcmp(args[idx], "store") == 0) {
971 int type, err;
Emeric Brunc64a2a32021-06-30 18:01:02 +0200972 char *cw, *nw, *sa, *sa2;
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100973
974 idx++;
975 nw = args[idx];
976 while (*nw) {
977 /* the "store" keyword supports a comma-separated list */
978 cw = nw;
979 sa = NULL; /* store arg */
Emeric Brunc64a2a32021-06-30 18:01:02 +0200980 sa2 = NULL;
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100981 while (*nw && *nw != ',') {
982 if (*nw == '(') {
983 *nw = 0;
984 sa = ++nw;
985 while (*nw != ')') {
986 if (!*nw) {
987 ha_alert("parsing [%s:%d] : %s: missing closing parenthesis after store option '%s'.\n",
988 file, linenum, args[0], cw);
989 err_code |= ERR_ALERT | ERR_FATAL;
990 goto out;
991 }
Emeric Brunc64a2a32021-06-30 18:01:02 +0200992 if (*nw == ',') {
993 *nw = '\0';
994 sa2 = nw + 1;
995 }
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100996 nw++;
997 }
998 *nw = '\0';
999 }
1000 nw++;
1001 }
1002 if (*nw)
1003 *nw++ = '\0';
1004 type = stktable_get_data_type(cw);
1005 if (type < 0) {
1006 ha_alert("parsing [%s:%d] : %s: unknown store option '%s'.\n",
1007 file, linenum, args[0], cw);
1008 err_code |= ERR_ALERT | ERR_FATAL;
1009 goto out;
1010 }
1011
Emeric Brunc64a2a32021-06-30 18:01:02 +02001012 err = stktable_alloc_data_type(t, type, sa, sa2);
Frédéric Lécailled456aa42019-03-08 14:47:00 +01001013 switch (err) {
1014 case PE_NONE: break;
1015 case PE_EXIST:
1016 ha_warning("parsing [%s:%d]: %s: store option '%s' already enabled, ignored.\n",
1017 file, linenum, args[0], cw);
1018 err_code |= ERR_WARN;
1019 break;
1020
1021 case PE_ARG_MISSING:
1022 ha_alert("parsing [%s:%d] : %s: missing argument to store option '%s'.\n",
1023 file, linenum, args[0], cw);
1024 err_code |= ERR_ALERT | ERR_FATAL;
1025 goto out;
1026
1027 case PE_ARG_NOT_USED:
1028 ha_alert("parsing [%s:%d] : %s: unexpected argument to store option '%s'.\n",
1029 file, linenum, args[0], cw);
1030 err_code |= ERR_ALERT | ERR_FATAL;
1031 goto out;
Emeric Brunc64a2a32021-06-30 18:01:02 +02001032 case PE_ARG_VALUE_OOR:
1033 ha_alert("parsing [%s:%d] : %s: array size is out of allowed range (1-%d) for store option '%s'.\n",
1034 file, linenum, args[0], STKTABLE_MAX_DT_ARRAY_SIZE, cw);
1035 err_code |= ERR_ALERT | ERR_FATAL;
1036 goto out;
Frédéric Lécailled456aa42019-03-08 14:47:00 +01001037
1038 default:
1039 ha_alert("parsing [%s:%d] : %s: error when processing store option '%s'.\n",
1040 file, linenum, args[0], cw);
1041 err_code |= ERR_ALERT | ERR_FATAL;
1042 goto out;
1043 }
1044 }
1045 idx++;
Emeric Brunf7ab0bf2021-06-30 18:58:22 +02001046 if (t->data_ofs[STKTABLE_DT_GPT] && t->data_ofs[STKTABLE_DT_GPT0]) {
1047 ha_alert("parsing [%s:%d] : %s: simultaneous usage of 'gpt' and 'gpt0' in a same table is not permitted as 'gpt' overrides 'gpt0'.\n",
1048 file, linenum, args[0]);
1049 err_code |= ERR_ALERT | ERR_FATAL;
1050 goto out;
1051 }
Emeric Brun726783d2021-06-30 19:06:43 +02001052 else if (t->data_ofs[STKTABLE_DT_GPC] && (t->data_ofs[STKTABLE_DT_GPC0] || t->data_ofs[STKTABLE_DT_GPC1])) {
1053 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",
1054 file, linenum, args[0]);
1055 err_code |= ERR_ALERT | ERR_FATAL;
1056 goto out;
1057 }
1058 else if (t->data_ofs[STKTABLE_DT_GPC_RATE] && (t->data_ofs[STKTABLE_DT_GPC0_RATE] || t->data_ofs[STKTABLE_DT_GPC1_RATE])) {
1059 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",
1060 file, linenum, args[0]);
1061 err_code |= ERR_ALERT | ERR_FATAL;
1062 goto out;
1063 }
Frédéric Lécailled456aa42019-03-08 14:47:00 +01001064 }
Thayne McCombs92149f92020-11-20 01:28:26 -07001065 else if (strcmp(args[idx], "srvkey") == 0) {
1066 char *keytype;
1067 idx++;
1068 keytype = args[idx];
1069 if (strcmp(keytype, "name") == 0) {
1070 t->server_key_type = STKTABLE_SRV_NAME;
1071 }
1072 else if (strcmp(keytype, "addr") == 0) {
1073 t->server_key_type = STKTABLE_SRV_ADDR;
1074 }
1075 else {
1076 ha_alert("parsing [%s:%d] : %s : unknown server key type '%s'.\n",
1077 file, linenum, args[0], keytype);
1078 err_code |= ERR_ALERT | ERR_FATAL;
1079 goto out;
1080
1081 }
1082 idx++;
1083 }
Frédéric Lécailled456aa42019-03-08 14:47:00 +01001084 else {
1085 ha_alert("parsing [%s:%d] : %s: unknown argument '%s'.\n",
1086 file, linenum, args[0], args[idx]);
1087 err_code |= ERR_ALERT | ERR_FATAL;
1088 goto out;
1089 }
1090 }
1091
1092 if (!t->size) {
1093 ha_alert("parsing [%s:%d] : %s: missing size.\n",
1094 file, linenum, args[0]);
1095 err_code |= ERR_ALERT | ERR_FATAL;
1096 goto out;
1097 }
1098
1099 if (t->type == (unsigned int)-1) {
1100 ha_alert("parsing [%s:%d] : %s: missing type.\n",
1101 file, linenum, args[0]);
1102 err_code |= ERR_ALERT | ERR_FATAL;
1103 goto out;
1104 }
1105
1106 out:
1107 return err_code;
1108}
1109
Willy Tarreau8fed9032014-07-03 17:02:46 +02001110/* Prepares a stktable_key from a sample <smp> to search into table <t>.
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001111 * Note that the sample *is* modified and that the returned key may point
1112 * to it, so the sample must not be modified afterwards before the lookup.
Willy Tarreau8fed9032014-07-03 17:02:46 +02001113 * Returns NULL if the sample could not be converted (eg: no matching type),
1114 * otherwise a pointer to the static stktable_key filled with what is needed
1115 * for the lookup.
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001116 */
Willy Tarreau8fed9032014-07-03 17:02:46 +02001117struct stktable_key *smp_to_stkey(struct sample *smp, struct stktable *t)
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001118{
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001119 /* Convert sample. */
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +02001120 if (!sample_convert(smp, t->type))
Willy Tarreau7fc1c6e2012-04-26 11:03:17 +02001121 return NULL;
1122
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001123 /* Fill static_table_key. */
1124 switch (t->type) {
Emeric Brun485479d2010-09-23 18:02:19 +02001125
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +02001126 case SMP_T_IPV4:
Christopher Fauletca20d022017-08-29 15:30:31 +02001127 static_table_key.key = &smp->data.u.ipv4;
1128 static_table_key.key_len = 4;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001129 break;
Emeric Brun485479d2010-09-23 18:02:19 +02001130
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +02001131 case SMP_T_IPV6:
Christopher Fauletca20d022017-08-29 15:30:31 +02001132 static_table_key.key = &smp->data.u.ipv6;
1133 static_table_key.key_len = 16;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001134 break;
Emeric Brun485479d2010-09-23 18:02:19 +02001135
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +02001136 case SMP_T_SINT:
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001137 /* The stick table require a 32bit unsigned int, "sint" is a
1138 * signed 64 it, so we can convert it inplace.
1139 */
Willy Tarreau28c63c12019-10-23 06:21:05 +02001140 smp->data.u.sint = (unsigned int)smp->data.u.sint;
Christopher Fauletca20d022017-08-29 15:30:31 +02001141 static_table_key.key = &smp->data.u.sint;
1142 static_table_key.key_len = 4;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001143 break;
1144
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +02001145 case SMP_T_STR:
Willy Tarreauce6955e2016-08-09 11:59:12 +02001146 if (!smp_make_safe(smp))
1147 return NULL;
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001148 static_table_key.key = smp->data.u.str.area;
1149 static_table_key.key_len = smp->data.u.str.data;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001150 break;
Emeric Brun485479d2010-09-23 18:02:19 +02001151
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +02001152 case SMP_T_BIN:
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001153 if (smp->data.u.str.data < t->key_size) {
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001154 /* This type needs padding with 0. */
Willy Tarreauf65c6c02016-08-09 12:08:41 +02001155 if (!smp_make_rw(smp))
1156 return NULL;
1157
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001158 if (smp->data.u.str.size < t->key_size)
1159 if (!smp_dup(smp))
1160 return NULL;
1161 if (smp->data.u.str.size < t->key_size)
1162 return NULL;
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001163 memset(smp->data.u.str.area + smp->data.u.str.data, 0,
1164 t->key_size - smp->data.u.str.data);
1165 smp->data.u.str.data = t->key_size;
Emeric Brun485479d2010-09-23 18:02:19 +02001166 }
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001167 static_table_key.key = smp->data.u.str.area;
1168 static_table_key.key_len = smp->data.u.str.data;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001169 break;
Emeric Brun485479d2010-09-23 18:02:19 +02001170
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001171 default: /* impossible case. */
1172 return NULL;
Emeric Brun485479d2010-09-23 18:02:19 +02001173 }
1174
Christopher Fauletca20d022017-08-29 15:30:31 +02001175 return &static_table_key;
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001176}
1177
1178/*
Willy Tarreau8fed9032014-07-03 17:02:46 +02001179 * Process a fetch + format conversion as defined by the sample expression <expr>
1180 * on request or response considering the <opt> parameter. Returns either NULL if
1181 * no key could be extracted, or a pointer to the converted result stored in
1182 * static_table_key in format <table_type>. If <smp> is not NULL, it will be reset
1183 * and its flags will be initialized so that the caller gets a copy of the input
Willy Tarreau6bcb0a82014-07-30 08:56:35 +02001184 * sample, and knows why it was not accepted (eg: SMP_F_MAY_CHANGE is present
1185 * without SMP_OPT_FINAL). The output will be usable like this :
1186 *
1187 * return MAY_CHANGE FINAL Meaning for the sample
1188 * NULL 0 * Not present and will never be (eg: header)
1189 * NULL 1 0 Not present or unstable, could change (eg: req_len)
1190 * NULL 1 1 Not present, will not change anymore
1191 * smp 0 * Present and will not change (eg: header)
1192 * smp 1 0 not possible
1193 * smp 1 1 Present, last known value (eg: request length)
Willy Tarreau8fed9032014-07-03 17:02:46 +02001194 */
Willy Tarreau192252e2015-04-04 01:47:55 +02001195struct stktable_key *stktable_fetch_key(struct stktable *t, struct proxy *px, struct session *sess, struct stream *strm,
Willy Tarreau8fed9032014-07-03 17:02:46 +02001196 unsigned int opt, struct sample_expr *expr, struct sample *smp)
1197{
1198 if (smp)
1199 memset(smp, 0, sizeof(*smp));
1200
Willy Tarreau192252e2015-04-04 01:47:55 +02001201 smp = sample_process(px, sess, strm, opt, expr, smp);
Willy Tarreau8fed9032014-07-03 17:02:46 +02001202 if (!smp)
1203 return NULL;
1204
1205 if ((smp->flags & SMP_F_MAY_CHANGE) && !(opt & SMP_OPT_FINAL))
1206 return NULL; /* we can only use stable samples */
1207
1208 return smp_to_stkey(smp, t);
1209}
1210
1211/*
Willy Tarreau12785782012-04-27 21:37:17 +02001212 * Returns 1 if sample expression <expr> result can be converted to table key of
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001213 * type <table_type>, otherwise zero. Used in configuration check.
1214 */
Willy Tarreau12785782012-04-27 21:37:17 +02001215int stktable_compatible_sample(struct sample_expr *expr, unsigned long table_type)
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001216{
Thierry FOURNIERf73eb8f2013-11-27 15:30:55 +01001217 int out_type;
1218
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +02001219 if (table_type >= SMP_TYPES || !stktable_types[table_type].kw)
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001220 return 0;
1221
Thierry FOURNIERf73eb8f2013-11-27 15:30:55 +01001222 out_type = smp_expr_output_type(expr);
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001223
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001224 /* Convert sample. */
1225 if (!sample_casts[out_type][table_type])
Thierry FOURNIERf73eb8f2013-11-27 15:30:55 +01001226 return 0;
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001227
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001228 return 1;
1229}
Emeric Brun3bd697e2010-01-04 15:23:48 +01001230
Willy Tarreauedee1d62014-07-15 16:44:27 +02001231/* Extra data types processing : after the last one, some room may remain
1232 * before STKTABLE_DATA_TYPES that may be used to register extra data types
1233 * at run time.
1234 */
Willy Tarreau08d5f982010-06-06 13:34:54 +02001235struct stktable_data_type stktable_data_types[STKTABLE_DATA_TYPES] = {
Willy Tarreau3b9c6e02010-07-18 08:04:30 +02001236 [STKTABLE_DT_SERVER_ID] = { .name = "server_id", .std_type = STD_T_SINT },
Thierry FOURNIER3cf11112015-07-28 08:57:05 +02001237 [STKTABLE_DT_GPT0] = { .name = "gpt0", .std_type = STD_T_UINT },
Willy Tarreau3b9c6e02010-07-18 08:04:30 +02001238 [STKTABLE_DT_GPC0] = { .name = "gpc0", .std_type = STD_T_UINT },
Willy Tarreauba2ffd12013-05-29 15:54:14 +02001239 [STKTABLE_DT_GPC0_RATE] = { .name = "gpc0_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
Willy Tarreau3b9c6e02010-07-18 08:04:30 +02001240 [STKTABLE_DT_CONN_CNT] = { .name = "conn_cnt", .std_type = STD_T_UINT },
1241 [STKTABLE_DT_CONN_RATE] = { .name = "conn_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
Willy Tarreaudb2ab822021-10-08 17:53:12 +02001242 [STKTABLE_DT_CONN_CUR] = { .name = "conn_cur", .std_type = STD_T_UINT, .is_local = 1 },
Willy Tarreau3b9c6e02010-07-18 08:04:30 +02001243 [STKTABLE_DT_SESS_CNT] = { .name = "sess_cnt", .std_type = STD_T_UINT },
1244 [STKTABLE_DT_SESS_RATE] = { .name = "sess_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
1245 [STKTABLE_DT_HTTP_REQ_CNT] = { .name = "http_req_cnt", .std_type = STD_T_UINT },
1246 [STKTABLE_DT_HTTP_REQ_RATE] = { .name = "http_req_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
1247 [STKTABLE_DT_HTTP_ERR_CNT] = { .name = "http_err_cnt", .std_type = STD_T_UINT },
1248 [STKTABLE_DT_HTTP_ERR_RATE] = { .name = "http_err_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
1249 [STKTABLE_DT_BYTES_IN_CNT] = { .name = "bytes_in_cnt", .std_type = STD_T_ULL },
1250 [STKTABLE_DT_BYTES_IN_RATE] = { .name = "bytes_in_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
1251 [STKTABLE_DT_BYTES_OUT_CNT] = { .name = "bytes_out_cnt", .std_type = STD_T_ULL },
1252 [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 +01001253 [STKTABLE_DT_GPC1] = { .name = "gpc1", .std_type = STD_T_UINT },
1254 [STKTABLE_DT_GPC1_RATE] = { .name = "gpc1_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
Thayne McCombs92149f92020-11-20 01:28:26 -07001255 [STKTABLE_DT_SERVER_KEY] = { .name = "server_key", .std_type = STD_T_DICT },
Willy Tarreau826f3ab2021-02-10 12:07:15 +01001256 [STKTABLE_DT_HTTP_FAIL_CNT] = { .name = "http_fail_cnt", .std_type = STD_T_UINT },
1257 [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 +02001258 [STKTABLE_DT_GPT] = { .name = "gpt", .std_type = STD_T_UINT, .is_array = 1 },
Emeric Brun4d7ada82021-06-30 19:04:16 +02001259 [STKTABLE_DT_GPC] = { .name = "gpc", .std_type = STD_T_UINT, .is_array = 1 },
1260 [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 +02001261};
1262
Willy Tarreauedee1d62014-07-15 16:44:27 +02001263/* Registers stick-table extra data type with index <idx>, name <name>, type
1264 * <std_type> and arg type <arg_type>. If the index is negative, the next free
1265 * index is automatically allocated. The allocated index is returned, or -1 if
1266 * no free index was found or <name> was already registered. The <name> is used
1267 * directly as a pointer, so if it's not stable, the caller must allocate it.
1268 */
1269int stktable_register_data_store(int idx, const char *name, int std_type, int arg_type)
1270{
1271 if (idx < 0) {
1272 for (idx = 0; idx < STKTABLE_DATA_TYPES; idx++) {
1273 if (!stktable_data_types[idx].name)
1274 break;
1275
1276 if (strcmp(stktable_data_types[idx].name, name) == 0)
1277 return -1;
1278 }
1279 }
1280
1281 if (idx >= STKTABLE_DATA_TYPES)
1282 return -1;
1283
1284 if (stktable_data_types[idx].name != NULL)
1285 return -1;
1286
1287 stktable_data_types[idx].name = name;
1288 stktable_data_types[idx].std_type = std_type;
1289 stktable_data_types[idx].arg_type = arg_type;
1290 return idx;
1291}
1292
Willy Tarreau08d5f982010-06-06 13:34:54 +02001293/*
1294 * Returns the data type number for the stktable_data_type whose name is <name>,
1295 * or <0 if not found.
1296 */
1297int stktable_get_data_type(char *name)
1298{
1299 int type;
1300
1301 for (type = 0; type < STKTABLE_DATA_TYPES; type++) {
Willy Tarreauedee1d62014-07-15 16:44:27 +02001302 if (!stktable_data_types[type].name)
1303 continue;
Willy Tarreau08d5f982010-06-06 13:34:54 +02001304 if (strcmp(name, stktable_data_types[type].name) == 0)
1305 return type;
1306 }
Thayne McCombs92149f92020-11-20 01:28:26 -07001307 /* For backwards compatibility */
1308 if (strcmp(name, "server_name") == 0)
1309 return STKTABLE_DT_SERVER_KEY;
Willy Tarreau08d5f982010-06-06 13:34:54 +02001310 return -1;
1311}
1312
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001313/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1314 * it up into this table. Returns true if found, false otherwise. The input
1315 * type is STR so that input samples are converted to string (since all types
1316 * can be converted to strings), then the function casts the string again into
1317 * the table's type. This is a double conversion, but in the future we might
1318 * support automatic input types to perform the cast on the fly.
1319 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001320static int sample_conv_in_table(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001321{
1322 struct stktable *t;
1323 struct stktable_key *key;
1324 struct stksess *ts;
1325
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001326 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001327
1328 key = smp_to_stkey(smp, t);
1329 if (!key)
1330 return 0;
1331
1332 ts = stktable_lookup_key(t, key);
1333
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001334 smp->data.type = SMP_T_BOOL;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001335 smp->data.u.sint = !!ts;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001336 smp->flags = SMP_F_VOL_TEST;
Willy Tarreau43e90352018-06-27 06:25:57 +02001337 stktable_release(t, ts);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001338 return 1;
1339}
1340
1341/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1342 * it up into this table. Returns the data rate received from clients in bytes/s
1343 * if the key is present in the table, otherwise zero, so that comparisons can
1344 * be easily performed. If the inspected parameter is not stored in the table,
1345 * <not found> is returned.
1346 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001347static int sample_conv_table_bytes_in_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001348{
1349 struct stktable *t;
1350 struct stktable_key *key;
1351 struct stksess *ts;
1352 void *ptr;
1353
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001354 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001355
1356 key = smp_to_stkey(smp, t);
1357 if (!key)
1358 return 0;
1359
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001360 ts = stktable_lookup_key(t, key);
1361
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001362 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001363 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001364 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001365
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001366 if (!ts) /* key not present */
1367 return 1;
1368
1369 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_IN_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001370 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001371 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Daniel Corbett3e60b112018-05-27 09:47:12 -04001372 t->data_arg[STKTABLE_DT_BYTES_IN_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001373
Daniel Corbett3e60b112018-05-27 09:47:12 -04001374 stktable_release(t, ts);
1375 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001376}
1377
1378/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1379 * it up into this table. Returns the cumulated number of connections for the key
1380 * if the key is present in the table, otherwise zero, so that comparisons can
1381 * be easily performed. If the inspected parameter is not stored in the table,
1382 * <not found> is returned.
1383 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001384static int sample_conv_table_conn_cnt(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001385{
1386 struct stktable *t;
1387 struct stktable_key *key;
1388 struct stksess *ts;
1389 void *ptr;
1390
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001391 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001392
1393 key = smp_to_stkey(smp, t);
1394 if (!key)
1395 return 0;
1396
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001397 ts = stktable_lookup_key(t, key);
1398
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001399 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001400 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001401 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001402
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001403 if (!ts) /* key not present */
1404 return 1;
1405
1406 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_CONN_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001407 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001408 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001409
Daniel Corbett3e60b112018-05-27 09:47:12 -04001410 stktable_release(t, ts);
1411 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001412}
1413
1414/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1415 * it up into this table. Returns the number of concurrent connections for the
1416 * key if the key is present in the table, otherwise zero, so that comparisons
1417 * can be easily performed. If the inspected parameter is not stored in the
1418 * table, <not found> is returned.
1419 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001420static int sample_conv_table_conn_cur(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001421{
1422 struct stktable *t;
1423 struct stktable_key *key;
1424 struct stksess *ts;
1425 void *ptr;
1426
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001427 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001428
1429 key = smp_to_stkey(smp, t);
1430 if (!key)
1431 return 0;
1432
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001433 ts = stktable_lookup_key(t, key);
1434
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001435 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001436 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001437 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001438
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001439 if (!ts) /* key not present */
1440 return 1;
1441
1442 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_CONN_CUR);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001443 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001444 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001445
Daniel Corbett3e60b112018-05-27 09:47:12 -04001446 stktable_release(t, ts);
1447 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001448}
1449
1450/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1451 * it up into this table. Returns the rate of incoming connections from the key
1452 * if the key is present in the table, otherwise zero, so that comparisons can
1453 * be easily performed. If the inspected parameter is not stored in the table,
1454 * <not found> is returned.
1455 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001456static int sample_conv_table_conn_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001457{
1458 struct stktable *t;
1459 struct stktable_key *key;
1460 struct stksess *ts;
1461 void *ptr;
1462
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001463 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001464
1465 key = smp_to_stkey(smp, t);
1466 if (!key)
1467 return 0;
1468
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001469 ts = stktable_lookup_key(t, key);
1470
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001471 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001472 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001473 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001474
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001475 if (!ts) /* key not present */
1476 return 1;
1477
1478 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_CONN_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001479 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001480 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Daniel Corbett3e60b112018-05-27 09:47:12 -04001481 t->data_arg[STKTABLE_DT_CONN_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001482
Daniel Corbett3e60b112018-05-27 09:47:12 -04001483 stktable_release(t, ts);
1484 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001485}
1486
1487/* 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 +02001488 * it up into this table. Returns the expiration delay for the key if the key is
1489 * present in the table, otherwise the default value provided as second argument
1490 * if any, if not (no default value), <not found> is returned.
1491 */
1492static int sample_conv_table_expire(const struct arg *arg_p, struct sample *smp, void *private)
1493{
1494 struct stktable *t;
1495 struct stktable_key *key;
1496 struct stksess *ts;
1497
1498 t = arg_p[0].data.t;
1499
1500 key = smp_to_stkey(smp, t);
1501 if (!key)
1502 return 0;
1503
1504 ts = stktable_lookup_key(t, key);
1505
1506 smp->flags = SMP_F_VOL_TEST;
1507 smp->data.type = SMP_T_SINT;
1508 smp->data.u.sint = 0;
1509
1510 if (!ts) { /* key not present */
1511 if (arg_p[1].type == ARGT_STOP)
1512 return 0;
1513
1514 /* default value */
1515 smp->data.u.sint = arg_p[1].data.sint;
1516 return 1;
1517 }
1518
1519 smp->data.u.sint = tick_remain(now_ms, ts->expire);
1520
1521 stktable_release(t, ts);
1522 return 1;
1523}
1524
1525/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1526 * it up into this table. Returns the time the key remains unused if the key is
1527 * present in the table, otherwise the default value provided as second argument
1528 * if any, if not (no default value), <not found> is returned.
1529 */
1530static int sample_conv_table_idle(const struct arg *arg_p, struct sample *smp, void *private)
1531{
1532 struct stktable *t;
1533 struct stktable_key *key;
1534 struct stksess *ts;
1535
1536 t = arg_p[0].data.t;
1537
1538 key = smp_to_stkey(smp, t);
1539 if (!key)
1540 return 0;
1541
1542 ts = stktable_lookup_key(t, key);
1543
1544 smp->flags = SMP_F_VOL_TEST;
1545 smp->data.type = SMP_T_SINT;
1546 smp->data.u.sint = 0;
1547
1548 if (!ts) { /* key not present */
1549 if (arg_p[1].type == ARGT_STOP)
1550 return 0;
1551
1552 /* default value */
1553 smp->data.u.sint = arg_p[1].data.sint;
1554 return 1;
1555 }
1556
1557 smp->data.u.sint = tick_remain(tick_remain(now_ms, ts->expire), t->expire);
1558
1559 stktable_release(t, ts);
1560 return 1;
1561}
1562
1563/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001564 * it up into this table. Returns the data rate sent to clients in bytes/s
1565 * if the key is present in the table, otherwise zero, so that comparisons can
1566 * be easily performed. If the inspected parameter is not stored in the table,
1567 * <not found> is returned.
1568 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001569static int sample_conv_table_bytes_out_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001570{
1571 struct stktable *t;
1572 struct stktable_key *key;
1573 struct stksess *ts;
1574 void *ptr;
1575
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001576 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001577
1578 key = smp_to_stkey(smp, t);
1579 if (!key)
1580 return 0;
1581
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001582 ts = stktable_lookup_key(t, key);
1583
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001584 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001585 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001586 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001587
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001588 if (!ts) /* key not present */
1589 return 1;
1590
1591 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_OUT_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001592 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001593 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Daniel Corbett3e60b112018-05-27 09:47:12 -04001594 t->data_arg[STKTABLE_DT_BYTES_OUT_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001595
Daniel Corbett3e60b112018-05-27 09:47:12 -04001596 stktable_release(t, ts);
1597 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001598}
1599
Emeric Brun877b0b52021-06-30 18:57:49 +02001600/* Casts sample <smp> to the type of the table specified in arg_p(1), and looks
1601 * it up into this table. Returns the value of the GPT[arg_p(0)] tag for the key
1602 * if the key is present in the table, otherwise false, so that comparisons can
1603 * be easily performed. If the inspected parameter is not stored in the table,
1604 * <not found> is returned.
1605 */
1606static int sample_conv_table_gpt(const struct arg *arg_p, struct sample *smp, void *private)
1607{
1608 struct stktable *t;
1609 struct stktable_key *key;
1610 struct stksess *ts;
1611 void *ptr;
1612 unsigned int idx;
1613
1614 idx = arg_p[0].data.sint;
1615
1616 t = arg_p[1].data.t;
1617
1618 key = smp_to_stkey(smp, t);
1619 if (!key)
1620 return 0;
1621
1622 ts = stktable_lookup_key(t, key);
1623
1624 smp->flags = SMP_F_VOL_TEST;
1625 smp->data.type = SMP_T_SINT;
1626 smp->data.u.sint = 0;
1627
1628 if (!ts) /* key not present */
1629 return 1;
1630
1631 ptr = stktable_data_ptr_idx(t, ts, STKTABLE_DT_GPT, idx);
1632 if (ptr)
1633 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
1634
1635 stktable_release(t, ts);
1636 return !!ptr;
1637}
1638
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001639/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001640 * it up into this table. Returns the value of the GPT0 tag for the key
1641 * if the key is present in the table, otherwise false, so that comparisons can
1642 * be easily performed. If the inspected parameter is not stored in the table,
1643 * <not found> is returned.
1644 */
1645static int sample_conv_table_gpt0(const struct arg *arg_p, struct sample *smp, void *private)
1646{
1647 struct stktable *t;
1648 struct stktable_key *key;
1649 struct stksess *ts;
1650 void *ptr;
1651
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001652 t = arg_p[0].data.t;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001653
1654 key = smp_to_stkey(smp, t);
1655 if (!key)
1656 return 0;
1657
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001658 ts = stktable_lookup_key(t, key);
1659
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001660 smp->flags = SMP_F_VOL_TEST;
1661 smp->data.type = SMP_T_SINT;
1662 smp->data.u.sint = 0;
1663
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001664 if (!ts) /* key not present */
1665 return 1;
1666
1667 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPT0);
Emeric Brunf7ab0bf2021-06-30 18:58:22 +02001668 if (!ptr)
1669 ptr = stktable_data_ptr_idx(t, ts, STKTABLE_DT_GPT, 0);
1670
Daniel Corbett3e60b112018-05-27 09:47:12 -04001671 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001672 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001673
Daniel Corbett3e60b112018-05-27 09:47:12 -04001674 stktable_release(t, ts);
1675 return !!ptr;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001676}
1677
Emeric Brun4d7ada82021-06-30 19:04:16 +02001678/* Casts sample <smp> to the type of the table specified in arg_p(1), and looks
1679 * it up into this table. Returns the value of the GPC[arg_p(0)] counter for the key
1680 * if the key is present in the table, otherwise zero, so that comparisons can
1681 * be easily performed. If the inspected parameter is not stored in the table,
1682 * <not found> is returned.
1683 */
1684static int sample_conv_table_gpc(const struct arg *arg_p, struct sample *smp, void *private)
1685{
1686 struct stktable *t;
1687 struct stktable_key *key;
1688 struct stksess *ts;
1689 void *ptr;
1690 unsigned int idx;
1691
1692 idx = arg_p[0].data.sint;
1693
1694 t = arg_p[1].data.t;
1695
1696 key = smp_to_stkey(smp, t);
1697 if (!key)
1698 return 0;
1699
1700 ts = stktable_lookup_key(t, key);
1701
1702 smp->flags = SMP_F_VOL_TEST;
1703 smp->data.type = SMP_T_SINT;
1704 smp->data.u.sint = 0;
1705
1706 if (!ts) /* key not present */
1707 return 1;
1708
1709 ptr = stktable_data_ptr_idx(t, ts, STKTABLE_DT_GPC, idx);
1710 if (ptr)
1711 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
1712
1713 stktable_release(t, ts);
1714 return !!ptr;
1715}
1716
1717/* Casts sample <smp> to the type of the table specified in arg_p(1), and looks
1718 * it up into this table. Returns the event rate of the GPC[arg_p(0)] counter
1719 * for the key if the key is present in the table, otherwise zero, so that
1720 * comparisons can be easily performed. If the inspected parameter is not
1721 * stored in the table, <not found> is returned.
1722 */
1723static int sample_conv_table_gpc_rate(const struct arg *arg_p, struct sample *smp, void *private)
1724{
1725 struct stktable *t;
1726 struct stktable_key *key;
1727 struct stksess *ts;
1728 void *ptr;
1729 unsigned int idx;
1730
1731 idx = arg_p[0].data.sint;
1732
1733 t = arg_p[1].data.t;
1734
1735 key = smp_to_stkey(smp, t);
1736 if (!key)
1737 return 0;
1738
1739 ts = stktable_lookup_key(t, key);
1740
1741 smp->flags = SMP_F_VOL_TEST;
1742 smp->data.type = SMP_T_SINT;
1743 smp->data.u.sint = 0;
1744
1745 if (!ts) /* key not present */
1746 return 1;
1747
1748 ptr = stktable_data_ptr_idx(t, ts, STKTABLE_DT_GPC_RATE, idx);
1749 if (ptr)
1750 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
1751 t->data_arg[STKTABLE_DT_GPC_RATE].u);
1752
1753 stktable_release(t, ts);
1754 return !!ptr;
1755}
1756
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001757/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001758 * it up into this table. Returns the value of the GPC0 counter for the key
1759 * if the key is present in the table, otherwise zero, so that comparisons can
1760 * be easily performed. If the inspected parameter is not stored in the table,
1761 * <not found> is returned.
1762 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001763static int sample_conv_table_gpc0(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001764{
1765 struct stktable *t;
1766 struct stktable_key *key;
1767 struct stksess *ts;
1768 void *ptr;
1769
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001770 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001771
1772 key = smp_to_stkey(smp, t);
1773 if (!key)
1774 return 0;
1775
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001776 ts = stktable_lookup_key(t, key);
1777
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001778 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001779 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001780 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001781
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001782 if (!ts) /* key not present */
1783 return 1;
1784
1785 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPC0);
Emeric Brun726783d2021-06-30 19:06:43 +02001786 if (!ptr) {
1787 /* fallback on the gpc array */
1788 ptr = stktable_data_ptr_idx(t, ts, STKTABLE_DT_GPC, 0);
1789 }
1790
Daniel Corbett3e60b112018-05-27 09:47:12 -04001791 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001792 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001793
Daniel Corbett3e60b112018-05-27 09:47:12 -04001794 stktable_release(t, ts);
1795 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001796}
1797
1798/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1799 * it up into this table. Returns the event rate of the GPC0 counter for the key
1800 * if the key is present in the table, otherwise zero, so that comparisons can
1801 * be easily performed. If the inspected parameter is not stored in the table,
1802 * <not found> is returned.
1803 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001804static int sample_conv_table_gpc0_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001805{
1806 struct stktable *t;
1807 struct stktable_key *key;
1808 struct stksess *ts;
1809 void *ptr;
1810
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001811 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001812
1813 key = smp_to_stkey(smp, t);
1814 if (!key)
1815 return 0;
1816
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001817 ts = stktable_lookup_key(t, key);
1818
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001819 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001820 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001821 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001822
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001823 if (!ts) /* key not present */
1824 return 1;
1825
1826 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPC0_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001827 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001828 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Daniel Corbett3e60b112018-05-27 09:47:12 -04001829 t->data_arg[STKTABLE_DT_GPC0_RATE].u);
Emeric Brun726783d2021-06-30 19:06:43 +02001830 else {
1831 /* fallback on the gpc array */
1832 ptr = stktable_data_ptr_idx(t, ts, STKTABLE_DT_GPC_RATE, 0);
1833 if (ptr)
1834 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
1835 t->data_arg[STKTABLE_DT_GPC_RATE].u);
1836 }
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001837
Daniel Corbett3e60b112018-05-27 09:47:12 -04001838 stktable_release(t, ts);
1839 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001840}
1841
1842/* 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 +01001843 * it up into this table. Returns the value of the GPC1 counter for the key
1844 * if the key is present in the table, otherwise zero, so that comparisons can
1845 * be easily performed. If the inspected parameter is not stored in the table,
1846 * <not found> is returned.
1847 */
1848static int sample_conv_table_gpc1(const struct arg *arg_p, struct sample *smp, void *private)
1849{
1850 struct stktable *t;
1851 struct stktable_key *key;
1852 struct stksess *ts;
1853 void *ptr;
1854
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001855 t = arg_p[0].data.t;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001856
1857 key = smp_to_stkey(smp, t);
1858 if (!key)
1859 return 0;
1860
1861 ts = stktable_lookup_key(t, key);
1862
1863 smp->flags = SMP_F_VOL_TEST;
1864 smp->data.type = SMP_T_SINT;
1865 smp->data.u.sint = 0;
1866
1867 if (!ts) /* key not present */
1868 return 1;
1869
1870 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPC1);
Emeric Brun726783d2021-06-30 19:06:43 +02001871 if (!ptr) {
1872 /* fallback on the gpc array */
1873 ptr = stktable_data_ptr_idx(t, ts, STKTABLE_DT_GPC, 1);
1874 }
1875
Daniel Corbett3e60b112018-05-27 09:47:12 -04001876 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001877 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001878
Daniel Corbett3e60b112018-05-27 09:47:12 -04001879 stktable_release(t, ts);
1880 return !!ptr;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001881}
1882
1883/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1884 * it up into this table. Returns the event rate of the GPC1 counter for the key
1885 * if the key is present in the table, otherwise zero, so that comparisons can
1886 * be easily performed. If the inspected parameter is not stored in the table,
1887 * <not found> is returned.
1888 */
1889static int sample_conv_table_gpc1_rate(const struct arg *arg_p, struct sample *smp, void *private)
1890{
1891 struct stktable *t;
1892 struct stktable_key *key;
1893 struct stksess *ts;
1894 void *ptr;
1895
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001896 t = arg_p[0].data.t;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001897
1898 key = smp_to_stkey(smp, t);
1899 if (!key)
1900 return 0;
1901
1902 ts = stktable_lookup_key(t, key);
1903
1904 smp->flags = SMP_F_VOL_TEST;
1905 smp->data.type = SMP_T_SINT;
1906 smp->data.u.sint = 0;
1907
1908 if (!ts) /* key not present */
1909 return 1;
1910
1911 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPC1_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001912 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001913 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Daniel Corbett3e60b112018-05-27 09:47:12 -04001914 t->data_arg[STKTABLE_DT_GPC1_RATE].u);
Emeric Brun726783d2021-06-30 19:06:43 +02001915 else {
1916 /* fallback on the gpc array */
1917 ptr = stktable_data_ptr_idx(t, ts, STKTABLE_DT_GPC_RATE, 1);
1918 if (ptr)
1919 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
1920 t->data_arg[STKTABLE_DT_GPC_RATE].u);
1921 }
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001922
Daniel Corbett3e60b112018-05-27 09:47:12 -04001923 stktable_release(t, ts);
1924 return !!ptr;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001925}
1926
1927/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001928 * it up into this table. Returns the cumulated number of HTTP request errors
1929 * for the key if the key is present in the table, otherwise zero, so that
1930 * comparisons can be easily performed. If the inspected parameter is not stored
1931 * in the table, <not found> is returned.
1932 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001933static int sample_conv_table_http_err_cnt(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001934{
1935 struct stktable *t;
1936 struct stktable_key *key;
1937 struct stksess *ts;
1938 void *ptr;
1939
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001940 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001941
1942 key = smp_to_stkey(smp, t);
1943 if (!key)
1944 return 0;
1945
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001946 ts = stktable_lookup_key(t, key);
1947
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001948 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001949 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001950 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001951
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001952 if (!ts) /* key not present */
1953 return 1;
1954
1955 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_ERR_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001956 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001957 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001958
Daniel Corbett3e60b112018-05-27 09:47:12 -04001959 stktable_release(t, ts);
1960 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001961}
1962
1963/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1964 * it up into this table. Returns the HTTP request error rate the key
1965 * if the key is present in the table, otherwise zero, so that comparisons can
1966 * be easily performed. If the inspected parameter is not stored in the table,
1967 * <not found> is returned.
1968 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001969static int sample_conv_table_http_err_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001970{
1971 struct stktable *t;
1972 struct stktable_key *key;
1973 struct stksess *ts;
1974 void *ptr;
1975
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001976 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001977
1978 key = smp_to_stkey(smp, t);
1979 if (!key)
1980 return 0;
1981
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001982 ts = stktable_lookup_key(t, key);
1983
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001984 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001985 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001986 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001987
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001988 if (!ts) /* key not present */
1989 return 1;
1990
1991 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_ERR_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001992 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001993 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Daniel Corbett3e60b112018-05-27 09:47:12 -04001994 t->data_arg[STKTABLE_DT_HTTP_ERR_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001995
Daniel Corbett3e60b112018-05-27 09:47:12 -04001996 stktable_release(t, ts);
1997 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001998}
1999
2000/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Willy Tarreau826f3ab2021-02-10 12:07:15 +01002001 * it up into this table. Returns the cumulated number of HTTP response failures
2002 * for the key if the key is present in the table, otherwise zero, so that
2003 * comparisons can be easily performed. If the inspected parameter is not stored
2004 * in the table, <not found> is returned.
2005 */
2006static int sample_conv_table_http_fail_cnt(const struct arg *arg_p, struct sample *smp, void *private)
2007{
2008 struct stktable *t;
2009 struct stktable_key *key;
2010 struct stksess *ts;
2011 void *ptr;
2012
2013 t = arg_p[0].data.t;
2014
2015 key = smp_to_stkey(smp, t);
2016 if (!key)
2017 return 0;
2018
2019 ts = stktable_lookup_key(t, key);
2020
2021 smp->flags = SMP_F_VOL_TEST;
2022 smp->data.type = SMP_T_SINT;
2023 smp->data.u.sint = 0;
2024
2025 if (!ts) /* key not present */
2026 return 1;
2027
2028 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_FAIL_CNT);
2029 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002030 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Willy Tarreau826f3ab2021-02-10 12:07:15 +01002031
2032 stktable_release(t, ts);
2033 return !!ptr;
2034}
2035
2036/* Casts sample <smp> to the type of the table specified in arg(0), and looks
2037 * it up into this table. Returns the HTTP response failure rate for the key
2038 * if the key is present in the table, otherwise zero, so that comparisons can
2039 * be easily performed. If the inspected parameter is not stored in the table,
2040 * <not found> is returned.
2041 */
2042static int sample_conv_table_http_fail_rate(const struct arg *arg_p, struct sample *smp, void *private)
2043{
2044 struct stktable *t;
2045 struct stktable_key *key;
2046 struct stksess *ts;
2047 void *ptr;
2048
2049 t = arg_p[0].data.t;
2050
2051 key = smp_to_stkey(smp, t);
2052 if (!key)
2053 return 0;
2054
2055 ts = stktable_lookup_key(t, key);
2056
2057 smp->flags = SMP_F_VOL_TEST;
2058 smp->data.type = SMP_T_SINT;
2059 smp->data.u.sint = 0;
2060
2061 if (!ts) /* key not present */
2062 return 1;
2063
2064 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_FAIL_RATE);
2065 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002066 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Willy Tarreau826f3ab2021-02-10 12:07:15 +01002067 t->data_arg[STKTABLE_DT_HTTP_FAIL_RATE].u);
2068
2069 stktable_release(t, ts);
2070 return !!ptr;
2071}
2072
2073/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002074 * it up into this table. Returns the cumulated number of HTTP request for the
2075 * key if the key is present in the table, otherwise zero, so that comparisons
2076 * can be easily performed. If the inspected parameter is not stored in the
2077 * table, <not found> is returned.
2078 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02002079static int sample_conv_table_http_req_cnt(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002080{
2081 struct stktable *t;
2082 struct stktable_key *key;
2083 struct stksess *ts;
2084 void *ptr;
2085
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002086 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002087
2088 key = smp_to_stkey(smp, t);
2089 if (!key)
2090 return 0;
2091
Willy Tarreauf0c730a2016-05-25 17:07:56 +02002092 ts = stktable_lookup_key(t, key);
2093
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002094 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02002095 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02002096 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002097
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002098 if (!ts) /* key not present */
2099 return 1;
2100
2101 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_REQ_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04002102 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002103 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002104
Daniel Corbett3e60b112018-05-27 09:47:12 -04002105 stktable_release(t, ts);
2106 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002107}
2108
2109/* Casts sample <smp> to the type of the table specified in arg(0), and looks
2110 * it up into this table. Returns the HTTP request rate the key if the key is
2111 * present in the table, otherwise zero, so that comparisons can be easily
2112 * performed. If the inspected parameter is not stored in the table, <not found>
2113 * is returned.
2114 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02002115static int sample_conv_table_http_req_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002116{
2117 struct stktable *t;
2118 struct stktable_key *key;
2119 struct stksess *ts;
2120 void *ptr;
2121
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002122 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002123
2124 key = smp_to_stkey(smp, t);
2125 if (!key)
2126 return 0;
2127
Willy Tarreauf0c730a2016-05-25 17:07:56 +02002128 ts = stktable_lookup_key(t, key);
2129
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002130 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02002131 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02002132 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002133
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002134 if (!ts) /* key not present */
2135 return 1;
2136
2137 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_REQ_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04002138 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002139 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Daniel Corbett3e60b112018-05-27 09:47:12 -04002140 t->data_arg[STKTABLE_DT_HTTP_REQ_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002141
Daniel Corbett3e60b112018-05-27 09:47:12 -04002142 stktable_release(t, ts);
2143 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002144}
2145
2146/* Casts sample <smp> to the type of the table specified in arg(0), and looks
2147 * it up into this table. Returns the volume of datareceived from clients in kbytes
2148 * if the key is present in the table, otherwise zero, so that comparisons can
2149 * be easily performed. If the inspected parameter is not stored in the table,
2150 * <not found> is returned.
2151 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02002152static int sample_conv_table_kbytes_in(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002153{
2154 struct stktable *t;
2155 struct stktable_key *key;
2156 struct stksess *ts;
2157 void *ptr;
2158
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002159 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002160
2161 key = smp_to_stkey(smp, t);
2162 if (!key)
2163 return 0;
2164
Willy Tarreauf0c730a2016-05-25 17:07:56 +02002165 ts = stktable_lookup_key(t, key);
2166
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002167 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02002168 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02002169 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002170
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002171 if (!ts) /* key not present */
2172 return 1;
2173
2174 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_IN_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04002175 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002176 smp->data.u.sint = stktable_data_cast(ptr, std_t_ull) >> 10;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002177
Daniel Corbett3e60b112018-05-27 09:47:12 -04002178 stktable_release(t, ts);
2179 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002180}
2181
2182/* Casts sample <smp> to the type of the table specified in arg(0), and looks
2183 * it up into this table. Returns the volume of data sent to clients in kbytes
2184 * if the key is present in the table, otherwise zero, so that comparisons can
2185 * be easily performed. If the inspected parameter is not stored in the table,
2186 * <not found> is returned.
2187 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02002188static int sample_conv_table_kbytes_out(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002189{
2190 struct stktable *t;
2191 struct stktable_key *key;
2192 struct stksess *ts;
2193 void *ptr;
2194
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002195 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002196
2197 key = smp_to_stkey(smp, t);
2198 if (!key)
2199 return 0;
2200
Willy Tarreauf0c730a2016-05-25 17:07:56 +02002201 ts = stktable_lookup_key(t, key);
2202
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002203 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02002204 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02002205 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002206
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002207 if (!ts) /* key not present */
2208 return 1;
2209
2210 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_OUT_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04002211 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002212 smp->data.u.sint = stktable_data_cast(ptr, std_t_ull) >> 10;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002213
Daniel Corbett3e60b112018-05-27 09:47:12 -04002214 stktable_release(t, ts);
2215 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002216}
2217
2218/* Casts sample <smp> to the type of the table specified in arg(0), and looks
2219 * it up into this table. Returns the server ID associated with the key if the
2220 * key is present in the table, otherwise zero, so that comparisons can be
2221 * easily performed. If the inspected parameter is not stored in the table,
2222 * <not found> is returned.
2223 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02002224static int sample_conv_table_server_id(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002225{
2226 struct stktable *t;
2227 struct stktable_key *key;
2228 struct stksess *ts;
2229 void *ptr;
2230
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002231 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002232
2233 key = smp_to_stkey(smp, t);
2234 if (!key)
2235 return 0;
2236
Willy Tarreauf0c730a2016-05-25 17:07:56 +02002237 ts = stktable_lookup_key(t, key);
2238
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002239 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02002240 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02002241 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002242
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002243 if (!ts) /* key not present */
2244 return 1;
2245
2246 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_SERVER_ID);
Daniel Corbett3e60b112018-05-27 09:47:12 -04002247 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002248 smp->data.u.sint = stktable_data_cast(ptr, std_t_sint);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002249
Daniel Corbett3e60b112018-05-27 09:47:12 -04002250 stktable_release(t, ts);
2251 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002252}
2253
2254/* Casts sample <smp> to the type of the table specified in arg(0), and looks
2255 * it up into this table. Returns the cumulated number of sessions for the
2256 * key if the key is present in the table, otherwise zero, so that comparisons
2257 * can be easily performed. If the inspected parameter is not stored in the
2258 * table, <not found> is returned.
2259 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02002260static int sample_conv_table_sess_cnt(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002261{
2262 struct stktable *t;
2263 struct stktable_key *key;
2264 struct stksess *ts;
2265 void *ptr;
2266
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002267 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002268
2269 key = smp_to_stkey(smp, t);
2270 if (!key)
2271 return 0;
2272
Willy Tarreauf0c730a2016-05-25 17:07:56 +02002273 ts = stktable_lookup_key(t, key);
2274
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002275 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02002276 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02002277 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002278
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002279 if (!ts) /* key not present */
2280 return 1;
2281
2282 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_SESS_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04002283 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002284 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002285
Daniel Corbett3e60b112018-05-27 09:47:12 -04002286 stktable_release(t, ts);
2287 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002288}
2289
2290/* Casts sample <smp> to the type of the table specified in arg(0), and looks
2291 * it up into this table. Returns the session rate the key if the key is
2292 * present in the table, otherwise zero, so that comparisons can be easily
2293 * performed. If the inspected parameter is not stored in the table, <not found>
2294 * is returned.
2295 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02002296static int sample_conv_table_sess_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002297{
2298 struct stktable *t;
2299 struct stktable_key *key;
2300 struct stksess *ts;
2301 void *ptr;
2302
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002303 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002304
2305 key = smp_to_stkey(smp, t);
2306 if (!key)
2307 return 0;
2308
Willy Tarreauf0c730a2016-05-25 17:07:56 +02002309 ts = stktable_lookup_key(t, key);
2310
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002311 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02002312 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02002313 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002314
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002315 if (!ts) /* key not present */
2316 return 1;
2317
2318 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_SESS_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04002319 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002320 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Daniel Corbett3e60b112018-05-27 09:47:12 -04002321 t->data_arg[STKTABLE_DT_SESS_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002322
Daniel Corbett3e60b112018-05-27 09:47:12 -04002323 stktable_release(t, ts);
2324 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002325}
2326
2327/* Casts sample <smp> to the type of the table specified in arg(0), and looks
2328 * it up into this table. Returns the amount of concurrent connections tracking
2329 * the same key if the key is present in the table, otherwise zero, so that
2330 * comparisons can be easily performed. If the inspected parameter is not
2331 * stored in the table, <not found> is returned.
2332 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02002333static int sample_conv_table_trackers(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002334{
2335 struct stktable *t;
2336 struct stktable_key *key;
2337 struct stksess *ts;
2338
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002339 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002340
2341 key = smp_to_stkey(smp, t);
2342 if (!key)
2343 return 0;
2344
Willy Tarreauf0c730a2016-05-25 17:07:56 +02002345 ts = stktable_lookup_key(t, key);
2346
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002347 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02002348 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02002349 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002350
Tim Duesterhus65189c12018-06-26 15:57:29 +02002351 if (!ts)
2352 return 1;
2353
2354 smp->data.u.sint = ts->ref_cnt;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002355
Daniel Corbett3e60b112018-05-27 09:47:12 -04002356 stktable_release(t, ts);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002357 return 1;
2358}
2359
Emeric Brun4d7ada82021-06-30 19:04:16 +02002360/* This function increments the gpc counter at index 'rule->arg.gpc.idx' of the
2361 * array on the tracksc counter of index 'rule->arg.gpc.sc' stored into the
2362 * <stream> or directly in the session <sess> if <stream> is set to NULL
2363 *
2364 * This function always returns ACT_RET_CONT and parameter flags is unused.
2365 */
2366static enum act_return action_inc_gpc(struct act_rule *rule, struct proxy *px,
2367 struct session *sess, struct stream *s, int flags)
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002368{
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002369 struct stksess *ts;
2370 struct stkctr *stkctr;
2371
2372 /* Extract the stksess, return OK if no stksess available. */
2373 if (s)
2374 stkctr = &s->stkctr[rule->arg.gpc.sc];
2375 else
2376 stkctr = &sess->stkctr[rule->arg.gpc.sc];
Willy Tarreau79c1e912016-01-25 14:54:45 +01002377
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002378 ts = stkctr_entry(stkctr);
Willy Tarreau79c1e912016-01-25 14:54:45 +01002379 if (ts) {
2380 void *ptr1, *ptr2;
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002381
Emeric Brun4d7ada82021-06-30 19:04:16 +02002382 /* First, update gpc_rate if it's tracked. Second, update its gpc if tracked. */
2383 ptr1 = stktable_data_ptr_idx(stkctr->table, ts, STKTABLE_DT_GPC_RATE, rule->arg.gpc.idx);
2384 ptr2 = stktable_data_ptr_idx(stkctr->table, ts, STKTABLE_DT_GPC, rule->arg.gpc.idx);
2385
Emeric Brun819fc6f2017-06-13 19:37:32 +02002386 if (ptr1 || ptr2) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002387 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002388
2389 if (ptr1)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002390 update_freq_ctr_period(&stktable_data_cast(ptr1, std_t_frqp),
Emeric Brun4d7ada82021-06-30 19:04:16 +02002391 stkctr->table->data_arg[STKTABLE_DT_GPC_RATE].u, 1);
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002392
Emeric Brun819fc6f2017-06-13 19:37:32 +02002393 if (ptr2)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002394 stktable_data_cast(ptr2, std_t_uint)++;
Willy Tarreau79c1e912016-01-25 14:54:45 +01002395
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002396 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002397
2398 /* If data was modified, we need to touch to re-schedule sync */
2399 stktable_touch_local(stkctr->table, ts, 0);
2400 }
Willy Tarreau79c1e912016-01-25 14:54:45 +01002401 }
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002402 return ACT_RET_CONT;
2403}
2404
Emeric Brun4d7ada82021-06-30 19:04:16 +02002405/* Same as action_inc_gpc() but for gpc0 only */
2406static enum act_return action_inc_gpc0(struct act_rule *rule, struct proxy *px,
2407 struct session *sess, struct stream *s, int flags)
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002408{
Emeric Brun4d7ada82021-06-30 19:04:16 +02002409 struct stksess *ts;
2410 struct stkctr *stkctr;
Willy Tarreau5b654ad2021-07-06 18:51:12 +02002411 unsigned int period = 0;
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002412
Emeric Brun4d7ada82021-06-30 19:04:16 +02002413 /* Extract the stksess, return OK if no stksess available. */
2414 if (s)
2415 stkctr = &s->stkctr[rule->arg.gpc.sc];
2416 else
2417 stkctr = &sess->stkctr[rule->arg.gpc.sc];
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002418
Emeric Brun4d7ada82021-06-30 19:04:16 +02002419 ts = stkctr_entry(stkctr);
2420 if (ts) {
2421 void *ptr1, *ptr2;
2422
2423 /* First, update gpc0_rate if it's tracked. Second, update its gpc0 if tracked. */
2424 ptr1 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC0_RATE);
Emeric Brun726783d2021-06-30 19:06:43 +02002425 if (ptr1) {
2426 period = stkctr->table->data_arg[STKTABLE_DT_GPC0_RATE].u;
2427 }
2428 else {
2429 /* fallback on the gpc array */
2430 ptr1 = stktable_data_ptr_idx(stkctr->table, ts, STKTABLE_DT_GPC_RATE, 0);
2431 if (ptr1)
2432 period = stkctr->table->data_arg[STKTABLE_DT_GPC_RATE].u;
2433 }
2434
Emeric Brun4d7ada82021-06-30 19:04:16 +02002435 ptr2 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC0);
Emeric Brun726783d2021-06-30 19:06:43 +02002436 if (!ptr2) {
2437 /* fallback on the gpc array */
2438 ptr2 = stktable_data_ptr_idx(stkctr->table, ts, STKTABLE_DT_GPC, 0);
2439 }
2440
Emeric Brun4d7ada82021-06-30 19:04:16 +02002441 if (ptr1 || ptr2) {
2442 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
2443
2444 if (ptr1)
2445 update_freq_ctr_period(&stktable_data_cast(ptr1, std_t_frqp),
Emeric Brun726783d2021-06-30 19:06:43 +02002446 period, 1);
Emeric Brun4d7ada82021-06-30 19:04:16 +02002447
2448 if (ptr2)
2449 stktable_data_cast(ptr2, std_t_uint)++;
2450
2451 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
2452
2453 /* If data was modified, we need to touch to re-schedule sync */
2454 stktable_touch_local(stkctr->table, ts, 0);
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002455 }
2456 }
Emeric Brun4d7ada82021-06-30 19:04:16 +02002457 return ACT_RET_CONT;
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002458}
2459
Emeric Brun4d7ada82021-06-30 19:04:16 +02002460/* Same as action_inc_gpc() but for gpc1 only */
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002461static enum act_return action_inc_gpc1(struct act_rule *rule, struct proxy *px,
2462 struct session *sess, struct stream *s, int flags)
2463{
2464 struct stksess *ts;
2465 struct stkctr *stkctr;
Willy Tarreau5b654ad2021-07-06 18:51:12 +02002466 unsigned int period = 0;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002467
2468 /* Extract the stksess, return OK if no stksess available. */
2469 if (s)
2470 stkctr = &s->stkctr[rule->arg.gpc.sc];
2471 else
2472 stkctr = &sess->stkctr[rule->arg.gpc.sc];
2473
2474 ts = stkctr_entry(stkctr);
2475 if (ts) {
2476 void *ptr1, *ptr2;
2477
2478 /* First, update gpc1_rate if it's tracked. Second, update its gpc1 if tracked. */
2479 ptr1 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC1_RATE);
Emeric Brun726783d2021-06-30 19:06:43 +02002480 if (ptr1) {
2481 period = stkctr->table->data_arg[STKTABLE_DT_GPC1_RATE].u;
2482 }
2483 else {
2484 /* fallback on the gpc array */
2485 ptr1 = stktable_data_ptr_idx(stkctr->table, ts, STKTABLE_DT_GPC_RATE, 1);
2486 if (ptr1)
2487 period = stkctr->table->data_arg[STKTABLE_DT_GPC_RATE].u;
2488 }
2489
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002490 ptr2 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC1);
Emeric Brun726783d2021-06-30 19:06:43 +02002491 if (!ptr2) {
2492 /* fallback on the gpc array */
2493 ptr2 = stktable_data_ptr_idx(stkctr->table, ts, STKTABLE_DT_GPC, 1);
2494 }
2495
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002496 if (ptr1 || ptr2) {
2497 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
2498
2499 if (ptr1)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002500 update_freq_ctr_period(&stktable_data_cast(ptr1, std_t_frqp),
Emeric Brun726783d2021-06-30 19:06:43 +02002501 period, 1);
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002502
2503 if (ptr2)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002504 stktable_data_cast(ptr2, std_t_uint)++;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002505
2506 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
2507
2508 /* If data was modified, we need to touch to re-schedule sync */
2509 stktable_touch_local(stkctr->table, ts, 0);
2510 }
2511 }
2512 return ACT_RET_CONT;
2513}
2514
Emeric Brun4d7ada82021-06-30 19:04:16 +02002515/* This function is a common parser for actions incrementing the GPC
2516 * (General Purpose Counters). It understands the formats:
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002517 *
Emeric Brun4d7ada82021-06-30 19:04:16 +02002518 * sc-inc-gpc(<gpc IDX>,<track ID>)
2519 * sc-inc-gpc0([<track ID>])
2520 * sc-inc-gpc1([<track ID>])
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002521 *
Emeric Brun4d7ada82021-06-30 19:04:16 +02002522 * It returns ACT_RET_PRS_ERR if fails and <err> is filled with an error
2523 * message. Otherwise it returns ACT_RET_PRS_OK.
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002524 */
Emeric Brun4d7ada82021-06-30 19:04:16 +02002525static enum act_parse_ret parse_inc_gpc(const char **args, int *arg, struct proxy *px,
2526 struct act_rule *rule, char **err)
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002527{
2528 const char *cmd_name = args[*arg-1];
2529 char *error;
2530
Emeric Brun4d7ada82021-06-30 19:04:16 +02002531 cmd_name += strlen("sc-inc-gpc");
2532 if (*cmd_name == '(') {
2533 cmd_name++; /* skip the '(' */
2534 rule->arg.gpc.idx = strtoul(cmd_name, &error, 10); /* Convert stick table id. */
2535 if (*error != ',') {
2536 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 +01002537 return ACT_RET_PRS_ERR;
2538 }
Emeric Brun4d7ada82021-06-30 19:04:16 +02002539 else {
2540 cmd_name = error + 1; /* skip the ',' */
2541 rule->arg.gpc.sc = strtol(cmd_name, &error, 10); /* Convert stick table id. */
2542 if (*error != ')') {
2543 memprintf(err, "invalid stick table track ID '%s'. Expects sc-inc-gpc(<GPC ID>,<Track ID>)", args[*arg-1]);
2544 return ACT_RET_PRS_ERR;
2545 }
2546
2547 if (rule->arg.gpc.sc >= MAX_SESS_STKCTR) {
2548 memprintf(err, "invalid stick table track ID '%s'. The max allowed ID is %d",
2549 args[*arg-1], MAX_SESS_STKCTR-1);
2550 return ACT_RET_PRS_ERR;
2551 }
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002552 }
Emeric Brun4d7ada82021-06-30 19:04:16 +02002553 rule->action_ptr = action_inc_gpc;
2554 }
2555 else if (*cmd_name == '0' ||*cmd_name == '1') {
2556 char c = *cmd_name;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002557
Emeric Brun4d7ada82021-06-30 19:04:16 +02002558 cmd_name++;
2559 if (*cmd_name == '\0') {
2560 /* default stick table id. */
2561 rule->arg.gpc.sc = 0;
2562 } else {
2563 /* parse the stick table id. */
2564 if (*cmd_name != '(') {
2565 memprintf(err, "invalid stick table track ID. Expects %s(<Track ID>)", args[*arg-1]);
2566 return ACT_RET_PRS_ERR;
2567 }
2568 cmd_name++; /* jump the '(' */
2569 rule->arg.gpc.sc = strtol(cmd_name, &error, 10); /* Convert stick table id. */
2570 if (*error != ')') {
2571 memprintf(err, "invalid stick table track ID. Expects %s(<Track ID>)", args[*arg-1]);
2572 return ACT_RET_PRS_ERR;
2573 }
2574
2575 if (rule->arg.gpc.sc >= MAX_SESS_STKCTR) {
2576 memprintf(err, "invalid stick table track ID. The max allowed ID is %d",
2577 MAX_SESS_STKCTR-1);
2578 return ACT_RET_PRS_ERR;
2579 }
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002580 }
Emeric Brun4d7ada82021-06-30 19:04:16 +02002581 if (c == '1')
2582 rule->action_ptr = action_inc_gpc1;
2583 else
2584 rule->action_ptr = action_inc_gpc0;
2585 }
2586 else {
2587 /* default stick table id. */
2588 memprintf(err, "invalid gpc ID '%s'. Expects sc-set-gpc(<GPC ID>,<Track ID>)", args[*arg-1]);
2589 return ACT_RET_PRS_ERR;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002590 }
2591 rule->action = ACT_CUSTOM;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002592 return ACT_RET_PRS_OK;
2593}
2594
Emeric Brun877b0b52021-06-30 18:57:49 +02002595/* This function sets the gpt at index 'rule->arg.gpt.idx' of the array on the
2596 * tracksc counter of index 'rule->arg.gpt.sc' stored into the <stream> or
2597 * directly in the session <sess> if <stream> is set to NULL. This gpt is
2598 * set to the value computed by the expression 'rule->arg.gpt.expr' or if
2599 * 'rule->arg.gpt.expr' is null directly to the value of 'rule->arg.gpt.value'.
2600 *
2601 * This function always returns ACT_RET_CONT and parameter flags is unused.
2602 */
2603static enum act_return action_set_gpt(struct act_rule *rule, struct proxy *px,
2604 struct session *sess, struct stream *s, int flags)
2605{
2606 void *ptr;
2607 struct stksess *ts;
2608 struct stkctr *stkctr;
2609 unsigned int value = 0;
2610 struct sample *smp;
2611 int smp_opt_dir;
2612
2613 /* Extract the stksess, return OK if no stksess available. */
2614 if (s)
2615 stkctr = &s->stkctr[rule->arg.gpt.sc];
2616 else
2617 stkctr = &sess->stkctr[rule->arg.gpt.sc];
2618
2619 ts = stkctr_entry(stkctr);
2620 if (!ts)
2621 return ACT_RET_CONT;
2622
2623 /* Store the sample in the required sc, and ignore errors. */
2624 ptr = stktable_data_ptr_idx(stkctr->table, ts, STKTABLE_DT_GPT, rule->arg.gpt.idx);
2625 if (ptr) {
2626
2627 if (!rule->arg.gpt.expr)
2628 value = (unsigned int)(rule->arg.gpt.value);
2629 else {
2630 switch (rule->from) {
2631 case ACT_F_TCP_REQ_SES: smp_opt_dir = SMP_OPT_DIR_REQ; break;
2632 case ACT_F_TCP_REQ_CNT: smp_opt_dir = SMP_OPT_DIR_REQ; break;
2633 case ACT_F_TCP_RES_CNT: smp_opt_dir = SMP_OPT_DIR_RES; break;
2634 case ACT_F_HTTP_REQ: smp_opt_dir = SMP_OPT_DIR_REQ; break;
2635 case ACT_F_HTTP_RES: smp_opt_dir = SMP_OPT_DIR_RES; break;
2636 default:
2637 send_log(px, LOG_ERR, "stick table: internal error while setting gpt%u.", rule->arg.gpt.idx);
2638 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))
2639 ha_alert("stick table: internal error while executing setting gpt%u.\n", rule->arg.gpt.idx);
2640 return ACT_RET_CONT;
2641 }
2642
2643 /* Fetch and cast the expression. */
2644 smp = sample_fetch_as_type(px, sess, s, smp_opt_dir|SMP_OPT_FINAL, rule->arg.gpt.expr, SMP_T_SINT);
2645 if (!smp) {
2646 send_log(px, LOG_WARNING, "stick table: invalid expression or data type while setting gpt%u.", rule->arg.gpt.idx);
2647 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))
2648 ha_alert("stick table: invalid expression or data type while setting gpt%u.\n", rule->arg.gpt.idx);
2649 return ACT_RET_CONT;
2650 }
2651 value = (unsigned int)(smp->data.u.sint);
2652 }
2653
2654 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
2655
2656 stktable_data_cast(ptr, std_t_uint) = value;
2657
2658 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
2659
2660 stktable_touch_local(stkctr->table, ts, 0);
2661 }
2662
2663 return ACT_RET_CONT;
2664}
2665
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002666/* Always returns 1. */
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002667static enum act_return action_set_gpt0(struct act_rule *rule, struct proxy *px,
Willy Tarreau658b85b2015-09-27 10:00:49 +02002668 struct session *sess, struct stream *s, int flags)
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002669{
2670 void *ptr;
2671 struct stksess *ts;
2672 struct stkctr *stkctr;
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002673 unsigned int value = 0;
2674 struct sample *smp;
2675 int smp_opt_dir;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002676
2677 /* Extract the stksess, return OK if no stksess available. */
2678 if (s)
2679 stkctr = &s->stkctr[rule->arg.gpt.sc];
2680 else
2681 stkctr = &sess->stkctr[rule->arg.gpt.sc];
Willy Tarreau79c1e912016-01-25 14:54:45 +01002682
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002683 ts = stkctr_entry(stkctr);
2684 if (!ts)
2685 return ACT_RET_CONT;
2686
2687 /* Store the sample in the required sc, and ignore errors. */
2688 ptr = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPT0);
Emeric Brunf7ab0bf2021-06-30 18:58:22 +02002689 if (!ptr)
2690 ptr = stktable_data_ptr_idx(stkctr->table, ts, STKTABLE_DT_GPT, 0);
2691
Willy Tarreau79c1e912016-01-25 14:54:45 +01002692 if (ptr) {
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002693 if (!rule->arg.gpt.expr)
2694 value = (unsigned int)(rule->arg.gpt.value);
2695 else {
2696 switch (rule->from) {
2697 case ACT_F_TCP_REQ_SES: smp_opt_dir = SMP_OPT_DIR_REQ; break;
2698 case ACT_F_TCP_REQ_CNT: smp_opt_dir = SMP_OPT_DIR_REQ; break;
2699 case ACT_F_TCP_RES_CNT: smp_opt_dir = SMP_OPT_DIR_RES; break;
2700 case ACT_F_HTTP_REQ: smp_opt_dir = SMP_OPT_DIR_REQ; break;
2701 case ACT_F_HTTP_RES: smp_opt_dir = SMP_OPT_DIR_RES; break;
2702 default:
2703 send_log(px, LOG_ERR, "stick table: internal error while setting gpt0.");
2704 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))
2705 ha_alert("stick table: internal error while executing setting gpt0.\n");
2706 return ACT_RET_CONT;
2707 }
2708
2709 /* Fetch and cast the expression. */
2710 smp = sample_fetch_as_type(px, sess, s, smp_opt_dir|SMP_OPT_FINAL, rule->arg.gpt.expr, SMP_T_SINT);
2711 if (!smp) {
2712 send_log(px, LOG_WARNING, "stick table: invalid expression or data type while setting gpt0.");
2713 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))
2714 ha_alert("stick table: invalid expression or data type while setting gpt0.\n");
2715 return ACT_RET_CONT;
2716 }
2717 value = (unsigned int)(smp->data.u.sint);
2718 }
2719
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002720 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002721
Emeric Brun0e3457b2021-06-30 17:18:28 +02002722 stktable_data_cast(ptr, std_t_uint) = value;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002723
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002724 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002725
2726 stktable_touch_local(stkctr->table, ts, 0);
Willy Tarreau79c1e912016-01-25 14:54:45 +01002727 }
2728
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002729 return ACT_RET_CONT;
2730}
2731
Emeric Brun877b0b52021-06-30 18:57:49 +02002732/* This function is a parser for the "sc-set-gpt" and "sc-set-gpt0" actions.
2733 * It understands the formats:
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002734 *
Emeric Brun877b0b52021-06-30 18:57:49 +02002735 * sc-set-gpt(<gpt IDX>,<track ID>) <expression>
2736 * sc-set-gpt0(<track ID>) <expression>
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002737 *
Emeric Brun877b0b52021-06-30 18:57:49 +02002738 * It returns ACT_RET_PRS_ERR if fails and <err> is filled with an error message.
2739 * Otherwise, it returns ACT_RET_PRS_OK and the variable 'rule->arg.gpt.expr'
2740 * is filled with the pointer to the expression to execute or NULL if the arg
2741 * is directly an integer stored into 'rule->arg.gpt.value'.
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002742 */
Emeric Brun877b0b52021-06-30 18:57:49 +02002743static enum act_parse_ret parse_set_gpt(const char **args, int *arg, struct proxy *px,
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002744 struct act_rule *rule, char **err)
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002745{
2746 const char *cmd_name = args[*arg-1];
2747 char *error;
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002748 int smp_val;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002749
Emeric Brun877b0b52021-06-30 18:57:49 +02002750 cmd_name += strlen("sc-set-gpt");
2751 if (*cmd_name == '(') {
2752 cmd_name++; /* skip the '(' */
2753 rule->arg.gpt.idx = strtoul(cmd_name, &error, 10); /* Convert stick table id. */
2754 if (*error != ',') {
2755 memprintf(err, "Missing gpt ID '%s'. Expects sc-set-gpt(<GPT ID>,<Track ID>)", args[*arg-1]);
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002756 return ACT_RET_PRS_ERR;
2757 }
Emeric Brun877b0b52021-06-30 18:57:49 +02002758 else {
2759 cmd_name = error + 1; /* skip the ',' */
2760 rule->arg.gpt.sc = strtol(cmd_name, &error, 10); /* Convert stick table id. */
2761 if (*error != ')') {
2762 memprintf(err, "invalid stick table track ID '%s'. Expects sc-set-gpt(<GPT ID>,<Track ID>)", args[*arg-1]);
2763 return ACT_RET_PRS_ERR;
2764 }
2765
2766 if (rule->arg.gpt.sc >= MAX_SESS_STKCTR) {
2767 memprintf(err, "invalid stick table track ID '%s'. The max allowed ID is %d",
2768 args[*arg-1], MAX_SESS_STKCTR-1);
2769 return ACT_RET_PRS_ERR;
2770 }
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002771 }
Emeric Brun877b0b52021-06-30 18:57:49 +02002772 rule->action_ptr = action_set_gpt;
2773 }
2774 else if (*cmd_name == '0') {
2775 cmd_name++;
2776 if (*cmd_name == '\0') {
2777 /* default stick table id. */
2778 rule->arg.gpt.sc = 0;
2779 } else {
2780 /* parse the stick table id. */
2781 if (*cmd_name != '(') {
2782 memprintf(err, "invalid stick table track ID '%s'. Expects sc-set-gpt0(<Track ID>)", args[*arg-1]);
2783 return ACT_RET_PRS_ERR;
2784 }
2785 cmd_name++; /* jump the '(' */
2786 rule->arg.gpt.sc = strtol(cmd_name, &error, 10); /* Convert stick table id. */
2787 if (*error != ')') {
2788 memprintf(err, "invalid stick table track ID '%s'. Expects sc-set-gpt0(<Track ID>)", args[*arg-1]);
2789 return ACT_RET_PRS_ERR;
2790 }
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002791
Emeric Brun877b0b52021-06-30 18:57:49 +02002792 if (rule->arg.gpt.sc >= MAX_SESS_STKCTR) {
2793 memprintf(err, "invalid stick table track ID '%s'. The max allowed ID is %d",
2794 args[*arg-1], MAX_SESS_STKCTR-1);
2795 return ACT_RET_PRS_ERR;
2796 }
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002797 }
Emeric Brun877b0b52021-06-30 18:57:49 +02002798 rule->action_ptr = action_set_gpt0;
2799 }
2800 else {
2801 /* default stick table id. */
2802 memprintf(err, "invalid gpt ID '%s'. Expects sc-set-gpt(<GPT ID>,<Track ID>)", args[*arg-1]);
2803 return ACT_RET_PRS_ERR;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002804 }
2805
Willy Tarreauece4c4a2021-08-24 14:57:28 +02002806 /* value may be either an integer or an expression */
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002807 rule->arg.gpt.expr = NULL;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002808 rule->arg.gpt.value = strtol(args[*arg], &error, 10);
Willy Tarreauece4c4a2021-08-24 14:57:28 +02002809 if (*error == '\0') {
2810 /* valid integer, skip it */
2811 (*arg)++;
2812 } else {
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002813 rule->arg.gpt.expr = sample_parse_expr((char **)args, arg, px->conf.args.file,
Willy Tarreaue3b57bf2020-02-14 16:50:14 +01002814 px->conf.args.line, err, &px->conf.args, NULL);
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002815 if (!rule->arg.gpt.expr)
2816 return ACT_RET_PRS_ERR;
2817
2818 switch (rule->from) {
2819 case ACT_F_TCP_REQ_SES: smp_val = SMP_VAL_FE_SES_ACC; break;
2820 case ACT_F_TCP_REQ_CNT: smp_val = SMP_VAL_FE_REQ_CNT; break;
2821 case ACT_F_TCP_RES_CNT: smp_val = SMP_VAL_BE_RES_CNT; break;
2822 case ACT_F_HTTP_REQ: smp_val = SMP_VAL_FE_HRQ_HDR; break;
2823 case ACT_F_HTTP_RES: smp_val = SMP_VAL_BE_HRS_HDR; break;
2824 default:
2825 memprintf(err, "internal error, unexpected rule->from=%d, please report this bug!", rule->from);
2826 return ACT_RET_PRS_ERR;
2827 }
2828 if (!(rule->arg.gpt.expr->fetch->val & smp_val)) {
2829 memprintf(err, "fetch method '%s' extracts information from '%s', none of which is available here", args[*arg-1],
2830 sample_src_names(rule->arg.gpt.expr->fetch->use));
2831 free(rule->arg.gpt.expr);
2832 return ACT_RET_PRS_ERR;
2833 }
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002834 }
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002835
Thierry FOURNIER42148732015-09-02 17:17:33 +02002836 rule->action = ACT_CUSTOM;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002837
2838 return ACT_RET_PRS_OK;
2839}
2840
Willy Tarreau7d562212016-11-25 16:10:05 +01002841/* set temp integer to the number of used entries in the table pointed to by expr.
2842 * Accepts exactly 1 argument of type table.
2843 */
2844static int
2845smp_fetch_table_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
2846{
2847 smp->flags = SMP_F_VOL_TEST;
2848 smp->data.type = SMP_T_SINT;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002849 smp->data.u.sint = args->data.t->current;
Willy Tarreau7d562212016-11-25 16:10:05 +01002850 return 1;
2851}
2852
2853/* set temp integer to the number of free entries in the table pointed to by expr.
2854 * Accepts exactly 1 argument of type table.
2855 */
2856static int
2857smp_fetch_table_avl(const struct arg *args, struct sample *smp, const char *kw, void *private)
2858{
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002859 struct stktable *t;
Willy Tarreau7d562212016-11-25 16:10:05 +01002860
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002861 t = args->data.t;
Willy Tarreau7d562212016-11-25 16:10:05 +01002862 smp->flags = SMP_F_VOL_TEST;
2863 smp->data.type = SMP_T_SINT;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002864 smp->data.u.sint = t->size - t->current;
Willy Tarreau7d562212016-11-25 16:10:05 +01002865 return 1;
2866}
2867
2868/* Returns a pointer to a stkctr depending on the fetch keyword name.
2869 * It is designed to be called as sc[0-9]_* sc_* or src_* exclusively.
2870 * sc[0-9]_* will return a pointer to the respective field in the
2871 * stream <l4>. sc_* requires an UINT argument specifying the stick
2872 * counter number. src_* will fill a locally allocated structure with
2873 * the table and entry corresponding to what is specified with src_*.
2874 * NULL may be returned if the designated stkctr is not tracked. For
2875 * the sc_* and sc[0-9]_* forms, an optional table argument may be
2876 * passed. When present, the currently tracked key is then looked up
2877 * in the specified table instead of the current table. The purpose is
Ilya Shipitsin47d17182020-06-21 21:42:57 +05002878 * to be able to convert multiple values per key (eg: have gpc0 from
Willy Tarreau7d562212016-11-25 16:10:05 +01002879 * multiple tables). <strm> is allowed to be NULL, in which case only
2880 * the session will be consulted.
2881 */
2882struct stkctr *
Emeric Brun819fc6f2017-06-13 19:37:32 +02002883smp_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 +01002884{
Willy Tarreau7d562212016-11-25 16:10:05 +01002885 struct stkctr *stkptr;
2886 struct stksess *stksess;
2887 unsigned int num = kw[2] - '0';
2888 int arg = 0;
2889
2890 if (num == '_' - '0') {
2891 /* sc_* variant, args[0] = ctr# (mandatory) */
2892 num = args[arg++].data.sint;
Willy Tarreau7d562212016-11-25 16:10:05 +01002893 }
2894 else if (num > 9) { /* src_* variant, args[0] = table */
2895 struct stktable_key *key;
2896 struct connection *conn = objt_conn(sess->origin);
2897 struct sample smp;
2898
2899 if (!conn)
2900 return NULL;
2901
Joseph Herlant5662fa42018-11-15 13:43:28 -08002902 /* Fetch source address in a sample. */
Willy Tarreau7d562212016-11-25 16:10:05 +01002903 smp.px = NULL;
2904 smp.sess = sess;
2905 smp.strm = strm;
Amaury Denoyellec460c702021-05-12 10:17:47 +02002906 if (!smp_fetch_src || !smp_fetch_src(empty_arg_list, &smp, "src", NULL))
Willy Tarreau7d562212016-11-25 16:10:05 +01002907 return NULL;
2908
2909 /* Converts into key. */
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002910 key = smp_to_stkey(&smp, args->data.t);
Willy Tarreau7d562212016-11-25 16:10:05 +01002911 if (!key)
2912 return NULL;
2913
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002914 stkctr->table = args->data.t;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002915 stkctr_set_entry(stkctr, stktable_lookup_key(stkctr->table, key));
2916 return stkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002917 }
2918
2919 /* Here, <num> contains the counter number from 0 to 9 for
2920 * the sc[0-9]_ form, or even higher using sc_(num) if needed.
2921 * args[arg] is the first optional argument. We first lookup the
2922 * ctr form the stream, then from the session if it was not there.
Christopher Fauleta9fa88a2019-10-21 10:53:34 +02002923 * But we must be sure the counter does not exceed MAX_SESS_STKCTR.
Willy Tarreau7d562212016-11-25 16:10:05 +01002924 */
Christopher Fauleta9fa88a2019-10-21 10:53:34 +02002925 if (num >= MAX_SESS_STKCTR)
2926 return NULL;
Willy Tarreau7d562212016-11-25 16:10:05 +01002927
2928 if (strm)
2929 stkptr = &strm->stkctr[num];
2930 if (!strm || !stkctr_entry(stkptr)) {
2931 stkptr = &sess->stkctr[num];
2932 if (!stkctr_entry(stkptr))
2933 return NULL;
2934 }
2935
2936 stksess = stkctr_entry(stkptr);
2937 if (!stksess)
2938 return NULL;
2939
2940 if (unlikely(args[arg].type == ARGT_TAB)) {
2941 /* an alternate table was specified, let's look up the same key there */
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002942 stkctr->table = args[arg].data.t;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002943 stkctr_set_entry(stkctr, stktable_lookup(stkctr->table, stksess));
2944 return stkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002945 }
2946 return stkptr;
2947}
2948
2949/* same as smp_fetch_sc_stkctr() but dedicated to src_* and can create
2950 * the entry if it doesn't exist yet. This is needed for a few fetch
2951 * functions which need to create an entry, such as src_inc_gpc* and
2952 * src_clr_gpc*.
2953 */
2954struct stkctr *
Emeric Brun819fc6f2017-06-13 19:37:32 +02002955smp_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 +01002956{
Willy Tarreau7d562212016-11-25 16:10:05 +01002957 struct stktable_key *key;
2958 struct connection *conn = objt_conn(sess->origin);
2959 struct sample smp;
2960
2961 if (strncmp(kw, "src_", 4) != 0)
2962 return NULL;
2963
2964 if (!conn)
2965 return NULL;
2966
Joseph Herlant5662fa42018-11-15 13:43:28 -08002967 /* Fetch source address in a sample. */
Willy Tarreau7d562212016-11-25 16:10:05 +01002968 smp.px = NULL;
2969 smp.sess = sess;
2970 smp.strm = strm;
Amaury Denoyellec460c702021-05-12 10:17:47 +02002971 if (!smp_fetch_src || !smp_fetch_src(empty_arg_list, &smp, "src", NULL))
Willy Tarreau7d562212016-11-25 16:10:05 +01002972 return NULL;
2973
2974 /* Converts into key. */
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002975 key = smp_to_stkey(&smp, args->data.t);
Willy Tarreau7d562212016-11-25 16:10:05 +01002976 if (!key)
2977 return NULL;
2978
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002979 stkctr->table = args->data.t;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002980 stkctr_set_entry(stkctr, stktable_get_entry(stkctr->table, key));
2981 return stkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002982}
2983
2984/* set return a boolean indicating if the requested stream counter is
2985 * currently being tracked or not.
2986 * Supports being called as "sc[0-9]_tracked" only.
2987 */
2988static int
2989smp_fetch_sc_tracked(const struct arg *args, struct sample *smp, const char *kw, void *private)
2990{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002991 struct stkctr tmpstkctr;
2992 struct stkctr *stkctr;
2993
Willy Tarreau7d562212016-11-25 16:10:05 +01002994 smp->flags = SMP_F_VOL_TEST;
2995 smp->data.type = SMP_T_BOOL;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002996 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2997 smp->data.u.sint = !!stkctr;
2998
2999 /* release the ref count */
Dirkjan Bussinkff57f1b2018-09-14 14:31:22 +02003000 if (stkctr == &tmpstkctr)
Emeric Brun819fc6f2017-06-13 19:37:32 +02003001 stktable_release(stkctr->table, stkctr_entry(stkctr));
3002
Emeric Brun877b0b52021-06-30 18:57:49 +02003003 return 1;
3004}
3005
3006/* set <smp> to the General Purpose Tag of index set as first arg
3007 * to value from the stream's tracked frontend counters or from the src.
3008 * Supports being called as "sc_get_gpt(<gpt-idx>,<sc-idx>[,<table>])" or
3009 * "src_get_gpt(<gpt-idx>[,<table>])" only. Value zero is returned if
3010 * the key is new or gpt is not stored.
3011 */
3012static int
3013smp_fetch_sc_get_gpt(const struct arg *args, struct sample *smp, const char *kw, void *private)
3014{
3015 struct stkctr tmpstkctr;
3016 struct stkctr *stkctr;
3017 unsigned int idx;
3018
3019 idx = args[0].data.sint;
3020
3021 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args + 1, kw, &tmpstkctr);
3022 if (!stkctr)
3023 return 0;
3024
3025 smp->flags = SMP_F_VOL_TEST;
3026 smp->data.type = SMP_T_SINT;
3027 smp->data.u.sint = 0;
3028
3029 if (stkctr_entry(stkctr)) {
3030 void *ptr;
3031
3032 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPT, idx);
3033 if (!ptr) {
3034 if (stkctr == &tmpstkctr)
3035 stktable_release(stkctr->table, stkctr_entry(stkctr));
3036 return 0; /* parameter not stored */
3037 }
3038
3039 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3040
3041 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
3042
3043 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3044
3045 if (stkctr == &tmpstkctr)
3046 stktable_release(stkctr->table, stkctr_entry(stkctr));
3047 }
Willy Tarreau7d562212016-11-25 16:10:05 +01003048 return 1;
3049}
3050
3051/* set <smp> to the General Purpose Flag 0 value from the stream's tracked
3052 * frontend counters or from the src.
3053 * Supports being called as "sc[0-9]_get_gpc0" or "src_get_gpt0" only. Value
3054 * zero is returned if the key is new.
3055 */
3056static int
3057smp_fetch_sc_get_gpt0(const struct arg *args, struct sample *smp, const char *kw, void *private)
3058{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003059 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003060 struct stkctr *stkctr;
3061
Emeric Brun819fc6f2017-06-13 19:37:32 +02003062 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003063 if (!stkctr)
3064 return 0;
3065
3066 smp->flags = SMP_F_VOL_TEST;
3067 smp->data.type = SMP_T_SINT;
3068 smp->data.u.sint = 0;
3069
Emeric Brun819fc6f2017-06-13 19:37:32 +02003070 if (stkctr_entry(stkctr)) {
3071 void *ptr;
3072
3073 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPT0);
Emeric Brunf7ab0bf2021-06-30 18:58:22 +02003074 if (!ptr)
3075 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPT, 0);
3076
Emeric Brun4d7ada82021-06-30 19:04:16 +02003077 if (!ptr) {
3078 if (stkctr == &tmpstkctr)
3079 stktable_release(stkctr->table, stkctr_entry(stkctr));
3080 return 0; /* parameter not stored */
3081 }
3082
3083 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3084
3085 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
3086
3087 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3088
3089 if (stkctr == &tmpstkctr)
3090 stktable_release(stkctr->table, stkctr_entry(stkctr));
3091 }
3092 return 1;
3093}
3094
3095/* set <smp> to the GPC[args(0)]'s value from the stream's tracked
3096 * frontend counters or from the src.
3097 * Supports being called as "sc_get_gpc(<gpc-idx>,<sc-idx>[,<table>])" or
3098 * "src_get_gpc(<gpc-idx>[,<table>])" only. Value
3099 * Value zero is returned if the key is new or gpc is not stored.
3100 */
3101static int
3102smp_fetch_sc_get_gpc(const struct arg *args, struct sample *smp, const char *kw, void *private)
3103{
3104 struct stkctr tmpstkctr;
3105 struct stkctr *stkctr;
3106 unsigned int idx;
3107
3108 idx = args[0].data.sint;
3109
3110 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args + 1, kw, &tmpstkctr);
3111 if (!stkctr)
3112 return 0;
3113
3114 smp->flags = SMP_F_VOL_TEST;
3115 smp->data.type = SMP_T_SINT;
3116 smp->data.u.sint = 0;
3117
3118 if (stkctr_entry(stkctr) != NULL) {
3119 void *ptr;
3120
3121 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC, idx);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003122 if (!ptr) {
3123 if (stkctr == &tmpstkctr)
3124 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003125 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003126 }
3127
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003128 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003129
Emeric Brun0e3457b2021-06-30 17:18:28 +02003130 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003131
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003132 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003133
3134 if (stkctr == &tmpstkctr)
3135 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003136 }
3137 return 1;
3138}
3139
3140/* set <smp> to the General Purpose Counter 0 value from the stream's tracked
3141 * frontend counters or from the src.
3142 * Supports being called as "sc[0-9]_get_gpc0" or "src_get_gpc0" only. Value
3143 * zero is returned if the key is new.
3144 */
3145static int
3146smp_fetch_sc_get_gpc0(const struct arg *args, struct sample *smp, const char *kw, void *private)
3147{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003148 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003149 struct stkctr *stkctr;
3150
Emeric Brun819fc6f2017-06-13 19:37:32 +02003151 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003152 if (!stkctr)
3153 return 0;
3154
3155 smp->flags = SMP_F_VOL_TEST;
3156 smp->data.type = SMP_T_SINT;
3157 smp->data.u.sint = 0;
3158
3159 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003160 void *ptr;
3161
3162 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0);
3163 if (!ptr) {
Emeric Brun726783d2021-06-30 19:06:43 +02003164 /* fallback on the gpc array */
3165 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC, 0);
3166 }
3167
3168 if (!ptr) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003169 if (stkctr == &tmpstkctr)
3170 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003171 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003172 }
3173
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003174 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003175
Emeric Brun0e3457b2021-06-30 17:18:28 +02003176 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003177
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003178 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003179
3180 if (stkctr == &tmpstkctr)
3181 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003182 }
3183 return 1;
3184}
3185
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003186/* set <smp> to the General Purpose Counter 1 value from the stream's tracked
3187 * frontend counters or from the src.
3188 * Supports being called as "sc[0-9]_get_gpc1" or "src_get_gpc1" only. Value
3189 * zero is returned if the key is new.
3190 */
3191static int
3192smp_fetch_sc_get_gpc1(const struct arg *args, struct sample *smp, const char *kw, void *private)
3193{
3194 struct stkctr tmpstkctr;
3195 struct stkctr *stkctr;
3196
3197 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
3198 if (!stkctr)
3199 return 0;
3200
3201 smp->flags = SMP_F_VOL_TEST;
3202 smp->data.type = SMP_T_SINT;
3203 smp->data.u.sint = 0;
3204
3205 if (stkctr_entry(stkctr) != NULL) {
3206 void *ptr;
3207
3208 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1);
3209 if (!ptr) {
Emeric Brun726783d2021-06-30 19:06:43 +02003210 /* fallback on the gpc array */
3211 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC, 1);
3212 }
3213
3214 if (!ptr) {
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003215 if (stkctr == &tmpstkctr)
3216 stktable_release(stkctr->table, stkctr_entry(stkctr));
3217 return 0; /* parameter not stored */
3218 }
3219
3220 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3221
Emeric Brun0e3457b2021-06-30 17:18:28 +02003222 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003223
3224 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3225
3226 if (stkctr == &tmpstkctr)
3227 stktable_release(stkctr->table, stkctr_entry(stkctr));
3228 }
3229 return 1;
3230}
3231
Emeric Brun4d7ada82021-06-30 19:04:16 +02003232/* set <smp> to the GPC[args(0)]'s event rate from the stream's
3233 * tracked frontend counters or from the src.
3234 * Supports being called as "sc_gpc_rate(<gpc-idx>,<sc-idx>[,<table])"
3235 * or "src_gpc_rate(<gpc-idx>[,<table>])" only.
3236 * Value zero is returned if the key is new or gpc_rate is not stored.
3237 */
3238static int
3239smp_fetch_sc_gpc_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3240{
3241 struct stkctr tmpstkctr;
3242 struct stkctr *stkctr;
3243 unsigned int idx;
3244
3245 idx = args[0].data.sint;
3246
3247 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args + 1, kw, &tmpstkctr);
3248 if (!stkctr)
3249 return 0;
3250
3251 smp->flags = SMP_F_VOL_TEST;
3252 smp->data.type = SMP_T_SINT;
3253 smp->data.u.sint = 0;
3254 if (stkctr_entry(stkctr) != NULL) {
3255 void *ptr;
3256
3257 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC_RATE, idx);
3258 if (!ptr) {
3259 if (stkctr == &tmpstkctr)
3260 stktable_release(stkctr->table, stkctr_entry(stkctr));
3261 return 0; /* parameter not stored */
3262 }
3263
3264 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3265
3266 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
3267 stkctr->table->data_arg[STKTABLE_DT_GPC_RATE].u);
3268
3269 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3270
3271 if (stkctr == &tmpstkctr)
3272 stktable_release(stkctr->table, stkctr_entry(stkctr));
3273 }
3274 return 1;
3275}
3276
Willy Tarreau7d562212016-11-25 16:10:05 +01003277/* set <smp> to the General Purpose Counter 0's event rate from the stream's
3278 * tracked frontend counters or from the src.
3279 * Supports being called as "sc[0-9]_gpc0_rate" or "src_gpc0_rate" only.
3280 * Value zero is returned if the key is new.
3281 */
3282static int
3283smp_fetch_sc_gpc0_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3284{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003285 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003286 struct stkctr *stkctr;
Emeric Brun726783d2021-06-30 19:06:43 +02003287 unsigned int period;
Willy Tarreau7d562212016-11-25 16:10:05 +01003288
Emeric Brun819fc6f2017-06-13 19:37:32 +02003289 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003290 if (!stkctr)
3291 return 0;
3292
3293 smp->flags = SMP_F_VOL_TEST;
3294 smp->data.type = SMP_T_SINT;
3295 smp->data.u.sint = 0;
3296 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003297 void *ptr;
3298
3299 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0_RATE);
Emeric Brun726783d2021-06-30 19:06:43 +02003300 if (ptr) {
3301 period = stkctr->table->data_arg[STKTABLE_DT_GPC0_RATE].u;
3302 }
3303 else {
3304 /* fallback on the gpc array */
3305 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC_RATE, 0);
3306 if (ptr)
3307 period = stkctr->table->data_arg[STKTABLE_DT_GPC_RATE].u;
3308 }
3309
Emeric Brun819fc6f2017-06-13 19:37:32 +02003310 if (!ptr) {
3311 if (stkctr == &tmpstkctr)
3312 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003313 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003314 }
3315
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003316 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003317
Emeric Brun726783d2021-06-30 19:06:43 +02003318 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp), period);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003319
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003320 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003321
3322 if (stkctr == &tmpstkctr)
3323 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003324 }
3325 return 1;
3326}
3327
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003328/* set <smp> to the General Purpose Counter 1's event rate from the stream's
3329 * tracked frontend counters or from the src.
3330 * Supports being called as "sc[0-9]_gpc1_rate" or "src_gpc1_rate" only.
3331 * Value zero is returned if the key is new.
3332 */
3333static int
3334smp_fetch_sc_gpc1_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3335{
3336 struct stkctr tmpstkctr;
3337 struct stkctr *stkctr;
Emeric Brun726783d2021-06-30 19:06:43 +02003338 unsigned int period;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003339
3340 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
3341 if (!stkctr)
3342 return 0;
3343
3344 smp->flags = SMP_F_VOL_TEST;
3345 smp->data.type = SMP_T_SINT;
3346 smp->data.u.sint = 0;
3347 if (stkctr_entry(stkctr) != NULL) {
3348 void *ptr;
3349
3350 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1_RATE);
Emeric Brun726783d2021-06-30 19:06:43 +02003351 if (ptr) {
3352 period = stkctr->table->data_arg[STKTABLE_DT_GPC1_RATE].u;
3353 }
3354 else {
3355 /* fallback on the gpc array */
3356 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC_RATE, 1);
3357 if (ptr)
3358 period = stkctr->table->data_arg[STKTABLE_DT_GPC_RATE].u;
3359 }
3360
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003361 if (!ptr) {
3362 if (stkctr == &tmpstkctr)
3363 stktable_release(stkctr->table, stkctr_entry(stkctr));
3364 return 0; /* parameter not stored */
3365 }
3366
3367 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3368
Emeric Brun726783d2021-06-30 19:06:43 +02003369 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 +01003370
3371 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3372
3373 if (stkctr == &tmpstkctr)
3374 stktable_release(stkctr->table, stkctr_entry(stkctr));
3375 }
3376 return 1;
3377}
3378
Emeric Brun4d7ada82021-06-30 19:04:16 +02003379/* Increment the GPC[args(0)] value from the stream's tracked
3380 * frontend counters and return it into temp integer.
3381 * Supports being called as "sc_inc_gpc(<gpc-idx>,<sc-idx>[,<table>])"
3382 * or "src_inc_gpc(<gpc-idx>[,<table>])" only.
3383 */
3384static int
3385smp_fetch_sc_inc_gpc(const struct arg *args, struct sample *smp, const char *kw, void *private)
3386{
3387 struct stkctr tmpstkctr;
3388 struct stkctr *stkctr;
3389 unsigned int idx;
3390
3391 idx = args[0].data.sint;
3392
3393 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args + 1, kw, &tmpstkctr);
3394 if (!stkctr)
3395 return 0;
3396
3397 smp->flags = SMP_F_VOL_TEST;
3398 smp->data.type = SMP_T_SINT;
3399 smp->data.u.sint = 0;
3400
3401 if (!stkctr_entry(stkctr))
3402 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
3403
3404 if (stkctr && stkctr_entry(stkctr)) {
3405 void *ptr1,*ptr2;
3406
3407
3408 /* First, update gpc0_rate if it's tracked. Second, update its
3409 * gpc0 if tracked. Returns gpc0's value otherwise the curr_ctr.
3410 */
3411 ptr1 = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC_RATE, idx);
3412 ptr2 = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC, idx);
3413 if (ptr1 || ptr2) {
3414 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3415
3416 if (ptr1) {
3417 update_freq_ctr_period(&stktable_data_cast(ptr1, std_t_frqp),
3418 stkctr->table->data_arg[STKTABLE_DT_GPC_RATE].u, 1);
3419 smp->data.u.sint = (&stktable_data_cast(ptr1, std_t_frqp))->curr_ctr;
3420 }
3421
3422 if (ptr2)
3423 smp->data.u.sint = ++stktable_data_cast(ptr2, std_t_uint);
3424
3425 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3426
3427 /* If data was modified, we need to touch to re-schedule sync */
3428 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
3429 }
3430 else if (stkctr == &tmpstkctr)
3431 stktable_release(stkctr->table, stkctr_entry(stkctr));
3432 }
3433 return 1;
3434}
3435
Willy Tarreau7d562212016-11-25 16:10:05 +01003436/* Increment the General Purpose Counter 0 value from the stream's tracked
3437 * frontend counters and return it into temp integer.
3438 * Supports being called as "sc[0-9]_inc_gpc0" or "src_inc_gpc0" only.
3439 */
3440static int
3441smp_fetch_sc_inc_gpc0(const struct arg *args, struct sample *smp, const char *kw, void *private)
3442{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003443 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003444 struct stkctr *stkctr;
Willy Tarreau5b654ad2021-07-06 18:51:12 +02003445 unsigned int period = 0;
Willy Tarreau7d562212016-11-25 16:10:05 +01003446
Emeric Brun819fc6f2017-06-13 19:37:32 +02003447 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003448 if (!stkctr)
3449 return 0;
3450
3451 smp->flags = SMP_F_VOL_TEST;
3452 smp->data.type = SMP_T_SINT;
3453 smp->data.u.sint = 0;
3454
Emeric Brun819fc6f2017-06-13 19:37:32 +02003455 if (!stkctr_entry(stkctr))
3456 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003457
3458 if (stkctr && stkctr_entry(stkctr)) {
3459 void *ptr1,*ptr2;
3460
Emeric Brun819fc6f2017-06-13 19:37:32 +02003461
Willy Tarreau7d562212016-11-25 16:10:05 +01003462 /* First, update gpc0_rate if it's tracked. Second, update its
3463 * gpc0 if tracked. Returns gpc0's value otherwise the curr_ctr.
3464 */
3465 ptr1 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0_RATE);
Emeric Brun726783d2021-06-30 19:06:43 +02003466 if (ptr1) {
3467 period = stkctr->table->data_arg[STKTABLE_DT_GPC0_RATE].u;
3468 }
3469 else {
3470 /* fallback on the gpc array */
3471 ptr1 = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC_RATE, 0);
3472 if (ptr1)
3473 period = stkctr->table->data_arg[STKTABLE_DT_GPC_RATE].u;
3474 }
3475
Willy Tarreau7d562212016-11-25 16:10:05 +01003476 ptr2 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0);
Emeric Brun726783d2021-06-30 19:06:43 +02003477 if (!ptr2) {
3478 /* fallback on the gpc array */
3479 ptr2 = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC, 0);
3480 }
3481
Emeric Brun819fc6f2017-06-13 19:37:32 +02003482 if (ptr1 || ptr2) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003483 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Willy Tarreau7d562212016-11-25 16:10:05 +01003484
Emeric Brun819fc6f2017-06-13 19:37:32 +02003485 if (ptr1) {
Emeric Brun0e3457b2021-06-30 17:18:28 +02003486 update_freq_ctr_period(&stktable_data_cast(ptr1, std_t_frqp),
Emeric Brun726783d2021-06-30 19:06:43 +02003487 period, 1);
Emeric Brun0e3457b2021-06-30 17:18:28 +02003488 smp->data.u.sint = (&stktable_data_cast(ptr1, std_t_frqp))->curr_ctr;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003489 }
3490
3491 if (ptr2)
Emeric Brun0e3457b2021-06-30 17:18:28 +02003492 smp->data.u.sint = ++stktable_data_cast(ptr2, std_t_uint);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003493
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003494 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003495
3496 /* If data was modified, we need to touch to re-schedule sync */
3497 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
3498 }
3499 else if (stkctr == &tmpstkctr)
3500 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003501 }
3502 return 1;
3503}
3504
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003505/* Increment the General Purpose Counter 1 value from the stream's tracked
3506 * frontend counters and return it into temp integer.
3507 * Supports being called as "sc[0-9]_inc_gpc1" or "src_inc_gpc1" only.
3508 */
3509static int
3510smp_fetch_sc_inc_gpc1(const struct arg *args, struct sample *smp, const char *kw, void *private)
3511{
3512 struct stkctr tmpstkctr;
3513 struct stkctr *stkctr;
Willy Tarreau5b654ad2021-07-06 18:51:12 +02003514 unsigned int period = 0;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003515
3516 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
3517 if (!stkctr)
3518 return 0;
3519
3520 smp->flags = SMP_F_VOL_TEST;
3521 smp->data.type = SMP_T_SINT;
3522 smp->data.u.sint = 0;
3523
3524 if (!stkctr_entry(stkctr))
3525 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
3526
3527 if (stkctr && stkctr_entry(stkctr)) {
3528 void *ptr1,*ptr2;
3529
3530
3531 /* First, update gpc1_rate if it's tracked. Second, update its
3532 * gpc1 if tracked. Returns gpc1's value otherwise the curr_ctr.
3533 */
3534 ptr1 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1_RATE);
Emeric Brun726783d2021-06-30 19:06:43 +02003535 if (ptr1) {
3536 period = stkctr->table->data_arg[STKTABLE_DT_GPC1_RATE].u;
3537 }
3538 else {
3539 /* fallback on the gpc array */
3540 ptr1 = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC_RATE, 1);
3541 if (ptr1)
3542 period = stkctr->table->data_arg[STKTABLE_DT_GPC_RATE].u;
3543 }
3544
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003545 ptr2 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1);
Emeric Brun726783d2021-06-30 19:06:43 +02003546 if (!ptr2) {
3547 /* fallback on the gpc array */
3548 ptr2 = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC, 1);
3549 }
3550
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003551 if (ptr1 || ptr2) {
3552 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3553
3554 if (ptr1) {
Emeric Brun0e3457b2021-06-30 17:18:28 +02003555 update_freq_ctr_period(&stktable_data_cast(ptr1, std_t_frqp),
Emeric Brun726783d2021-06-30 19:06:43 +02003556 period, 1);
Emeric Brun0e3457b2021-06-30 17:18:28 +02003557 smp->data.u.sint = (&stktable_data_cast(ptr1, std_t_frqp))->curr_ctr;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003558 }
3559
3560 if (ptr2)
Emeric Brun0e3457b2021-06-30 17:18:28 +02003561 smp->data.u.sint = ++stktable_data_cast(ptr2, std_t_uint);
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003562
3563 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3564
3565 /* If data was modified, we need to touch to re-schedule sync */
3566 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
3567 }
3568 else if (stkctr == &tmpstkctr)
3569 stktable_release(stkctr->table, stkctr_entry(stkctr));
3570 }
3571 return 1;
3572}
3573
Emeric Brun4d7ada82021-06-30 19:04:16 +02003574/* Clear the GPC[args(0)] value from the stream's tracked
3575 * frontend counters and return its previous value into temp integer.
3576 * Supports being called as "sc_clr_gpc(<gpc-idx>,<sc-idx>[,<table>])"
3577 * or "src_clr_gpc(<gpc-idx>[,<table>])" only.
3578 */
3579static int
3580smp_fetch_sc_clr_gpc(const struct arg *args, struct sample *smp, const char *kw, void *private)
3581{
3582 struct stkctr tmpstkctr;
3583 struct stkctr *stkctr;
3584 unsigned int idx;
3585
3586 idx = args[0].data.sint;
3587
3588 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args + 1, kw, &tmpstkctr);
3589 if (!stkctr)
3590 return 0;
3591
3592 smp->flags = SMP_F_VOL_TEST;
3593 smp->data.type = SMP_T_SINT;
3594 smp->data.u.sint = 0;
3595
3596 if (!stkctr_entry(stkctr))
3597 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
3598
3599 if (stkctr && stkctr_entry(stkctr)) {
3600 void *ptr;
3601
3602 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC, idx);
3603 if (!ptr) {
3604 if (stkctr == &tmpstkctr)
3605 stktable_release(stkctr->table, stkctr_entry(stkctr));
3606 return 0; /* parameter not stored */
3607 }
3608
3609 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3610
3611 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
3612 stktable_data_cast(ptr, std_t_uint) = 0;
3613
3614 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3615
3616 /* If data was modified, we need to touch to re-schedule sync */
3617 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
3618 }
3619 return 1;
3620}
3621
Willy Tarreau7d562212016-11-25 16:10:05 +01003622/* Clear the General Purpose Counter 0 value from the stream's tracked
3623 * frontend counters and return its previous value into temp integer.
3624 * Supports being called as "sc[0-9]_clr_gpc0" or "src_clr_gpc0" only.
3625 */
3626static int
3627smp_fetch_sc_clr_gpc0(const struct arg *args, struct sample *smp, const char *kw, void *private)
3628{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003629 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003630 struct stkctr *stkctr;
3631
Emeric Brun819fc6f2017-06-13 19:37:32 +02003632 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003633 if (!stkctr)
3634 return 0;
3635
3636 smp->flags = SMP_F_VOL_TEST;
3637 smp->data.type = SMP_T_SINT;
3638 smp->data.u.sint = 0;
3639
Emeric Brun819fc6f2017-06-13 19:37:32 +02003640 if (!stkctr_entry(stkctr))
3641 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003642
Emeric Brun819fc6f2017-06-13 19:37:32 +02003643 if (stkctr && stkctr_entry(stkctr)) {
3644 void *ptr;
3645
3646 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0);
3647 if (!ptr) {
Emeric Brun726783d2021-06-30 19:06:43 +02003648 /* fallback on the gpc array */
3649 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC, 0);
3650 }
3651
3652 if (!ptr) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003653 if (stkctr == &tmpstkctr)
3654 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003655 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003656 }
3657
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003658 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003659
Emeric Brun0e3457b2021-06-30 17:18:28 +02003660 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
3661 stktable_data_cast(ptr, std_t_uint) = 0;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003662
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003663 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003664
Willy Tarreau7d562212016-11-25 16:10:05 +01003665 /* If data was modified, we need to touch to re-schedule sync */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003666 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
Willy Tarreau7d562212016-11-25 16:10:05 +01003667 }
3668 return 1;
3669}
3670
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003671/* Clear the General Purpose Counter 1 value from the stream's tracked
3672 * frontend counters and return its previous value into temp integer.
3673 * Supports being called as "sc[0-9]_clr_gpc1" or "src_clr_gpc1" only.
3674 */
3675static int
3676smp_fetch_sc_clr_gpc1(const struct arg *args, struct sample *smp, const char *kw, void *private)
3677{
3678 struct stkctr tmpstkctr;
3679 struct stkctr *stkctr;
3680
3681 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
3682 if (!stkctr)
3683 return 0;
3684
3685 smp->flags = SMP_F_VOL_TEST;
3686 smp->data.type = SMP_T_SINT;
3687 smp->data.u.sint = 0;
3688
3689 if (!stkctr_entry(stkctr))
3690 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
3691
3692 if (stkctr && stkctr_entry(stkctr)) {
3693 void *ptr;
3694
3695 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1);
3696 if (!ptr) {
Emeric Brun726783d2021-06-30 19:06:43 +02003697 /* fallback on the gpc array */
3698 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC, 1);
3699 }
3700
3701 if (!ptr) {
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003702 if (stkctr == &tmpstkctr)
3703 stktable_release(stkctr->table, stkctr_entry(stkctr));
3704 return 0; /* parameter not stored */
3705 }
3706
3707 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3708
Emeric Brun0e3457b2021-06-30 17:18:28 +02003709 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
3710 stktable_data_cast(ptr, std_t_uint) = 0;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003711
3712 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3713
3714 /* If data was modified, we need to touch to re-schedule sync */
3715 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
3716 }
3717 return 1;
3718}
3719
Willy Tarreau7d562212016-11-25 16:10:05 +01003720/* set <smp> to the cumulated number of connections from the stream's tracked
3721 * frontend counters. Supports being called as "sc[0-9]_conn_cnt" or
3722 * "src_conn_cnt" only.
3723 */
3724static int
3725smp_fetch_sc_conn_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
3726{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003727 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003728 struct stkctr *stkctr;
3729
Emeric Brun819fc6f2017-06-13 19:37:32 +02003730 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003731 if (!stkctr)
3732 return 0;
3733
3734 smp->flags = SMP_F_VOL_TEST;
3735 smp->data.type = SMP_T_SINT;
3736 smp->data.u.sint = 0;
3737 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003738 void *ptr;
3739
3740 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_CONN_CNT);
3741 if (!ptr) {
3742 if (stkctr == &tmpstkctr)
3743 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003744 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003745 }
3746
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003747 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003748
Emeric Brun0e3457b2021-06-30 17:18:28 +02003749 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003750
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003751 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003752
3753 if (stkctr == &tmpstkctr)
3754 stktable_release(stkctr->table, stkctr_entry(stkctr));
3755
3756
Willy Tarreau7d562212016-11-25 16:10:05 +01003757 }
3758 return 1;
3759}
3760
3761/* set <smp> to the connection rate from the stream's tracked frontend
3762 * counters. Supports being called as "sc[0-9]_conn_rate" or "src_conn_rate"
3763 * only.
3764 */
3765static int
3766smp_fetch_sc_conn_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3767{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003768 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003769 struct stkctr *stkctr;
3770
Emeric Brun819fc6f2017-06-13 19:37:32 +02003771 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003772 if (!stkctr)
3773 return 0;
3774
3775 smp->flags = SMP_F_VOL_TEST;
3776 smp->data.type = SMP_T_SINT;
3777 smp->data.u.sint = 0;
3778 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003779 void *ptr;
3780
3781 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_CONN_RATE);
3782 if (!ptr) {
3783 if (stkctr == &tmpstkctr)
3784 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003785 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003786 }
3787
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003788 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003789
Emeric Brun0e3457b2021-06-30 17:18:28 +02003790 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Willy Tarreau7d562212016-11-25 16:10:05 +01003791 stkctr->table->data_arg[STKTABLE_DT_CONN_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003792
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003793 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003794
3795 if (stkctr == &tmpstkctr)
3796 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003797 }
3798 return 1;
3799}
3800
3801/* set temp integer to the number of connections from the stream's source address
3802 * in the table pointed to by expr, after updating it.
3803 * Accepts exactly 1 argument of type table.
3804 */
3805static int
3806smp_fetch_src_updt_conn_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
3807{
3808 struct connection *conn = objt_conn(smp->sess->origin);
3809 struct stksess *ts;
3810 struct stktable_key *key;
3811 void *ptr;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003812 struct stktable *t;
Willy Tarreau7d562212016-11-25 16:10:05 +01003813
3814 if (!conn)
3815 return 0;
3816
Joseph Herlant5662fa42018-11-15 13:43:28 -08003817 /* Fetch source address in a sample. */
Amaury Denoyellec460c702021-05-12 10:17:47 +02003818 if (!smp_fetch_src || !smp_fetch_src(empty_arg_list, smp, "src", NULL))
Willy Tarreau7d562212016-11-25 16:10:05 +01003819 return 0;
3820
3821 /* Converts into key. */
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003822 key = smp_to_stkey(smp, args->data.t);
Willy Tarreau7d562212016-11-25 16:10:05 +01003823 if (!key)
3824 return 0;
3825
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003826 t = args->data.t;
Willy Tarreau7d562212016-11-25 16:10:05 +01003827
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003828 if ((ts = stktable_get_entry(t, key)) == NULL)
Willy Tarreau7d562212016-11-25 16:10:05 +01003829 /* entry does not exist and could not be created */
3830 return 0;
3831
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003832 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_CONN_CNT);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003833 if (!ptr) {
Willy Tarreau7d562212016-11-25 16:10:05 +01003834 return 0; /* parameter not stored in this table */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003835 }
Willy Tarreau7d562212016-11-25 16:10:05 +01003836
3837 smp->data.type = SMP_T_SINT;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003838
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003839 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003840
Emeric Brun0e3457b2021-06-30 17:18:28 +02003841 smp->data.u.sint = ++stktable_data_cast(ptr, std_t_uint);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003842
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003843 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003844
Willy Tarreau7d562212016-11-25 16:10:05 +01003845 smp->flags = SMP_F_VOL_TEST;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003846
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003847 stktable_touch_local(t, ts, 1);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003848
3849 /* Touch was previously performed by stktable_update_key */
Willy Tarreau7d562212016-11-25 16:10:05 +01003850 return 1;
3851}
3852
3853/* set <smp> to the number of concurrent connections from the stream's tracked
3854 * frontend counters. Supports being called as "sc[0-9]_conn_cur" or
3855 * "src_conn_cur" only.
3856 */
3857static int
3858smp_fetch_sc_conn_cur(const struct arg *args, struct sample *smp, const char *kw, void *private)
3859{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003860 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003861 struct stkctr *stkctr;
3862
Emeric Brun819fc6f2017-06-13 19:37:32 +02003863 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003864 if (!stkctr)
3865 return 0;
3866
3867 smp->flags = SMP_F_VOL_TEST;
3868 smp->data.type = SMP_T_SINT;
3869 smp->data.u.sint = 0;
3870 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003871 void *ptr;
3872
3873 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_CONN_CUR);
3874 if (!ptr) {
3875 if (stkctr == &tmpstkctr)
3876 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003877 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003878 }
3879
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003880 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003881
Emeric Brun0e3457b2021-06-30 17:18:28 +02003882 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003883
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003884 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003885
3886 if (stkctr == &tmpstkctr)
3887 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003888 }
3889 return 1;
3890}
3891
3892/* set <smp> to the cumulated number of streams from the stream's tracked
3893 * frontend counters. Supports being called as "sc[0-9]_sess_cnt" or
3894 * "src_sess_cnt" only.
3895 */
3896static int
3897smp_fetch_sc_sess_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
3898{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003899 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003900 struct stkctr *stkctr;
3901
Emeric Brun819fc6f2017-06-13 19:37:32 +02003902 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003903 if (!stkctr)
3904 return 0;
3905
3906 smp->flags = SMP_F_VOL_TEST;
3907 smp->data.type = SMP_T_SINT;
3908 smp->data.u.sint = 0;
3909 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003910 void *ptr;
3911
3912 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_SESS_CNT);
3913 if (!ptr) {
3914 if (stkctr == &tmpstkctr)
3915 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003916 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003917 }
3918
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003919 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003920
Emeric Brun0e3457b2021-06-30 17:18:28 +02003921 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003922
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003923 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003924
3925 if (stkctr == &tmpstkctr)
3926 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003927 }
3928 return 1;
3929}
3930
3931/* set <smp> to the stream rate from the stream's tracked frontend counters.
3932 * Supports being called as "sc[0-9]_sess_rate" or "src_sess_rate" only.
3933 */
3934static int
3935smp_fetch_sc_sess_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3936{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003937 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003938 struct stkctr *stkctr;
3939
Emeric Brun819fc6f2017-06-13 19:37:32 +02003940 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003941 if (!stkctr)
3942 return 0;
3943
3944 smp->flags = SMP_F_VOL_TEST;
3945 smp->data.type = SMP_T_SINT;
3946 smp->data.u.sint = 0;
3947 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003948 void *ptr;
3949
3950 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_SESS_RATE);
3951 if (!ptr) {
3952 if (stkctr == &tmpstkctr)
3953 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003954 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003955 }
3956
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003957 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003958
Emeric Brun0e3457b2021-06-30 17:18:28 +02003959 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Willy Tarreau7d562212016-11-25 16:10:05 +01003960 stkctr->table->data_arg[STKTABLE_DT_SESS_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003961
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003962 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003963
3964 if (stkctr == &tmpstkctr)
3965 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003966 }
3967 return 1;
3968}
3969
3970/* set <smp> to the cumulated number of HTTP requests from the stream's tracked
3971 * frontend counters. Supports being called as "sc[0-9]_http_req_cnt" or
3972 * "src_http_req_cnt" only.
3973 */
3974static int
3975smp_fetch_sc_http_req_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
3976{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003977 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003978 struct stkctr *stkctr;
3979
Emeric Brun819fc6f2017-06-13 19:37:32 +02003980 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003981 if (!stkctr)
3982 return 0;
3983
3984 smp->flags = SMP_F_VOL_TEST;
3985 smp->data.type = SMP_T_SINT;
3986 smp->data.u.sint = 0;
3987 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003988 void *ptr;
3989
3990 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_REQ_CNT);
3991 if (!ptr) {
3992 if (stkctr == &tmpstkctr)
3993 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003994 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003995 }
3996
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003997 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003998
Emeric Brun0e3457b2021-06-30 17:18:28 +02003999 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004000
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004001 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004002
4003 if (stkctr == &tmpstkctr)
4004 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004005 }
4006 return 1;
4007}
4008
4009/* set <smp> to the HTTP request rate from the stream's tracked frontend
4010 * counters. Supports being called as "sc[0-9]_http_req_rate" or
4011 * "src_http_req_rate" only.
4012 */
4013static int
4014smp_fetch_sc_http_req_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
4015{
Emeric Brun819fc6f2017-06-13 19:37:32 +02004016 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01004017 struct stkctr *stkctr;
4018
Emeric Brun819fc6f2017-06-13 19:37:32 +02004019 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01004020 if (!stkctr)
4021 return 0;
4022
4023 smp->flags = SMP_F_VOL_TEST;
4024 smp->data.type = SMP_T_SINT;
4025 smp->data.u.sint = 0;
4026 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02004027 void *ptr;
4028
4029 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_REQ_RATE);
4030 if (!ptr) {
4031 if (stkctr == &tmpstkctr)
4032 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004033 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02004034 }
4035
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004036 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004037
Emeric Brun0e3457b2021-06-30 17:18:28 +02004038 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Willy Tarreau7d562212016-11-25 16:10:05 +01004039 stkctr->table->data_arg[STKTABLE_DT_HTTP_REQ_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004040
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004041 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004042
4043 if (stkctr == &tmpstkctr)
4044 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004045 }
4046 return 1;
4047}
4048
4049/* set <smp> to the cumulated number of HTTP requests errors from the stream's
4050 * tracked frontend counters. Supports being called as "sc[0-9]_http_err_cnt" or
4051 * "src_http_err_cnt" only.
4052 */
4053static int
4054smp_fetch_sc_http_err_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
4055{
Emeric Brun819fc6f2017-06-13 19:37:32 +02004056 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01004057 struct stkctr *stkctr;
4058
Emeric Brun819fc6f2017-06-13 19:37:32 +02004059 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01004060 if (!stkctr)
4061 return 0;
4062
4063 smp->flags = SMP_F_VOL_TEST;
4064 smp->data.type = SMP_T_SINT;
4065 smp->data.u.sint = 0;
4066 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02004067 void *ptr;
4068
4069 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_ERR_CNT);
4070 if (!ptr) {
4071 if (stkctr == &tmpstkctr)
4072 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004073 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02004074 }
4075
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004076 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004077
Emeric Brun0e3457b2021-06-30 17:18:28 +02004078 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004079
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004080 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004081
4082 if (stkctr == &tmpstkctr)
4083 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004084 }
4085 return 1;
4086}
4087
4088/* set <smp> to the HTTP request error rate from the stream's tracked frontend
4089 * counters. Supports being called as "sc[0-9]_http_err_rate" or
4090 * "src_http_err_rate" only.
4091 */
4092static int
4093smp_fetch_sc_http_err_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
4094{
Emeric Brun819fc6f2017-06-13 19:37:32 +02004095 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01004096 struct stkctr *stkctr;
4097
Emeric Brun819fc6f2017-06-13 19:37:32 +02004098 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01004099 if (!stkctr)
4100 return 0;
4101
4102 smp->flags = SMP_F_VOL_TEST;
4103 smp->data.type = SMP_T_SINT;
4104 smp->data.u.sint = 0;
4105 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02004106 void *ptr;
4107
4108 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_ERR_RATE);
4109 if (!ptr) {
4110 if (stkctr == &tmpstkctr)
4111 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004112 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02004113 }
4114
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004115 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004116
Emeric Brun0e3457b2021-06-30 17:18:28 +02004117 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Willy Tarreau7d562212016-11-25 16:10:05 +01004118 stkctr->table->data_arg[STKTABLE_DT_HTTP_ERR_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004119
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004120 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004121
4122 if (stkctr == &tmpstkctr)
4123 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004124 }
4125 return 1;
4126}
4127
Willy Tarreau826f3ab2021-02-10 12:07:15 +01004128/* set <smp> to the cumulated number of HTTP response failures from the stream's
4129 * tracked frontend counters. Supports being called as "sc[0-9]_http_fail_cnt" or
4130 * "src_http_fail_cnt" only.
4131 */
4132static int
4133smp_fetch_sc_http_fail_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
4134{
4135 struct stkctr tmpstkctr;
4136 struct stkctr *stkctr;
4137
4138 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
4139 if (!stkctr)
4140 return 0;
4141
4142 smp->flags = SMP_F_VOL_TEST;
4143 smp->data.type = SMP_T_SINT;
4144 smp->data.u.sint = 0;
4145 if (stkctr_entry(stkctr) != NULL) {
4146 void *ptr;
4147
4148 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_FAIL_CNT);
4149 if (!ptr) {
4150 if (stkctr == &tmpstkctr)
4151 stktable_release(stkctr->table, stkctr_entry(stkctr));
4152 return 0; /* parameter not stored */
4153 }
4154
4155 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
4156
Emeric Brun0e3457b2021-06-30 17:18:28 +02004157 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Willy Tarreau826f3ab2021-02-10 12:07:15 +01004158
4159 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
4160
4161 if (stkctr == &tmpstkctr)
4162 stktable_release(stkctr->table, stkctr_entry(stkctr));
4163 }
4164 return 1;
4165}
4166
4167/* set <smp> to the HTTP response failure rate from the stream's tracked frontend
4168 * counters. Supports being called as "sc[0-9]_http_fail_rate" or
4169 * "src_http_fail_rate" only.
4170 */
4171static int
4172smp_fetch_sc_http_fail_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
4173{
4174 struct stkctr tmpstkctr;
4175 struct stkctr *stkctr;
4176
4177 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
4178 if (!stkctr)
4179 return 0;
4180
4181 smp->flags = SMP_F_VOL_TEST;
4182 smp->data.type = SMP_T_SINT;
4183 smp->data.u.sint = 0;
4184 if (stkctr_entry(stkctr) != NULL) {
4185 void *ptr;
4186
4187 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_FAIL_RATE);
4188 if (!ptr) {
4189 if (stkctr == &tmpstkctr)
4190 stktable_release(stkctr->table, stkctr_entry(stkctr));
4191 return 0; /* parameter not stored */
4192 }
4193
4194 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
4195
Emeric Brun0e3457b2021-06-30 17:18:28 +02004196 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Willy Tarreau826f3ab2021-02-10 12:07:15 +01004197 stkctr->table->data_arg[STKTABLE_DT_HTTP_FAIL_RATE].u);
4198
4199 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
4200
4201 if (stkctr == &tmpstkctr)
4202 stktable_release(stkctr->table, stkctr_entry(stkctr));
4203 }
4204 return 1;
4205}
4206
Willy Tarreau7d562212016-11-25 16:10:05 +01004207/* set <smp> to the number of kbytes received from clients, as found in the
4208 * stream's tracked frontend counters. Supports being called as
4209 * "sc[0-9]_kbytes_in" or "src_kbytes_in" only.
4210 */
4211static int
4212smp_fetch_sc_kbytes_in(const struct arg *args, struct sample *smp, const char *kw, void *private)
4213{
Emeric Brun819fc6f2017-06-13 19:37:32 +02004214 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01004215 struct stkctr *stkctr;
4216
Emeric Brun819fc6f2017-06-13 19:37:32 +02004217 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01004218 if (!stkctr)
4219 return 0;
4220
4221 smp->flags = SMP_F_VOL_TEST;
4222 smp->data.type = SMP_T_SINT;
4223 smp->data.u.sint = 0;
4224 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02004225 void *ptr;
4226
4227 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_IN_CNT);
4228 if (!ptr) {
4229 if (stkctr == &tmpstkctr)
4230 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004231 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02004232 }
4233
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004234 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004235
Emeric Brun0e3457b2021-06-30 17:18:28 +02004236 smp->data.u.sint = stktable_data_cast(ptr, std_t_ull) >> 10;
Emeric Brun819fc6f2017-06-13 19:37:32 +02004237
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004238 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004239
4240 if (stkctr == &tmpstkctr)
4241 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004242 }
4243 return 1;
4244}
4245
4246/* set <smp> to the data rate received from clients in bytes/s, as found
4247 * in the stream's tracked frontend counters. Supports being called as
4248 * "sc[0-9]_bytes_in_rate" or "src_bytes_in_rate" only.
4249 */
4250static int
4251smp_fetch_sc_bytes_in_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
4252{
Emeric Brun819fc6f2017-06-13 19:37:32 +02004253 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01004254 struct stkctr *stkctr;
4255
Emeric Brun819fc6f2017-06-13 19:37:32 +02004256 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01004257 if (!stkctr)
4258 return 0;
4259
4260 smp->flags = SMP_F_VOL_TEST;
4261 smp->data.type = SMP_T_SINT;
4262 smp->data.u.sint = 0;
4263 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02004264 void *ptr;
4265
4266 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_IN_RATE);
4267 if (!ptr) {
4268 if (stkctr == &tmpstkctr)
4269 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004270 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02004271 }
4272
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004273 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004274
Emeric Brun0e3457b2021-06-30 17:18:28 +02004275 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Willy Tarreau7d562212016-11-25 16:10:05 +01004276 stkctr->table->data_arg[STKTABLE_DT_BYTES_IN_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004277
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004278 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004279
4280 if (stkctr == &tmpstkctr)
4281 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004282 }
4283 return 1;
4284}
4285
4286/* set <smp> to the number of kbytes sent to clients, as found in the
4287 * stream's tracked frontend counters. Supports being called as
4288 * "sc[0-9]_kbytes_out" or "src_kbytes_out" only.
4289 */
4290static int
4291smp_fetch_sc_kbytes_out(const struct arg *args, struct sample *smp, const char *kw, void *private)
4292{
Emeric Brun819fc6f2017-06-13 19:37:32 +02004293 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01004294 struct stkctr *stkctr;
4295
Emeric Brun819fc6f2017-06-13 19:37:32 +02004296 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01004297 if (!stkctr)
4298 return 0;
4299
4300 smp->flags = SMP_F_VOL_TEST;
4301 smp->data.type = SMP_T_SINT;
4302 smp->data.u.sint = 0;
4303 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02004304 void *ptr;
4305
4306 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_OUT_CNT);
4307 if (!ptr) {
4308 if (stkctr == &tmpstkctr)
4309 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004310 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02004311 }
4312
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004313 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004314
Emeric Brun0e3457b2021-06-30 17:18:28 +02004315 smp->data.u.sint = stktable_data_cast(ptr, std_t_ull) >> 10;
Emeric Brun819fc6f2017-06-13 19:37:32 +02004316
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004317 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004318
4319 if (stkctr == &tmpstkctr)
4320 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004321 }
4322 return 1;
4323}
4324
4325/* set <smp> to the data rate sent to clients in bytes/s, as found in the
4326 * stream's tracked frontend counters. Supports being called as
4327 * "sc[0-9]_bytes_out_rate" or "src_bytes_out_rate" only.
4328 */
4329static int
4330smp_fetch_sc_bytes_out_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
4331{
Emeric Brun819fc6f2017-06-13 19:37:32 +02004332 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01004333 struct stkctr *stkctr;
4334
Emeric Brun819fc6f2017-06-13 19:37:32 +02004335 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01004336 if (!stkctr)
4337 return 0;
4338
4339 smp->flags = SMP_F_VOL_TEST;
4340 smp->data.type = SMP_T_SINT;
4341 smp->data.u.sint = 0;
4342 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02004343 void *ptr;
4344
4345 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_OUT_RATE);
4346 if (!ptr) {
4347 if (stkctr == &tmpstkctr)
4348 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004349 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02004350 }
4351
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004352 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004353
Emeric Brun0e3457b2021-06-30 17:18:28 +02004354 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Willy Tarreau7d562212016-11-25 16:10:05 +01004355 stkctr->table->data_arg[STKTABLE_DT_BYTES_OUT_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004356
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004357 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004358
4359 if (stkctr == &tmpstkctr)
4360 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004361 }
4362 return 1;
4363}
4364
4365/* set <smp> to the number of active trackers on the SC entry in the stream's
4366 * tracked frontend counters. Supports being called as "sc[0-9]_trackers" only.
4367 */
4368static int
4369smp_fetch_sc_trackers(const struct arg *args, struct sample *smp, const char *kw, void *private)
4370{
Emeric Brun819fc6f2017-06-13 19:37:32 +02004371 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01004372 struct stkctr *stkctr;
4373
Emeric Brun819fc6f2017-06-13 19:37:32 +02004374 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01004375 if (!stkctr)
4376 return 0;
4377
4378 smp->flags = SMP_F_VOL_TEST;
4379 smp->data.type = SMP_T_SINT;
Emeric Brun819fc6f2017-06-13 19:37:32 +02004380 if (stkctr == &tmpstkctr) {
4381 smp->data.u.sint = stkctr_entry(stkctr) ? (stkctr_entry(stkctr)->ref_cnt-1) : 0;
4382 stktable_release(stkctr->table, stkctr_entry(stkctr));
4383 }
4384 else {
4385 smp->data.u.sint = stkctr_entry(stkctr) ? stkctr_entry(stkctr)->ref_cnt : 0;
4386 }
4387
Willy Tarreau7d562212016-11-25 16:10:05 +01004388 return 1;
4389}
4390
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004391
4392/* The functions below are used to manipulate table contents from the CLI.
4393 * There are 3 main actions, "clear", "set" and "show". The code is shared
4394 * between all actions, and the action is encoded in the void *private in
4395 * the appctx as well as in the keyword registration, among one of the
4396 * following values.
4397 */
4398
4399enum {
4400 STK_CLI_ACT_CLR,
4401 STK_CLI_ACT_SET,
4402 STK_CLI_ACT_SHOW,
4403};
4404
Willy Tarreau4596fe22022-05-17 19:07:51 +02004405/* Dump the status of a table to a stream connector's
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004406 * read buffer. It returns 0 if the output buffer is full
4407 * and needs to be called again, otherwise non-zero.
4408 */
Willy Tarreau83061a82018-07-13 11:56:34 +02004409static int table_dump_head_to_buffer(struct buffer *msg,
Willy Tarreaud0a06d52022-05-18 15:07:19 +02004410 struct appctx *appctx,
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004411 struct stktable *t, struct stktable *target)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004412{
Willy Tarreauc12b3212022-05-27 11:08:15 +02004413 struct stream *s = __sc_strm(appctx_sc(appctx));
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004414
4415 chunk_appendf(msg, "# table: %s, type: %s, size:%d, used:%d\n",
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004416 t->id, stktable_types[t->type].kw, t->size, t->current);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004417
4418 /* any other information should be dumped here */
4419
William Lallemand07a62f72017-05-24 00:57:40 +02004420 if (target && (strm_li(s)->bind_conf->level & ACCESS_LVL_MASK) < ACCESS_LVL_OPER)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004421 chunk_appendf(msg, "# contents not dumped due to insufficient privileges\n");
4422
Willy Tarreaud0a06d52022-05-18 15:07:19 +02004423 if (applet_putchk(appctx, msg) == -1)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004424 return 0;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004425
4426 return 1;
4427}
4428
Willy Tarreau4596fe22022-05-17 19:07:51 +02004429/* Dump a table entry to a stream connector's
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004430 * read buffer. It returns 0 if the output buffer is full
4431 * and needs to be called again, otherwise non-zero.
4432 */
Willy Tarreau83061a82018-07-13 11:56:34 +02004433static int table_dump_entry_to_buffer(struct buffer *msg,
Willy Tarreaud0a06d52022-05-18 15:07:19 +02004434 struct appctx *appctx,
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004435 struct stktable *t, struct stksess *entry)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004436{
4437 int dt;
4438
4439 chunk_appendf(msg, "%p:", entry);
4440
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004441 if (t->type == SMP_T_IPV4) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004442 char addr[INET_ADDRSTRLEN];
4443 inet_ntop(AF_INET, (const void *)&entry->key.key, addr, sizeof(addr));
4444 chunk_appendf(msg, " key=%s", addr);
4445 }
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004446 else if (t->type == SMP_T_IPV6) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004447 char addr[INET6_ADDRSTRLEN];
4448 inet_ntop(AF_INET6, (const void *)&entry->key.key, addr, sizeof(addr));
4449 chunk_appendf(msg, " key=%s", addr);
4450 }
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004451 else if (t->type == SMP_T_SINT) {
Willy Tarreau6cde5d82020-02-25 09:41:22 +01004452 chunk_appendf(msg, " key=%u", read_u32(entry->key.key));
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004453 }
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004454 else if (t->type == SMP_T_STR) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004455 chunk_appendf(msg, " key=");
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004456 dump_text(msg, (const char *)entry->key.key, t->key_size);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004457 }
4458 else {
4459 chunk_appendf(msg, " key=");
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004460 dump_binary(msg, (const char *)entry->key.key, t->key_size);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004461 }
4462
4463 chunk_appendf(msg, " use=%d exp=%d", entry->ref_cnt - 1, tick_remain(now_ms, entry->expire));
4464
4465 for (dt = 0; dt < STKTABLE_DATA_TYPES; dt++) {
4466 void *ptr;
4467
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004468 if (t->data_ofs[dt] == 0)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004469 continue;
Emeric Brunc64a2a32021-06-30 18:01:02 +02004470 if (stktable_data_types[dt].is_array) {
4471 char tmp[16] = {};
4472 const char *name_pfx = stktable_data_types[dt].name;
4473 const char *name_sfx = NULL;
4474 unsigned int idx = 0;
4475 int i = 0;
4476
4477 /* split name to show index before first _ of the name
4478 * for example: 'gpc3_rate' if array name is 'gpc_rate'.
4479 */
4480 for (i = 0 ; i < (sizeof(tmp) - 1); i++) {
4481 if (!name_pfx[i])
4482 break;
4483 if (name_pfx[i] == '_') {
4484 name_pfx = &tmp[0];
4485 name_sfx = &stktable_data_types[dt].name[i];
4486 break;
4487 }
4488 tmp[i] = name_pfx[i];
4489 }
4490
4491 ptr = stktable_data_ptr_idx(t, entry, dt, idx);
4492 while (ptr) {
4493 if (stktable_data_types[dt].arg_type == ARG_T_DELAY)
4494 chunk_appendf(msg, " %s%u%s(%u)=", name_pfx, idx, name_sfx ? name_sfx : "", t->data_arg[dt].u);
4495 else
4496 chunk_appendf(msg, " %s%u%s=", name_pfx, idx, name_sfx ? name_sfx : "");
4497 switch (stktable_data_types[dt].std_type) {
4498 case STD_T_SINT:
4499 chunk_appendf(msg, "%d", stktable_data_cast(ptr, std_t_sint));
4500 break;
4501 case STD_T_UINT:
4502 chunk_appendf(msg, "%u", stktable_data_cast(ptr, std_t_uint));
4503 break;
4504 case STD_T_ULL:
4505 chunk_appendf(msg, "%llu", stktable_data_cast(ptr, std_t_ull));
4506 break;
4507 case STD_T_FRQP:
4508 chunk_appendf(msg, "%u",
4509 read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
4510 t->data_arg[dt].u));
4511 break;
4512 }
4513 ptr = stktable_data_ptr_idx(t, entry, dt, ++idx);
4514 }
4515 continue;
4516 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004517 if (stktable_data_types[dt].arg_type == ARG_T_DELAY)
Emeric Brun01928ae2021-06-30 16:24:04 +02004518 chunk_appendf(msg, " %s(%u)=", stktable_data_types[dt].name, t->data_arg[dt].u);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004519 else
4520 chunk_appendf(msg, " %s=", stktable_data_types[dt].name);
4521
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004522 ptr = stktable_data_ptr(t, entry, dt);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004523 switch (stktable_data_types[dt].std_type) {
4524 case STD_T_SINT:
4525 chunk_appendf(msg, "%d", stktable_data_cast(ptr, std_t_sint));
4526 break;
4527 case STD_T_UINT:
4528 chunk_appendf(msg, "%u", stktable_data_cast(ptr, std_t_uint));
4529 break;
4530 case STD_T_ULL:
Emeric Brun01928ae2021-06-30 16:24:04 +02004531 chunk_appendf(msg, "%llu", stktable_data_cast(ptr, std_t_ull));
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004532 break;
4533 case STD_T_FRQP:
Emeric Brun01928ae2021-06-30 16:24:04 +02004534 chunk_appendf(msg, "%u",
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004535 read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004536 t->data_arg[dt].u));
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004537 break;
Frédéric Lécaille16b4f542019-05-23 12:15:04 +02004538 case STD_T_DICT: {
4539 struct dict_entry *de;
4540 de = stktable_data_cast(ptr, std_t_dict);
4541 chunk_appendf(msg, "%s", de ? (char *)de->value.key : "-");
4542 break;
4543 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004544 }
4545 }
4546 chunk_appendf(msg, "\n");
4547
Willy Tarreaud0a06d52022-05-18 15:07:19 +02004548 if (applet_putchk(appctx, msg) == -1)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004549 return 0;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004550
4551 return 1;
4552}
4553
Willy Tarreau3c69e082022-05-03 11:35:07 +02004554/* appctx context used by the "show table" command */
4555struct show_table_ctx {
4556 void *target; /* table we want to dump, or NULL for all */
4557 struct stktable *t; /* table being currently dumped (first if NULL) */
4558 struct stksess *entry; /* last entry we were trying to dump (or first if NULL) */
4559 long long value[STKTABLE_FILTER_LEN]; /* value to compare against */
4560 signed char data_type[STKTABLE_FILTER_LEN]; /* type of data to compare, or -1 if none */
4561 signed char data_op[STKTABLE_FILTER_LEN]; /* operator (STD_OP_*) when data_type set */
Willy Tarreau7849d4c2022-05-03 11:45:02 +02004562 enum {
Willy Tarreau0f154ed2022-05-03 12:02:36 +02004563 STATE_NEXT = 0, /* px points to next table, entry=NULL */
Willy Tarreau7849d4c2022-05-03 11:45:02 +02004564 STATE_DUMP, /* px points to curr table, entry is valid, refcount held */
4565 STATE_DONE, /* done dumping */
4566 } state;
Willy Tarreau3c69e082022-05-03 11:35:07 +02004567 char action; /* action on the table : one of STK_CLI_ACT_* */
4568};
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004569
4570/* Processes a single table entry matching a specific key passed in argument.
4571 * returns 0 if wants to be called again, 1 if has ended processing.
4572 */
4573static int table_process_entry_per_key(struct appctx *appctx, char **args)
4574{
Willy Tarreau3c69e082022-05-03 11:35:07 +02004575 struct show_table_ctx *ctx = appctx->svcctx;
4576 struct stktable *t = ctx->target;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004577 struct stksess *ts;
4578 uint32_t uint32_key;
4579 unsigned char ip6_key[sizeof(struct in6_addr)];
4580 long long value;
4581 int data_type;
4582 int cur_arg;
4583 void *ptr;
Willy Tarreaufa1258f2021-04-10 23:00:53 +02004584 struct freq_ctr *frqp;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004585
Willy Tarreau9d008692019-08-09 11:21:01 +02004586 if (!*args[4])
4587 return cli_err(appctx, "Key value expected\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004588
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004589 switch (t->type) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004590 case SMP_T_IPV4:
4591 uint32_key = htonl(inetaddr_host(args[4]));
Christopher Fauletca20d022017-08-29 15:30:31 +02004592 static_table_key.key = &uint32_key;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004593 break;
4594 case SMP_T_IPV6:
Christopher Fauletb7c962b2021-11-15 09:17:25 +01004595 if (inet_pton(AF_INET6, args[4], ip6_key) <= 0)
4596 return cli_err(appctx, "Invalid key\n");
Christopher Fauletca20d022017-08-29 15:30:31 +02004597 static_table_key.key = &ip6_key;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004598 break;
4599 case SMP_T_SINT:
4600 {
4601 char *endptr;
4602 unsigned long val;
4603 errno = 0;
4604 val = strtoul(args[4], &endptr, 10);
4605 if ((errno == ERANGE && val == ULONG_MAX) ||
4606 (errno != 0 && val == 0) || endptr == args[4] ||
Willy Tarreau9d008692019-08-09 11:21:01 +02004607 val > 0xffffffff)
4608 return cli_err(appctx, "Invalid key\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004609 uint32_key = (uint32_t) val;
Christopher Fauletca20d022017-08-29 15:30:31 +02004610 static_table_key.key = &uint32_key;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004611 break;
4612 }
4613 break;
4614 case SMP_T_STR:
Christopher Fauletca20d022017-08-29 15:30:31 +02004615 static_table_key.key = args[4];
4616 static_table_key.key_len = strlen(args[4]);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004617 break;
4618 default:
Willy Tarreau3c69e082022-05-03 11:35:07 +02004619 switch (ctx->action) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004620 case STK_CLI_ACT_SHOW:
Willy Tarreau9d008692019-08-09 11:21:01 +02004621 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 +01004622 case STK_CLI_ACT_CLR:
Willy Tarreau9d008692019-08-09 11:21:01 +02004623 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 +01004624 case STK_CLI_ACT_SET:
Willy Tarreau9d008692019-08-09 11:21:01 +02004625 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 +01004626 default:
Willy Tarreau9d008692019-08-09 11:21:01 +02004627 return cli_err(appctx, "Unknown action\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004628 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004629 }
4630
4631 /* check permissions */
4632 if (!cli_has_level(appctx, ACCESS_LVL_OPER))
4633 return 1;
4634
Willy Tarreau3c69e082022-05-03 11:35:07 +02004635 switch (ctx->action) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004636 case STK_CLI_ACT_SHOW:
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004637 ts = stktable_lookup_key(t, &static_table_key);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004638 if (!ts)
4639 return 1;
4640 chunk_reset(&trash);
Willy Tarreaud0a06d52022-05-18 15:07:19 +02004641 if (!table_dump_head_to_buffer(&trash, appctx, t, t)) {
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004642 stktable_release(t, ts);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004643 return 0;
Emeric Brun819fc6f2017-06-13 19:37:32 +02004644 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004645 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &ts->lock);
Willy Tarreaud0a06d52022-05-18 15:07:19 +02004646 if (!table_dump_entry_to_buffer(&trash, appctx, t, ts)) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004647 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004648 stktable_release(t, ts);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004649 return 0;
Emeric Brun819fc6f2017-06-13 19:37:32 +02004650 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004651 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004652 stktable_release(t, ts);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004653 break;
4654
4655 case STK_CLI_ACT_CLR:
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004656 ts = stktable_lookup_key(t, &static_table_key);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004657 if (!ts)
4658 return 1;
Emeric Brun819fc6f2017-06-13 19:37:32 +02004659
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004660 if (!stksess_kill(t, ts, 1)) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004661 /* don't delete an entry which is currently referenced */
Willy Tarreau9d008692019-08-09 11:21:01 +02004662 return cli_err(appctx, "Entry currently in use, cannot remove\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004663 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004664 break;
4665
4666 case STK_CLI_ACT_SET:
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004667 ts = stktable_get_entry(t, &static_table_key);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004668 if (!ts) {
4669 /* don't delete an entry which is currently referenced */
Willy Tarreau9d008692019-08-09 11:21:01 +02004670 return cli_err(appctx, "Unable to allocate a new entry\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004671 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004672 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004673 for (cur_arg = 5; *args[cur_arg]; cur_arg += 2) {
4674 if (strncmp(args[cur_arg], "data.", 5) != 0) {
Willy Tarreau9d008692019-08-09 11:21:01 +02004675 cli_err(appctx, "\"data.<type>\" followed by a value expected\n");
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004676 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004677 stktable_touch_local(t, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004678 return 1;
4679 }
4680
4681 data_type = stktable_get_data_type(args[cur_arg] + 5);
4682 if (data_type < 0) {
Willy Tarreau9d008692019-08-09 11:21:01 +02004683 cli_err(appctx, "Unknown data type\n");
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004684 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004685 stktable_touch_local(t, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004686 return 1;
4687 }
4688
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004689 if (!t->data_ofs[data_type]) {
Willy Tarreau9d008692019-08-09 11:21:01 +02004690 cli_err(appctx, "Data type not stored in this table\n");
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004691 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004692 stktable_touch_local(t, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004693 return 1;
4694 }
4695
4696 if (!*args[cur_arg+1] || strl2llrc(args[cur_arg+1], strlen(args[cur_arg+1]), &value) != 0) {
Willy Tarreau9d008692019-08-09 11:21:01 +02004697 cli_err(appctx, "Require a valid integer value to store\n");
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004698 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004699 stktable_touch_local(t, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004700 return 1;
4701 }
4702
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004703 ptr = stktable_data_ptr(t, ts, data_type);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004704
4705 switch (stktable_data_types[data_type].std_type) {
4706 case STD_T_SINT:
4707 stktable_data_cast(ptr, std_t_sint) = value;
4708 break;
4709 case STD_T_UINT:
4710 stktable_data_cast(ptr, std_t_uint) = value;
4711 break;
4712 case STD_T_ULL:
4713 stktable_data_cast(ptr, std_t_ull) = value;
4714 break;
4715 case STD_T_FRQP:
4716 /* We set both the current and previous values. That way
4717 * the reported frequency is stable during all the period
4718 * then slowly fades out. This allows external tools to
4719 * push measures without having to update them too often.
4720 */
4721 frqp = &stktable_data_cast(ptr, std_t_frqp);
Willy Tarreaufa1258f2021-04-10 23:00:53 +02004722 /* First bit is reserved for the freq_ctr lock
Emeric Brunf2fc1fd2017-11-02 17:32:43 +01004723 Note: here we're still protected by the stksess lock
Willy Tarreaufa1258f2021-04-10 23:00:53 +02004724 so we don't need to update the update the freq_ctr
Emeric Brunf2fc1fd2017-11-02 17:32:43 +01004725 using its internal lock */
4726 frqp->curr_tick = now_ms & ~0x1;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004727 frqp->prev_ctr = 0;
4728 frqp->curr_ctr = value;
4729 break;
4730 }
4731 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004732 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004733 stktable_touch_local(t, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004734 break;
4735
4736 default:
Willy Tarreau9d008692019-08-09 11:21:01 +02004737 return cli_err(appctx, "Unknown action\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004738 }
4739 return 1;
4740}
4741
4742/* Prepares the appctx fields with the data-based filters from the command line.
4743 * Returns 0 if the dump can proceed, 1 if has ended processing.
4744 */
4745static int table_prepare_data_request(struct appctx *appctx, char **args)
4746{
Willy Tarreau3c69e082022-05-03 11:35:07 +02004747 struct show_table_ctx *ctx = appctx->svcctx;
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004748 int i;
Adis Nezirovicd0142e72020-01-22 16:50:27 +01004749 char *err = NULL;
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004750
Willy Tarreau3c69e082022-05-03 11:35:07 +02004751 if (ctx->action != STK_CLI_ACT_SHOW && ctx->action != STK_CLI_ACT_CLR)
Willy Tarreau9d008692019-08-09 11:21:01 +02004752 return cli_err(appctx, "content-based lookup is only supported with the \"show\" and \"clear\" actions\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004753
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004754 for (i = 0; i < STKTABLE_FILTER_LEN; i++) {
4755 if (i > 0 && !*args[3+3*i]) // number of filter entries can be less than STKTABLE_FILTER_LEN
4756 break;
4757 /* condition on stored data value */
Willy Tarreau3c69e082022-05-03 11:35:07 +02004758 ctx->data_type[i] = stktable_get_data_type(args[3+3*i] + 5);
4759 if (ctx->data_type[i] < 0)
Adis Nezirovicd0142e72020-01-22 16:50:27 +01004760 return cli_dynerr(appctx, memprintf(&err, "Filter entry #%i: Unknown data type\n", i + 1));
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004761
Willy Tarreau3c69e082022-05-03 11:35:07 +02004762 if (!((struct stktable *)ctx->target)->data_ofs[ctx->data_type[i]])
Adis Nezirovicd0142e72020-01-22 16:50:27 +01004763 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 +01004764
Willy Tarreau3c69e082022-05-03 11:35:07 +02004765 ctx->data_op[i] = get_std_op(args[4+3*i]);
4766 if (ctx->data_op[i] < 0)
Adis Nezirovicd0142e72020-01-22 16:50:27 +01004767 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 +01004768
Willy Tarreau3c69e082022-05-03 11:35:07 +02004769 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 +01004770 return cli_dynerr(appctx, memprintf(&err, "Filter entry #%i: Require a valid integer value to compare against\n", i + 1));
4771 }
4772
4773 if (*args[3+3*i]) {
4774 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 +01004775 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004776
4777 /* OK we're done, all the fields are set */
4778 return 0;
4779}
4780
4781/* returns 0 if wants to be called, 1 if has ended processing */
Aurélien Nephtaliabbf6072018-04-18 13:26:46 +02004782static int cli_parse_table_req(char **args, char *payload, struct appctx *appctx, void *private)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004783{
Willy Tarreau3c69e082022-05-03 11:35:07 +02004784 struct show_table_ctx *ctx = applet_reserve_svcctx(appctx, sizeof(*ctx));
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004785 int i;
4786
4787 for (i = 0; i < STKTABLE_FILTER_LEN; i++)
Willy Tarreau3c69e082022-05-03 11:35:07 +02004788 ctx->data_type[i] = -1;
4789 ctx->target = NULL;
4790 ctx->entry = NULL;
4791 ctx->action = (long)private; // keyword argument, one of STK_CLI_ACT_*
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004792
4793 if (*args[2]) {
Willy Tarreau0f154ed2022-05-03 12:02:36 +02004794 ctx->t = ctx->target = stktable_find_by_name(args[2]);
Willy Tarreau3c69e082022-05-03 11:35:07 +02004795 if (!ctx->target)
Willy Tarreau9d008692019-08-09 11:21:01 +02004796 return cli_err(appctx, "No such table\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004797 }
4798 else {
Willy Tarreau0f154ed2022-05-03 12:02:36 +02004799 ctx->t = stktables_list;
Willy Tarreau3c69e082022-05-03 11:35:07 +02004800 if (ctx->action != STK_CLI_ACT_SHOW)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004801 goto err_args;
4802 return 0;
4803 }
4804
4805 if (strcmp(args[3], "key") == 0)
4806 return table_process_entry_per_key(appctx, args);
4807 else if (strncmp(args[3], "data.", 5) == 0)
4808 return table_prepare_data_request(appctx, args);
4809 else if (*args[3])
4810 goto err_args;
4811
4812 return 0;
4813
4814err_args:
Willy Tarreau3c69e082022-05-03 11:35:07 +02004815 switch (ctx->action) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004816 case STK_CLI_ACT_SHOW:
Willy Tarreau9d008692019-08-09 11:21:01 +02004817 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 +01004818 case STK_CLI_ACT_CLR:
Willy Tarreau9d008692019-08-09 11:21:01 +02004819 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 +01004820 case STK_CLI_ACT_SET:
Willy Tarreau9d008692019-08-09 11:21:01 +02004821 return cli_err(appctx, "Required arguments: <table> key <key> [data.<store_data_type> <value>]*\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004822 default:
Willy Tarreau9d008692019-08-09 11:21:01 +02004823 return cli_err(appctx, "Unknown action\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004824 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004825}
4826
4827/* This function is used to deal with table operations (dump or clear depending
4828 * on the action stored in appctx->private). It returns 0 if the output buffer is
4829 * full and it needs to be called again, otherwise non-zero.
4830 */
4831static int cli_io_handler_table(struct appctx *appctx)
4832{
Willy Tarreau3c69e082022-05-03 11:35:07 +02004833 struct show_table_ctx *ctx = appctx->svcctx;
Willy Tarreauc12b3212022-05-27 11:08:15 +02004834 struct stconn *sc = appctx_sc(appctx);
Willy Tarreau475e4632022-05-27 10:26:46 +02004835 struct stream *s = __sc_strm(sc);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004836 struct ebmb_node *eb;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004837 int skip_entry;
Willy Tarreau3c69e082022-05-03 11:35:07 +02004838 int show = ctx->action == STK_CLI_ACT_SHOW;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004839
4840 /*
Willy Tarreau0f154ed2022-05-03 12:02:36 +02004841 * We have 3 possible states in ctx->state :
Willy Tarreau7849d4c2022-05-03 11:45:02 +02004842 * - STATE_NEXT : the proxy pointer points to the next table to
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004843 * dump, the entry pointer is NULL ;
Willy Tarreau7849d4c2022-05-03 11:45:02 +02004844 * - STATE_DUMP : the proxy pointer points to the current table
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004845 * and the entry pointer points to the next entry to be dumped,
4846 * and the refcount on the next entry is held ;
Willy Tarreau7849d4c2022-05-03 11:45:02 +02004847 * - STATE_DONE : nothing left to dump, the buffer may contain some
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004848 * data though.
4849 */
4850
Willy Tarreau475e4632022-05-27 10:26:46 +02004851 if (unlikely(sc_ic(sc)->flags & (CF_WRITE_ERROR|CF_SHUTW))) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004852 /* in case of abort, remove any refcount we might have set on an entry */
Willy Tarreau7849d4c2022-05-03 11:45:02 +02004853 if (ctx->state == STATE_DUMP) {
Willy Tarreau3c69e082022-05-03 11:35:07 +02004854 stksess_kill_if_expired(ctx->t, ctx->entry, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004855 }
4856 return 1;
4857 }
4858
4859 chunk_reset(&trash);
4860
Willy Tarreau7849d4c2022-05-03 11:45:02 +02004861 while (ctx->state != STATE_DONE) {
4862 switch (ctx->state) {
Willy Tarreau7849d4c2022-05-03 11:45:02 +02004863 case STATE_NEXT:
Willy Tarreau3c69e082022-05-03 11:35:07 +02004864 if (!ctx->t ||
4865 (ctx->target &&
4866 ctx->t != ctx->target)) {
Willy Tarreau7849d4c2022-05-03 11:45:02 +02004867 ctx->state = STATE_DONE;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004868 break;
4869 }
4870
Willy Tarreau3c69e082022-05-03 11:35:07 +02004871 if (ctx->t->size) {
Willy Tarreaud0a06d52022-05-18 15:07:19 +02004872 if (show && !table_dump_head_to_buffer(&trash, appctx, ctx->t, ctx->target))
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004873 return 0;
4874
Willy Tarreau3c69e082022-05-03 11:35:07 +02004875 if (ctx->target &&
William Lallemand07a62f72017-05-24 00:57:40 +02004876 (strm_li(s)->bind_conf->level & ACCESS_LVL_MASK) >= ACCESS_LVL_OPER) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004877 /* dump entries only if table explicitly requested */
Willy Tarreau76642222022-10-11 12:02:50 +02004878 HA_RWLOCK_WRLOCK(STK_TABLE_LOCK, &ctx->t->lock);
Willy Tarreau3c69e082022-05-03 11:35:07 +02004879 eb = ebmb_first(&ctx->t->keys);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004880 if (eb) {
Willy Tarreau3c69e082022-05-03 11:35:07 +02004881 ctx->entry = ebmb_entry(eb, struct stksess, key);
4882 ctx->entry->ref_cnt++;
Willy Tarreau7849d4c2022-05-03 11:45:02 +02004883 ctx->state = STATE_DUMP;
Willy Tarreau76642222022-10-11 12:02:50 +02004884 HA_RWLOCK_WRUNLOCK(STK_TABLE_LOCK, &ctx->t->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004885 break;
4886 }
Willy Tarreau76642222022-10-11 12:02:50 +02004887 HA_RWLOCK_WRUNLOCK(STK_TABLE_LOCK, &ctx->t->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004888 }
4889 }
Willy Tarreau3c69e082022-05-03 11:35:07 +02004890 ctx->t = ctx->t->next;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004891 break;
4892
Willy Tarreau7849d4c2022-05-03 11:45:02 +02004893 case STATE_DUMP:
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004894 skip_entry = 0;
4895
Willy Tarreau3c69e082022-05-03 11:35:07 +02004896 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &ctx->entry->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004897
Willy Tarreau3c69e082022-05-03 11:35:07 +02004898 if (ctx->data_type[0] >= 0) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004899 /* we're filtering on some data contents */
4900 void *ptr;
Willy Tarreau2b64a352020-01-22 17:09:47 +01004901 int dt, i;
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004902 signed char op;
4903 long long data, value;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004904
Emeric Brun819fc6f2017-06-13 19:37:32 +02004905
Willy Tarreau2b64a352020-01-22 17:09:47 +01004906 for (i = 0; i < STKTABLE_FILTER_LEN; i++) {
Willy Tarreau3c69e082022-05-03 11:35:07 +02004907 if (ctx->data_type[i] == -1)
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004908 break;
Willy Tarreau3c69e082022-05-03 11:35:07 +02004909 dt = ctx->data_type[i];
4910 ptr = stktable_data_ptr(ctx->t,
4911 ctx->entry,
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004912 dt);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004913
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004914 data = 0;
4915 switch (stktable_data_types[dt].std_type) {
4916 case STD_T_SINT:
4917 data = stktable_data_cast(ptr, std_t_sint);
4918 break;
4919 case STD_T_UINT:
4920 data = stktable_data_cast(ptr, std_t_uint);
4921 break;
4922 case STD_T_ULL:
4923 data = stktable_data_cast(ptr, std_t_ull);
4924 break;
4925 case STD_T_FRQP:
4926 data = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Willy Tarreau3c69e082022-05-03 11:35:07 +02004927 ctx->t->data_arg[dt].u);
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004928 break;
4929 }
4930
Willy Tarreau3c69e082022-05-03 11:35:07 +02004931 op = ctx->data_op[i];
4932 value = ctx->value[i];
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004933
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004934 /* skip the entry if the data does not match the test and the value */
4935 if ((data < value &&
4936 (op == STD_OP_EQ || op == STD_OP_GT || op == STD_OP_GE)) ||
4937 (data == value &&
4938 (op == STD_OP_NE || op == STD_OP_GT || op == STD_OP_LT)) ||
4939 (data > value &&
4940 (op == STD_OP_EQ || op == STD_OP_LT || op == STD_OP_LE))) {
4941 skip_entry = 1;
4942 break;
4943 }
4944 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004945 }
4946
4947 if (show && !skip_entry &&
Willy Tarreaud0a06d52022-05-18 15:07:19 +02004948 !table_dump_entry_to_buffer(&trash, appctx, ctx->t, ctx->entry)) {
Willy Tarreau3c69e082022-05-03 11:35:07 +02004949 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &ctx->entry->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004950 return 0;
4951 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004952
Willy Tarreau3c69e082022-05-03 11:35:07 +02004953 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &ctx->entry->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004954
Willy Tarreau76642222022-10-11 12:02:50 +02004955 HA_RWLOCK_WRLOCK(STK_TABLE_LOCK, &ctx->t->lock);
Willy Tarreau3c69e082022-05-03 11:35:07 +02004956 ctx->entry->ref_cnt--;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004957
Willy Tarreau3c69e082022-05-03 11:35:07 +02004958 eb = ebmb_next(&ctx->entry->key);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004959 if (eb) {
Willy Tarreau3c69e082022-05-03 11:35:07 +02004960 struct stksess *old = ctx->entry;
4961 ctx->entry = ebmb_entry(eb, struct stksess, key);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004962 if (show)
Willy Tarreau3c69e082022-05-03 11:35:07 +02004963 __stksess_kill_if_expired(ctx->t, old);
4964 else if (!skip_entry && !ctx->entry->ref_cnt)
4965 __stksess_kill(ctx->t, old);
4966 ctx->entry->ref_cnt++;
Willy Tarreau76642222022-10-11 12:02:50 +02004967 HA_RWLOCK_WRUNLOCK(STK_TABLE_LOCK, &ctx->t->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004968 break;
4969 }
4970
4971
4972 if (show)
Willy Tarreau3c69e082022-05-03 11:35:07 +02004973 __stksess_kill_if_expired(ctx->t, ctx->entry);
4974 else if (!skip_entry && !ctx->entry->ref_cnt)
4975 __stksess_kill(ctx->t, ctx->entry);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004976
Willy Tarreau76642222022-10-11 12:02:50 +02004977 HA_RWLOCK_WRUNLOCK(STK_TABLE_LOCK, &ctx->t->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004978
Willy Tarreau3c69e082022-05-03 11:35:07 +02004979 ctx->t = ctx->t->next;
Willy Tarreau7849d4c2022-05-03 11:45:02 +02004980 ctx->state = STATE_NEXT;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004981 break;
4982
Willy Tarreau7849d4c2022-05-03 11:45:02 +02004983 default:
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004984 break;
4985 }
4986 }
4987 return 1;
4988}
4989
4990static void cli_release_show_table(struct appctx *appctx)
4991{
Willy Tarreau3c69e082022-05-03 11:35:07 +02004992 struct show_table_ctx *ctx = appctx->svcctx;
4993
Willy Tarreau7849d4c2022-05-03 11:45:02 +02004994 if (ctx->state == STATE_DUMP) {
Willy Tarreau3c69e082022-05-03 11:35:07 +02004995 stksess_kill_if_expired(ctx->t, ctx->entry, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004996 }
4997}
4998
Willy Tarreau478331d2020-08-28 11:31:31 +02004999static void stkt_late_init(void)
5000{
5001 struct sample_fetch *f;
5002
5003 f = find_sample_fetch("src", strlen("src"));
5004 if (f)
5005 smp_fetch_src = f->process;
5006}
5007
5008INITCALL0(STG_INIT, stkt_late_init);
5009
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01005010/* register cli keywords */
5011static struct cli_kw_list cli_kws = {{ },{
Willy Tarreaub205bfd2021-05-07 11:38:37 +02005012 { { "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 },
5013 { { "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 },
5014 { { "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 +01005015 {{},}
5016}};
5017
Willy Tarreau0108d902018-11-25 19:14:37 +01005018INITCALL1(STG_REGISTER, cli_register_kw, &cli_kws);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01005019
Thierry FOURNIER236657b2015-08-19 08:25:14 +02005020static struct action_kw_list tcp_conn_kws = { { }, {
Emeric Brun4d7ada82021-06-30 19:04:16 +02005021 { "sc-inc-gpc", parse_inc_gpc, KWF_MATCH_PREFIX },
5022 { "sc-inc-gpc0", parse_inc_gpc, KWF_MATCH_PREFIX },
5023 { "sc-inc-gpc1", parse_inc_gpc, KWF_MATCH_PREFIX },
Emeric Brun877b0b52021-06-30 18:57:49 +02005024 { "sc-set-gpt", parse_set_gpt, KWF_MATCH_PREFIX },
5025 { "sc-set-gpt0", parse_set_gpt, KWF_MATCH_PREFIX },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02005026 { /* END */ }
5027}};
5028
Willy Tarreau0108d902018-11-25 19:14:37 +01005029INITCALL1(STG_REGISTER, tcp_req_conn_keywords_register, &tcp_conn_kws);
5030
Willy Tarreau620408f2016-10-21 16:37:51 +02005031static struct action_kw_list tcp_sess_kws = { { }, {
Emeric Brun4d7ada82021-06-30 19:04:16 +02005032 { "sc-inc-gpc", parse_inc_gpc, KWF_MATCH_PREFIX },
5033 { "sc-inc-gpc0", parse_inc_gpc, KWF_MATCH_PREFIX },
5034 { "sc-inc-gpc1", parse_inc_gpc, KWF_MATCH_PREFIX },
Emeric Brun877b0b52021-06-30 18:57:49 +02005035 { "sc-set-gpt", parse_set_gpt, KWF_MATCH_PREFIX },
5036 { "sc-set-gpt0", parse_set_gpt, KWF_MATCH_PREFIX },
Willy Tarreau620408f2016-10-21 16:37:51 +02005037 { /* END */ }
5038}};
5039
Willy Tarreau0108d902018-11-25 19:14:37 +01005040INITCALL1(STG_REGISTER, tcp_req_sess_keywords_register, &tcp_sess_kws);
5041
Thierry FOURNIER236657b2015-08-19 08:25:14 +02005042static struct action_kw_list tcp_req_kws = { { }, {
Emeric Brun4d7ada82021-06-30 19:04:16 +02005043 { "sc-inc-gpc", parse_inc_gpc, KWF_MATCH_PREFIX },
5044 { "sc-inc-gpc0", parse_inc_gpc, KWF_MATCH_PREFIX },
5045 { "sc-inc-gpc1", parse_inc_gpc, KWF_MATCH_PREFIX },
Emeric Brun877b0b52021-06-30 18:57:49 +02005046 { "sc-set-gpt", parse_set_gpt, KWF_MATCH_PREFIX },
5047 { "sc-set-gpt0", parse_set_gpt, KWF_MATCH_PREFIX },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02005048 { /* END */ }
5049}};
5050
Willy Tarreau0108d902018-11-25 19:14:37 +01005051INITCALL1(STG_REGISTER, tcp_req_cont_keywords_register, &tcp_req_kws);
5052
Thierry FOURNIER236657b2015-08-19 08:25:14 +02005053static struct action_kw_list tcp_res_kws = { { }, {
Emeric Brun4d7ada82021-06-30 19:04:16 +02005054 { "sc-inc-gpc", parse_inc_gpc, KWF_MATCH_PREFIX },
5055 { "sc-inc-gpc0", parse_inc_gpc, KWF_MATCH_PREFIX },
5056 { "sc-inc-gpc1", parse_inc_gpc, KWF_MATCH_PREFIX },
Emeric Brun877b0b52021-06-30 18:57:49 +02005057 { "sc-set-gpt", parse_set_gpt, KWF_MATCH_PREFIX },
5058 { "sc-set-gpt0", parse_set_gpt, KWF_MATCH_PREFIX },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02005059 { /* END */ }
5060}};
5061
Willy Tarreau0108d902018-11-25 19:14:37 +01005062INITCALL1(STG_REGISTER, tcp_res_cont_keywords_register, &tcp_res_kws);
5063
Thierry FOURNIER236657b2015-08-19 08:25:14 +02005064static struct action_kw_list http_req_kws = { { }, {
Emeric Brun4d7ada82021-06-30 19:04:16 +02005065 { "sc-inc-gpc", parse_inc_gpc, KWF_MATCH_PREFIX },
5066 { "sc-inc-gpc0", parse_inc_gpc, KWF_MATCH_PREFIX },
5067 { "sc-inc-gpc1", parse_inc_gpc, KWF_MATCH_PREFIX },
Emeric Brun877b0b52021-06-30 18:57:49 +02005068 { "sc-set-gpt", parse_set_gpt, KWF_MATCH_PREFIX },
5069 { "sc-set-gpt0", parse_set_gpt, KWF_MATCH_PREFIX },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02005070 { /* END */ }
5071}};
5072
Willy Tarreau0108d902018-11-25 19:14:37 +01005073INITCALL1(STG_REGISTER, http_req_keywords_register, &http_req_kws);
5074
Thierry FOURNIER236657b2015-08-19 08:25:14 +02005075static struct action_kw_list http_res_kws = { { }, {
Emeric Brun4d7ada82021-06-30 19:04:16 +02005076 { "sc-inc-gpc", parse_inc_gpc, KWF_MATCH_PREFIX },
5077 { "sc-inc-gpc0", parse_inc_gpc, KWF_MATCH_PREFIX },
5078 { "sc-inc-gpc1", parse_inc_gpc, KWF_MATCH_PREFIX },
Emeric Brun877b0b52021-06-30 18:57:49 +02005079 { "sc-set-gpt", parse_set_gpt, KWF_MATCH_PREFIX },
5080 { "sc-set-gpt0", parse_set_gpt, KWF_MATCH_PREFIX },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02005081 { /* END */ }
5082}};
5083
Willy Tarreau0108d902018-11-25 19:14:37 +01005084INITCALL1(STG_REGISTER, http_res_keywords_register, &http_res_kws);
5085
Willy Tarreau7d562212016-11-25 16:10:05 +01005086/* Note: must not be declared <const> as its list will be overwritten.
5087 * Please take care of keeping this list alphabetically sorted.
5088 */
5089static struct sample_fetch_kw_list smp_fetch_keywords = {ILH, {
5090 { "sc_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5091 { "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 +02005092 { "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 +01005093 { "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 +01005094 { "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 +01005095 { "sc_conn_cnt", smp_fetch_sc_conn_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5096 { "sc_conn_cur", smp_fetch_sc_conn_cur, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5097 { "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 +02005098 { "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 +01005099 { "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 +02005100 { "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 +01005101 { "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 +01005102 { "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 +02005103 { "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 +01005104 { "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 +01005105 { "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 +01005106 { "sc_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5107 { "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 +01005108 { "sc_http_fail_cnt", smp_fetch_sc_http_fail_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5109 { "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 +01005110 { "sc_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5111 { "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 +02005112 { "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 +01005113 { "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 +01005114 { "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 +01005115 { "sc_kbytes_in", smp_fetch_sc_kbytes_in, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5116 { "sc_kbytes_out", smp_fetch_sc_kbytes_out, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5117 { "sc_sess_cnt", smp_fetch_sc_sess_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5118 { "sc_sess_rate", smp_fetch_sc_sess_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5119 { "sc_tracked", smp_fetch_sc_tracked, ARG2(1,SINT,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
5120 { "sc_trackers", smp_fetch_sc_trackers, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5121 { "sc0_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5122 { "sc0_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5123 { "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 +01005124 { "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 +01005125 { "sc0_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5126 { "sc0_conn_cur", smp_fetch_sc_conn_cur, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5127 { "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 +01005128 { "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 +01005129 { "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 +01005130 { "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 +01005131 { "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 +01005132 { "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 +01005133 { "sc0_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5134 { "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 +01005135 { "sc0_http_fail_cnt", smp_fetch_sc_http_fail_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5136 { "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 +01005137 { "sc0_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5138 { "sc0_http_req_rate", smp_fetch_sc_http_req_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5139 { "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 +01005140 { "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 +01005141 { "sc0_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5142 { "sc0_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5143 { "sc0_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5144 { "sc0_sess_rate", smp_fetch_sc_sess_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5145 { "sc0_tracked", smp_fetch_sc_tracked, ARG1(0,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
5146 { "sc0_trackers", smp_fetch_sc_trackers, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5147 { "sc1_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5148 { "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 +02005149 { "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 +01005150 { "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 +01005151 { "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 +01005152 { "sc1_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5153 { "sc1_conn_cur", smp_fetch_sc_conn_cur, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5154 { "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 +01005155 { "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 +01005156 { "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 +01005157 { "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 +01005158 { "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 +01005159 { "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 +01005160 { "sc1_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5161 { "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 +01005162 { "sc1_http_fail_cnt", smp_fetch_sc_http_fail_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5163 { "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 +01005164 { "sc1_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5165 { "sc1_http_req_rate", smp_fetch_sc_http_req_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5166 { "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 +01005167 { "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 +01005168 { "sc1_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5169 { "sc1_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5170 { "sc1_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5171 { "sc1_sess_rate", smp_fetch_sc_sess_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5172 { "sc1_tracked", smp_fetch_sc_tracked, ARG1(0,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
5173 { "sc1_trackers", smp_fetch_sc_trackers, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5174 { "sc2_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5175 { "sc2_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5176 { "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 +01005177 { "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 +01005178 { "sc2_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5179 { "sc2_conn_cur", smp_fetch_sc_conn_cur, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5180 { "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 +01005181 { "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 +01005182 { "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 +01005183 { "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 +01005184 { "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 +01005185 { "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 +01005186 { "sc2_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5187 { "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 +01005188 { "sc2_http_fail_cnt", smp_fetch_sc_http_fail_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5189 { "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 +01005190 { "sc2_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5191 { "sc2_http_req_rate", smp_fetch_sc_http_req_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5192 { "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 +01005193 { "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 +01005194 { "sc2_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5195 { "sc2_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5196 { "sc2_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5197 { "sc2_sess_rate", smp_fetch_sc_sess_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5198 { "sc2_tracked", smp_fetch_sc_tracked, ARG1(0,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
5199 { "sc2_trackers", smp_fetch_sc_trackers, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5200 { "src_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5201 { "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 +02005202 { "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 +01005203 { "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 +01005204 { "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 +01005205 { "src_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5206 { "src_conn_cur", smp_fetch_sc_conn_cur, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5207 { "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 +02005208 { "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 +01005209 { "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 +02005210 { "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 +01005211 { "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 +01005212 { "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 +02005213 { "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 +01005214 { "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 +01005215 { "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 +01005216 { "src_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5217 { "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 +01005218 { "src_http_fail_cnt", smp_fetch_sc_http_fail_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5219 { "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 +01005220 { "src_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5221 { "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 +02005222 { "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 +01005223 { "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 +01005224 { "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 +01005225 { "src_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5226 { "src_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5227 { "src_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5228 { "src_sess_rate", smp_fetch_sc_sess_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5229 { "src_updt_conn_cnt", smp_fetch_src_updt_conn_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5230 { "table_avl", smp_fetch_table_avl, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5231 { "table_cnt", smp_fetch_table_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5232 { /* END */ },
5233}};
5234
Willy Tarreau0108d902018-11-25 19:14:37 +01005235INITCALL1(STG_REGISTER, sample_register_fetches, &smp_fetch_keywords);
Willy Tarreau7d562212016-11-25 16:10:05 +01005236
Willy Tarreaud9f316a2014-07-10 14:03:38 +02005237/* Note: must not be declared <const> as its list will be overwritten */
5238static struct sample_conv_kw_list sample_conv_kws = {ILH, {
Willy Tarreau2d17db52016-05-25 17:16:38 +02005239 { "in_table", sample_conv_in_table, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_BOOL },
5240 { "table_bytes_in_rate", sample_conv_table_bytes_in_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5241 { "table_bytes_out_rate", sample_conv_table_bytes_out_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5242 { "table_conn_cnt", sample_conv_table_conn_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5243 { "table_conn_cur", sample_conv_table_conn_cur, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5244 { "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 +02005245 { "table_expire", sample_conv_table_expire, ARG2(1,TAB,SINT), NULL, SMP_T_ANY, SMP_T_SINT },
Emeric Brun877b0b52021-06-30 18:57:49 +02005246 { "table_gpt", sample_conv_table_gpt, ARG2(2,SINT,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
Willy Tarreau2d17db52016-05-25 17:16:38 +02005247 { "table_gpt0", sample_conv_table_gpt0, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
Emeric Brun4d7ada82021-06-30 19:04:16 +02005248 { "table_gpc", sample_conv_table_gpc, ARG2(2,SINT,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
Willy Tarreau2d17db52016-05-25 17:16:38 +02005249 { "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 +01005250 { "table_gpc1", sample_conv_table_gpc1, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
Emeric Brun4d7ada82021-06-30 19:04:16 +02005251 { "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 +02005252 { "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 +01005253 { "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 +02005254 { "table_http_err_cnt", sample_conv_table_http_err_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5255 { "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 +01005256 { "table_http_fail_cnt", sample_conv_table_http_fail_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5257 { "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 +02005258 { "table_http_req_cnt", sample_conv_table_http_req_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5259 { "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 +02005260 { "table_idle", sample_conv_table_idle, ARG2(1,TAB,SINT), NULL, SMP_T_ANY, SMP_T_SINT },
Willy Tarreau2d17db52016-05-25 17:16:38 +02005261 { "table_kbytes_in", sample_conv_table_kbytes_in, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5262 { "table_kbytes_out", sample_conv_table_kbytes_out, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5263 { "table_server_id", sample_conv_table_server_id, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5264 { "table_sess_cnt", sample_conv_table_sess_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5265 { "table_sess_rate", sample_conv_table_sess_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5266 { "table_trackers", sample_conv_table_trackers, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
Willy Tarreaud9f316a2014-07-10 14:03:38 +02005267 { /* END */ },
5268}};
5269
Willy Tarreau0108d902018-11-25 19:14:37 +01005270INITCALL1(STG_REGISTER, sample_register_convs, &sample_conv_kws);