blob: b1144661e938929318c5a767f5ccf808e812c72d [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 Tarreaue3f5ae82022-10-12 09:45:36 +0000381 int old_exp, new_exp;
Willy Tarreau9f5cb432022-10-11 18:17:58 +0000382
Willy Tarreaua7536ef2022-10-11 18:31:04 +0000383 if (expire != HA_ATOMIC_LOAD(&ts->expire)) {
384 /* we'll need to set the expiration and to wake up the expiration timer .*/
385 HA_ATOMIC_STORE(&ts->expire, expire);
386 if (t->expire) {
Willy Tarreaue3f5ae82022-10-12 09:45:36 +0000387 /* set both t->exp_next and the task's expire to the newest
388 * expiration date.
389 */
390 old_exp = HA_ATOMIC_LOAD(&t->exp_next);
391 do {
392 new_exp = tick_first(expire, old_exp);
393 } while (new_exp != old_exp &&
394 !HA_ATOMIC_CAS(&t->exp_next, &old_exp, new_exp) &&
395 __ha_cpu_relax());
396
397 old_exp = HA_ATOMIC_LOAD(&t->exp_task->expire);
398 do {
399 new_exp = HA_ATOMIC_LOAD(&t->exp_next);
400 } while (new_exp != old_exp &&
401 !HA_ATOMIC_CAS(&t->exp_task->expire, &old_exp, new_exp) &&
402 __ha_cpu_relax());
403
Willy Tarreaua7536ef2022-10-11 18:31:04 +0000404 task_queue(t->exp_task);
405 /* keep the lock */
406 }
Willy Tarreaucb183642010-06-06 17:58:34 +0200407 }
Emeric Brun85e77c72010-09-23 18:16:52 +0200408
Emeric Brun819fc6f2017-06-13 19:37:32 +0200409 /* If sync is enabled */
410 if (t->sync_task) {
411 if (local) {
412 /* If this entry is not in the tree
Willy Tarreaua7536ef2022-10-11 18:31:04 +0000413 * or not scheduled for at least one peer.
414 */
415 if (!locked++)
416 HA_RWLOCK_WRLOCK(STK_TABLE_LOCK, &t->lock);
417
Emeric Brun819fc6f2017-06-13 19:37:32 +0200418 if (!ts->upd.node.leaf_p
419 || (int)(t->commitupdate - ts->upd.key) >= 0
420 || (int)(ts->upd.key - t->localupdate) >= 0) {
421 ts->upd.key = ++t->update;
422 t->localupdate = t->update;
423 eb32_delete(&ts->upd);
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 }
Emeric Brunaaf58602015-06-15 17:23:30 +0200429 }
Emeric Brun819fc6f2017-06-13 19:37:32 +0200430 task_wakeup(t->sync_task, TASK_WOKEN_MSG);
Emeric Brun85e77c72010-09-23 18:16:52 +0200431 }
Emeric Brun819fc6f2017-06-13 19:37:32 +0200432 else {
433 /* If this entry is not in the tree */
Willy Tarreaua7536ef2022-10-11 18:31:04 +0000434 if (!locked++)
435 HA_RWLOCK_WRLOCK(STK_TABLE_LOCK, &t->lock);
436
Emeric Brun819fc6f2017-06-13 19:37:32 +0200437 if (!ts->upd.node.leaf_p) {
438 ts->upd.key= (++t->update)+(2147483648U);
439 eb = eb32_insert(&t->updates, &ts->upd);
440 if (eb != &ts->upd) {
441 eb32_delete(eb);
442 eb32_insert(&t->updates, &ts->upd);
443 }
444 }
445 }
Emeric Brun85e77c72010-09-23 18:16:52 +0200446 }
Willy Tarreau9f5cb432022-10-11 18:17:58 +0000447
Willy Tarreaua7536ef2022-10-11 18:31:04 +0000448 if (decrefcnt) {
449 if (locked)
450 ts->ref_cnt--;
451 else {
452 HA_RWLOCK_RDLOCK(STK_TABLE_LOCK, &t->lock);
453 HA_ATOMIC_DEC(&ts->ref_cnt);
454 HA_RWLOCK_RDUNLOCK(STK_TABLE_LOCK, &t->lock);
455 }
456 }
457
458 if (locked)
459 HA_RWLOCK_WRUNLOCK(STK_TABLE_LOCK, &t->lock);
Willy Tarreaucb183642010-06-06 17:58:34 +0200460}
461
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200462/* Update the expiration timer for <ts> but do not touch its expiration node.
Emeric Brun819fc6f2017-06-13 19:37:32 +0200463 * The table's expiration timer is updated using the date of expiration coming from
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200464 * <t> stick-table configuration.
Emeric Brun819fc6f2017-06-13 19:37:32 +0200465 * The node will be also inserted into the update tree if needed, at a position
466 * considering the update is coming from a remote node
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200467 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200468void stktable_touch_remote(struct stktable *t, struct stksess *ts, int decrefcnt)
469{
Willy Tarreau9f5cb432022-10-11 18:17:58 +0000470 stktable_touch_with_exp(t, ts, 0, ts->expire, decrefcnt);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200471}
472
473/* Update the expiration timer for <ts> but do not touch its expiration node.
474 * The table's expiration timer is updated using the date of expiration coming from
475 * <t> stick-table configuration.
476 * The node will be also inserted into the update tree if needed, at a position
477 * considering the update was made locally
478 */
479void stktable_touch_local(struct stktable *t, struct stksess *ts, int decrefcnt)
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200480{
481 int expire = tick_add(now_ms, MS_TO_TICKS(t->expire));
482
Willy Tarreau9f5cb432022-10-11 18:17:58 +0000483 stktable_touch_with_exp(t, ts, 1, expire, decrefcnt);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200484}
Willy Tarreau4be073b2022-10-11 18:10:27 +0000485/* Just decrease the ref_cnt of the current session. Does nothing if <ts> is NULL.
486 * Note that we still need to take the read lock because a number of other places
487 * (including in Lua and peers) update the ref_cnt non-atomically under the write
488 * lock.
489 */
Willy Tarreau43e90352018-06-27 06:25:57 +0200490static void stktable_release(struct stktable *t, struct stksess *ts)
Emeric Brun819fc6f2017-06-13 19:37:32 +0200491{
Willy Tarreau43e90352018-06-27 06:25:57 +0200492 if (!ts)
493 return;
Willy Tarreau4be073b2022-10-11 18:10:27 +0000494 HA_RWLOCK_RDLOCK(STK_TABLE_LOCK, &t->lock);
495 HA_ATOMIC_DEC(&ts->ref_cnt);
496 HA_RWLOCK_RDUNLOCK(STK_TABLE_LOCK, &t->lock);
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200497}
498
Willy Tarreauf16d2b82010-06-06 15:38:59 +0200499/* Insert new sticky session <ts> in the table. It is assumed that it does not
500 * yet exist (the caller must check this). The table's timeout is updated if it
Willy Tarreaud2d3fd92022-10-11 15:09:46 +0200501 * is set. <ts> is returned if properly inserted, otherwise the one already
502 * present if any.
Willy Tarreauf16d2b82010-06-06 15:38:59 +0200503 */
Willy Tarreaud2d3fd92022-10-11 15:09:46 +0200504struct stksess *__stktable_store(struct stktable *t, struct stksess *ts)
Willy Tarreauf16d2b82010-06-06 15:38:59 +0200505{
Willy Tarreaud2d3fd92022-10-11 15:09:46 +0200506 struct ebmb_node *eb;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100507
Willy Tarreaud2d3fd92022-10-11 15:09:46 +0200508 eb = ebmb_insert(&t->keys, &ts->key, t->key_size);
509 if (likely(eb == &ts->key)) {
510 ts->exp.key = ts->expire;
511 eb32_insert(&t->exps, &ts->exp);
512 }
Emeric Brun819fc6f2017-06-13 19:37:32 +0200513 if (t->expire) {
514 t->exp_task->expire = t->exp_next = tick_first(ts->expire, t->exp_next);
515 task_queue(t->exp_task);
516 }
Willy Tarreaud2d3fd92022-10-11 15:09:46 +0200517 return ebmb_entry(eb, struct stksess, key); // most commonly this is <ts>
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200518}
519
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200520/* Returns a valid or initialized stksess for the specified stktable_key in the
521 * specified table, or NULL if the key was NULL, or if no entry was found nor
Willy Tarreau47f22972022-10-11 15:22:42 +0200522 * could be created. The entry's expiration is updated. This function locks the
523 * table, and the refcount of the entry is increased.
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200524 */
Willy Tarreau47f22972022-10-11 15:22:42 +0200525struct stksess *stktable_get_entry(struct stktable *table, struct stktable_key *key)
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200526{
Willy Tarreau175aa062022-10-11 15:13:46 +0200527 struct stksess *ts, *ts2;
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200528
529 if (!key)
530 return NULL;
531
Willy Tarreau47f22972022-10-11 15:22:42 +0200532 ts = stktable_lookup_key(table, key);
533 if (ts)
534 return ts;
Emeric Brun819fc6f2017-06-13 19:37:32 +0200535
Willy Tarreau996f1a52022-10-11 16:19:35 +0200536 /* No such entry exists, let's try to create a new one. this doesn't
537 * require locking yet.
538 */
539
540 ts = stksess_new(table, key);
541 if (!ts)
542 return NULL;
543
544 /* Now we're certain to have a ts. We need to store it. For this we'll
Willy Tarreau47f22972022-10-11 15:22:42 +0200545 * need an exclusive access. We don't need an atomic upgrade, this is
546 * rare and an unlock+lock sequence will do the job fine. Given that
547 * this will not be atomic, the missing entry might appear in the mean
548 * tome so we have to be careful that the one we try to insert is the
549 * one we find.
550 */
Willy Tarreau47f22972022-10-11 15:22:42 +0200551
Willy Tarreau996f1a52022-10-11 16:19:35 +0200552 HA_RWLOCK_WRLOCK(STK_TABLE_LOCK, &table->lock);
Willy Tarreau47f22972022-10-11 15:22:42 +0200553
554 ts2 = __stktable_store(table, ts);
555 if (unlikely(ts2 != ts)) {
556 /* another entry was added in the mean time, let's
557 * switch to it.
558 */
559 __stksess_free(table, ts);
560 ts = ts2;
561 }
562
563 HA_ATOMIC_INC(&ts->ref_cnt);
Willy Tarreau76642222022-10-11 12:02:50 +0200564 HA_RWLOCK_WRUNLOCK(STK_TABLE_LOCK, &table->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200565
566 return ts;
567}
568
569/* Lookup for an entry with the same key and store the submitted
Willy Tarreaue6288522022-10-12 09:13:14 +0000570 * stksess if not found. This function locks the table either shared or
571 * exclusively, and the refcount of the entry is increased.
Emeric Brun819fc6f2017-06-13 19:37:32 +0200572 */
Willy Tarreaue6288522022-10-12 09:13:14 +0000573struct stksess *stktable_set_entry(struct stktable *table, struct stksess *nts)
Emeric Brun819fc6f2017-06-13 19:37:32 +0200574{
575 struct stksess *ts;
576
Willy Tarreaue6288522022-10-12 09:13:14 +0000577 HA_RWLOCK_RDLOCK(STK_TABLE_LOCK, &table->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200578 ts = __stktable_lookup(table, nts);
Willy Tarreaue6288522022-10-12 09:13:14 +0000579 if (ts) {
580 HA_ATOMIC_INC(&ts->ref_cnt);
581 HA_RWLOCK_RDUNLOCK(STK_TABLE_LOCK, &table->lock);
582 return ts;
Emeric Brun819fc6f2017-06-13 19:37:32 +0200583 }
Willy Tarreaue6288522022-10-12 09:13:14 +0000584 ts = nts;
Emeric Brun819fc6f2017-06-13 19:37:32 +0200585
Willy Tarreaue6288522022-10-12 09:13:14 +0000586 /* let's increment it before switching to exclusive */
587 HA_ATOMIC_INC(&ts->ref_cnt);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200588
Willy Tarreaue6288522022-10-12 09:13:14 +0000589 if (HA_RWLOCK_TRYRDTOSK(STK_TABLE_LOCK, &table->lock) != 0) {
590 /* upgrade to seek lock failed, let's drop and take */
591 HA_RWLOCK_RDUNLOCK(STK_TABLE_LOCK, &table->lock);
592 HA_RWLOCK_WRLOCK(STK_TABLE_LOCK, &table->lock);
593 }
594 else
595 HA_RWLOCK_SKTOWR(STK_TABLE_LOCK, &table->lock);
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200596
Willy Tarreaue6288522022-10-12 09:13:14 +0000597 /* now we're write-locked */
598
599 __stktable_store(table, ts);
600 HA_RWLOCK_WRUNLOCK(STK_TABLE_LOCK, &table->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200601 return ts;
602}
Willy Tarreaue6288522022-10-12 09:13:14 +0000603
Emeric Brun3bd697e2010-01-04 15:23:48 +0100604/*
Willy Tarreauaea940e2010-06-06 11:56:36 +0200605 * Trash expired sticky sessions from table <t>. The next expiration date is
606 * returned.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100607 */
608static int stktable_trash_expired(struct stktable *t)
609{
610 struct stksess *ts;
611 struct eb32_node *eb;
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200612 int looped = 0;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100613
Willy Tarreau76642222022-10-11 12:02:50 +0200614 HA_RWLOCK_WRLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100615 eb = eb32_lookup_ge(&t->exps, now_ms - TIMER_LOOK_BACK);
616
617 while (1) {
618 if (unlikely(!eb)) {
619 /* we might have reached the end of the tree, typically because
620 * <now_ms> is in the first half and we're first scanning the last
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200621 * half. Let's loop back to the beginning of the tree now if we
622 * have not yet visited it.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100623 */
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200624 if (looped)
625 break;
626 looped = 1;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100627 eb = eb32_first(&t->exps);
628 if (likely(!eb))
629 break;
630 }
631
632 if (likely(tick_is_lt(now_ms, eb->key))) {
633 /* timer not expired yet, revisit it later */
634 t->exp_next = eb->key;
Willy Tarreau4d5f13c2017-11-05 11:04:47 +0100635 goto out_unlock;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100636 }
637
638 /* timer looks expired, detach it from the queue */
Willy Tarreau86257dc2010-06-06 12:57:10 +0200639 ts = eb32_entry(eb, struct stksess, exp);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100640 eb = eb32_next(eb);
641
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200642 /* don't delete an entry which is currently referenced */
643 if (ts->ref_cnt)
644 continue;
645
Willy Tarreau86257dc2010-06-06 12:57:10 +0200646 eb32_delete(&ts->exp);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100647
648 if (!tick_is_expired(ts->expire, now_ms)) {
649 if (!tick_isset(ts->expire))
650 continue;
651
Willy Tarreau86257dc2010-06-06 12:57:10 +0200652 ts->exp.key = ts->expire;
653 eb32_insert(&t->exps, &ts->exp);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100654
Willy Tarreau86257dc2010-06-06 12:57:10 +0200655 if (!eb || eb->key > ts->exp.key)
656 eb = &ts->exp;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100657 continue;
658 }
659
660 /* session expired, trash it */
Willy Tarreau86257dc2010-06-06 12:57:10 +0200661 ebmb_delete(&ts->key);
Emeric Brun85e77c72010-09-23 18:16:52 +0200662 eb32_delete(&ts->upd);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200663 __stksess_free(t, ts);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100664 }
665
666 /* We have found no task to expire in any tree */
667 t->exp_next = TICK_ETERNITY;
Willy Tarreau4d5f13c2017-11-05 11:04:47 +0100668out_unlock:
Willy Tarreau76642222022-10-11 12:02:50 +0200669 HA_RWLOCK_WRUNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100670 return t->exp_next;
671}
672
673/*
Willy Tarreauaea940e2010-06-06 11:56:36 +0200674 * Task processing function to trash expired sticky sessions. A pointer to the
675 * task itself is returned since it never dies.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100676 */
Willy Tarreau144f84a2021-03-02 16:09:26 +0100677struct task *process_table_expire(struct task *task, void *context, unsigned int state)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100678{
Olivier Houchard9f6af332018-05-25 14:04:04 +0200679 struct stktable *t = context;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100680
681 task->expire = stktable_trash_expired(t);
682 return task;
683}
684
Willy Tarreauaea940e2010-06-06 11:56:36 +0200685/* Perform minimal stick table intializations, report 0 in case of error, 1 if OK. */
Emeric Brun3bd697e2010-01-04 15:23:48 +0100686int stktable_init(struct stktable *t)
687{
Remi Tricot-Le Breton208ff012021-05-12 17:39:04 +0200688 int peers_retval = 0;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100689 if (t->size) {
Emeric Brun819fc6f2017-06-13 19:37:32 +0200690 t->keys = EB_ROOT_UNIQUE;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100691 memset(&t->exps, 0, sizeof(t->exps));
Emeric Brun1c6235d2015-12-16 15:28:12 +0100692 t->updates = EB_ROOT_UNIQUE;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100693 HA_SPIN_INIT(&t->lock);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100694
Olivier Houchard52dabbc2018-11-14 17:54:36 +0100695 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 +0100696
697 t->exp_next = TICK_ETERNITY;
698 if ( t->expire ) {
Willy Tarreaubeeabf52021-10-01 18:23:30 +0200699 t->exp_task = task_new_anywhere();
Willy Tarreau848522f2018-10-15 11:12:15 +0200700 if (!t->exp_task)
701 return 0;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100702 t->exp_task->process = process_table_expire;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100703 t->exp_task->context = (void *)t;
704 }
Christopher Fauletdfd10ab2021-10-06 14:24:19 +0200705 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 +0200706 peers_retval = peers_register_table(t->peers.p, t);
Emeric Brun32da3c42010-09-23 18:39:19 +0200707 }
708
Remi Tricot-Le Breton208ff012021-05-12 17:39:04 +0200709 return (t->pool != NULL) && !peers_retval;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100710 }
711 return 1;
712}
713
714/*
715 * Configuration keywords of known table types
716 */
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200717struct stktable_type stktable_types[SMP_TYPES] = {
718 [SMP_T_SINT] = { "integer", 0, 4 },
719 [SMP_T_IPV4] = { "ip", 0, 4 },
720 [SMP_T_IPV6] = { "ipv6", 0, 16 },
721 [SMP_T_STR] = { "string", STK_F_CUSTOM_KEYSIZE, 32 },
722 [SMP_T_BIN] = { "binary", STK_F_CUSTOM_KEYSIZE, 32 }
723};
Emeric Brun3bd697e2010-01-04 15:23:48 +0100724
725/*
726 * Parse table type configuration.
727 * Returns 0 on successful parsing, else 1.
728 * <myidx> is set at next configuration <args> index.
729 */
730int stktable_parse_type(char **args, int *myidx, unsigned long *type, size_t *key_size)
731{
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200732 for (*type = 0; *type < SMP_TYPES; (*type)++) {
733 if (!stktable_types[*type].kw)
734 continue;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100735 if (strcmp(args[*myidx], stktable_types[*type].kw) != 0)
736 continue;
737
738 *key_size = stktable_types[*type].default_size;
739 (*myidx)++;
740
Willy Tarreauaea940e2010-06-06 11:56:36 +0200741 if (stktable_types[*type].flags & STK_F_CUSTOM_KEYSIZE) {
Emeric Brun3bd697e2010-01-04 15:23:48 +0100742 if (strcmp("len", args[*myidx]) == 0) {
743 (*myidx)++;
744 *key_size = atol(args[*myidx]);
Emeric Brun485479d2010-09-23 18:02:19 +0200745 if (!*key_size)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100746 break;
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200747 if (*type == SMP_T_STR) {
Emeric Brun485479d2010-09-23 18:02:19 +0200748 /* null terminated string needs +1 for '\0'. */
749 (*key_size)++;
750 }
Emeric Brun3bd697e2010-01-04 15:23:48 +0100751 (*myidx)++;
752 }
753 }
754 return 0;
755 }
756 return 1;
757}
758
Emeric Brunc64a2a32021-06-30 18:01:02 +0200759/* reserve some space for data type <type>, there is 2 optionnals
760 * argument at <sa> and <sa2> to configure this data type and
761 * they can be NULL if unused for a given type.
762 * Returns PE_NONE (0) if OK or an error code among :
Willy Tarreau3b63ca22021-05-08 14:10:42 +0200763 * - PE_ENUM_OOR if <type> does not exist
764 * - PE_EXIST if <type> is already registered
Emeric Brunc64a2a32021-06-30 18:01:02 +0200765 * - PE_ARG_NOT_USE if <sa>/<sa2> was provided but not expected
766 * - PE_ARG_MISSING if <sa>/<sa2> was expected but not provided
767 * - PE_ARG_VALUE_OOR if type is an array and <sa> it out of array size range.
Willy Tarreau3b63ca22021-05-08 14:10:42 +0200768 */
Emeric Brunc64a2a32021-06-30 18:01:02 +0200769int stktable_alloc_data_type(struct stktable *t, int type, const char *sa, const char *sa2)
770
Willy Tarreau3b63ca22021-05-08 14:10:42 +0200771{
772 if (type >= STKTABLE_DATA_TYPES)
773 return PE_ENUM_OOR;
774
775 if (t->data_ofs[type])
776 /* already allocated */
777 return PE_EXIST;
778
Emeric Brunc64a2a32021-06-30 18:01:02 +0200779 t->data_nbelem[type] = 1;
780 if (stktable_data_types[type].is_array) {
781 /* arrays take their element count on first argument */
782 if (!sa)
783 return PE_ARG_MISSING;
784 t->data_nbelem[type] = atoi(sa);
785 if (!t->data_nbelem[type] || (t->data_nbelem[type] > STKTABLE_MAX_DT_ARRAY_SIZE))
786 return PE_ARG_VALUE_OOR;
787 sa = sa2;
788 }
789
Willy Tarreau3b63ca22021-05-08 14:10:42 +0200790 switch (stktable_data_types[type].arg_type) {
791 case ARG_T_NONE:
792 if (sa)
793 return PE_ARG_NOT_USED;
794 break;
795 case ARG_T_INT:
796 if (!sa)
797 return PE_ARG_MISSING;
798 t->data_arg[type].i = atoi(sa);
799 break;
800 case ARG_T_DELAY:
801 if (!sa)
802 return PE_ARG_MISSING;
803 sa = parse_time_err(sa, &t->data_arg[type].u, TIME_UNIT_MS);
804 if (sa)
805 return PE_ARG_INVC; /* invalid char */
806 break;
807 }
808
Emeric Brunc64a2a32021-06-30 18:01:02 +0200809 t->data_size += t->data_nbelem[type] * stktable_type_size(stktable_data_types[type].std_type);
Willy Tarreau3b63ca22021-05-08 14:10:42 +0200810 t->data_ofs[type] = -t->data_size;
811 return PE_NONE;
812}
813
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100814/*
Frédéric Lécaillec02766a2019-03-20 15:06:55 +0100815 * Parse a line with <linenum> as number in <file> configuration file to configure
816 * the stick-table with <t> as address and <id> as ID.
817 * <peers> provides the "peers" section pointer only if this function is called
818 * from a "peers" section.
819 * <nid> is the stick-table name which is sent over the network. It must be equal
820 * to <id> if this stick-table is parsed from a proxy section, and prefixed by <peers>
821 * "peers" section name followed by a '/' character if parsed from a "peers" section.
Ilya Shipitsind4259502020-04-08 01:07:56 +0500822 * This is the responsibility of the caller to check this.
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100823 * Return an error status with ERR_* flags set if required, 0 if no error was encountered.
824 */
825int parse_stick_table(const char *file, int linenum, char **args,
Frédéric Lécaillec02766a2019-03-20 15:06:55 +0100826 struct stktable *t, char *id, char *nid, struct peers *peers)
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100827{
828 int err_code = 0;
829 int idx = 1;
830 unsigned int val;
831
832 if (!id || !*id) {
833 ha_alert("parsing [%s:%d] : %s: ID not provided.\n", file, linenum, args[0]);
834 err_code |= ERR_ALERT | ERR_ABORT;
835 goto out;
836 }
837
838 /* Store the "peers" section if this function is called from a "peers" section. */
839 if (peers) {
840 t->peers.p = peers;
841 idx++;
842 }
843
844 t->id = id;
Frédéric Lécaillec02766a2019-03-20 15:06:55 +0100845 t->nid = nid;
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100846 t->type = (unsigned int)-1;
847 t->conf.file = file;
848 t->conf.line = linenum;
849
850 while (*args[idx]) {
851 const char *err;
852
853 if (strcmp(args[idx], "size") == 0) {
854 idx++;
855 if (!*(args[idx])) {
856 ha_alert("parsing [%s:%d] : %s: missing argument after '%s'.\n",
857 file, linenum, args[0], args[idx-1]);
858 err_code |= ERR_ALERT | ERR_FATAL;
859 goto out;
860 }
861 if ((err = parse_size_err(args[idx], &t->size))) {
862 ha_alert("parsing [%s:%d] : %s: unexpected character '%c' in argument of '%s'.\n",
863 file, linenum, args[0], *err, args[idx-1]);
864 err_code |= ERR_ALERT | ERR_FATAL;
865 goto out;
866 }
867 idx++;
868 }
869 /* This argument does not exit in "peers" section. */
870 else if (!peers && strcmp(args[idx], "peers") == 0) {
871 idx++;
872 if (!*(args[idx])) {
873 ha_alert("parsing [%s:%d] : %s: missing argument after '%s'.\n",
874 file, linenum, args[0], args[idx-1]);
875 err_code |= ERR_ALERT | ERR_FATAL;
876 goto out;
877 }
878 t->peers.name = strdup(args[idx++]);
879 }
880 else if (strcmp(args[idx], "expire") == 0) {
881 idx++;
882 if (!*(args[idx])) {
883 ha_alert("parsing [%s:%d] : %s: missing argument after '%s'.\n",
884 file, linenum, args[0], args[idx-1]);
885 err_code |= ERR_ALERT | ERR_FATAL;
886 goto out;
887 }
888 err = parse_time_err(args[idx], &val, TIME_UNIT_MS);
Willy Tarreau9faebe32019-06-07 19:00:37 +0200889 if (err == PARSE_TIME_OVER) {
890 ha_alert("parsing [%s:%d]: %s: timer overflow in argument <%s> to <%s>, maximum value is 2147483647 ms (~24.8 days).\n",
891 file, linenum, args[0], args[idx], args[idx-1]);
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100892 err_code |= ERR_ALERT | ERR_FATAL;
893 goto out;
894 }
Willy Tarreau9faebe32019-06-07 19:00:37 +0200895 else if (err == PARSE_TIME_UNDER) {
896 ha_alert("parsing [%s:%d]: %s: timer underflow in argument <%s> to <%s>, minimum non-null value is 1 ms.\n",
897 file, linenum, args[0], args[idx], args[idx-1]);
898 err_code |= ERR_ALERT | ERR_FATAL;
899 goto out;
900 }
901 else if (err) {
902 ha_alert("parsing [%s:%d] : %s: unexpected character '%c' in argument of '%s'.\n",
903 file, linenum, args[0], *err, args[idx-1]);
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100904 err_code |= ERR_ALERT | ERR_FATAL;
905 goto out;
906 }
907 t->expire = val;
908 idx++;
909 }
910 else if (strcmp(args[idx], "nopurge") == 0) {
911 t->nopurge = 1;
912 idx++;
913 }
914 else if (strcmp(args[idx], "type") == 0) {
915 idx++;
916 if (stktable_parse_type(args, &idx, &t->type, &t->key_size) != 0) {
917 ha_alert("parsing [%s:%d] : %s: unknown type '%s'.\n",
918 file, linenum, args[0], args[idx]);
919 err_code |= ERR_ALERT | ERR_FATAL;
920 goto out;
921 }
922 /* idx already points to next arg */
923 }
924 else if (strcmp(args[idx], "store") == 0) {
925 int type, err;
Emeric Brunc64a2a32021-06-30 18:01:02 +0200926 char *cw, *nw, *sa, *sa2;
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100927
928 idx++;
929 nw = args[idx];
930 while (*nw) {
931 /* the "store" keyword supports a comma-separated list */
932 cw = nw;
933 sa = NULL; /* store arg */
Emeric Brunc64a2a32021-06-30 18:01:02 +0200934 sa2 = NULL;
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100935 while (*nw && *nw != ',') {
936 if (*nw == '(') {
937 *nw = 0;
938 sa = ++nw;
939 while (*nw != ')') {
940 if (!*nw) {
941 ha_alert("parsing [%s:%d] : %s: missing closing parenthesis after store option '%s'.\n",
942 file, linenum, args[0], cw);
943 err_code |= ERR_ALERT | ERR_FATAL;
944 goto out;
945 }
Emeric Brunc64a2a32021-06-30 18:01:02 +0200946 if (*nw == ',') {
947 *nw = '\0';
948 sa2 = nw + 1;
949 }
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100950 nw++;
951 }
952 *nw = '\0';
953 }
954 nw++;
955 }
956 if (*nw)
957 *nw++ = '\0';
958 type = stktable_get_data_type(cw);
959 if (type < 0) {
960 ha_alert("parsing [%s:%d] : %s: unknown store option '%s'.\n",
961 file, linenum, args[0], cw);
962 err_code |= ERR_ALERT | ERR_FATAL;
963 goto out;
964 }
965
Emeric Brunc64a2a32021-06-30 18:01:02 +0200966 err = stktable_alloc_data_type(t, type, sa, sa2);
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100967 switch (err) {
968 case PE_NONE: break;
969 case PE_EXIST:
970 ha_warning("parsing [%s:%d]: %s: store option '%s' already enabled, ignored.\n",
971 file, linenum, args[0], cw);
972 err_code |= ERR_WARN;
973 break;
974
975 case PE_ARG_MISSING:
976 ha_alert("parsing [%s:%d] : %s: missing argument to store option '%s'.\n",
977 file, linenum, args[0], cw);
978 err_code |= ERR_ALERT | ERR_FATAL;
979 goto out;
980
981 case PE_ARG_NOT_USED:
982 ha_alert("parsing [%s:%d] : %s: unexpected argument to store option '%s'.\n",
983 file, linenum, args[0], cw);
984 err_code |= ERR_ALERT | ERR_FATAL;
985 goto out;
Emeric Brunc64a2a32021-06-30 18:01:02 +0200986 case PE_ARG_VALUE_OOR:
987 ha_alert("parsing [%s:%d] : %s: array size is out of allowed range (1-%d) for store option '%s'.\n",
988 file, linenum, args[0], STKTABLE_MAX_DT_ARRAY_SIZE, cw);
989 err_code |= ERR_ALERT | ERR_FATAL;
990 goto out;
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100991
992 default:
993 ha_alert("parsing [%s:%d] : %s: error when processing store option '%s'.\n",
994 file, linenum, args[0], cw);
995 err_code |= ERR_ALERT | ERR_FATAL;
996 goto out;
997 }
998 }
999 idx++;
Emeric Brunf7ab0bf2021-06-30 18:58:22 +02001000 if (t->data_ofs[STKTABLE_DT_GPT] && t->data_ofs[STKTABLE_DT_GPT0]) {
1001 ha_alert("parsing [%s:%d] : %s: simultaneous usage of 'gpt' and 'gpt0' in a same table is not permitted as 'gpt' overrides 'gpt0'.\n",
1002 file, linenum, args[0]);
1003 err_code |= ERR_ALERT | ERR_FATAL;
1004 goto out;
1005 }
Emeric Brun726783d2021-06-30 19:06:43 +02001006 else if (t->data_ofs[STKTABLE_DT_GPC] && (t->data_ofs[STKTABLE_DT_GPC0] || t->data_ofs[STKTABLE_DT_GPC1])) {
1007 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",
1008 file, linenum, args[0]);
1009 err_code |= ERR_ALERT | ERR_FATAL;
1010 goto out;
1011 }
1012 else if (t->data_ofs[STKTABLE_DT_GPC_RATE] && (t->data_ofs[STKTABLE_DT_GPC0_RATE] || t->data_ofs[STKTABLE_DT_GPC1_RATE])) {
1013 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",
1014 file, linenum, args[0]);
1015 err_code |= ERR_ALERT | ERR_FATAL;
1016 goto out;
1017 }
Frédéric Lécailled456aa42019-03-08 14:47:00 +01001018 }
Thayne McCombs92149f92020-11-20 01:28:26 -07001019 else if (strcmp(args[idx], "srvkey") == 0) {
1020 char *keytype;
1021 idx++;
1022 keytype = args[idx];
1023 if (strcmp(keytype, "name") == 0) {
1024 t->server_key_type = STKTABLE_SRV_NAME;
1025 }
1026 else if (strcmp(keytype, "addr") == 0) {
1027 t->server_key_type = STKTABLE_SRV_ADDR;
1028 }
1029 else {
1030 ha_alert("parsing [%s:%d] : %s : unknown server key type '%s'.\n",
1031 file, linenum, args[0], keytype);
1032 err_code |= ERR_ALERT | ERR_FATAL;
1033 goto out;
1034
1035 }
1036 idx++;
1037 }
Frédéric Lécailled456aa42019-03-08 14:47:00 +01001038 else {
1039 ha_alert("parsing [%s:%d] : %s: unknown argument '%s'.\n",
1040 file, linenum, args[0], args[idx]);
1041 err_code |= ERR_ALERT | ERR_FATAL;
1042 goto out;
1043 }
1044 }
1045
1046 if (!t->size) {
1047 ha_alert("parsing [%s:%d] : %s: missing size.\n",
1048 file, linenum, args[0]);
1049 err_code |= ERR_ALERT | ERR_FATAL;
1050 goto out;
1051 }
1052
1053 if (t->type == (unsigned int)-1) {
1054 ha_alert("parsing [%s:%d] : %s: missing type.\n",
1055 file, linenum, args[0]);
1056 err_code |= ERR_ALERT | ERR_FATAL;
1057 goto out;
1058 }
1059
1060 out:
1061 return err_code;
1062}
1063
Willy Tarreau8fed9032014-07-03 17:02:46 +02001064/* Prepares a stktable_key from a sample <smp> to search into table <t>.
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001065 * Note that the sample *is* modified and that the returned key may point
1066 * to it, so the sample must not be modified afterwards before the lookup.
Willy Tarreau8fed9032014-07-03 17:02:46 +02001067 * Returns NULL if the sample could not be converted (eg: no matching type),
1068 * otherwise a pointer to the static stktable_key filled with what is needed
1069 * for the lookup.
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001070 */
Willy Tarreau8fed9032014-07-03 17:02:46 +02001071struct stktable_key *smp_to_stkey(struct sample *smp, struct stktable *t)
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001072{
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001073 /* Convert sample. */
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +02001074 if (!sample_convert(smp, t->type))
Willy Tarreau7fc1c6e2012-04-26 11:03:17 +02001075 return NULL;
1076
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001077 /* Fill static_table_key. */
1078 switch (t->type) {
Emeric Brun485479d2010-09-23 18:02:19 +02001079
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +02001080 case SMP_T_IPV4:
Christopher Fauletca20d022017-08-29 15:30:31 +02001081 static_table_key.key = &smp->data.u.ipv4;
1082 static_table_key.key_len = 4;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001083 break;
Emeric Brun485479d2010-09-23 18:02:19 +02001084
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +02001085 case SMP_T_IPV6:
Christopher Fauletca20d022017-08-29 15:30:31 +02001086 static_table_key.key = &smp->data.u.ipv6;
1087 static_table_key.key_len = 16;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001088 break;
Emeric Brun485479d2010-09-23 18:02:19 +02001089
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +02001090 case SMP_T_SINT:
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001091 /* The stick table require a 32bit unsigned int, "sint" is a
1092 * signed 64 it, so we can convert it inplace.
1093 */
Willy Tarreau28c63c12019-10-23 06:21:05 +02001094 smp->data.u.sint = (unsigned int)smp->data.u.sint;
Christopher Fauletca20d022017-08-29 15:30:31 +02001095 static_table_key.key = &smp->data.u.sint;
1096 static_table_key.key_len = 4;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001097 break;
1098
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +02001099 case SMP_T_STR:
Willy Tarreauce6955e2016-08-09 11:59:12 +02001100 if (!smp_make_safe(smp))
1101 return NULL;
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001102 static_table_key.key = smp->data.u.str.area;
1103 static_table_key.key_len = smp->data.u.str.data;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001104 break;
Emeric Brun485479d2010-09-23 18:02:19 +02001105
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +02001106 case SMP_T_BIN:
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001107 if (smp->data.u.str.data < t->key_size) {
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001108 /* This type needs padding with 0. */
Willy Tarreauf65c6c02016-08-09 12:08:41 +02001109 if (!smp_make_rw(smp))
1110 return NULL;
1111
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001112 if (smp->data.u.str.size < t->key_size)
1113 if (!smp_dup(smp))
1114 return NULL;
1115 if (smp->data.u.str.size < t->key_size)
1116 return NULL;
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001117 memset(smp->data.u.str.area + smp->data.u.str.data, 0,
1118 t->key_size - smp->data.u.str.data);
1119 smp->data.u.str.data = t->key_size;
Emeric Brun485479d2010-09-23 18:02:19 +02001120 }
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001121 static_table_key.key = smp->data.u.str.area;
1122 static_table_key.key_len = smp->data.u.str.data;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001123 break;
Emeric Brun485479d2010-09-23 18:02:19 +02001124
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001125 default: /* impossible case. */
1126 return NULL;
Emeric Brun485479d2010-09-23 18:02:19 +02001127 }
1128
Christopher Fauletca20d022017-08-29 15:30:31 +02001129 return &static_table_key;
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001130}
1131
1132/*
Willy Tarreau8fed9032014-07-03 17:02:46 +02001133 * Process a fetch + format conversion as defined by the sample expression <expr>
1134 * on request or response considering the <opt> parameter. Returns either NULL if
1135 * no key could be extracted, or a pointer to the converted result stored in
1136 * static_table_key in format <table_type>. If <smp> is not NULL, it will be reset
1137 * and its flags will be initialized so that the caller gets a copy of the input
Willy Tarreau6bcb0a82014-07-30 08:56:35 +02001138 * sample, and knows why it was not accepted (eg: SMP_F_MAY_CHANGE is present
1139 * without SMP_OPT_FINAL). The output will be usable like this :
1140 *
1141 * return MAY_CHANGE FINAL Meaning for the sample
1142 * NULL 0 * Not present and will never be (eg: header)
1143 * NULL 1 0 Not present or unstable, could change (eg: req_len)
1144 * NULL 1 1 Not present, will not change anymore
1145 * smp 0 * Present and will not change (eg: header)
1146 * smp 1 0 not possible
1147 * smp 1 1 Present, last known value (eg: request length)
Willy Tarreau8fed9032014-07-03 17:02:46 +02001148 */
Willy Tarreau192252e2015-04-04 01:47:55 +02001149struct stktable_key *stktable_fetch_key(struct stktable *t, struct proxy *px, struct session *sess, struct stream *strm,
Willy Tarreau8fed9032014-07-03 17:02:46 +02001150 unsigned int opt, struct sample_expr *expr, struct sample *smp)
1151{
1152 if (smp)
1153 memset(smp, 0, sizeof(*smp));
1154
Willy Tarreau192252e2015-04-04 01:47:55 +02001155 smp = sample_process(px, sess, strm, opt, expr, smp);
Willy Tarreau8fed9032014-07-03 17:02:46 +02001156 if (!smp)
1157 return NULL;
1158
1159 if ((smp->flags & SMP_F_MAY_CHANGE) && !(opt & SMP_OPT_FINAL))
1160 return NULL; /* we can only use stable samples */
1161
1162 return smp_to_stkey(smp, t);
1163}
1164
1165/*
Willy Tarreau12785782012-04-27 21:37:17 +02001166 * Returns 1 if sample expression <expr> result can be converted to table key of
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001167 * type <table_type>, otherwise zero. Used in configuration check.
1168 */
Willy Tarreau12785782012-04-27 21:37:17 +02001169int stktable_compatible_sample(struct sample_expr *expr, unsigned long table_type)
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001170{
Thierry FOURNIERf73eb8f2013-11-27 15:30:55 +01001171 int out_type;
1172
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +02001173 if (table_type >= SMP_TYPES || !stktable_types[table_type].kw)
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001174 return 0;
1175
Thierry FOURNIERf73eb8f2013-11-27 15:30:55 +01001176 out_type = smp_expr_output_type(expr);
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001177
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001178 /* Convert sample. */
1179 if (!sample_casts[out_type][table_type])
Thierry FOURNIERf73eb8f2013-11-27 15:30:55 +01001180 return 0;
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001181
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001182 return 1;
1183}
Emeric Brun3bd697e2010-01-04 15:23:48 +01001184
Willy Tarreauedee1d62014-07-15 16:44:27 +02001185/* Extra data types processing : after the last one, some room may remain
1186 * before STKTABLE_DATA_TYPES that may be used to register extra data types
1187 * at run time.
1188 */
Willy Tarreau08d5f982010-06-06 13:34:54 +02001189struct stktable_data_type stktable_data_types[STKTABLE_DATA_TYPES] = {
Willy Tarreau3b9c6e02010-07-18 08:04:30 +02001190 [STKTABLE_DT_SERVER_ID] = { .name = "server_id", .std_type = STD_T_SINT },
Thierry FOURNIER3cf11112015-07-28 08:57:05 +02001191 [STKTABLE_DT_GPT0] = { .name = "gpt0", .std_type = STD_T_UINT },
Willy Tarreau3b9c6e02010-07-18 08:04:30 +02001192 [STKTABLE_DT_GPC0] = { .name = "gpc0", .std_type = STD_T_UINT },
Willy Tarreauba2ffd12013-05-29 15:54:14 +02001193 [STKTABLE_DT_GPC0_RATE] = { .name = "gpc0_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
Willy Tarreau3b9c6e02010-07-18 08:04:30 +02001194 [STKTABLE_DT_CONN_CNT] = { .name = "conn_cnt", .std_type = STD_T_UINT },
1195 [STKTABLE_DT_CONN_RATE] = { .name = "conn_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
Willy Tarreaudb2ab822021-10-08 17:53:12 +02001196 [STKTABLE_DT_CONN_CUR] = { .name = "conn_cur", .std_type = STD_T_UINT, .is_local = 1 },
Willy Tarreau3b9c6e02010-07-18 08:04:30 +02001197 [STKTABLE_DT_SESS_CNT] = { .name = "sess_cnt", .std_type = STD_T_UINT },
1198 [STKTABLE_DT_SESS_RATE] = { .name = "sess_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
1199 [STKTABLE_DT_HTTP_REQ_CNT] = { .name = "http_req_cnt", .std_type = STD_T_UINT },
1200 [STKTABLE_DT_HTTP_REQ_RATE] = { .name = "http_req_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
1201 [STKTABLE_DT_HTTP_ERR_CNT] = { .name = "http_err_cnt", .std_type = STD_T_UINT },
1202 [STKTABLE_DT_HTTP_ERR_RATE] = { .name = "http_err_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
1203 [STKTABLE_DT_BYTES_IN_CNT] = { .name = "bytes_in_cnt", .std_type = STD_T_ULL },
1204 [STKTABLE_DT_BYTES_IN_RATE] = { .name = "bytes_in_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
1205 [STKTABLE_DT_BYTES_OUT_CNT] = { .name = "bytes_out_cnt", .std_type = STD_T_ULL },
1206 [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 +01001207 [STKTABLE_DT_GPC1] = { .name = "gpc1", .std_type = STD_T_UINT },
1208 [STKTABLE_DT_GPC1_RATE] = { .name = "gpc1_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
Thayne McCombs92149f92020-11-20 01:28:26 -07001209 [STKTABLE_DT_SERVER_KEY] = { .name = "server_key", .std_type = STD_T_DICT },
Willy Tarreau826f3ab2021-02-10 12:07:15 +01001210 [STKTABLE_DT_HTTP_FAIL_CNT] = { .name = "http_fail_cnt", .std_type = STD_T_UINT },
1211 [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 +02001212 [STKTABLE_DT_GPT] = { .name = "gpt", .std_type = STD_T_UINT, .is_array = 1 },
Emeric Brun4d7ada82021-06-30 19:04:16 +02001213 [STKTABLE_DT_GPC] = { .name = "gpc", .std_type = STD_T_UINT, .is_array = 1 },
1214 [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 +02001215};
1216
Willy Tarreauedee1d62014-07-15 16:44:27 +02001217/* Registers stick-table extra data type with index <idx>, name <name>, type
1218 * <std_type> and arg type <arg_type>. If the index is negative, the next free
1219 * index is automatically allocated. The allocated index is returned, or -1 if
1220 * no free index was found or <name> was already registered. The <name> is used
1221 * directly as a pointer, so if it's not stable, the caller must allocate it.
1222 */
1223int stktable_register_data_store(int idx, const char *name, int std_type, int arg_type)
1224{
1225 if (idx < 0) {
1226 for (idx = 0; idx < STKTABLE_DATA_TYPES; idx++) {
1227 if (!stktable_data_types[idx].name)
1228 break;
1229
1230 if (strcmp(stktable_data_types[idx].name, name) == 0)
1231 return -1;
1232 }
1233 }
1234
1235 if (idx >= STKTABLE_DATA_TYPES)
1236 return -1;
1237
1238 if (stktable_data_types[idx].name != NULL)
1239 return -1;
1240
1241 stktable_data_types[idx].name = name;
1242 stktable_data_types[idx].std_type = std_type;
1243 stktable_data_types[idx].arg_type = arg_type;
1244 return idx;
1245}
1246
Willy Tarreau08d5f982010-06-06 13:34:54 +02001247/*
1248 * Returns the data type number for the stktable_data_type whose name is <name>,
1249 * or <0 if not found.
1250 */
1251int stktable_get_data_type(char *name)
1252{
1253 int type;
1254
1255 for (type = 0; type < STKTABLE_DATA_TYPES; type++) {
Willy Tarreauedee1d62014-07-15 16:44:27 +02001256 if (!stktable_data_types[type].name)
1257 continue;
Willy Tarreau08d5f982010-06-06 13:34:54 +02001258 if (strcmp(name, stktable_data_types[type].name) == 0)
1259 return type;
1260 }
Thayne McCombs92149f92020-11-20 01:28:26 -07001261 /* For backwards compatibility */
1262 if (strcmp(name, "server_name") == 0)
1263 return STKTABLE_DT_SERVER_KEY;
Willy Tarreau08d5f982010-06-06 13:34:54 +02001264 return -1;
1265}
1266
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001267/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1268 * it up into this table. Returns true if found, false otherwise. The input
1269 * type is STR so that input samples are converted to string (since all types
1270 * can be converted to strings), then the function casts the string again into
1271 * the table's type. This is a double conversion, but in the future we might
1272 * support automatic input types to perform the cast on the fly.
1273 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001274static int sample_conv_in_table(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001275{
1276 struct stktable *t;
1277 struct stktable_key *key;
1278 struct stksess *ts;
1279
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001280 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001281
1282 key = smp_to_stkey(smp, t);
1283 if (!key)
1284 return 0;
1285
1286 ts = stktable_lookup_key(t, key);
1287
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001288 smp->data.type = SMP_T_BOOL;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001289 smp->data.u.sint = !!ts;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001290 smp->flags = SMP_F_VOL_TEST;
Willy Tarreau43e90352018-06-27 06:25:57 +02001291 stktable_release(t, ts);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001292 return 1;
1293}
1294
1295/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1296 * it up into this table. Returns the data rate received from clients in bytes/s
1297 * if the key is present in the table, otherwise zero, so that comparisons can
1298 * be easily performed. If the inspected parameter is not stored in the table,
1299 * <not found> is returned.
1300 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001301static int sample_conv_table_bytes_in_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001302{
1303 struct stktable *t;
1304 struct stktable_key *key;
1305 struct stksess *ts;
1306 void *ptr;
1307
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001308 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001309
1310 key = smp_to_stkey(smp, t);
1311 if (!key)
1312 return 0;
1313
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001314 ts = stktable_lookup_key(t, key);
1315
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001316 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001317 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001318 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001319
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001320 if (!ts) /* key not present */
1321 return 1;
1322
1323 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_IN_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001324 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001325 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Daniel Corbett3e60b112018-05-27 09:47:12 -04001326 t->data_arg[STKTABLE_DT_BYTES_IN_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001327
Daniel Corbett3e60b112018-05-27 09:47:12 -04001328 stktable_release(t, ts);
1329 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001330}
1331
1332/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1333 * it up into this table. Returns the cumulated number of connections for the key
1334 * if the key is present in the table, otherwise zero, so that comparisons can
1335 * be easily performed. If the inspected parameter is not stored in the table,
1336 * <not found> is returned.
1337 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001338static int sample_conv_table_conn_cnt(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001339{
1340 struct stktable *t;
1341 struct stktable_key *key;
1342 struct stksess *ts;
1343 void *ptr;
1344
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001345 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001346
1347 key = smp_to_stkey(smp, t);
1348 if (!key)
1349 return 0;
1350
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001351 ts = stktable_lookup_key(t, key);
1352
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001353 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001354 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001355 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001356
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001357 if (!ts) /* key not present */
1358 return 1;
1359
1360 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_CONN_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001361 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001362 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001363
Daniel Corbett3e60b112018-05-27 09:47:12 -04001364 stktable_release(t, ts);
1365 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001366}
1367
1368/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1369 * it up into this table. Returns the number of concurrent connections for the
1370 * key if the key is present in the table, otherwise zero, so that comparisons
1371 * can be easily performed. If the inspected parameter is not stored in the
1372 * table, <not found> is returned.
1373 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001374static int sample_conv_table_conn_cur(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001375{
1376 struct stktable *t;
1377 struct stktable_key *key;
1378 struct stksess *ts;
1379 void *ptr;
1380
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001381 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001382
1383 key = smp_to_stkey(smp, t);
1384 if (!key)
1385 return 0;
1386
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001387 ts = stktable_lookup_key(t, key);
1388
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001389 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001390 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001391 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001392
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001393 if (!ts) /* key not present */
1394 return 1;
1395
1396 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_CONN_CUR);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001397 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001398 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001399
Daniel Corbett3e60b112018-05-27 09:47:12 -04001400 stktable_release(t, ts);
1401 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001402}
1403
1404/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1405 * it up into this table. Returns the rate of incoming connections from the key
1406 * if the key is present in the table, otherwise zero, so that comparisons can
1407 * be easily performed. If the inspected parameter is not stored in the table,
1408 * <not found> is returned.
1409 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001410static int sample_conv_table_conn_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001411{
1412 struct stktable *t;
1413 struct stktable_key *key;
1414 struct stksess *ts;
1415 void *ptr;
1416
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001417 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001418
1419 key = smp_to_stkey(smp, t);
1420 if (!key)
1421 return 0;
1422
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001423 ts = stktable_lookup_key(t, key);
1424
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001425 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001426 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001427 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001428
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001429 if (!ts) /* key not present */
1430 return 1;
1431
1432 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_CONN_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001433 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001434 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Daniel Corbett3e60b112018-05-27 09:47:12 -04001435 t->data_arg[STKTABLE_DT_CONN_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001436
Daniel Corbett3e60b112018-05-27 09:47:12 -04001437 stktable_release(t, ts);
1438 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001439}
1440
1441/* 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 +02001442 * it up into this table. Returns the expiration delay for the key if the key is
1443 * present in the table, otherwise the default value provided as second argument
1444 * if any, if not (no default value), <not found> is returned.
1445 */
1446static int sample_conv_table_expire(const struct arg *arg_p, struct sample *smp, void *private)
1447{
1448 struct stktable *t;
1449 struct stktable_key *key;
1450 struct stksess *ts;
1451
1452 t = arg_p[0].data.t;
1453
1454 key = smp_to_stkey(smp, t);
1455 if (!key)
1456 return 0;
1457
1458 ts = stktable_lookup_key(t, key);
1459
1460 smp->flags = SMP_F_VOL_TEST;
1461 smp->data.type = SMP_T_SINT;
1462 smp->data.u.sint = 0;
1463
1464 if (!ts) { /* key not present */
1465 if (arg_p[1].type == ARGT_STOP)
1466 return 0;
1467
1468 /* default value */
1469 smp->data.u.sint = arg_p[1].data.sint;
1470 return 1;
1471 }
1472
1473 smp->data.u.sint = tick_remain(now_ms, ts->expire);
1474
1475 stktable_release(t, ts);
1476 return 1;
1477}
1478
1479/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1480 * it up into this table. Returns the time the key remains unused if the key is
1481 * present in the table, otherwise the default value provided as second argument
1482 * if any, if not (no default value), <not found> is returned.
1483 */
1484static int sample_conv_table_idle(const struct arg *arg_p, struct sample *smp, void *private)
1485{
1486 struct stktable *t;
1487 struct stktable_key *key;
1488 struct stksess *ts;
1489
1490 t = arg_p[0].data.t;
1491
1492 key = smp_to_stkey(smp, t);
1493 if (!key)
1494 return 0;
1495
1496 ts = stktable_lookup_key(t, key);
1497
1498 smp->flags = SMP_F_VOL_TEST;
1499 smp->data.type = SMP_T_SINT;
1500 smp->data.u.sint = 0;
1501
1502 if (!ts) { /* key not present */
1503 if (arg_p[1].type == ARGT_STOP)
1504 return 0;
1505
1506 /* default value */
1507 smp->data.u.sint = arg_p[1].data.sint;
1508 return 1;
1509 }
1510
1511 smp->data.u.sint = tick_remain(tick_remain(now_ms, ts->expire), t->expire);
1512
1513 stktable_release(t, ts);
1514 return 1;
1515}
1516
1517/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001518 * it up into this table. Returns the data rate sent to clients in bytes/s
1519 * if the key is present in the table, otherwise zero, so that comparisons can
1520 * be easily performed. If the inspected parameter is not stored in the table,
1521 * <not found> is returned.
1522 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001523static int sample_conv_table_bytes_out_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001524{
1525 struct stktable *t;
1526 struct stktable_key *key;
1527 struct stksess *ts;
1528 void *ptr;
1529
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001530 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001531
1532 key = smp_to_stkey(smp, t);
1533 if (!key)
1534 return 0;
1535
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001536 ts = stktable_lookup_key(t, key);
1537
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001538 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001539 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001540 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001541
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001542 if (!ts) /* key not present */
1543 return 1;
1544
1545 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_OUT_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001546 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001547 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Daniel Corbett3e60b112018-05-27 09:47:12 -04001548 t->data_arg[STKTABLE_DT_BYTES_OUT_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001549
Daniel Corbett3e60b112018-05-27 09:47:12 -04001550 stktable_release(t, ts);
1551 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001552}
1553
Emeric Brun877b0b52021-06-30 18:57:49 +02001554/* Casts sample <smp> to the type of the table specified in arg_p(1), and looks
1555 * it up into this table. Returns the value of the GPT[arg_p(0)] tag for the key
1556 * if the key is present in the table, otherwise false, so that comparisons can
1557 * be easily performed. If the inspected parameter is not stored in the table,
1558 * <not found> is returned.
1559 */
1560static int sample_conv_table_gpt(const struct arg *arg_p, struct sample *smp, void *private)
1561{
1562 struct stktable *t;
1563 struct stktable_key *key;
1564 struct stksess *ts;
1565 void *ptr;
1566 unsigned int idx;
1567
1568 idx = arg_p[0].data.sint;
1569
1570 t = arg_p[1].data.t;
1571
1572 key = smp_to_stkey(smp, t);
1573 if (!key)
1574 return 0;
1575
1576 ts = stktable_lookup_key(t, key);
1577
1578 smp->flags = SMP_F_VOL_TEST;
1579 smp->data.type = SMP_T_SINT;
1580 smp->data.u.sint = 0;
1581
1582 if (!ts) /* key not present */
1583 return 1;
1584
1585 ptr = stktable_data_ptr_idx(t, ts, STKTABLE_DT_GPT, idx);
1586 if (ptr)
1587 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
1588
1589 stktable_release(t, ts);
1590 return !!ptr;
1591}
1592
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001593/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001594 * it up into this table. Returns the value of the GPT0 tag for the key
1595 * if the key is present in the table, otherwise false, so that comparisons can
1596 * be easily performed. If the inspected parameter is not stored in the table,
1597 * <not found> is returned.
1598 */
1599static int sample_conv_table_gpt0(const struct arg *arg_p, struct sample *smp, void *private)
1600{
1601 struct stktable *t;
1602 struct stktable_key *key;
1603 struct stksess *ts;
1604 void *ptr;
1605
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001606 t = arg_p[0].data.t;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001607
1608 key = smp_to_stkey(smp, t);
1609 if (!key)
1610 return 0;
1611
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001612 ts = stktable_lookup_key(t, key);
1613
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001614 smp->flags = SMP_F_VOL_TEST;
1615 smp->data.type = SMP_T_SINT;
1616 smp->data.u.sint = 0;
1617
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001618 if (!ts) /* key not present */
1619 return 1;
1620
1621 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPT0);
Emeric Brunf7ab0bf2021-06-30 18:58:22 +02001622 if (!ptr)
1623 ptr = stktable_data_ptr_idx(t, ts, STKTABLE_DT_GPT, 0);
1624
Daniel Corbett3e60b112018-05-27 09:47:12 -04001625 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001626 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001627
Daniel Corbett3e60b112018-05-27 09:47:12 -04001628 stktable_release(t, ts);
1629 return !!ptr;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001630}
1631
Emeric Brun4d7ada82021-06-30 19:04:16 +02001632/* Casts sample <smp> to the type of the table specified in arg_p(1), and looks
1633 * it up into this table. Returns the value of the GPC[arg_p(0)] counter for the key
1634 * if the key is present in the table, otherwise zero, so that comparisons can
1635 * be easily performed. If the inspected parameter is not stored in the table,
1636 * <not found> is returned.
1637 */
1638static int sample_conv_table_gpc(const struct arg *arg_p, struct sample *smp, void *private)
1639{
1640 struct stktable *t;
1641 struct stktable_key *key;
1642 struct stksess *ts;
1643 void *ptr;
1644 unsigned int idx;
1645
1646 idx = arg_p[0].data.sint;
1647
1648 t = arg_p[1].data.t;
1649
1650 key = smp_to_stkey(smp, t);
1651 if (!key)
1652 return 0;
1653
1654 ts = stktable_lookup_key(t, key);
1655
1656 smp->flags = SMP_F_VOL_TEST;
1657 smp->data.type = SMP_T_SINT;
1658 smp->data.u.sint = 0;
1659
1660 if (!ts) /* key not present */
1661 return 1;
1662
1663 ptr = stktable_data_ptr_idx(t, ts, STKTABLE_DT_GPC, idx);
1664 if (ptr)
1665 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
1666
1667 stktable_release(t, ts);
1668 return !!ptr;
1669}
1670
1671/* Casts sample <smp> to the type of the table specified in arg_p(1), and looks
1672 * it up into this table. Returns the event rate of the GPC[arg_p(0)] counter
1673 * for the key if the key is present in the table, otherwise zero, so that
1674 * comparisons can be easily performed. If the inspected parameter is not
1675 * stored in the table, <not found> is returned.
1676 */
1677static int sample_conv_table_gpc_rate(const struct arg *arg_p, struct sample *smp, void *private)
1678{
1679 struct stktable *t;
1680 struct stktable_key *key;
1681 struct stksess *ts;
1682 void *ptr;
1683 unsigned int idx;
1684
1685 idx = arg_p[0].data.sint;
1686
1687 t = arg_p[1].data.t;
1688
1689 key = smp_to_stkey(smp, t);
1690 if (!key)
1691 return 0;
1692
1693 ts = stktable_lookup_key(t, key);
1694
1695 smp->flags = SMP_F_VOL_TEST;
1696 smp->data.type = SMP_T_SINT;
1697 smp->data.u.sint = 0;
1698
1699 if (!ts) /* key not present */
1700 return 1;
1701
1702 ptr = stktable_data_ptr_idx(t, ts, STKTABLE_DT_GPC_RATE, idx);
1703 if (ptr)
1704 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
1705 t->data_arg[STKTABLE_DT_GPC_RATE].u);
1706
1707 stktable_release(t, ts);
1708 return !!ptr;
1709}
1710
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001711/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001712 * it up into this table. Returns the value of the GPC0 counter for the key
1713 * if the key is present in the table, otherwise zero, so that comparisons can
1714 * be easily performed. If the inspected parameter is not stored in the table,
1715 * <not found> is returned.
1716 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001717static int sample_conv_table_gpc0(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001718{
1719 struct stktable *t;
1720 struct stktable_key *key;
1721 struct stksess *ts;
1722 void *ptr;
1723
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001724 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001725
1726 key = smp_to_stkey(smp, t);
1727 if (!key)
1728 return 0;
1729
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001730 ts = stktable_lookup_key(t, key);
1731
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001732 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001733 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001734 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001735
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001736 if (!ts) /* key not present */
1737 return 1;
1738
1739 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPC0);
Emeric Brun726783d2021-06-30 19:06:43 +02001740 if (!ptr) {
1741 /* fallback on the gpc array */
1742 ptr = stktable_data_ptr_idx(t, ts, STKTABLE_DT_GPC, 0);
1743 }
1744
Daniel Corbett3e60b112018-05-27 09:47:12 -04001745 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001746 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001747
Daniel Corbett3e60b112018-05-27 09:47:12 -04001748 stktable_release(t, ts);
1749 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001750}
1751
1752/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1753 * it up into this table. Returns the event rate of the GPC0 counter for the key
1754 * if the key is present in the table, otherwise zero, so that comparisons can
1755 * be easily performed. If the inspected parameter is not stored in the table,
1756 * <not found> is returned.
1757 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001758static int sample_conv_table_gpc0_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001759{
1760 struct stktable *t;
1761 struct stktable_key *key;
1762 struct stksess *ts;
1763 void *ptr;
1764
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001765 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001766
1767 key = smp_to_stkey(smp, t);
1768 if (!key)
1769 return 0;
1770
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001771 ts = stktable_lookup_key(t, key);
1772
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001773 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001774 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001775 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001776
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001777 if (!ts) /* key not present */
1778 return 1;
1779
1780 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPC0_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001781 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001782 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Daniel Corbett3e60b112018-05-27 09:47:12 -04001783 t->data_arg[STKTABLE_DT_GPC0_RATE].u);
Emeric Brun726783d2021-06-30 19:06:43 +02001784 else {
1785 /* fallback on the gpc array */
1786 ptr = stktable_data_ptr_idx(t, ts, STKTABLE_DT_GPC_RATE, 0);
1787 if (ptr)
1788 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
1789 t->data_arg[STKTABLE_DT_GPC_RATE].u);
1790 }
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001791
Daniel Corbett3e60b112018-05-27 09:47:12 -04001792 stktable_release(t, ts);
1793 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001794}
1795
1796/* 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 +01001797 * it up into this table. Returns the value of the GPC1 counter for the key
1798 * if the key is present in the table, otherwise zero, so that comparisons can
1799 * be easily performed. If the inspected parameter is not stored in the table,
1800 * <not found> is returned.
1801 */
1802static int sample_conv_table_gpc1(const struct arg *arg_p, struct sample *smp, void *private)
1803{
1804 struct stktable *t;
1805 struct stktable_key *key;
1806 struct stksess *ts;
1807 void *ptr;
1808
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001809 t = arg_p[0].data.t;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001810
1811 key = smp_to_stkey(smp, t);
1812 if (!key)
1813 return 0;
1814
1815 ts = stktable_lookup_key(t, key);
1816
1817 smp->flags = SMP_F_VOL_TEST;
1818 smp->data.type = SMP_T_SINT;
1819 smp->data.u.sint = 0;
1820
1821 if (!ts) /* key not present */
1822 return 1;
1823
1824 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPC1);
Emeric Brun726783d2021-06-30 19:06:43 +02001825 if (!ptr) {
1826 /* fallback on the gpc array */
1827 ptr = stktable_data_ptr_idx(t, ts, STKTABLE_DT_GPC, 1);
1828 }
1829
Daniel Corbett3e60b112018-05-27 09:47:12 -04001830 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001831 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001832
Daniel Corbett3e60b112018-05-27 09:47:12 -04001833 stktable_release(t, ts);
1834 return !!ptr;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001835}
1836
1837/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1838 * it up into this table. Returns the event rate of the GPC1 counter for the key
1839 * if the key is present in the table, otherwise zero, so that comparisons can
1840 * be easily performed. If the inspected parameter is not stored in the table,
1841 * <not found> is returned.
1842 */
1843static int sample_conv_table_gpc1_rate(const struct arg *arg_p, struct sample *smp, void *private)
1844{
1845 struct stktable *t;
1846 struct stktable_key *key;
1847 struct stksess *ts;
1848 void *ptr;
1849
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001850 t = arg_p[0].data.t;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001851
1852 key = smp_to_stkey(smp, t);
1853 if (!key)
1854 return 0;
1855
1856 ts = stktable_lookup_key(t, key);
1857
1858 smp->flags = SMP_F_VOL_TEST;
1859 smp->data.type = SMP_T_SINT;
1860 smp->data.u.sint = 0;
1861
1862 if (!ts) /* key not present */
1863 return 1;
1864
1865 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPC1_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001866 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001867 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Daniel Corbett3e60b112018-05-27 09:47:12 -04001868 t->data_arg[STKTABLE_DT_GPC1_RATE].u);
Emeric Brun726783d2021-06-30 19:06:43 +02001869 else {
1870 /* fallback on the gpc array */
1871 ptr = stktable_data_ptr_idx(t, ts, STKTABLE_DT_GPC_RATE, 1);
1872 if (ptr)
1873 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
1874 t->data_arg[STKTABLE_DT_GPC_RATE].u);
1875 }
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001876
Daniel Corbett3e60b112018-05-27 09:47:12 -04001877 stktable_release(t, ts);
1878 return !!ptr;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001879}
1880
1881/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001882 * it up into this table. Returns the cumulated number of HTTP request errors
1883 * for the key if the key is present in the table, otherwise zero, so that
1884 * comparisons can be easily performed. If the inspected parameter is not stored
1885 * in the table, <not found> is returned.
1886 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001887static int sample_conv_table_http_err_cnt(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001888{
1889 struct stktable *t;
1890 struct stktable_key *key;
1891 struct stksess *ts;
1892 void *ptr;
1893
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001894 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001895
1896 key = smp_to_stkey(smp, t);
1897 if (!key)
1898 return 0;
1899
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001900 ts = stktable_lookup_key(t, key);
1901
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001902 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001903 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001904 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001905
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001906 if (!ts) /* key not present */
1907 return 1;
1908
1909 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_ERR_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001910 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001911 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001912
Daniel Corbett3e60b112018-05-27 09:47:12 -04001913 stktable_release(t, ts);
1914 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001915}
1916
1917/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1918 * it up into this table. Returns the HTTP request error rate the key
1919 * if the key is present in the table, otherwise zero, so that comparisons can
1920 * be easily performed. If the inspected parameter is not stored in the table,
1921 * <not found> is returned.
1922 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001923static int sample_conv_table_http_err_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001924{
1925 struct stktable *t;
1926 struct stktable_key *key;
1927 struct stksess *ts;
1928 void *ptr;
1929
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001930 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001931
1932 key = smp_to_stkey(smp, t);
1933 if (!key)
1934 return 0;
1935
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001936 ts = stktable_lookup_key(t, key);
1937
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001938 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001939 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001940 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001941
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001942 if (!ts) /* key not present */
1943 return 1;
1944
1945 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_ERR_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001946 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001947 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Daniel Corbett3e60b112018-05-27 09:47:12 -04001948 t->data_arg[STKTABLE_DT_HTTP_ERR_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001949
Daniel Corbett3e60b112018-05-27 09:47:12 -04001950 stktable_release(t, ts);
1951 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001952}
1953
1954/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Willy Tarreau826f3ab2021-02-10 12:07:15 +01001955 * it up into this table. Returns the cumulated number of HTTP response failures
1956 * for the key if the key is present in the table, otherwise zero, so that
1957 * comparisons can be easily performed. If the inspected parameter is not stored
1958 * in the table, <not found> is returned.
1959 */
1960static int sample_conv_table_http_fail_cnt(const struct arg *arg_p, struct sample *smp, void *private)
1961{
1962 struct stktable *t;
1963 struct stktable_key *key;
1964 struct stksess *ts;
1965 void *ptr;
1966
1967 t = arg_p[0].data.t;
1968
1969 key = smp_to_stkey(smp, t);
1970 if (!key)
1971 return 0;
1972
1973 ts = stktable_lookup_key(t, key);
1974
1975 smp->flags = SMP_F_VOL_TEST;
1976 smp->data.type = SMP_T_SINT;
1977 smp->data.u.sint = 0;
1978
1979 if (!ts) /* key not present */
1980 return 1;
1981
1982 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_FAIL_CNT);
1983 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001984 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Willy Tarreau826f3ab2021-02-10 12:07:15 +01001985
1986 stktable_release(t, ts);
1987 return !!ptr;
1988}
1989
1990/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1991 * it up into this table. Returns the HTTP response failure rate for the key
1992 * if the key is present in the table, otherwise zero, so that comparisons can
1993 * be easily performed. If the inspected parameter is not stored in the table,
1994 * <not found> is returned.
1995 */
1996static int sample_conv_table_http_fail_rate(const struct arg *arg_p, struct sample *smp, void *private)
1997{
1998 struct stktable *t;
1999 struct stktable_key *key;
2000 struct stksess *ts;
2001 void *ptr;
2002
2003 t = arg_p[0].data.t;
2004
2005 key = smp_to_stkey(smp, t);
2006 if (!key)
2007 return 0;
2008
2009 ts = stktable_lookup_key(t, key);
2010
2011 smp->flags = SMP_F_VOL_TEST;
2012 smp->data.type = SMP_T_SINT;
2013 smp->data.u.sint = 0;
2014
2015 if (!ts) /* key not present */
2016 return 1;
2017
2018 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_FAIL_RATE);
2019 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002020 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Willy Tarreau826f3ab2021-02-10 12:07:15 +01002021 t->data_arg[STKTABLE_DT_HTTP_FAIL_RATE].u);
2022
2023 stktable_release(t, ts);
2024 return !!ptr;
2025}
2026
2027/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002028 * it up into this table. Returns the cumulated number of HTTP request for the
2029 * key if the key is present in the table, otherwise zero, so that comparisons
2030 * can be easily performed. If the inspected parameter is not stored in the
2031 * table, <not found> is returned.
2032 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02002033static int sample_conv_table_http_req_cnt(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002034{
2035 struct stktable *t;
2036 struct stktable_key *key;
2037 struct stksess *ts;
2038 void *ptr;
2039
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002040 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002041
2042 key = smp_to_stkey(smp, t);
2043 if (!key)
2044 return 0;
2045
Willy Tarreauf0c730a2016-05-25 17:07:56 +02002046 ts = stktable_lookup_key(t, key);
2047
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002048 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02002049 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02002050 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002051
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002052 if (!ts) /* key not present */
2053 return 1;
2054
2055 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_REQ_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04002056 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002057 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002058
Daniel Corbett3e60b112018-05-27 09:47:12 -04002059 stktable_release(t, ts);
2060 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002061}
2062
2063/* Casts sample <smp> to the type of the table specified in arg(0), and looks
2064 * it up into this table. Returns the HTTP request rate the key if the key is
2065 * present in the table, otherwise zero, so that comparisons can be easily
2066 * performed. If the inspected parameter is not stored in the table, <not found>
2067 * is returned.
2068 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02002069static int sample_conv_table_http_req_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002070{
2071 struct stktable *t;
2072 struct stktable_key *key;
2073 struct stksess *ts;
2074 void *ptr;
2075
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002076 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002077
2078 key = smp_to_stkey(smp, t);
2079 if (!key)
2080 return 0;
2081
Willy Tarreauf0c730a2016-05-25 17:07:56 +02002082 ts = stktable_lookup_key(t, key);
2083
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002084 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02002085 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02002086 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002087
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002088 if (!ts) /* key not present */
2089 return 1;
2090
2091 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_REQ_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04002092 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002093 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Daniel Corbett3e60b112018-05-27 09:47:12 -04002094 t->data_arg[STKTABLE_DT_HTTP_REQ_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002095
Daniel Corbett3e60b112018-05-27 09:47:12 -04002096 stktable_release(t, ts);
2097 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002098}
2099
2100/* Casts sample <smp> to the type of the table specified in arg(0), and looks
2101 * it up into this table. Returns the volume of datareceived from clients in kbytes
2102 * if the key is present in the table, otherwise zero, so that comparisons can
2103 * be easily performed. If the inspected parameter is not stored in the table,
2104 * <not found> is returned.
2105 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02002106static int sample_conv_table_kbytes_in(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002107{
2108 struct stktable *t;
2109 struct stktable_key *key;
2110 struct stksess *ts;
2111 void *ptr;
2112
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002113 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002114
2115 key = smp_to_stkey(smp, t);
2116 if (!key)
2117 return 0;
2118
Willy Tarreauf0c730a2016-05-25 17:07:56 +02002119 ts = stktable_lookup_key(t, key);
2120
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002121 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02002122 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02002123 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002124
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002125 if (!ts) /* key not present */
2126 return 1;
2127
2128 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_IN_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04002129 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002130 smp->data.u.sint = stktable_data_cast(ptr, std_t_ull) >> 10;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002131
Daniel Corbett3e60b112018-05-27 09:47:12 -04002132 stktable_release(t, ts);
2133 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002134}
2135
2136/* Casts sample <smp> to the type of the table specified in arg(0), and looks
2137 * it up into this table. Returns the volume of data sent to clients in kbytes
2138 * if the key is present in the table, otherwise zero, so that comparisons can
2139 * be easily performed. If the inspected parameter is not stored in the table,
2140 * <not found> is returned.
2141 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02002142static int sample_conv_table_kbytes_out(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002143{
2144 struct stktable *t;
2145 struct stktable_key *key;
2146 struct stksess *ts;
2147 void *ptr;
2148
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002149 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002150
2151 key = smp_to_stkey(smp, t);
2152 if (!key)
2153 return 0;
2154
Willy Tarreauf0c730a2016-05-25 17:07:56 +02002155 ts = stktable_lookup_key(t, key);
2156
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002157 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02002158 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02002159 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002160
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002161 if (!ts) /* key not present */
2162 return 1;
2163
2164 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_OUT_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04002165 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002166 smp->data.u.sint = stktable_data_cast(ptr, std_t_ull) >> 10;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002167
Daniel Corbett3e60b112018-05-27 09:47:12 -04002168 stktable_release(t, ts);
2169 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002170}
2171
2172/* Casts sample <smp> to the type of the table specified in arg(0), and looks
2173 * it up into this table. Returns the server ID associated with the key if the
2174 * key is present in the table, otherwise zero, so that comparisons can be
2175 * easily performed. If the inspected parameter is not stored in the table,
2176 * <not found> is returned.
2177 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02002178static int sample_conv_table_server_id(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002179{
2180 struct stktable *t;
2181 struct stktable_key *key;
2182 struct stksess *ts;
2183 void *ptr;
2184
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002185 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002186
2187 key = smp_to_stkey(smp, t);
2188 if (!key)
2189 return 0;
2190
Willy Tarreauf0c730a2016-05-25 17:07:56 +02002191 ts = stktable_lookup_key(t, key);
2192
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002193 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02002194 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02002195 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002196
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002197 if (!ts) /* key not present */
2198 return 1;
2199
2200 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_SERVER_ID);
Daniel Corbett3e60b112018-05-27 09:47:12 -04002201 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002202 smp->data.u.sint = stktable_data_cast(ptr, std_t_sint);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002203
Daniel Corbett3e60b112018-05-27 09:47:12 -04002204 stktable_release(t, ts);
2205 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002206}
2207
2208/* Casts sample <smp> to the type of the table specified in arg(0), and looks
2209 * it up into this table. Returns the cumulated number of sessions for the
2210 * key if the key is present in the table, otherwise zero, so that comparisons
2211 * can be easily performed. If the inspected parameter is not stored in the
2212 * table, <not found> is returned.
2213 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02002214static int sample_conv_table_sess_cnt(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002215{
2216 struct stktable *t;
2217 struct stktable_key *key;
2218 struct stksess *ts;
2219 void *ptr;
2220
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002221 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002222
2223 key = smp_to_stkey(smp, t);
2224 if (!key)
2225 return 0;
2226
Willy Tarreauf0c730a2016-05-25 17:07:56 +02002227 ts = stktable_lookup_key(t, key);
2228
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002229 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02002230 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02002231 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002232
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002233 if (!ts) /* key not present */
2234 return 1;
2235
2236 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_SESS_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04002237 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002238 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002239
Daniel Corbett3e60b112018-05-27 09:47:12 -04002240 stktable_release(t, ts);
2241 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002242}
2243
2244/* Casts sample <smp> to the type of the table specified in arg(0), and looks
2245 * it up into this table. Returns the session rate the key if the key is
2246 * present in the table, otherwise zero, so that comparisons can be easily
2247 * performed. If the inspected parameter is not stored in the table, <not found>
2248 * is returned.
2249 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02002250static int sample_conv_table_sess_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002251{
2252 struct stktable *t;
2253 struct stktable_key *key;
2254 struct stksess *ts;
2255 void *ptr;
2256
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002257 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002258
2259 key = smp_to_stkey(smp, t);
2260 if (!key)
2261 return 0;
2262
Willy Tarreauf0c730a2016-05-25 17:07:56 +02002263 ts = stktable_lookup_key(t, key);
2264
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002265 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02002266 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02002267 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002268
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002269 if (!ts) /* key not present */
2270 return 1;
2271
2272 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_SESS_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04002273 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002274 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Daniel Corbett3e60b112018-05-27 09:47:12 -04002275 t->data_arg[STKTABLE_DT_SESS_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002276
Daniel Corbett3e60b112018-05-27 09:47:12 -04002277 stktable_release(t, ts);
2278 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002279}
2280
2281/* Casts sample <smp> to the type of the table specified in arg(0), and looks
2282 * it up into this table. Returns the amount of concurrent connections tracking
2283 * the same key if the key is present in the table, otherwise zero, so that
2284 * comparisons can be easily performed. If the inspected parameter is not
2285 * stored in the table, <not found> is returned.
2286 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02002287static int sample_conv_table_trackers(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002288{
2289 struct stktable *t;
2290 struct stktable_key *key;
2291 struct stksess *ts;
2292
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002293 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002294
2295 key = smp_to_stkey(smp, t);
2296 if (!key)
2297 return 0;
2298
Willy Tarreauf0c730a2016-05-25 17:07:56 +02002299 ts = stktable_lookup_key(t, key);
2300
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002301 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02002302 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02002303 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002304
Tim Duesterhus65189c12018-06-26 15:57:29 +02002305 if (!ts)
2306 return 1;
2307
2308 smp->data.u.sint = ts->ref_cnt;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002309
Daniel Corbett3e60b112018-05-27 09:47:12 -04002310 stktable_release(t, ts);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002311 return 1;
2312}
2313
Emeric Brun4d7ada82021-06-30 19:04:16 +02002314/* This function increments the gpc counter at index 'rule->arg.gpc.idx' of the
2315 * array on the tracksc counter of index 'rule->arg.gpc.sc' stored into the
2316 * <stream> or directly in the session <sess> if <stream> is set to NULL
2317 *
2318 * This function always returns ACT_RET_CONT and parameter flags is unused.
2319 */
2320static enum act_return action_inc_gpc(struct act_rule *rule, struct proxy *px,
2321 struct session *sess, struct stream *s, int flags)
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002322{
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002323 struct stksess *ts;
2324 struct stkctr *stkctr;
2325
2326 /* Extract the stksess, return OK if no stksess available. */
2327 if (s)
2328 stkctr = &s->stkctr[rule->arg.gpc.sc];
2329 else
2330 stkctr = &sess->stkctr[rule->arg.gpc.sc];
Willy Tarreau79c1e912016-01-25 14:54:45 +01002331
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002332 ts = stkctr_entry(stkctr);
Willy Tarreau79c1e912016-01-25 14:54:45 +01002333 if (ts) {
2334 void *ptr1, *ptr2;
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002335
Emeric Brun4d7ada82021-06-30 19:04:16 +02002336 /* First, update gpc_rate if it's tracked. Second, update its gpc if tracked. */
2337 ptr1 = stktable_data_ptr_idx(stkctr->table, ts, STKTABLE_DT_GPC_RATE, rule->arg.gpc.idx);
2338 ptr2 = stktable_data_ptr_idx(stkctr->table, ts, STKTABLE_DT_GPC, rule->arg.gpc.idx);
2339
Emeric Brun819fc6f2017-06-13 19:37:32 +02002340 if (ptr1 || ptr2) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002341 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002342
2343 if (ptr1)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002344 update_freq_ctr_period(&stktable_data_cast(ptr1, std_t_frqp),
Emeric Brun4d7ada82021-06-30 19:04:16 +02002345 stkctr->table->data_arg[STKTABLE_DT_GPC_RATE].u, 1);
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002346
Emeric Brun819fc6f2017-06-13 19:37:32 +02002347 if (ptr2)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002348 stktable_data_cast(ptr2, std_t_uint)++;
Willy Tarreau79c1e912016-01-25 14:54:45 +01002349
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002350 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002351
2352 /* If data was modified, we need to touch to re-schedule sync */
2353 stktable_touch_local(stkctr->table, ts, 0);
2354 }
Willy Tarreau79c1e912016-01-25 14:54:45 +01002355 }
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002356 return ACT_RET_CONT;
2357}
2358
Emeric Brun4d7ada82021-06-30 19:04:16 +02002359/* Same as action_inc_gpc() but for gpc0 only */
2360static enum act_return action_inc_gpc0(struct act_rule *rule, struct proxy *px,
2361 struct session *sess, struct stream *s, int flags)
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002362{
Emeric Brun4d7ada82021-06-30 19:04:16 +02002363 struct stksess *ts;
2364 struct stkctr *stkctr;
Willy Tarreau5b654ad2021-07-06 18:51:12 +02002365 unsigned int period = 0;
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002366
Emeric Brun4d7ada82021-06-30 19:04:16 +02002367 /* Extract the stksess, return OK if no stksess available. */
2368 if (s)
2369 stkctr = &s->stkctr[rule->arg.gpc.sc];
2370 else
2371 stkctr = &sess->stkctr[rule->arg.gpc.sc];
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002372
Emeric Brun4d7ada82021-06-30 19:04:16 +02002373 ts = stkctr_entry(stkctr);
2374 if (ts) {
2375 void *ptr1, *ptr2;
2376
2377 /* First, update gpc0_rate if it's tracked. Second, update its gpc0 if tracked. */
2378 ptr1 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC0_RATE);
Emeric Brun726783d2021-06-30 19:06:43 +02002379 if (ptr1) {
2380 period = stkctr->table->data_arg[STKTABLE_DT_GPC0_RATE].u;
2381 }
2382 else {
2383 /* fallback on the gpc array */
2384 ptr1 = stktable_data_ptr_idx(stkctr->table, ts, STKTABLE_DT_GPC_RATE, 0);
2385 if (ptr1)
2386 period = stkctr->table->data_arg[STKTABLE_DT_GPC_RATE].u;
2387 }
2388
Emeric Brun4d7ada82021-06-30 19:04:16 +02002389 ptr2 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC0);
Emeric Brun726783d2021-06-30 19:06:43 +02002390 if (!ptr2) {
2391 /* fallback on the gpc array */
2392 ptr2 = stktable_data_ptr_idx(stkctr->table, ts, STKTABLE_DT_GPC, 0);
2393 }
2394
Emeric Brun4d7ada82021-06-30 19:04:16 +02002395 if (ptr1 || ptr2) {
2396 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
2397
2398 if (ptr1)
2399 update_freq_ctr_period(&stktable_data_cast(ptr1, std_t_frqp),
Emeric Brun726783d2021-06-30 19:06:43 +02002400 period, 1);
Emeric Brun4d7ada82021-06-30 19:04:16 +02002401
2402 if (ptr2)
2403 stktable_data_cast(ptr2, std_t_uint)++;
2404
2405 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
2406
2407 /* If data was modified, we need to touch to re-schedule sync */
2408 stktable_touch_local(stkctr->table, ts, 0);
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002409 }
2410 }
Emeric Brun4d7ada82021-06-30 19:04:16 +02002411 return ACT_RET_CONT;
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002412}
2413
Emeric Brun4d7ada82021-06-30 19:04:16 +02002414/* Same as action_inc_gpc() but for gpc1 only */
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002415static enum act_return action_inc_gpc1(struct act_rule *rule, struct proxy *px,
2416 struct session *sess, struct stream *s, int flags)
2417{
2418 struct stksess *ts;
2419 struct stkctr *stkctr;
Willy Tarreau5b654ad2021-07-06 18:51:12 +02002420 unsigned int period = 0;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002421
2422 /* Extract the stksess, return OK if no stksess available. */
2423 if (s)
2424 stkctr = &s->stkctr[rule->arg.gpc.sc];
2425 else
2426 stkctr = &sess->stkctr[rule->arg.gpc.sc];
2427
2428 ts = stkctr_entry(stkctr);
2429 if (ts) {
2430 void *ptr1, *ptr2;
2431
2432 /* First, update gpc1_rate if it's tracked. Second, update its gpc1 if tracked. */
2433 ptr1 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC1_RATE);
Emeric Brun726783d2021-06-30 19:06:43 +02002434 if (ptr1) {
2435 period = stkctr->table->data_arg[STKTABLE_DT_GPC1_RATE].u;
2436 }
2437 else {
2438 /* fallback on the gpc array */
2439 ptr1 = stktable_data_ptr_idx(stkctr->table, ts, STKTABLE_DT_GPC_RATE, 1);
2440 if (ptr1)
2441 period = stkctr->table->data_arg[STKTABLE_DT_GPC_RATE].u;
2442 }
2443
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002444 ptr2 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC1);
Emeric Brun726783d2021-06-30 19:06:43 +02002445 if (!ptr2) {
2446 /* fallback on the gpc array */
2447 ptr2 = stktable_data_ptr_idx(stkctr->table, ts, STKTABLE_DT_GPC, 1);
2448 }
2449
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002450 if (ptr1 || ptr2) {
2451 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
2452
2453 if (ptr1)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002454 update_freq_ctr_period(&stktable_data_cast(ptr1, std_t_frqp),
Emeric Brun726783d2021-06-30 19:06:43 +02002455 period, 1);
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002456
2457 if (ptr2)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002458 stktable_data_cast(ptr2, std_t_uint)++;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002459
2460 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
2461
2462 /* If data was modified, we need to touch to re-schedule sync */
2463 stktable_touch_local(stkctr->table, ts, 0);
2464 }
2465 }
2466 return ACT_RET_CONT;
2467}
2468
Emeric Brun4d7ada82021-06-30 19:04:16 +02002469/* This function is a common parser for actions incrementing the GPC
2470 * (General Purpose Counters). It understands the formats:
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002471 *
Emeric Brun4d7ada82021-06-30 19:04:16 +02002472 * sc-inc-gpc(<gpc IDX>,<track ID>)
2473 * sc-inc-gpc0([<track ID>])
2474 * sc-inc-gpc1([<track ID>])
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002475 *
Emeric Brun4d7ada82021-06-30 19:04:16 +02002476 * It returns ACT_RET_PRS_ERR if fails and <err> is filled with an error
2477 * message. Otherwise it returns ACT_RET_PRS_OK.
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002478 */
Emeric Brun4d7ada82021-06-30 19:04:16 +02002479static enum act_parse_ret parse_inc_gpc(const char **args, int *arg, struct proxy *px,
2480 struct act_rule *rule, char **err)
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002481{
2482 const char *cmd_name = args[*arg-1];
2483 char *error;
2484
Emeric Brun4d7ada82021-06-30 19:04:16 +02002485 cmd_name += strlen("sc-inc-gpc");
2486 if (*cmd_name == '(') {
2487 cmd_name++; /* skip the '(' */
2488 rule->arg.gpc.idx = strtoul(cmd_name, &error, 10); /* Convert stick table id. */
2489 if (*error != ',') {
2490 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 +01002491 return ACT_RET_PRS_ERR;
2492 }
Emeric Brun4d7ada82021-06-30 19:04:16 +02002493 else {
2494 cmd_name = error + 1; /* skip the ',' */
2495 rule->arg.gpc.sc = strtol(cmd_name, &error, 10); /* Convert stick table id. */
2496 if (*error != ')') {
2497 memprintf(err, "invalid stick table track ID '%s'. Expects sc-inc-gpc(<GPC ID>,<Track ID>)", args[*arg-1]);
2498 return ACT_RET_PRS_ERR;
2499 }
2500
2501 if (rule->arg.gpc.sc >= MAX_SESS_STKCTR) {
2502 memprintf(err, "invalid stick table track ID '%s'. The max allowed ID is %d",
2503 args[*arg-1], MAX_SESS_STKCTR-1);
2504 return ACT_RET_PRS_ERR;
2505 }
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002506 }
Emeric Brun4d7ada82021-06-30 19:04:16 +02002507 rule->action_ptr = action_inc_gpc;
2508 }
2509 else if (*cmd_name == '0' ||*cmd_name == '1') {
2510 char c = *cmd_name;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002511
Emeric Brun4d7ada82021-06-30 19:04:16 +02002512 cmd_name++;
2513 if (*cmd_name == '\0') {
2514 /* default stick table id. */
2515 rule->arg.gpc.sc = 0;
2516 } else {
2517 /* parse the stick table id. */
2518 if (*cmd_name != '(') {
2519 memprintf(err, "invalid stick table track ID. Expects %s(<Track ID>)", args[*arg-1]);
2520 return ACT_RET_PRS_ERR;
2521 }
2522 cmd_name++; /* jump the '(' */
2523 rule->arg.gpc.sc = strtol(cmd_name, &error, 10); /* Convert stick table id. */
2524 if (*error != ')') {
2525 memprintf(err, "invalid stick table track ID. Expects %s(<Track ID>)", args[*arg-1]);
2526 return ACT_RET_PRS_ERR;
2527 }
2528
2529 if (rule->arg.gpc.sc >= MAX_SESS_STKCTR) {
2530 memprintf(err, "invalid stick table track ID. The max allowed ID is %d",
2531 MAX_SESS_STKCTR-1);
2532 return ACT_RET_PRS_ERR;
2533 }
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002534 }
Emeric Brun4d7ada82021-06-30 19:04:16 +02002535 if (c == '1')
2536 rule->action_ptr = action_inc_gpc1;
2537 else
2538 rule->action_ptr = action_inc_gpc0;
2539 }
2540 else {
2541 /* default stick table id. */
2542 memprintf(err, "invalid gpc ID '%s'. Expects sc-set-gpc(<GPC ID>,<Track ID>)", args[*arg-1]);
2543 return ACT_RET_PRS_ERR;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002544 }
2545 rule->action = ACT_CUSTOM;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002546 return ACT_RET_PRS_OK;
2547}
2548
Emeric Brun877b0b52021-06-30 18:57:49 +02002549/* This function sets the gpt at index 'rule->arg.gpt.idx' of the array on the
2550 * tracksc counter of index 'rule->arg.gpt.sc' stored into the <stream> or
2551 * directly in the session <sess> if <stream> is set to NULL. This gpt is
2552 * set to the value computed by the expression 'rule->arg.gpt.expr' or if
2553 * 'rule->arg.gpt.expr' is null directly to the value of 'rule->arg.gpt.value'.
2554 *
2555 * This function always returns ACT_RET_CONT and parameter flags is unused.
2556 */
2557static enum act_return action_set_gpt(struct act_rule *rule, struct proxy *px,
2558 struct session *sess, struct stream *s, int flags)
2559{
2560 void *ptr;
2561 struct stksess *ts;
2562 struct stkctr *stkctr;
2563 unsigned int value = 0;
2564 struct sample *smp;
2565 int smp_opt_dir;
2566
2567 /* Extract the stksess, return OK if no stksess available. */
2568 if (s)
2569 stkctr = &s->stkctr[rule->arg.gpt.sc];
2570 else
2571 stkctr = &sess->stkctr[rule->arg.gpt.sc];
2572
2573 ts = stkctr_entry(stkctr);
2574 if (!ts)
2575 return ACT_RET_CONT;
2576
2577 /* Store the sample in the required sc, and ignore errors. */
2578 ptr = stktable_data_ptr_idx(stkctr->table, ts, STKTABLE_DT_GPT, rule->arg.gpt.idx);
2579 if (ptr) {
2580
2581 if (!rule->arg.gpt.expr)
2582 value = (unsigned int)(rule->arg.gpt.value);
2583 else {
2584 switch (rule->from) {
2585 case ACT_F_TCP_REQ_SES: smp_opt_dir = SMP_OPT_DIR_REQ; break;
2586 case ACT_F_TCP_REQ_CNT: smp_opt_dir = SMP_OPT_DIR_REQ; break;
2587 case ACT_F_TCP_RES_CNT: smp_opt_dir = SMP_OPT_DIR_RES; break;
2588 case ACT_F_HTTP_REQ: smp_opt_dir = SMP_OPT_DIR_REQ; break;
2589 case ACT_F_HTTP_RES: smp_opt_dir = SMP_OPT_DIR_RES; break;
2590 default:
2591 send_log(px, LOG_ERR, "stick table: internal error while setting gpt%u.", rule->arg.gpt.idx);
2592 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))
2593 ha_alert("stick table: internal error while executing setting gpt%u.\n", rule->arg.gpt.idx);
2594 return ACT_RET_CONT;
2595 }
2596
2597 /* Fetch and cast the expression. */
2598 smp = sample_fetch_as_type(px, sess, s, smp_opt_dir|SMP_OPT_FINAL, rule->arg.gpt.expr, SMP_T_SINT);
2599 if (!smp) {
2600 send_log(px, LOG_WARNING, "stick table: invalid expression or data type while setting gpt%u.", rule->arg.gpt.idx);
2601 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))
2602 ha_alert("stick table: invalid expression or data type while setting gpt%u.\n", rule->arg.gpt.idx);
2603 return ACT_RET_CONT;
2604 }
2605 value = (unsigned int)(smp->data.u.sint);
2606 }
2607
2608 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
2609
2610 stktable_data_cast(ptr, std_t_uint) = value;
2611
2612 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
2613
2614 stktable_touch_local(stkctr->table, ts, 0);
2615 }
2616
2617 return ACT_RET_CONT;
2618}
2619
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002620/* Always returns 1. */
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002621static enum act_return action_set_gpt0(struct act_rule *rule, struct proxy *px,
Willy Tarreau658b85b2015-09-27 10:00:49 +02002622 struct session *sess, struct stream *s, int flags)
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002623{
2624 void *ptr;
2625 struct stksess *ts;
2626 struct stkctr *stkctr;
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002627 unsigned int value = 0;
2628 struct sample *smp;
2629 int smp_opt_dir;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002630
2631 /* Extract the stksess, return OK if no stksess available. */
2632 if (s)
2633 stkctr = &s->stkctr[rule->arg.gpt.sc];
2634 else
2635 stkctr = &sess->stkctr[rule->arg.gpt.sc];
Willy Tarreau79c1e912016-01-25 14:54:45 +01002636
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002637 ts = stkctr_entry(stkctr);
2638 if (!ts)
2639 return ACT_RET_CONT;
2640
2641 /* Store the sample in the required sc, and ignore errors. */
2642 ptr = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPT0);
Emeric Brunf7ab0bf2021-06-30 18:58:22 +02002643 if (!ptr)
2644 ptr = stktable_data_ptr_idx(stkctr->table, ts, STKTABLE_DT_GPT, 0);
2645
Willy Tarreau79c1e912016-01-25 14:54:45 +01002646 if (ptr) {
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002647 if (!rule->arg.gpt.expr)
2648 value = (unsigned int)(rule->arg.gpt.value);
2649 else {
2650 switch (rule->from) {
2651 case ACT_F_TCP_REQ_SES: smp_opt_dir = SMP_OPT_DIR_REQ; break;
2652 case ACT_F_TCP_REQ_CNT: smp_opt_dir = SMP_OPT_DIR_REQ; break;
2653 case ACT_F_TCP_RES_CNT: smp_opt_dir = SMP_OPT_DIR_RES; break;
2654 case ACT_F_HTTP_REQ: smp_opt_dir = SMP_OPT_DIR_REQ; break;
2655 case ACT_F_HTTP_RES: smp_opt_dir = SMP_OPT_DIR_RES; break;
2656 default:
2657 send_log(px, LOG_ERR, "stick table: internal error while setting gpt0.");
2658 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))
2659 ha_alert("stick table: internal error while executing setting gpt0.\n");
2660 return ACT_RET_CONT;
2661 }
2662
2663 /* Fetch and cast the expression. */
2664 smp = sample_fetch_as_type(px, sess, s, smp_opt_dir|SMP_OPT_FINAL, rule->arg.gpt.expr, SMP_T_SINT);
2665 if (!smp) {
2666 send_log(px, LOG_WARNING, "stick table: invalid expression or data type while setting gpt0.");
2667 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))
2668 ha_alert("stick table: invalid expression or data type while setting gpt0.\n");
2669 return ACT_RET_CONT;
2670 }
2671 value = (unsigned int)(smp->data.u.sint);
2672 }
2673
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002674 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002675
Emeric Brun0e3457b2021-06-30 17:18:28 +02002676 stktable_data_cast(ptr, std_t_uint) = value;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002677
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002678 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002679
2680 stktable_touch_local(stkctr->table, ts, 0);
Willy Tarreau79c1e912016-01-25 14:54:45 +01002681 }
2682
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002683 return ACT_RET_CONT;
2684}
2685
Emeric Brun877b0b52021-06-30 18:57:49 +02002686/* This function is a parser for the "sc-set-gpt" and "sc-set-gpt0" actions.
2687 * It understands the formats:
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002688 *
Emeric Brun877b0b52021-06-30 18:57:49 +02002689 * sc-set-gpt(<gpt IDX>,<track ID>) <expression>
2690 * sc-set-gpt0(<track ID>) <expression>
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002691 *
Emeric Brun877b0b52021-06-30 18:57:49 +02002692 * It returns ACT_RET_PRS_ERR if fails and <err> is filled with an error message.
2693 * Otherwise, it returns ACT_RET_PRS_OK and the variable 'rule->arg.gpt.expr'
2694 * is filled with the pointer to the expression to execute or NULL if the arg
2695 * is directly an integer stored into 'rule->arg.gpt.value'.
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002696 */
Emeric Brun877b0b52021-06-30 18:57:49 +02002697static enum act_parse_ret parse_set_gpt(const char **args, int *arg, struct proxy *px,
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002698 struct act_rule *rule, char **err)
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002699{
2700 const char *cmd_name = args[*arg-1];
2701 char *error;
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002702 int smp_val;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002703
Emeric Brun877b0b52021-06-30 18:57:49 +02002704 cmd_name += strlen("sc-set-gpt");
2705 if (*cmd_name == '(') {
2706 cmd_name++; /* skip the '(' */
2707 rule->arg.gpt.idx = strtoul(cmd_name, &error, 10); /* Convert stick table id. */
2708 if (*error != ',') {
2709 memprintf(err, "Missing gpt ID '%s'. Expects sc-set-gpt(<GPT ID>,<Track ID>)", args[*arg-1]);
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002710 return ACT_RET_PRS_ERR;
2711 }
Emeric Brun877b0b52021-06-30 18:57:49 +02002712 else {
2713 cmd_name = error + 1; /* skip the ',' */
2714 rule->arg.gpt.sc = strtol(cmd_name, &error, 10); /* Convert stick table id. */
2715 if (*error != ')') {
2716 memprintf(err, "invalid stick table track ID '%s'. Expects sc-set-gpt(<GPT ID>,<Track ID>)", args[*arg-1]);
2717 return ACT_RET_PRS_ERR;
2718 }
2719
2720 if (rule->arg.gpt.sc >= MAX_SESS_STKCTR) {
2721 memprintf(err, "invalid stick table track ID '%s'. The max allowed ID is %d",
2722 args[*arg-1], MAX_SESS_STKCTR-1);
2723 return ACT_RET_PRS_ERR;
2724 }
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002725 }
Emeric Brun877b0b52021-06-30 18:57:49 +02002726 rule->action_ptr = action_set_gpt;
2727 }
2728 else if (*cmd_name == '0') {
2729 cmd_name++;
2730 if (*cmd_name == '\0') {
2731 /* default stick table id. */
2732 rule->arg.gpt.sc = 0;
2733 } else {
2734 /* parse the stick table id. */
2735 if (*cmd_name != '(') {
2736 memprintf(err, "invalid stick table track ID '%s'. Expects sc-set-gpt0(<Track ID>)", args[*arg-1]);
2737 return ACT_RET_PRS_ERR;
2738 }
2739 cmd_name++; /* jump the '(' */
2740 rule->arg.gpt.sc = strtol(cmd_name, &error, 10); /* Convert stick table id. */
2741 if (*error != ')') {
2742 memprintf(err, "invalid stick table track ID '%s'. Expects sc-set-gpt0(<Track ID>)", args[*arg-1]);
2743 return ACT_RET_PRS_ERR;
2744 }
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002745
Emeric Brun877b0b52021-06-30 18:57:49 +02002746 if (rule->arg.gpt.sc >= MAX_SESS_STKCTR) {
2747 memprintf(err, "invalid stick table track ID '%s'. The max allowed ID is %d",
2748 args[*arg-1], MAX_SESS_STKCTR-1);
2749 return ACT_RET_PRS_ERR;
2750 }
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002751 }
Emeric Brun877b0b52021-06-30 18:57:49 +02002752 rule->action_ptr = action_set_gpt0;
2753 }
2754 else {
2755 /* default stick table id. */
2756 memprintf(err, "invalid gpt ID '%s'. Expects sc-set-gpt(<GPT ID>,<Track ID>)", args[*arg-1]);
2757 return ACT_RET_PRS_ERR;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002758 }
2759
Willy Tarreauece4c4a2021-08-24 14:57:28 +02002760 /* value may be either an integer or an expression */
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002761 rule->arg.gpt.expr = NULL;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002762 rule->arg.gpt.value = strtol(args[*arg], &error, 10);
Willy Tarreauece4c4a2021-08-24 14:57:28 +02002763 if (*error == '\0') {
2764 /* valid integer, skip it */
2765 (*arg)++;
2766 } else {
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002767 rule->arg.gpt.expr = sample_parse_expr((char **)args, arg, px->conf.args.file,
Willy Tarreaue3b57bf2020-02-14 16:50:14 +01002768 px->conf.args.line, err, &px->conf.args, NULL);
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002769 if (!rule->arg.gpt.expr)
2770 return ACT_RET_PRS_ERR;
2771
2772 switch (rule->from) {
2773 case ACT_F_TCP_REQ_SES: smp_val = SMP_VAL_FE_SES_ACC; break;
2774 case ACT_F_TCP_REQ_CNT: smp_val = SMP_VAL_FE_REQ_CNT; break;
2775 case ACT_F_TCP_RES_CNT: smp_val = SMP_VAL_BE_RES_CNT; break;
2776 case ACT_F_HTTP_REQ: smp_val = SMP_VAL_FE_HRQ_HDR; break;
2777 case ACT_F_HTTP_RES: smp_val = SMP_VAL_BE_HRS_HDR; break;
2778 default:
2779 memprintf(err, "internal error, unexpected rule->from=%d, please report this bug!", rule->from);
2780 return ACT_RET_PRS_ERR;
2781 }
2782 if (!(rule->arg.gpt.expr->fetch->val & smp_val)) {
2783 memprintf(err, "fetch method '%s' extracts information from '%s', none of which is available here", args[*arg-1],
2784 sample_src_names(rule->arg.gpt.expr->fetch->use));
2785 free(rule->arg.gpt.expr);
2786 return ACT_RET_PRS_ERR;
2787 }
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002788 }
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002789
Thierry FOURNIER42148732015-09-02 17:17:33 +02002790 rule->action = ACT_CUSTOM;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002791
2792 return ACT_RET_PRS_OK;
2793}
2794
Willy Tarreau7d562212016-11-25 16:10:05 +01002795/* set temp integer to the number of used entries in the table pointed to by expr.
2796 * Accepts exactly 1 argument of type table.
2797 */
2798static int
2799smp_fetch_table_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
2800{
2801 smp->flags = SMP_F_VOL_TEST;
2802 smp->data.type = SMP_T_SINT;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002803 smp->data.u.sint = args->data.t->current;
Willy Tarreau7d562212016-11-25 16:10:05 +01002804 return 1;
2805}
2806
2807/* set temp integer to the number of free entries in the table pointed to by expr.
2808 * Accepts exactly 1 argument of type table.
2809 */
2810static int
2811smp_fetch_table_avl(const struct arg *args, struct sample *smp, const char *kw, void *private)
2812{
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002813 struct stktable *t;
Willy Tarreau7d562212016-11-25 16:10:05 +01002814
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002815 t = args->data.t;
Willy Tarreau7d562212016-11-25 16:10:05 +01002816 smp->flags = SMP_F_VOL_TEST;
2817 smp->data.type = SMP_T_SINT;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002818 smp->data.u.sint = t->size - t->current;
Willy Tarreau7d562212016-11-25 16:10:05 +01002819 return 1;
2820}
2821
2822/* Returns a pointer to a stkctr depending on the fetch keyword name.
2823 * It is designed to be called as sc[0-9]_* sc_* or src_* exclusively.
2824 * sc[0-9]_* will return a pointer to the respective field in the
2825 * stream <l4>. sc_* requires an UINT argument specifying the stick
2826 * counter number. src_* will fill a locally allocated structure with
2827 * the table and entry corresponding to what is specified with src_*.
2828 * NULL may be returned if the designated stkctr is not tracked. For
2829 * the sc_* and sc[0-9]_* forms, an optional table argument may be
2830 * passed. When present, the currently tracked key is then looked up
2831 * in the specified table instead of the current table. The purpose is
Ilya Shipitsin47d17182020-06-21 21:42:57 +05002832 * to be able to convert multiple values per key (eg: have gpc0 from
Willy Tarreau7d562212016-11-25 16:10:05 +01002833 * multiple tables). <strm> is allowed to be NULL, in which case only
2834 * the session will be consulted.
2835 */
2836struct stkctr *
Emeric Brun819fc6f2017-06-13 19:37:32 +02002837smp_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 +01002838{
Willy Tarreau7d562212016-11-25 16:10:05 +01002839 struct stkctr *stkptr;
2840 struct stksess *stksess;
2841 unsigned int num = kw[2] - '0';
2842 int arg = 0;
2843
2844 if (num == '_' - '0') {
2845 /* sc_* variant, args[0] = ctr# (mandatory) */
2846 num = args[arg++].data.sint;
Willy Tarreau7d562212016-11-25 16:10:05 +01002847 }
2848 else if (num > 9) { /* src_* variant, args[0] = table */
2849 struct stktable_key *key;
2850 struct connection *conn = objt_conn(sess->origin);
2851 struct sample smp;
2852
2853 if (!conn)
2854 return NULL;
2855
Joseph Herlant5662fa42018-11-15 13:43:28 -08002856 /* Fetch source address in a sample. */
Willy Tarreau7d562212016-11-25 16:10:05 +01002857 smp.px = NULL;
2858 smp.sess = sess;
2859 smp.strm = strm;
Amaury Denoyellec460c702021-05-12 10:17:47 +02002860 if (!smp_fetch_src || !smp_fetch_src(empty_arg_list, &smp, "src", NULL))
Willy Tarreau7d562212016-11-25 16:10:05 +01002861 return NULL;
2862
2863 /* Converts into key. */
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002864 key = smp_to_stkey(&smp, args->data.t);
Willy Tarreau7d562212016-11-25 16:10:05 +01002865 if (!key)
2866 return NULL;
2867
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002868 stkctr->table = args->data.t;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002869 stkctr_set_entry(stkctr, stktable_lookup_key(stkctr->table, key));
2870 return stkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002871 }
2872
2873 /* Here, <num> contains the counter number from 0 to 9 for
2874 * the sc[0-9]_ form, or even higher using sc_(num) if needed.
2875 * args[arg] is the first optional argument. We first lookup the
2876 * ctr form the stream, then from the session if it was not there.
Christopher Fauleta9fa88a2019-10-21 10:53:34 +02002877 * But we must be sure the counter does not exceed MAX_SESS_STKCTR.
Willy Tarreau7d562212016-11-25 16:10:05 +01002878 */
Christopher Fauleta9fa88a2019-10-21 10:53:34 +02002879 if (num >= MAX_SESS_STKCTR)
2880 return NULL;
Willy Tarreau7d562212016-11-25 16:10:05 +01002881
2882 if (strm)
2883 stkptr = &strm->stkctr[num];
2884 if (!strm || !stkctr_entry(stkptr)) {
2885 stkptr = &sess->stkctr[num];
2886 if (!stkctr_entry(stkptr))
2887 return NULL;
2888 }
2889
2890 stksess = stkctr_entry(stkptr);
2891 if (!stksess)
2892 return NULL;
2893
2894 if (unlikely(args[arg].type == ARGT_TAB)) {
2895 /* an alternate table was specified, let's look up the same key there */
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002896 stkctr->table = args[arg].data.t;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002897 stkctr_set_entry(stkctr, stktable_lookup(stkctr->table, stksess));
2898 return stkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002899 }
2900 return stkptr;
2901}
2902
2903/* same as smp_fetch_sc_stkctr() but dedicated to src_* and can create
2904 * the entry if it doesn't exist yet. This is needed for a few fetch
2905 * functions which need to create an entry, such as src_inc_gpc* and
2906 * src_clr_gpc*.
2907 */
2908struct stkctr *
Emeric Brun819fc6f2017-06-13 19:37:32 +02002909smp_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 +01002910{
Willy Tarreau7d562212016-11-25 16:10:05 +01002911 struct stktable_key *key;
2912 struct connection *conn = objt_conn(sess->origin);
2913 struct sample smp;
2914
2915 if (strncmp(kw, "src_", 4) != 0)
2916 return NULL;
2917
2918 if (!conn)
2919 return NULL;
2920
Joseph Herlant5662fa42018-11-15 13:43:28 -08002921 /* Fetch source address in a sample. */
Willy Tarreau7d562212016-11-25 16:10:05 +01002922 smp.px = NULL;
2923 smp.sess = sess;
2924 smp.strm = strm;
Amaury Denoyellec460c702021-05-12 10:17:47 +02002925 if (!smp_fetch_src || !smp_fetch_src(empty_arg_list, &smp, "src", NULL))
Willy Tarreau7d562212016-11-25 16:10:05 +01002926 return NULL;
2927
2928 /* Converts into key. */
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002929 key = smp_to_stkey(&smp, args->data.t);
Willy Tarreau7d562212016-11-25 16:10:05 +01002930 if (!key)
2931 return NULL;
2932
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002933 stkctr->table = args->data.t;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002934 stkctr_set_entry(stkctr, stktable_get_entry(stkctr->table, key));
2935 return stkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002936}
2937
2938/* set return a boolean indicating if the requested stream counter is
2939 * currently being tracked or not.
2940 * Supports being called as "sc[0-9]_tracked" only.
2941 */
2942static int
2943smp_fetch_sc_tracked(const struct arg *args, struct sample *smp, const char *kw, void *private)
2944{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002945 struct stkctr tmpstkctr;
2946 struct stkctr *stkctr;
2947
Willy Tarreau7d562212016-11-25 16:10:05 +01002948 smp->flags = SMP_F_VOL_TEST;
2949 smp->data.type = SMP_T_BOOL;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002950 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2951 smp->data.u.sint = !!stkctr;
2952
2953 /* release the ref count */
Dirkjan Bussinkff57f1b2018-09-14 14:31:22 +02002954 if (stkctr == &tmpstkctr)
Emeric Brun819fc6f2017-06-13 19:37:32 +02002955 stktable_release(stkctr->table, stkctr_entry(stkctr));
2956
Emeric Brun877b0b52021-06-30 18:57:49 +02002957 return 1;
2958}
2959
2960/* set <smp> to the General Purpose Tag of index set as first arg
2961 * to value from the stream's tracked frontend counters or from the src.
2962 * Supports being called as "sc_get_gpt(<gpt-idx>,<sc-idx>[,<table>])" or
2963 * "src_get_gpt(<gpt-idx>[,<table>])" only. Value zero is returned if
2964 * the key is new or gpt is not stored.
2965 */
2966static int
2967smp_fetch_sc_get_gpt(const struct arg *args, struct sample *smp, const char *kw, void *private)
2968{
2969 struct stkctr tmpstkctr;
2970 struct stkctr *stkctr;
2971 unsigned int idx;
2972
2973 idx = args[0].data.sint;
2974
2975 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args + 1, kw, &tmpstkctr);
2976 if (!stkctr)
2977 return 0;
2978
2979 smp->flags = SMP_F_VOL_TEST;
2980 smp->data.type = SMP_T_SINT;
2981 smp->data.u.sint = 0;
2982
2983 if (stkctr_entry(stkctr)) {
2984 void *ptr;
2985
2986 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPT, idx);
2987 if (!ptr) {
2988 if (stkctr == &tmpstkctr)
2989 stktable_release(stkctr->table, stkctr_entry(stkctr));
2990 return 0; /* parameter not stored */
2991 }
2992
2993 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2994
2995 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
2996
2997 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2998
2999 if (stkctr == &tmpstkctr)
3000 stktable_release(stkctr->table, stkctr_entry(stkctr));
3001 }
Willy Tarreau7d562212016-11-25 16:10:05 +01003002 return 1;
3003}
3004
3005/* set <smp> to the General Purpose Flag 0 value from the stream's tracked
3006 * frontend counters or from the src.
3007 * Supports being called as "sc[0-9]_get_gpc0" or "src_get_gpt0" only. Value
3008 * zero is returned if the key is new.
3009 */
3010static int
3011smp_fetch_sc_get_gpt0(const struct arg *args, struct sample *smp, const char *kw, void *private)
3012{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003013 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003014 struct stkctr *stkctr;
3015
Emeric Brun819fc6f2017-06-13 19:37:32 +02003016 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003017 if (!stkctr)
3018 return 0;
3019
3020 smp->flags = SMP_F_VOL_TEST;
3021 smp->data.type = SMP_T_SINT;
3022 smp->data.u.sint = 0;
3023
Emeric Brun819fc6f2017-06-13 19:37:32 +02003024 if (stkctr_entry(stkctr)) {
3025 void *ptr;
3026
3027 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPT0);
Emeric Brunf7ab0bf2021-06-30 18:58:22 +02003028 if (!ptr)
3029 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPT, 0);
3030
Emeric Brun4d7ada82021-06-30 19:04:16 +02003031 if (!ptr) {
3032 if (stkctr == &tmpstkctr)
3033 stktable_release(stkctr->table, stkctr_entry(stkctr));
3034 return 0; /* parameter not stored */
3035 }
3036
3037 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3038
3039 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
3040
3041 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3042
3043 if (stkctr == &tmpstkctr)
3044 stktable_release(stkctr->table, stkctr_entry(stkctr));
3045 }
3046 return 1;
3047}
3048
3049/* set <smp> to the GPC[args(0)]'s value from the stream's tracked
3050 * frontend counters or from the src.
3051 * Supports being called as "sc_get_gpc(<gpc-idx>,<sc-idx>[,<table>])" or
3052 * "src_get_gpc(<gpc-idx>[,<table>])" only. Value
3053 * Value zero is returned if the key is new or gpc is not stored.
3054 */
3055static int
3056smp_fetch_sc_get_gpc(const struct arg *args, struct sample *smp, const char *kw, void *private)
3057{
3058 struct stkctr tmpstkctr;
3059 struct stkctr *stkctr;
3060 unsigned int idx;
3061
3062 idx = args[0].data.sint;
3063
3064 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args + 1, kw, &tmpstkctr);
3065 if (!stkctr)
3066 return 0;
3067
3068 smp->flags = SMP_F_VOL_TEST;
3069 smp->data.type = SMP_T_SINT;
3070 smp->data.u.sint = 0;
3071
3072 if (stkctr_entry(stkctr) != NULL) {
3073 void *ptr;
3074
3075 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC, idx);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003076 if (!ptr) {
3077 if (stkctr == &tmpstkctr)
3078 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003079 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003080 }
3081
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003082 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003083
Emeric Brun0e3457b2021-06-30 17:18:28 +02003084 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003085
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003086 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003087
3088 if (stkctr == &tmpstkctr)
3089 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003090 }
3091 return 1;
3092}
3093
3094/* set <smp> to the General Purpose Counter 0 value from the stream's tracked
3095 * frontend counters or from the src.
3096 * Supports being called as "sc[0-9]_get_gpc0" or "src_get_gpc0" only. Value
3097 * zero is returned if the key is new.
3098 */
3099static int
3100smp_fetch_sc_get_gpc0(const struct arg *args, struct sample *smp, const char *kw, void *private)
3101{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003102 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003103 struct stkctr *stkctr;
3104
Emeric Brun819fc6f2017-06-13 19:37:32 +02003105 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003106 if (!stkctr)
3107 return 0;
3108
3109 smp->flags = SMP_F_VOL_TEST;
3110 smp->data.type = SMP_T_SINT;
3111 smp->data.u.sint = 0;
3112
3113 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003114 void *ptr;
3115
3116 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0);
3117 if (!ptr) {
Emeric Brun726783d2021-06-30 19:06:43 +02003118 /* fallback on the gpc array */
3119 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC, 0);
3120 }
3121
3122 if (!ptr) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003123 if (stkctr == &tmpstkctr)
3124 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003125 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003126 }
3127
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003128 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003129
Emeric Brun0e3457b2021-06-30 17:18:28 +02003130 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003131
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003132 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003133
3134 if (stkctr == &tmpstkctr)
3135 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003136 }
3137 return 1;
3138}
3139
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003140/* set <smp> to the General Purpose Counter 1 value from the stream's tracked
3141 * frontend counters or from the src.
3142 * Supports being called as "sc[0-9]_get_gpc1" or "src_get_gpc1" only. Value
3143 * zero is returned if the key is new.
3144 */
3145static int
3146smp_fetch_sc_get_gpc1(const struct arg *args, struct sample *smp, const char *kw, void *private)
3147{
3148 struct stkctr tmpstkctr;
3149 struct stkctr *stkctr;
3150
3151 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
3152 if (!stkctr)
3153 return 0;
3154
3155 smp->flags = SMP_F_VOL_TEST;
3156 smp->data.type = SMP_T_SINT;
3157 smp->data.u.sint = 0;
3158
3159 if (stkctr_entry(stkctr) != NULL) {
3160 void *ptr;
3161
3162 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1);
3163 if (!ptr) {
Emeric Brun726783d2021-06-30 19:06:43 +02003164 /* fallback on the gpc array */
3165 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC, 1);
3166 }
3167
3168 if (!ptr) {
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003169 if (stkctr == &tmpstkctr)
3170 stktable_release(stkctr->table, stkctr_entry(stkctr));
3171 return 0; /* parameter not stored */
3172 }
3173
3174 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3175
Emeric Brun0e3457b2021-06-30 17:18:28 +02003176 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003177
3178 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3179
3180 if (stkctr == &tmpstkctr)
3181 stktable_release(stkctr->table, stkctr_entry(stkctr));
3182 }
3183 return 1;
3184}
3185
Emeric Brun4d7ada82021-06-30 19:04:16 +02003186/* set <smp> to the GPC[args(0)]'s event rate from the stream's
3187 * tracked frontend counters or from the src.
3188 * Supports being called as "sc_gpc_rate(<gpc-idx>,<sc-idx>[,<table])"
3189 * or "src_gpc_rate(<gpc-idx>[,<table>])" only.
3190 * Value zero is returned if the key is new or gpc_rate is not stored.
3191 */
3192static int
3193smp_fetch_sc_gpc_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3194{
3195 struct stkctr tmpstkctr;
3196 struct stkctr *stkctr;
3197 unsigned int idx;
3198
3199 idx = args[0].data.sint;
3200
3201 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args + 1, kw, &tmpstkctr);
3202 if (!stkctr)
3203 return 0;
3204
3205 smp->flags = SMP_F_VOL_TEST;
3206 smp->data.type = SMP_T_SINT;
3207 smp->data.u.sint = 0;
3208 if (stkctr_entry(stkctr) != NULL) {
3209 void *ptr;
3210
3211 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC_RATE, idx);
3212 if (!ptr) {
3213 if (stkctr == &tmpstkctr)
3214 stktable_release(stkctr->table, stkctr_entry(stkctr));
3215 return 0; /* parameter not stored */
3216 }
3217
3218 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3219
3220 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
3221 stkctr->table->data_arg[STKTABLE_DT_GPC_RATE].u);
3222
3223 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3224
3225 if (stkctr == &tmpstkctr)
3226 stktable_release(stkctr->table, stkctr_entry(stkctr));
3227 }
3228 return 1;
3229}
3230
Willy Tarreau7d562212016-11-25 16:10:05 +01003231/* set <smp> to the General Purpose Counter 0's event rate from the stream's
3232 * tracked frontend counters or from the src.
3233 * Supports being called as "sc[0-9]_gpc0_rate" or "src_gpc0_rate" only.
3234 * Value zero is returned if the key is new.
3235 */
3236static int
3237smp_fetch_sc_gpc0_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3238{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003239 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003240 struct stkctr *stkctr;
Emeric Brun726783d2021-06-30 19:06:43 +02003241 unsigned int period;
Willy Tarreau7d562212016-11-25 16:10:05 +01003242
Emeric Brun819fc6f2017-06-13 19:37:32 +02003243 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003244 if (!stkctr)
3245 return 0;
3246
3247 smp->flags = SMP_F_VOL_TEST;
3248 smp->data.type = SMP_T_SINT;
3249 smp->data.u.sint = 0;
3250 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003251 void *ptr;
3252
3253 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0_RATE);
Emeric Brun726783d2021-06-30 19:06:43 +02003254 if (ptr) {
3255 period = stkctr->table->data_arg[STKTABLE_DT_GPC0_RATE].u;
3256 }
3257 else {
3258 /* fallback on the gpc array */
3259 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC_RATE, 0);
3260 if (ptr)
3261 period = stkctr->table->data_arg[STKTABLE_DT_GPC_RATE].u;
3262 }
3263
Emeric Brun819fc6f2017-06-13 19:37:32 +02003264 if (!ptr) {
3265 if (stkctr == &tmpstkctr)
3266 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003267 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003268 }
3269
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003270 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003271
Emeric Brun726783d2021-06-30 19:06:43 +02003272 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp), period);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003273
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003274 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003275
3276 if (stkctr == &tmpstkctr)
3277 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003278 }
3279 return 1;
3280}
3281
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003282/* set <smp> to the General Purpose Counter 1's event rate from the stream's
3283 * tracked frontend counters or from the src.
3284 * Supports being called as "sc[0-9]_gpc1_rate" or "src_gpc1_rate" only.
3285 * Value zero is returned if the key is new.
3286 */
3287static int
3288smp_fetch_sc_gpc1_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3289{
3290 struct stkctr tmpstkctr;
3291 struct stkctr *stkctr;
Emeric Brun726783d2021-06-30 19:06:43 +02003292 unsigned int period;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003293
3294 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
3295 if (!stkctr)
3296 return 0;
3297
3298 smp->flags = SMP_F_VOL_TEST;
3299 smp->data.type = SMP_T_SINT;
3300 smp->data.u.sint = 0;
3301 if (stkctr_entry(stkctr) != NULL) {
3302 void *ptr;
3303
3304 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1_RATE);
Emeric Brun726783d2021-06-30 19:06:43 +02003305 if (ptr) {
3306 period = stkctr->table->data_arg[STKTABLE_DT_GPC1_RATE].u;
3307 }
3308 else {
3309 /* fallback on the gpc array */
3310 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC_RATE, 1);
3311 if (ptr)
3312 period = stkctr->table->data_arg[STKTABLE_DT_GPC_RATE].u;
3313 }
3314
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003315 if (!ptr) {
3316 if (stkctr == &tmpstkctr)
3317 stktable_release(stkctr->table, stkctr_entry(stkctr));
3318 return 0; /* parameter not stored */
3319 }
3320
3321 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3322
Emeric Brun726783d2021-06-30 19:06:43 +02003323 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 +01003324
3325 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3326
3327 if (stkctr == &tmpstkctr)
3328 stktable_release(stkctr->table, stkctr_entry(stkctr));
3329 }
3330 return 1;
3331}
3332
Emeric Brun4d7ada82021-06-30 19:04:16 +02003333/* Increment the GPC[args(0)] value from the stream's tracked
3334 * frontend counters and return it into temp integer.
3335 * Supports being called as "sc_inc_gpc(<gpc-idx>,<sc-idx>[,<table>])"
3336 * or "src_inc_gpc(<gpc-idx>[,<table>])" only.
3337 */
3338static int
3339smp_fetch_sc_inc_gpc(const struct arg *args, struct sample *smp, const char *kw, void *private)
3340{
3341 struct stkctr tmpstkctr;
3342 struct stkctr *stkctr;
3343 unsigned int idx;
3344
3345 idx = args[0].data.sint;
3346
3347 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args + 1, kw, &tmpstkctr);
3348 if (!stkctr)
3349 return 0;
3350
3351 smp->flags = SMP_F_VOL_TEST;
3352 smp->data.type = SMP_T_SINT;
3353 smp->data.u.sint = 0;
3354
3355 if (!stkctr_entry(stkctr))
3356 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
3357
3358 if (stkctr && stkctr_entry(stkctr)) {
3359 void *ptr1,*ptr2;
3360
3361
3362 /* First, update gpc0_rate if it's tracked. Second, update its
3363 * gpc0 if tracked. Returns gpc0's value otherwise the curr_ctr.
3364 */
3365 ptr1 = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC_RATE, idx);
3366 ptr2 = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC, idx);
3367 if (ptr1 || ptr2) {
3368 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3369
3370 if (ptr1) {
3371 update_freq_ctr_period(&stktable_data_cast(ptr1, std_t_frqp),
3372 stkctr->table->data_arg[STKTABLE_DT_GPC_RATE].u, 1);
3373 smp->data.u.sint = (&stktable_data_cast(ptr1, std_t_frqp))->curr_ctr;
3374 }
3375
3376 if (ptr2)
3377 smp->data.u.sint = ++stktable_data_cast(ptr2, std_t_uint);
3378
3379 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3380
3381 /* If data was modified, we need to touch to re-schedule sync */
3382 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
3383 }
3384 else if (stkctr == &tmpstkctr)
3385 stktable_release(stkctr->table, stkctr_entry(stkctr));
3386 }
3387 return 1;
3388}
3389
Willy Tarreau7d562212016-11-25 16:10:05 +01003390/* Increment the General Purpose Counter 0 value from the stream's tracked
3391 * frontend counters and return it into temp integer.
3392 * Supports being called as "sc[0-9]_inc_gpc0" or "src_inc_gpc0" only.
3393 */
3394static int
3395smp_fetch_sc_inc_gpc0(const struct arg *args, struct sample *smp, const char *kw, void *private)
3396{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003397 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003398 struct stkctr *stkctr;
Willy Tarreau5b654ad2021-07-06 18:51:12 +02003399 unsigned int period = 0;
Willy Tarreau7d562212016-11-25 16:10:05 +01003400
Emeric Brun819fc6f2017-06-13 19:37:32 +02003401 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003402 if (!stkctr)
3403 return 0;
3404
3405 smp->flags = SMP_F_VOL_TEST;
3406 smp->data.type = SMP_T_SINT;
3407 smp->data.u.sint = 0;
3408
Emeric Brun819fc6f2017-06-13 19:37:32 +02003409 if (!stkctr_entry(stkctr))
3410 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003411
3412 if (stkctr && stkctr_entry(stkctr)) {
3413 void *ptr1,*ptr2;
3414
Emeric Brun819fc6f2017-06-13 19:37:32 +02003415
Willy Tarreau7d562212016-11-25 16:10:05 +01003416 /* First, update gpc0_rate if it's tracked. Second, update its
3417 * gpc0 if tracked. Returns gpc0's value otherwise the curr_ctr.
3418 */
3419 ptr1 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0_RATE);
Emeric Brun726783d2021-06-30 19:06:43 +02003420 if (ptr1) {
3421 period = stkctr->table->data_arg[STKTABLE_DT_GPC0_RATE].u;
3422 }
3423 else {
3424 /* fallback on the gpc array */
3425 ptr1 = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC_RATE, 0);
3426 if (ptr1)
3427 period = stkctr->table->data_arg[STKTABLE_DT_GPC_RATE].u;
3428 }
3429
Willy Tarreau7d562212016-11-25 16:10:05 +01003430 ptr2 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0);
Emeric Brun726783d2021-06-30 19:06:43 +02003431 if (!ptr2) {
3432 /* fallback on the gpc array */
3433 ptr2 = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC, 0);
3434 }
3435
Emeric Brun819fc6f2017-06-13 19:37:32 +02003436 if (ptr1 || ptr2) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003437 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Willy Tarreau7d562212016-11-25 16:10:05 +01003438
Emeric Brun819fc6f2017-06-13 19:37:32 +02003439 if (ptr1) {
Emeric Brun0e3457b2021-06-30 17:18:28 +02003440 update_freq_ctr_period(&stktable_data_cast(ptr1, std_t_frqp),
Emeric Brun726783d2021-06-30 19:06:43 +02003441 period, 1);
Emeric Brun0e3457b2021-06-30 17:18:28 +02003442 smp->data.u.sint = (&stktable_data_cast(ptr1, std_t_frqp))->curr_ctr;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003443 }
3444
3445 if (ptr2)
Emeric Brun0e3457b2021-06-30 17:18:28 +02003446 smp->data.u.sint = ++stktable_data_cast(ptr2, std_t_uint);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003447
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003448 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003449
3450 /* If data was modified, we need to touch to re-schedule sync */
3451 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
3452 }
3453 else if (stkctr == &tmpstkctr)
3454 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003455 }
3456 return 1;
3457}
3458
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003459/* Increment the General Purpose Counter 1 value from the stream's tracked
3460 * frontend counters and return it into temp integer.
3461 * Supports being called as "sc[0-9]_inc_gpc1" or "src_inc_gpc1" only.
3462 */
3463static int
3464smp_fetch_sc_inc_gpc1(const struct arg *args, struct sample *smp, const char *kw, void *private)
3465{
3466 struct stkctr tmpstkctr;
3467 struct stkctr *stkctr;
Willy Tarreau5b654ad2021-07-06 18:51:12 +02003468 unsigned int period = 0;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003469
3470 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
3471 if (!stkctr)
3472 return 0;
3473
3474 smp->flags = SMP_F_VOL_TEST;
3475 smp->data.type = SMP_T_SINT;
3476 smp->data.u.sint = 0;
3477
3478 if (!stkctr_entry(stkctr))
3479 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
3480
3481 if (stkctr && stkctr_entry(stkctr)) {
3482 void *ptr1,*ptr2;
3483
3484
3485 /* First, update gpc1_rate if it's tracked. Second, update its
3486 * gpc1 if tracked. Returns gpc1's value otherwise the curr_ctr.
3487 */
3488 ptr1 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1_RATE);
Emeric Brun726783d2021-06-30 19:06:43 +02003489 if (ptr1) {
3490 period = stkctr->table->data_arg[STKTABLE_DT_GPC1_RATE].u;
3491 }
3492 else {
3493 /* fallback on the gpc array */
3494 ptr1 = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC_RATE, 1);
3495 if (ptr1)
3496 period = stkctr->table->data_arg[STKTABLE_DT_GPC_RATE].u;
3497 }
3498
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003499 ptr2 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1);
Emeric Brun726783d2021-06-30 19:06:43 +02003500 if (!ptr2) {
3501 /* fallback on the gpc array */
3502 ptr2 = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC, 1);
3503 }
3504
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003505 if (ptr1 || ptr2) {
3506 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3507
3508 if (ptr1) {
Emeric Brun0e3457b2021-06-30 17:18:28 +02003509 update_freq_ctr_period(&stktable_data_cast(ptr1, std_t_frqp),
Emeric Brun726783d2021-06-30 19:06:43 +02003510 period, 1);
Emeric Brun0e3457b2021-06-30 17:18:28 +02003511 smp->data.u.sint = (&stktable_data_cast(ptr1, std_t_frqp))->curr_ctr;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003512 }
3513
3514 if (ptr2)
Emeric Brun0e3457b2021-06-30 17:18:28 +02003515 smp->data.u.sint = ++stktable_data_cast(ptr2, std_t_uint);
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003516
3517 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3518
3519 /* If data was modified, we need to touch to re-schedule sync */
3520 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
3521 }
3522 else if (stkctr == &tmpstkctr)
3523 stktable_release(stkctr->table, stkctr_entry(stkctr));
3524 }
3525 return 1;
3526}
3527
Emeric Brun4d7ada82021-06-30 19:04:16 +02003528/* Clear the GPC[args(0)] value from the stream's tracked
3529 * frontend counters and return its previous value into temp integer.
3530 * Supports being called as "sc_clr_gpc(<gpc-idx>,<sc-idx>[,<table>])"
3531 * or "src_clr_gpc(<gpc-idx>[,<table>])" only.
3532 */
3533static int
3534smp_fetch_sc_clr_gpc(const struct arg *args, struct sample *smp, const char *kw, void *private)
3535{
3536 struct stkctr tmpstkctr;
3537 struct stkctr *stkctr;
3538 unsigned int idx;
3539
3540 idx = args[0].data.sint;
3541
3542 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args + 1, kw, &tmpstkctr);
3543 if (!stkctr)
3544 return 0;
3545
3546 smp->flags = SMP_F_VOL_TEST;
3547 smp->data.type = SMP_T_SINT;
3548 smp->data.u.sint = 0;
3549
3550 if (!stkctr_entry(stkctr))
3551 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
3552
3553 if (stkctr && stkctr_entry(stkctr)) {
3554 void *ptr;
3555
3556 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC, idx);
3557 if (!ptr) {
3558 if (stkctr == &tmpstkctr)
3559 stktable_release(stkctr->table, stkctr_entry(stkctr));
3560 return 0; /* parameter not stored */
3561 }
3562
3563 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3564
3565 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
3566 stktable_data_cast(ptr, std_t_uint) = 0;
3567
3568 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3569
3570 /* If data was modified, we need to touch to re-schedule sync */
3571 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
3572 }
3573 return 1;
3574}
3575
Willy Tarreau7d562212016-11-25 16:10:05 +01003576/* Clear the General Purpose Counter 0 value from the stream's tracked
3577 * frontend counters and return its previous value into temp integer.
3578 * Supports being called as "sc[0-9]_clr_gpc0" or "src_clr_gpc0" only.
3579 */
3580static int
3581smp_fetch_sc_clr_gpc0(const struct arg *args, struct sample *smp, const char *kw, void *private)
3582{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003583 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003584 struct stkctr *stkctr;
3585
Emeric Brun819fc6f2017-06-13 19:37:32 +02003586 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003587 if (!stkctr)
3588 return 0;
3589
3590 smp->flags = SMP_F_VOL_TEST;
3591 smp->data.type = SMP_T_SINT;
3592 smp->data.u.sint = 0;
3593
Emeric Brun819fc6f2017-06-13 19:37:32 +02003594 if (!stkctr_entry(stkctr))
3595 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003596
Emeric Brun819fc6f2017-06-13 19:37:32 +02003597 if (stkctr && stkctr_entry(stkctr)) {
3598 void *ptr;
3599
3600 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0);
3601 if (!ptr) {
Emeric Brun726783d2021-06-30 19:06:43 +02003602 /* fallback on the gpc array */
3603 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC, 0);
3604 }
3605
3606 if (!ptr) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003607 if (stkctr == &tmpstkctr)
3608 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003609 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003610 }
3611
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003612 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003613
Emeric Brun0e3457b2021-06-30 17:18:28 +02003614 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
3615 stktable_data_cast(ptr, std_t_uint) = 0;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003616
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003617 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003618
Willy Tarreau7d562212016-11-25 16:10:05 +01003619 /* If data was modified, we need to touch to re-schedule sync */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003620 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
Willy Tarreau7d562212016-11-25 16:10:05 +01003621 }
3622 return 1;
3623}
3624
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003625/* Clear the General Purpose Counter 1 value from the stream's tracked
3626 * frontend counters and return its previous value into temp integer.
3627 * Supports being called as "sc[0-9]_clr_gpc1" or "src_clr_gpc1" only.
3628 */
3629static int
3630smp_fetch_sc_clr_gpc1(const struct arg *args, struct sample *smp, const char *kw, void *private)
3631{
3632 struct stkctr tmpstkctr;
3633 struct stkctr *stkctr;
3634
3635 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
3636 if (!stkctr)
3637 return 0;
3638
3639 smp->flags = SMP_F_VOL_TEST;
3640 smp->data.type = SMP_T_SINT;
3641 smp->data.u.sint = 0;
3642
3643 if (!stkctr_entry(stkctr))
3644 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
3645
3646 if (stkctr && stkctr_entry(stkctr)) {
3647 void *ptr;
3648
3649 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1);
3650 if (!ptr) {
Emeric Brun726783d2021-06-30 19:06:43 +02003651 /* fallback on the gpc array */
3652 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC, 1);
3653 }
3654
3655 if (!ptr) {
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003656 if (stkctr == &tmpstkctr)
3657 stktable_release(stkctr->table, stkctr_entry(stkctr));
3658 return 0; /* parameter not stored */
3659 }
3660
3661 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3662
Emeric Brun0e3457b2021-06-30 17:18:28 +02003663 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
3664 stktable_data_cast(ptr, std_t_uint) = 0;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003665
3666 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3667
3668 /* If data was modified, we need to touch to re-schedule sync */
3669 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
3670 }
3671 return 1;
3672}
3673
Willy Tarreau7d562212016-11-25 16:10:05 +01003674/* set <smp> to the cumulated number of connections from the stream's tracked
3675 * frontend counters. Supports being called as "sc[0-9]_conn_cnt" or
3676 * "src_conn_cnt" only.
3677 */
3678static int
3679smp_fetch_sc_conn_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
3680{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003681 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003682 struct stkctr *stkctr;
3683
Emeric Brun819fc6f2017-06-13 19:37:32 +02003684 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003685 if (!stkctr)
3686 return 0;
3687
3688 smp->flags = SMP_F_VOL_TEST;
3689 smp->data.type = SMP_T_SINT;
3690 smp->data.u.sint = 0;
3691 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003692 void *ptr;
3693
3694 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_CONN_CNT);
3695 if (!ptr) {
3696 if (stkctr == &tmpstkctr)
3697 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003698 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003699 }
3700
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003701 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003702
Emeric Brun0e3457b2021-06-30 17:18:28 +02003703 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003704
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003705 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003706
3707 if (stkctr == &tmpstkctr)
3708 stktable_release(stkctr->table, stkctr_entry(stkctr));
3709
3710
Willy Tarreau7d562212016-11-25 16:10:05 +01003711 }
3712 return 1;
3713}
3714
3715/* set <smp> to the connection rate from the stream's tracked frontend
3716 * counters. Supports being called as "sc[0-9]_conn_rate" or "src_conn_rate"
3717 * only.
3718 */
3719static int
3720smp_fetch_sc_conn_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3721{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003722 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003723 struct stkctr *stkctr;
3724
Emeric Brun819fc6f2017-06-13 19:37:32 +02003725 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003726 if (!stkctr)
3727 return 0;
3728
3729 smp->flags = SMP_F_VOL_TEST;
3730 smp->data.type = SMP_T_SINT;
3731 smp->data.u.sint = 0;
3732 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003733 void *ptr;
3734
3735 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_CONN_RATE);
3736 if (!ptr) {
3737 if (stkctr == &tmpstkctr)
3738 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003739 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003740 }
3741
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003742 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003743
Emeric Brun0e3457b2021-06-30 17:18:28 +02003744 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Willy Tarreau7d562212016-11-25 16:10:05 +01003745 stkctr->table->data_arg[STKTABLE_DT_CONN_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003746
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003747 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003748
3749 if (stkctr == &tmpstkctr)
3750 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003751 }
3752 return 1;
3753}
3754
3755/* set temp integer to the number of connections from the stream's source address
3756 * in the table pointed to by expr, after updating it.
3757 * Accepts exactly 1 argument of type table.
3758 */
3759static int
3760smp_fetch_src_updt_conn_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
3761{
3762 struct connection *conn = objt_conn(smp->sess->origin);
3763 struct stksess *ts;
3764 struct stktable_key *key;
3765 void *ptr;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003766 struct stktable *t;
Willy Tarreau7d562212016-11-25 16:10:05 +01003767
3768 if (!conn)
3769 return 0;
3770
Joseph Herlant5662fa42018-11-15 13:43:28 -08003771 /* Fetch source address in a sample. */
Amaury Denoyellec460c702021-05-12 10:17:47 +02003772 if (!smp_fetch_src || !smp_fetch_src(empty_arg_list, smp, "src", NULL))
Willy Tarreau7d562212016-11-25 16:10:05 +01003773 return 0;
3774
3775 /* Converts into key. */
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003776 key = smp_to_stkey(smp, args->data.t);
Willy Tarreau7d562212016-11-25 16:10:05 +01003777 if (!key)
3778 return 0;
3779
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003780 t = args->data.t;
Willy Tarreau7d562212016-11-25 16:10:05 +01003781
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003782 if ((ts = stktable_get_entry(t, key)) == NULL)
Willy Tarreau7d562212016-11-25 16:10:05 +01003783 /* entry does not exist and could not be created */
3784 return 0;
3785
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003786 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_CONN_CNT);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003787 if (!ptr) {
Willy Tarreau7d562212016-11-25 16:10:05 +01003788 return 0; /* parameter not stored in this table */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003789 }
Willy Tarreau7d562212016-11-25 16:10:05 +01003790
3791 smp->data.type = SMP_T_SINT;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003792
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003793 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003794
Emeric Brun0e3457b2021-06-30 17:18:28 +02003795 smp->data.u.sint = ++stktable_data_cast(ptr, std_t_uint);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003796
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003797 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003798
Willy Tarreau7d562212016-11-25 16:10:05 +01003799 smp->flags = SMP_F_VOL_TEST;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003800
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003801 stktable_touch_local(t, ts, 1);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003802
3803 /* Touch was previously performed by stktable_update_key */
Willy Tarreau7d562212016-11-25 16:10:05 +01003804 return 1;
3805}
3806
3807/* set <smp> to the number of concurrent connections from the stream's tracked
3808 * frontend counters. Supports being called as "sc[0-9]_conn_cur" or
3809 * "src_conn_cur" only.
3810 */
3811static int
3812smp_fetch_sc_conn_cur(const struct arg *args, struct sample *smp, const char *kw, void *private)
3813{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003814 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003815 struct stkctr *stkctr;
3816
Emeric Brun819fc6f2017-06-13 19:37:32 +02003817 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003818 if (!stkctr)
3819 return 0;
3820
3821 smp->flags = SMP_F_VOL_TEST;
3822 smp->data.type = SMP_T_SINT;
3823 smp->data.u.sint = 0;
3824 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003825 void *ptr;
3826
3827 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_CONN_CUR);
3828 if (!ptr) {
3829 if (stkctr == &tmpstkctr)
3830 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003831 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003832 }
3833
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003834 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003835
Emeric Brun0e3457b2021-06-30 17:18:28 +02003836 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003837
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003838 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003839
3840 if (stkctr == &tmpstkctr)
3841 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003842 }
3843 return 1;
3844}
3845
3846/* set <smp> to the cumulated number of streams from the stream's tracked
3847 * frontend counters. Supports being called as "sc[0-9]_sess_cnt" or
3848 * "src_sess_cnt" only.
3849 */
3850static int
3851smp_fetch_sc_sess_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
3852{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003853 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003854 struct stkctr *stkctr;
3855
Emeric Brun819fc6f2017-06-13 19:37:32 +02003856 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003857 if (!stkctr)
3858 return 0;
3859
3860 smp->flags = SMP_F_VOL_TEST;
3861 smp->data.type = SMP_T_SINT;
3862 smp->data.u.sint = 0;
3863 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003864 void *ptr;
3865
3866 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_SESS_CNT);
3867 if (!ptr) {
3868 if (stkctr == &tmpstkctr)
3869 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003870 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003871 }
3872
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003873 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003874
Emeric Brun0e3457b2021-06-30 17:18:28 +02003875 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003876
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003877 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003878
3879 if (stkctr == &tmpstkctr)
3880 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003881 }
3882 return 1;
3883}
3884
3885/* set <smp> to the stream rate from the stream's tracked frontend counters.
3886 * Supports being called as "sc[0-9]_sess_rate" or "src_sess_rate" only.
3887 */
3888static int
3889smp_fetch_sc_sess_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3890{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003891 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003892 struct stkctr *stkctr;
3893
Emeric Brun819fc6f2017-06-13 19:37:32 +02003894 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003895 if (!stkctr)
3896 return 0;
3897
3898 smp->flags = SMP_F_VOL_TEST;
3899 smp->data.type = SMP_T_SINT;
3900 smp->data.u.sint = 0;
3901 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003902 void *ptr;
3903
3904 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_SESS_RATE);
3905 if (!ptr) {
3906 if (stkctr == &tmpstkctr)
3907 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003908 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003909 }
3910
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003911 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003912
Emeric Brun0e3457b2021-06-30 17:18:28 +02003913 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Willy Tarreau7d562212016-11-25 16:10:05 +01003914 stkctr->table->data_arg[STKTABLE_DT_SESS_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003915
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003916 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003917
3918 if (stkctr == &tmpstkctr)
3919 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003920 }
3921 return 1;
3922}
3923
3924/* set <smp> to the cumulated number of HTTP requests from the stream's tracked
3925 * frontend counters. Supports being called as "sc[0-9]_http_req_cnt" or
3926 * "src_http_req_cnt" only.
3927 */
3928static int
3929smp_fetch_sc_http_req_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
3930{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003931 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003932 struct stkctr *stkctr;
3933
Emeric Brun819fc6f2017-06-13 19:37:32 +02003934 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003935 if (!stkctr)
3936 return 0;
3937
3938 smp->flags = SMP_F_VOL_TEST;
3939 smp->data.type = SMP_T_SINT;
3940 smp->data.u.sint = 0;
3941 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003942 void *ptr;
3943
3944 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_REQ_CNT);
3945 if (!ptr) {
3946 if (stkctr == &tmpstkctr)
3947 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003948 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003949 }
3950
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003951 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003952
Emeric Brun0e3457b2021-06-30 17:18:28 +02003953 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003954
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003955 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003956
3957 if (stkctr == &tmpstkctr)
3958 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003959 }
3960 return 1;
3961}
3962
3963/* set <smp> to the HTTP request rate from the stream's tracked frontend
3964 * counters. Supports being called as "sc[0-9]_http_req_rate" or
3965 * "src_http_req_rate" only.
3966 */
3967static int
3968smp_fetch_sc_http_req_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3969{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003970 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003971 struct stkctr *stkctr;
3972
Emeric Brun819fc6f2017-06-13 19:37:32 +02003973 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003974 if (!stkctr)
3975 return 0;
3976
3977 smp->flags = SMP_F_VOL_TEST;
3978 smp->data.type = SMP_T_SINT;
3979 smp->data.u.sint = 0;
3980 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003981 void *ptr;
3982
3983 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_REQ_RATE);
3984 if (!ptr) {
3985 if (stkctr == &tmpstkctr)
3986 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003987 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003988 }
3989
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003990 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003991
Emeric Brun0e3457b2021-06-30 17:18:28 +02003992 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Willy Tarreau7d562212016-11-25 16:10:05 +01003993 stkctr->table->data_arg[STKTABLE_DT_HTTP_REQ_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003994
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003995 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003996
3997 if (stkctr == &tmpstkctr)
3998 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003999 }
4000 return 1;
4001}
4002
4003/* set <smp> to the cumulated number of HTTP requests errors from the stream's
4004 * tracked frontend counters. Supports being called as "sc[0-9]_http_err_cnt" or
4005 * "src_http_err_cnt" only.
4006 */
4007static int
4008smp_fetch_sc_http_err_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
4009{
Emeric Brun819fc6f2017-06-13 19:37:32 +02004010 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01004011 struct stkctr *stkctr;
4012
Emeric Brun819fc6f2017-06-13 19:37:32 +02004013 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01004014 if (!stkctr)
4015 return 0;
4016
4017 smp->flags = SMP_F_VOL_TEST;
4018 smp->data.type = SMP_T_SINT;
4019 smp->data.u.sint = 0;
4020 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02004021 void *ptr;
4022
4023 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_ERR_CNT);
4024 if (!ptr) {
4025 if (stkctr == &tmpstkctr)
4026 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004027 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02004028 }
4029
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004030 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004031
Emeric Brun0e3457b2021-06-30 17:18:28 +02004032 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004033
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004034 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004035
4036 if (stkctr == &tmpstkctr)
4037 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004038 }
4039 return 1;
4040}
4041
4042/* set <smp> to the HTTP request error rate from the stream's tracked frontend
4043 * counters. Supports being called as "sc[0-9]_http_err_rate" or
4044 * "src_http_err_rate" only.
4045 */
4046static int
4047smp_fetch_sc_http_err_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
4048{
Emeric Brun819fc6f2017-06-13 19:37:32 +02004049 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01004050 struct stkctr *stkctr;
4051
Emeric Brun819fc6f2017-06-13 19:37:32 +02004052 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01004053 if (!stkctr)
4054 return 0;
4055
4056 smp->flags = SMP_F_VOL_TEST;
4057 smp->data.type = SMP_T_SINT;
4058 smp->data.u.sint = 0;
4059 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02004060 void *ptr;
4061
4062 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_ERR_RATE);
4063 if (!ptr) {
4064 if (stkctr == &tmpstkctr)
4065 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004066 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02004067 }
4068
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004069 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004070
Emeric Brun0e3457b2021-06-30 17:18:28 +02004071 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Willy Tarreau7d562212016-11-25 16:10:05 +01004072 stkctr->table->data_arg[STKTABLE_DT_HTTP_ERR_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004073
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004074 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004075
4076 if (stkctr == &tmpstkctr)
4077 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004078 }
4079 return 1;
4080}
4081
Willy Tarreau826f3ab2021-02-10 12:07:15 +01004082/* set <smp> to the cumulated number of HTTP response failures from the stream's
4083 * tracked frontend counters. Supports being called as "sc[0-9]_http_fail_cnt" or
4084 * "src_http_fail_cnt" only.
4085 */
4086static int
4087smp_fetch_sc_http_fail_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
4088{
4089 struct stkctr tmpstkctr;
4090 struct stkctr *stkctr;
4091
4092 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
4093 if (!stkctr)
4094 return 0;
4095
4096 smp->flags = SMP_F_VOL_TEST;
4097 smp->data.type = SMP_T_SINT;
4098 smp->data.u.sint = 0;
4099 if (stkctr_entry(stkctr) != NULL) {
4100 void *ptr;
4101
4102 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_FAIL_CNT);
4103 if (!ptr) {
4104 if (stkctr == &tmpstkctr)
4105 stktable_release(stkctr->table, stkctr_entry(stkctr));
4106 return 0; /* parameter not stored */
4107 }
4108
4109 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
4110
Emeric Brun0e3457b2021-06-30 17:18:28 +02004111 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Willy Tarreau826f3ab2021-02-10 12:07:15 +01004112
4113 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
4114
4115 if (stkctr == &tmpstkctr)
4116 stktable_release(stkctr->table, stkctr_entry(stkctr));
4117 }
4118 return 1;
4119}
4120
4121/* set <smp> to the HTTP response failure rate from the stream's tracked frontend
4122 * counters. Supports being called as "sc[0-9]_http_fail_rate" or
4123 * "src_http_fail_rate" only.
4124 */
4125static int
4126smp_fetch_sc_http_fail_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
4127{
4128 struct stkctr tmpstkctr;
4129 struct stkctr *stkctr;
4130
4131 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
4132 if (!stkctr)
4133 return 0;
4134
4135 smp->flags = SMP_F_VOL_TEST;
4136 smp->data.type = SMP_T_SINT;
4137 smp->data.u.sint = 0;
4138 if (stkctr_entry(stkctr) != NULL) {
4139 void *ptr;
4140
4141 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_FAIL_RATE);
4142 if (!ptr) {
4143 if (stkctr == &tmpstkctr)
4144 stktable_release(stkctr->table, stkctr_entry(stkctr));
4145 return 0; /* parameter not stored */
4146 }
4147
4148 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
4149
Emeric Brun0e3457b2021-06-30 17:18:28 +02004150 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Willy Tarreau826f3ab2021-02-10 12:07:15 +01004151 stkctr->table->data_arg[STKTABLE_DT_HTTP_FAIL_RATE].u);
4152
4153 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
4154
4155 if (stkctr == &tmpstkctr)
4156 stktable_release(stkctr->table, stkctr_entry(stkctr));
4157 }
4158 return 1;
4159}
4160
Willy Tarreau7d562212016-11-25 16:10:05 +01004161/* set <smp> to the number of kbytes received from clients, as found in the
4162 * stream's tracked frontend counters. Supports being called as
4163 * "sc[0-9]_kbytes_in" or "src_kbytes_in" only.
4164 */
4165static int
4166smp_fetch_sc_kbytes_in(const struct arg *args, struct sample *smp, const char *kw, void *private)
4167{
Emeric Brun819fc6f2017-06-13 19:37:32 +02004168 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01004169 struct stkctr *stkctr;
4170
Emeric Brun819fc6f2017-06-13 19:37:32 +02004171 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01004172 if (!stkctr)
4173 return 0;
4174
4175 smp->flags = SMP_F_VOL_TEST;
4176 smp->data.type = SMP_T_SINT;
4177 smp->data.u.sint = 0;
4178 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02004179 void *ptr;
4180
4181 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_IN_CNT);
4182 if (!ptr) {
4183 if (stkctr == &tmpstkctr)
4184 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004185 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02004186 }
4187
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004188 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004189
Emeric Brun0e3457b2021-06-30 17:18:28 +02004190 smp->data.u.sint = stktable_data_cast(ptr, std_t_ull) >> 10;
Emeric Brun819fc6f2017-06-13 19:37:32 +02004191
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004192 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004193
4194 if (stkctr == &tmpstkctr)
4195 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004196 }
4197 return 1;
4198}
4199
4200/* set <smp> to the data rate received from clients in bytes/s, as found
4201 * in the stream's tracked frontend counters. Supports being called as
4202 * "sc[0-9]_bytes_in_rate" or "src_bytes_in_rate" only.
4203 */
4204static int
4205smp_fetch_sc_bytes_in_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
4206{
Emeric Brun819fc6f2017-06-13 19:37:32 +02004207 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01004208 struct stkctr *stkctr;
4209
Emeric Brun819fc6f2017-06-13 19:37:32 +02004210 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01004211 if (!stkctr)
4212 return 0;
4213
4214 smp->flags = SMP_F_VOL_TEST;
4215 smp->data.type = SMP_T_SINT;
4216 smp->data.u.sint = 0;
4217 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02004218 void *ptr;
4219
4220 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_IN_RATE);
4221 if (!ptr) {
4222 if (stkctr == &tmpstkctr)
4223 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004224 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02004225 }
4226
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004227 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004228
Emeric Brun0e3457b2021-06-30 17:18:28 +02004229 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Willy Tarreau7d562212016-11-25 16:10:05 +01004230 stkctr->table->data_arg[STKTABLE_DT_BYTES_IN_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004231
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004232 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004233
4234 if (stkctr == &tmpstkctr)
4235 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004236 }
4237 return 1;
4238}
4239
4240/* set <smp> to the number of kbytes sent to clients, as found in the
4241 * stream's tracked frontend counters. Supports being called as
4242 * "sc[0-9]_kbytes_out" or "src_kbytes_out" only.
4243 */
4244static int
4245smp_fetch_sc_kbytes_out(const struct arg *args, struct sample *smp, const char *kw, void *private)
4246{
Emeric Brun819fc6f2017-06-13 19:37:32 +02004247 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01004248 struct stkctr *stkctr;
4249
Emeric Brun819fc6f2017-06-13 19:37:32 +02004250 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01004251 if (!stkctr)
4252 return 0;
4253
4254 smp->flags = SMP_F_VOL_TEST;
4255 smp->data.type = SMP_T_SINT;
4256 smp->data.u.sint = 0;
4257 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02004258 void *ptr;
4259
4260 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_OUT_CNT);
4261 if (!ptr) {
4262 if (stkctr == &tmpstkctr)
4263 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004264 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02004265 }
4266
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004267 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004268
Emeric Brun0e3457b2021-06-30 17:18:28 +02004269 smp->data.u.sint = stktable_data_cast(ptr, std_t_ull) >> 10;
Emeric Brun819fc6f2017-06-13 19:37:32 +02004270
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004271 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004272
4273 if (stkctr == &tmpstkctr)
4274 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004275 }
4276 return 1;
4277}
4278
4279/* set <smp> to the data rate sent to clients in bytes/s, as found in the
4280 * stream's tracked frontend counters. Supports being called as
4281 * "sc[0-9]_bytes_out_rate" or "src_bytes_out_rate" only.
4282 */
4283static int
4284smp_fetch_sc_bytes_out_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
4285{
Emeric Brun819fc6f2017-06-13 19:37:32 +02004286 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01004287 struct stkctr *stkctr;
4288
Emeric Brun819fc6f2017-06-13 19:37:32 +02004289 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01004290 if (!stkctr)
4291 return 0;
4292
4293 smp->flags = SMP_F_VOL_TEST;
4294 smp->data.type = SMP_T_SINT;
4295 smp->data.u.sint = 0;
4296 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02004297 void *ptr;
4298
4299 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_OUT_RATE);
4300 if (!ptr) {
4301 if (stkctr == &tmpstkctr)
4302 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004303 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02004304 }
4305
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004306 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004307
Emeric Brun0e3457b2021-06-30 17:18:28 +02004308 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Willy Tarreau7d562212016-11-25 16:10:05 +01004309 stkctr->table->data_arg[STKTABLE_DT_BYTES_OUT_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004310
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004311 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004312
4313 if (stkctr == &tmpstkctr)
4314 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004315 }
4316 return 1;
4317}
4318
4319/* set <smp> to the number of active trackers on the SC entry in the stream's
4320 * tracked frontend counters. Supports being called as "sc[0-9]_trackers" only.
4321 */
4322static int
4323smp_fetch_sc_trackers(const struct arg *args, struct sample *smp, const char *kw, void *private)
4324{
Emeric Brun819fc6f2017-06-13 19:37:32 +02004325 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01004326 struct stkctr *stkctr;
4327
Emeric Brun819fc6f2017-06-13 19:37:32 +02004328 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01004329 if (!stkctr)
4330 return 0;
4331
4332 smp->flags = SMP_F_VOL_TEST;
4333 smp->data.type = SMP_T_SINT;
Emeric Brun819fc6f2017-06-13 19:37:32 +02004334 if (stkctr == &tmpstkctr) {
4335 smp->data.u.sint = stkctr_entry(stkctr) ? (stkctr_entry(stkctr)->ref_cnt-1) : 0;
4336 stktable_release(stkctr->table, stkctr_entry(stkctr));
4337 }
4338 else {
4339 smp->data.u.sint = stkctr_entry(stkctr) ? stkctr_entry(stkctr)->ref_cnt : 0;
4340 }
4341
Willy Tarreau7d562212016-11-25 16:10:05 +01004342 return 1;
4343}
4344
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004345
4346/* The functions below are used to manipulate table contents from the CLI.
4347 * There are 3 main actions, "clear", "set" and "show". The code is shared
4348 * between all actions, and the action is encoded in the void *private in
4349 * the appctx as well as in the keyword registration, among one of the
4350 * following values.
4351 */
4352
4353enum {
4354 STK_CLI_ACT_CLR,
4355 STK_CLI_ACT_SET,
4356 STK_CLI_ACT_SHOW,
4357};
4358
Willy Tarreau4596fe22022-05-17 19:07:51 +02004359/* Dump the status of a table to a stream connector's
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004360 * read buffer. It returns 0 if the output buffer is full
4361 * and needs to be called again, otherwise non-zero.
4362 */
Willy Tarreau83061a82018-07-13 11:56:34 +02004363static int table_dump_head_to_buffer(struct buffer *msg,
Willy Tarreaud0a06d52022-05-18 15:07:19 +02004364 struct appctx *appctx,
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004365 struct stktable *t, struct stktable *target)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004366{
Willy Tarreauc12b3212022-05-27 11:08:15 +02004367 struct stream *s = __sc_strm(appctx_sc(appctx));
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004368
4369 chunk_appendf(msg, "# table: %s, type: %s, size:%d, used:%d\n",
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004370 t->id, stktable_types[t->type].kw, t->size, t->current);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004371
4372 /* any other information should be dumped here */
4373
William Lallemand07a62f72017-05-24 00:57:40 +02004374 if (target && (strm_li(s)->bind_conf->level & ACCESS_LVL_MASK) < ACCESS_LVL_OPER)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004375 chunk_appendf(msg, "# contents not dumped due to insufficient privileges\n");
4376
Willy Tarreaud0a06d52022-05-18 15:07:19 +02004377 if (applet_putchk(appctx, msg) == -1)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004378 return 0;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004379
4380 return 1;
4381}
4382
Willy Tarreau4596fe22022-05-17 19:07:51 +02004383/* Dump a table entry to a stream connector's
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004384 * read buffer. It returns 0 if the output buffer is full
4385 * and needs to be called again, otherwise non-zero.
4386 */
Willy Tarreau83061a82018-07-13 11:56:34 +02004387static int table_dump_entry_to_buffer(struct buffer *msg,
Willy Tarreaud0a06d52022-05-18 15:07:19 +02004388 struct appctx *appctx,
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004389 struct stktable *t, struct stksess *entry)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004390{
4391 int dt;
4392
4393 chunk_appendf(msg, "%p:", entry);
4394
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004395 if (t->type == SMP_T_IPV4) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004396 char addr[INET_ADDRSTRLEN];
4397 inet_ntop(AF_INET, (const void *)&entry->key.key, addr, sizeof(addr));
4398 chunk_appendf(msg, " key=%s", addr);
4399 }
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004400 else if (t->type == SMP_T_IPV6) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004401 char addr[INET6_ADDRSTRLEN];
4402 inet_ntop(AF_INET6, (const void *)&entry->key.key, addr, sizeof(addr));
4403 chunk_appendf(msg, " key=%s", addr);
4404 }
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004405 else if (t->type == SMP_T_SINT) {
Willy Tarreau6cde5d82020-02-25 09:41:22 +01004406 chunk_appendf(msg, " key=%u", read_u32(entry->key.key));
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004407 }
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004408 else if (t->type == SMP_T_STR) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004409 chunk_appendf(msg, " key=");
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004410 dump_text(msg, (const char *)entry->key.key, t->key_size);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004411 }
4412 else {
4413 chunk_appendf(msg, " key=");
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004414 dump_binary(msg, (const char *)entry->key.key, t->key_size);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004415 }
4416
4417 chunk_appendf(msg, " use=%d exp=%d", entry->ref_cnt - 1, tick_remain(now_ms, entry->expire));
4418
4419 for (dt = 0; dt < STKTABLE_DATA_TYPES; dt++) {
4420 void *ptr;
4421
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004422 if (t->data_ofs[dt] == 0)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004423 continue;
Emeric Brunc64a2a32021-06-30 18:01:02 +02004424 if (stktable_data_types[dt].is_array) {
4425 char tmp[16] = {};
4426 const char *name_pfx = stktable_data_types[dt].name;
4427 const char *name_sfx = NULL;
4428 unsigned int idx = 0;
4429 int i = 0;
4430
4431 /* split name to show index before first _ of the name
4432 * for example: 'gpc3_rate' if array name is 'gpc_rate'.
4433 */
4434 for (i = 0 ; i < (sizeof(tmp) - 1); i++) {
4435 if (!name_pfx[i])
4436 break;
4437 if (name_pfx[i] == '_') {
4438 name_pfx = &tmp[0];
4439 name_sfx = &stktable_data_types[dt].name[i];
4440 break;
4441 }
4442 tmp[i] = name_pfx[i];
4443 }
4444
4445 ptr = stktable_data_ptr_idx(t, entry, dt, idx);
4446 while (ptr) {
4447 if (stktable_data_types[dt].arg_type == ARG_T_DELAY)
4448 chunk_appendf(msg, " %s%u%s(%u)=", name_pfx, idx, name_sfx ? name_sfx : "", t->data_arg[dt].u);
4449 else
4450 chunk_appendf(msg, " %s%u%s=", name_pfx, idx, name_sfx ? name_sfx : "");
4451 switch (stktable_data_types[dt].std_type) {
4452 case STD_T_SINT:
4453 chunk_appendf(msg, "%d", stktable_data_cast(ptr, std_t_sint));
4454 break;
4455 case STD_T_UINT:
4456 chunk_appendf(msg, "%u", stktable_data_cast(ptr, std_t_uint));
4457 break;
4458 case STD_T_ULL:
4459 chunk_appendf(msg, "%llu", stktable_data_cast(ptr, std_t_ull));
4460 break;
4461 case STD_T_FRQP:
4462 chunk_appendf(msg, "%u",
4463 read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
4464 t->data_arg[dt].u));
4465 break;
4466 }
4467 ptr = stktable_data_ptr_idx(t, entry, dt, ++idx);
4468 }
4469 continue;
4470 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004471 if (stktable_data_types[dt].arg_type == ARG_T_DELAY)
Emeric Brun01928ae2021-06-30 16:24:04 +02004472 chunk_appendf(msg, " %s(%u)=", stktable_data_types[dt].name, t->data_arg[dt].u);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004473 else
4474 chunk_appendf(msg, " %s=", stktable_data_types[dt].name);
4475
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004476 ptr = stktable_data_ptr(t, entry, dt);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004477 switch (stktable_data_types[dt].std_type) {
4478 case STD_T_SINT:
4479 chunk_appendf(msg, "%d", stktable_data_cast(ptr, std_t_sint));
4480 break;
4481 case STD_T_UINT:
4482 chunk_appendf(msg, "%u", stktable_data_cast(ptr, std_t_uint));
4483 break;
4484 case STD_T_ULL:
Emeric Brun01928ae2021-06-30 16:24:04 +02004485 chunk_appendf(msg, "%llu", stktable_data_cast(ptr, std_t_ull));
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004486 break;
4487 case STD_T_FRQP:
Emeric Brun01928ae2021-06-30 16:24:04 +02004488 chunk_appendf(msg, "%u",
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004489 read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004490 t->data_arg[dt].u));
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004491 break;
Frédéric Lécaille16b4f542019-05-23 12:15:04 +02004492 case STD_T_DICT: {
4493 struct dict_entry *de;
4494 de = stktable_data_cast(ptr, std_t_dict);
4495 chunk_appendf(msg, "%s", de ? (char *)de->value.key : "-");
4496 break;
4497 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004498 }
4499 }
4500 chunk_appendf(msg, "\n");
4501
Willy Tarreaud0a06d52022-05-18 15:07:19 +02004502 if (applet_putchk(appctx, msg) == -1)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004503 return 0;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004504
4505 return 1;
4506}
4507
Willy Tarreau3c69e082022-05-03 11:35:07 +02004508/* appctx context used by the "show table" command */
4509struct show_table_ctx {
4510 void *target; /* table we want to dump, or NULL for all */
4511 struct stktable *t; /* table being currently dumped (first if NULL) */
4512 struct stksess *entry; /* last entry we were trying to dump (or first if NULL) */
4513 long long value[STKTABLE_FILTER_LEN]; /* value to compare against */
4514 signed char data_type[STKTABLE_FILTER_LEN]; /* type of data to compare, or -1 if none */
4515 signed char data_op[STKTABLE_FILTER_LEN]; /* operator (STD_OP_*) when data_type set */
Willy Tarreau7849d4c2022-05-03 11:45:02 +02004516 enum {
Willy Tarreau0f154ed2022-05-03 12:02:36 +02004517 STATE_NEXT = 0, /* px points to next table, entry=NULL */
Willy Tarreau7849d4c2022-05-03 11:45:02 +02004518 STATE_DUMP, /* px points to curr table, entry is valid, refcount held */
4519 STATE_DONE, /* done dumping */
4520 } state;
Willy Tarreau3c69e082022-05-03 11:35:07 +02004521 char action; /* action on the table : one of STK_CLI_ACT_* */
4522};
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004523
4524/* Processes a single table entry matching a specific key passed in argument.
4525 * returns 0 if wants to be called again, 1 if has ended processing.
4526 */
4527static int table_process_entry_per_key(struct appctx *appctx, char **args)
4528{
Willy Tarreau3c69e082022-05-03 11:35:07 +02004529 struct show_table_ctx *ctx = appctx->svcctx;
4530 struct stktable *t = ctx->target;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004531 struct stksess *ts;
4532 uint32_t uint32_key;
4533 unsigned char ip6_key[sizeof(struct in6_addr)];
4534 long long value;
4535 int data_type;
4536 int cur_arg;
4537 void *ptr;
Willy Tarreaufa1258f2021-04-10 23:00:53 +02004538 struct freq_ctr *frqp;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004539
Willy Tarreau9d008692019-08-09 11:21:01 +02004540 if (!*args[4])
4541 return cli_err(appctx, "Key value expected\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004542
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004543 switch (t->type) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004544 case SMP_T_IPV4:
4545 uint32_key = htonl(inetaddr_host(args[4]));
Christopher Fauletca20d022017-08-29 15:30:31 +02004546 static_table_key.key = &uint32_key;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004547 break;
4548 case SMP_T_IPV6:
Christopher Fauletb7c962b2021-11-15 09:17:25 +01004549 if (inet_pton(AF_INET6, args[4], ip6_key) <= 0)
4550 return cli_err(appctx, "Invalid key\n");
Christopher Fauletca20d022017-08-29 15:30:31 +02004551 static_table_key.key = &ip6_key;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004552 break;
4553 case SMP_T_SINT:
4554 {
4555 char *endptr;
4556 unsigned long val;
4557 errno = 0;
4558 val = strtoul(args[4], &endptr, 10);
4559 if ((errno == ERANGE && val == ULONG_MAX) ||
4560 (errno != 0 && val == 0) || endptr == args[4] ||
Willy Tarreau9d008692019-08-09 11:21:01 +02004561 val > 0xffffffff)
4562 return cli_err(appctx, "Invalid key\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004563 uint32_key = (uint32_t) val;
Christopher Fauletca20d022017-08-29 15:30:31 +02004564 static_table_key.key = &uint32_key;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004565 break;
4566 }
4567 break;
4568 case SMP_T_STR:
Christopher Fauletca20d022017-08-29 15:30:31 +02004569 static_table_key.key = args[4];
4570 static_table_key.key_len = strlen(args[4]);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004571 break;
4572 default:
Willy Tarreau3c69e082022-05-03 11:35:07 +02004573 switch (ctx->action) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004574 case STK_CLI_ACT_SHOW:
Willy Tarreau9d008692019-08-09 11:21:01 +02004575 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 +01004576 case STK_CLI_ACT_CLR:
Willy Tarreau9d008692019-08-09 11:21:01 +02004577 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 +01004578 case STK_CLI_ACT_SET:
Willy Tarreau9d008692019-08-09 11:21:01 +02004579 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 +01004580 default:
Willy Tarreau9d008692019-08-09 11:21:01 +02004581 return cli_err(appctx, "Unknown action\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004582 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004583 }
4584
4585 /* check permissions */
4586 if (!cli_has_level(appctx, ACCESS_LVL_OPER))
4587 return 1;
4588
Willy Tarreau3c69e082022-05-03 11:35:07 +02004589 switch (ctx->action) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004590 case STK_CLI_ACT_SHOW:
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004591 ts = stktable_lookup_key(t, &static_table_key);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004592 if (!ts)
4593 return 1;
4594 chunk_reset(&trash);
Willy Tarreaud0a06d52022-05-18 15:07:19 +02004595 if (!table_dump_head_to_buffer(&trash, appctx, t, t)) {
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004596 stktable_release(t, ts);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004597 return 0;
Emeric Brun819fc6f2017-06-13 19:37:32 +02004598 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004599 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &ts->lock);
Willy Tarreaud0a06d52022-05-18 15:07:19 +02004600 if (!table_dump_entry_to_buffer(&trash, appctx, t, ts)) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004601 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004602 stktable_release(t, ts);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004603 return 0;
Emeric Brun819fc6f2017-06-13 19:37:32 +02004604 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004605 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004606 stktable_release(t, ts);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004607 break;
4608
4609 case STK_CLI_ACT_CLR:
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004610 ts = stktable_lookup_key(t, &static_table_key);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004611 if (!ts)
4612 return 1;
Emeric Brun819fc6f2017-06-13 19:37:32 +02004613
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004614 if (!stksess_kill(t, ts, 1)) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004615 /* don't delete an entry which is currently referenced */
Willy Tarreau9d008692019-08-09 11:21:01 +02004616 return cli_err(appctx, "Entry currently in use, cannot remove\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004617 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004618 break;
4619
4620 case STK_CLI_ACT_SET:
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004621 ts = stktable_get_entry(t, &static_table_key);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004622 if (!ts) {
4623 /* don't delete an entry which is currently referenced */
Willy Tarreau9d008692019-08-09 11:21:01 +02004624 return cli_err(appctx, "Unable to allocate a new entry\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004625 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004626 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004627 for (cur_arg = 5; *args[cur_arg]; cur_arg += 2) {
4628 if (strncmp(args[cur_arg], "data.", 5) != 0) {
Willy Tarreau9d008692019-08-09 11:21:01 +02004629 cli_err(appctx, "\"data.<type>\" followed by a value expected\n");
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004630 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004631 stktable_touch_local(t, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004632 return 1;
4633 }
4634
4635 data_type = stktable_get_data_type(args[cur_arg] + 5);
4636 if (data_type < 0) {
Willy Tarreau9d008692019-08-09 11:21:01 +02004637 cli_err(appctx, "Unknown data type\n");
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004638 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004639 stktable_touch_local(t, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004640 return 1;
4641 }
4642
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004643 if (!t->data_ofs[data_type]) {
Willy Tarreau9d008692019-08-09 11:21:01 +02004644 cli_err(appctx, "Data type not stored in this table\n");
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004645 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004646 stktable_touch_local(t, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004647 return 1;
4648 }
4649
4650 if (!*args[cur_arg+1] || strl2llrc(args[cur_arg+1], strlen(args[cur_arg+1]), &value) != 0) {
Willy Tarreau9d008692019-08-09 11:21:01 +02004651 cli_err(appctx, "Require a valid integer value to store\n");
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004652 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004653 stktable_touch_local(t, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004654 return 1;
4655 }
4656
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004657 ptr = stktable_data_ptr(t, ts, data_type);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004658
4659 switch (stktable_data_types[data_type].std_type) {
4660 case STD_T_SINT:
4661 stktable_data_cast(ptr, std_t_sint) = value;
4662 break;
4663 case STD_T_UINT:
4664 stktable_data_cast(ptr, std_t_uint) = value;
4665 break;
4666 case STD_T_ULL:
4667 stktable_data_cast(ptr, std_t_ull) = value;
4668 break;
4669 case STD_T_FRQP:
4670 /* We set both the current and previous values. That way
4671 * the reported frequency is stable during all the period
4672 * then slowly fades out. This allows external tools to
4673 * push measures without having to update them too often.
4674 */
4675 frqp = &stktable_data_cast(ptr, std_t_frqp);
Willy Tarreaufa1258f2021-04-10 23:00:53 +02004676 /* First bit is reserved for the freq_ctr lock
Emeric Brunf2fc1fd2017-11-02 17:32:43 +01004677 Note: here we're still protected by the stksess lock
Willy Tarreaufa1258f2021-04-10 23:00:53 +02004678 so we don't need to update the update the freq_ctr
Emeric Brunf2fc1fd2017-11-02 17:32:43 +01004679 using its internal lock */
4680 frqp->curr_tick = now_ms & ~0x1;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004681 frqp->prev_ctr = 0;
4682 frqp->curr_ctr = value;
4683 break;
4684 }
4685 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004686 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004687 stktable_touch_local(t, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004688 break;
4689
4690 default:
Willy Tarreau9d008692019-08-09 11:21:01 +02004691 return cli_err(appctx, "Unknown action\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004692 }
4693 return 1;
4694}
4695
4696/* Prepares the appctx fields with the data-based filters from the command line.
4697 * Returns 0 if the dump can proceed, 1 if has ended processing.
4698 */
4699static int table_prepare_data_request(struct appctx *appctx, char **args)
4700{
Willy Tarreau3c69e082022-05-03 11:35:07 +02004701 struct show_table_ctx *ctx = appctx->svcctx;
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004702 int i;
Adis Nezirovicd0142e72020-01-22 16:50:27 +01004703 char *err = NULL;
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004704
Willy Tarreau3c69e082022-05-03 11:35:07 +02004705 if (ctx->action != STK_CLI_ACT_SHOW && ctx->action != STK_CLI_ACT_CLR)
Willy Tarreau9d008692019-08-09 11:21:01 +02004706 return cli_err(appctx, "content-based lookup is only supported with the \"show\" and \"clear\" actions\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004707
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004708 for (i = 0; i < STKTABLE_FILTER_LEN; i++) {
4709 if (i > 0 && !*args[3+3*i]) // number of filter entries can be less than STKTABLE_FILTER_LEN
4710 break;
4711 /* condition on stored data value */
Willy Tarreau3c69e082022-05-03 11:35:07 +02004712 ctx->data_type[i] = stktable_get_data_type(args[3+3*i] + 5);
4713 if (ctx->data_type[i] < 0)
Adis Nezirovicd0142e72020-01-22 16:50:27 +01004714 return cli_dynerr(appctx, memprintf(&err, "Filter entry #%i: Unknown data type\n", i + 1));
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004715
Willy Tarreau3c69e082022-05-03 11:35:07 +02004716 if (!((struct stktable *)ctx->target)->data_ofs[ctx->data_type[i]])
Adis Nezirovicd0142e72020-01-22 16:50:27 +01004717 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 +01004718
Willy Tarreau3c69e082022-05-03 11:35:07 +02004719 ctx->data_op[i] = get_std_op(args[4+3*i]);
4720 if (ctx->data_op[i] < 0)
Adis Nezirovicd0142e72020-01-22 16:50:27 +01004721 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 +01004722
Willy Tarreau3c69e082022-05-03 11:35:07 +02004723 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 +01004724 return cli_dynerr(appctx, memprintf(&err, "Filter entry #%i: Require a valid integer value to compare against\n", i + 1));
4725 }
4726
4727 if (*args[3+3*i]) {
4728 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 +01004729 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004730
4731 /* OK we're done, all the fields are set */
4732 return 0;
4733}
4734
4735/* returns 0 if wants to be called, 1 if has ended processing */
Aurélien Nephtaliabbf6072018-04-18 13:26:46 +02004736static int cli_parse_table_req(char **args, char *payload, struct appctx *appctx, void *private)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004737{
Willy Tarreau3c69e082022-05-03 11:35:07 +02004738 struct show_table_ctx *ctx = applet_reserve_svcctx(appctx, sizeof(*ctx));
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004739 int i;
4740
4741 for (i = 0; i < STKTABLE_FILTER_LEN; i++)
Willy Tarreau3c69e082022-05-03 11:35:07 +02004742 ctx->data_type[i] = -1;
4743 ctx->target = NULL;
4744 ctx->entry = NULL;
4745 ctx->action = (long)private; // keyword argument, one of STK_CLI_ACT_*
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004746
4747 if (*args[2]) {
Willy Tarreau0f154ed2022-05-03 12:02:36 +02004748 ctx->t = ctx->target = stktable_find_by_name(args[2]);
Willy Tarreau3c69e082022-05-03 11:35:07 +02004749 if (!ctx->target)
Willy Tarreau9d008692019-08-09 11:21:01 +02004750 return cli_err(appctx, "No such table\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004751 }
4752 else {
Willy Tarreau0f154ed2022-05-03 12:02:36 +02004753 ctx->t = stktables_list;
Willy Tarreau3c69e082022-05-03 11:35:07 +02004754 if (ctx->action != STK_CLI_ACT_SHOW)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004755 goto err_args;
4756 return 0;
4757 }
4758
4759 if (strcmp(args[3], "key") == 0)
4760 return table_process_entry_per_key(appctx, args);
4761 else if (strncmp(args[3], "data.", 5) == 0)
4762 return table_prepare_data_request(appctx, args);
4763 else if (*args[3])
4764 goto err_args;
4765
4766 return 0;
4767
4768err_args:
Willy Tarreau3c69e082022-05-03 11:35:07 +02004769 switch (ctx->action) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004770 case STK_CLI_ACT_SHOW:
Willy Tarreau9d008692019-08-09 11:21:01 +02004771 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 +01004772 case STK_CLI_ACT_CLR:
Willy Tarreau9d008692019-08-09 11:21:01 +02004773 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 +01004774 case STK_CLI_ACT_SET:
Willy Tarreau9d008692019-08-09 11:21:01 +02004775 return cli_err(appctx, "Required arguments: <table> key <key> [data.<store_data_type> <value>]*\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004776 default:
Willy Tarreau9d008692019-08-09 11:21:01 +02004777 return cli_err(appctx, "Unknown action\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004778 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004779}
4780
4781/* This function is used to deal with table operations (dump or clear depending
4782 * on the action stored in appctx->private). It returns 0 if the output buffer is
4783 * full and it needs to be called again, otherwise non-zero.
4784 */
4785static int cli_io_handler_table(struct appctx *appctx)
4786{
Willy Tarreau3c69e082022-05-03 11:35:07 +02004787 struct show_table_ctx *ctx = appctx->svcctx;
Willy Tarreauc12b3212022-05-27 11:08:15 +02004788 struct stconn *sc = appctx_sc(appctx);
Willy Tarreau475e4632022-05-27 10:26:46 +02004789 struct stream *s = __sc_strm(sc);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004790 struct ebmb_node *eb;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004791 int skip_entry;
Willy Tarreau3c69e082022-05-03 11:35:07 +02004792 int show = ctx->action == STK_CLI_ACT_SHOW;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004793
4794 /*
Willy Tarreau0f154ed2022-05-03 12:02:36 +02004795 * We have 3 possible states in ctx->state :
Willy Tarreau7849d4c2022-05-03 11:45:02 +02004796 * - STATE_NEXT : the proxy pointer points to the next table to
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004797 * dump, the entry pointer is NULL ;
Willy Tarreau7849d4c2022-05-03 11:45:02 +02004798 * - STATE_DUMP : the proxy pointer points to the current table
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004799 * and the entry pointer points to the next entry to be dumped,
4800 * and the refcount on the next entry is held ;
Willy Tarreau7849d4c2022-05-03 11:45:02 +02004801 * - STATE_DONE : nothing left to dump, the buffer may contain some
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004802 * data though.
4803 */
4804
Willy Tarreau475e4632022-05-27 10:26:46 +02004805 if (unlikely(sc_ic(sc)->flags & (CF_WRITE_ERROR|CF_SHUTW))) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004806 /* in case of abort, remove any refcount we might have set on an entry */
Willy Tarreau7849d4c2022-05-03 11:45:02 +02004807 if (ctx->state == STATE_DUMP) {
Willy Tarreau3c69e082022-05-03 11:35:07 +02004808 stksess_kill_if_expired(ctx->t, ctx->entry, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004809 }
4810 return 1;
4811 }
4812
4813 chunk_reset(&trash);
4814
Willy Tarreau7849d4c2022-05-03 11:45:02 +02004815 while (ctx->state != STATE_DONE) {
4816 switch (ctx->state) {
Willy Tarreau7849d4c2022-05-03 11:45:02 +02004817 case STATE_NEXT:
Willy Tarreau3c69e082022-05-03 11:35:07 +02004818 if (!ctx->t ||
4819 (ctx->target &&
4820 ctx->t != ctx->target)) {
Willy Tarreau7849d4c2022-05-03 11:45:02 +02004821 ctx->state = STATE_DONE;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004822 break;
4823 }
4824
Willy Tarreau3c69e082022-05-03 11:35:07 +02004825 if (ctx->t->size) {
Willy Tarreaud0a06d52022-05-18 15:07:19 +02004826 if (show && !table_dump_head_to_buffer(&trash, appctx, ctx->t, ctx->target))
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004827 return 0;
4828
Willy Tarreau3c69e082022-05-03 11:35:07 +02004829 if (ctx->target &&
William Lallemand07a62f72017-05-24 00:57:40 +02004830 (strm_li(s)->bind_conf->level & ACCESS_LVL_MASK) >= ACCESS_LVL_OPER) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004831 /* dump entries only if table explicitly requested */
Willy Tarreau76642222022-10-11 12:02:50 +02004832 HA_RWLOCK_WRLOCK(STK_TABLE_LOCK, &ctx->t->lock);
Willy Tarreau3c69e082022-05-03 11:35:07 +02004833 eb = ebmb_first(&ctx->t->keys);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004834 if (eb) {
Willy Tarreau3c69e082022-05-03 11:35:07 +02004835 ctx->entry = ebmb_entry(eb, struct stksess, key);
4836 ctx->entry->ref_cnt++;
Willy Tarreau7849d4c2022-05-03 11:45:02 +02004837 ctx->state = STATE_DUMP;
Willy Tarreau76642222022-10-11 12:02:50 +02004838 HA_RWLOCK_WRUNLOCK(STK_TABLE_LOCK, &ctx->t->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004839 break;
4840 }
Willy Tarreau76642222022-10-11 12:02:50 +02004841 HA_RWLOCK_WRUNLOCK(STK_TABLE_LOCK, &ctx->t->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004842 }
4843 }
Willy Tarreau3c69e082022-05-03 11:35:07 +02004844 ctx->t = ctx->t->next;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004845 break;
4846
Willy Tarreau7849d4c2022-05-03 11:45:02 +02004847 case STATE_DUMP:
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004848 skip_entry = 0;
4849
Willy Tarreau3c69e082022-05-03 11:35:07 +02004850 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &ctx->entry->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004851
Willy Tarreau3c69e082022-05-03 11:35:07 +02004852 if (ctx->data_type[0] >= 0) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004853 /* we're filtering on some data contents */
4854 void *ptr;
Willy Tarreau2b64a352020-01-22 17:09:47 +01004855 int dt, i;
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004856 signed char op;
4857 long long data, value;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004858
Emeric Brun819fc6f2017-06-13 19:37:32 +02004859
Willy Tarreau2b64a352020-01-22 17:09:47 +01004860 for (i = 0; i < STKTABLE_FILTER_LEN; i++) {
Willy Tarreau3c69e082022-05-03 11:35:07 +02004861 if (ctx->data_type[i] == -1)
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004862 break;
Willy Tarreau3c69e082022-05-03 11:35:07 +02004863 dt = ctx->data_type[i];
4864 ptr = stktable_data_ptr(ctx->t,
4865 ctx->entry,
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004866 dt);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004867
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004868 data = 0;
4869 switch (stktable_data_types[dt].std_type) {
4870 case STD_T_SINT:
4871 data = stktable_data_cast(ptr, std_t_sint);
4872 break;
4873 case STD_T_UINT:
4874 data = stktable_data_cast(ptr, std_t_uint);
4875 break;
4876 case STD_T_ULL:
4877 data = stktable_data_cast(ptr, std_t_ull);
4878 break;
4879 case STD_T_FRQP:
4880 data = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Willy Tarreau3c69e082022-05-03 11:35:07 +02004881 ctx->t->data_arg[dt].u);
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004882 break;
4883 }
4884
Willy Tarreau3c69e082022-05-03 11:35:07 +02004885 op = ctx->data_op[i];
4886 value = ctx->value[i];
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004887
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004888 /* skip the entry if the data does not match the test and the value */
4889 if ((data < value &&
4890 (op == STD_OP_EQ || op == STD_OP_GT || op == STD_OP_GE)) ||
4891 (data == value &&
4892 (op == STD_OP_NE || op == STD_OP_GT || op == STD_OP_LT)) ||
4893 (data > value &&
4894 (op == STD_OP_EQ || op == STD_OP_LT || op == STD_OP_LE))) {
4895 skip_entry = 1;
4896 break;
4897 }
4898 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004899 }
4900
4901 if (show && !skip_entry &&
Willy Tarreaud0a06d52022-05-18 15:07:19 +02004902 !table_dump_entry_to_buffer(&trash, appctx, ctx->t, ctx->entry)) {
Willy Tarreau3c69e082022-05-03 11:35:07 +02004903 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &ctx->entry->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004904 return 0;
4905 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004906
Willy Tarreau3c69e082022-05-03 11:35:07 +02004907 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &ctx->entry->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004908
Willy Tarreau76642222022-10-11 12:02:50 +02004909 HA_RWLOCK_WRLOCK(STK_TABLE_LOCK, &ctx->t->lock);
Willy Tarreau3c69e082022-05-03 11:35:07 +02004910 ctx->entry->ref_cnt--;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004911
Willy Tarreau3c69e082022-05-03 11:35:07 +02004912 eb = ebmb_next(&ctx->entry->key);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004913 if (eb) {
Willy Tarreau3c69e082022-05-03 11:35:07 +02004914 struct stksess *old = ctx->entry;
4915 ctx->entry = ebmb_entry(eb, struct stksess, key);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004916 if (show)
Willy Tarreau3c69e082022-05-03 11:35:07 +02004917 __stksess_kill_if_expired(ctx->t, old);
4918 else if (!skip_entry && !ctx->entry->ref_cnt)
4919 __stksess_kill(ctx->t, old);
4920 ctx->entry->ref_cnt++;
Willy Tarreau76642222022-10-11 12:02:50 +02004921 HA_RWLOCK_WRUNLOCK(STK_TABLE_LOCK, &ctx->t->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004922 break;
4923 }
4924
4925
4926 if (show)
Willy Tarreau3c69e082022-05-03 11:35:07 +02004927 __stksess_kill_if_expired(ctx->t, ctx->entry);
4928 else if (!skip_entry && !ctx->entry->ref_cnt)
4929 __stksess_kill(ctx->t, ctx->entry);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004930
Willy Tarreau76642222022-10-11 12:02:50 +02004931 HA_RWLOCK_WRUNLOCK(STK_TABLE_LOCK, &ctx->t->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004932
Willy Tarreau3c69e082022-05-03 11:35:07 +02004933 ctx->t = ctx->t->next;
Willy Tarreau7849d4c2022-05-03 11:45:02 +02004934 ctx->state = STATE_NEXT;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004935 break;
4936
Willy Tarreau7849d4c2022-05-03 11:45:02 +02004937 default:
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004938 break;
4939 }
4940 }
4941 return 1;
4942}
4943
4944static void cli_release_show_table(struct appctx *appctx)
4945{
Willy Tarreau3c69e082022-05-03 11:35:07 +02004946 struct show_table_ctx *ctx = appctx->svcctx;
4947
Willy Tarreau7849d4c2022-05-03 11:45:02 +02004948 if (ctx->state == STATE_DUMP) {
Willy Tarreau3c69e082022-05-03 11:35:07 +02004949 stksess_kill_if_expired(ctx->t, ctx->entry, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004950 }
4951}
4952
Willy Tarreau478331d2020-08-28 11:31:31 +02004953static void stkt_late_init(void)
4954{
4955 struct sample_fetch *f;
4956
4957 f = find_sample_fetch("src", strlen("src"));
4958 if (f)
4959 smp_fetch_src = f->process;
4960}
4961
4962INITCALL0(STG_INIT, stkt_late_init);
4963
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004964/* register cli keywords */
4965static struct cli_kw_list cli_kws = {{ },{
Willy Tarreaub205bfd2021-05-07 11:38:37 +02004966 { { "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 },
4967 { { "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 },
4968 { { "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 +01004969 {{},}
4970}};
4971
Willy Tarreau0108d902018-11-25 19:14:37 +01004972INITCALL1(STG_REGISTER, cli_register_kw, &cli_kws);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004973
Thierry FOURNIER236657b2015-08-19 08:25:14 +02004974static struct action_kw_list tcp_conn_kws = { { }, {
Emeric Brun4d7ada82021-06-30 19:04:16 +02004975 { "sc-inc-gpc", parse_inc_gpc, KWF_MATCH_PREFIX },
4976 { "sc-inc-gpc0", parse_inc_gpc, KWF_MATCH_PREFIX },
4977 { "sc-inc-gpc1", parse_inc_gpc, KWF_MATCH_PREFIX },
Emeric Brun877b0b52021-06-30 18:57:49 +02004978 { "sc-set-gpt", parse_set_gpt, KWF_MATCH_PREFIX },
4979 { "sc-set-gpt0", parse_set_gpt, KWF_MATCH_PREFIX },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02004980 { /* END */ }
4981}};
4982
Willy Tarreau0108d902018-11-25 19:14:37 +01004983INITCALL1(STG_REGISTER, tcp_req_conn_keywords_register, &tcp_conn_kws);
4984
Willy Tarreau620408f2016-10-21 16:37:51 +02004985static struct action_kw_list tcp_sess_kws = { { }, {
Emeric Brun4d7ada82021-06-30 19:04:16 +02004986 { "sc-inc-gpc", parse_inc_gpc, KWF_MATCH_PREFIX },
4987 { "sc-inc-gpc0", parse_inc_gpc, KWF_MATCH_PREFIX },
4988 { "sc-inc-gpc1", parse_inc_gpc, KWF_MATCH_PREFIX },
Emeric Brun877b0b52021-06-30 18:57:49 +02004989 { "sc-set-gpt", parse_set_gpt, KWF_MATCH_PREFIX },
4990 { "sc-set-gpt0", parse_set_gpt, KWF_MATCH_PREFIX },
Willy Tarreau620408f2016-10-21 16:37:51 +02004991 { /* END */ }
4992}};
4993
Willy Tarreau0108d902018-11-25 19:14:37 +01004994INITCALL1(STG_REGISTER, tcp_req_sess_keywords_register, &tcp_sess_kws);
4995
Thierry FOURNIER236657b2015-08-19 08:25:14 +02004996static struct action_kw_list tcp_req_kws = { { }, {
Emeric Brun4d7ada82021-06-30 19:04:16 +02004997 { "sc-inc-gpc", parse_inc_gpc, KWF_MATCH_PREFIX },
4998 { "sc-inc-gpc0", parse_inc_gpc, KWF_MATCH_PREFIX },
4999 { "sc-inc-gpc1", parse_inc_gpc, KWF_MATCH_PREFIX },
Emeric Brun877b0b52021-06-30 18:57:49 +02005000 { "sc-set-gpt", parse_set_gpt, KWF_MATCH_PREFIX },
5001 { "sc-set-gpt0", parse_set_gpt, KWF_MATCH_PREFIX },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02005002 { /* END */ }
5003}};
5004
Willy Tarreau0108d902018-11-25 19:14:37 +01005005INITCALL1(STG_REGISTER, tcp_req_cont_keywords_register, &tcp_req_kws);
5006
Thierry FOURNIER236657b2015-08-19 08:25:14 +02005007static struct action_kw_list tcp_res_kws = { { }, {
Emeric Brun4d7ada82021-06-30 19:04:16 +02005008 { "sc-inc-gpc", parse_inc_gpc, KWF_MATCH_PREFIX },
5009 { "sc-inc-gpc0", parse_inc_gpc, KWF_MATCH_PREFIX },
5010 { "sc-inc-gpc1", parse_inc_gpc, KWF_MATCH_PREFIX },
Emeric Brun877b0b52021-06-30 18:57:49 +02005011 { "sc-set-gpt", parse_set_gpt, KWF_MATCH_PREFIX },
5012 { "sc-set-gpt0", parse_set_gpt, KWF_MATCH_PREFIX },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02005013 { /* END */ }
5014}};
5015
Willy Tarreau0108d902018-11-25 19:14:37 +01005016INITCALL1(STG_REGISTER, tcp_res_cont_keywords_register, &tcp_res_kws);
5017
Thierry FOURNIER236657b2015-08-19 08:25:14 +02005018static struct action_kw_list http_req_kws = { { }, {
Emeric Brun4d7ada82021-06-30 19:04:16 +02005019 { "sc-inc-gpc", parse_inc_gpc, KWF_MATCH_PREFIX },
5020 { "sc-inc-gpc0", parse_inc_gpc, KWF_MATCH_PREFIX },
5021 { "sc-inc-gpc1", parse_inc_gpc, KWF_MATCH_PREFIX },
Emeric Brun877b0b52021-06-30 18:57:49 +02005022 { "sc-set-gpt", parse_set_gpt, KWF_MATCH_PREFIX },
5023 { "sc-set-gpt0", parse_set_gpt, KWF_MATCH_PREFIX },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02005024 { /* END */ }
5025}};
5026
Willy Tarreau0108d902018-11-25 19:14:37 +01005027INITCALL1(STG_REGISTER, http_req_keywords_register, &http_req_kws);
5028
Thierry FOURNIER236657b2015-08-19 08:25:14 +02005029static struct action_kw_list http_res_kws = { { }, {
Emeric Brun4d7ada82021-06-30 19:04:16 +02005030 { "sc-inc-gpc", parse_inc_gpc, KWF_MATCH_PREFIX },
5031 { "sc-inc-gpc0", parse_inc_gpc, KWF_MATCH_PREFIX },
5032 { "sc-inc-gpc1", parse_inc_gpc, KWF_MATCH_PREFIX },
Emeric Brun877b0b52021-06-30 18:57:49 +02005033 { "sc-set-gpt", parse_set_gpt, KWF_MATCH_PREFIX },
5034 { "sc-set-gpt0", parse_set_gpt, KWF_MATCH_PREFIX },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02005035 { /* END */ }
5036}};
5037
Willy Tarreau0108d902018-11-25 19:14:37 +01005038INITCALL1(STG_REGISTER, http_res_keywords_register, &http_res_kws);
5039
Willy Tarreau7d562212016-11-25 16:10:05 +01005040/* Note: must not be declared <const> as its list will be overwritten.
5041 * Please take care of keeping this list alphabetically sorted.
5042 */
5043static struct sample_fetch_kw_list smp_fetch_keywords = {ILH, {
5044 { "sc_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5045 { "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 +02005046 { "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 +01005047 { "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 +01005048 { "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 +01005049 { "sc_conn_cnt", smp_fetch_sc_conn_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5050 { "sc_conn_cur", smp_fetch_sc_conn_cur, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5051 { "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 +02005052 { "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 +01005053 { "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 +02005054 { "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 +01005055 { "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 +01005056 { "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 +02005057 { "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 +01005058 { "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 +01005059 { "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 +01005060 { "sc_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5061 { "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 +01005062 { "sc_http_fail_cnt", smp_fetch_sc_http_fail_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5063 { "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 +01005064 { "sc_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5065 { "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 +02005066 { "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 +01005067 { "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 +01005068 { "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 +01005069 { "sc_kbytes_in", smp_fetch_sc_kbytes_in, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5070 { "sc_kbytes_out", smp_fetch_sc_kbytes_out, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5071 { "sc_sess_cnt", smp_fetch_sc_sess_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5072 { "sc_sess_rate", smp_fetch_sc_sess_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5073 { "sc_tracked", smp_fetch_sc_tracked, ARG2(1,SINT,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
5074 { "sc_trackers", smp_fetch_sc_trackers, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5075 { "sc0_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5076 { "sc0_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5077 { "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 +01005078 { "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 +01005079 { "sc0_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5080 { "sc0_conn_cur", smp_fetch_sc_conn_cur, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5081 { "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 +01005082 { "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 +01005083 { "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 +01005084 { "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 +01005085 { "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 +01005086 { "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 +01005087 { "sc0_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5088 { "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 +01005089 { "sc0_http_fail_cnt", smp_fetch_sc_http_fail_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5090 { "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 +01005091 { "sc0_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5092 { "sc0_http_req_rate", smp_fetch_sc_http_req_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5093 { "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 +01005094 { "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 +01005095 { "sc0_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5096 { "sc0_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5097 { "sc0_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5098 { "sc0_sess_rate", smp_fetch_sc_sess_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5099 { "sc0_tracked", smp_fetch_sc_tracked, ARG1(0,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
5100 { "sc0_trackers", smp_fetch_sc_trackers, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5101 { "sc1_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5102 { "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 +02005103 { "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 +01005104 { "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 +01005105 { "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 +01005106 { "sc1_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5107 { "sc1_conn_cur", smp_fetch_sc_conn_cur, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5108 { "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 +01005109 { "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 +01005110 { "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 +01005111 { "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 +01005112 { "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 +01005113 { "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 +01005114 { "sc1_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5115 { "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 +01005116 { "sc1_http_fail_cnt", smp_fetch_sc_http_fail_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5117 { "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 +01005118 { "sc1_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5119 { "sc1_http_req_rate", smp_fetch_sc_http_req_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5120 { "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 +01005121 { "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 +01005122 { "sc1_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5123 { "sc1_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5124 { "sc1_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5125 { "sc1_sess_rate", smp_fetch_sc_sess_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5126 { "sc1_tracked", smp_fetch_sc_tracked, ARG1(0,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
5127 { "sc1_trackers", smp_fetch_sc_trackers, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5128 { "sc2_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5129 { "sc2_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5130 { "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 +01005131 { "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 +01005132 { "sc2_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5133 { "sc2_conn_cur", smp_fetch_sc_conn_cur, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5134 { "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 +01005135 { "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 +01005136 { "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 +01005137 { "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 +01005138 { "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 +01005139 { "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 +01005140 { "sc2_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5141 { "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 +01005142 { "sc2_http_fail_cnt", smp_fetch_sc_http_fail_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5143 { "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 +01005144 { "sc2_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5145 { "sc2_http_req_rate", smp_fetch_sc_http_req_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5146 { "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 +01005147 { "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 +01005148 { "sc2_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5149 { "sc2_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5150 { "sc2_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5151 { "sc2_sess_rate", smp_fetch_sc_sess_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5152 { "sc2_tracked", smp_fetch_sc_tracked, ARG1(0,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
5153 { "sc2_trackers", smp_fetch_sc_trackers, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5154 { "src_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5155 { "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 +02005156 { "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 +01005157 { "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 +01005158 { "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 +01005159 { "src_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5160 { "src_conn_cur", smp_fetch_sc_conn_cur, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5161 { "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 +02005162 { "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 +01005163 { "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 +02005164 { "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 +01005165 { "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 +01005166 { "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 +02005167 { "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 +01005168 { "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 +01005169 { "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 +01005170 { "src_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5171 { "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 +01005172 { "src_http_fail_cnt", smp_fetch_sc_http_fail_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5173 { "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 +01005174 { "src_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5175 { "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 +02005176 { "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 +01005177 { "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 +01005178 { "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 +01005179 { "src_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5180 { "src_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5181 { "src_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5182 { "src_sess_rate", smp_fetch_sc_sess_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5183 { "src_updt_conn_cnt", smp_fetch_src_updt_conn_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5184 { "table_avl", smp_fetch_table_avl, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5185 { "table_cnt", smp_fetch_table_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5186 { /* END */ },
5187}};
5188
Willy Tarreau0108d902018-11-25 19:14:37 +01005189INITCALL1(STG_REGISTER, sample_register_fetches, &smp_fetch_keywords);
Willy Tarreau7d562212016-11-25 16:10:05 +01005190
Willy Tarreaud9f316a2014-07-10 14:03:38 +02005191/* Note: must not be declared <const> as its list will be overwritten */
5192static struct sample_conv_kw_list sample_conv_kws = {ILH, {
Willy Tarreau2d17db52016-05-25 17:16:38 +02005193 { "in_table", sample_conv_in_table, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_BOOL },
5194 { "table_bytes_in_rate", sample_conv_table_bytes_in_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5195 { "table_bytes_out_rate", sample_conv_table_bytes_out_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5196 { "table_conn_cnt", sample_conv_table_conn_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5197 { "table_conn_cur", sample_conv_table_conn_cur, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5198 { "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 +02005199 { "table_expire", sample_conv_table_expire, ARG2(1,TAB,SINT), NULL, SMP_T_ANY, SMP_T_SINT },
Emeric Brun877b0b52021-06-30 18:57:49 +02005200 { "table_gpt", sample_conv_table_gpt, ARG2(2,SINT,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
Willy Tarreau2d17db52016-05-25 17:16:38 +02005201 { "table_gpt0", sample_conv_table_gpt0, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
Emeric Brun4d7ada82021-06-30 19:04:16 +02005202 { "table_gpc", sample_conv_table_gpc, ARG2(2,SINT,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
Willy Tarreau2d17db52016-05-25 17:16:38 +02005203 { "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 +01005204 { "table_gpc1", sample_conv_table_gpc1, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
Emeric Brun4d7ada82021-06-30 19:04:16 +02005205 { "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 +02005206 { "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 +01005207 { "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 +02005208 { "table_http_err_cnt", sample_conv_table_http_err_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5209 { "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 +01005210 { "table_http_fail_cnt", sample_conv_table_http_fail_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5211 { "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 +02005212 { "table_http_req_cnt", sample_conv_table_http_req_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5213 { "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 +02005214 { "table_idle", sample_conv_table_idle, ARG2(1,TAB,SINT), NULL, SMP_T_ANY, SMP_T_SINT },
Willy Tarreau2d17db52016-05-25 17:16:38 +02005215 { "table_kbytes_in", sample_conv_table_kbytes_in, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5216 { "table_kbytes_out", sample_conv_table_kbytes_out, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5217 { "table_server_id", sample_conv_table_server_id, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5218 { "table_sess_cnt", sample_conv_table_sess_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5219 { "table_sess_rate", sample_conv_table_sess_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5220 { "table_trackers", sample_conv_table_trackers, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
Willy Tarreaud9f316a2014-07-10 14:03:38 +02005221 { /* END */ },
5222}};
5223
Willy Tarreau0108d902018-11-25 19:14:37 +01005224INITCALL1(STG_REGISTER, sample_register_convs, &sample_conv_kws);