blob: 1050a0fa8c4ee1c0a9501967c6d405e4ceedcf08 [file] [log] [blame]
Emeric Brun3bd697e2010-01-04 15:23:48 +01001/*
2 * Stick tables management functions.
3 *
4 * Copyright 2009-2010 EXCELIANCE, Emeric Brun <ebrun@exceliance.fr>
Willy Tarreau08d5f982010-06-06 13:34:54 +02005 * Copyright (C) 2010 Willy Tarreau <w@1wt.eu>
Emeric Brun3bd697e2010-01-04 15:23:48 +01006 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version
10 * 2 of the License, or (at your option) any later version.
11 *
12 */
13
14#include <string.h>
Willy Tarreauf13ebdf2016-11-22 18:00:53 +010015#include <errno.h>
Emeric Brun3bd697e2010-01-04 15:23:48 +010016
Willy Tarreaub2551052020-06-09 09:07:15 +020017#include <import/ebmbtree.h>
18#include <import/ebsttree.h>
19#include <import/ebistree.h>
20
Willy Tarreau4c7e4b72020-05-27 12:58:42 +020021#include <haproxy/api.h>
Willy Tarreau3c69e082022-05-03 11:35:07 +020022#include <haproxy/applet.h>
Willy Tarreaub2551052020-06-09 09:07:15 +020023#include <haproxy/arg.h>
Willy Tarreau6be78492020-06-05 00:00:29 +020024#include <haproxy/cfgparse.h>
Willy Tarreau83487a82020-06-04 20:19:54 +020025#include <haproxy/cli.h>
Thayne McCombs92149f92020-11-20 01:28:26 -070026#include <haproxy/dict.h>
Willy Tarreau36979d92020-06-05 17:27:29 +020027#include <haproxy/errors.h>
Willy Tarreauf268ee82020-06-04 17:05:57 +020028#include <haproxy/global.h>
Willy Tarreauc761f842020-06-04 11:40:28 +020029#include <haproxy/http_rules.h>
Willy Tarreau853b2972020-05-27 18:01:47 +020030#include <haproxy/list.h>
Willy Tarreauaeed4a82020-06-04 22:01:04 +020031#include <haproxy/log.h>
Willy Tarreau6131d6a2020-06-02 16:48:09 +020032#include <haproxy/net_helper.h>
Willy Tarreau3c2a7c22020-06-04 18:38:21 +020033#include <haproxy/peers.h>
Willy Tarreaub2551052020-06-09 09:07:15 +020034#include <haproxy/pool.h>
35#include <haproxy/proto_tcp.h>
Willy Tarreaua264d962020-06-04 22:29:18 +020036#include <haproxy/proxy.h>
Willy Tarreaub2551052020-06-09 09:07:15 +020037#include <haproxy/sample.h>
Willy Tarreau5edca2f2022-05-27 09:25:10 +020038#include <haproxy/sc_strm.h>
Willy Tarreau2eec9b52020-06-04 19:58:55 +020039#include <haproxy/stats-t.h>
Willy Tarreaucb086c62022-05-27 09:47:12 +020040#include <haproxy/stconn.h>
Willy Tarreaub2551052020-06-09 09:07:15 +020041#include <haproxy/stick_table.h>
Willy Tarreaudfd3de82020-06-04 23:46:14 +020042#include <haproxy/stream.h>
Willy Tarreaucea0e1b2020-06-04 17:25:40 +020043#include <haproxy/task.h>
Willy Tarreau8b550af2020-06-04 17:42:48 +020044#include <haproxy/tcp_rules.h>
Willy Tarreau9310f482021-10-06 16:18:40 +020045#include <haproxy/ticks.h>
Willy Tarreaub2551052020-06-09 09:07:15 +020046#include <haproxy/tools.h>
Emeric Brun3bd697e2010-01-04 15:23:48 +010047
Emeric Brun3bd697e2010-01-04 15:23:48 +010048
Willy Tarreau12785782012-04-27 21:37:17 +020049/* structure used to return a table key built from a sample */
Emeric Brun819fc6f2017-06-13 19:37:32 +020050static THREAD_LOCAL struct stktable_key static_table_key;
Willy Tarreau478331d2020-08-28 11:31:31 +020051static int (*smp_fetch_src)(const struct arg *, struct sample *, const char *, void *);
Willy Tarreauf0b38bf2010-06-06 13:22:23 +020052
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +010053struct stktable *stktables_list;
54struct eb_root stktable_by_name = EB_ROOT;
55
Olivier Houchard52dabbc2018-11-14 17:54:36 +010056#define round_ptr_size(i) (((i) + (sizeof(void *) - 1)) &~ (sizeof(void *) - 1))
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +010057
58/* This function inserts stktable <t> into the tree of known stick-table.
59 * The stick-table ID is used as the storing key so it must already have
60 * been initialized.
61 */
62void stktable_store_name(struct stktable *t)
63{
64 t->name.key = t->id;
65 ebis_insert(&stktable_by_name, &t->name);
66}
67
68struct stktable *stktable_find_by_name(const char *name)
69{
70 struct ebpt_node *node;
71 struct stktable *t;
72
73 node = ebis_lookup(&stktable_by_name, name);
74 if (node) {
75 t = container_of(node, struct stktable, name);
Tim Duesterhuse5ff1412021-01-02 22:31:53 +010076 if (strcmp(t->id, name) == 0)
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +010077 return t;
78 }
79
80 return NULL;
81}
82
Emeric Brun3bd697e2010-01-04 15:23:48 +010083/*
Willy Tarreauaea940e2010-06-06 11:56:36 +020084 * Free an allocated sticky session <ts>, and decrease sticky sessions counter
Willy Tarreau996f1a52022-10-11 16:19:35 +020085 * in table <t>. It's safe to call it under or out of a lock.
Emeric Brun3bd697e2010-01-04 15:23:48 +010086 */
Emeric Brun819fc6f2017-06-13 19:37:32 +020087void __stksess_free(struct stktable *t, struct stksess *ts)
Emeric Brun3bd697e2010-01-04 15:23:48 +010088{
Willy Tarreau996f1a52022-10-11 16:19:35 +020089 HA_ATOMIC_DEC(&t->current);
Olivier Houchard52dabbc2018-11-14 17:54:36 +010090 pool_free(t->pool, (void *)ts - round_ptr_size(t->data_size));
Emeric Brun3bd697e2010-01-04 15:23:48 +010091}
92
93/*
Emeric Brun819fc6f2017-06-13 19:37:32 +020094 * Free an allocated sticky session <ts>, and decrease sticky sessions counter
95 * in table <t>.
96 * This function locks the table
97 */
98void stksess_free(struct stktable *t, struct stksess *ts)
99{
Thayne McCombs92149f92020-11-20 01:28:26 -0700100 void *data;
101 data = stktable_data_ptr(t, ts, STKTABLE_DT_SERVER_KEY);
102 if (data) {
Emeric Brun0e3457b2021-06-30 17:18:28 +0200103 dict_entry_unref(&server_key_dict, stktable_data_cast(data, std_t_dict));
104 stktable_data_cast(data, std_t_dict) = NULL;
Thayne McCombs92149f92020-11-20 01:28:26 -0700105 }
Willy Tarreau8d3c3332022-10-11 18:50:22 +0000106 HA_RWLOCK_RDLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200107 __stksess_free(t, ts);
Willy Tarreau8d3c3332022-10-11 18:50:22 +0000108 HA_RWLOCK_RDUNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200109}
110
111/*
Willy Tarreauf6efda12010-08-03 20:34:06 +0200112 * Kill an stksess (only if its ref_cnt is zero).
113 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200114int __stksess_kill(struct stktable *t, struct stksess *ts)
Willy Tarreauf6efda12010-08-03 20:34:06 +0200115{
116 if (ts->ref_cnt)
Emeric Brun819fc6f2017-06-13 19:37:32 +0200117 return 0;
Willy Tarreauf6efda12010-08-03 20:34:06 +0200118
119 eb32_delete(&ts->exp);
Emeric Brun85e77c72010-09-23 18:16:52 +0200120 eb32_delete(&ts->upd);
Willy Tarreauf6efda12010-08-03 20:34:06 +0200121 ebmb_delete(&ts->key);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200122 __stksess_free(t, ts);
123 return 1;
Willy Tarreauf6efda12010-08-03 20:34:06 +0200124}
125
126/*
Emeric Brun819fc6f2017-06-13 19:37:32 +0200127 * Decrease the refcount if decrefcnt is not 0.
128 * and try to kill the stksess
129 * This function locks the table
130 */
131int stksess_kill(struct stktable *t, struct stksess *ts, int decrefcnt)
132{
133 int ret;
134
Willy Tarreau76642222022-10-11 12:02:50 +0200135 HA_RWLOCK_WRLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200136 if (decrefcnt)
137 ts->ref_cnt--;
138 ret = __stksess_kill(t, ts);
Willy Tarreau76642222022-10-11 12:02:50 +0200139 HA_RWLOCK_WRUNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200140
141 return ret;
142}
143
144/*
Willy Tarreauaea940e2010-06-06 11:56:36 +0200145 * Initialize or update the key in the sticky session <ts> present in table <t>
146 * from the value present in <key>.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100147 */
Willy Tarreau393379c2010-06-06 12:11:37 +0200148void stksess_setkey(struct stktable *t, struct stksess *ts, struct stktable_key *key)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100149{
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200150 if (t->type != SMP_T_STR)
Willy Tarreau86257dc2010-06-06 12:57:10 +0200151 memcpy(ts->key.key, key->key, t->key_size);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100152 else {
Willy Tarreau86257dc2010-06-06 12:57:10 +0200153 memcpy(ts->key.key, key->key, MIN(t->key_size - 1, key->key_len));
154 ts->key.key[MIN(t->key_size - 1, key->key_len)] = 0;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100155 }
156}
157
158
159/*
Willy Tarreau393379c2010-06-06 12:11:37 +0200160 * Init sticky session <ts> of table <t>. The data parts are cleared and <ts>
161 * is returned.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100162 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200163static struct stksess *__stksess_init(struct stktable *t, struct stksess * ts)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100164{
Willy Tarreau393379c2010-06-06 12:11:37 +0200165 memset((void *)ts - t->data_size, 0, t->data_size);
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200166 ts->ref_cnt = 0;
Willy Tarreau86257dc2010-06-06 12:57:10 +0200167 ts->key.node.leaf_p = NULL;
168 ts->exp.node.leaf_p = NULL;
Emeric Brun85e77c72010-09-23 18:16:52 +0200169 ts->upd.node.leaf_p = NULL;
Emeric Brun819fc6f2017-06-13 19:37:32 +0200170 ts->expire = tick_add(now_ms, MS_TO_TICKS(t->expire));
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100171 HA_RWLOCK_INIT(&ts->lock);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100172 return ts;
173}
174
175/*
Willy Tarreauaea940e2010-06-06 11:56:36 +0200176 * Trash oldest <to_batch> sticky sessions from table <t>
Willy Tarreaudfe79252020-11-03 17:47:41 +0100177 * Returns number of trashed sticky sessions. It may actually trash less
178 * than expected if finding these requires too long a search time (e.g.
179 * most of them have ts->ref_cnt>0).
Emeric Brun3bd697e2010-01-04 15:23:48 +0100180 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200181int __stktable_trash_oldest(struct stktable *t, int to_batch)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100182{
183 struct stksess *ts;
184 struct eb32_node *eb;
Willy Tarreaudfe79252020-11-03 17:47:41 +0100185 int max_search = to_batch * 2; // no more than 50% misses
Emeric Brun3bd697e2010-01-04 15:23:48 +0100186 int batched = 0;
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200187 int looped = 0;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100188
189 eb = eb32_lookup_ge(&t->exps, now_ms - TIMER_LOOK_BACK);
190
191 while (batched < to_batch) {
192
193 if (unlikely(!eb)) {
194 /* we might have reached the end of the tree, typically because
195 * <now_ms> is in the first half and we're first scanning the last
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200196 * half. Let's loop back to the beginning of the tree now if we
197 * have not yet visited it.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100198 */
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200199 if (looped)
200 break;
201 looped = 1;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100202 eb = eb32_first(&t->exps);
203 if (likely(!eb))
204 break;
205 }
206
Willy Tarreaudfe79252020-11-03 17:47:41 +0100207 if (--max_search < 0)
208 break;
209
Emeric Brun3bd697e2010-01-04 15:23:48 +0100210 /* timer looks expired, detach it from the queue */
Willy Tarreau86257dc2010-06-06 12:57:10 +0200211 ts = eb32_entry(eb, struct stksess, exp);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100212 eb = eb32_next(eb);
213
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200214 /* don't delete an entry which is currently referenced */
215 if (ts->ref_cnt)
216 continue;
217
Willy Tarreau86257dc2010-06-06 12:57:10 +0200218 eb32_delete(&ts->exp);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100219
Willy Tarreau86257dc2010-06-06 12:57:10 +0200220 if (ts->expire != ts->exp.key) {
Emeric Brun3bd697e2010-01-04 15:23:48 +0100221 if (!tick_isset(ts->expire))
222 continue;
223
Willy Tarreau86257dc2010-06-06 12:57:10 +0200224 ts->exp.key = ts->expire;
225 eb32_insert(&t->exps, &ts->exp);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100226
Willy Tarreau86257dc2010-06-06 12:57:10 +0200227 if (!eb || eb->key > ts->exp.key)
228 eb = &ts->exp;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100229
230 continue;
231 }
Emeric Brun3bd697e2010-01-04 15:23:48 +0100232
Willy Tarreauaea940e2010-06-06 11:56:36 +0200233 /* session expired, trash it */
Willy Tarreau86257dc2010-06-06 12:57:10 +0200234 ebmb_delete(&ts->key);
Emeric Brun85e77c72010-09-23 18:16:52 +0200235 eb32_delete(&ts->upd);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200236 __stksess_free(t, ts);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100237 batched++;
238 }
239
240 return batched;
241}
242
243/*
Emeric Brun819fc6f2017-06-13 19:37:32 +0200244 * Trash oldest <to_batch> sticky sessions from table <t>
245 * Returns number of trashed sticky sessions.
246 * This function locks the table
247 */
248int stktable_trash_oldest(struct stktable *t, int to_batch)
249{
250 int ret;
251
Willy Tarreau76642222022-10-11 12:02:50 +0200252 HA_RWLOCK_WRLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200253 ret = __stktable_trash_oldest(t, to_batch);
Willy Tarreau76642222022-10-11 12:02:50 +0200254 HA_RWLOCK_WRUNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200255
256 return ret;
257}
258/*
Willy Tarreauaea940e2010-06-06 11:56:36 +0200259 * Allocate and initialise a new sticky session.
260 * The new sticky session is returned or NULL in case of lack of memory.
261 * Sticky sessions should only be allocated this way, and must be freed using
Willy Tarreaua7b46b52013-04-11 16:55:37 +0200262 * stksess_free(). Table <t>'s sticky session counter is increased. If <key>
Willy Tarreau996f1a52022-10-11 16:19:35 +0200263 * is not NULL, it is assigned to the new session. It must be called unlocked
264 * as it may rely on a lock to trash older entries.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100265 */
Willy Tarreau996f1a52022-10-11 16:19:35 +0200266struct stksess *stksess_new(struct stktable *t, struct stktable_key *key)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100267{
268 struct stksess *ts;
Willy Tarreau996f1a52022-10-11 16:19:35 +0200269 unsigned int current;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100270
Willy Tarreau996f1a52022-10-11 16:19:35 +0200271 current = HA_ATOMIC_FETCH_ADD(&t->current, 1);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100272
Willy Tarreau996f1a52022-10-11 16:19:35 +0200273 if (unlikely(current >= t->size)) {
274 /* the table was already full, we may have to purge entries */
275 if (t->nopurge || !stktable_trash_oldest(t, (t->size >> 8) + 1)) {
276 HA_ATOMIC_DEC(&t->current);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100277 return NULL;
Willy Tarreau996f1a52022-10-11 16:19:35 +0200278 }
Emeric Brun3bd697e2010-01-04 15:23:48 +0100279 }
280
Willy Tarreaubafbe012017-11-24 17:34:44 +0100281 ts = pool_alloc(t->pool);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100282 if (ts) {
Olivier Houchard52dabbc2018-11-14 17:54:36 +0100283 ts = (void *)ts + round_ptr_size(t->data_size);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200284 __stksess_init(t, ts);
Willy Tarreaua7b46b52013-04-11 16:55:37 +0200285 if (key)
286 stksess_setkey(t, ts, key);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100287 }
288
289 return ts;
290}
291
292/*
Willy Tarreauf16d2b82010-06-06 15:38:59 +0200293 * Looks in table <t> for a sticky session matching key <key>.
Willy Tarreauaea940e2010-06-06 11:56:36 +0200294 * Returns pointer on requested sticky session or NULL if none was found.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100295 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200296struct stksess *__stktable_lookup_key(struct stktable *t, struct stktable_key *key)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100297{
298 struct ebmb_node *eb;
299
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200300 if (t->type == SMP_T_STR)
Emeric Brun485479d2010-09-23 18:02:19 +0200301 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 +0100302 else
303 eb = ebmb_lookup(&t->keys, key->key, t->key_size);
304
305 if (unlikely(!eb)) {
306 /* no session found */
307 return NULL;
308 }
309
Willy Tarreau86257dc2010-06-06 12:57:10 +0200310 return ebmb_entry(eb, struct stksess, key);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100311}
312
Emeric Brun819fc6f2017-06-13 19:37:32 +0200313/*
314 * Looks in table <t> for a sticky session matching key <key>.
315 * Returns pointer on requested sticky session or NULL if none was found.
316 * The refcount of the found entry is increased and this function
317 * is protected using the table lock
Willy Tarreau1f7e9252010-06-20 12:27:21 +0200318 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200319struct stksess *stktable_lookup_key(struct stktable *t, struct stktable_key *key)
Willy Tarreau1f7e9252010-06-20 12:27:21 +0200320{
321 struct stksess *ts;
322
Willy Tarreaua7d6a132022-10-11 15:42:54 +0200323 HA_RWLOCK_RDLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200324 ts = __stktable_lookup_key(t, key);
325 if (ts)
Willy Tarreaua7d6a132022-10-11 15:42:54 +0200326 HA_ATOMIC_INC(&ts->ref_cnt);
327 HA_RWLOCK_RDUNLOCK(STK_TABLE_LOCK, &t->lock);
Willy Tarreau1f7e9252010-06-20 12:27:21 +0200328
Willy Tarreau1f7e9252010-06-20 12:27:21 +0200329 return ts;
330}
331
Willy Tarreauf16d2b82010-06-06 15:38:59 +0200332/*
333 * Looks in table <t> for a sticky session with same key as <ts>.
334 * Returns pointer on requested sticky session or NULL if none was found.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100335 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200336struct stksess *__stktable_lookup(struct stktable *t, struct stksess *ts)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100337{
Emeric Brun3bd697e2010-01-04 15:23:48 +0100338 struct ebmb_node *eb;
339
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200340 if (t->type == SMP_T_STR)
Willy Tarreau86257dc2010-06-06 12:57:10 +0200341 eb = ebst_lookup(&(t->keys), (char *)ts->key.key);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100342 else
Willy Tarreau86257dc2010-06-06 12:57:10 +0200343 eb = ebmb_lookup(&(t->keys), ts->key.key, t->key_size);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100344
Willy Tarreauf16d2b82010-06-06 15:38:59 +0200345 if (unlikely(!eb))
346 return NULL;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100347
Willy Tarreauf16d2b82010-06-06 15:38:59 +0200348 return ebmb_entry(eb, struct stksess, key);
349}
Emeric Brun3bd697e2010-01-04 15:23:48 +0100350
Emeric Brun819fc6f2017-06-13 19:37:32 +0200351/*
352 * Looks in table <t> for a sticky session with same key as <ts>.
353 * Returns pointer on requested sticky session or NULL if none was found.
354 * The refcount of the found entry is increased and this function
355 * is protected using the table lock
356 */
357struct stksess *stktable_lookup(struct stktable *t, struct stksess *ts)
358{
359 struct stksess *lts;
360
Willy Tarreaua7d6a132022-10-11 15:42:54 +0200361 HA_RWLOCK_RDLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200362 lts = __stktable_lookup(t, ts);
363 if (lts)
Willy Tarreaua7d6a132022-10-11 15:42:54 +0200364 HA_ATOMIC_INC(&lts->ref_cnt);
365 HA_RWLOCK_RDUNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200366
367 return lts;
368}
369
Willy Tarreaucb183642010-06-06 17:58:34 +0200370/* Update the expiration timer for <ts> but do not touch its expiration node.
371 * The table's expiration timer is updated if set.
Emeric Brun819fc6f2017-06-13 19:37:32 +0200372 * The node will be also inserted into the update tree if needed, at a position
Willy Tarreau9f5cb432022-10-11 18:17:58 +0000373 * depending if the update is a local or coming from a remote node.
374 * If <decrefcnt> is set, the ts entry's ref_cnt will be decremented. The table's
375 * write lock may be taken.
Willy Tarreaucb183642010-06-06 17:58:34 +0200376 */
Willy Tarreau9f5cb432022-10-11 18:17:58 +0000377void stktable_touch_with_exp(struct stktable *t, struct stksess *ts, int local, int expire, int decrefcnt)
Willy Tarreaucb183642010-06-06 17:58:34 +0200378{
Emeric Brun85e77c72010-09-23 18:16:52 +0200379 struct eb32_node * eb;
Willy Tarreaua7536ef2022-10-11 18:31:04 +0000380 int locked = 0;
Willy Tarreau9f5cb432022-10-11 18:17:58 +0000381
Willy Tarreaua7536ef2022-10-11 18:31:04 +0000382 if (expire != HA_ATOMIC_LOAD(&ts->expire)) {
383 /* we'll need to set the expiration and to wake up the expiration timer .*/
384 HA_ATOMIC_STORE(&ts->expire, expire);
385 if (t->expire) {
386 if (!locked++)
387 HA_RWLOCK_WRLOCK(STK_TABLE_LOCK, &t->lock);
388 t->exp_task->expire = t->exp_next = tick_first(expire, t->exp_next);
389 task_queue(t->exp_task);
390 /* keep the lock */
391 }
Willy Tarreaucb183642010-06-06 17:58:34 +0200392 }
Emeric Brun85e77c72010-09-23 18:16:52 +0200393
Emeric Brun819fc6f2017-06-13 19:37:32 +0200394 /* If sync is enabled */
395 if (t->sync_task) {
396 if (local) {
397 /* If this entry is not in the tree
Willy Tarreaua7536ef2022-10-11 18:31:04 +0000398 * or not scheduled for at least one peer.
399 */
400 if (!locked++)
401 HA_RWLOCK_WRLOCK(STK_TABLE_LOCK, &t->lock);
402
Emeric Brun819fc6f2017-06-13 19:37:32 +0200403 if (!ts->upd.node.leaf_p
404 || (int)(t->commitupdate - ts->upd.key) >= 0
405 || (int)(ts->upd.key - t->localupdate) >= 0) {
406 ts->upd.key = ++t->update;
407 t->localupdate = t->update;
408 eb32_delete(&ts->upd);
409 eb = eb32_insert(&t->updates, &ts->upd);
410 if (eb != &ts->upd) {
411 eb32_delete(eb);
412 eb32_insert(&t->updates, &ts->upd);
413 }
Emeric Brunaaf58602015-06-15 17:23:30 +0200414 }
Emeric Brun819fc6f2017-06-13 19:37:32 +0200415 task_wakeup(t->sync_task, TASK_WOKEN_MSG);
Emeric Brun85e77c72010-09-23 18:16:52 +0200416 }
Emeric Brun819fc6f2017-06-13 19:37:32 +0200417 else {
418 /* If this entry is not in the tree */
Willy Tarreaua7536ef2022-10-11 18:31:04 +0000419 if (!locked++)
420 HA_RWLOCK_WRLOCK(STK_TABLE_LOCK, &t->lock);
421
Emeric Brun819fc6f2017-06-13 19:37:32 +0200422 if (!ts->upd.node.leaf_p) {
423 ts->upd.key= (++t->update)+(2147483648U);
424 eb = eb32_insert(&t->updates, &ts->upd);
425 if (eb != &ts->upd) {
426 eb32_delete(eb);
427 eb32_insert(&t->updates, &ts->upd);
428 }
429 }
430 }
Emeric Brun85e77c72010-09-23 18:16:52 +0200431 }
Willy Tarreau9f5cb432022-10-11 18:17:58 +0000432
Willy Tarreaua7536ef2022-10-11 18:31:04 +0000433 if (decrefcnt) {
434 if (locked)
435 ts->ref_cnt--;
436 else {
437 HA_RWLOCK_RDLOCK(STK_TABLE_LOCK, &t->lock);
438 HA_ATOMIC_DEC(&ts->ref_cnt);
439 HA_RWLOCK_RDUNLOCK(STK_TABLE_LOCK, &t->lock);
440 }
441 }
442
443 if (locked)
444 HA_RWLOCK_WRUNLOCK(STK_TABLE_LOCK, &t->lock);
Willy Tarreaucb183642010-06-06 17:58:34 +0200445}
446
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200447/* Update the expiration timer for <ts> but do not touch its expiration node.
Emeric Brun819fc6f2017-06-13 19:37:32 +0200448 * The table's expiration timer is updated using the date of expiration coming from
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200449 * <t> stick-table configuration.
Emeric Brun819fc6f2017-06-13 19:37:32 +0200450 * The node will be also inserted into the update tree if needed, at a position
451 * considering the update is coming from a remote node
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200452 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200453void stktable_touch_remote(struct stktable *t, struct stksess *ts, int decrefcnt)
454{
Willy Tarreau9f5cb432022-10-11 18:17:58 +0000455 stktable_touch_with_exp(t, ts, 0, ts->expire, decrefcnt);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200456}
457
458/* Update the expiration timer for <ts> but do not touch its expiration node.
459 * The table's expiration timer is updated using the date of expiration coming from
460 * <t> stick-table configuration.
461 * The node will be also inserted into the update tree if needed, at a position
462 * considering the update was made locally
463 */
464void stktable_touch_local(struct stktable *t, struct stksess *ts, int decrefcnt)
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200465{
466 int expire = tick_add(now_ms, MS_TO_TICKS(t->expire));
467
Willy Tarreau9f5cb432022-10-11 18:17:58 +0000468 stktable_touch_with_exp(t, ts, 1, expire, decrefcnt);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200469}
Willy Tarreau4be073b2022-10-11 18:10:27 +0000470/* Just decrease the ref_cnt of the current session. Does nothing if <ts> is NULL.
471 * Note that we still need to take the read lock because a number of other places
472 * (including in Lua and peers) update the ref_cnt non-atomically under the write
473 * lock.
474 */
Willy Tarreau43e90352018-06-27 06:25:57 +0200475static void stktable_release(struct stktable *t, struct stksess *ts)
Emeric Brun819fc6f2017-06-13 19:37:32 +0200476{
Willy Tarreau43e90352018-06-27 06:25:57 +0200477 if (!ts)
478 return;
Willy Tarreau4be073b2022-10-11 18:10:27 +0000479 HA_RWLOCK_RDLOCK(STK_TABLE_LOCK, &t->lock);
480 HA_ATOMIC_DEC(&ts->ref_cnt);
481 HA_RWLOCK_RDUNLOCK(STK_TABLE_LOCK, &t->lock);
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200482}
483
Willy Tarreauf16d2b82010-06-06 15:38:59 +0200484/* Insert new sticky session <ts> in the table. It is assumed that it does not
485 * yet exist (the caller must check this). The table's timeout is updated if it
Willy Tarreaud2d3fd92022-10-11 15:09:46 +0200486 * is set. <ts> is returned if properly inserted, otherwise the one already
487 * present if any.
Willy Tarreauf16d2b82010-06-06 15:38:59 +0200488 */
Willy Tarreaud2d3fd92022-10-11 15:09:46 +0200489struct stksess *__stktable_store(struct stktable *t, struct stksess *ts)
Willy Tarreauf16d2b82010-06-06 15:38:59 +0200490{
Willy Tarreaud2d3fd92022-10-11 15:09:46 +0200491 struct ebmb_node *eb;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100492
Willy Tarreaud2d3fd92022-10-11 15:09:46 +0200493 eb = ebmb_insert(&t->keys, &ts->key, t->key_size);
494 if (likely(eb == &ts->key)) {
495 ts->exp.key = ts->expire;
496 eb32_insert(&t->exps, &ts->exp);
497 }
Emeric Brun819fc6f2017-06-13 19:37:32 +0200498 if (t->expire) {
499 t->exp_task->expire = t->exp_next = tick_first(ts->expire, t->exp_next);
500 task_queue(t->exp_task);
501 }
Willy Tarreaud2d3fd92022-10-11 15:09:46 +0200502 return ebmb_entry(eb, struct stksess, key); // most commonly this is <ts>
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200503}
504
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200505/* Returns a valid or initialized stksess for the specified stktable_key in the
506 * specified table, or NULL if the key was NULL, or if no entry was found nor
Willy Tarreau47f22972022-10-11 15:22:42 +0200507 * could be created. The entry's expiration is updated. This function locks the
508 * table, and the refcount of the entry is increased.
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200509 */
Willy Tarreau47f22972022-10-11 15:22:42 +0200510struct stksess *stktable_get_entry(struct stktable *table, struct stktable_key *key)
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200511{
Willy Tarreau175aa062022-10-11 15:13:46 +0200512 struct stksess *ts, *ts2;
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200513
514 if (!key)
515 return NULL;
516
Willy Tarreau47f22972022-10-11 15:22:42 +0200517 ts = stktable_lookup_key(table, key);
518 if (ts)
519 return ts;
Emeric Brun819fc6f2017-06-13 19:37:32 +0200520
Willy Tarreau996f1a52022-10-11 16:19:35 +0200521 /* No such entry exists, let's try to create a new one. this doesn't
522 * require locking yet.
523 */
524
525 ts = stksess_new(table, key);
526 if (!ts)
527 return NULL;
528
529 /* Now we're certain to have a ts. We need to store it. For this we'll
Willy Tarreau47f22972022-10-11 15:22:42 +0200530 * need an exclusive access. We don't need an atomic upgrade, this is
531 * rare and an unlock+lock sequence will do the job fine. Given that
532 * this will not be atomic, the missing entry might appear in the mean
533 * tome so we have to be careful that the one we try to insert is the
534 * one we find.
535 */
Willy Tarreau47f22972022-10-11 15:22:42 +0200536
Willy Tarreau996f1a52022-10-11 16:19:35 +0200537 HA_RWLOCK_WRLOCK(STK_TABLE_LOCK, &table->lock);
Willy Tarreau47f22972022-10-11 15:22:42 +0200538
539 ts2 = __stktable_store(table, ts);
540 if (unlikely(ts2 != ts)) {
541 /* another entry was added in the mean time, let's
542 * switch to it.
543 */
544 __stksess_free(table, ts);
545 ts = ts2;
546 }
547
548 HA_ATOMIC_INC(&ts->ref_cnt);
Willy Tarreau76642222022-10-11 12:02:50 +0200549 HA_RWLOCK_WRUNLOCK(STK_TABLE_LOCK, &table->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200550
551 return ts;
552}
553
554/* Lookup for an entry with the same key and store the submitted
555 * stksess if not found.
556 */
557struct stksess *__stktable_set_entry(struct stktable *table, struct stksess *nts)
558{
559 struct stksess *ts;
560
561 ts = __stktable_lookup(table, nts);
562 if (ts == NULL) {
563 ts = nts;
564 __stktable_store(table, ts);
565 }
566 return ts;
567}
568
569/* Lookup for an entry with the same key and store the submitted
570 * stksess if not found.
571 * This function locks the table, and the refcount of the entry is increased.
572 */
573struct stksess *stktable_set_entry(struct stktable *table, struct stksess *nts)
574{
575 struct stksess *ts;
576
Willy Tarreau76642222022-10-11 12:02:50 +0200577 HA_RWLOCK_WRLOCK(STK_TABLE_LOCK, &table->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200578 ts = __stktable_set_entry(table, nts);
579 ts->ref_cnt++;
Willy Tarreau76642222022-10-11 12:02:50 +0200580 HA_RWLOCK_WRUNLOCK(STK_TABLE_LOCK, &table->lock);
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200581
Emeric Brun819fc6f2017-06-13 19:37:32 +0200582 return ts;
583}
Emeric Brun3bd697e2010-01-04 15:23:48 +0100584/*
Willy Tarreauaea940e2010-06-06 11:56:36 +0200585 * Trash expired sticky sessions from table <t>. The next expiration date is
586 * returned.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100587 */
588static int stktable_trash_expired(struct stktable *t)
589{
590 struct stksess *ts;
591 struct eb32_node *eb;
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200592 int looped = 0;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100593
Willy Tarreau76642222022-10-11 12:02:50 +0200594 HA_RWLOCK_WRLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100595 eb = eb32_lookup_ge(&t->exps, now_ms - TIMER_LOOK_BACK);
596
597 while (1) {
598 if (unlikely(!eb)) {
599 /* we might have reached the end of the tree, typically because
600 * <now_ms> is in the first half and we're first scanning the last
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200601 * half. Let's loop back to the beginning of the tree now if we
602 * have not yet visited it.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100603 */
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200604 if (looped)
605 break;
606 looped = 1;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100607 eb = eb32_first(&t->exps);
608 if (likely(!eb))
609 break;
610 }
611
612 if (likely(tick_is_lt(now_ms, eb->key))) {
613 /* timer not expired yet, revisit it later */
614 t->exp_next = eb->key;
Willy Tarreau4d5f13c2017-11-05 11:04:47 +0100615 goto out_unlock;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100616 }
617
618 /* timer looks expired, detach it from the queue */
Willy Tarreau86257dc2010-06-06 12:57:10 +0200619 ts = eb32_entry(eb, struct stksess, exp);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100620 eb = eb32_next(eb);
621
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200622 /* don't delete an entry which is currently referenced */
623 if (ts->ref_cnt)
624 continue;
625
Willy Tarreau86257dc2010-06-06 12:57:10 +0200626 eb32_delete(&ts->exp);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100627
628 if (!tick_is_expired(ts->expire, now_ms)) {
629 if (!tick_isset(ts->expire))
630 continue;
631
Willy Tarreau86257dc2010-06-06 12:57:10 +0200632 ts->exp.key = ts->expire;
633 eb32_insert(&t->exps, &ts->exp);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100634
Willy Tarreau86257dc2010-06-06 12:57:10 +0200635 if (!eb || eb->key > ts->exp.key)
636 eb = &ts->exp;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100637 continue;
638 }
639
640 /* session expired, trash it */
Willy Tarreau86257dc2010-06-06 12:57:10 +0200641 ebmb_delete(&ts->key);
Emeric Brun85e77c72010-09-23 18:16:52 +0200642 eb32_delete(&ts->upd);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200643 __stksess_free(t, ts);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100644 }
645
646 /* We have found no task to expire in any tree */
647 t->exp_next = TICK_ETERNITY;
Willy Tarreau4d5f13c2017-11-05 11:04:47 +0100648out_unlock:
Willy Tarreau76642222022-10-11 12:02:50 +0200649 HA_RWLOCK_WRUNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100650 return t->exp_next;
651}
652
653/*
Willy Tarreauaea940e2010-06-06 11:56:36 +0200654 * Task processing function to trash expired sticky sessions. A pointer to the
655 * task itself is returned since it never dies.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100656 */
Willy Tarreau144f84a2021-03-02 16:09:26 +0100657struct task *process_table_expire(struct task *task, void *context, unsigned int state)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100658{
Olivier Houchard9f6af332018-05-25 14:04:04 +0200659 struct stktable *t = context;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100660
661 task->expire = stktable_trash_expired(t);
662 return task;
663}
664
Willy Tarreauaea940e2010-06-06 11:56:36 +0200665/* Perform minimal stick table intializations, report 0 in case of error, 1 if OK. */
Emeric Brun3bd697e2010-01-04 15:23:48 +0100666int stktable_init(struct stktable *t)
667{
Remi Tricot-Le Breton208ff012021-05-12 17:39:04 +0200668 int peers_retval = 0;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100669 if (t->size) {
Emeric Brun819fc6f2017-06-13 19:37:32 +0200670 t->keys = EB_ROOT_UNIQUE;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100671 memset(&t->exps, 0, sizeof(t->exps));
Emeric Brun1c6235d2015-12-16 15:28:12 +0100672 t->updates = EB_ROOT_UNIQUE;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100673 HA_SPIN_INIT(&t->lock);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100674
Olivier Houchard52dabbc2018-11-14 17:54:36 +0100675 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 +0100676
677 t->exp_next = TICK_ETERNITY;
678 if ( t->expire ) {
Willy Tarreaubeeabf52021-10-01 18:23:30 +0200679 t->exp_task = task_new_anywhere();
Willy Tarreau848522f2018-10-15 11:12:15 +0200680 if (!t->exp_task)
681 return 0;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100682 t->exp_task->process = process_table_expire;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100683 t->exp_task->context = (void *)t;
684 }
Christopher Fauletdfd10ab2021-10-06 14:24:19 +0200685 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 +0200686 peers_retval = peers_register_table(t->peers.p, t);
Emeric Brun32da3c42010-09-23 18:39:19 +0200687 }
688
Remi Tricot-Le Breton208ff012021-05-12 17:39:04 +0200689 return (t->pool != NULL) && !peers_retval;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100690 }
691 return 1;
692}
693
694/*
695 * Configuration keywords of known table types
696 */
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200697struct stktable_type stktable_types[SMP_TYPES] = {
698 [SMP_T_SINT] = { "integer", 0, 4 },
699 [SMP_T_IPV4] = { "ip", 0, 4 },
700 [SMP_T_IPV6] = { "ipv6", 0, 16 },
701 [SMP_T_STR] = { "string", STK_F_CUSTOM_KEYSIZE, 32 },
702 [SMP_T_BIN] = { "binary", STK_F_CUSTOM_KEYSIZE, 32 }
703};
Emeric Brun3bd697e2010-01-04 15:23:48 +0100704
705/*
706 * Parse table type configuration.
707 * Returns 0 on successful parsing, else 1.
708 * <myidx> is set at next configuration <args> index.
709 */
710int stktable_parse_type(char **args, int *myidx, unsigned long *type, size_t *key_size)
711{
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200712 for (*type = 0; *type < SMP_TYPES; (*type)++) {
713 if (!stktable_types[*type].kw)
714 continue;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100715 if (strcmp(args[*myidx], stktable_types[*type].kw) != 0)
716 continue;
717
718 *key_size = stktable_types[*type].default_size;
719 (*myidx)++;
720
Willy Tarreauaea940e2010-06-06 11:56:36 +0200721 if (stktable_types[*type].flags & STK_F_CUSTOM_KEYSIZE) {
Emeric Brun3bd697e2010-01-04 15:23:48 +0100722 if (strcmp("len", args[*myidx]) == 0) {
723 (*myidx)++;
724 *key_size = atol(args[*myidx]);
Emeric Brun485479d2010-09-23 18:02:19 +0200725 if (!*key_size)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100726 break;
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200727 if (*type == SMP_T_STR) {
Emeric Brun485479d2010-09-23 18:02:19 +0200728 /* null terminated string needs +1 for '\0'. */
729 (*key_size)++;
730 }
Emeric Brun3bd697e2010-01-04 15:23:48 +0100731 (*myidx)++;
732 }
733 }
734 return 0;
735 }
736 return 1;
737}
738
Emeric Brunc64a2a32021-06-30 18:01:02 +0200739/* reserve some space for data type <type>, there is 2 optionnals
740 * argument at <sa> and <sa2> to configure this data type and
741 * they can be NULL if unused for a given type.
742 * Returns PE_NONE (0) if OK or an error code among :
Willy Tarreau3b63ca22021-05-08 14:10:42 +0200743 * - PE_ENUM_OOR if <type> does not exist
744 * - PE_EXIST if <type> is already registered
Emeric Brunc64a2a32021-06-30 18:01:02 +0200745 * - PE_ARG_NOT_USE if <sa>/<sa2> was provided but not expected
746 * - PE_ARG_MISSING if <sa>/<sa2> was expected but not provided
747 * - PE_ARG_VALUE_OOR if type is an array and <sa> it out of array size range.
Willy Tarreau3b63ca22021-05-08 14:10:42 +0200748 */
Emeric Brunc64a2a32021-06-30 18:01:02 +0200749int stktable_alloc_data_type(struct stktable *t, int type, const char *sa, const char *sa2)
750
Willy Tarreau3b63ca22021-05-08 14:10:42 +0200751{
752 if (type >= STKTABLE_DATA_TYPES)
753 return PE_ENUM_OOR;
754
755 if (t->data_ofs[type])
756 /* already allocated */
757 return PE_EXIST;
758
Emeric Brunc64a2a32021-06-30 18:01:02 +0200759 t->data_nbelem[type] = 1;
760 if (stktable_data_types[type].is_array) {
761 /* arrays take their element count on first argument */
762 if (!sa)
763 return PE_ARG_MISSING;
764 t->data_nbelem[type] = atoi(sa);
765 if (!t->data_nbelem[type] || (t->data_nbelem[type] > STKTABLE_MAX_DT_ARRAY_SIZE))
766 return PE_ARG_VALUE_OOR;
767 sa = sa2;
768 }
769
Willy Tarreau3b63ca22021-05-08 14:10:42 +0200770 switch (stktable_data_types[type].arg_type) {
771 case ARG_T_NONE:
772 if (sa)
773 return PE_ARG_NOT_USED;
774 break;
775 case ARG_T_INT:
776 if (!sa)
777 return PE_ARG_MISSING;
778 t->data_arg[type].i = atoi(sa);
779 break;
780 case ARG_T_DELAY:
781 if (!sa)
782 return PE_ARG_MISSING;
783 sa = parse_time_err(sa, &t->data_arg[type].u, TIME_UNIT_MS);
784 if (sa)
785 return PE_ARG_INVC; /* invalid char */
786 break;
787 }
788
Emeric Brunc64a2a32021-06-30 18:01:02 +0200789 t->data_size += t->data_nbelem[type] * stktable_type_size(stktable_data_types[type].std_type);
Willy Tarreau3b63ca22021-05-08 14:10:42 +0200790 t->data_ofs[type] = -t->data_size;
791 return PE_NONE;
792}
793
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100794/*
Frédéric Lécaillec02766a2019-03-20 15:06:55 +0100795 * Parse a line with <linenum> as number in <file> configuration file to configure
796 * the stick-table with <t> as address and <id> as ID.
797 * <peers> provides the "peers" section pointer only if this function is called
798 * from a "peers" section.
799 * <nid> is the stick-table name which is sent over the network. It must be equal
800 * to <id> if this stick-table is parsed from a proxy section, and prefixed by <peers>
801 * "peers" section name followed by a '/' character if parsed from a "peers" section.
Ilya Shipitsind4259502020-04-08 01:07:56 +0500802 * This is the responsibility of the caller to check this.
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100803 * Return an error status with ERR_* flags set if required, 0 if no error was encountered.
804 */
805int parse_stick_table(const char *file, int linenum, char **args,
Frédéric Lécaillec02766a2019-03-20 15:06:55 +0100806 struct stktable *t, char *id, char *nid, struct peers *peers)
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100807{
808 int err_code = 0;
809 int idx = 1;
810 unsigned int val;
811
812 if (!id || !*id) {
813 ha_alert("parsing [%s:%d] : %s: ID not provided.\n", file, linenum, args[0]);
814 err_code |= ERR_ALERT | ERR_ABORT;
815 goto out;
816 }
817
818 /* Store the "peers" section if this function is called from a "peers" section. */
819 if (peers) {
820 t->peers.p = peers;
821 idx++;
822 }
823
824 t->id = id;
Frédéric Lécaillec02766a2019-03-20 15:06:55 +0100825 t->nid = nid;
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100826 t->type = (unsigned int)-1;
827 t->conf.file = file;
828 t->conf.line = linenum;
829
830 while (*args[idx]) {
831 const char *err;
832
833 if (strcmp(args[idx], "size") == 0) {
834 idx++;
835 if (!*(args[idx])) {
836 ha_alert("parsing [%s:%d] : %s: missing argument after '%s'.\n",
837 file, linenum, args[0], args[idx-1]);
838 err_code |= ERR_ALERT | ERR_FATAL;
839 goto out;
840 }
841 if ((err = parse_size_err(args[idx], &t->size))) {
842 ha_alert("parsing [%s:%d] : %s: unexpected character '%c' in argument of '%s'.\n",
843 file, linenum, args[0], *err, args[idx-1]);
844 err_code |= ERR_ALERT | ERR_FATAL;
845 goto out;
846 }
847 idx++;
848 }
849 /* This argument does not exit in "peers" section. */
850 else if (!peers && strcmp(args[idx], "peers") == 0) {
851 idx++;
852 if (!*(args[idx])) {
853 ha_alert("parsing [%s:%d] : %s: missing argument after '%s'.\n",
854 file, linenum, args[0], args[idx-1]);
855 err_code |= ERR_ALERT | ERR_FATAL;
856 goto out;
857 }
858 t->peers.name = strdup(args[idx++]);
859 }
860 else if (strcmp(args[idx], "expire") == 0) {
861 idx++;
862 if (!*(args[idx])) {
863 ha_alert("parsing [%s:%d] : %s: missing argument after '%s'.\n",
864 file, linenum, args[0], args[idx-1]);
865 err_code |= ERR_ALERT | ERR_FATAL;
866 goto out;
867 }
868 err = parse_time_err(args[idx], &val, TIME_UNIT_MS);
Willy Tarreau9faebe32019-06-07 19:00:37 +0200869 if (err == PARSE_TIME_OVER) {
870 ha_alert("parsing [%s:%d]: %s: timer overflow in argument <%s> to <%s>, maximum value is 2147483647 ms (~24.8 days).\n",
871 file, linenum, args[0], args[idx], args[idx-1]);
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100872 err_code |= ERR_ALERT | ERR_FATAL;
873 goto out;
874 }
Willy Tarreau9faebe32019-06-07 19:00:37 +0200875 else if (err == PARSE_TIME_UNDER) {
876 ha_alert("parsing [%s:%d]: %s: timer underflow in argument <%s> to <%s>, minimum non-null value is 1 ms.\n",
877 file, linenum, args[0], args[idx], args[idx-1]);
878 err_code |= ERR_ALERT | ERR_FATAL;
879 goto out;
880 }
881 else if (err) {
882 ha_alert("parsing [%s:%d] : %s: unexpected character '%c' in argument of '%s'.\n",
883 file, linenum, args[0], *err, args[idx-1]);
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100884 err_code |= ERR_ALERT | ERR_FATAL;
885 goto out;
886 }
887 t->expire = val;
888 idx++;
889 }
890 else if (strcmp(args[idx], "nopurge") == 0) {
891 t->nopurge = 1;
892 idx++;
893 }
894 else if (strcmp(args[idx], "type") == 0) {
895 idx++;
896 if (stktable_parse_type(args, &idx, &t->type, &t->key_size) != 0) {
897 ha_alert("parsing [%s:%d] : %s: unknown type '%s'.\n",
898 file, linenum, args[0], args[idx]);
899 err_code |= ERR_ALERT | ERR_FATAL;
900 goto out;
901 }
902 /* idx already points to next arg */
903 }
904 else if (strcmp(args[idx], "store") == 0) {
905 int type, err;
Emeric Brunc64a2a32021-06-30 18:01:02 +0200906 char *cw, *nw, *sa, *sa2;
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100907
908 idx++;
909 nw = args[idx];
910 while (*nw) {
911 /* the "store" keyword supports a comma-separated list */
912 cw = nw;
913 sa = NULL; /* store arg */
Emeric Brunc64a2a32021-06-30 18:01:02 +0200914 sa2 = NULL;
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100915 while (*nw && *nw != ',') {
916 if (*nw == '(') {
917 *nw = 0;
918 sa = ++nw;
919 while (*nw != ')') {
920 if (!*nw) {
921 ha_alert("parsing [%s:%d] : %s: missing closing parenthesis after store option '%s'.\n",
922 file, linenum, args[0], cw);
923 err_code |= ERR_ALERT | ERR_FATAL;
924 goto out;
925 }
Emeric Brunc64a2a32021-06-30 18:01:02 +0200926 if (*nw == ',') {
927 *nw = '\0';
928 sa2 = nw + 1;
929 }
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100930 nw++;
931 }
932 *nw = '\0';
933 }
934 nw++;
935 }
936 if (*nw)
937 *nw++ = '\0';
938 type = stktable_get_data_type(cw);
939 if (type < 0) {
940 ha_alert("parsing [%s:%d] : %s: unknown store option '%s'.\n",
941 file, linenum, args[0], cw);
942 err_code |= ERR_ALERT | ERR_FATAL;
943 goto out;
944 }
945
Emeric Brunc64a2a32021-06-30 18:01:02 +0200946 err = stktable_alloc_data_type(t, type, sa, sa2);
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100947 switch (err) {
948 case PE_NONE: break;
949 case PE_EXIST:
950 ha_warning("parsing [%s:%d]: %s: store option '%s' already enabled, ignored.\n",
951 file, linenum, args[0], cw);
952 err_code |= ERR_WARN;
953 break;
954
955 case PE_ARG_MISSING:
956 ha_alert("parsing [%s:%d] : %s: missing argument to store option '%s'.\n",
957 file, linenum, args[0], cw);
958 err_code |= ERR_ALERT | ERR_FATAL;
959 goto out;
960
961 case PE_ARG_NOT_USED:
962 ha_alert("parsing [%s:%d] : %s: unexpected argument to store option '%s'.\n",
963 file, linenum, args[0], cw);
964 err_code |= ERR_ALERT | ERR_FATAL;
965 goto out;
Emeric Brunc64a2a32021-06-30 18:01:02 +0200966 case PE_ARG_VALUE_OOR:
967 ha_alert("parsing [%s:%d] : %s: array size is out of allowed range (1-%d) for store option '%s'.\n",
968 file, linenum, args[0], STKTABLE_MAX_DT_ARRAY_SIZE, cw);
969 err_code |= ERR_ALERT | ERR_FATAL;
970 goto out;
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100971
972 default:
973 ha_alert("parsing [%s:%d] : %s: error when processing store option '%s'.\n",
974 file, linenum, args[0], cw);
975 err_code |= ERR_ALERT | ERR_FATAL;
976 goto out;
977 }
978 }
979 idx++;
Emeric Brunf7ab0bf2021-06-30 18:58:22 +0200980 if (t->data_ofs[STKTABLE_DT_GPT] && t->data_ofs[STKTABLE_DT_GPT0]) {
981 ha_alert("parsing [%s:%d] : %s: simultaneous usage of 'gpt' and 'gpt0' in a same table is not permitted as 'gpt' overrides 'gpt0'.\n",
982 file, linenum, args[0]);
983 err_code |= ERR_ALERT | ERR_FATAL;
984 goto out;
985 }
Emeric Brun726783d2021-06-30 19:06:43 +0200986 else if (t->data_ofs[STKTABLE_DT_GPC] && (t->data_ofs[STKTABLE_DT_GPC0] || t->data_ofs[STKTABLE_DT_GPC1])) {
987 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",
988 file, linenum, args[0]);
989 err_code |= ERR_ALERT | ERR_FATAL;
990 goto out;
991 }
992 else if (t->data_ofs[STKTABLE_DT_GPC_RATE] && (t->data_ofs[STKTABLE_DT_GPC0_RATE] || t->data_ofs[STKTABLE_DT_GPC1_RATE])) {
993 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",
994 file, linenum, args[0]);
995 err_code |= ERR_ALERT | ERR_FATAL;
996 goto out;
997 }
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100998 }
Thayne McCombs92149f92020-11-20 01:28:26 -0700999 else if (strcmp(args[idx], "srvkey") == 0) {
1000 char *keytype;
1001 idx++;
1002 keytype = args[idx];
1003 if (strcmp(keytype, "name") == 0) {
1004 t->server_key_type = STKTABLE_SRV_NAME;
1005 }
1006 else if (strcmp(keytype, "addr") == 0) {
1007 t->server_key_type = STKTABLE_SRV_ADDR;
1008 }
1009 else {
1010 ha_alert("parsing [%s:%d] : %s : unknown server key type '%s'.\n",
1011 file, linenum, args[0], keytype);
1012 err_code |= ERR_ALERT | ERR_FATAL;
1013 goto out;
1014
1015 }
1016 idx++;
1017 }
Frédéric Lécailled456aa42019-03-08 14:47:00 +01001018 else {
1019 ha_alert("parsing [%s:%d] : %s: unknown argument '%s'.\n",
1020 file, linenum, args[0], args[idx]);
1021 err_code |= ERR_ALERT | ERR_FATAL;
1022 goto out;
1023 }
1024 }
1025
1026 if (!t->size) {
1027 ha_alert("parsing [%s:%d] : %s: missing size.\n",
1028 file, linenum, args[0]);
1029 err_code |= ERR_ALERT | ERR_FATAL;
1030 goto out;
1031 }
1032
1033 if (t->type == (unsigned int)-1) {
1034 ha_alert("parsing [%s:%d] : %s: missing type.\n",
1035 file, linenum, args[0]);
1036 err_code |= ERR_ALERT | ERR_FATAL;
1037 goto out;
1038 }
1039
1040 out:
1041 return err_code;
1042}
1043
Willy Tarreau8fed9032014-07-03 17:02:46 +02001044/* Prepares a stktable_key from a sample <smp> to search into table <t>.
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001045 * Note that the sample *is* modified and that the returned key may point
1046 * to it, so the sample must not be modified afterwards before the lookup.
Willy Tarreau8fed9032014-07-03 17:02:46 +02001047 * Returns NULL if the sample could not be converted (eg: no matching type),
1048 * otherwise a pointer to the static stktable_key filled with what is needed
1049 * for the lookup.
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001050 */
Willy Tarreau8fed9032014-07-03 17:02:46 +02001051struct stktable_key *smp_to_stkey(struct sample *smp, struct stktable *t)
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001052{
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001053 /* Convert sample. */
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +02001054 if (!sample_convert(smp, t->type))
Willy Tarreau7fc1c6e2012-04-26 11:03:17 +02001055 return NULL;
1056
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001057 /* Fill static_table_key. */
1058 switch (t->type) {
Emeric Brun485479d2010-09-23 18:02:19 +02001059
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +02001060 case SMP_T_IPV4:
Christopher Fauletca20d022017-08-29 15:30:31 +02001061 static_table_key.key = &smp->data.u.ipv4;
1062 static_table_key.key_len = 4;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001063 break;
Emeric Brun485479d2010-09-23 18:02:19 +02001064
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +02001065 case SMP_T_IPV6:
Christopher Fauletca20d022017-08-29 15:30:31 +02001066 static_table_key.key = &smp->data.u.ipv6;
1067 static_table_key.key_len = 16;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001068 break;
Emeric Brun485479d2010-09-23 18:02:19 +02001069
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +02001070 case SMP_T_SINT:
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001071 /* The stick table require a 32bit unsigned int, "sint" is a
1072 * signed 64 it, so we can convert it inplace.
1073 */
Willy Tarreau28c63c12019-10-23 06:21:05 +02001074 smp->data.u.sint = (unsigned int)smp->data.u.sint;
Christopher Fauletca20d022017-08-29 15:30:31 +02001075 static_table_key.key = &smp->data.u.sint;
1076 static_table_key.key_len = 4;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001077 break;
1078
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +02001079 case SMP_T_STR:
Willy Tarreauce6955e2016-08-09 11:59:12 +02001080 if (!smp_make_safe(smp))
1081 return NULL;
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001082 static_table_key.key = smp->data.u.str.area;
1083 static_table_key.key_len = smp->data.u.str.data;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001084 break;
Emeric Brun485479d2010-09-23 18:02:19 +02001085
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +02001086 case SMP_T_BIN:
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001087 if (smp->data.u.str.data < t->key_size) {
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001088 /* This type needs padding with 0. */
Willy Tarreauf65c6c02016-08-09 12:08:41 +02001089 if (!smp_make_rw(smp))
1090 return NULL;
1091
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001092 if (smp->data.u.str.size < t->key_size)
1093 if (!smp_dup(smp))
1094 return NULL;
1095 if (smp->data.u.str.size < t->key_size)
1096 return NULL;
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001097 memset(smp->data.u.str.area + smp->data.u.str.data, 0,
1098 t->key_size - smp->data.u.str.data);
1099 smp->data.u.str.data = t->key_size;
Emeric Brun485479d2010-09-23 18:02:19 +02001100 }
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001101 static_table_key.key = smp->data.u.str.area;
1102 static_table_key.key_len = smp->data.u.str.data;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001103 break;
Emeric Brun485479d2010-09-23 18:02:19 +02001104
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001105 default: /* impossible case. */
1106 return NULL;
Emeric Brun485479d2010-09-23 18:02:19 +02001107 }
1108
Christopher Fauletca20d022017-08-29 15:30:31 +02001109 return &static_table_key;
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001110}
1111
1112/*
Willy Tarreau8fed9032014-07-03 17:02:46 +02001113 * Process a fetch + format conversion as defined by the sample expression <expr>
1114 * on request or response considering the <opt> parameter. Returns either NULL if
1115 * no key could be extracted, or a pointer to the converted result stored in
1116 * static_table_key in format <table_type>. If <smp> is not NULL, it will be reset
1117 * and its flags will be initialized so that the caller gets a copy of the input
Willy Tarreau6bcb0a82014-07-30 08:56:35 +02001118 * sample, and knows why it was not accepted (eg: SMP_F_MAY_CHANGE is present
1119 * without SMP_OPT_FINAL). The output will be usable like this :
1120 *
1121 * return MAY_CHANGE FINAL Meaning for the sample
1122 * NULL 0 * Not present and will never be (eg: header)
1123 * NULL 1 0 Not present or unstable, could change (eg: req_len)
1124 * NULL 1 1 Not present, will not change anymore
1125 * smp 0 * Present and will not change (eg: header)
1126 * smp 1 0 not possible
1127 * smp 1 1 Present, last known value (eg: request length)
Willy Tarreau8fed9032014-07-03 17:02:46 +02001128 */
Willy Tarreau192252e2015-04-04 01:47:55 +02001129struct stktable_key *stktable_fetch_key(struct stktable *t, struct proxy *px, struct session *sess, struct stream *strm,
Willy Tarreau8fed9032014-07-03 17:02:46 +02001130 unsigned int opt, struct sample_expr *expr, struct sample *smp)
1131{
1132 if (smp)
1133 memset(smp, 0, sizeof(*smp));
1134
Willy Tarreau192252e2015-04-04 01:47:55 +02001135 smp = sample_process(px, sess, strm, opt, expr, smp);
Willy Tarreau8fed9032014-07-03 17:02:46 +02001136 if (!smp)
1137 return NULL;
1138
1139 if ((smp->flags & SMP_F_MAY_CHANGE) && !(opt & SMP_OPT_FINAL))
1140 return NULL; /* we can only use stable samples */
1141
1142 return smp_to_stkey(smp, t);
1143}
1144
1145/*
Willy Tarreau12785782012-04-27 21:37:17 +02001146 * Returns 1 if sample expression <expr> result can be converted to table key of
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001147 * type <table_type>, otherwise zero. Used in configuration check.
1148 */
Willy Tarreau12785782012-04-27 21:37:17 +02001149int stktable_compatible_sample(struct sample_expr *expr, unsigned long table_type)
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001150{
Thierry FOURNIERf73eb8f2013-11-27 15:30:55 +01001151 int out_type;
1152
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +02001153 if (table_type >= SMP_TYPES || !stktable_types[table_type].kw)
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001154 return 0;
1155
Thierry FOURNIERf73eb8f2013-11-27 15:30:55 +01001156 out_type = smp_expr_output_type(expr);
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001157
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001158 /* Convert sample. */
1159 if (!sample_casts[out_type][table_type])
Thierry FOURNIERf73eb8f2013-11-27 15:30:55 +01001160 return 0;
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001161
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001162 return 1;
1163}
Emeric Brun3bd697e2010-01-04 15:23:48 +01001164
Willy Tarreauedee1d62014-07-15 16:44:27 +02001165/* Extra data types processing : after the last one, some room may remain
1166 * before STKTABLE_DATA_TYPES that may be used to register extra data types
1167 * at run time.
1168 */
Willy Tarreau08d5f982010-06-06 13:34:54 +02001169struct stktable_data_type stktable_data_types[STKTABLE_DATA_TYPES] = {
Willy Tarreau3b9c6e02010-07-18 08:04:30 +02001170 [STKTABLE_DT_SERVER_ID] = { .name = "server_id", .std_type = STD_T_SINT },
Thierry FOURNIER3cf11112015-07-28 08:57:05 +02001171 [STKTABLE_DT_GPT0] = { .name = "gpt0", .std_type = STD_T_UINT },
Willy Tarreau3b9c6e02010-07-18 08:04:30 +02001172 [STKTABLE_DT_GPC0] = { .name = "gpc0", .std_type = STD_T_UINT },
Willy Tarreauba2ffd12013-05-29 15:54:14 +02001173 [STKTABLE_DT_GPC0_RATE] = { .name = "gpc0_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
Willy Tarreau3b9c6e02010-07-18 08:04:30 +02001174 [STKTABLE_DT_CONN_CNT] = { .name = "conn_cnt", .std_type = STD_T_UINT },
1175 [STKTABLE_DT_CONN_RATE] = { .name = "conn_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
Willy Tarreaudb2ab822021-10-08 17:53:12 +02001176 [STKTABLE_DT_CONN_CUR] = { .name = "conn_cur", .std_type = STD_T_UINT, .is_local = 1 },
Willy Tarreau3b9c6e02010-07-18 08:04:30 +02001177 [STKTABLE_DT_SESS_CNT] = { .name = "sess_cnt", .std_type = STD_T_UINT },
1178 [STKTABLE_DT_SESS_RATE] = { .name = "sess_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
1179 [STKTABLE_DT_HTTP_REQ_CNT] = { .name = "http_req_cnt", .std_type = STD_T_UINT },
1180 [STKTABLE_DT_HTTP_REQ_RATE] = { .name = "http_req_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
1181 [STKTABLE_DT_HTTP_ERR_CNT] = { .name = "http_err_cnt", .std_type = STD_T_UINT },
1182 [STKTABLE_DT_HTTP_ERR_RATE] = { .name = "http_err_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
1183 [STKTABLE_DT_BYTES_IN_CNT] = { .name = "bytes_in_cnt", .std_type = STD_T_ULL },
1184 [STKTABLE_DT_BYTES_IN_RATE] = { .name = "bytes_in_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
1185 [STKTABLE_DT_BYTES_OUT_CNT] = { .name = "bytes_out_cnt", .std_type = STD_T_ULL },
1186 [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 +01001187 [STKTABLE_DT_GPC1] = { .name = "gpc1", .std_type = STD_T_UINT },
1188 [STKTABLE_DT_GPC1_RATE] = { .name = "gpc1_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
Thayne McCombs92149f92020-11-20 01:28:26 -07001189 [STKTABLE_DT_SERVER_KEY] = { .name = "server_key", .std_type = STD_T_DICT },
Willy Tarreau826f3ab2021-02-10 12:07:15 +01001190 [STKTABLE_DT_HTTP_FAIL_CNT] = { .name = "http_fail_cnt", .std_type = STD_T_UINT },
1191 [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 +02001192 [STKTABLE_DT_GPT] = { .name = "gpt", .std_type = STD_T_UINT, .is_array = 1 },
Emeric Brun4d7ada82021-06-30 19:04:16 +02001193 [STKTABLE_DT_GPC] = { .name = "gpc", .std_type = STD_T_UINT, .is_array = 1 },
1194 [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 +02001195};
1196
Willy Tarreauedee1d62014-07-15 16:44:27 +02001197/* Registers stick-table extra data type with index <idx>, name <name>, type
1198 * <std_type> and arg type <arg_type>. If the index is negative, the next free
1199 * index is automatically allocated. The allocated index is returned, or -1 if
1200 * no free index was found or <name> was already registered. The <name> is used
1201 * directly as a pointer, so if it's not stable, the caller must allocate it.
1202 */
1203int stktable_register_data_store(int idx, const char *name, int std_type, int arg_type)
1204{
1205 if (idx < 0) {
1206 for (idx = 0; idx < STKTABLE_DATA_TYPES; idx++) {
1207 if (!stktable_data_types[idx].name)
1208 break;
1209
1210 if (strcmp(stktable_data_types[idx].name, name) == 0)
1211 return -1;
1212 }
1213 }
1214
1215 if (idx >= STKTABLE_DATA_TYPES)
1216 return -1;
1217
1218 if (stktable_data_types[idx].name != NULL)
1219 return -1;
1220
1221 stktable_data_types[idx].name = name;
1222 stktable_data_types[idx].std_type = std_type;
1223 stktable_data_types[idx].arg_type = arg_type;
1224 return idx;
1225}
1226
Willy Tarreau08d5f982010-06-06 13:34:54 +02001227/*
1228 * Returns the data type number for the stktable_data_type whose name is <name>,
1229 * or <0 if not found.
1230 */
1231int stktable_get_data_type(char *name)
1232{
1233 int type;
1234
1235 for (type = 0; type < STKTABLE_DATA_TYPES; type++) {
Willy Tarreauedee1d62014-07-15 16:44:27 +02001236 if (!stktable_data_types[type].name)
1237 continue;
Willy Tarreau08d5f982010-06-06 13:34:54 +02001238 if (strcmp(name, stktable_data_types[type].name) == 0)
1239 return type;
1240 }
Thayne McCombs92149f92020-11-20 01:28:26 -07001241 /* For backwards compatibility */
1242 if (strcmp(name, "server_name") == 0)
1243 return STKTABLE_DT_SERVER_KEY;
Willy Tarreau08d5f982010-06-06 13:34:54 +02001244 return -1;
1245}
1246
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001247/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1248 * it up into this table. Returns true if found, false otherwise. The input
1249 * type is STR so that input samples are converted to string (since all types
1250 * can be converted to strings), then the function casts the string again into
1251 * the table's type. This is a double conversion, but in the future we might
1252 * support automatic input types to perform the cast on the fly.
1253 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001254static int sample_conv_in_table(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001255{
1256 struct stktable *t;
1257 struct stktable_key *key;
1258 struct stksess *ts;
1259
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001260 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001261
1262 key = smp_to_stkey(smp, t);
1263 if (!key)
1264 return 0;
1265
1266 ts = stktable_lookup_key(t, key);
1267
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001268 smp->data.type = SMP_T_BOOL;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001269 smp->data.u.sint = !!ts;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001270 smp->flags = SMP_F_VOL_TEST;
Willy Tarreau43e90352018-06-27 06:25:57 +02001271 stktable_release(t, ts);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001272 return 1;
1273}
1274
1275/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1276 * it up into this table. Returns the data rate received from clients in bytes/s
1277 * if the key is present in the table, otherwise zero, so that comparisons can
1278 * be easily performed. If the inspected parameter is not stored in the table,
1279 * <not found> is returned.
1280 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001281static int sample_conv_table_bytes_in_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001282{
1283 struct stktable *t;
1284 struct stktable_key *key;
1285 struct stksess *ts;
1286 void *ptr;
1287
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001288 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001289
1290 key = smp_to_stkey(smp, t);
1291 if (!key)
1292 return 0;
1293
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001294 ts = stktable_lookup_key(t, key);
1295
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001296 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001297 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001298 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001299
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001300 if (!ts) /* key not present */
1301 return 1;
1302
1303 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_IN_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001304 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001305 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Daniel Corbett3e60b112018-05-27 09:47:12 -04001306 t->data_arg[STKTABLE_DT_BYTES_IN_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001307
Daniel Corbett3e60b112018-05-27 09:47:12 -04001308 stktable_release(t, ts);
1309 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001310}
1311
1312/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1313 * it up into this table. Returns the cumulated number of connections for the key
1314 * if the key is present in the table, otherwise zero, so that comparisons can
1315 * be easily performed. If the inspected parameter is not stored in the table,
1316 * <not found> is returned.
1317 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001318static int sample_conv_table_conn_cnt(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001319{
1320 struct stktable *t;
1321 struct stktable_key *key;
1322 struct stksess *ts;
1323 void *ptr;
1324
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001325 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001326
1327 key = smp_to_stkey(smp, t);
1328 if (!key)
1329 return 0;
1330
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001331 ts = stktable_lookup_key(t, key);
1332
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001333 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001334 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001335 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001336
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001337 if (!ts) /* key not present */
1338 return 1;
1339
1340 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_CONN_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001341 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001342 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001343
Daniel Corbett3e60b112018-05-27 09:47:12 -04001344 stktable_release(t, ts);
1345 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001346}
1347
1348/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1349 * it up into this table. Returns the number of concurrent connections for the
1350 * key if the key is present in the table, otherwise zero, so that comparisons
1351 * can be easily performed. If the inspected parameter is not stored in the
1352 * table, <not found> is returned.
1353 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001354static int sample_conv_table_conn_cur(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001355{
1356 struct stktable *t;
1357 struct stktable_key *key;
1358 struct stksess *ts;
1359 void *ptr;
1360
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001361 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001362
1363 key = smp_to_stkey(smp, t);
1364 if (!key)
1365 return 0;
1366
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001367 ts = stktable_lookup_key(t, key);
1368
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001369 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001370 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001371 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001372
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001373 if (!ts) /* key not present */
1374 return 1;
1375
1376 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_CONN_CUR);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001377 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001378 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001379
Daniel Corbett3e60b112018-05-27 09:47:12 -04001380 stktable_release(t, ts);
1381 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001382}
1383
1384/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1385 * it up into this table. Returns the rate of incoming connections from the key
1386 * if the key is present in the table, otherwise zero, so that comparisons can
1387 * be easily performed. If the inspected parameter is not stored in the table,
1388 * <not found> is returned.
1389 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001390static int sample_conv_table_conn_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001391{
1392 struct stktable *t;
1393 struct stktable_key *key;
1394 struct stksess *ts;
1395 void *ptr;
1396
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001397 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001398
1399 key = smp_to_stkey(smp, t);
1400 if (!key)
1401 return 0;
1402
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001403 ts = stktable_lookup_key(t, key);
1404
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001405 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001406 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001407 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001408
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001409 if (!ts) /* key not present */
1410 return 1;
1411
1412 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_CONN_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001413 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001414 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Daniel Corbett3e60b112018-05-27 09:47:12 -04001415 t->data_arg[STKTABLE_DT_CONN_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001416
Daniel Corbett3e60b112018-05-27 09:47:12 -04001417 stktable_release(t, ts);
1418 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001419}
1420
1421/* 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 +02001422 * it up into this table. Returns the expiration delay for the key if the key is
1423 * present in the table, otherwise the default value provided as second argument
1424 * if any, if not (no default value), <not found> is returned.
1425 */
1426static int sample_conv_table_expire(const struct arg *arg_p, struct sample *smp, void *private)
1427{
1428 struct stktable *t;
1429 struct stktable_key *key;
1430 struct stksess *ts;
1431
1432 t = arg_p[0].data.t;
1433
1434 key = smp_to_stkey(smp, t);
1435 if (!key)
1436 return 0;
1437
1438 ts = stktable_lookup_key(t, key);
1439
1440 smp->flags = SMP_F_VOL_TEST;
1441 smp->data.type = SMP_T_SINT;
1442 smp->data.u.sint = 0;
1443
1444 if (!ts) { /* key not present */
1445 if (arg_p[1].type == ARGT_STOP)
1446 return 0;
1447
1448 /* default value */
1449 smp->data.u.sint = arg_p[1].data.sint;
1450 return 1;
1451 }
1452
1453 smp->data.u.sint = tick_remain(now_ms, ts->expire);
1454
1455 stktable_release(t, ts);
1456 return 1;
1457}
1458
1459/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1460 * it up into this table. Returns the time the key remains unused if the key is
1461 * present in the table, otherwise the default value provided as second argument
1462 * if any, if not (no default value), <not found> is returned.
1463 */
1464static int sample_conv_table_idle(const struct arg *arg_p, struct sample *smp, void *private)
1465{
1466 struct stktable *t;
1467 struct stktable_key *key;
1468 struct stksess *ts;
1469
1470 t = arg_p[0].data.t;
1471
1472 key = smp_to_stkey(smp, t);
1473 if (!key)
1474 return 0;
1475
1476 ts = stktable_lookup_key(t, key);
1477
1478 smp->flags = SMP_F_VOL_TEST;
1479 smp->data.type = SMP_T_SINT;
1480 smp->data.u.sint = 0;
1481
1482 if (!ts) { /* key not present */
1483 if (arg_p[1].type == ARGT_STOP)
1484 return 0;
1485
1486 /* default value */
1487 smp->data.u.sint = arg_p[1].data.sint;
1488 return 1;
1489 }
1490
1491 smp->data.u.sint = tick_remain(tick_remain(now_ms, ts->expire), t->expire);
1492
1493 stktable_release(t, ts);
1494 return 1;
1495}
1496
1497/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001498 * it up into this table. Returns the data rate sent to clients in bytes/s
1499 * if the key is present in the table, otherwise zero, so that comparisons can
1500 * be easily performed. If the inspected parameter is not stored in the table,
1501 * <not found> is returned.
1502 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001503static int sample_conv_table_bytes_out_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001504{
1505 struct stktable *t;
1506 struct stktable_key *key;
1507 struct stksess *ts;
1508 void *ptr;
1509
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001510 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001511
1512 key = smp_to_stkey(smp, t);
1513 if (!key)
1514 return 0;
1515
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001516 ts = stktable_lookup_key(t, key);
1517
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001518 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001519 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001520 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001521
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001522 if (!ts) /* key not present */
1523 return 1;
1524
1525 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_OUT_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001526 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001527 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Daniel Corbett3e60b112018-05-27 09:47:12 -04001528 t->data_arg[STKTABLE_DT_BYTES_OUT_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001529
Daniel Corbett3e60b112018-05-27 09:47:12 -04001530 stktable_release(t, ts);
1531 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001532}
1533
Emeric Brun877b0b52021-06-30 18:57:49 +02001534/* Casts sample <smp> to the type of the table specified in arg_p(1), and looks
1535 * it up into this table. Returns the value of the GPT[arg_p(0)] tag for the key
1536 * if the key is present in the table, otherwise false, so that comparisons can
1537 * be easily performed. If the inspected parameter is not stored in the table,
1538 * <not found> is returned.
1539 */
1540static int sample_conv_table_gpt(const struct arg *arg_p, struct sample *smp, void *private)
1541{
1542 struct stktable *t;
1543 struct stktable_key *key;
1544 struct stksess *ts;
1545 void *ptr;
1546 unsigned int idx;
1547
1548 idx = arg_p[0].data.sint;
1549
1550 t = arg_p[1].data.t;
1551
1552 key = smp_to_stkey(smp, t);
1553 if (!key)
1554 return 0;
1555
1556 ts = stktable_lookup_key(t, key);
1557
1558 smp->flags = SMP_F_VOL_TEST;
1559 smp->data.type = SMP_T_SINT;
1560 smp->data.u.sint = 0;
1561
1562 if (!ts) /* key not present */
1563 return 1;
1564
1565 ptr = stktable_data_ptr_idx(t, ts, STKTABLE_DT_GPT, idx);
1566 if (ptr)
1567 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
1568
1569 stktable_release(t, ts);
1570 return !!ptr;
1571}
1572
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001573/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001574 * it up into this table. Returns the value of the GPT0 tag for the key
1575 * if the key is present in the table, otherwise false, so that comparisons can
1576 * be easily performed. If the inspected parameter is not stored in the table,
1577 * <not found> is returned.
1578 */
1579static int sample_conv_table_gpt0(const struct arg *arg_p, struct sample *smp, void *private)
1580{
1581 struct stktable *t;
1582 struct stktable_key *key;
1583 struct stksess *ts;
1584 void *ptr;
1585
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001586 t = arg_p[0].data.t;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001587
1588 key = smp_to_stkey(smp, t);
1589 if (!key)
1590 return 0;
1591
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001592 ts = stktable_lookup_key(t, key);
1593
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001594 smp->flags = SMP_F_VOL_TEST;
1595 smp->data.type = SMP_T_SINT;
1596 smp->data.u.sint = 0;
1597
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001598 if (!ts) /* key not present */
1599 return 1;
1600
1601 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPT0);
Emeric Brunf7ab0bf2021-06-30 18:58:22 +02001602 if (!ptr)
1603 ptr = stktable_data_ptr_idx(t, ts, STKTABLE_DT_GPT, 0);
1604
Daniel Corbett3e60b112018-05-27 09:47:12 -04001605 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001606 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001607
Daniel Corbett3e60b112018-05-27 09:47:12 -04001608 stktable_release(t, ts);
1609 return !!ptr;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001610}
1611
Emeric Brun4d7ada82021-06-30 19:04:16 +02001612/* Casts sample <smp> to the type of the table specified in arg_p(1), and looks
1613 * it up into this table. Returns the value of the GPC[arg_p(0)] counter for the key
1614 * if the key is present in the table, otherwise zero, so that comparisons can
1615 * be easily performed. If the inspected parameter is not stored in the table,
1616 * <not found> is returned.
1617 */
1618static int sample_conv_table_gpc(const struct arg *arg_p, struct sample *smp, void *private)
1619{
1620 struct stktable *t;
1621 struct stktable_key *key;
1622 struct stksess *ts;
1623 void *ptr;
1624 unsigned int idx;
1625
1626 idx = arg_p[0].data.sint;
1627
1628 t = arg_p[1].data.t;
1629
1630 key = smp_to_stkey(smp, t);
1631 if (!key)
1632 return 0;
1633
1634 ts = stktable_lookup_key(t, key);
1635
1636 smp->flags = SMP_F_VOL_TEST;
1637 smp->data.type = SMP_T_SINT;
1638 smp->data.u.sint = 0;
1639
1640 if (!ts) /* key not present */
1641 return 1;
1642
1643 ptr = stktable_data_ptr_idx(t, ts, STKTABLE_DT_GPC, idx);
1644 if (ptr)
1645 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
1646
1647 stktable_release(t, ts);
1648 return !!ptr;
1649}
1650
1651/* Casts sample <smp> to the type of the table specified in arg_p(1), and looks
1652 * it up into this table. Returns the event rate of the GPC[arg_p(0)] counter
1653 * for the key if the key is present in the table, otherwise zero, so that
1654 * comparisons can be easily performed. If the inspected parameter is not
1655 * stored in the table, <not found> is returned.
1656 */
1657static int sample_conv_table_gpc_rate(const struct arg *arg_p, struct sample *smp, void *private)
1658{
1659 struct stktable *t;
1660 struct stktable_key *key;
1661 struct stksess *ts;
1662 void *ptr;
1663 unsigned int idx;
1664
1665 idx = arg_p[0].data.sint;
1666
1667 t = arg_p[1].data.t;
1668
1669 key = smp_to_stkey(smp, t);
1670 if (!key)
1671 return 0;
1672
1673 ts = stktable_lookup_key(t, key);
1674
1675 smp->flags = SMP_F_VOL_TEST;
1676 smp->data.type = SMP_T_SINT;
1677 smp->data.u.sint = 0;
1678
1679 if (!ts) /* key not present */
1680 return 1;
1681
1682 ptr = stktable_data_ptr_idx(t, ts, STKTABLE_DT_GPC_RATE, idx);
1683 if (ptr)
1684 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
1685 t->data_arg[STKTABLE_DT_GPC_RATE].u);
1686
1687 stktable_release(t, ts);
1688 return !!ptr;
1689}
1690
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001691/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001692 * it up into this table. Returns the value of the GPC0 counter for the key
1693 * if the key is present in the table, otherwise zero, so that comparisons can
1694 * be easily performed. If the inspected parameter is not stored in the table,
1695 * <not found> is returned.
1696 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001697static int sample_conv_table_gpc0(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001698{
1699 struct stktable *t;
1700 struct stktable_key *key;
1701 struct stksess *ts;
1702 void *ptr;
1703
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001704 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001705
1706 key = smp_to_stkey(smp, t);
1707 if (!key)
1708 return 0;
1709
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001710 ts = stktable_lookup_key(t, key);
1711
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001712 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001713 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001714 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001715
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001716 if (!ts) /* key not present */
1717 return 1;
1718
1719 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPC0);
Emeric Brun726783d2021-06-30 19:06:43 +02001720 if (!ptr) {
1721 /* fallback on the gpc array */
1722 ptr = stktable_data_ptr_idx(t, ts, STKTABLE_DT_GPC, 0);
1723 }
1724
Daniel Corbett3e60b112018-05-27 09:47:12 -04001725 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001726 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001727
Daniel Corbett3e60b112018-05-27 09:47:12 -04001728 stktable_release(t, ts);
1729 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001730}
1731
1732/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1733 * it up into this table. Returns the event rate of the GPC0 counter for the key
1734 * if the key is present in the table, otherwise zero, so that comparisons can
1735 * be easily performed. If the inspected parameter is not stored in the table,
1736 * <not found> is returned.
1737 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001738static int sample_conv_table_gpc0_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001739{
1740 struct stktable *t;
1741 struct stktable_key *key;
1742 struct stksess *ts;
1743 void *ptr;
1744
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001745 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001746
1747 key = smp_to_stkey(smp, t);
1748 if (!key)
1749 return 0;
1750
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001751 ts = stktable_lookup_key(t, key);
1752
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001753 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001754 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001755 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001756
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001757 if (!ts) /* key not present */
1758 return 1;
1759
1760 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPC0_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001761 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001762 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Daniel Corbett3e60b112018-05-27 09:47:12 -04001763 t->data_arg[STKTABLE_DT_GPC0_RATE].u);
Emeric Brun726783d2021-06-30 19:06:43 +02001764 else {
1765 /* fallback on the gpc array */
1766 ptr = stktable_data_ptr_idx(t, ts, STKTABLE_DT_GPC_RATE, 0);
1767 if (ptr)
1768 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
1769 t->data_arg[STKTABLE_DT_GPC_RATE].u);
1770 }
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001771
Daniel Corbett3e60b112018-05-27 09:47:12 -04001772 stktable_release(t, ts);
1773 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001774}
1775
1776/* 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 +01001777 * it up into this table. Returns the value of the GPC1 counter for the key
1778 * if the key is present in the table, otherwise zero, so that comparisons can
1779 * be easily performed. If the inspected parameter is not stored in the table,
1780 * <not found> is returned.
1781 */
1782static int sample_conv_table_gpc1(const struct arg *arg_p, struct sample *smp, void *private)
1783{
1784 struct stktable *t;
1785 struct stktable_key *key;
1786 struct stksess *ts;
1787 void *ptr;
1788
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001789 t = arg_p[0].data.t;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001790
1791 key = smp_to_stkey(smp, t);
1792 if (!key)
1793 return 0;
1794
1795 ts = stktable_lookup_key(t, key);
1796
1797 smp->flags = SMP_F_VOL_TEST;
1798 smp->data.type = SMP_T_SINT;
1799 smp->data.u.sint = 0;
1800
1801 if (!ts) /* key not present */
1802 return 1;
1803
1804 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPC1);
Emeric Brun726783d2021-06-30 19:06:43 +02001805 if (!ptr) {
1806 /* fallback on the gpc array */
1807 ptr = stktable_data_ptr_idx(t, ts, STKTABLE_DT_GPC, 1);
1808 }
1809
Daniel Corbett3e60b112018-05-27 09:47:12 -04001810 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001811 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001812
Daniel Corbett3e60b112018-05-27 09:47:12 -04001813 stktable_release(t, ts);
1814 return !!ptr;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001815}
1816
1817/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1818 * it up into this table. Returns the event rate of the GPC1 counter for the key
1819 * if the key is present in the table, otherwise zero, so that comparisons can
1820 * be easily performed. If the inspected parameter is not stored in the table,
1821 * <not found> is returned.
1822 */
1823static int sample_conv_table_gpc1_rate(const struct arg *arg_p, struct sample *smp, void *private)
1824{
1825 struct stktable *t;
1826 struct stktable_key *key;
1827 struct stksess *ts;
1828 void *ptr;
1829
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001830 t = arg_p[0].data.t;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001831
1832 key = smp_to_stkey(smp, t);
1833 if (!key)
1834 return 0;
1835
1836 ts = stktable_lookup_key(t, key);
1837
1838 smp->flags = SMP_F_VOL_TEST;
1839 smp->data.type = SMP_T_SINT;
1840 smp->data.u.sint = 0;
1841
1842 if (!ts) /* key not present */
1843 return 1;
1844
1845 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPC1_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001846 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001847 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Daniel Corbett3e60b112018-05-27 09:47:12 -04001848 t->data_arg[STKTABLE_DT_GPC1_RATE].u);
Emeric Brun726783d2021-06-30 19:06:43 +02001849 else {
1850 /* fallback on the gpc array */
1851 ptr = stktable_data_ptr_idx(t, ts, STKTABLE_DT_GPC_RATE, 1);
1852 if (ptr)
1853 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
1854 t->data_arg[STKTABLE_DT_GPC_RATE].u);
1855 }
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001856
Daniel Corbett3e60b112018-05-27 09:47:12 -04001857 stktable_release(t, ts);
1858 return !!ptr;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001859}
1860
1861/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001862 * it up into this table. Returns the cumulated number of HTTP request errors
1863 * for the key if the key is present in the table, otherwise zero, so that
1864 * comparisons can be easily performed. If the inspected parameter is not stored
1865 * in the table, <not found> is returned.
1866 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001867static int sample_conv_table_http_err_cnt(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001868{
1869 struct stktable *t;
1870 struct stktable_key *key;
1871 struct stksess *ts;
1872 void *ptr;
1873
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001874 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001875
1876 key = smp_to_stkey(smp, t);
1877 if (!key)
1878 return 0;
1879
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001880 ts = stktable_lookup_key(t, key);
1881
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001882 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001883 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001884 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001885
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001886 if (!ts) /* key not present */
1887 return 1;
1888
1889 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_ERR_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001890 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001891 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001892
Daniel Corbett3e60b112018-05-27 09:47:12 -04001893 stktable_release(t, ts);
1894 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001895}
1896
1897/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1898 * it up into this table. Returns the HTTP request error rate the key
1899 * if the key is present in the table, otherwise zero, so that comparisons can
1900 * be easily performed. If the inspected parameter is not stored in the table,
1901 * <not found> is returned.
1902 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001903static int sample_conv_table_http_err_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001904{
1905 struct stktable *t;
1906 struct stktable_key *key;
1907 struct stksess *ts;
1908 void *ptr;
1909
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001910 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001911
1912 key = smp_to_stkey(smp, t);
1913 if (!key)
1914 return 0;
1915
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001916 ts = stktable_lookup_key(t, key);
1917
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001918 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001919 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001920 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001921
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001922 if (!ts) /* key not present */
1923 return 1;
1924
1925 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_ERR_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001926 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001927 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Daniel Corbett3e60b112018-05-27 09:47:12 -04001928 t->data_arg[STKTABLE_DT_HTTP_ERR_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001929
Daniel Corbett3e60b112018-05-27 09:47:12 -04001930 stktable_release(t, ts);
1931 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001932}
1933
1934/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Willy Tarreau826f3ab2021-02-10 12:07:15 +01001935 * it up into this table. Returns the cumulated number of HTTP response failures
1936 * for the key if the key is present in the table, otherwise zero, so that
1937 * comparisons can be easily performed. If the inspected parameter is not stored
1938 * in the table, <not found> is returned.
1939 */
1940static int sample_conv_table_http_fail_cnt(const struct arg *arg_p, struct sample *smp, void *private)
1941{
1942 struct stktable *t;
1943 struct stktable_key *key;
1944 struct stksess *ts;
1945 void *ptr;
1946
1947 t = arg_p[0].data.t;
1948
1949 key = smp_to_stkey(smp, t);
1950 if (!key)
1951 return 0;
1952
1953 ts = stktable_lookup_key(t, key);
1954
1955 smp->flags = SMP_F_VOL_TEST;
1956 smp->data.type = SMP_T_SINT;
1957 smp->data.u.sint = 0;
1958
1959 if (!ts) /* key not present */
1960 return 1;
1961
1962 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_FAIL_CNT);
1963 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001964 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Willy Tarreau826f3ab2021-02-10 12:07:15 +01001965
1966 stktable_release(t, ts);
1967 return !!ptr;
1968}
1969
1970/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1971 * it up into this table. Returns the HTTP response failure rate for the key
1972 * if the key is present in the table, otherwise zero, so that comparisons can
1973 * be easily performed. If the inspected parameter is not stored in the table,
1974 * <not found> is returned.
1975 */
1976static int sample_conv_table_http_fail_rate(const struct arg *arg_p, struct sample *smp, void *private)
1977{
1978 struct stktable *t;
1979 struct stktable_key *key;
1980 struct stksess *ts;
1981 void *ptr;
1982
1983 t = arg_p[0].data.t;
1984
1985 key = smp_to_stkey(smp, t);
1986 if (!key)
1987 return 0;
1988
1989 ts = stktable_lookup_key(t, key);
1990
1991 smp->flags = SMP_F_VOL_TEST;
1992 smp->data.type = SMP_T_SINT;
1993 smp->data.u.sint = 0;
1994
1995 if (!ts) /* key not present */
1996 return 1;
1997
1998 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_FAIL_RATE);
1999 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002000 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Willy Tarreau826f3ab2021-02-10 12:07:15 +01002001 t->data_arg[STKTABLE_DT_HTTP_FAIL_RATE].u);
2002
2003 stktable_release(t, ts);
2004 return !!ptr;
2005}
2006
2007/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002008 * it up into this table. Returns the cumulated number of HTTP request for the
2009 * key if the key is present in the table, otherwise zero, so that comparisons
2010 * can be easily performed. If the inspected parameter is not stored in the
2011 * table, <not found> is returned.
2012 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02002013static int sample_conv_table_http_req_cnt(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002014{
2015 struct stktable *t;
2016 struct stktable_key *key;
2017 struct stksess *ts;
2018 void *ptr;
2019
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002020 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002021
2022 key = smp_to_stkey(smp, t);
2023 if (!key)
2024 return 0;
2025
Willy Tarreauf0c730a2016-05-25 17:07:56 +02002026 ts = stktable_lookup_key(t, key);
2027
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002028 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02002029 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02002030 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002031
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002032 if (!ts) /* key not present */
2033 return 1;
2034
2035 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_REQ_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04002036 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002037 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002038
Daniel Corbett3e60b112018-05-27 09:47:12 -04002039 stktable_release(t, ts);
2040 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002041}
2042
2043/* Casts sample <smp> to the type of the table specified in arg(0), and looks
2044 * it up into this table. Returns the HTTP request rate the key if the key is
2045 * present in the table, otherwise zero, so that comparisons can be easily
2046 * performed. If the inspected parameter is not stored in the table, <not found>
2047 * is returned.
2048 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02002049static int sample_conv_table_http_req_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002050{
2051 struct stktable *t;
2052 struct stktable_key *key;
2053 struct stksess *ts;
2054 void *ptr;
2055
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002056 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002057
2058 key = smp_to_stkey(smp, t);
2059 if (!key)
2060 return 0;
2061
Willy Tarreauf0c730a2016-05-25 17:07:56 +02002062 ts = stktable_lookup_key(t, key);
2063
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002064 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02002065 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02002066 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002067
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002068 if (!ts) /* key not present */
2069 return 1;
2070
2071 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_REQ_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04002072 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002073 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Daniel Corbett3e60b112018-05-27 09:47:12 -04002074 t->data_arg[STKTABLE_DT_HTTP_REQ_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002075
Daniel Corbett3e60b112018-05-27 09:47:12 -04002076 stktable_release(t, ts);
2077 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002078}
2079
2080/* Casts sample <smp> to the type of the table specified in arg(0), and looks
2081 * it up into this table. Returns the volume of datareceived from clients in kbytes
2082 * if the key is present in the table, otherwise zero, so that comparisons can
2083 * be easily performed. If the inspected parameter is not stored in the table,
2084 * <not found> is returned.
2085 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02002086static int sample_conv_table_kbytes_in(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002087{
2088 struct stktable *t;
2089 struct stktable_key *key;
2090 struct stksess *ts;
2091 void *ptr;
2092
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002093 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002094
2095 key = smp_to_stkey(smp, t);
2096 if (!key)
2097 return 0;
2098
Willy Tarreauf0c730a2016-05-25 17:07:56 +02002099 ts = stktable_lookup_key(t, key);
2100
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002101 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02002102 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02002103 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002104
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002105 if (!ts) /* key not present */
2106 return 1;
2107
2108 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_IN_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04002109 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002110 smp->data.u.sint = stktable_data_cast(ptr, std_t_ull) >> 10;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002111
Daniel Corbett3e60b112018-05-27 09:47:12 -04002112 stktable_release(t, ts);
2113 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002114}
2115
2116/* Casts sample <smp> to the type of the table specified in arg(0), and looks
2117 * it up into this table. Returns the volume of data sent to clients in kbytes
2118 * if the key is present in the table, otherwise zero, so that comparisons can
2119 * be easily performed. If the inspected parameter is not stored in the table,
2120 * <not found> is returned.
2121 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02002122static int sample_conv_table_kbytes_out(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002123{
2124 struct stktable *t;
2125 struct stktable_key *key;
2126 struct stksess *ts;
2127 void *ptr;
2128
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002129 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002130
2131 key = smp_to_stkey(smp, t);
2132 if (!key)
2133 return 0;
2134
Willy Tarreauf0c730a2016-05-25 17:07:56 +02002135 ts = stktable_lookup_key(t, key);
2136
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002137 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02002138 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02002139 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002140
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002141 if (!ts) /* key not present */
2142 return 1;
2143
2144 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_OUT_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04002145 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002146 smp->data.u.sint = stktable_data_cast(ptr, std_t_ull) >> 10;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002147
Daniel Corbett3e60b112018-05-27 09:47:12 -04002148 stktable_release(t, ts);
2149 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002150}
2151
2152/* Casts sample <smp> to the type of the table specified in arg(0), and looks
2153 * it up into this table. Returns the server ID associated with the key if the
2154 * key is present in the table, otherwise zero, so that comparisons can be
2155 * easily performed. If the inspected parameter is not stored in the table,
2156 * <not found> is returned.
2157 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02002158static int sample_conv_table_server_id(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002159{
2160 struct stktable *t;
2161 struct stktable_key *key;
2162 struct stksess *ts;
2163 void *ptr;
2164
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002165 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002166
2167 key = smp_to_stkey(smp, t);
2168 if (!key)
2169 return 0;
2170
Willy Tarreauf0c730a2016-05-25 17:07:56 +02002171 ts = stktable_lookup_key(t, key);
2172
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002173 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02002174 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02002175 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002176
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002177 if (!ts) /* key not present */
2178 return 1;
2179
2180 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_SERVER_ID);
Daniel Corbett3e60b112018-05-27 09:47:12 -04002181 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002182 smp->data.u.sint = stktable_data_cast(ptr, std_t_sint);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002183
Daniel Corbett3e60b112018-05-27 09:47:12 -04002184 stktable_release(t, ts);
2185 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002186}
2187
2188/* Casts sample <smp> to the type of the table specified in arg(0), and looks
2189 * it up into this table. Returns the cumulated number of sessions for the
2190 * key if the key is present in the table, otherwise zero, so that comparisons
2191 * can be easily performed. If the inspected parameter is not stored in the
2192 * table, <not found> is returned.
2193 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02002194static int sample_conv_table_sess_cnt(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002195{
2196 struct stktable *t;
2197 struct stktable_key *key;
2198 struct stksess *ts;
2199 void *ptr;
2200
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002201 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002202
2203 key = smp_to_stkey(smp, t);
2204 if (!key)
2205 return 0;
2206
Willy Tarreauf0c730a2016-05-25 17:07:56 +02002207 ts = stktable_lookup_key(t, key);
2208
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002209 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02002210 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02002211 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002212
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002213 if (!ts) /* key not present */
2214 return 1;
2215
2216 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_SESS_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04002217 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002218 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002219
Daniel Corbett3e60b112018-05-27 09:47:12 -04002220 stktable_release(t, ts);
2221 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002222}
2223
2224/* Casts sample <smp> to the type of the table specified in arg(0), and looks
2225 * it up into this table. Returns the session rate the key if the key is
2226 * present in the table, otherwise zero, so that comparisons can be easily
2227 * performed. If the inspected parameter is not stored in the table, <not found>
2228 * is returned.
2229 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02002230static int sample_conv_table_sess_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002231{
2232 struct stktable *t;
2233 struct stktable_key *key;
2234 struct stksess *ts;
2235 void *ptr;
2236
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002237 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002238
2239 key = smp_to_stkey(smp, t);
2240 if (!key)
2241 return 0;
2242
Willy Tarreauf0c730a2016-05-25 17:07:56 +02002243 ts = stktable_lookup_key(t, key);
2244
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002245 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02002246 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02002247 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002248
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002249 if (!ts) /* key not present */
2250 return 1;
2251
2252 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_SESS_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04002253 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002254 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Daniel Corbett3e60b112018-05-27 09:47:12 -04002255 t->data_arg[STKTABLE_DT_SESS_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002256
Daniel Corbett3e60b112018-05-27 09:47:12 -04002257 stktable_release(t, ts);
2258 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002259}
2260
2261/* Casts sample <smp> to the type of the table specified in arg(0), and looks
2262 * it up into this table. Returns the amount of concurrent connections tracking
2263 * the same key if the key is present in the table, otherwise zero, so that
2264 * comparisons can be easily performed. If the inspected parameter is not
2265 * stored in the table, <not found> is returned.
2266 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02002267static int sample_conv_table_trackers(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002268{
2269 struct stktable *t;
2270 struct stktable_key *key;
2271 struct stksess *ts;
2272
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002273 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002274
2275 key = smp_to_stkey(smp, t);
2276 if (!key)
2277 return 0;
2278
Willy Tarreauf0c730a2016-05-25 17:07:56 +02002279 ts = stktable_lookup_key(t, key);
2280
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002281 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02002282 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02002283 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002284
Tim Duesterhus65189c12018-06-26 15:57:29 +02002285 if (!ts)
2286 return 1;
2287
2288 smp->data.u.sint = ts->ref_cnt;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002289
Daniel Corbett3e60b112018-05-27 09:47:12 -04002290 stktable_release(t, ts);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002291 return 1;
2292}
2293
Emeric Brun4d7ada82021-06-30 19:04:16 +02002294/* This function increments the gpc counter at index 'rule->arg.gpc.idx' of the
2295 * array on the tracksc counter of index 'rule->arg.gpc.sc' stored into the
2296 * <stream> or directly in the session <sess> if <stream> is set to NULL
2297 *
2298 * This function always returns ACT_RET_CONT and parameter flags is unused.
2299 */
2300static enum act_return action_inc_gpc(struct act_rule *rule, struct proxy *px,
2301 struct session *sess, struct stream *s, int flags)
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002302{
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002303 struct stksess *ts;
2304 struct stkctr *stkctr;
2305
2306 /* Extract the stksess, return OK if no stksess available. */
2307 if (s)
2308 stkctr = &s->stkctr[rule->arg.gpc.sc];
2309 else
2310 stkctr = &sess->stkctr[rule->arg.gpc.sc];
Willy Tarreau79c1e912016-01-25 14:54:45 +01002311
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002312 ts = stkctr_entry(stkctr);
Willy Tarreau79c1e912016-01-25 14:54:45 +01002313 if (ts) {
2314 void *ptr1, *ptr2;
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002315
Emeric Brun4d7ada82021-06-30 19:04:16 +02002316 /* First, update gpc_rate if it's tracked. Second, update its gpc if tracked. */
2317 ptr1 = stktable_data_ptr_idx(stkctr->table, ts, STKTABLE_DT_GPC_RATE, rule->arg.gpc.idx);
2318 ptr2 = stktable_data_ptr_idx(stkctr->table, ts, STKTABLE_DT_GPC, rule->arg.gpc.idx);
2319
Emeric Brun819fc6f2017-06-13 19:37:32 +02002320 if (ptr1 || ptr2) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002321 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002322
2323 if (ptr1)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002324 update_freq_ctr_period(&stktable_data_cast(ptr1, std_t_frqp),
Emeric Brun4d7ada82021-06-30 19:04:16 +02002325 stkctr->table->data_arg[STKTABLE_DT_GPC_RATE].u, 1);
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002326
Emeric Brun819fc6f2017-06-13 19:37:32 +02002327 if (ptr2)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002328 stktable_data_cast(ptr2, std_t_uint)++;
Willy Tarreau79c1e912016-01-25 14:54:45 +01002329
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002330 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002331
2332 /* If data was modified, we need to touch to re-schedule sync */
2333 stktable_touch_local(stkctr->table, ts, 0);
2334 }
Willy Tarreau79c1e912016-01-25 14:54:45 +01002335 }
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002336 return ACT_RET_CONT;
2337}
2338
Emeric Brun4d7ada82021-06-30 19:04:16 +02002339/* Same as action_inc_gpc() but for gpc0 only */
2340static enum act_return action_inc_gpc0(struct act_rule *rule, struct proxy *px,
2341 struct session *sess, struct stream *s, int flags)
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002342{
Emeric Brun4d7ada82021-06-30 19:04:16 +02002343 struct stksess *ts;
2344 struct stkctr *stkctr;
Willy Tarreau5b654ad2021-07-06 18:51:12 +02002345 unsigned int period = 0;
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002346
Emeric Brun4d7ada82021-06-30 19:04:16 +02002347 /* Extract the stksess, return OK if no stksess available. */
2348 if (s)
2349 stkctr = &s->stkctr[rule->arg.gpc.sc];
2350 else
2351 stkctr = &sess->stkctr[rule->arg.gpc.sc];
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002352
Emeric Brun4d7ada82021-06-30 19:04:16 +02002353 ts = stkctr_entry(stkctr);
2354 if (ts) {
2355 void *ptr1, *ptr2;
2356
2357 /* First, update gpc0_rate if it's tracked. Second, update its gpc0 if tracked. */
2358 ptr1 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC0_RATE);
Emeric Brun726783d2021-06-30 19:06:43 +02002359 if (ptr1) {
2360 period = stkctr->table->data_arg[STKTABLE_DT_GPC0_RATE].u;
2361 }
2362 else {
2363 /* fallback on the gpc array */
2364 ptr1 = stktable_data_ptr_idx(stkctr->table, ts, STKTABLE_DT_GPC_RATE, 0);
2365 if (ptr1)
2366 period = stkctr->table->data_arg[STKTABLE_DT_GPC_RATE].u;
2367 }
2368
Emeric Brun4d7ada82021-06-30 19:04:16 +02002369 ptr2 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC0);
Emeric Brun726783d2021-06-30 19:06:43 +02002370 if (!ptr2) {
2371 /* fallback on the gpc array */
2372 ptr2 = stktable_data_ptr_idx(stkctr->table, ts, STKTABLE_DT_GPC, 0);
2373 }
2374
Emeric Brun4d7ada82021-06-30 19:04:16 +02002375 if (ptr1 || ptr2) {
2376 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
2377
2378 if (ptr1)
2379 update_freq_ctr_period(&stktable_data_cast(ptr1, std_t_frqp),
Emeric Brun726783d2021-06-30 19:06:43 +02002380 period, 1);
Emeric Brun4d7ada82021-06-30 19:04:16 +02002381
2382 if (ptr2)
2383 stktable_data_cast(ptr2, std_t_uint)++;
2384
2385 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
2386
2387 /* If data was modified, we need to touch to re-schedule sync */
2388 stktable_touch_local(stkctr->table, ts, 0);
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002389 }
2390 }
Emeric Brun4d7ada82021-06-30 19:04:16 +02002391 return ACT_RET_CONT;
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002392}
2393
Emeric Brun4d7ada82021-06-30 19:04:16 +02002394/* Same as action_inc_gpc() but for gpc1 only */
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002395static enum act_return action_inc_gpc1(struct act_rule *rule, struct proxy *px,
2396 struct session *sess, struct stream *s, int flags)
2397{
2398 struct stksess *ts;
2399 struct stkctr *stkctr;
Willy Tarreau5b654ad2021-07-06 18:51:12 +02002400 unsigned int period = 0;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002401
2402 /* Extract the stksess, return OK if no stksess available. */
2403 if (s)
2404 stkctr = &s->stkctr[rule->arg.gpc.sc];
2405 else
2406 stkctr = &sess->stkctr[rule->arg.gpc.sc];
2407
2408 ts = stkctr_entry(stkctr);
2409 if (ts) {
2410 void *ptr1, *ptr2;
2411
2412 /* First, update gpc1_rate if it's tracked. Second, update its gpc1 if tracked. */
2413 ptr1 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC1_RATE);
Emeric Brun726783d2021-06-30 19:06:43 +02002414 if (ptr1) {
2415 period = stkctr->table->data_arg[STKTABLE_DT_GPC1_RATE].u;
2416 }
2417 else {
2418 /* fallback on the gpc array */
2419 ptr1 = stktable_data_ptr_idx(stkctr->table, ts, STKTABLE_DT_GPC_RATE, 1);
2420 if (ptr1)
2421 period = stkctr->table->data_arg[STKTABLE_DT_GPC_RATE].u;
2422 }
2423
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002424 ptr2 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC1);
Emeric Brun726783d2021-06-30 19:06:43 +02002425 if (!ptr2) {
2426 /* fallback on the gpc array */
2427 ptr2 = stktable_data_ptr_idx(stkctr->table, ts, STKTABLE_DT_GPC, 1);
2428 }
2429
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002430 if (ptr1 || ptr2) {
2431 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
2432
2433 if (ptr1)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002434 update_freq_ctr_period(&stktable_data_cast(ptr1, std_t_frqp),
Emeric Brun726783d2021-06-30 19:06:43 +02002435 period, 1);
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002436
2437 if (ptr2)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002438 stktable_data_cast(ptr2, std_t_uint)++;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002439
2440 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
2441
2442 /* If data was modified, we need to touch to re-schedule sync */
2443 stktable_touch_local(stkctr->table, ts, 0);
2444 }
2445 }
2446 return ACT_RET_CONT;
2447}
2448
Emeric Brun4d7ada82021-06-30 19:04:16 +02002449/* This function is a common parser for actions incrementing the GPC
2450 * (General Purpose Counters). It understands the formats:
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002451 *
Emeric Brun4d7ada82021-06-30 19:04:16 +02002452 * sc-inc-gpc(<gpc IDX>,<track ID>)
2453 * sc-inc-gpc0([<track ID>])
2454 * sc-inc-gpc1([<track ID>])
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002455 *
Emeric Brun4d7ada82021-06-30 19:04:16 +02002456 * It returns ACT_RET_PRS_ERR if fails and <err> is filled with an error
2457 * message. Otherwise it returns ACT_RET_PRS_OK.
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002458 */
Emeric Brun4d7ada82021-06-30 19:04:16 +02002459static enum act_parse_ret parse_inc_gpc(const char **args, int *arg, struct proxy *px,
2460 struct act_rule *rule, char **err)
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002461{
2462 const char *cmd_name = args[*arg-1];
2463 char *error;
2464
Emeric Brun4d7ada82021-06-30 19:04:16 +02002465 cmd_name += strlen("sc-inc-gpc");
2466 if (*cmd_name == '(') {
2467 cmd_name++; /* skip the '(' */
2468 rule->arg.gpc.idx = strtoul(cmd_name, &error, 10); /* Convert stick table id. */
2469 if (*error != ',') {
2470 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 +01002471 return ACT_RET_PRS_ERR;
2472 }
Emeric Brun4d7ada82021-06-30 19:04:16 +02002473 else {
2474 cmd_name = error + 1; /* skip the ',' */
2475 rule->arg.gpc.sc = strtol(cmd_name, &error, 10); /* Convert stick table id. */
2476 if (*error != ')') {
2477 memprintf(err, "invalid stick table track ID '%s'. Expects sc-inc-gpc(<GPC ID>,<Track ID>)", args[*arg-1]);
2478 return ACT_RET_PRS_ERR;
2479 }
2480
2481 if (rule->arg.gpc.sc >= MAX_SESS_STKCTR) {
2482 memprintf(err, "invalid stick table track ID '%s'. The max allowed ID is %d",
2483 args[*arg-1], MAX_SESS_STKCTR-1);
2484 return ACT_RET_PRS_ERR;
2485 }
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002486 }
Emeric Brun4d7ada82021-06-30 19:04:16 +02002487 rule->action_ptr = action_inc_gpc;
2488 }
2489 else if (*cmd_name == '0' ||*cmd_name == '1') {
2490 char c = *cmd_name;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002491
Emeric Brun4d7ada82021-06-30 19:04:16 +02002492 cmd_name++;
2493 if (*cmd_name == '\0') {
2494 /* default stick table id. */
2495 rule->arg.gpc.sc = 0;
2496 } else {
2497 /* parse the stick table id. */
2498 if (*cmd_name != '(') {
2499 memprintf(err, "invalid stick table track ID. Expects %s(<Track ID>)", args[*arg-1]);
2500 return ACT_RET_PRS_ERR;
2501 }
2502 cmd_name++; /* jump the '(' */
2503 rule->arg.gpc.sc = strtol(cmd_name, &error, 10); /* Convert stick table id. */
2504 if (*error != ')') {
2505 memprintf(err, "invalid stick table track ID. Expects %s(<Track ID>)", args[*arg-1]);
2506 return ACT_RET_PRS_ERR;
2507 }
2508
2509 if (rule->arg.gpc.sc >= MAX_SESS_STKCTR) {
2510 memprintf(err, "invalid stick table track ID. The max allowed ID is %d",
2511 MAX_SESS_STKCTR-1);
2512 return ACT_RET_PRS_ERR;
2513 }
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002514 }
Emeric Brun4d7ada82021-06-30 19:04:16 +02002515 if (c == '1')
2516 rule->action_ptr = action_inc_gpc1;
2517 else
2518 rule->action_ptr = action_inc_gpc0;
2519 }
2520 else {
2521 /* default stick table id. */
2522 memprintf(err, "invalid gpc ID '%s'. Expects sc-set-gpc(<GPC ID>,<Track ID>)", args[*arg-1]);
2523 return ACT_RET_PRS_ERR;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002524 }
2525 rule->action = ACT_CUSTOM;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002526 return ACT_RET_PRS_OK;
2527}
2528
Emeric Brun877b0b52021-06-30 18:57:49 +02002529/* This function sets the gpt at index 'rule->arg.gpt.idx' of the array on the
2530 * tracksc counter of index 'rule->arg.gpt.sc' stored into the <stream> or
2531 * directly in the session <sess> if <stream> is set to NULL. This gpt is
2532 * set to the value computed by the expression 'rule->arg.gpt.expr' or if
2533 * 'rule->arg.gpt.expr' is null directly to the value of 'rule->arg.gpt.value'.
2534 *
2535 * This function always returns ACT_RET_CONT and parameter flags is unused.
2536 */
2537static enum act_return action_set_gpt(struct act_rule *rule, struct proxy *px,
2538 struct session *sess, struct stream *s, int flags)
2539{
2540 void *ptr;
2541 struct stksess *ts;
2542 struct stkctr *stkctr;
2543 unsigned int value = 0;
2544 struct sample *smp;
2545 int smp_opt_dir;
2546
2547 /* Extract the stksess, return OK if no stksess available. */
2548 if (s)
2549 stkctr = &s->stkctr[rule->arg.gpt.sc];
2550 else
2551 stkctr = &sess->stkctr[rule->arg.gpt.sc];
2552
2553 ts = stkctr_entry(stkctr);
2554 if (!ts)
2555 return ACT_RET_CONT;
2556
2557 /* Store the sample in the required sc, and ignore errors. */
2558 ptr = stktable_data_ptr_idx(stkctr->table, ts, STKTABLE_DT_GPT, rule->arg.gpt.idx);
2559 if (ptr) {
2560
2561 if (!rule->arg.gpt.expr)
2562 value = (unsigned int)(rule->arg.gpt.value);
2563 else {
2564 switch (rule->from) {
2565 case ACT_F_TCP_REQ_SES: smp_opt_dir = SMP_OPT_DIR_REQ; break;
2566 case ACT_F_TCP_REQ_CNT: smp_opt_dir = SMP_OPT_DIR_REQ; break;
2567 case ACT_F_TCP_RES_CNT: smp_opt_dir = SMP_OPT_DIR_RES; break;
2568 case ACT_F_HTTP_REQ: smp_opt_dir = SMP_OPT_DIR_REQ; break;
2569 case ACT_F_HTTP_RES: smp_opt_dir = SMP_OPT_DIR_RES; break;
2570 default:
2571 send_log(px, LOG_ERR, "stick table: internal error while setting gpt%u.", rule->arg.gpt.idx);
2572 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))
2573 ha_alert("stick table: internal error while executing setting gpt%u.\n", rule->arg.gpt.idx);
2574 return ACT_RET_CONT;
2575 }
2576
2577 /* Fetch and cast the expression. */
2578 smp = sample_fetch_as_type(px, sess, s, smp_opt_dir|SMP_OPT_FINAL, rule->arg.gpt.expr, SMP_T_SINT);
2579 if (!smp) {
2580 send_log(px, LOG_WARNING, "stick table: invalid expression or data type while setting gpt%u.", rule->arg.gpt.idx);
2581 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))
2582 ha_alert("stick table: invalid expression or data type while setting gpt%u.\n", rule->arg.gpt.idx);
2583 return ACT_RET_CONT;
2584 }
2585 value = (unsigned int)(smp->data.u.sint);
2586 }
2587
2588 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
2589
2590 stktable_data_cast(ptr, std_t_uint) = value;
2591
2592 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
2593
2594 stktable_touch_local(stkctr->table, ts, 0);
2595 }
2596
2597 return ACT_RET_CONT;
2598}
2599
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002600/* Always returns 1. */
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002601static enum act_return action_set_gpt0(struct act_rule *rule, struct proxy *px,
Willy Tarreau658b85b2015-09-27 10:00:49 +02002602 struct session *sess, struct stream *s, int flags)
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002603{
2604 void *ptr;
2605 struct stksess *ts;
2606 struct stkctr *stkctr;
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002607 unsigned int value = 0;
2608 struct sample *smp;
2609 int smp_opt_dir;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002610
2611 /* Extract the stksess, return OK if no stksess available. */
2612 if (s)
2613 stkctr = &s->stkctr[rule->arg.gpt.sc];
2614 else
2615 stkctr = &sess->stkctr[rule->arg.gpt.sc];
Willy Tarreau79c1e912016-01-25 14:54:45 +01002616
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002617 ts = stkctr_entry(stkctr);
2618 if (!ts)
2619 return ACT_RET_CONT;
2620
2621 /* Store the sample in the required sc, and ignore errors. */
2622 ptr = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPT0);
Emeric Brunf7ab0bf2021-06-30 18:58:22 +02002623 if (!ptr)
2624 ptr = stktable_data_ptr_idx(stkctr->table, ts, STKTABLE_DT_GPT, 0);
2625
Willy Tarreau79c1e912016-01-25 14:54:45 +01002626 if (ptr) {
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002627 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 gpt0.");
2638 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))
2639 ha_alert("stick table: internal error while executing setting gpt0.\n");
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 gpt0.");
2647 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))
2648 ha_alert("stick table: invalid expression or data type while setting gpt0.\n");
2649 return ACT_RET_CONT;
2650 }
2651 value = (unsigned int)(smp->data.u.sint);
2652 }
2653
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002654 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002655
Emeric Brun0e3457b2021-06-30 17:18:28 +02002656 stktable_data_cast(ptr, std_t_uint) = value;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002657
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002658 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002659
2660 stktable_touch_local(stkctr->table, ts, 0);
Willy Tarreau79c1e912016-01-25 14:54:45 +01002661 }
2662
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002663 return ACT_RET_CONT;
2664}
2665
Emeric Brun877b0b52021-06-30 18:57:49 +02002666/* This function is a parser for the "sc-set-gpt" and "sc-set-gpt0" actions.
2667 * It understands the formats:
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002668 *
Emeric Brun877b0b52021-06-30 18:57:49 +02002669 * sc-set-gpt(<gpt IDX>,<track ID>) <expression>
2670 * sc-set-gpt0(<track ID>) <expression>
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002671 *
Emeric Brun877b0b52021-06-30 18:57:49 +02002672 * It returns ACT_RET_PRS_ERR if fails and <err> is filled with an error message.
2673 * Otherwise, it returns ACT_RET_PRS_OK and the variable 'rule->arg.gpt.expr'
2674 * is filled with the pointer to the expression to execute or NULL if the arg
2675 * is directly an integer stored into 'rule->arg.gpt.value'.
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002676 */
Emeric Brun877b0b52021-06-30 18:57:49 +02002677static enum act_parse_ret parse_set_gpt(const char **args, int *arg, struct proxy *px,
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002678 struct act_rule *rule, char **err)
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002679{
2680 const char *cmd_name = args[*arg-1];
2681 char *error;
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002682 int smp_val;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002683
Emeric Brun877b0b52021-06-30 18:57:49 +02002684 cmd_name += strlen("sc-set-gpt");
2685 if (*cmd_name == '(') {
2686 cmd_name++; /* skip the '(' */
2687 rule->arg.gpt.idx = strtoul(cmd_name, &error, 10); /* Convert stick table id. */
2688 if (*error != ',') {
2689 memprintf(err, "Missing gpt ID '%s'. Expects sc-set-gpt(<GPT ID>,<Track ID>)", args[*arg-1]);
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002690 return ACT_RET_PRS_ERR;
2691 }
Emeric Brun877b0b52021-06-30 18:57:49 +02002692 else {
2693 cmd_name = error + 1; /* skip the ',' */
2694 rule->arg.gpt.sc = strtol(cmd_name, &error, 10); /* Convert stick table id. */
2695 if (*error != ')') {
2696 memprintf(err, "invalid stick table track ID '%s'. Expects sc-set-gpt(<GPT ID>,<Track ID>)", args[*arg-1]);
2697 return ACT_RET_PRS_ERR;
2698 }
2699
2700 if (rule->arg.gpt.sc >= MAX_SESS_STKCTR) {
2701 memprintf(err, "invalid stick table track ID '%s'. The max allowed ID is %d",
2702 args[*arg-1], MAX_SESS_STKCTR-1);
2703 return ACT_RET_PRS_ERR;
2704 }
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002705 }
Emeric Brun877b0b52021-06-30 18:57:49 +02002706 rule->action_ptr = action_set_gpt;
2707 }
2708 else if (*cmd_name == '0') {
2709 cmd_name++;
2710 if (*cmd_name == '\0') {
2711 /* default stick table id. */
2712 rule->arg.gpt.sc = 0;
2713 } else {
2714 /* parse the stick table id. */
2715 if (*cmd_name != '(') {
2716 memprintf(err, "invalid stick table track ID '%s'. Expects sc-set-gpt0(<Track ID>)", args[*arg-1]);
2717 return ACT_RET_PRS_ERR;
2718 }
2719 cmd_name++; /* jump the '(' */
2720 rule->arg.gpt.sc = strtol(cmd_name, &error, 10); /* Convert stick table id. */
2721 if (*error != ')') {
2722 memprintf(err, "invalid stick table track ID '%s'. Expects sc-set-gpt0(<Track ID>)", args[*arg-1]);
2723 return ACT_RET_PRS_ERR;
2724 }
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002725
Emeric Brun877b0b52021-06-30 18:57:49 +02002726 if (rule->arg.gpt.sc >= MAX_SESS_STKCTR) {
2727 memprintf(err, "invalid stick table track ID '%s'. The max allowed ID is %d",
2728 args[*arg-1], MAX_SESS_STKCTR-1);
2729 return ACT_RET_PRS_ERR;
2730 }
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002731 }
Emeric Brun877b0b52021-06-30 18:57:49 +02002732 rule->action_ptr = action_set_gpt0;
2733 }
2734 else {
2735 /* default stick table id. */
2736 memprintf(err, "invalid gpt ID '%s'. Expects sc-set-gpt(<GPT ID>,<Track ID>)", args[*arg-1]);
2737 return ACT_RET_PRS_ERR;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002738 }
2739
Willy Tarreauece4c4a2021-08-24 14:57:28 +02002740 /* value may be either an integer or an expression */
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002741 rule->arg.gpt.expr = NULL;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002742 rule->arg.gpt.value = strtol(args[*arg], &error, 10);
Willy Tarreauece4c4a2021-08-24 14:57:28 +02002743 if (*error == '\0') {
2744 /* valid integer, skip it */
2745 (*arg)++;
2746 } else {
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002747 rule->arg.gpt.expr = sample_parse_expr((char **)args, arg, px->conf.args.file,
Willy Tarreaue3b57bf2020-02-14 16:50:14 +01002748 px->conf.args.line, err, &px->conf.args, NULL);
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002749 if (!rule->arg.gpt.expr)
2750 return ACT_RET_PRS_ERR;
2751
2752 switch (rule->from) {
2753 case ACT_F_TCP_REQ_SES: smp_val = SMP_VAL_FE_SES_ACC; break;
2754 case ACT_F_TCP_REQ_CNT: smp_val = SMP_VAL_FE_REQ_CNT; break;
2755 case ACT_F_TCP_RES_CNT: smp_val = SMP_VAL_BE_RES_CNT; break;
2756 case ACT_F_HTTP_REQ: smp_val = SMP_VAL_FE_HRQ_HDR; break;
2757 case ACT_F_HTTP_RES: smp_val = SMP_VAL_BE_HRS_HDR; break;
2758 default:
2759 memprintf(err, "internal error, unexpected rule->from=%d, please report this bug!", rule->from);
2760 return ACT_RET_PRS_ERR;
2761 }
2762 if (!(rule->arg.gpt.expr->fetch->val & smp_val)) {
2763 memprintf(err, "fetch method '%s' extracts information from '%s', none of which is available here", args[*arg-1],
2764 sample_src_names(rule->arg.gpt.expr->fetch->use));
2765 free(rule->arg.gpt.expr);
2766 return ACT_RET_PRS_ERR;
2767 }
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002768 }
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002769
Thierry FOURNIER42148732015-09-02 17:17:33 +02002770 rule->action = ACT_CUSTOM;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002771
2772 return ACT_RET_PRS_OK;
2773}
2774
Willy Tarreau7d562212016-11-25 16:10:05 +01002775/* set temp integer to the number of used entries in the table pointed to by expr.
2776 * Accepts exactly 1 argument of type table.
2777 */
2778static int
2779smp_fetch_table_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
2780{
2781 smp->flags = SMP_F_VOL_TEST;
2782 smp->data.type = SMP_T_SINT;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002783 smp->data.u.sint = args->data.t->current;
Willy Tarreau7d562212016-11-25 16:10:05 +01002784 return 1;
2785}
2786
2787/* set temp integer to the number of free entries in the table pointed to by expr.
2788 * Accepts exactly 1 argument of type table.
2789 */
2790static int
2791smp_fetch_table_avl(const struct arg *args, struct sample *smp, const char *kw, void *private)
2792{
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002793 struct stktable *t;
Willy Tarreau7d562212016-11-25 16:10:05 +01002794
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002795 t = args->data.t;
Willy Tarreau7d562212016-11-25 16:10:05 +01002796 smp->flags = SMP_F_VOL_TEST;
2797 smp->data.type = SMP_T_SINT;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002798 smp->data.u.sint = t->size - t->current;
Willy Tarreau7d562212016-11-25 16:10:05 +01002799 return 1;
2800}
2801
2802/* Returns a pointer to a stkctr depending on the fetch keyword name.
2803 * It is designed to be called as sc[0-9]_* sc_* or src_* exclusively.
2804 * sc[0-9]_* will return a pointer to the respective field in the
2805 * stream <l4>. sc_* requires an UINT argument specifying the stick
2806 * counter number. src_* will fill a locally allocated structure with
2807 * the table and entry corresponding to what is specified with src_*.
2808 * NULL may be returned if the designated stkctr is not tracked. For
2809 * the sc_* and sc[0-9]_* forms, an optional table argument may be
2810 * passed. When present, the currently tracked key is then looked up
2811 * in the specified table instead of the current table. The purpose is
Ilya Shipitsin47d17182020-06-21 21:42:57 +05002812 * to be able to convert multiple values per key (eg: have gpc0 from
Willy Tarreau7d562212016-11-25 16:10:05 +01002813 * multiple tables). <strm> is allowed to be NULL, in which case only
2814 * the session will be consulted.
2815 */
2816struct stkctr *
Emeric Brun819fc6f2017-06-13 19:37:32 +02002817smp_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 +01002818{
Willy Tarreau7d562212016-11-25 16:10:05 +01002819 struct stkctr *stkptr;
2820 struct stksess *stksess;
2821 unsigned int num = kw[2] - '0';
2822 int arg = 0;
2823
2824 if (num == '_' - '0') {
2825 /* sc_* variant, args[0] = ctr# (mandatory) */
2826 num = args[arg++].data.sint;
Willy Tarreau7d562212016-11-25 16:10:05 +01002827 }
2828 else if (num > 9) { /* src_* variant, args[0] = table */
2829 struct stktable_key *key;
2830 struct connection *conn = objt_conn(sess->origin);
2831 struct sample smp;
2832
2833 if (!conn)
2834 return NULL;
2835
Joseph Herlant5662fa42018-11-15 13:43:28 -08002836 /* Fetch source address in a sample. */
Willy Tarreau7d562212016-11-25 16:10:05 +01002837 smp.px = NULL;
2838 smp.sess = sess;
2839 smp.strm = strm;
Amaury Denoyellec460c702021-05-12 10:17:47 +02002840 if (!smp_fetch_src || !smp_fetch_src(empty_arg_list, &smp, "src", NULL))
Willy Tarreau7d562212016-11-25 16:10:05 +01002841 return NULL;
2842
2843 /* Converts into key. */
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002844 key = smp_to_stkey(&smp, args->data.t);
Willy Tarreau7d562212016-11-25 16:10:05 +01002845 if (!key)
2846 return NULL;
2847
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002848 stkctr->table = args->data.t;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002849 stkctr_set_entry(stkctr, stktable_lookup_key(stkctr->table, key));
2850 return stkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002851 }
2852
2853 /* Here, <num> contains the counter number from 0 to 9 for
2854 * the sc[0-9]_ form, or even higher using sc_(num) if needed.
2855 * args[arg] is the first optional argument. We first lookup the
2856 * ctr form the stream, then from the session if it was not there.
Christopher Fauleta9fa88a2019-10-21 10:53:34 +02002857 * But we must be sure the counter does not exceed MAX_SESS_STKCTR.
Willy Tarreau7d562212016-11-25 16:10:05 +01002858 */
Christopher Fauleta9fa88a2019-10-21 10:53:34 +02002859 if (num >= MAX_SESS_STKCTR)
2860 return NULL;
Willy Tarreau7d562212016-11-25 16:10:05 +01002861
2862 if (strm)
2863 stkptr = &strm->stkctr[num];
2864 if (!strm || !stkctr_entry(stkptr)) {
2865 stkptr = &sess->stkctr[num];
2866 if (!stkctr_entry(stkptr))
2867 return NULL;
2868 }
2869
2870 stksess = stkctr_entry(stkptr);
2871 if (!stksess)
2872 return NULL;
2873
2874 if (unlikely(args[arg].type == ARGT_TAB)) {
2875 /* an alternate table was specified, let's look up the same key there */
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002876 stkctr->table = args[arg].data.t;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002877 stkctr_set_entry(stkctr, stktable_lookup(stkctr->table, stksess));
2878 return stkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002879 }
2880 return stkptr;
2881}
2882
2883/* same as smp_fetch_sc_stkctr() but dedicated to src_* and can create
2884 * the entry if it doesn't exist yet. This is needed for a few fetch
2885 * functions which need to create an entry, such as src_inc_gpc* and
2886 * src_clr_gpc*.
2887 */
2888struct stkctr *
Emeric Brun819fc6f2017-06-13 19:37:32 +02002889smp_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 +01002890{
Willy Tarreau7d562212016-11-25 16:10:05 +01002891 struct stktable_key *key;
2892 struct connection *conn = objt_conn(sess->origin);
2893 struct sample smp;
2894
2895 if (strncmp(kw, "src_", 4) != 0)
2896 return NULL;
2897
2898 if (!conn)
2899 return NULL;
2900
Joseph Herlant5662fa42018-11-15 13:43:28 -08002901 /* Fetch source address in a sample. */
Willy Tarreau7d562212016-11-25 16:10:05 +01002902 smp.px = NULL;
2903 smp.sess = sess;
2904 smp.strm = strm;
Amaury Denoyellec460c702021-05-12 10:17:47 +02002905 if (!smp_fetch_src || !smp_fetch_src(empty_arg_list, &smp, "src", NULL))
Willy Tarreau7d562212016-11-25 16:10:05 +01002906 return NULL;
2907
2908 /* Converts into key. */
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002909 key = smp_to_stkey(&smp, args->data.t);
Willy Tarreau7d562212016-11-25 16:10:05 +01002910 if (!key)
2911 return NULL;
2912
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002913 stkctr->table = args->data.t;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002914 stkctr_set_entry(stkctr, stktable_get_entry(stkctr->table, key));
2915 return stkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002916}
2917
2918/* set return a boolean indicating if the requested stream counter is
2919 * currently being tracked or not.
2920 * Supports being called as "sc[0-9]_tracked" only.
2921 */
2922static int
2923smp_fetch_sc_tracked(const struct arg *args, struct sample *smp, const char *kw, void *private)
2924{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002925 struct stkctr tmpstkctr;
2926 struct stkctr *stkctr;
2927
Willy Tarreau7d562212016-11-25 16:10:05 +01002928 smp->flags = SMP_F_VOL_TEST;
2929 smp->data.type = SMP_T_BOOL;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002930 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2931 smp->data.u.sint = !!stkctr;
2932
2933 /* release the ref count */
Dirkjan Bussinkff57f1b2018-09-14 14:31:22 +02002934 if (stkctr == &tmpstkctr)
Emeric Brun819fc6f2017-06-13 19:37:32 +02002935 stktable_release(stkctr->table, stkctr_entry(stkctr));
2936
Emeric Brun877b0b52021-06-30 18:57:49 +02002937 return 1;
2938}
2939
2940/* set <smp> to the General Purpose Tag of index set as first arg
2941 * to value from the stream's tracked frontend counters or from the src.
2942 * Supports being called as "sc_get_gpt(<gpt-idx>,<sc-idx>[,<table>])" or
2943 * "src_get_gpt(<gpt-idx>[,<table>])" only. Value zero is returned if
2944 * the key is new or gpt is not stored.
2945 */
2946static int
2947smp_fetch_sc_get_gpt(const struct arg *args, struct sample *smp, const char *kw, void *private)
2948{
2949 struct stkctr tmpstkctr;
2950 struct stkctr *stkctr;
2951 unsigned int idx;
2952
2953 idx = args[0].data.sint;
2954
2955 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args + 1, kw, &tmpstkctr);
2956 if (!stkctr)
2957 return 0;
2958
2959 smp->flags = SMP_F_VOL_TEST;
2960 smp->data.type = SMP_T_SINT;
2961 smp->data.u.sint = 0;
2962
2963 if (stkctr_entry(stkctr)) {
2964 void *ptr;
2965
2966 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPT, idx);
2967 if (!ptr) {
2968 if (stkctr == &tmpstkctr)
2969 stktable_release(stkctr->table, stkctr_entry(stkctr));
2970 return 0; /* parameter not stored */
2971 }
2972
2973 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2974
2975 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
2976
2977 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2978
2979 if (stkctr == &tmpstkctr)
2980 stktable_release(stkctr->table, stkctr_entry(stkctr));
2981 }
Willy Tarreau7d562212016-11-25 16:10:05 +01002982 return 1;
2983}
2984
2985/* set <smp> to the General Purpose Flag 0 value from the stream's tracked
2986 * frontend counters or from the src.
2987 * Supports being called as "sc[0-9]_get_gpc0" or "src_get_gpt0" only. Value
2988 * zero is returned if the key is new.
2989 */
2990static int
2991smp_fetch_sc_get_gpt0(const struct arg *args, struct sample *smp, const char *kw, void *private)
2992{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002993 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002994 struct stkctr *stkctr;
2995
Emeric Brun819fc6f2017-06-13 19:37:32 +02002996 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002997 if (!stkctr)
2998 return 0;
2999
3000 smp->flags = SMP_F_VOL_TEST;
3001 smp->data.type = SMP_T_SINT;
3002 smp->data.u.sint = 0;
3003
Emeric Brun819fc6f2017-06-13 19:37:32 +02003004 if (stkctr_entry(stkctr)) {
3005 void *ptr;
3006
3007 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPT0);
Emeric Brunf7ab0bf2021-06-30 18:58:22 +02003008 if (!ptr)
3009 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPT, 0);
3010
Emeric Brun4d7ada82021-06-30 19:04:16 +02003011 if (!ptr) {
3012 if (stkctr == &tmpstkctr)
3013 stktable_release(stkctr->table, stkctr_entry(stkctr));
3014 return 0; /* parameter not stored */
3015 }
3016
3017 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3018
3019 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
3020
3021 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3022
3023 if (stkctr == &tmpstkctr)
3024 stktable_release(stkctr->table, stkctr_entry(stkctr));
3025 }
3026 return 1;
3027}
3028
3029/* set <smp> to the GPC[args(0)]'s value from the stream's tracked
3030 * frontend counters or from the src.
3031 * Supports being called as "sc_get_gpc(<gpc-idx>,<sc-idx>[,<table>])" or
3032 * "src_get_gpc(<gpc-idx>[,<table>])" only. Value
3033 * Value zero is returned if the key is new or gpc is not stored.
3034 */
3035static int
3036smp_fetch_sc_get_gpc(const struct arg *args, struct sample *smp, const char *kw, void *private)
3037{
3038 struct stkctr tmpstkctr;
3039 struct stkctr *stkctr;
3040 unsigned int idx;
3041
3042 idx = args[0].data.sint;
3043
3044 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args + 1, kw, &tmpstkctr);
3045 if (!stkctr)
3046 return 0;
3047
3048 smp->flags = SMP_F_VOL_TEST;
3049 smp->data.type = SMP_T_SINT;
3050 smp->data.u.sint = 0;
3051
3052 if (stkctr_entry(stkctr) != NULL) {
3053 void *ptr;
3054
3055 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC, idx);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003056 if (!ptr) {
3057 if (stkctr == &tmpstkctr)
3058 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003059 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003060 }
3061
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003062 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003063
Emeric Brun0e3457b2021-06-30 17:18:28 +02003064 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003065
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003066 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003067
3068 if (stkctr == &tmpstkctr)
3069 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003070 }
3071 return 1;
3072}
3073
3074/* set <smp> to the General Purpose Counter 0 value from the stream's tracked
3075 * frontend counters or from the src.
3076 * Supports being called as "sc[0-9]_get_gpc0" or "src_get_gpc0" only. Value
3077 * zero is returned if the key is new.
3078 */
3079static int
3080smp_fetch_sc_get_gpc0(const struct arg *args, struct sample *smp, const char *kw, void *private)
3081{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003082 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003083 struct stkctr *stkctr;
3084
Emeric Brun819fc6f2017-06-13 19:37:32 +02003085 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003086 if (!stkctr)
3087 return 0;
3088
3089 smp->flags = SMP_F_VOL_TEST;
3090 smp->data.type = SMP_T_SINT;
3091 smp->data.u.sint = 0;
3092
3093 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003094 void *ptr;
3095
3096 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0);
3097 if (!ptr) {
Emeric Brun726783d2021-06-30 19:06:43 +02003098 /* fallback on the gpc array */
3099 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC, 0);
3100 }
3101
3102 if (!ptr) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003103 if (stkctr == &tmpstkctr)
3104 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003105 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003106 }
3107
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003108 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003109
Emeric Brun0e3457b2021-06-30 17:18:28 +02003110 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003111
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003112 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003113
3114 if (stkctr == &tmpstkctr)
3115 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003116 }
3117 return 1;
3118}
3119
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003120/* set <smp> to the General Purpose Counter 1 value from the stream's tracked
3121 * frontend counters or from the src.
3122 * Supports being called as "sc[0-9]_get_gpc1" or "src_get_gpc1" only. Value
3123 * zero is returned if the key is new.
3124 */
3125static int
3126smp_fetch_sc_get_gpc1(const struct arg *args, struct sample *smp, const char *kw, void *private)
3127{
3128 struct stkctr tmpstkctr;
3129 struct stkctr *stkctr;
3130
3131 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
3132 if (!stkctr)
3133 return 0;
3134
3135 smp->flags = SMP_F_VOL_TEST;
3136 smp->data.type = SMP_T_SINT;
3137 smp->data.u.sint = 0;
3138
3139 if (stkctr_entry(stkctr) != NULL) {
3140 void *ptr;
3141
3142 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1);
3143 if (!ptr) {
Emeric Brun726783d2021-06-30 19:06:43 +02003144 /* fallback on the gpc array */
3145 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC, 1);
3146 }
3147
3148 if (!ptr) {
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003149 if (stkctr == &tmpstkctr)
3150 stktable_release(stkctr->table, stkctr_entry(stkctr));
3151 return 0; /* parameter not stored */
3152 }
3153
3154 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3155
Emeric Brun0e3457b2021-06-30 17:18:28 +02003156 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003157
3158 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3159
3160 if (stkctr == &tmpstkctr)
3161 stktable_release(stkctr->table, stkctr_entry(stkctr));
3162 }
3163 return 1;
3164}
3165
Emeric Brun4d7ada82021-06-30 19:04:16 +02003166/* set <smp> to the GPC[args(0)]'s event rate from the stream's
3167 * tracked frontend counters or from the src.
3168 * Supports being called as "sc_gpc_rate(<gpc-idx>,<sc-idx>[,<table])"
3169 * or "src_gpc_rate(<gpc-idx>[,<table>])" only.
3170 * Value zero is returned if the key is new or gpc_rate is not stored.
3171 */
3172static int
3173smp_fetch_sc_gpc_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3174{
3175 struct stkctr tmpstkctr;
3176 struct stkctr *stkctr;
3177 unsigned int idx;
3178
3179 idx = args[0].data.sint;
3180
3181 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args + 1, kw, &tmpstkctr);
3182 if (!stkctr)
3183 return 0;
3184
3185 smp->flags = SMP_F_VOL_TEST;
3186 smp->data.type = SMP_T_SINT;
3187 smp->data.u.sint = 0;
3188 if (stkctr_entry(stkctr) != NULL) {
3189 void *ptr;
3190
3191 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC_RATE, idx);
3192 if (!ptr) {
3193 if (stkctr == &tmpstkctr)
3194 stktable_release(stkctr->table, stkctr_entry(stkctr));
3195 return 0; /* parameter not stored */
3196 }
3197
3198 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3199
3200 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
3201 stkctr->table->data_arg[STKTABLE_DT_GPC_RATE].u);
3202
3203 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3204
3205 if (stkctr == &tmpstkctr)
3206 stktable_release(stkctr->table, stkctr_entry(stkctr));
3207 }
3208 return 1;
3209}
3210
Willy Tarreau7d562212016-11-25 16:10:05 +01003211/* set <smp> to the General Purpose Counter 0's event rate from the stream's
3212 * tracked frontend counters or from the src.
3213 * Supports being called as "sc[0-9]_gpc0_rate" or "src_gpc0_rate" only.
3214 * Value zero is returned if the key is new.
3215 */
3216static int
3217smp_fetch_sc_gpc0_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3218{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003219 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003220 struct stkctr *stkctr;
Emeric Brun726783d2021-06-30 19:06:43 +02003221 unsigned int period;
Willy Tarreau7d562212016-11-25 16:10:05 +01003222
Emeric Brun819fc6f2017-06-13 19:37:32 +02003223 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003224 if (!stkctr)
3225 return 0;
3226
3227 smp->flags = SMP_F_VOL_TEST;
3228 smp->data.type = SMP_T_SINT;
3229 smp->data.u.sint = 0;
3230 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003231 void *ptr;
3232
3233 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0_RATE);
Emeric Brun726783d2021-06-30 19:06:43 +02003234 if (ptr) {
3235 period = stkctr->table->data_arg[STKTABLE_DT_GPC0_RATE].u;
3236 }
3237 else {
3238 /* fallback on the gpc array */
3239 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC_RATE, 0);
3240 if (ptr)
3241 period = stkctr->table->data_arg[STKTABLE_DT_GPC_RATE].u;
3242 }
3243
Emeric Brun819fc6f2017-06-13 19:37:32 +02003244 if (!ptr) {
3245 if (stkctr == &tmpstkctr)
3246 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003247 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003248 }
3249
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003250 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003251
Emeric Brun726783d2021-06-30 19:06:43 +02003252 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp), period);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003253
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003254 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003255
3256 if (stkctr == &tmpstkctr)
3257 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003258 }
3259 return 1;
3260}
3261
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003262/* set <smp> to the General Purpose Counter 1's event rate from the stream's
3263 * tracked frontend counters or from the src.
3264 * Supports being called as "sc[0-9]_gpc1_rate" or "src_gpc1_rate" only.
3265 * Value zero is returned if the key is new.
3266 */
3267static int
3268smp_fetch_sc_gpc1_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3269{
3270 struct stkctr tmpstkctr;
3271 struct stkctr *stkctr;
Emeric Brun726783d2021-06-30 19:06:43 +02003272 unsigned int period;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003273
3274 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
3275 if (!stkctr)
3276 return 0;
3277
3278 smp->flags = SMP_F_VOL_TEST;
3279 smp->data.type = SMP_T_SINT;
3280 smp->data.u.sint = 0;
3281 if (stkctr_entry(stkctr) != NULL) {
3282 void *ptr;
3283
3284 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1_RATE);
Emeric Brun726783d2021-06-30 19:06:43 +02003285 if (ptr) {
3286 period = stkctr->table->data_arg[STKTABLE_DT_GPC1_RATE].u;
3287 }
3288 else {
3289 /* fallback on the gpc array */
3290 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC_RATE, 1);
3291 if (ptr)
3292 period = stkctr->table->data_arg[STKTABLE_DT_GPC_RATE].u;
3293 }
3294
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003295 if (!ptr) {
3296 if (stkctr == &tmpstkctr)
3297 stktable_release(stkctr->table, stkctr_entry(stkctr));
3298 return 0; /* parameter not stored */
3299 }
3300
3301 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3302
Emeric Brun726783d2021-06-30 19:06:43 +02003303 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 +01003304
3305 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3306
3307 if (stkctr == &tmpstkctr)
3308 stktable_release(stkctr->table, stkctr_entry(stkctr));
3309 }
3310 return 1;
3311}
3312
Emeric Brun4d7ada82021-06-30 19:04:16 +02003313/* Increment the GPC[args(0)] value from the stream's tracked
3314 * frontend counters and return it into temp integer.
3315 * Supports being called as "sc_inc_gpc(<gpc-idx>,<sc-idx>[,<table>])"
3316 * or "src_inc_gpc(<gpc-idx>[,<table>])" only.
3317 */
3318static int
3319smp_fetch_sc_inc_gpc(const struct arg *args, struct sample *smp, const char *kw, void *private)
3320{
3321 struct stkctr tmpstkctr;
3322 struct stkctr *stkctr;
3323 unsigned int idx;
3324
3325 idx = args[0].data.sint;
3326
3327 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args + 1, kw, &tmpstkctr);
3328 if (!stkctr)
3329 return 0;
3330
3331 smp->flags = SMP_F_VOL_TEST;
3332 smp->data.type = SMP_T_SINT;
3333 smp->data.u.sint = 0;
3334
3335 if (!stkctr_entry(stkctr))
3336 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
3337
3338 if (stkctr && stkctr_entry(stkctr)) {
3339 void *ptr1,*ptr2;
3340
3341
3342 /* First, update gpc0_rate if it's tracked. Second, update its
3343 * gpc0 if tracked. Returns gpc0's value otherwise the curr_ctr.
3344 */
3345 ptr1 = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC_RATE, idx);
3346 ptr2 = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC, idx);
3347 if (ptr1 || ptr2) {
3348 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3349
3350 if (ptr1) {
3351 update_freq_ctr_period(&stktable_data_cast(ptr1, std_t_frqp),
3352 stkctr->table->data_arg[STKTABLE_DT_GPC_RATE].u, 1);
3353 smp->data.u.sint = (&stktable_data_cast(ptr1, std_t_frqp))->curr_ctr;
3354 }
3355
3356 if (ptr2)
3357 smp->data.u.sint = ++stktable_data_cast(ptr2, std_t_uint);
3358
3359 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3360
3361 /* If data was modified, we need to touch to re-schedule sync */
3362 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
3363 }
3364 else if (stkctr == &tmpstkctr)
3365 stktable_release(stkctr->table, stkctr_entry(stkctr));
3366 }
3367 return 1;
3368}
3369
Willy Tarreau7d562212016-11-25 16:10:05 +01003370/* Increment the General Purpose Counter 0 value from the stream's tracked
3371 * frontend counters and return it into temp integer.
3372 * Supports being called as "sc[0-9]_inc_gpc0" or "src_inc_gpc0" only.
3373 */
3374static int
3375smp_fetch_sc_inc_gpc0(const struct arg *args, struct sample *smp, const char *kw, void *private)
3376{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003377 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003378 struct stkctr *stkctr;
Willy Tarreau5b654ad2021-07-06 18:51:12 +02003379 unsigned int period = 0;
Willy Tarreau7d562212016-11-25 16:10:05 +01003380
Emeric Brun819fc6f2017-06-13 19:37:32 +02003381 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003382 if (!stkctr)
3383 return 0;
3384
3385 smp->flags = SMP_F_VOL_TEST;
3386 smp->data.type = SMP_T_SINT;
3387 smp->data.u.sint = 0;
3388
Emeric Brun819fc6f2017-06-13 19:37:32 +02003389 if (!stkctr_entry(stkctr))
3390 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003391
3392 if (stkctr && stkctr_entry(stkctr)) {
3393 void *ptr1,*ptr2;
3394
Emeric Brun819fc6f2017-06-13 19:37:32 +02003395
Willy Tarreau7d562212016-11-25 16:10:05 +01003396 /* First, update gpc0_rate if it's tracked. Second, update its
3397 * gpc0 if tracked. Returns gpc0's value otherwise the curr_ctr.
3398 */
3399 ptr1 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0_RATE);
Emeric Brun726783d2021-06-30 19:06:43 +02003400 if (ptr1) {
3401 period = stkctr->table->data_arg[STKTABLE_DT_GPC0_RATE].u;
3402 }
3403 else {
3404 /* fallback on the gpc array */
3405 ptr1 = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC_RATE, 0);
3406 if (ptr1)
3407 period = stkctr->table->data_arg[STKTABLE_DT_GPC_RATE].u;
3408 }
3409
Willy Tarreau7d562212016-11-25 16:10:05 +01003410 ptr2 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0);
Emeric Brun726783d2021-06-30 19:06:43 +02003411 if (!ptr2) {
3412 /* fallback on the gpc array */
3413 ptr2 = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC, 0);
3414 }
3415
Emeric Brun819fc6f2017-06-13 19:37:32 +02003416 if (ptr1 || ptr2) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003417 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Willy Tarreau7d562212016-11-25 16:10:05 +01003418
Emeric Brun819fc6f2017-06-13 19:37:32 +02003419 if (ptr1) {
Emeric Brun0e3457b2021-06-30 17:18:28 +02003420 update_freq_ctr_period(&stktable_data_cast(ptr1, std_t_frqp),
Emeric Brun726783d2021-06-30 19:06:43 +02003421 period, 1);
Emeric Brun0e3457b2021-06-30 17:18:28 +02003422 smp->data.u.sint = (&stktable_data_cast(ptr1, std_t_frqp))->curr_ctr;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003423 }
3424
3425 if (ptr2)
Emeric Brun0e3457b2021-06-30 17:18:28 +02003426 smp->data.u.sint = ++stktable_data_cast(ptr2, std_t_uint);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003427
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003428 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003429
3430 /* If data was modified, we need to touch to re-schedule sync */
3431 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
3432 }
3433 else if (stkctr == &tmpstkctr)
3434 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003435 }
3436 return 1;
3437}
3438
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003439/* Increment the General Purpose Counter 1 value from the stream's tracked
3440 * frontend counters and return it into temp integer.
3441 * Supports being called as "sc[0-9]_inc_gpc1" or "src_inc_gpc1" only.
3442 */
3443static int
3444smp_fetch_sc_inc_gpc1(const struct arg *args, struct sample *smp, const char *kw, void *private)
3445{
3446 struct stkctr tmpstkctr;
3447 struct stkctr *stkctr;
Willy Tarreau5b654ad2021-07-06 18:51:12 +02003448 unsigned int period = 0;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003449
3450 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
3451 if (!stkctr)
3452 return 0;
3453
3454 smp->flags = SMP_F_VOL_TEST;
3455 smp->data.type = SMP_T_SINT;
3456 smp->data.u.sint = 0;
3457
3458 if (!stkctr_entry(stkctr))
3459 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
3460
3461 if (stkctr && stkctr_entry(stkctr)) {
3462 void *ptr1,*ptr2;
3463
3464
3465 /* First, update gpc1_rate if it's tracked. Second, update its
3466 * gpc1 if tracked. Returns gpc1's value otherwise the curr_ctr.
3467 */
3468 ptr1 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1_RATE);
Emeric Brun726783d2021-06-30 19:06:43 +02003469 if (ptr1) {
3470 period = stkctr->table->data_arg[STKTABLE_DT_GPC1_RATE].u;
3471 }
3472 else {
3473 /* fallback on the gpc array */
3474 ptr1 = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC_RATE, 1);
3475 if (ptr1)
3476 period = stkctr->table->data_arg[STKTABLE_DT_GPC_RATE].u;
3477 }
3478
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003479 ptr2 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1);
Emeric Brun726783d2021-06-30 19:06:43 +02003480 if (!ptr2) {
3481 /* fallback on the gpc array */
3482 ptr2 = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC, 1);
3483 }
3484
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003485 if (ptr1 || ptr2) {
3486 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3487
3488 if (ptr1) {
Emeric Brun0e3457b2021-06-30 17:18:28 +02003489 update_freq_ctr_period(&stktable_data_cast(ptr1, std_t_frqp),
Emeric Brun726783d2021-06-30 19:06:43 +02003490 period, 1);
Emeric Brun0e3457b2021-06-30 17:18:28 +02003491 smp->data.u.sint = (&stktable_data_cast(ptr1, std_t_frqp))->curr_ctr;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003492 }
3493
3494 if (ptr2)
Emeric Brun0e3457b2021-06-30 17:18:28 +02003495 smp->data.u.sint = ++stktable_data_cast(ptr2, std_t_uint);
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003496
3497 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3498
3499 /* If data was modified, we need to touch to re-schedule sync */
3500 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
3501 }
3502 else if (stkctr == &tmpstkctr)
3503 stktable_release(stkctr->table, stkctr_entry(stkctr));
3504 }
3505 return 1;
3506}
3507
Emeric Brun4d7ada82021-06-30 19:04:16 +02003508/* Clear the GPC[args(0)] value from the stream's tracked
3509 * frontend counters and return its previous value into temp integer.
3510 * Supports being called as "sc_clr_gpc(<gpc-idx>,<sc-idx>[,<table>])"
3511 * or "src_clr_gpc(<gpc-idx>[,<table>])" only.
3512 */
3513static int
3514smp_fetch_sc_clr_gpc(const struct arg *args, struct sample *smp, const char *kw, void *private)
3515{
3516 struct stkctr tmpstkctr;
3517 struct stkctr *stkctr;
3518 unsigned int idx;
3519
3520 idx = args[0].data.sint;
3521
3522 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args + 1, kw, &tmpstkctr);
3523 if (!stkctr)
3524 return 0;
3525
3526 smp->flags = SMP_F_VOL_TEST;
3527 smp->data.type = SMP_T_SINT;
3528 smp->data.u.sint = 0;
3529
3530 if (!stkctr_entry(stkctr))
3531 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
3532
3533 if (stkctr && stkctr_entry(stkctr)) {
3534 void *ptr;
3535
3536 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC, idx);
3537 if (!ptr) {
3538 if (stkctr == &tmpstkctr)
3539 stktable_release(stkctr->table, stkctr_entry(stkctr));
3540 return 0; /* parameter not stored */
3541 }
3542
3543 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3544
3545 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
3546 stktable_data_cast(ptr, std_t_uint) = 0;
3547
3548 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3549
3550 /* If data was modified, we need to touch to re-schedule sync */
3551 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
3552 }
3553 return 1;
3554}
3555
Willy Tarreau7d562212016-11-25 16:10:05 +01003556/* Clear the General Purpose Counter 0 value from the stream's tracked
3557 * frontend counters and return its previous value into temp integer.
3558 * Supports being called as "sc[0-9]_clr_gpc0" or "src_clr_gpc0" only.
3559 */
3560static int
3561smp_fetch_sc_clr_gpc0(const struct arg *args, struct sample *smp, const char *kw, void *private)
3562{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003563 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003564 struct stkctr *stkctr;
3565
Emeric Brun819fc6f2017-06-13 19:37:32 +02003566 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003567 if (!stkctr)
3568 return 0;
3569
3570 smp->flags = SMP_F_VOL_TEST;
3571 smp->data.type = SMP_T_SINT;
3572 smp->data.u.sint = 0;
3573
Emeric Brun819fc6f2017-06-13 19:37:32 +02003574 if (!stkctr_entry(stkctr))
3575 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003576
Emeric Brun819fc6f2017-06-13 19:37:32 +02003577 if (stkctr && stkctr_entry(stkctr)) {
3578 void *ptr;
3579
3580 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0);
3581 if (!ptr) {
Emeric Brun726783d2021-06-30 19:06:43 +02003582 /* fallback on the gpc array */
3583 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC, 0);
3584 }
3585
3586 if (!ptr) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003587 if (stkctr == &tmpstkctr)
3588 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003589 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003590 }
3591
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003592 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003593
Emeric Brun0e3457b2021-06-30 17:18:28 +02003594 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
3595 stktable_data_cast(ptr, std_t_uint) = 0;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003596
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003597 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003598
Willy Tarreau7d562212016-11-25 16:10:05 +01003599 /* If data was modified, we need to touch to re-schedule sync */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003600 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
Willy Tarreau7d562212016-11-25 16:10:05 +01003601 }
3602 return 1;
3603}
3604
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003605/* Clear the General Purpose Counter 1 value from the stream's tracked
3606 * frontend counters and return its previous value into temp integer.
3607 * Supports being called as "sc[0-9]_clr_gpc1" or "src_clr_gpc1" only.
3608 */
3609static int
3610smp_fetch_sc_clr_gpc1(const struct arg *args, struct sample *smp, const char *kw, void *private)
3611{
3612 struct stkctr tmpstkctr;
3613 struct stkctr *stkctr;
3614
3615 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
3616 if (!stkctr)
3617 return 0;
3618
3619 smp->flags = SMP_F_VOL_TEST;
3620 smp->data.type = SMP_T_SINT;
3621 smp->data.u.sint = 0;
3622
3623 if (!stkctr_entry(stkctr))
3624 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
3625
3626 if (stkctr && stkctr_entry(stkctr)) {
3627 void *ptr;
3628
3629 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1);
3630 if (!ptr) {
Emeric Brun726783d2021-06-30 19:06:43 +02003631 /* fallback on the gpc array */
3632 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC, 1);
3633 }
3634
3635 if (!ptr) {
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003636 if (stkctr == &tmpstkctr)
3637 stktable_release(stkctr->table, stkctr_entry(stkctr));
3638 return 0; /* parameter not stored */
3639 }
3640
3641 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3642
Emeric Brun0e3457b2021-06-30 17:18:28 +02003643 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
3644 stktable_data_cast(ptr, std_t_uint) = 0;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003645
3646 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3647
3648 /* If data was modified, we need to touch to re-schedule sync */
3649 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
3650 }
3651 return 1;
3652}
3653
Willy Tarreau7d562212016-11-25 16:10:05 +01003654/* set <smp> to the cumulated number of connections from the stream's tracked
3655 * frontend counters. Supports being called as "sc[0-9]_conn_cnt" or
3656 * "src_conn_cnt" only.
3657 */
3658static int
3659smp_fetch_sc_conn_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
3660{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003661 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003662 struct stkctr *stkctr;
3663
Emeric Brun819fc6f2017-06-13 19:37:32 +02003664 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003665 if (!stkctr)
3666 return 0;
3667
3668 smp->flags = SMP_F_VOL_TEST;
3669 smp->data.type = SMP_T_SINT;
3670 smp->data.u.sint = 0;
3671 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003672 void *ptr;
3673
3674 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_CONN_CNT);
3675 if (!ptr) {
3676 if (stkctr == &tmpstkctr)
3677 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003678 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003679 }
3680
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003681 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003682
Emeric Brun0e3457b2021-06-30 17:18:28 +02003683 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003684
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003685 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003686
3687 if (stkctr == &tmpstkctr)
3688 stktable_release(stkctr->table, stkctr_entry(stkctr));
3689
3690
Willy Tarreau7d562212016-11-25 16:10:05 +01003691 }
3692 return 1;
3693}
3694
3695/* set <smp> to the connection rate from the stream's tracked frontend
3696 * counters. Supports being called as "sc[0-9]_conn_rate" or "src_conn_rate"
3697 * only.
3698 */
3699static int
3700smp_fetch_sc_conn_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3701{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003702 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003703 struct stkctr *stkctr;
3704
Emeric Brun819fc6f2017-06-13 19:37:32 +02003705 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003706 if (!stkctr)
3707 return 0;
3708
3709 smp->flags = SMP_F_VOL_TEST;
3710 smp->data.type = SMP_T_SINT;
3711 smp->data.u.sint = 0;
3712 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003713 void *ptr;
3714
3715 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_CONN_RATE);
3716 if (!ptr) {
3717 if (stkctr == &tmpstkctr)
3718 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003719 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003720 }
3721
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003722 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003723
Emeric Brun0e3457b2021-06-30 17:18:28 +02003724 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Willy Tarreau7d562212016-11-25 16:10:05 +01003725 stkctr->table->data_arg[STKTABLE_DT_CONN_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003726
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003727 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003728
3729 if (stkctr == &tmpstkctr)
3730 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003731 }
3732 return 1;
3733}
3734
3735/* set temp integer to the number of connections from the stream's source address
3736 * in the table pointed to by expr, after updating it.
3737 * Accepts exactly 1 argument of type table.
3738 */
3739static int
3740smp_fetch_src_updt_conn_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
3741{
3742 struct connection *conn = objt_conn(smp->sess->origin);
3743 struct stksess *ts;
3744 struct stktable_key *key;
3745 void *ptr;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003746 struct stktable *t;
Willy Tarreau7d562212016-11-25 16:10:05 +01003747
3748 if (!conn)
3749 return 0;
3750
Joseph Herlant5662fa42018-11-15 13:43:28 -08003751 /* Fetch source address in a sample. */
Amaury Denoyellec460c702021-05-12 10:17:47 +02003752 if (!smp_fetch_src || !smp_fetch_src(empty_arg_list, smp, "src", NULL))
Willy Tarreau7d562212016-11-25 16:10:05 +01003753 return 0;
3754
3755 /* Converts into key. */
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003756 key = smp_to_stkey(smp, args->data.t);
Willy Tarreau7d562212016-11-25 16:10:05 +01003757 if (!key)
3758 return 0;
3759
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003760 t = args->data.t;
Willy Tarreau7d562212016-11-25 16:10:05 +01003761
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003762 if ((ts = stktable_get_entry(t, key)) == NULL)
Willy Tarreau7d562212016-11-25 16:10:05 +01003763 /* entry does not exist and could not be created */
3764 return 0;
3765
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003766 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_CONN_CNT);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003767 if (!ptr) {
Willy Tarreau7d562212016-11-25 16:10:05 +01003768 return 0; /* parameter not stored in this table */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003769 }
Willy Tarreau7d562212016-11-25 16:10:05 +01003770
3771 smp->data.type = SMP_T_SINT;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003772
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003773 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003774
Emeric Brun0e3457b2021-06-30 17:18:28 +02003775 smp->data.u.sint = ++stktable_data_cast(ptr, std_t_uint);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003776
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003777 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003778
Willy Tarreau7d562212016-11-25 16:10:05 +01003779 smp->flags = SMP_F_VOL_TEST;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003780
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003781 stktable_touch_local(t, ts, 1);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003782
3783 /* Touch was previously performed by stktable_update_key */
Willy Tarreau7d562212016-11-25 16:10:05 +01003784 return 1;
3785}
3786
3787/* set <smp> to the number of concurrent connections from the stream's tracked
3788 * frontend counters. Supports being called as "sc[0-9]_conn_cur" or
3789 * "src_conn_cur" only.
3790 */
3791static int
3792smp_fetch_sc_conn_cur(const struct arg *args, struct sample *smp, const char *kw, void *private)
3793{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003794 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003795 struct stkctr *stkctr;
3796
Emeric Brun819fc6f2017-06-13 19:37:32 +02003797 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003798 if (!stkctr)
3799 return 0;
3800
3801 smp->flags = SMP_F_VOL_TEST;
3802 smp->data.type = SMP_T_SINT;
3803 smp->data.u.sint = 0;
3804 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003805 void *ptr;
3806
3807 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_CONN_CUR);
3808 if (!ptr) {
3809 if (stkctr == &tmpstkctr)
3810 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003811 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003812 }
3813
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003814 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003815
Emeric Brun0e3457b2021-06-30 17:18:28 +02003816 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003817
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003818 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003819
3820 if (stkctr == &tmpstkctr)
3821 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003822 }
3823 return 1;
3824}
3825
3826/* set <smp> to the cumulated number of streams from the stream's tracked
3827 * frontend counters. Supports being called as "sc[0-9]_sess_cnt" or
3828 * "src_sess_cnt" only.
3829 */
3830static int
3831smp_fetch_sc_sess_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
3832{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003833 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003834 struct stkctr *stkctr;
3835
Emeric Brun819fc6f2017-06-13 19:37:32 +02003836 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003837 if (!stkctr)
3838 return 0;
3839
3840 smp->flags = SMP_F_VOL_TEST;
3841 smp->data.type = SMP_T_SINT;
3842 smp->data.u.sint = 0;
3843 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003844 void *ptr;
3845
3846 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_SESS_CNT);
3847 if (!ptr) {
3848 if (stkctr == &tmpstkctr)
3849 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003850 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003851 }
3852
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003853 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003854
Emeric Brun0e3457b2021-06-30 17:18:28 +02003855 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003856
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003857 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003858
3859 if (stkctr == &tmpstkctr)
3860 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003861 }
3862 return 1;
3863}
3864
3865/* set <smp> to the stream rate from the stream's tracked frontend counters.
3866 * Supports being called as "sc[0-9]_sess_rate" or "src_sess_rate" only.
3867 */
3868static int
3869smp_fetch_sc_sess_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3870{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003871 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003872 struct stkctr *stkctr;
3873
Emeric Brun819fc6f2017-06-13 19:37:32 +02003874 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003875 if (!stkctr)
3876 return 0;
3877
3878 smp->flags = SMP_F_VOL_TEST;
3879 smp->data.type = SMP_T_SINT;
3880 smp->data.u.sint = 0;
3881 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003882 void *ptr;
3883
3884 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_SESS_RATE);
3885 if (!ptr) {
3886 if (stkctr == &tmpstkctr)
3887 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003888 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003889 }
3890
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003891 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003892
Emeric Brun0e3457b2021-06-30 17:18:28 +02003893 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Willy Tarreau7d562212016-11-25 16:10:05 +01003894 stkctr->table->data_arg[STKTABLE_DT_SESS_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003895
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003896 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003897
3898 if (stkctr == &tmpstkctr)
3899 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003900 }
3901 return 1;
3902}
3903
3904/* set <smp> to the cumulated number of HTTP requests from the stream's tracked
3905 * frontend counters. Supports being called as "sc[0-9]_http_req_cnt" or
3906 * "src_http_req_cnt" only.
3907 */
3908static int
3909smp_fetch_sc_http_req_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
3910{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003911 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003912 struct stkctr *stkctr;
3913
Emeric Brun819fc6f2017-06-13 19:37:32 +02003914 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003915 if (!stkctr)
3916 return 0;
3917
3918 smp->flags = SMP_F_VOL_TEST;
3919 smp->data.type = SMP_T_SINT;
3920 smp->data.u.sint = 0;
3921 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003922 void *ptr;
3923
3924 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_REQ_CNT);
3925 if (!ptr) {
3926 if (stkctr == &tmpstkctr)
3927 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003928 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003929 }
3930
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003931 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003932
Emeric Brun0e3457b2021-06-30 17:18:28 +02003933 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003934
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003935 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003936
3937 if (stkctr == &tmpstkctr)
3938 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003939 }
3940 return 1;
3941}
3942
3943/* set <smp> to the HTTP request rate from the stream's tracked frontend
3944 * counters. Supports being called as "sc[0-9]_http_req_rate" or
3945 * "src_http_req_rate" only.
3946 */
3947static int
3948smp_fetch_sc_http_req_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3949{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003950 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003951 struct stkctr *stkctr;
3952
Emeric Brun819fc6f2017-06-13 19:37:32 +02003953 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003954 if (!stkctr)
3955 return 0;
3956
3957 smp->flags = SMP_F_VOL_TEST;
3958 smp->data.type = SMP_T_SINT;
3959 smp->data.u.sint = 0;
3960 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003961 void *ptr;
3962
3963 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_REQ_RATE);
3964 if (!ptr) {
3965 if (stkctr == &tmpstkctr)
3966 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003967 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003968 }
3969
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003970 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003971
Emeric Brun0e3457b2021-06-30 17:18:28 +02003972 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Willy Tarreau7d562212016-11-25 16:10:05 +01003973 stkctr->table->data_arg[STKTABLE_DT_HTTP_REQ_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003974
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003975 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003976
3977 if (stkctr == &tmpstkctr)
3978 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003979 }
3980 return 1;
3981}
3982
3983/* set <smp> to the cumulated number of HTTP requests errors from the stream's
3984 * tracked frontend counters. Supports being called as "sc[0-9]_http_err_cnt" or
3985 * "src_http_err_cnt" only.
3986 */
3987static int
3988smp_fetch_sc_http_err_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
3989{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003990 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003991 struct stkctr *stkctr;
3992
Emeric Brun819fc6f2017-06-13 19:37:32 +02003993 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003994 if (!stkctr)
3995 return 0;
3996
3997 smp->flags = SMP_F_VOL_TEST;
3998 smp->data.type = SMP_T_SINT;
3999 smp->data.u.sint = 0;
4000 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02004001 void *ptr;
4002
4003 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_ERR_CNT);
4004 if (!ptr) {
4005 if (stkctr == &tmpstkctr)
4006 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004007 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02004008 }
4009
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004010 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004011
Emeric Brun0e3457b2021-06-30 17:18:28 +02004012 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004013
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004014 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004015
4016 if (stkctr == &tmpstkctr)
4017 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004018 }
4019 return 1;
4020}
4021
4022/* set <smp> to the HTTP request error rate from the stream's tracked frontend
4023 * counters. Supports being called as "sc[0-9]_http_err_rate" or
4024 * "src_http_err_rate" only.
4025 */
4026static int
4027smp_fetch_sc_http_err_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
4028{
Emeric Brun819fc6f2017-06-13 19:37:32 +02004029 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01004030 struct stkctr *stkctr;
4031
Emeric Brun819fc6f2017-06-13 19:37:32 +02004032 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01004033 if (!stkctr)
4034 return 0;
4035
4036 smp->flags = SMP_F_VOL_TEST;
4037 smp->data.type = SMP_T_SINT;
4038 smp->data.u.sint = 0;
4039 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02004040 void *ptr;
4041
4042 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_ERR_RATE);
4043 if (!ptr) {
4044 if (stkctr == &tmpstkctr)
4045 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004046 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02004047 }
4048
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004049 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004050
Emeric Brun0e3457b2021-06-30 17:18:28 +02004051 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Willy Tarreau7d562212016-11-25 16:10:05 +01004052 stkctr->table->data_arg[STKTABLE_DT_HTTP_ERR_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004053
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004054 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004055
4056 if (stkctr == &tmpstkctr)
4057 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004058 }
4059 return 1;
4060}
4061
Willy Tarreau826f3ab2021-02-10 12:07:15 +01004062/* set <smp> to the cumulated number of HTTP response failures from the stream's
4063 * tracked frontend counters. Supports being called as "sc[0-9]_http_fail_cnt" or
4064 * "src_http_fail_cnt" only.
4065 */
4066static int
4067smp_fetch_sc_http_fail_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
4068{
4069 struct stkctr tmpstkctr;
4070 struct stkctr *stkctr;
4071
4072 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
4073 if (!stkctr)
4074 return 0;
4075
4076 smp->flags = SMP_F_VOL_TEST;
4077 smp->data.type = SMP_T_SINT;
4078 smp->data.u.sint = 0;
4079 if (stkctr_entry(stkctr) != NULL) {
4080 void *ptr;
4081
4082 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_FAIL_CNT);
4083 if (!ptr) {
4084 if (stkctr == &tmpstkctr)
4085 stktable_release(stkctr->table, stkctr_entry(stkctr));
4086 return 0; /* parameter not stored */
4087 }
4088
4089 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
4090
Emeric Brun0e3457b2021-06-30 17:18:28 +02004091 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Willy Tarreau826f3ab2021-02-10 12:07:15 +01004092
4093 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
4094
4095 if (stkctr == &tmpstkctr)
4096 stktable_release(stkctr->table, stkctr_entry(stkctr));
4097 }
4098 return 1;
4099}
4100
4101/* set <smp> to the HTTP response failure rate from the stream's tracked frontend
4102 * counters. Supports being called as "sc[0-9]_http_fail_rate" or
4103 * "src_http_fail_rate" only.
4104 */
4105static int
4106smp_fetch_sc_http_fail_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
4107{
4108 struct stkctr tmpstkctr;
4109 struct stkctr *stkctr;
4110
4111 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
4112 if (!stkctr)
4113 return 0;
4114
4115 smp->flags = SMP_F_VOL_TEST;
4116 smp->data.type = SMP_T_SINT;
4117 smp->data.u.sint = 0;
4118 if (stkctr_entry(stkctr) != NULL) {
4119 void *ptr;
4120
4121 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_FAIL_RATE);
4122 if (!ptr) {
4123 if (stkctr == &tmpstkctr)
4124 stktable_release(stkctr->table, stkctr_entry(stkctr));
4125 return 0; /* parameter not stored */
4126 }
4127
4128 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
4129
Emeric Brun0e3457b2021-06-30 17:18:28 +02004130 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Willy Tarreau826f3ab2021-02-10 12:07:15 +01004131 stkctr->table->data_arg[STKTABLE_DT_HTTP_FAIL_RATE].u);
4132
4133 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
4134
4135 if (stkctr == &tmpstkctr)
4136 stktable_release(stkctr->table, stkctr_entry(stkctr));
4137 }
4138 return 1;
4139}
4140
Willy Tarreau7d562212016-11-25 16:10:05 +01004141/* set <smp> to the number of kbytes received from clients, as found in the
4142 * stream's tracked frontend counters. Supports being called as
4143 * "sc[0-9]_kbytes_in" or "src_kbytes_in" only.
4144 */
4145static int
4146smp_fetch_sc_kbytes_in(const struct arg *args, struct sample *smp, const char *kw, void *private)
4147{
Emeric Brun819fc6f2017-06-13 19:37:32 +02004148 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01004149 struct stkctr *stkctr;
4150
Emeric Brun819fc6f2017-06-13 19:37:32 +02004151 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01004152 if (!stkctr)
4153 return 0;
4154
4155 smp->flags = SMP_F_VOL_TEST;
4156 smp->data.type = SMP_T_SINT;
4157 smp->data.u.sint = 0;
4158 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02004159 void *ptr;
4160
4161 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_IN_CNT);
4162 if (!ptr) {
4163 if (stkctr == &tmpstkctr)
4164 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004165 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02004166 }
4167
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004168 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004169
Emeric Brun0e3457b2021-06-30 17:18:28 +02004170 smp->data.u.sint = stktable_data_cast(ptr, std_t_ull) >> 10;
Emeric Brun819fc6f2017-06-13 19:37:32 +02004171
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004172 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004173
4174 if (stkctr == &tmpstkctr)
4175 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004176 }
4177 return 1;
4178}
4179
4180/* set <smp> to the data rate received from clients in bytes/s, as found
4181 * in the stream's tracked frontend counters. Supports being called as
4182 * "sc[0-9]_bytes_in_rate" or "src_bytes_in_rate" only.
4183 */
4184static int
4185smp_fetch_sc_bytes_in_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
4186{
Emeric Brun819fc6f2017-06-13 19:37:32 +02004187 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01004188 struct stkctr *stkctr;
4189
Emeric Brun819fc6f2017-06-13 19:37:32 +02004190 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01004191 if (!stkctr)
4192 return 0;
4193
4194 smp->flags = SMP_F_VOL_TEST;
4195 smp->data.type = SMP_T_SINT;
4196 smp->data.u.sint = 0;
4197 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02004198 void *ptr;
4199
4200 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_IN_RATE);
4201 if (!ptr) {
4202 if (stkctr == &tmpstkctr)
4203 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004204 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02004205 }
4206
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004207 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004208
Emeric Brun0e3457b2021-06-30 17:18:28 +02004209 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Willy Tarreau7d562212016-11-25 16:10:05 +01004210 stkctr->table->data_arg[STKTABLE_DT_BYTES_IN_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004211
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004212 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004213
4214 if (stkctr == &tmpstkctr)
4215 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004216 }
4217 return 1;
4218}
4219
4220/* set <smp> to the number of kbytes sent to clients, as found in the
4221 * stream's tracked frontend counters. Supports being called as
4222 * "sc[0-9]_kbytes_out" or "src_kbytes_out" only.
4223 */
4224static int
4225smp_fetch_sc_kbytes_out(const struct arg *args, struct sample *smp, const char *kw, void *private)
4226{
Emeric Brun819fc6f2017-06-13 19:37:32 +02004227 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01004228 struct stkctr *stkctr;
4229
Emeric Brun819fc6f2017-06-13 19:37:32 +02004230 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01004231 if (!stkctr)
4232 return 0;
4233
4234 smp->flags = SMP_F_VOL_TEST;
4235 smp->data.type = SMP_T_SINT;
4236 smp->data.u.sint = 0;
4237 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02004238 void *ptr;
4239
4240 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_OUT_CNT);
4241 if (!ptr) {
4242 if (stkctr == &tmpstkctr)
4243 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004244 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02004245 }
4246
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004247 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004248
Emeric Brun0e3457b2021-06-30 17:18:28 +02004249 smp->data.u.sint = stktable_data_cast(ptr, std_t_ull) >> 10;
Emeric Brun819fc6f2017-06-13 19:37:32 +02004250
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004251 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004252
4253 if (stkctr == &tmpstkctr)
4254 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004255 }
4256 return 1;
4257}
4258
4259/* set <smp> to the data rate sent to clients in bytes/s, as found in the
4260 * stream's tracked frontend counters. Supports being called as
4261 * "sc[0-9]_bytes_out_rate" or "src_bytes_out_rate" only.
4262 */
4263static int
4264smp_fetch_sc_bytes_out_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
4265{
Emeric Brun819fc6f2017-06-13 19:37:32 +02004266 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01004267 struct stkctr *stkctr;
4268
Emeric Brun819fc6f2017-06-13 19:37:32 +02004269 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01004270 if (!stkctr)
4271 return 0;
4272
4273 smp->flags = SMP_F_VOL_TEST;
4274 smp->data.type = SMP_T_SINT;
4275 smp->data.u.sint = 0;
4276 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02004277 void *ptr;
4278
4279 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_OUT_RATE);
4280 if (!ptr) {
4281 if (stkctr == &tmpstkctr)
4282 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004283 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02004284 }
4285
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004286 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004287
Emeric Brun0e3457b2021-06-30 17:18:28 +02004288 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Willy Tarreau7d562212016-11-25 16:10:05 +01004289 stkctr->table->data_arg[STKTABLE_DT_BYTES_OUT_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004290
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004291 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004292
4293 if (stkctr == &tmpstkctr)
4294 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004295 }
4296 return 1;
4297}
4298
4299/* set <smp> to the number of active trackers on the SC entry in the stream's
4300 * tracked frontend counters. Supports being called as "sc[0-9]_trackers" only.
4301 */
4302static int
4303smp_fetch_sc_trackers(const struct arg *args, struct sample *smp, const char *kw, void *private)
4304{
Emeric Brun819fc6f2017-06-13 19:37:32 +02004305 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01004306 struct stkctr *stkctr;
4307
Emeric Brun819fc6f2017-06-13 19:37:32 +02004308 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01004309 if (!stkctr)
4310 return 0;
4311
4312 smp->flags = SMP_F_VOL_TEST;
4313 smp->data.type = SMP_T_SINT;
Emeric Brun819fc6f2017-06-13 19:37:32 +02004314 if (stkctr == &tmpstkctr) {
4315 smp->data.u.sint = stkctr_entry(stkctr) ? (stkctr_entry(stkctr)->ref_cnt-1) : 0;
4316 stktable_release(stkctr->table, stkctr_entry(stkctr));
4317 }
4318 else {
4319 smp->data.u.sint = stkctr_entry(stkctr) ? stkctr_entry(stkctr)->ref_cnt : 0;
4320 }
4321
Willy Tarreau7d562212016-11-25 16:10:05 +01004322 return 1;
4323}
4324
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004325
4326/* The functions below are used to manipulate table contents from the CLI.
4327 * There are 3 main actions, "clear", "set" and "show". The code is shared
4328 * between all actions, and the action is encoded in the void *private in
4329 * the appctx as well as in the keyword registration, among one of the
4330 * following values.
4331 */
4332
4333enum {
4334 STK_CLI_ACT_CLR,
4335 STK_CLI_ACT_SET,
4336 STK_CLI_ACT_SHOW,
4337};
4338
Willy Tarreau4596fe22022-05-17 19:07:51 +02004339/* Dump the status of a table to a stream connector's
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004340 * read buffer. It returns 0 if the output buffer is full
4341 * and needs to be called again, otherwise non-zero.
4342 */
Willy Tarreau83061a82018-07-13 11:56:34 +02004343static int table_dump_head_to_buffer(struct buffer *msg,
Willy Tarreaud0a06d52022-05-18 15:07:19 +02004344 struct appctx *appctx,
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004345 struct stktable *t, struct stktable *target)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004346{
Willy Tarreauc12b3212022-05-27 11:08:15 +02004347 struct stream *s = __sc_strm(appctx_sc(appctx));
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004348
4349 chunk_appendf(msg, "# table: %s, type: %s, size:%d, used:%d\n",
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004350 t->id, stktable_types[t->type].kw, t->size, t->current);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004351
4352 /* any other information should be dumped here */
4353
William Lallemand07a62f72017-05-24 00:57:40 +02004354 if (target && (strm_li(s)->bind_conf->level & ACCESS_LVL_MASK) < ACCESS_LVL_OPER)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004355 chunk_appendf(msg, "# contents not dumped due to insufficient privileges\n");
4356
Willy Tarreaud0a06d52022-05-18 15:07:19 +02004357 if (applet_putchk(appctx, msg) == -1)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004358 return 0;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004359
4360 return 1;
4361}
4362
Willy Tarreau4596fe22022-05-17 19:07:51 +02004363/* Dump a table entry to a stream connector's
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004364 * read buffer. It returns 0 if the output buffer is full
4365 * and needs to be called again, otherwise non-zero.
4366 */
Willy Tarreau83061a82018-07-13 11:56:34 +02004367static int table_dump_entry_to_buffer(struct buffer *msg,
Willy Tarreaud0a06d52022-05-18 15:07:19 +02004368 struct appctx *appctx,
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004369 struct stktable *t, struct stksess *entry)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004370{
4371 int dt;
4372
4373 chunk_appendf(msg, "%p:", entry);
4374
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004375 if (t->type == SMP_T_IPV4) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004376 char addr[INET_ADDRSTRLEN];
4377 inet_ntop(AF_INET, (const void *)&entry->key.key, addr, sizeof(addr));
4378 chunk_appendf(msg, " key=%s", addr);
4379 }
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004380 else if (t->type == SMP_T_IPV6) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004381 char addr[INET6_ADDRSTRLEN];
4382 inet_ntop(AF_INET6, (const void *)&entry->key.key, addr, sizeof(addr));
4383 chunk_appendf(msg, " key=%s", addr);
4384 }
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004385 else if (t->type == SMP_T_SINT) {
Willy Tarreau6cde5d82020-02-25 09:41:22 +01004386 chunk_appendf(msg, " key=%u", read_u32(entry->key.key));
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004387 }
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004388 else if (t->type == SMP_T_STR) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004389 chunk_appendf(msg, " key=");
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004390 dump_text(msg, (const char *)entry->key.key, t->key_size);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004391 }
4392 else {
4393 chunk_appendf(msg, " key=");
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004394 dump_binary(msg, (const char *)entry->key.key, t->key_size);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004395 }
4396
4397 chunk_appendf(msg, " use=%d exp=%d", entry->ref_cnt - 1, tick_remain(now_ms, entry->expire));
4398
4399 for (dt = 0; dt < STKTABLE_DATA_TYPES; dt++) {
4400 void *ptr;
4401
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004402 if (t->data_ofs[dt] == 0)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004403 continue;
Emeric Brunc64a2a32021-06-30 18:01:02 +02004404 if (stktable_data_types[dt].is_array) {
4405 char tmp[16] = {};
4406 const char *name_pfx = stktable_data_types[dt].name;
4407 const char *name_sfx = NULL;
4408 unsigned int idx = 0;
4409 int i = 0;
4410
4411 /* split name to show index before first _ of the name
4412 * for example: 'gpc3_rate' if array name is 'gpc_rate'.
4413 */
4414 for (i = 0 ; i < (sizeof(tmp) - 1); i++) {
4415 if (!name_pfx[i])
4416 break;
4417 if (name_pfx[i] == '_') {
4418 name_pfx = &tmp[0];
4419 name_sfx = &stktable_data_types[dt].name[i];
4420 break;
4421 }
4422 tmp[i] = name_pfx[i];
4423 }
4424
4425 ptr = stktable_data_ptr_idx(t, entry, dt, idx);
4426 while (ptr) {
4427 if (stktable_data_types[dt].arg_type == ARG_T_DELAY)
4428 chunk_appendf(msg, " %s%u%s(%u)=", name_pfx, idx, name_sfx ? name_sfx : "", t->data_arg[dt].u);
4429 else
4430 chunk_appendf(msg, " %s%u%s=", name_pfx, idx, name_sfx ? name_sfx : "");
4431 switch (stktable_data_types[dt].std_type) {
4432 case STD_T_SINT:
4433 chunk_appendf(msg, "%d", stktable_data_cast(ptr, std_t_sint));
4434 break;
4435 case STD_T_UINT:
4436 chunk_appendf(msg, "%u", stktable_data_cast(ptr, std_t_uint));
4437 break;
4438 case STD_T_ULL:
4439 chunk_appendf(msg, "%llu", stktable_data_cast(ptr, std_t_ull));
4440 break;
4441 case STD_T_FRQP:
4442 chunk_appendf(msg, "%u",
4443 read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
4444 t->data_arg[dt].u));
4445 break;
4446 }
4447 ptr = stktable_data_ptr_idx(t, entry, dt, ++idx);
4448 }
4449 continue;
4450 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004451 if (stktable_data_types[dt].arg_type == ARG_T_DELAY)
Emeric Brun01928ae2021-06-30 16:24:04 +02004452 chunk_appendf(msg, " %s(%u)=", stktable_data_types[dt].name, t->data_arg[dt].u);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004453 else
4454 chunk_appendf(msg, " %s=", stktable_data_types[dt].name);
4455
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004456 ptr = stktable_data_ptr(t, entry, dt);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004457 switch (stktable_data_types[dt].std_type) {
4458 case STD_T_SINT:
4459 chunk_appendf(msg, "%d", stktable_data_cast(ptr, std_t_sint));
4460 break;
4461 case STD_T_UINT:
4462 chunk_appendf(msg, "%u", stktable_data_cast(ptr, std_t_uint));
4463 break;
4464 case STD_T_ULL:
Emeric Brun01928ae2021-06-30 16:24:04 +02004465 chunk_appendf(msg, "%llu", stktable_data_cast(ptr, std_t_ull));
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004466 break;
4467 case STD_T_FRQP:
Emeric Brun01928ae2021-06-30 16:24:04 +02004468 chunk_appendf(msg, "%u",
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004469 read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004470 t->data_arg[dt].u));
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004471 break;
Frédéric Lécaille16b4f542019-05-23 12:15:04 +02004472 case STD_T_DICT: {
4473 struct dict_entry *de;
4474 de = stktable_data_cast(ptr, std_t_dict);
4475 chunk_appendf(msg, "%s", de ? (char *)de->value.key : "-");
4476 break;
4477 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004478 }
4479 }
4480 chunk_appendf(msg, "\n");
4481
Willy Tarreaud0a06d52022-05-18 15:07:19 +02004482 if (applet_putchk(appctx, msg) == -1)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004483 return 0;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004484
4485 return 1;
4486}
4487
Willy Tarreau3c69e082022-05-03 11:35:07 +02004488/* appctx context used by the "show table" command */
4489struct show_table_ctx {
4490 void *target; /* table we want to dump, or NULL for all */
4491 struct stktable *t; /* table being currently dumped (first if NULL) */
4492 struct stksess *entry; /* last entry we were trying to dump (or first if NULL) */
4493 long long value[STKTABLE_FILTER_LEN]; /* value to compare against */
4494 signed char data_type[STKTABLE_FILTER_LEN]; /* type of data to compare, or -1 if none */
4495 signed char data_op[STKTABLE_FILTER_LEN]; /* operator (STD_OP_*) when data_type set */
Willy Tarreau7849d4c2022-05-03 11:45:02 +02004496 enum {
Willy Tarreau0f154ed2022-05-03 12:02:36 +02004497 STATE_NEXT = 0, /* px points to next table, entry=NULL */
Willy Tarreau7849d4c2022-05-03 11:45:02 +02004498 STATE_DUMP, /* px points to curr table, entry is valid, refcount held */
4499 STATE_DONE, /* done dumping */
4500 } state;
Willy Tarreau3c69e082022-05-03 11:35:07 +02004501 char action; /* action on the table : one of STK_CLI_ACT_* */
4502};
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004503
4504/* Processes a single table entry matching a specific key passed in argument.
4505 * returns 0 if wants to be called again, 1 if has ended processing.
4506 */
4507static int table_process_entry_per_key(struct appctx *appctx, char **args)
4508{
Willy Tarreau3c69e082022-05-03 11:35:07 +02004509 struct show_table_ctx *ctx = appctx->svcctx;
4510 struct stktable *t = ctx->target;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004511 struct stksess *ts;
4512 uint32_t uint32_key;
4513 unsigned char ip6_key[sizeof(struct in6_addr)];
4514 long long value;
4515 int data_type;
4516 int cur_arg;
4517 void *ptr;
Willy Tarreaufa1258f2021-04-10 23:00:53 +02004518 struct freq_ctr *frqp;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004519
Willy Tarreau9d008692019-08-09 11:21:01 +02004520 if (!*args[4])
4521 return cli_err(appctx, "Key value expected\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004522
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004523 switch (t->type) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004524 case SMP_T_IPV4:
4525 uint32_key = htonl(inetaddr_host(args[4]));
Christopher Fauletca20d022017-08-29 15:30:31 +02004526 static_table_key.key = &uint32_key;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004527 break;
4528 case SMP_T_IPV6:
Christopher Fauletb7c962b2021-11-15 09:17:25 +01004529 if (inet_pton(AF_INET6, args[4], ip6_key) <= 0)
4530 return cli_err(appctx, "Invalid key\n");
Christopher Fauletca20d022017-08-29 15:30:31 +02004531 static_table_key.key = &ip6_key;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004532 break;
4533 case SMP_T_SINT:
4534 {
4535 char *endptr;
4536 unsigned long val;
4537 errno = 0;
4538 val = strtoul(args[4], &endptr, 10);
4539 if ((errno == ERANGE && val == ULONG_MAX) ||
4540 (errno != 0 && val == 0) || endptr == args[4] ||
Willy Tarreau9d008692019-08-09 11:21:01 +02004541 val > 0xffffffff)
4542 return cli_err(appctx, "Invalid key\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004543 uint32_key = (uint32_t) val;
Christopher Fauletca20d022017-08-29 15:30:31 +02004544 static_table_key.key = &uint32_key;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004545 break;
4546 }
4547 break;
4548 case SMP_T_STR:
Christopher Fauletca20d022017-08-29 15:30:31 +02004549 static_table_key.key = args[4];
4550 static_table_key.key_len = strlen(args[4]);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004551 break;
4552 default:
Willy Tarreau3c69e082022-05-03 11:35:07 +02004553 switch (ctx->action) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004554 case STK_CLI_ACT_SHOW:
Willy Tarreau9d008692019-08-09 11:21:01 +02004555 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 +01004556 case STK_CLI_ACT_CLR:
Willy Tarreau9d008692019-08-09 11:21:01 +02004557 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 +01004558 case STK_CLI_ACT_SET:
Willy Tarreau9d008692019-08-09 11:21:01 +02004559 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 +01004560 default:
Willy Tarreau9d008692019-08-09 11:21:01 +02004561 return cli_err(appctx, "Unknown action\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004562 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004563 }
4564
4565 /* check permissions */
4566 if (!cli_has_level(appctx, ACCESS_LVL_OPER))
4567 return 1;
4568
Willy Tarreau3c69e082022-05-03 11:35:07 +02004569 switch (ctx->action) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004570 case STK_CLI_ACT_SHOW:
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004571 ts = stktable_lookup_key(t, &static_table_key);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004572 if (!ts)
4573 return 1;
4574 chunk_reset(&trash);
Willy Tarreaud0a06d52022-05-18 15:07:19 +02004575 if (!table_dump_head_to_buffer(&trash, appctx, t, t)) {
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004576 stktable_release(t, ts);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004577 return 0;
Emeric Brun819fc6f2017-06-13 19:37:32 +02004578 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004579 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &ts->lock);
Willy Tarreaud0a06d52022-05-18 15:07:19 +02004580 if (!table_dump_entry_to_buffer(&trash, appctx, t, ts)) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004581 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004582 stktable_release(t, ts);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004583 return 0;
Emeric Brun819fc6f2017-06-13 19:37:32 +02004584 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004585 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004586 stktable_release(t, ts);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004587 break;
4588
4589 case STK_CLI_ACT_CLR:
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004590 ts = stktable_lookup_key(t, &static_table_key);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004591 if (!ts)
4592 return 1;
Emeric Brun819fc6f2017-06-13 19:37:32 +02004593
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004594 if (!stksess_kill(t, ts, 1)) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004595 /* don't delete an entry which is currently referenced */
Willy Tarreau9d008692019-08-09 11:21:01 +02004596 return cli_err(appctx, "Entry currently in use, cannot remove\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004597 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004598 break;
4599
4600 case STK_CLI_ACT_SET:
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004601 ts = stktable_get_entry(t, &static_table_key);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004602 if (!ts) {
4603 /* don't delete an entry which is currently referenced */
Willy Tarreau9d008692019-08-09 11:21:01 +02004604 return cli_err(appctx, "Unable to allocate a new entry\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004605 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004606 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004607 for (cur_arg = 5; *args[cur_arg]; cur_arg += 2) {
4608 if (strncmp(args[cur_arg], "data.", 5) != 0) {
Willy Tarreau9d008692019-08-09 11:21:01 +02004609 cli_err(appctx, "\"data.<type>\" followed by a value expected\n");
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004610 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004611 stktable_touch_local(t, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004612 return 1;
4613 }
4614
4615 data_type = stktable_get_data_type(args[cur_arg] + 5);
4616 if (data_type < 0) {
Willy Tarreau9d008692019-08-09 11:21:01 +02004617 cli_err(appctx, "Unknown data type\n");
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004618 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004619 stktable_touch_local(t, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004620 return 1;
4621 }
4622
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004623 if (!t->data_ofs[data_type]) {
Willy Tarreau9d008692019-08-09 11:21:01 +02004624 cli_err(appctx, "Data type not stored in this table\n");
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004625 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004626 stktable_touch_local(t, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004627 return 1;
4628 }
4629
4630 if (!*args[cur_arg+1] || strl2llrc(args[cur_arg+1], strlen(args[cur_arg+1]), &value) != 0) {
Willy Tarreau9d008692019-08-09 11:21:01 +02004631 cli_err(appctx, "Require a valid integer value to store\n");
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004632 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004633 stktable_touch_local(t, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004634 return 1;
4635 }
4636
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004637 ptr = stktable_data_ptr(t, ts, data_type);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004638
4639 switch (stktable_data_types[data_type].std_type) {
4640 case STD_T_SINT:
4641 stktable_data_cast(ptr, std_t_sint) = value;
4642 break;
4643 case STD_T_UINT:
4644 stktable_data_cast(ptr, std_t_uint) = value;
4645 break;
4646 case STD_T_ULL:
4647 stktable_data_cast(ptr, std_t_ull) = value;
4648 break;
4649 case STD_T_FRQP:
4650 /* We set both the current and previous values. That way
4651 * the reported frequency is stable during all the period
4652 * then slowly fades out. This allows external tools to
4653 * push measures without having to update them too often.
4654 */
4655 frqp = &stktable_data_cast(ptr, std_t_frqp);
Willy Tarreaufa1258f2021-04-10 23:00:53 +02004656 /* First bit is reserved for the freq_ctr lock
Emeric Brunf2fc1fd2017-11-02 17:32:43 +01004657 Note: here we're still protected by the stksess lock
Willy Tarreaufa1258f2021-04-10 23:00:53 +02004658 so we don't need to update the update the freq_ctr
Emeric Brunf2fc1fd2017-11-02 17:32:43 +01004659 using its internal lock */
4660 frqp->curr_tick = now_ms & ~0x1;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004661 frqp->prev_ctr = 0;
4662 frqp->curr_ctr = value;
4663 break;
4664 }
4665 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004666 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004667 stktable_touch_local(t, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004668 break;
4669
4670 default:
Willy Tarreau9d008692019-08-09 11:21:01 +02004671 return cli_err(appctx, "Unknown action\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004672 }
4673 return 1;
4674}
4675
4676/* Prepares the appctx fields with the data-based filters from the command line.
4677 * Returns 0 if the dump can proceed, 1 if has ended processing.
4678 */
4679static int table_prepare_data_request(struct appctx *appctx, char **args)
4680{
Willy Tarreau3c69e082022-05-03 11:35:07 +02004681 struct show_table_ctx *ctx = appctx->svcctx;
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004682 int i;
Adis Nezirovicd0142e72020-01-22 16:50:27 +01004683 char *err = NULL;
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004684
Willy Tarreau3c69e082022-05-03 11:35:07 +02004685 if (ctx->action != STK_CLI_ACT_SHOW && ctx->action != STK_CLI_ACT_CLR)
Willy Tarreau9d008692019-08-09 11:21:01 +02004686 return cli_err(appctx, "content-based lookup is only supported with the \"show\" and \"clear\" actions\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004687
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004688 for (i = 0; i < STKTABLE_FILTER_LEN; i++) {
4689 if (i > 0 && !*args[3+3*i]) // number of filter entries can be less than STKTABLE_FILTER_LEN
4690 break;
4691 /* condition on stored data value */
Willy Tarreau3c69e082022-05-03 11:35:07 +02004692 ctx->data_type[i] = stktable_get_data_type(args[3+3*i] + 5);
4693 if (ctx->data_type[i] < 0)
Adis Nezirovicd0142e72020-01-22 16:50:27 +01004694 return cli_dynerr(appctx, memprintf(&err, "Filter entry #%i: Unknown data type\n", i + 1));
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004695
Willy Tarreau3c69e082022-05-03 11:35:07 +02004696 if (!((struct stktable *)ctx->target)->data_ofs[ctx->data_type[i]])
Adis Nezirovicd0142e72020-01-22 16:50:27 +01004697 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 +01004698
Willy Tarreau3c69e082022-05-03 11:35:07 +02004699 ctx->data_op[i] = get_std_op(args[4+3*i]);
4700 if (ctx->data_op[i] < 0)
Adis Nezirovicd0142e72020-01-22 16:50:27 +01004701 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 +01004702
Willy Tarreau3c69e082022-05-03 11:35:07 +02004703 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 +01004704 return cli_dynerr(appctx, memprintf(&err, "Filter entry #%i: Require a valid integer value to compare against\n", i + 1));
4705 }
4706
4707 if (*args[3+3*i]) {
4708 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 +01004709 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004710
4711 /* OK we're done, all the fields are set */
4712 return 0;
4713}
4714
4715/* returns 0 if wants to be called, 1 if has ended processing */
Aurélien Nephtaliabbf6072018-04-18 13:26:46 +02004716static int cli_parse_table_req(char **args, char *payload, struct appctx *appctx, void *private)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004717{
Willy Tarreau3c69e082022-05-03 11:35:07 +02004718 struct show_table_ctx *ctx = applet_reserve_svcctx(appctx, sizeof(*ctx));
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004719 int i;
4720
4721 for (i = 0; i < STKTABLE_FILTER_LEN; i++)
Willy Tarreau3c69e082022-05-03 11:35:07 +02004722 ctx->data_type[i] = -1;
4723 ctx->target = NULL;
4724 ctx->entry = NULL;
4725 ctx->action = (long)private; // keyword argument, one of STK_CLI_ACT_*
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004726
4727 if (*args[2]) {
Willy Tarreau0f154ed2022-05-03 12:02:36 +02004728 ctx->t = ctx->target = stktable_find_by_name(args[2]);
Willy Tarreau3c69e082022-05-03 11:35:07 +02004729 if (!ctx->target)
Willy Tarreau9d008692019-08-09 11:21:01 +02004730 return cli_err(appctx, "No such table\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004731 }
4732 else {
Willy Tarreau0f154ed2022-05-03 12:02:36 +02004733 ctx->t = stktables_list;
Willy Tarreau3c69e082022-05-03 11:35:07 +02004734 if (ctx->action != STK_CLI_ACT_SHOW)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004735 goto err_args;
4736 return 0;
4737 }
4738
4739 if (strcmp(args[3], "key") == 0)
4740 return table_process_entry_per_key(appctx, args);
4741 else if (strncmp(args[3], "data.", 5) == 0)
4742 return table_prepare_data_request(appctx, args);
4743 else if (*args[3])
4744 goto err_args;
4745
4746 return 0;
4747
4748err_args:
Willy Tarreau3c69e082022-05-03 11:35:07 +02004749 switch (ctx->action) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004750 case STK_CLI_ACT_SHOW:
Willy Tarreau9d008692019-08-09 11:21:01 +02004751 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 +01004752 case STK_CLI_ACT_CLR:
Willy Tarreau9d008692019-08-09 11:21:01 +02004753 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 +01004754 case STK_CLI_ACT_SET:
Willy Tarreau9d008692019-08-09 11:21:01 +02004755 return cli_err(appctx, "Required arguments: <table> key <key> [data.<store_data_type> <value>]*\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004756 default:
Willy Tarreau9d008692019-08-09 11:21:01 +02004757 return cli_err(appctx, "Unknown action\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004758 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004759}
4760
4761/* This function is used to deal with table operations (dump or clear depending
4762 * on the action stored in appctx->private). It returns 0 if the output buffer is
4763 * full and it needs to be called again, otherwise non-zero.
4764 */
4765static int cli_io_handler_table(struct appctx *appctx)
4766{
Willy Tarreau3c69e082022-05-03 11:35:07 +02004767 struct show_table_ctx *ctx = appctx->svcctx;
Willy Tarreauc12b3212022-05-27 11:08:15 +02004768 struct stconn *sc = appctx_sc(appctx);
Willy Tarreau475e4632022-05-27 10:26:46 +02004769 struct stream *s = __sc_strm(sc);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004770 struct ebmb_node *eb;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004771 int skip_entry;
Willy Tarreau3c69e082022-05-03 11:35:07 +02004772 int show = ctx->action == STK_CLI_ACT_SHOW;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004773
4774 /*
Willy Tarreau0f154ed2022-05-03 12:02:36 +02004775 * We have 3 possible states in ctx->state :
Willy Tarreau7849d4c2022-05-03 11:45:02 +02004776 * - STATE_NEXT : the proxy pointer points to the next table to
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004777 * dump, the entry pointer is NULL ;
Willy Tarreau7849d4c2022-05-03 11:45:02 +02004778 * - STATE_DUMP : the proxy pointer points to the current table
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004779 * and the entry pointer points to the next entry to be dumped,
4780 * and the refcount on the next entry is held ;
Willy Tarreau7849d4c2022-05-03 11:45:02 +02004781 * - STATE_DONE : nothing left to dump, the buffer may contain some
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004782 * data though.
4783 */
4784
Willy Tarreau475e4632022-05-27 10:26:46 +02004785 if (unlikely(sc_ic(sc)->flags & (CF_WRITE_ERROR|CF_SHUTW))) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004786 /* in case of abort, remove any refcount we might have set on an entry */
Willy Tarreau7849d4c2022-05-03 11:45:02 +02004787 if (ctx->state == STATE_DUMP) {
Willy Tarreau3c69e082022-05-03 11:35:07 +02004788 stksess_kill_if_expired(ctx->t, ctx->entry, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004789 }
4790 return 1;
4791 }
4792
4793 chunk_reset(&trash);
4794
Willy Tarreau7849d4c2022-05-03 11:45:02 +02004795 while (ctx->state != STATE_DONE) {
4796 switch (ctx->state) {
Willy Tarreau7849d4c2022-05-03 11:45:02 +02004797 case STATE_NEXT:
Willy Tarreau3c69e082022-05-03 11:35:07 +02004798 if (!ctx->t ||
4799 (ctx->target &&
4800 ctx->t != ctx->target)) {
Willy Tarreau7849d4c2022-05-03 11:45:02 +02004801 ctx->state = STATE_DONE;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004802 break;
4803 }
4804
Willy Tarreau3c69e082022-05-03 11:35:07 +02004805 if (ctx->t->size) {
Willy Tarreaud0a06d52022-05-18 15:07:19 +02004806 if (show && !table_dump_head_to_buffer(&trash, appctx, ctx->t, ctx->target))
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004807 return 0;
4808
Willy Tarreau3c69e082022-05-03 11:35:07 +02004809 if (ctx->target &&
William Lallemand07a62f72017-05-24 00:57:40 +02004810 (strm_li(s)->bind_conf->level & ACCESS_LVL_MASK) >= ACCESS_LVL_OPER) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004811 /* dump entries only if table explicitly requested */
Willy Tarreau76642222022-10-11 12:02:50 +02004812 HA_RWLOCK_WRLOCK(STK_TABLE_LOCK, &ctx->t->lock);
Willy Tarreau3c69e082022-05-03 11:35:07 +02004813 eb = ebmb_first(&ctx->t->keys);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004814 if (eb) {
Willy Tarreau3c69e082022-05-03 11:35:07 +02004815 ctx->entry = ebmb_entry(eb, struct stksess, key);
4816 ctx->entry->ref_cnt++;
Willy Tarreau7849d4c2022-05-03 11:45:02 +02004817 ctx->state = STATE_DUMP;
Willy Tarreau76642222022-10-11 12:02:50 +02004818 HA_RWLOCK_WRUNLOCK(STK_TABLE_LOCK, &ctx->t->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004819 break;
4820 }
Willy Tarreau76642222022-10-11 12:02:50 +02004821 HA_RWLOCK_WRUNLOCK(STK_TABLE_LOCK, &ctx->t->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004822 }
4823 }
Willy Tarreau3c69e082022-05-03 11:35:07 +02004824 ctx->t = ctx->t->next;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004825 break;
4826
Willy Tarreau7849d4c2022-05-03 11:45:02 +02004827 case STATE_DUMP:
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004828 skip_entry = 0;
4829
Willy Tarreau3c69e082022-05-03 11:35:07 +02004830 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &ctx->entry->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004831
Willy Tarreau3c69e082022-05-03 11:35:07 +02004832 if (ctx->data_type[0] >= 0) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004833 /* we're filtering on some data contents */
4834 void *ptr;
Willy Tarreau2b64a352020-01-22 17:09:47 +01004835 int dt, i;
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004836 signed char op;
4837 long long data, value;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004838
Emeric Brun819fc6f2017-06-13 19:37:32 +02004839
Willy Tarreau2b64a352020-01-22 17:09:47 +01004840 for (i = 0; i < STKTABLE_FILTER_LEN; i++) {
Willy Tarreau3c69e082022-05-03 11:35:07 +02004841 if (ctx->data_type[i] == -1)
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004842 break;
Willy Tarreau3c69e082022-05-03 11:35:07 +02004843 dt = ctx->data_type[i];
4844 ptr = stktable_data_ptr(ctx->t,
4845 ctx->entry,
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004846 dt);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004847
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004848 data = 0;
4849 switch (stktable_data_types[dt].std_type) {
4850 case STD_T_SINT:
4851 data = stktable_data_cast(ptr, std_t_sint);
4852 break;
4853 case STD_T_UINT:
4854 data = stktable_data_cast(ptr, std_t_uint);
4855 break;
4856 case STD_T_ULL:
4857 data = stktable_data_cast(ptr, std_t_ull);
4858 break;
4859 case STD_T_FRQP:
4860 data = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Willy Tarreau3c69e082022-05-03 11:35:07 +02004861 ctx->t->data_arg[dt].u);
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004862 break;
4863 }
4864
Willy Tarreau3c69e082022-05-03 11:35:07 +02004865 op = ctx->data_op[i];
4866 value = ctx->value[i];
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004867
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004868 /* skip the entry if the data does not match the test and the value */
4869 if ((data < value &&
4870 (op == STD_OP_EQ || op == STD_OP_GT || op == STD_OP_GE)) ||
4871 (data == value &&
4872 (op == STD_OP_NE || op == STD_OP_GT || op == STD_OP_LT)) ||
4873 (data > value &&
4874 (op == STD_OP_EQ || op == STD_OP_LT || op == STD_OP_LE))) {
4875 skip_entry = 1;
4876 break;
4877 }
4878 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004879 }
4880
4881 if (show && !skip_entry &&
Willy Tarreaud0a06d52022-05-18 15:07:19 +02004882 !table_dump_entry_to_buffer(&trash, appctx, ctx->t, ctx->entry)) {
Willy Tarreau3c69e082022-05-03 11:35:07 +02004883 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &ctx->entry->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004884 return 0;
4885 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004886
Willy Tarreau3c69e082022-05-03 11:35:07 +02004887 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &ctx->entry->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004888
Willy Tarreau76642222022-10-11 12:02:50 +02004889 HA_RWLOCK_WRLOCK(STK_TABLE_LOCK, &ctx->t->lock);
Willy Tarreau3c69e082022-05-03 11:35:07 +02004890 ctx->entry->ref_cnt--;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004891
Willy Tarreau3c69e082022-05-03 11:35:07 +02004892 eb = ebmb_next(&ctx->entry->key);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004893 if (eb) {
Willy Tarreau3c69e082022-05-03 11:35:07 +02004894 struct stksess *old = ctx->entry;
4895 ctx->entry = ebmb_entry(eb, struct stksess, key);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004896 if (show)
Willy Tarreau3c69e082022-05-03 11:35:07 +02004897 __stksess_kill_if_expired(ctx->t, old);
4898 else if (!skip_entry && !ctx->entry->ref_cnt)
4899 __stksess_kill(ctx->t, old);
4900 ctx->entry->ref_cnt++;
Willy Tarreau76642222022-10-11 12:02:50 +02004901 HA_RWLOCK_WRUNLOCK(STK_TABLE_LOCK, &ctx->t->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004902 break;
4903 }
4904
4905
4906 if (show)
Willy Tarreau3c69e082022-05-03 11:35:07 +02004907 __stksess_kill_if_expired(ctx->t, ctx->entry);
4908 else if (!skip_entry && !ctx->entry->ref_cnt)
4909 __stksess_kill(ctx->t, ctx->entry);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004910
Willy Tarreau76642222022-10-11 12:02:50 +02004911 HA_RWLOCK_WRUNLOCK(STK_TABLE_LOCK, &ctx->t->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004912
Willy Tarreau3c69e082022-05-03 11:35:07 +02004913 ctx->t = ctx->t->next;
Willy Tarreau7849d4c2022-05-03 11:45:02 +02004914 ctx->state = STATE_NEXT;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004915 break;
4916
Willy Tarreau7849d4c2022-05-03 11:45:02 +02004917 default:
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004918 break;
4919 }
4920 }
4921 return 1;
4922}
4923
4924static void cli_release_show_table(struct appctx *appctx)
4925{
Willy Tarreau3c69e082022-05-03 11:35:07 +02004926 struct show_table_ctx *ctx = appctx->svcctx;
4927
Willy Tarreau7849d4c2022-05-03 11:45:02 +02004928 if (ctx->state == STATE_DUMP) {
Willy Tarreau3c69e082022-05-03 11:35:07 +02004929 stksess_kill_if_expired(ctx->t, ctx->entry, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004930 }
4931}
4932
Willy Tarreau478331d2020-08-28 11:31:31 +02004933static void stkt_late_init(void)
4934{
4935 struct sample_fetch *f;
4936
4937 f = find_sample_fetch("src", strlen("src"));
4938 if (f)
4939 smp_fetch_src = f->process;
4940}
4941
4942INITCALL0(STG_INIT, stkt_late_init);
4943
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004944/* register cli keywords */
4945static struct cli_kw_list cli_kws = {{ },{
Willy Tarreaub205bfd2021-05-07 11:38:37 +02004946 { { "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 },
4947 { { "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 },
4948 { { "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 +01004949 {{},}
4950}};
4951
Willy Tarreau0108d902018-11-25 19:14:37 +01004952INITCALL1(STG_REGISTER, cli_register_kw, &cli_kws);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004953
Thierry FOURNIER236657b2015-08-19 08:25:14 +02004954static struct action_kw_list tcp_conn_kws = { { }, {
Emeric Brun4d7ada82021-06-30 19:04:16 +02004955 { "sc-inc-gpc", parse_inc_gpc, KWF_MATCH_PREFIX },
4956 { "sc-inc-gpc0", parse_inc_gpc, KWF_MATCH_PREFIX },
4957 { "sc-inc-gpc1", parse_inc_gpc, KWF_MATCH_PREFIX },
Emeric Brun877b0b52021-06-30 18:57:49 +02004958 { "sc-set-gpt", parse_set_gpt, KWF_MATCH_PREFIX },
4959 { "sc-set-gpt0", parse_set_gpt, KWF_MATCH_PREFIX },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02004960 { /* END */ }
4961}};
4962
Willy Tarreau0108d902018-11-25 19:14:37 +01004963INITCALL1(STG_REGISTER, tcp_req_conn_keywords_register, &tcp_conn_kws);
4964
Willy Tarreau620408f2016-10-21 16:37:51 +02004965static struct action_kw_list tcp_sess_kws = { { }, {
Emeric Brun4d7ada82021-06-30 19:04:16 +02004966 { "sc-inc-gpc", parse_inc_gpc, KWF_MATCH_PREFIX },
4967 { "sc-inc-gpc0", parse_inc_gpc, KWF_MATCH_PREFIX },
4968 { "sc-inc-gpc1", parse_inc_gpc, KWF_MATCH_PREFIX },
Emeric Brun877b0b52021-06-30 18:57:49 +02004969 { "sc-set-gpt", parse_set_gpt, KWF_MATCH_PREFIX },
4970 { "sc-set-gpt0", parse_set_gpt, KWF_MATCH_PREFIX },
Willy Tarreau620408f2016-10-21 16:37:51 +02004971 { /* END */ }
4972}};
4973
Willy Tarreau0108d902018-11-25 19:14:37 +01004974INITCALL1(STG_REGISTER, tcp_req_sess_keywords_register, &tcp_sess_kws);
4975
Thierry FOURNIER236657b2015-08-19 08:25:14 +02004976static struct action_kw_list tcp_req_kws = { { }, {
Emeric Brun4d7ada82021-06-30 19:04:16 +02004977 { "sc-inc-gpc", parse_inc_gpc, KWF_MATCH_PREFIX },
4978 { "sc-inc-gpc0", parse_inc_gpc, KWF_MATCH_PREFIX },
4979 { "sc-inc-gpc1", parse_inc_gpc, KWF_MATCH_PREFIX },
Emeric Brun877b0b52021-06-30 18:57:49 +02004980 { "sc-set-gpt", parse_set_gpt, KWF_MATCH_PREFIX },
4981 { "sc-set-gpt0", parse_set_gpt, KWF_MATCH_PREFIX },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02004982 { /* END */ }
4983}};
4984
Willy Tarreau0108d902018-11-25 19:14:37 +01004985INITCALL1(STG_REGISTER, tcp_req_cont_keywords_register, &tcp_req_kws);
4986
Thierry FOURNIER236657b2015-08-19 08:25:14 +02004987static struct action_kw_list tcp_res_kws = { { }, {
Emeric Brun4d7ada82021-06-30 19:04:16 +02004988 { "sc-inc-gpc", parse_inc_gpc, KWF_MATCH_PREFIX },
4989 { "sc-inc-gpc0", parse_inc_gpc, KWF_MATCH_PREFIX },
4990 { "sc-inc-gpc1", parse_inc_gpc, KWF_MATCH_PREFIX },
Emeric Brun877b0b52021-06-30 18:57:49 +02004991 { "sc-set-gpt", parse_set_gpt, KWF_MATCH_PREFIX },
4992 { "sc-set-gpt0", parse_set_gpt, KWF_MATCH_PREFIX },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02004993 { /* END */ }
4994}};
4995
Willy Tarreau0108d902018-11-25 19:14:37 +01004996INITCALL1(STG_REGISTER, tcp_res_cont_keywords_register, &tcp_res_kws);
4997
Thierry FOURNIER236657b2015-08-19 08:25:14 +02004998static struct action_kw_list http_req_kws = { { }, {
Emeric Brun4d7ada82021-06-30 19:04:16 +02004999 { "sc-inc-gpc", parse_inc_gpc, KWF_MATCH_PREFIX },
5000 { "sc-inc-gpc0", parse_inc_gpc, KWF_MATCH_PREFIX },
5001 { "sc-inc-gpc1", parse_inc_gpc, KWF_MATCH_PREFIX },
Emeric Brun877b0b52021-06-30 18:57:49 +02005002 { "sc-set-gpt", parse_set_gpt, KWF_MATCH_PREFIX },
5003 { "sc-set-gpt0", parse_set_gpt, KWF_MATCH_PREFIX },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02005004 { /* END */ }
5005}};
5006
Willy Tarreau0108d902018-11-25 19:14:37 +01005007INITCALL1(STG_REGISTER, http_req_keywords_register, &http_req_kws);
5008
Thierry FOURNIER236657b2015-08-19 08:25:14 +02005009static struct action_kw_list http_res_kws = { { }, {
Emeric Brun4d7ada82021-06-30 19:04:16 +02005010 { "sc-inc-gpc", parse_inc_gpc, KWF_MATCH_PREFIX },
5011 { "sc-inc-gpc0", parse_inc_gpc, KWF_MATCH_PREFIX },
5012 { "sc-inc-gpc1", parse_inc_gpc, KWF_MATCH_PREFIX },
Emeric Brun877b0b52021-06-30 18:57:49 +02005013 { "sc-set-gpt", parse_set_gpt, KWF_MATCH_PREFIX },
5014 { "sc-set-gpt0", parse_set_gpt, KWF_MATCH_PREFIX },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02005015 { /* END */ }
5016}};
5017
Willy Tarreau0108d902018-11-25 19:14:37 +01005018INITCALL1(STG_REGISTER, http_res_keywords_register, &http_res_kws);
5019
Willy Tarreau7d562212016-11-25 16:10:05 +01005020/* Note: must not be declared <const> as its list will be overwritten.
5021 * Please take care of keeping this list alphabetically sorted.
5022 */
5023static struct sample_fetch_kw_list smp_fetch_keywords = {ILH, {
5024 { "sc_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5025 { "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 +02005026 { "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 +01005027 { "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 +01005028 { "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 +01005029 { "sc_conn_cnt", smp_fetch_sc_conn_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5030 { "sc_conn_cur", smp_fetch_sc_conn_cur, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5031 { "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 +02005032 { "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 +01005033 { "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 +02005034 { "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 +01005035 { "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 +01005036 { "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 +02005037 { "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 +01005038 { "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 +01005039 { "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 +01005040 { "sc_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5041 { "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 +01005042 { "sc_http_fail_cnt", smp_fetch_sc_http_fail_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5043 { "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 +01005044 { "sc_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5045 { "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 +02005046 { "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 +01005047 { "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 +01005048 { "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 +01005049 { "sc_kbytes_in", smp_fetch_sc_kbytes_in, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5050 { "sc_kbytes_out", smp_fetch_sc_kbytes_out, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5051 { "sc_sess_cnt", smp_fetch_sc_sess_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5052 { "sc_sess_rate", smp_fetch_sc_sess_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5053 { "sc_tracked", smp_fetch_sc_tracked, ARG2(1,SINT,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
5054 { "sc_trackers", smp_fetch_sc_trackers, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5055 { "sc0_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5056 { "sc0_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5057 { "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 +01005058 { "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 +01005059 { "sc0_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5060 { "sc0_conn_cur", smp_fetch_sc_conn_cur, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5061 { "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 +01005062 { "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 +01005063 { "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 +01005064 { "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 +01005065 { "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 +01005066 { "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 +01005067 { "sc0_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5068 { "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 +01005069 { "sc0_http_fail_cnt", smp_fetch_sc_http_fail_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5070 { "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 +01005071 { "sc0_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5072 { "sc0_http_req_rate", smp_fetch_sc_http_req_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5073 { "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 +01005074 { "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 +01005075 { "sc0_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5076 { "sc0_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5077 { "sc0_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5078 { "sc0_sess_rate", smp_fetch_sc_sess_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5079 { "sc0_tracked", smp_fetch_sc_tracked, ARG1(0,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
5080 { "sc0_trackers", smp_fetch_sc_trackers, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5081 { "sc1_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5082 { "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 +02005083 { "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 +01005084 { "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 +01005085 { "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 +01005086 { "sc1_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5087 { "sc1_conn_cur", smp_fetch_sc_conn_cur, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5088 { "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 +01005089 { "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 +01005090 { "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 +01005091 { "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 +01005092 { "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 +01005093 { "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 +01005094 { "sc1_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5095 { "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 +01005096 { "sc1_http_fail_cnt", smp_fetch_sc_http_fail_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5097 { "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 +01005098 { "sc1_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5099 { "sc1_http_req_rate", smp_fetch_sc_http_req_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5100 { "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 +01005101 { "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 +01005102 { "sc1_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5103 { "sc1_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5104 { "sc1_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5105 { "sc1_sess_rate", smp_fetch_sc_sess_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5106 { "sc1_tracked", smp_fetch_sc_tracked, ARG1(0,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
5107 { "sc1_trackers", smp_fetch_sc_trackers, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5108 { "sc2_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5109 { "sc2_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5110 { "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 +01005111 { "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 +01005112 { "sc2_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5113 { "sc2_conn_cur", smp_fetch_sc_conn_cur, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5114 { "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 +01005115 { "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 +01005116 { "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 +01005117 { "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 +01005118 { "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 +01005119 { "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 +01005120 { "sc2_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5121 { "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 +01005122 { "sc2_http_fail_cnt", smp_fetch_sc_http_fail_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5123 { "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 +01005124 { "sc2_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5125 { "sc2_http_req_rate", smp_fetch_sc_http_req_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5126 { "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 +01005127 { "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 +01005128 { "sc2_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5129 { "sc2_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5130 { "sc2_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5131 { "sc2_sess_rate", smp_fetch_sc_sess_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5132 { "sc2_tracked", smp_fetch_sc_tracked, ARG1(0,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
5133 { "sc2_trackers", smp_fetch_sc_trackers, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5134 { "src_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5135 { "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 +02005136 { "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 +01005137 { "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 +01005138 { "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 +01005139 { "src_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5140 { "src_conn_cur", smp_fetch_sc_conn_cur, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5141 { "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 +02005142 { "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 +01005143 { "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 +02005144 { "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 +01005145 { "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 +01005146 { "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 +02005147 { "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 +01005148 { "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 +01005149 { "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 +01005150 { "src_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5151 { "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 +01005152 { "src_http_fail_cnt", smp_fetch_sc_http_fail_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5153 { "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 +01005154 { "src_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5155 { "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 +02005156 { "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 +01005157 { "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 +01005158 { "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 +01005159 { "src_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5160 { "src_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5161 { "src_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5162 { "src_sess_rate", smp_fetch_sc_sess_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5163 { "src_updt_conn_cnt", smp_fetch_src_updt_conn_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5164 { "table_avl", smp_fetch_table_avl, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5165 { "table_cnt", smp_fetch_table_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5166 { /* END */ },
5167}};
5168
Willy Tarreau0108d902018-11-25 19:14:37 +01005169INITCALL1(STG_REGISTER, sample_register_fetches, &smp_fetch_keywords);
Willy Tarreau7d562212016-11-25 16:10:05 +01005170
Willy Tarreaud9f316a2014-07-10 14:03:38 +02005171/* Note: must not be declared <const> as its list will be overwritten */
5172static struct sample_conv_kw_list sample_conv_kws = {ILH, {
Willy Tarreau2d17db52016-05-25 17:16:38 +02005173 { "in_table", sample_conv_in_table, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_BOOL },
5174 { "table_bytes_in_rate", sample_conv_table_bytes_in_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5175 { "table_bytes_out_rate", sample_conv_table_bytes_out_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5176 { "table_conn_cnt", sample_conv_table_conn_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5177 { "table_conn_cur", sample_conv_table_conn_cur, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5178 { "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 +02005179 { "table_expire", sample_conv_table_expire, ARG2(1,TAB,SINT), NULL, SMP_T_ANY, SMP_T_SINT },
Emeric Brun877b0b52021-06-30 18:57:49 +02005180 { "table_gpt", sample_conv_table_gpt, ARG2(2,SINT,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
Willy Tarreau2d17db52016-05-25 17:16:38 +02005181 { "table_gpt0", sample_conv_table_gpt0, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
Emeric Brun4d7ada82021-06-30 19:04:16 +02005182 { "table_gpc", sample_conv_table_gpc, ARG2(2,SINT,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
Willy Tarreau2d17db52016-05-25 17:16:38 +02005183 { "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 +01005184 { "table_gpc1", sample_conv_table_gpc1, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
Emeric Brun4d7ada82021-06-30 19:04:16 +02005185 { "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 +02005186 { "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 +01005187 { "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 +02005188 { "table_http_err_cnt", sample_conv_table_http_err_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5189 { "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 +01005190 { "table_http_fail_cnt", sample_conv_table_http_fail_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5191 { "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 +02005192 { "table_http_req_cnt", sample_conv_table_http_req_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5193 { "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 +02005194 { "table_idle", sample_conv_table_idle, ARG2(1,TAB,SINT), NULL, SMP_T_ANY, SMP_T_SINT },
Willy Tarreau2d17db52016-05-25 17:16:38 +02005195 { "table_kbytes_in", sample_conv_table_kbytes_in, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5196 { "table_kbytes_out", sample_conv_table_kbytes_out, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5197 { "table_server_id", sample_conv_table_server_id, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5198 { "table_sess_cnt", sample_conv_table_sess_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5199 { "table_sess_rate", sample_conv_table_sess_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5200 { "table_trackers", sample_conv_table_trackers, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
Willy Tarreaud9f316a2014-07-10 14:03:38 +02005201 { /* END */ },
5202}};
5203
Willy Tarreau0108d902018-11-25 19:14:37 +01005204INITCALL1(STG_REGISTER, sample_register_convs, &sample_conv_kws);