blob: f4f1de1eb8e7eaa409a0534b0a7551915f673f8b [file] [log] [blame]
Emeric Brun3bd697e2010-01-04 15:23:48 +01001/*
2 * Stick tables management functions.
3 *
4 * Copyright 2009-2010 EXCELIANCE, Emeric Brun <ebrun@exceliance.fr>
Willy Tarreau08d5f982010-06-06 13:34:54 +02005 * Copyright (C) 2010 Willy Tarreau <w@1wt.eu>
Emeric Brun3bd697e2010-01-04 15:23:48 +01006 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version
10 * 2 of the License, or (at your option) any later version.
11 *
12 */
13
14#include <string.h>
Willy Tarreauf13ebdf2016-11-22 18:00:53 +010015#include <errno.h>
Emeric Brun3bd697e2010-01-04 15:23:48 +010016
Willy Tarreaub2551052020-06-09 09:07:15 +020017#include <import/ebmbtree.h>
18#include <import/ebsttree.h>
19#include <import/ebistree.h>
20
Willy Tarreau4c7e4b72020-05-27 12:58:42 +020021#include <haproxy/api.h>
Willy Tarreau3c69e082022-05-03 11:35:07 +020022#include <haproxy/applet.h>
Willy Tarreaub2551052020-06-09 09:07:15 +020023#include <haproxy/arg.h>
Willy Tarreau6be78492020-06-05 00:00:29 +020024#include <haproxy/cfgparse.h>
Willy Tarreau83487a82020-06-04 20:19:54 +020025#include <haproxy/cli.h>
Thayne McCombs92149f92020-11-20 01:28:26 -070026#include <haproxy/dict.h>
Willy Tarreau36979d92020-06-05 17:27:29 +020027#include <haproxy/errors.h>
Willy Tarreauf268ee82020-06-04 17:05:57 +020028#include <haproxy/global.h>
Willy Tarreauc761f842020-06-04 11:40:28 +020029#include <haproxy/http_rules.h>
Willy Tarreau853b2972020-05-27 18:01:47 +020030#include <haproxy/list.h>
Willy Tarreauaeed4a82020-06-04 22:01:04 +020031#include <haproxy/log.h>
Willy Tarreau6131d6a2020-06-02 16:48:09 +020032#include <haproxy/net_helper.h>
Willy Tarreau3c2a7c22020-06-04 18:38:21 +020033#include <haproxy/peers.h>
Willy Tarreaub2551052020-06-09 09:07:15 +020034#include <haproxy/pool.h>
35#include <haproxy/proto_tcp.h>
Willy Tarreaua264d962020-06-04 22:29:18 +020036#include <haproxy/proxy.h>
Willy Tarreaub2551052020-06-09 09:07:15 +020037#include <haproxy/sample.h>
Willy Tarreau5edca2f2022-05-27 09:25:10 +020038#include <haproxy/sc_strm.h>
Willy Tarreau2eec9b52020-06-04 19:58:55 +020039#include <haproxy/stats-t.h>
Willy Tarreaucb086c62022-05-27 09:47:12 +020040#include <haproxy/stconn.h>
Willy Tarreaub2551052020-06-09 09:07:15 +020041#include <haproxy/stick_table.h>
Willy Tarreaudfd3de82020-06-04 23:46:14 +020042#include <haproxy/stream.h>
Willy Tarreaucea0e1b2020-06-04 17:25:40 +020043#include <haproxy/task.h>
Willy Tarreau8b550af2020-06-04 17:42:48 +020044#include <haproxy/tcp_rules.h>
Willy Tarreau9310f482021-10-06 16:18:40 +020045#include <haproxy/ticks.h>
Willy Tarreaub2551052020-06-09 09:07:15 +020046#include <haproxy/tools.h>
Emeric Brun3bd697e2010-01-04 15:23:48 +010047
Emeric Brun3bd697e2010-01-04 15:23:48 +010048
Willy Tarreau12785782012-04-27 21:37:17 +020049/* structure used to return a table key built from a sample */
Emeric Brun819fc6f2017-06-13 19:37:32 +020050static THREAD_LOCAL struct stktable_key static_table_key;
Willy Tarreau478331d2020-08-28 11:31:31 +020051static int (*smp_fetch_src)(const struct arg *, struct sample *, const char *, void *);
Willy Tarreauf0b38bf2010-06-06 13:22:23 +020052
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +010053struct stktable *stktables_list;
54struct eb_root stktable_by_name = EB_ROOT;
55
Olivier Houchard52dabbc2018-11-14 17:54:36 +010056#define round_ptr_size(i) (((i) + (sizeof(void *) - 1)) &~ (sizeof(void *) - 1))
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +010057
58/* This function inserts stktable <t> into the tree of known stick-table.
59 * The stick-table ID is used as the storing key so it must already have
60 * been initialized.
61 */
62void stktable_store_name(struct stktable *t)
63{
64 t->name.key = t->id;
65 ebis_insert(&stktable_by_name, &t->name);
66}
67
68struct stktable *stktable_find_by_name(const char *name)
69{
70 struct ebpt_node *node;
71 struct stktable *t;
72
73 node = ebis_lookup(&stktable_by_name, name);
74 if (node) {
75 t = container_of(node, struct stktable, name);
Tim Duesterhuse5ff1412021-01-02 22:31:53 +010076 if (strcmp(t->id, name) == 0)
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +010077 return t;
78 }
79
80 return NULL;
81}
82
Emeric Brun3bd697e2010-01-04 15:23:48 +010083/*
Willy Tarreauaea940e2010-06-06 11:56:36 +020084 * Free an allocated sticky session <ts>, and decrease sticky sessions counter
Willy Tarreau996f1a52022-10-11 16:19:35 +020085 * in table <t>. It's safe to call it under or out of a lock.
Emeric Brun3bd697e2010-01-04 15:23:48 +010086 */
Emeric Brun819fc6f2017-06-13 19:37:32 +020087void __stksess_free(struct stktable *t, struct stksess *ts)
Emeric Brun3bd697e2010-01-04 15:23:48 +010088{
Willy Tarreau996f1a52022-10-11 16:19:35 +020089 HA_ATOMIC_DEC(&t->current);
Olivier Houchard52dabbc2018-11-14 17:54:36 +010090 pool_free(t->pool, (void *)ts - round_ptr_size(t->data_size));
Emeric Brun3bd697e2010-01-04 15:23:48 +010091}
92
93/*
Emeric Brun819fc6f2017-06-13 19:37:32 +020094 * Free an allocated sticky session <ts>, and decrease sticky sessions counter
95 * in table <t>.
96 * This function locks the table
97 */
98void stksess_free(struct stktable *t, struct stksess *ts)
99{
Thayne McCombs92149f92020-11-20 01:28:26 -0700100 void *data;
101 data = stktable_data_ptr(t, ts, STKTABLE_DT_SERVER_KEY);
102 if (data) {
Emeric Brun0e3457b2021-06-30 17:18:28 +0200103 dict_entry_unref(&server_key_dict, stktable_data_cast(data, std_t_dict));
104 stktable_data_cast(data, std_t_dict) = NULL;
Thayne McCombs92149f92020-11-20 01:28:26 -0700105 }
Willy Tarreau8d3c3332022-10-11 18:50:22 +0000106 HA_RWLOCK_RDLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200107 __stksess_free(t, ts);
Willy Tarreau8d3c3332022-10-11 18:50:22 +0000108 HA_RWLOCK_RDUNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200109}
110
111/*
Willy Tarreauf6efda12010-08-03 20:34:06 +0200112 * Kill an stksess (only if its ref_cnt is zero).
113 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200114int __stksess_kill(struct stktable *t, struct stksess *ts)
Willy Tarreauf6efda12010-08-03 20:34:06 +0200115{
116 if (ts->ref_cnt)
Emeric Brun819fc6f2017-06-13 19:37:32 +0200117 return 0;
Willy Tarreauf6efda12010-08-03 20:34:06 +0200118
119 eb32_delete(&ts->exp);
Emeric Brun85e77c72010-09-23 18:16:52 +0200120 eb32_delete(&ts->upd);
Willy Tarreauf6efda12010-08-03 20:34:06 +0200121 ebmb_delete(&ts->key);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200122 __stksess_free(t, ts);
123 return 1;
Willy Tarreauf6efda12010-08-03 20:34:06 +0200124}
125
126/*
Emeric Brun819fc6f2017-06-13 19:37:32 +0200127 * Decrease the refcount if decrefcnt is not 0.
128 * and try to kill the stksess
129 * This function locks the table
130 */
131int stksess_kill(struct stktable *t, struct stksess *ts, int decrefcnt)
132{
133 int ret;
134
Willy Tarreau76642222022-10-11 12:02:50 +0200135 HA_RWLOCK_WRLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200136 if (decrefcnt)
137 ts->ref_cnt--;
138 ret = __stksess_kill(t, ts);
Willy Tarreau76642222022-10-11 12:02:50 +0200139 HA_RWLOCK_WRUNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200140
141 return ret;
142}
143
144/*
Willy Tarreauaea940e2010-06-06 11:56:36 +0200145 * Initialize or update the key in the sticky session <ts> present in table <t>
146 * from the value present in <key>.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100147 */
Willy Tarreau393379c2010-06-06 12:11:37 +0200148void stksess_setkey(struct stktable *t, struct stksess *ts, struct stktable_key *key)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100149{
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200150 if (t->type != SMP_T_STR)
Willy Tarreau86257dc2010-06-06 12:57:10 +0200151 memcpy(ts->key.key, key->key, t->key_size);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100152 else {
Willy Tarreau86257dc2010-06-06 12:57:10 +0200153 memcpy(ts->key.key, key->key, MIN(t->key_size - 1, key->key_len));
154 ts->key.key[MIN(t->key_size - 1, key->key_len)] = 0;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100155 }
156}
157
158
159/*
Willy Tarreau393379c2010-06-06 12:11:37 +0200160 * Init sticky session <ts> of table <t>. The data parts are cleared and <ts>
161 * is returned.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100162 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200163static struct stksess *__stksess_init(struct stktable *t, struct stksess * ts)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100164{
Willy Tarreau393379c2010-06-06 12:11:37 +0200165 memset((void *)ts - t->data_size, 0, t->data_size);
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200166 ts->ref_cnt = 0;
Willy Tarreau86257dc2010-06-06 12:57:10 +0200167 ts->key.node.leaf_p = NULL;
168 ts->exp.node.leaf_p = NULL;
Emeric Brun85e77c72010-09-23 18:16:52 +0200169 ts->upd.node.leaf_p = NULL;
Emeric Brun819fc6f2017-06-13 19:37:32 +0200170 ts->expire = tick_add(now_ms, MS_TO_TICKS(t->expire));
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100171 HA_RWLOCK_INIT(&ts->lock);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100172 return ts;
173}
174
175/*
Willy Tarreauaea940e2010-06-06 11:56:36 +0200176 * Trash oldest <to_batch> sticky sessions from table <t>
Willy Tarreaudfe79252020-11-03 17:47:41 +0100177 * Returns number of trashed sticky sessions. It may actually trash less
178 * than expected if finding these requires too long a search time (e.g.
179 * most of them have ts->ref_cnt>0).
Emeric Brun3bd697e2010-01-04 15:23:48 +0100180 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200181int __stktable_trash_oldest(struct stktable *t, int to_batch)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100182{
183 struct stksess *ts;
184 struct eb32_node *eb;
Willy Tarreaudfe79252020-11-03 17:47:41 +0100185 int max_search = to_batch * 2; // no more than 50% misses
Emeric Brun3bd697e2010-01-04 15:23:48 +0100186 int batched = 0;
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200187 int looped = 0;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100188
189 eb = eb32_lookup_ge(&t->exps, now_ms - TIMER_LOOK_BACK);
190
191 while (batched < to_batch) {
192
193 if (unlikely(!eb)) {
194 /* we might have reached the end of the tree, typically because
195 * <now_ms> is in the first half and we're first scanning the last
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200196 * half. Let's loop back to the beginning of the tree now if we
197 * have not yet visited it.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100198 */
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200199 if (looped)
200 break;
201 looped = 1;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100202 eb = eb32_first(&t->exps);
203 if (likely(!eb))
204 break;
205 }
206
Willy Tarreaudfe79252020-11-03 17:47:41 +0100207 if (--max_search < 0)
208 break;
209
Emeric Brun3bd697e2010-01-04 15:23:48 +0100210 /* timer looks expired, detach it from the queue */
Willy Tarreau86257dc2010-06-06 12:57:10 +0200211 ts = eb32_entry(eb, struct stksess, exp);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100212 eb = eb32_next(eb);
213
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200214 /* don't delete an entry which is currently referenced */
215 if (ts->ref_cnt)
216 continue;
217
Willy Tarreau86257dc2010-06-06 12:57:10 +0200218 eb32_delete(&ts->exp);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100219
Willy Tarreau86257dc2010-06-06 12:57:10 +0200220 if (ts->expire != ts->exp.key) {
Emeric Brun3bd697e2010-01-04 15:23:48 +0100221 if (!tick_isset(ts->expire))
222 continue;
223
Willy Tarreau86257dc2010-06-06 12:57:10 +0200224 ts->exp.key = ts->expire;
225 eb32_insert(&t->exps, &ts->exp);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100226
Willy Tarreau86257dc2010-06-06 12:57:10 +0200227 if (!eb || eb->key > ts->exp.key)
228 eb = &ts->exp;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100229
230 continue;
231 }
Emeric Brun3bd697e2010-01-04 15:23:48 +0100232
Willy Tarreauaea940e2010-06-06 11:56:36 +0200233 /* session expired, trash it */
Willy Tarreau86257dc2010-06-06 12:57:10 +0200234 ebmb_delete(&ts->key);
Emeric Brun85e77c72010-09-23 18:16:52 +0200235 eb32_delete(&ts->upd);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200236 __stksess_free(t, ts);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100237 batched++;
238 }
239
240 return batched;
241}
242
243/*
Emeric Brun819fc6f2017-06-13 19:37:32 +0200244 * Trash oldest <to_batch> sticky sessions from table <t>
245 * Returns number of trashed sticky sessions.
246 * This function locks the table
247 */
248int stktable_trash_oldest(struct stktable *t, int to_batch)
249{
250 int ret;
251
Willy Tarreau76642222022-10-11 12:02:50 +0200252 HA_RWLOCK_WRLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200253 ret = __stktable_trash_oldest(t, to_batch);
Willy Tarreau76642222022-10-11 12:02:50 +0200254 HA_RWLOCK_WRUNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200255
256 return ret;
257}
258/*
Willy Tarreauaea940e2010-06-06 11:56:36 +0200259 * Allocate and initialise a new sticky session.
260 * The new sticky session is returned or NULL in case of lack of memory.
261 * Sticky sessions should only be allocated this way, and must be freed using
Willy Tarreaua7b46b52013-04-11 16:55:37 +0200262 * stksess_free(). Table <t>'s sticky session counter is increased. If <key>
Willy Tarreau996f1a52022-10-11 16:19:35 +0200263 * is not NULL, it is assigned to the new session. It must be called unlocked
264 * as it may rely on a lock to trash older entries.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100265 */
Willy Tarreau996f1a52022-10-11 16:19:35 +0200266struct stksess *stksess_new(struct stktable *t, struct stktable_key *key)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100267{
268 struct stksess *ts;
Willy Tarreau996f1a52022-10-11 16:19:35 +0200269 unsigned int current;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100270
Willy Tarreau996f1a52022-10-11 16:19:35 +0200271 current = HA_ATOMIC_FETCH_ADD(&t->current, 1);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100272
Willy Tarreau996f1a52022-10-11 16:19:35 +0200273 if (unlikely(current >= t->size)) {
274 /* the table was already full, we may have to purge entries */
275 if (t->nopurge || !stktable_trash_oldest(t, (t->size >> 8) + 1)) {
276 HA_ATOMIC_DEC(&t->current);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100277 return NULL;
Willy Tarreau996f1a52022-10-11 16:19:35 +0200278 }
Emeric Brun3bd697e2010-01-04 15:23:48 +0100279 }
280
Willy Tarreaubafbe012017-11-24 17:34:44 +0100281 ts = pool_alloc(t->pool);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100282 if (ts) {
Olivier Houchard52dabbc2018-11-14 17:54:36 +0100283 ts = (void *)ts + round_ptr_size(t->data_size);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200284 __stksess_init(t, ts);
Willy Tarreaua7b46b52013-04-11 16:55:37 +0200285 if (key)
286 stksess_setkey(t, ts, key);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100287 }
288
289 return ts;
290}
291
292/*
Willy Tarreauf16d2b82010-06-06 15:38:59 +0200293 * Looks in table <t> for a sticky session matching key <key>.
Willy Tarreauaea940e2010-06-06 11:56:36 +0200294 * Returns pointer on requested sticky session or NULL if none was found.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100295 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200296struct stksess *__stktable_lookup_key(struct stktable *t, struct stktable_key *key)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100297{
298 struct ebmb_node *eb;
299
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200300 if (t->type == SMP_T_STR)
Emeric Brun485479d2010-09-23 18:02:19 +0200301 eb = ebst_lookup_len(&t->keys, key->key, key->key_len+1 < t->key_size ? key->key_len : t->key_size-1);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100302 else
303 eb = ebmb_lookup(&t->keys, key->key, t->key_size);
304
305 if (unlikely(!eb)) {
306 /* no session found */
307 return NULL;
308 }
309
Willy Tarreau86257dc2010-06-06 12:57:10 +0200310 return ebmb_entry(eb, struct stksess, key);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100311}
312
Emeric Brun819fc6f2017-06-13 19:37:32 +0200313/*
314 * Looks in table <t> for a sticky session matching key <key>.
315 * Returns pointer on requested sticky session or NULL if none was found.
316 * The refcount of the found entry is increased and this function
317 * is protected using the table lock
Willy Tarreau1f7e9252010-06-20 12:27:21 +0200318 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200319struct stksess *stktable_lookup_key(struct stktable *t, struct stktable_key *key)
Willy Tarreau1f7e9252010-06-20 12:27:21 +0200320{
321 struct stksess *ts;
322
Willy Tarreaua7d6a132022-10-11 15:42:54 +0200323 HA_RWLOCK_RDLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200324 ts = __stktable_lookup_key(t, key);
325 if (ts)
Willy Tarreaua7d6a132022-10-11 15:42:54 +0200326 HA_ATOMIC_INC(&ts->ref_cnt);
327 HA_RWLOCK_RDUNLOCK(STK_TABLE_LOCK, &t->lock);
Willy Tarreau1f7e9252010-06-20 12:27:21 +0200328
Willy Tarreau1f7e9252010-06-20 12:27:21 +0200329 return ts;
330}
331
Willy Tarreauf16d2b82010-06-06 15:38:59 +0200332/*
333 * Looks in table <t> for a sticky session with same key as <ts>.
334 * Returns pointer on requested sticky session or NULL if none was found.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100335 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200336struct stksess *__stktable_lookup(struct stktable *t, struct stksess *ts)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100337{
Emeric Brun3bd697e2010-01-04 15:23:48 +0100338 struct ebmb_node *eb;
339
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200340 if (t->type == SMP_T_STR)
Willy Tarreau86257dc2010-06-06 12:57:10 +0200341 eb = ebst_lookup(&(t->keys), (char *)ts->key.key);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100342 else
Willy Tarreau86257dc2010-06-06 12:57:10 +0200343 eb = ebmb_lookup(&(t->keys), ts->key.key, t->key_size);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100344
Willy Tarreauf16d2b82010-06-06 15:38:59 +0200345 if (unlikely(!eb))
346 return NULL;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100347
Willy Tarreauf16d2b82010-06-06 15:38:59 +0200348 return ebmb_entry(eb, struct stksess, key);
349}
Emeric Brun3bd697e2010-01-04 15:23:48 +0100350
Emeric Brun819fc6f2017-06-13 19:37:32 +0200351/*
352 * Looks in table <t> for a sticky session with same key as <ts>.
353 * Returns pointer on requested sticky session or NULL if none was found.
354 * The refcount of the found entry is increased and this function
355 * is protected using the table lock
356 */
357struct stksess *stktable_lookup(struct stktable *t, struct stksess *ts)
358{
359 struct stksess *lts;
360
Willy Tarreaua7d6a132022-10-11 15:42:54 +0200361 HA_RWLOCK_RDLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200362 lts = __stktable_lookup(t, ts);
363 if (lts)
Willy Tarreaua7d6a132022-10-11 15:42:54 +0200364 HA_ATOMIC_INC(&lts->ref_cnt);
365 HA_RWLOCK_RDUNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200366
367 return lts;
368}
369
Willy Tarreaucb183642010-06-06 17:58:34 +0200370/* Update the expiration timer for <ts> but do not touch its expiration node.
371 * The table's expiration timer is updated if set.
Emeric Brun819fc6f2017-06-13 19:37:32 +0200372 * The node will be also inserted into the update tree if needed, at a position
Willy Tarreau9f5cb432022-10-11 18:17:58 +0000373 * depending if the update is a local or coming from a remote node.
374 * If <decrefcnt> is set, the ts entry's ref_cnt will be decremented. The table's
375 * write lock may be taken.
Willy Tarreaucb183642010-06-06 17:58:34 +0200376 */
Willy Tarreau9f5cb432022-10-11 18:17:58 +0000377void stktable_touch_with_exp(struct stktable *t, struct stksess *ts, int local, int expire, int decrefcnt)
Willy Tarreaucb183642010-06-06 17:58:34 +0200378{
Emeric Brun85e77c72010-09-23 18:16:52 +0200379 struct eb32_node * eb;
Willy Tarreaua7536ef2022-10-11 18:31:04 +0000380 int locked = 0;
Willy Tarreau9f5cb432022-10-11 18:17:58 +0000381
Willy Tarreaua7536ef2022-10-11 18:31:04 +0000382 if (expire != HA_ATOMIC_LOAD(&ts->expire)) {
383 /* we'll need to set the expiration and to wake up the expiration timer .*/
384 HA_ATOMIC_STORE(&ts->expire, expire);
385 if (t->expire) {
386 if (!locked++)
387 HA_RWLOCK_WRLOCK(STK_TABLE_LOCK, &t->lock);
388 t->exp_task->expire = t->exp_next = tick_first(expire, t->exp_next);
389 task_queue(t->exp_task);
390 /* keep the lock */
391 }
Willy Tarreaucb183642010-06-06 17:58:34 +0200392 }
Emeric Brun85e77c72010-09-23 18:16:52 +0200393
Emeric Brun819fc6f2017-06-13 19:37:32 +0200394 /* If sync is enabled */
395 if (t->sync_task) {
396 if (local) {
397 /* If this entry is not in the tree
Willy Tarreaua7536ef2022-10-11 18:31:04 +0000398 * or not scheduled for at least one peer.
399 */
400 if (!locked++)
401 HA_RWLOCK_WRLOCK(STK_TABLE_LOCK, &t->lock);
402
Emeric Brun819fc6f2017-06-13 19:37:32 +0200403 if (!ts->upd.node.leaf_p
404 || (int)(t->commitupdate - ts->upd.key) >= 0
405 || (int)(ts->upd.key - t->localupdate) >= 0) {
406 ts->upd.key = ++t->update;
407 t->localupdate = t->update;
408 eb32_delete(&ts->upd);
409 eb = eb32_insert(&t->updates, &ts->upd);
410 if (eb != &ts->upd) {
411 eb32_delete(eb);
412 eb32_insert(&t->updates, &ts->upd);
413 }
Emeric Brunaaf58602015-06-15 17:23:30 +0200414 }
Emeric Brun819fc6f2017-06-13 19:37:32 +0200415 task_wakeup(t->sync_task, TASK_WOKEN_MSG);
Emeric Brun85e77c72010-09-23 18:16:52 +0200416 }
Emeric Brun819fc6f2017-06-13 19:37:32 +0200417 else {
418 /* If this entry is not in the tree */
Willy Tarreaua7536ef2022-10-11 18:31:04 +0000419 if (!locked++)
420 HA_RWLOCK_WRLOCK(STK_TABLE_LOCK, &t->lock);
421
Emeric Brun819fc6f2017-06-13 19:37:32 +0200422 if (!ts->upd.node.leaf_p) {
423 ts->upd.key= (++t->update)+(2147483648U);
424 eb = eb32_insert(&t->updates, &ts->upd);
425 if (eb != &ts->upd) {
426 eb32_delete(eb);
427 eb32_insert(&t->updates, &ts->upd);
428 }
429 }
430 }
Emeric Brun85e77c72010-09-23 18:16:52 +0200431 }
Willy Tarreau9f5cb432022-10-11 18:17:58 +0000432
Willy Tarreaua7536ef2022-10-11 18:31:04 +0000433 if (decrefcnt) {
434 if (locked)
435 ts->ref_cnt--;
436 else {
437 HA_RWLOCK_RDLOCK(STK_TABLE_LOCK, &t->lock);
438 HA_ATOMIC_DEC(&ts->ref_cnt);
439 HA_RWLOCK_RDUNLOCK(STK_TABLE_LOCK, &t->lock);
440 }
441 }
442
443 if (locked)
444 HA_RWLOCK_WRUNLOCK(STK_TABLE_LOCK, &t->lock);
Willy Tarreaucb183642010-06-06 17:58:34 +0200445}
446
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200447/* Update the expiration timer for <ts> but do not touch its expiration node.
Emeric Brun819fc6f2017-06-13 19:37:32 +0200448 * The table's expiration timer is updated using the date of expiration coming from
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200449 * <t> stick-table configuration.
Emeric Brun819fc6f2017-06-13 19:37:32 +0200450 * The node will be also inserted into the update tree if needed, at a position
451 * considering the update is coming from a remote node
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200452 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200453void stktable_touch_remote(struct stktable *t, struct stksess *ts, int decrefcnt)
454{
Willy Tarreau9f5cb432022-10-11 18:17:58 +0000455 stktable_touch_with_exp(t, ts, 0, ts->expire, decrefcnt);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200456}
457
458/* Update the expiration timer for <ts> but do not touch its expiration node.
459 * The table's expiration timer is updated using the date of expiration coming from
460 * <t> stick-table configuration.
461 * The node will be also inserted into the update tree if needed, at a position
462 * considering the update was made locally
463 */
464void stktable_touch_local(struct stktable *t, struct stksess *ts, int decrefcnt)
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200465{
466 int expire = tick_add(now_ms, MS_TO_TICKS(t->expire));
467
Willy Tarreau9f5cb432022-10-11 18:17:58 +0000468 stktable_touch_with_exp(t, ts, 1, expire, decrefcnt);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200469}
Willy Tarreau4be073b2022-10-11 18:10:27 +0000470/* Just decrease the ref_cnt of the current session. Does nothing if <ts> is NULL.
471 * Note that we still need to take the read lock because a number of other places
472 * (including in Lua and peers) update the ref_cnt non-atomically under the write
473 * lock.
474 */
Willy Tarreau43e90352018-06-27 06:25:57 +0200475static void stktable_release(struct stktable *t, struct stksess *ts)
Emeric Brun819fc6f2017-06-13 19:37:32 +0200476{
Willy Tarreau43e90352018-06-27 06:25:57 +0200477 if (!ts)
478 return;
Willy Tarreau4be073b2022-10-11 18:10:27 +0000479 HA_RWLOCK_RDLOCK(STK_TABLE_LOCK, &t->lock);
480 HA_ATOMIC_DEC(&ts->ref_cnt);
481 HA_RWLOCK_RDUNLOCK(STK_TABLE_LOCK, &t->lock);
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200482}
483
Willy Tarreauf16d2b82010-06-06 15:38:59 +0200484/* Insert new sticky session <ts> in the table. It is assumed that it does not
485 * yet exist (the caller must check this). The table's timeout is updated if it
Willy Tarreaud2d3fd92022-10-11 15:09:46 +0200486 * is set. <ts> is returned if properly inserted, otherwise the one already
487 * present if any.
Willy Tarreauf16d2b82010-06-06 15:38:59 +0200488 */
Willy Tarreaud2d3fd92022-10-11 15:09:46 +0200489struct stksess *__stktable_store(struct stktable *t, struct stksess *ts)
Willy Tarreauf16d2b82010-06-06 15:38:59 +0200490{
Willy Tarreaud2d3fd92022-10-11 15:09:46 +0200491 struct ebmb_node *eb;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100492
Willy Tarreaud2d3fd92022-10-11 15:09:46 +0200493 eb = ebmb_insert(&t->keys, &ts->key, t->key_size);
494 if (likely(eb == &ts->key)) {
495 ts->exp.key = ts->expire;
496 eb32_insert(&t->exps, &ts->exp);
497 }
Emeric Brun819fc6f2017-06-13 19:37:32 +0200498 if (t->expire) {
499 t->exp_task->expire = t->exp_next = tick_first(ts->expire, t->exp_next);
500 task_queue(t->exp_task);
501 }
Willy Tarreaud2d3fd92022-10-11 15:09:46 +0200502 return ebmb_entry(eb, struct stksess, key); // most commonly this is <ts>
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200503}
504
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200505/* Returns a valid or initialized stksess for the specified stktable_key in the
506 * specified table, or NULL if the key was NULL, or if no entry was found nor
Willy Tarreau47f22972022-10-11 15:22:42 +0200507 * could be created. The entry's expiration is updated. This function locks the
508 * table, and the refcount of the entry is increased.
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200509 */
Willy Tarreau47f22972022-10-11 15:22:42 +0200510struct stksess *stktable_get_entry(struct stktable *table, struct stktable_key *key)
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200511{
Willy Tarreau175aa062022-10-11 15:13:46 +0200512 struct stksess *ts, *ts2;
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200513
514 if (!key)
515 return NULL;
516
Willy Tarreau47f22972022-10-11 15:22:42 +0200517 ts = stktable_lookup_key(table, key);
518 if (ts)
519 return ts;
Emeric Brun819fc6f2017-06-13 19:37:32 +0200520
Willy Tarreau996f1a52022-10-11 16:19:35 +0200521 /* No such entry exists, let's try to create a new one. this doesn't
522 * require locking yet.
523 */
524
525 ts = stksess_new(table, key);
526 if (!ts)
527 return NULL;
528
529 /* Now we're certain to have a ts. We need to store it. For this we'll
Willy Tarreau47f22972022-10-11 15:22:42 +0200530 * need an exclusive access. We don't need an atomic upgrade, this is
531 * rare and an unlock+lock sequence will do the job fine. Given that
532 * this will not be atomic, the missing entry might appear in the mean
533 * tome so we have to be careful that the one we try to insert is the
534 * one we find.
535 */
Willy Tarreau47f22972022-10-11 15:22:42 +0200536
Willy Tarreau996f1a52022-10-11 16:19:35 +0200537 HA_RWLOCK_WRLOCK(STK_TABLE_LOCK, &table->lock);
Willy Tarreau47f22972022-10-11 15:22:42 +0200538
539 ts2 = __stktable_store(table, ts);
540 if (unlikely(ts2 != ts)) {
541 /* another entry was added in the mean time, let's
542 * switch to it.
543 */
544 __stksess_free(table, ts);
545 ts = ts2;
546 }
547
548 HA_ATOMIC_INC(&ts->ref_cnt);
Willy Tarreau76642222022-10-11 12:02:50 +0200549 HA_RWLOCK_WRUNLOCK(STK_TABLE_LOCK, &table->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200550
551 return ts;
552}
553
554/* Lookup for an entry with the same key and store the submitted
Willy Tarreaue6288522022-10-12 09:13:14 +0000555 * stksess if not found. This function locks the table either shared or
556 * exclusively, and the refcount of the entry is increased.
Emeric Brun819fc6f2017-06-13 19:37:32 +0200557 */
Willy Tarreaue6288522022-10-12 09:13:14 +0000558struct stksess *stktable_set_entry(struct stktable *table, struct stksess *nts)
Emeric Brun819fc6f2017-06-13 19:37:32 +0200559{
560 struct stksess *ts;
561
Willy Tarreaue6288522022-10-12 09:13:14 +0000562 HA_RWLOCK_RDLOCK(STK_TABLE_LOCK, &table->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200563 ts = __stktable_lookup(table, nts);
Willy Tarreaue6288522022-10-12 09:13:14 +0000564 if (ts) {
565 HA_ATOMIC_INC(&ts->ref_cnt);
566 HA_RWLOCK_RDUNLOCK(STK_TABLE_LOCK, &table->lock);
567 return ts;
Emeric Brun819fc6f2017-06-13 19:37:32 +0200568 }
Willy Tarreaue6288522022-10-12 09:13:14 +0000569 ts = nts;
Emeric Brun819fc6f2017-06-13 19:37:32 +0200570
Willy Tarreaue6288522022-10-12 09:13:14 +0000571 /* let's increment it before switching to exclusive */
572 HA_ATOMIC_INC(&ts->ref_cnt);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200573
Willy Tarreaue6288522022-10-12 09:13:14 +0000574 if (HA_RWLOCK_TRYRDTOSK(STK_TABLE_LOCK, &table->lock) != 0) {
575 /* upgrade to seek lock failed, let's drop and take */
576 HA_RWLOCK_RDUNLOCK(STK_TABLE_LOCK, &table->lock);
577 HA_RWLOCK_WRLOCK(STK_TABLE_LOCK, &table->lock);
578 }
579 else
580 HA_RWLOCK_SKTOWR(STK_TABLE_LOCK, &table->lock);
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200581
Willy Tarreaue6288522022-10-12 09:13:14 +0000582 /* now we're write-locked */
583
584 __stktable_store(table, ts);
585 HA_RWLOCK_WRUNLOCK(STK_TABLE_LOCK, &table->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200586 return ts;
587}
Willy Tarreaue6288522022-10-12 09:13:14 +0000588
Emeric Brun3bd697e2010-01-04 15:23:48 +0100589/*
Willy Tarreauaea940e2010-06-06 11:56:36 +0200590 * Trash expired sticky sessions from table <t>. The next expiration date is
591 * returned.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100592 */
593static int stktable_trash_expired(struct stktable *t)
594{
595 struct stksess *ts;
596 struct eb32_node *eb;
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200597 int looped = 0;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100598
Willy Tarreau76642222022-10-11 12:02:50 +0200599 HA_RWLOCK_WRLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100600 eb = eb32_lookup_ge(&t->exps, now_ms - TIMER_LOOK_BACK);
601
602 while (1) {
603 if (unlikely(!eb)) {
604 /* we might have reached the end of the tree, typically because
605 * <now_ms> is in the first half and we're first scanning the last
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200606 * half. Let's loop back to the beginning of the tree now if we
607 * have not yet visited it.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100608 */
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200609 if (looped)
610 break;
611 looped = 1;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100612 eb = eb32_first(&t->exps);
613 if (likely(!eb))
614 break;
615 }
616
617 if (likely(tick_is_lt(now_ms, eb->key))) {
618 /* timer not expired yet, revisit it later */
619 t->exp_next = eb->key;
Willy Tarreau4d5f13c2017-11-05 11:04:47 +0100620 goto out_unlock;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100621 }
622
623 /* timer looks expired, detach it from the queue */
Willy Tarreau86257dc2010-06-06 12:57:10 +0200624 ts = eb32_entry(eb, struct stksess, exp);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100625 eb = eb32_next(eb);
626
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200627 /* don't delete an entry which is currently referenced */
628 if (ts->ref_cnt)
629 continue;
630
Willy Tarreau86257dc2010-06-06 12:57:10 +0200631 eb32_delete(&ts->exp);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100632
633 if (!tick_is_expired(ts->expire, now_ms)) {
634 if (!tick_isset(ts->expire))
635 continue;
636
Willy Tarreau86257dc2010-06-06 12:57:10 +0200637 ts->exp.key = ts->expire;
638 eb32_insert(&t->exps, &ts->exp);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100639
Willy Tarreau86257dc2010-06-06 12:57:10 +0200640 if (!eb || eb->key > ts->exp.key)
641 eb = &ts->exp;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100642 continue;
643 }
644
645 /* session expired, trash it */
Willy Tarreau86257dc2010-06-06 12:57:10 +0200646 ebmb_delete(&ts->key);
Emeric Brun85e77c72010-09-23 18:16:52 +0200647 eb32_delete(&ts->upd);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200648 __stksess_free(t, ts);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100649 }
650
651 /* We have found no task to expire in any tree */
652 t->exp_next = TICK_ETERNITY;
Willy Tarreau4d5f13c2017-11-05 11:04:47 +0100653out_unlock:
Willy Tarreau76642222022-10-11 12:02:50 +0200654 HA_RWLOCK_WRUNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100655 return t->exp_next;
656}
657
658/*
Willy Tarreauaea940e2010-06-06 11:56:36 +0200659 * Task processing function to trash expired sticky sessions. A pointer to the
660 * task itself is returned since it never dies.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100661 */
Willy Tarreau144f84a2021-03-02 16:09:26 +0100662struct task *process_table_expire(struct task *task, void *context, unsigned int state)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100663{
Olivier Houchard9f6af332018-05-25 14:04:04 +0200664 struct stktable *t = context;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100665
666 task->expire = stktable_trash_expired(t);
667 return task;
668}
669
Willy Tarreauaea940e2010-06-06 11:56:36 +0200670/* Perform minimal stick table intializations, report 0 in case of error, 1 if OK. */
Emeric Brun3bd697e2010-01-04 15:23:48 +0100671int stktable_init(struct stktable *t)
672{
Remi Tricot-Le Breton208ff012021-05-12 17:39:04 +0200673 int peers_retval = 0;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100674 if (t->size) {
Emeric Brun819fc6f2017-06-13 19:37:32 +0200675 t->keys = EB_ROOT_UNIQUE;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100676 memset(&t->exps, 0, sizeof(t->exps));
Emeric Brun1c6235d2015-12-16 15:28:12 +0100677 t->updates = EB_ROOT_UNIQUE;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100678 HA_SPIN_INIT(&t->lock);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100679
Olivier Houchard52dabbc2018-11-14 17:54:36 +0100680 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 +0100681
682 t->exp_next = TICK_ETERNITY;
683 if ( t->expire ) {
Willy Tarreaubeeabf52021-10-01 18:23:30 +0200684 t->exp_task = task_new_anywhere();
Willy Tarreau848522f2018-10-15 11:12:15 +0200685 if (!t->exp_task)
686 return 0;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100687 t->exp_task->process = process_table_expire;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100688 t->exp_task->context = (void *)t;
689 }
Christopher Fauletdfd10ab2021-10-06 14:24:19 +0200690 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 +0200691 peers_retval = peers_register_table(t->peers.p, t);
Emeric Brun32da3c42010-09-23 18:39:19 +0200692 }
693
Remi Tricot-Le Breton208ff012021-05-12 17:39:04 +0200694 return (t->pool != NULL) && !peers_retval;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100695 }
696 return 1;
697}
698
699/*
700 * Configuration keywords of known table types
701 */
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200702struct stktable_type stktable_types[SMP_TYPES] = {
703 [SMP_T_SINT] = { "integer", 0, 4 },
704 [SMP_T_IPV4] = { "ip", 0, 4 },
705 [SMP_T_IPV6] = { "ipv6", 0, 16 },
706 [SMP_T_STR] = { "string", STK_F_CUSTOM_KEYSIZE, 32 },
707 [SMP_T_BIN] = { "binary", STK_F_CUSTOM_KEYSIZE, 32 }
708};
Emeric Brun3bd697e2010-01-04 15:23:48 +0100709
710/*
711 * Parse table type configuration.
712 * Returns 0 on successful parsing, else 1.
713 * <myidx> is set at next configuration <args> index.
714 */
715int stktable_parse_type(char **args, int *myidx, unsigned long *type, size_t *key_size)
716{
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200717 for (*type = 0; *type < SMP_TYPES; (*type)++) {
718 if (!stktable_types[*type].kw)
719 continue;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100720 if (strcmp(args[*myidx], stktable_types[*type].kw) != 0)
721 continue;
722
723 *key_size = stktable_types[*type].default_size;
724 (*myidx)++;
725
Willy Tarreauaea940e2010-06-06 11:56:36 +0200726 if (stktable_types[*type].flags & STK_F_CUSTOM_KEYSIZE) {
Emeric Brun3bd697e2010-01-04 15:23:48 +0100727 if (strcmp("len", args[*myidx]) == 0) {
728 (*myidx)++;
729 *key_size = atol(args[*myidx]);
Emeric Brun485479d2010-09-23 18:02:19 +0200730 if (!*key_size)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100731 break;
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200732 if (*type == SMP_T_STR) {
Emeric Brun485479d2010-09-23 18:02:19 +0200733 /* null terminated string needs +1 for '\0'. */
734 (*key_size)++;
735 }
Emeric Brun3bd697e2010-01-04 15:23:48 +0100736 (*myidx)++;
737 }
738 }
739 return 0;
740 }
741 return 1;
742}
743
Emeric Brunc64a2a32021-06-30 18:01:02 +0200744/* reserve some space for data type <type>, there is 2 optionnals
745 * argument at <sa> and <sa2> to configure this data type and
746 * they can be NULL if unused for a given type.
747 * Returns PE_NONE (0) if OK or an error code among :
Willy Tarreau3b63ca22021-05-08 14:10:42 +0200748 * - PE_ENUM_OOR if <type> does not exist
749 * - PE_EXIST if <type> is already registered
Emeric Brunc64a2a32021-06-30 18:01:02 +0200750 * - PE_ARG_NOT_USE if <sa>/<sa2> was provided but not expected
751 * - PE_ARG_MISSING if <sa>/<sa2> was expected but not provided
752 * - PE_ARG_VALUE_OOR if type is an array and <sa> it out of array size range.
Willy Tarreau3b63ca22021-05-08 14:10:42 +0200753 */
Emeric Brunc64a2a32021-06-30 18:01:02 +0200754int stktable_alloc_data_type(struct stktable *t, int type, const char *sa, const char *sa2)
755
Willy Tarreau3b63ca22021-05-08 14:10:42 +0200756{
757 if (type >= STKTABLE_DATA_TYPES)
758 return PE_ENUM_OOR;
759
760 if (t->data_ofs[type])
761 /* already allocated */
762 return PE_EXIST;
763
Emeric Brunc64a2a32021-06-30 18:01:02 +0200764 t->data_nbelem[type] = 1;
765 if (stktable_data_types[type].is_array) {
766 /* arrays take their element count on first argument */
767 if (!sa)
768 return PE_ARG_MISSING;
769 t->data_nbelem[type] = atoi(sa);
770 if (!t->data_nbelem[type] || (t->data_nbelem[type] > STKTABLE_MAX_DT_ARRAY_SIZE))
771 return PE_ARG_VALUE_OOR;
772 sa = sa2;
773 }
774
Willy Tarreau3b63ca22021-05-08 14:10:42 +0200775 switch (stktable_data_types[type].arg_type) {
776 case ARG_T_NONE:
777 if (sa)
778 return PE_ARG_NOT_USED;
779 break;
780 case ARG_T_INT:
781 if (!sa)
782 return PE_ARG_MISSING;
783 t->data_arg[type].i = atoi(sa);
784 break;
785 case ARG_T_DELAY:
786 if (!sa)
787 return PE_ARG_MISSING;
788 sa = parse_time_err(sa, &t->data_arg[type].u, TIME_UNIT_MS);
789 if (sa)
790 return PE_ARG_INVC; /* invalid char */
791 break;
792 }
793
Emeric Brunc64a2a32021-06-30 18:01:02 +0200794 t->data_size += t->data_nbelem[type] * stktable_type_size(stktable_data_types[type].std_type);
Willy Tarreau3b63ca22021-05-08 14:10:42 +0200795 t->data_ofs[type] = -t->data_size;
796 return PE_NONE;
797}
798
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100799/*
Frédéric Lécaillec02766a2019-03-20 15:06:55 +0100800 * Parse a line with <linenum> as number in <file> configuration file to configure
801 * the stick-table with <t> as address and <id> as ID.
802 * <peers> provides the "peers" section pointer only if this function is called
803 * from a "peers" section.
804 * <nid> is the stick-table name which is sent over the network. It must be equal
805 * to <id> if this stick-table is parsed from a proxy section, and prefixed by <peers>
806 * "peers" section name followed by a '/' character if parsed from a "peers" section.
Ilya Shipitsind4259502020-04-08 01:07:56 +0500807 * This is the responsibility of the caller to check this.
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100808 * Return an error status with ERR_* flags set if required, 0 if no error was encountered.
809 */
810int parse_stick_table(const char *file, int linenum, char **args,
Frédéric Lécaillec02766a2019-03-20 15:06:55 +0100811 struct stktable *t, char *id, char *nid, struct peers *peers)
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100812{
813 int err_code = 0;
814 int idx = 1;
815 unsigned int val;
816
817 if (!id || !*id) {
818 ha_alert("parsing [%s:%d] : %s: ID not provided.\n", file, linenum, args[0]);
819 err_code |= ERR_ALERT | ERR_ABORT;
820 goto out;
821 }
822
823 /* Store the "peers" section if this function is called from a "peers" section. */
824 if (peers) {
825 t->peers.p = peers;
826 idx++;
827 }
828
829 t->id = id;
Frédéric Lécaillec02766a2019-03-20 15:06:55 +0100830 t->nid = nid;
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100831 t->type = (unsigned int)-1;
832 t->conf.file = file;
833 t->conf.line = linenum;
834
835 while (*args[idx]) {
836 const char *err;
837
838 if (strcmp(args[idx], "size") == 0) {
839 idx++;
840 if (!*(args[idx])) {
841 ha_alert("parsing [%s:%d] : %s: missing argument after '%s'.\n",
842 file, linenum, args[0], args[idx-1]);
843 err_code |= ERR_ALERT | ERR_FATAL;
844 goto out;
845 }
846 if ((err = parse_size_err(args[idx], &t->size))) {
847 ha_alert("parsing [%s:%d] : %s: unexpected character '%c' in argument of '%s'.\n",
848 file, linenum, args[0], *err, args[idx-1]);
849 err_code |= ERR_ALERT | ERR_FATAL;
850 goto out;
851 }
852 idx++;
853 }
854 /* This argument does not exit in "peers" section. */
855 else if (!peers && strcmp(args[idx], "peers") == 0) {
856 idx++;
857 if (!*(args[idx])) {
858 ha_alert("parsing [%s:%d] : %s: missing argument after '%s'.\n",
859 file, linenum, args[0], args[idx-1]);
860 err_code |= ERR_ALERT | ERR_FATAL;
861 goto out;
862 }
863 t->peers.name = strdup(args[idx++]);
864 }
865 else if (strcmp(args[idx], "expire") == 0) {
866 idx++;
867 if (!*(args[idx])) {
868 ha_alert("parsing [%s:%d] : %s: missing argument after '%s'.\n",
869 file, linenum, args[0], args[idx-1]);
870 err_code |= ERR_ALERT | ERR_FATAL;
871 goto out;
872 }
873 err = parse_time_err(args[idx], &val, TIME_UNIT_MS);
Willy Tarreau9faebe32019-06-07 19:00:37 +0200874 if (err == PARSE_TIME_OVER) {
875 ha_alert("parsing [%s:%d]: %s: timer overflow in argument <%s> to <%s>, maximum value is 2147483647 ms (~24.8 days).\n",
876 file, linenum, args[0], args[idx], args[idx-1]);
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100877 err_code |= ERR_ALERT | ERR_FATAL;
878 goto out;
879 }
Willy Tarreau9faebe32019-06-07 19:00:37 +0200880 else if (err == PARSE_TIME_UNDER) {
881 ha_alert("parsing [%s:%d]: %s: timer underflow in argument <%s> to <%s>, minimum non-null value is 1 ms.\n",
882 file, linenum, args[0], args[idx], args[idx-1]);
883 err_code |= ERR_ALERT | ERR_FATAL;
884 goto out;
885 }
886 else if (err) {
887 ha_alert("parsing [%s:%d] : %s: unexpected character '%c' in argument of '%s'.\n",
888 file, linenum, args[0], *err, args[idx-1]);
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100889 err_code |= ERR_ALERT | ERR_FATAL;
890 goto out;
891 }
892 t->expire = val;
893 idx++;
894 }
895 else if (strcmp(args[idx], "nopurge") == 0) {
896 t->nopurge = 1;
897 idx++;
898 }
899 else if (strcmp(args[idx], "type") == 0) {
900 idx++;
901 if (stktable_parse_type(args, &idx, &t->type, &t->key_size) != 0) {
902 ha_alert("parsing [%s:%d] : %s: unknown type '%s'.\n",
903 file, linenum, args[0], args[idx]);
904 err_code |= ERR_ALERT | ERR_FATAL;
905 goto out;
906 }
907 /* idx already points to next arg */
908 }
909 else if (strcmp(args[idx], "store") == 0) {
910 int type, err;
Emeric Brunc64a2a32021-06-30 18:01:02 +0200911 char *cw, *nw, *sa, *sa2;
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100912
913 idx++;
914 nw = args[idx];
915 while (*nw) {
916 /* the "store" keyword supports a comma-separated list */
917 cw = nw;
918 sa = NULL; /* store arg */
Emeric Brunc64a2a32021-06-30 18:01:02 +0200919 sa2 = NULL;
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100920 while (*nw && *nw != ',') {
921 if (*nw == '(') {
922 *nw = 0;
923 sa = ++nw;
924 while (*nw != ')') {
925 if (!*nw) {
926 ha_alert("parsing [%s:%d] : %s: missing closing parenthesis after store option '%s'.\n",
927 file, linenum, args[0], cw);
928 err_code |= ERR_ALERT | ERR_FATAL;
929 goto out;
930 }
Emeric Brunc64a2a32021-06-30 18:01:02 +0200931 if (*nw == ',') {
932 *nw = '\0';
933 sa2 = nw + 1;
934 }
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100935 nw++;
936 }
937 *nw = '\0';
938 }
939 nw++;
940 }
941 if (*nw)
942 *nw++ = '\0';
943 type = stktable_get_data_type(cw);
944 if (type < 0) {
945 ha_alert("parsing [%s:%d] : %s: unknown store option '%s'.\n",
946 file, linenum, args[0], cw);
947 err_code |= ERR_ALERT | ERR_FATAL;
948 goto out;
949 }
950
Emeric Brunc64a2a32021-06-30 18:01:02 +0200951 err = stktable_alloc_data_type(t, type, sa, sa2);
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100952 switch (err) {
953 case PE_NONE: break;
954 case PE_EXIST:
955 ha_warning("parsing [%s:%d]: %s: store option '%s' already enabled, ignored.\n",
956 file, linenum, args[0], cw);
957 err_code |= ERR_WARN;
958 break;
959
960 case PE_ARG_MISSING:
961 ha_alert("parsing [%s:%d] : %s: missing argument to store option '%s'.\n",
962 file, linenum, args[0], cw);
963 err_code |= ERR_ALERT | ERR_FATAL;
964 goto out;
965
966 case PE_ARG_NOT_USED:
967 ha_alert("parsing [%s:%d] : %s: unexpected argument to store option '%s'.\n",
968 file, linenum, args[0], cw);
969 err_code |= ERR_ALERT | ERR_FATAL;
970 goto out;
Emeric Brunc64a2a32021-06-30 18:01:02 +0200971 case PE_ARG_VALUE_OOR:
972 ha_alert("parsing [%s:%d] : %s: array size is out of allowed range (1-%d) for store option '%s'.\n",
973 file, linenum, args[0], STKTABLE_MAX_DT_ARRAY_SIZE, cw);
974 err_code |= ERR_ALERT | ERR_FATAL;
975 goto out;
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100976
977 default:
978 ha_alert("parsing [%s:%d] : %s: error when processing store option '%s'.\n",
979 file, linenum, args[0], cw);
980 err_code |= ERR_ALERT | ERR_FATAL;
981 goto out;
982 }
983 }
984 idx++;
Emeric Brunf7ab0bf2021-06-30 18:58:22 +0200985 if (t->data_ofs[STKTABLE_DT_GPT] && t->data_ofs[STKTABLE_DT_GPT0]) {
986 ha_alert("parsing [%s:%d] : %s: simultaneous usage of 'gpt' and 'gpt0' in a same table is not permitted as 'gpt' overrides 'gpt0'.\n",
987 file, linenum, args[0]);
988 err_code |= ERR_ALERT | ERR_FATAL;
989 goto out;
990 }
Emeric Brun726783d2021-06-30 19:06:43 +0200991 else if (t->data_ofs[STKTABLE_DT_GPC] && (t->data_ofs[STKTABLE_DT_GPC0] || t->data_ofs[STKTABLE_DT_GPC1])) {
992 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",
993 file, linenum, args[0]);
994 err_code |= ERR_ALERT | ERR_FATAL;
995 goto out;
996 }
997 else if (t->data_ofs[STKTABLE_DT_GPC_RATE] && (t->data_ofs[STKTABLE_DT_GPC0_RATE] || t->data_ofs[STKTABLE_DT_GPC1_RATE])) {
998 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",
999 file, linenum, args[0]);
1000 err_code |= ERR_ALERT | ERR_FATAL;
1001 goto out;
1002 }
Frédéric Lécailled456aa42019-03-08 14:47:00 +01001003 }
Thayne McCombs92149f92020-11-20 01:28:26 -07001004 else if (strcmp(args[idx], "srvkey") == 0) {
1005 char *keytype;
1006 idx++;
1007 keytype = args[idx];
1008 if (strcmp(keytype, "name") == 0) {
1009 t->server_key_type = STKTABLE_SRV_NAME;
1010 }
1011 else if (strcmp(keytype, "addr") == 0) {
1012 t->server_key_type = STKTABLE_SRV_ADDR;
1013 }
1014 else {
1015 ha_alert("parsing [%s:%d] : %s : unknown server key type '%s'.\n",
1016 file, linenum, args[0], keytype);
1017 err_code |= ERR_ALERT | ERR_FATAL;
1018 goto out;
1019
1020 }
1021 idx++;
1022 }
Frédéric Lécailled456aa42019-03-08 14:47:00 +01001023 else {
1024 ha_alert("parsing [%s:%d] : %s: unknown argument '%s'.\n",
1025 file, linenum, args[0], args[idx]);
1026 err_code |= ERR_ALERT | ERR_FATAL;
1027 goto out;
1028 }
1029 }
1030
1031 if (!t->size) {
1032 ha_alert("parsing [%s:%d] : %s: missing size.\n",
1033 file, linenum, args[0]);
1034 err_code |= ERR_ALERT | ERR_FATAL;
1035 goto out;
1036 }
1037
1038 if (t->type == (unsigned int)-1) {
1039 ha_alert("parsing [%s:%d] : %s: missing type.\n",
1040 file, linenum, args[0]);
1041 err_code |= ERR_ALERT | ERR_FATAL;
1042 goto out;
1043 }
1044
1045 out:
1046 return err_code;
1047}
1048
Willy Tarreau8fed9032014-07-03 17:02:46 +02001049/* Prepares a stktable_key from a sample <smp> to search into table <t>.
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001050 * Note that the sample *is* modified and that the returned key may point
1051 * to it, so the sample must not be modified afterwards before the lookup.
Willy Tarreau8fed9032014-07-03 17:02:46 +02001052 * Returns NULL if the sample could not be converted (eg: no matching type),
1053 * otherwise a pointer to the static stktable_key filled with what is needed
1054 * for the lookup.
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001055 */
Willy Tarreau8fed9032014-07-03 17:02:46 +02001056struct stktable_key *smp_to_stkey(struct sample *smp, struct stktable *t)
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001057{
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001058 /* Convert sample. */
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +02001059 if (!sample_convert(smp, t->type))
Willy Tarreau7fc1c6e2012-04-26 11:03:17 +02001060 return NULL;
1061
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001062 /* Fill static_table_key. */
1063 switch (t->type) {
Emeric Brun485479d2010-09-23 18:02:19 +02001064
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +02001065 case SMP_T_IPV4:
Christopher Fauletca20d022017-08-29 15:30:31 +02001066 static_table_key.key = &smp->data.u.ipv4;
1067 static_table_key.key_len = 4;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001068 break;
Emeric Brun485479d2010-09-23 18:02:19 +02001069
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +02001070 case SMP_T_IPV6:
Christopher Fauletca20d022017-08-29 15:30:31 +02001071 static_table_key.key = &smp->data.u.ipv6;
1072 static_table_key.key_len = 16;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001073 break;
Emeric Brun485479d2010-09-23 18:02:19 +02001074
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +02001075 case SMP_T_SINT:
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001076 /* The stick table require a 32bit unsigned int, "sint" is a
1077 * signed 64 it, so we can convert it inplace.
1078 */
Willy Tarreau28c63c12019-10-23 06:21:05 +02001079 smp->data.u.sint = (unsigned int)smp->data.u.sint;
Christopher Fauletca20d022017-08-29 15:30:31 +02001080 static_table_key.key = &smp->data.u.sint;
1081 static_table_key.key_len = 4;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001082 break;
1083
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +02001084 case SMP_T_STR:
Willy Tarreauce6955e2016-08-09 11:59:12 +02001085 if (!smp_make_safe(smp))
1086 return NULL;
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001087 static_table_key.key = smp->data.u.str.area;
1088 static_table_key.key_len = smp->data.u.str.data;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001089 break;
Emeric Brun485479d2010-09-23 18:02:19 +02001090
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +02001091 case SMP_T_BIN:
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001092 if (smp->data.u.str.data < t->key_size) {
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001093 /* This type needs padding with 0. */
Willy Tarreauf65c6c02016-08-09 12:08:41 +02001094 if (!smp_make_rw(smp))
1095 return NULL;
1096
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001097 if (smp->data.u.str.size < t->key_size)
1098 if (!smp_dup(smp))
1099 return NULL;
1100 if (smp->data.u.str.size < t->key_size)
1101 return NULL;
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001102 memset(smp->data.u.str.area + smp->data.u.str.data, 0,
1103 t->key_size - smp->data.u.str.data);
1104 smp->data.u.str.data = t->key_size;
Emeric Brun485479d2010-09-23 18:02:19 +02001105 }
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001106 static_table_key.key = smp->data.u.str.area;
1107 static_table_key.key_len = smp->data.u.str.data;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001108 break;
Emeric Brun485479d2010-09-23 18:02:19 +02001109
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001110 default: /* impossible case. */
1111 return NULL;
Emeric Brun485479d2010-09-23 18:02:19 +02001112 }
1113
Christopher Fauletca20d022017-08-29 15:30:31 +02001114 return &static_table_key;
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001115}
1116
1117/*
Willy Tarreau8fed9032014-07-03 17:02:46 +02001118 * Process a fetch + format conversion as defined by the sample expression <expr>
1119 * on request or response considering the <opt> parameter. Returns either NULL if
1120 * no key could be extracted, or a pointer to the converted result stored in
1121 * static_table_key in format <table_type>. If <smp> is not NULL, it will be reset
1122 * and its flags will be initialized so that the caller gets a copy of the input
Willy Tarreau6bcb0a82014-07-30 08:56:35 +02001123 * sample, and knows why it was not accepted (eg: SMP_F_MAY_CHANGE is present
1124 * without SMP_OPT_FINAL). The output will be usable like this :
1125 *
1126 * return MAY_CHANGE FINAL Meaning for the sample
1127 * NULL 0 * Not present and will never be (eg: header)
1128 * NULL 1 0 Not present or unstable, could change (eg: req_len)
1129 * NULL 1 1 Not present, will not change anymore
1130 * smp 0 * Present and will not change (eg: header)
1131 * smp 1 0 not possible
1132 * smp 1 1 Present, last known value (eg: request length)
Willy Tarreau8fed9032014-07-03 17:02:46 +02001133 */
Willy Tarreau192252e2015-04-04 01:47:55 +02001134struct stktable_key *stktable_fetch_key(struct stktable *t, struct proxy *px, struct session *sess, struct stream *strm,
Willy Tarreau8fed9032014-07-03 17:02:46 +02001135 unsigned int opt, struct sample_expr *expr, struct sample *smp)
1136{
1137 if (smp)
1138 memset(smp, 0, sizeof(*smp));
1139
Willy Tarreau192252e2015-04-04 01:47:55 +02001140 smp = sample_process(px, sess, strm, opt, expr, smp);
Willy Tarreau8fed9032014-07-03 17:02:46 +02001141 if (!smp)
1142 return NULL;
1143
1144 if ((smp->flags & SMP_F_MAY_CHANGE) && !(opt & SMP_OPT_FINAL))
1145 return NULL; /* we can only use stable samples */
1146
1147 return smp_to_stkey(smp, t);
1148}
1149
1150/*
Willy Tarreau12785782012-04-27 21:37:17 +02001151 * Returns 1 if sample expression <expr> result can be converted to table key of
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001152 * type <table_type>, otherwise zero. Used in configuration check.
1153 */
Willy Tarreau12785782012-04-27 21:37:17 +02001154int stktable_compatible_sample(struct sample_expr *expr, unsigned long table_type)
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001155{
Thierry FOURNIERf73eb8f2013-11-27 15:30:55 +01001156 int out_type;
1157
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +02001158 if (table_type >= SMP_TYPES || !stktable_types[table_type].kw)
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001159 return 0;
1160
Thierry FOURNIERf73eb8f2013-11-27 15:30:55 +01001161 out_type = smp_expr_output_type(expr);
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001162
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001163 /* Convert sample. */
1164 if (!sample_casts[out_type][table_type])
Thierry FOURNIERf73eb8f2013-11-27 15:30:55 +01001165 return 0;
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001166
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001167 return 1;
1168}
Emeric Brun3bd697e2010-01-04 15:23:48 +01001169
Willy Tarreauedee1d62014-07-15 16:44:27 +02001170/* Extra data types processing : after the last one, some room may remain
1171 * before STKTABLE_DATA_TYPES that may be used to register extra data types
1172 * at run time.
1173 */
Willy Tarreau08d5f982010-06-06 13:34:54 +02001174struct stktable_data_type stktable_data_types[STKTABLE_DATA_TYPES] = {
Willy Tarreau3b9c6e02010-07-18 08:04:30 +02001175 [STKTABLE_DT_SERVER_ID] = { .name = "server_id", .std_type = STD_T_SINT },
Thierry FOURNIER3cf11112015-07-28 08:57:05 +02001176 [STKTABLE_DT_GPT0] = { .name = "gpt0", .std_type = STD_T_UINT },
Willy Tarreau3b9c6e02010-07-18 08:04:30 +02001177 [STKTABLE_DT_GPC0] = { .name = "gpc0", .std_type = STD_T_UINT },
Willy Tarreauba2ffd12013-05-29 15:54:14 +02001178 [STKTABLE_DT_GPC0_RATE] = { .name = "gpc0_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
Willy Tarreau3b9c6e02010-07-18 08:04:30 +02001179 [STKTABLE_DT_CONN_CNT] = { .name = "conn_cnt", .std_type = STD_T_UINT },
1180 [STKTABLE_DT_CONN_RATE] = { .name = "conn_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
Willy Tarreaudb2ab822021-10-08 17:53:12 +02001181 [STKTABLE_DT_CONN_CUR] = { .name = "conn_cur", .std_type = STD_T_UINT, .is_local = 1 },
Willy Tarreau3b9c6e02010-07-18 08:04:30 +02001182 [STKTABLE_DT_SESS_CNT] = { .name = "sess_cnt", .std_type = STD_T_UINT },
1183 [STKTABLE_DT_SESS_RATE] = { .name = "sess_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
1184 [STKTABLE_DT_HTTP_REQ_CNT] = { .name = "http_req_cnt", .std_type = STD_T_UINT },
1185 [STKTABLE_DT_HTTP_REQ_RATE] = { .name = "http_req_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
1186 [STKTABLE_DT_HTTP_ERR_CNT] = { .name = "http_err_cnt", .std_type = STD_T_UINT },
1187 [STKTABLE_DT_HTTP_ERR_RATE] = { .name = "http_err_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
1188 [STKTABLE_DT_BYTES_IN_CNT] = { .name = "bytes_in_cnt", .std_type = STD_T_ULL },
1189 [STKTABLE_DT_BYTES_IN_RATE] = { .name = "bytes_in_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
1190 [STKTABLE_DT_BYTES_OUT_CNT] = { .name = "bytes_out_cnt", .std_type = STD_T_ULL },
1191 [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 +01001192 [STKTABLE_DT_GPC1] = { .name = "gpc1", .std_type = STD_T_UINT },
1193 [STKTABLE_DT_GPC1_RATE] = { .name = "gpc1_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
Thayne McCombs92149f92020-11-20 01:28:26 -07001194 [STKTABLE_DT_SERVER_KEY] = { .name = "server_key", .std_type = STD_T_DICT },
Willy Tarreau826f3ab2021-02-10 12:07:15 +01001195 [STKTABLE_DT_HTTP_FAIL_CNT] = { .name = "http_fail_cnt", .std_type = STD_T_UINT },
1196 [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 +02001197 [STKTABLE_DT_GPT] = { .name = "gpt", .std_type = STD_T_UINT, .is_array = 1 },
Emeric Brun4d7ada82021-06-30 19:04:16 +02001198 [STKTABLE_DT_GPC] = { .name = "gpc", .std_type = STD_T_UINT, .is_array = 1 },
1199 [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 +02001200};
1201
Willy Tarreauedee1d62014-07-15 16:44:27 +02001202/* Registers stick-table extra data type with index <idx>, name <name>, type
1203 * <std_type> and arg type <arg_type>. If the index is negative, the next free
1204 * index is automatically allocated. The allocated index is returned, or -1 if
1205 * no free index was found or <name> was already registered. The <name> is used
1206 * directly as a pointer, so if it's not stable, the caller must allocate it.
1207 */
1208int stktable_register_data_store(int idx, const char *name, int std_type, int arg_type)
1209{
1210 if (idx < 0) {
1211 for (idx = 0; idx < STKTABLE_DATA_TYPES; idx++) {
1212 if (!stktable_data_types[idx].name)
1213 break;
1214
1215 if (strcmp(stktable_data_types[idx].name, name) == 0)
1216 return -1;
1217 }
1218 }
1219
1220 if (idx >= STKTABLE_DATA_TYPES)
1221 return -1;
1222
1223 if (stktable_data_types[idx].name != NULL)
1224 return -1;
1225
1226 stktable_data_types[idx].name = name;
1227 stktable_data_types[idx].std_type = std_type;
1228 stktable_data_types[idx].arg_type = arg_type;
1229 return idx;
1230}
1231
Willy Tarreau08d5f982010-06-06 13:34:54 +02001232/*
1233 * Returns the data type number for the stktable_data_type whose name is <name>,
1234 * or <0 if not found.
1235 */
1236int stktable_get_data_type(char *name)
1237{
1238 int type;
1239
1240 for (type = 0; type < STKTABLE_DATA_TYPES; type++) {
Willy Tarreauedee1d62014-07-15 16:44:27 +02001241 if (!stktable_data_types[type].name)
1242 continue;
Willy Tarreau08d5f982010-06-06 13:34:54 +02001243 if (strcmp(name, stktable_data_types[type].name) == 0)
1244 return type;
1245 }
Thayne McCombs92149f92020-11-20 01:28:26 -07001246 /* For backwards compatibility */
1247 if (strcmp(name, "server_name") == 0)
1248 return STKTABLE_DT_SERVER_KEY;
Willy Tarreau08d5f982010-06-06 13:34:54 +02001249 return -1;
1250}
1251
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001252/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1253 * it up into this table. Returns true if found, false otherwise. The input
1254 * type is STR so that input samples are converted to string (since all types
1255 * can be converted to strings), then the function casts the string again into
1256 * the table's type. This is a double conversion, but in the future we might
1257 * support automatic input types to perform the cast on the fly.
1258 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001259static int sample_conv_in_table(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001260{
1261 struct stktable *t;
1262 struct stktable_key *key;
1263 struct stksess *ts;
1264
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001265 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001266
1267 key = smp_to_stkey(smp, t);
1268 if (!key)
1269 return 0;
1270
1271 ts = stktable_lookup_key(t, key);
1272
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001273 smp->data.type = SMP_T_BOOL;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001274 smp->data.u.sint = !!ts;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001275 smp->flags = SMP_F_VOL_TEST;
Willy Tarreau43e90352018-06-27 06:25:57 +02001276 stktable_release(t, ts);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001277 return 1;
1278}
1279
1280/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1281 * it up into this table. Returns the data rate received from clients in bytes/s
1282 * if the key is present in the table, otherwise zero, so that comparisons can
1283 * be easily performed. If the inspected parameter is not stored in the table,
1284 * <not found> is returned.
1285 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001286static int sample_conv_table_bytes_in_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001287{
1288 struct stktable *t;
1289 struct stktable_key *key;
1290 struct stksess *ts;
1291 void *ptr;
1292
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001293 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001294
1295 key = smp_to_stkey(smp, t);
1296 if (!key)
1297 return 0;
1298
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001299 ts = stktable_lookup_key(t, key);
1300
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001301 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001302 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001303 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001304
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001305 if (!ts) /* key not present */
1306 return 1;
1307
1308 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_IN_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001309 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001310 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Daniel Corbett3e60b112018-05-27 09:47:12 -04001311 t->data_arg[STKTABLE_DT_BYTES_IN_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001312
Daniel Corbett3e60b112018-05-27 09:47:12 -04001313 stktable_release(t, ts);
1314 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001315}
1316
1317/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1318 * it up into this table. Returns the cumulated number of connections for the key
1319 * if the key is present in the table, otherwise zero, so that comparisons can
1320 * be easily performed. If the inspected parameter is not stored in the table,
1321 * <not found> is returned.
1322 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001323static int sample_conv_table_conn_cnt(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001324{
1325 struct stktable *t;
1326 struct stktable_key *key;
1327 struct stksess *ts;
1328 void *ptr;
1329
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001330 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001331
1332 key = smp_to_stkey(smp, t);
1333 if (!key)
1334 return 0;
1335
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001336 ts = stktable_lookup_key(t, key);
1337
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001338 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001339 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001340 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001341
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001342 if (!ts) /* key not present */
1343 return 1;
1344
1345 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_CONN_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001346 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001347 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001348
Daniel Corbett3e60b112018-05-27 09:47:12 -04001349 stktable_release(t, ts);
1350 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001351}
1352
1353/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1354 * it up into this table. Returns the number of concurrent connections for the
1355 * key if the key is present in the table, otherwise zero, so that comparisons
1356 * can be easily performed. If the inspected parameter is not stored in the
1357 * table, <not found> is returned.
1358 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001359static int sample_conv_table_conn_cur(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001360{
1361 struct stktable *t;
1362 struct stktable_key *key;
1363 struct stksess *ts;
1364 void *ptr;
1365
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001366 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001367
1368 key = smp_to_stkey(smp, t);
1369 if (!key)
1370 return 0;
1371
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001372 ts = stktable_lookup_key(t, key);
1373
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001374 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001375 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001376 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001377
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001378 if (!ts) /* key not present */
1379 return 1;
1380
1381 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_CONN_CUR);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001382 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001383 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001384
Daniel Corbett3e60b112018-05-27 09:47:12 -04001385 stktable_release(t, ts);
1386 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001387}
1388
1389/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1390 * it up into this table. Returns the rate of incoming connections from the key
1391 * if the key is present in the table, otherwise zero, so that comparisons can
1392 * be easily performed. If the inspected parameter is not stored in the table,
1393 * <not found> is returned.
1394 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001395static int sample_conv_table_conn_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001396{
1397 struct stktable *t;
1398 struct stktable_key *key;
1399 struct stksess *ts;
1400 void *ptr;
1401
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001402 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001403
1404 key = smp_to_stkey(smp, t);
1405 if (!key)
1406 return 0;
1407
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001408 ts = stktable_lookup_key(t, key);
1409
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001410 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001411 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001412 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001413
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001414 if (!ts) /* key not present */
1415 return 1;
1416
1417 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_CONN_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001418 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001419 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Daniel Corbett3e60b112018-05-27 09:47:12 -04001420 t->data_arg[STKTABLE_DT_CONN_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001421
Daniel Corbett3e60b112018-05-27 09:47:12 -04001422 stktable_release(t, ts);
1423 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001424}
1425
1426/* 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 +02001427 * it up into this table. Returns the expiration delay for the key if the key is
1428 * present in the table, otherwise the default value provided as second argument
1429 * if any, if not (no default value), <not found> is returned.
1430 */
1431static int sample_conv_table_expire(const struct arg *arg_p, struct sample *smp, void *private)
1432{
1433 struct stktable *t;
1434 struct stktable_key *key;
1435 struct stksess *ts;
1436
1437 t = arg_p[0].data.t;
1438
1439 key = smp_to_stkey(smp, t);
1440 if (!key)
1441 return 0;
1442
1443 ts = stktable_lookup_key(t, key);
1444
1445 smp->flags = SMP_F_VOL_TEST;
1446 smp->data.type = SMP_T_SINT;
1447 smp->data.u.sint = 0;
1448
1449 if (!ts) { /* key not present */
1450 if (arg_p[1].type == ARGT_STOP)
1451 return 0;
1452
1453 /* default value */
1454 smp->data.u.sint = arg_p[1].data.sint;
1455 return 1;
1456 }
1457
1458 smp->data.u.sint = tick_remain(now_ms, ts->expire);
1459
1460 stktable_release(t, ts);
1461 return 1;
1462}
1463
1464/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1465 * it up into this table. Returns the time the key remains unused if the key is
1466 * present in the table, otherwise the default value provided as second argument
1467 * if any, if not (no default value), <not found> is returned.
1468 */
1469static int sample_conv_table_idle(const struct arg *arg_p, struct sample *smp, void *private)
1470{
1471 struct stktable *t;
1472 struct stktable_key *key;
1473 struct stksess *ts;
1474
1475 t = arg_p[0].data.t;
1476
1477 key = smp_to_stkey(smp, t);
1478 if (!key)
1479 return 0;
1480
1481 ts = stktable_lookup_key(t, key);
1482
1483 smp->flags = SMP_F_VOL_TEST;
1484 smp->data.type = SMP_T_SINT;
1485 smp->data.u.sint = 0;
1486
1487 if (!ts) { /* key not present */
1488 if (arg_p[1].type == ARGT_STOP)
1489 return 0;
1490
1491 /* default value */
1492 smp->data.u.sint = arg_p[1].data.sint;
1493 return 1;
1494 }
1495
1496 smp->data.u.sint = tick_remain(tick_remain(now_ms, ts->expire), t->expire);
1497
1498 stktable_release(t, ts);
1499 return 1;
1500}
1501
1502/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001503 * it up into this table. Returns the data rate sent to clients in bytes/s
1504 * if the key is present in the table, otherwise zero, so that comparisons can
1505 * be easily performed. If the inspected parameter is not stored in the table,
1506 * <not found> is returned.
1507 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001508static int sample_conv_table_bytes_out_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001509{
1510 struct stktable *t;
1511 struct stktable_key *key;
1512 struct stksess *ts;
1513 void *ptr;
1514
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001515 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001516
1517 key = smp_to_stkey(smp, t);
1518 if (!key)
1519 return 0;
1520
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001521 ts = stktable_lookup_key(t, key);
1522
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001523 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001524 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001525 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001526
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001527 if (!ts) /* key not present */
1528 return 1;
1529
1530 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_OUT_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001531 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001532 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Daniel Corbett3e60b112018-05-27 09:47:12 -04001533 t->data_arg[STKTABLE_DT_BYTES_OUT_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001534
Daniel Corbett3e60b112018-05-27 09:47:12 -04001535 stktable_release(t, ts);
1536 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001537}
1538
Emeric Brun877b0b52021-06-30 18:57:49 +02001539/* Casts sample <smp> to the type of the table specified in arg_p(1), and looks
1540 * it up into this table. Returns the value of the GPT[arg_p(0)] tag for the key
1541 * if the key is present in the table, otherwise false, so that comparisons can
1542 * be easily performed. If the inspected parameter is not stored in the table,
1543 * <not found> is returned.
1544 */
1545static int sample_conv_table_gpt(const struct arg *arg_p, struct sample *smp, void *private)
1546{
1547 struct stktable *t;
1548 struct stktable_key *key;
1549 struct stksess *ts;
1550 void *ptr;
1551 unsigned int idx;
1552
1553 idx = arg_p[0].data.sint;
1554
1555 t = arg_p[1].data.t;
1556
1557 key = smp_to_stkey(smp, t);
1558 if (!key)
1559 return 0;
1560
1561 ts = stktable_lookup_key(t, key);
1562
1563 smp->flags = SMP_F_VOL_TEST;
1564 smp->data.type = SMP_T_SINT;
1565 smp->data.u.sint = 0;
1566
1567 if (!ts) /* key not present */
1568 return 1;
1569
1570 ptr = stktable_data_ptr_idx(t, ts, STKTABLE_DT_GPT, idx);
1571 if (ptr)
1572 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
1573
1574 stktable_release(t, ts);
1575 return !!ptr;
1576}
1577
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001578/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001579 * it up into this table. Returns the value of the GPT0 tag for the key
1580 * if the key is present in the table, otherwise false, so that comparisons can
1581 * be easily performed. If the inspected parameter is not stored in the table,
1582 * <not found> is returned.
1583 */
1584static int sample_conv_table_gpt0(const struct arg *arg_p, struct sample *smp, void *private)
1585{
1586 struct stktable *t;
1587 struct stktable_key *key;
1588 struct stksess *ts;
1589 void *ptr;
1590
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001591 t = arg_p[0].data.t;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001592
1593 key = smp_to_stkey(smp, t);
1594 if (!key)
1595 return 0;
1596
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001597 ts = stktable_lookup_key(t, key);
1598
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001599 smp->flags = SMP_F_VOL_TEST;
1600 smp->data.type = SMP_T_SINT;
1601 smp->data.u.sint = 0;
1602
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001603 if (!ts) /* key not present */
1604 return 1;
1605
1606 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPT0);
Emeric Brunf7ab0bf2021-06-30 18:58:22 +02001607 if (!ptr)
1608 ptr = stktable_data_ptr_idx(t, ts, STKTABLE_DT_GPT, 0);
1609
Daniel Corbett3e60b112018-05-27 09:47:12 -04001610 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001611 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001612
Daniel Corbett3e60b112018-05-27 09:47:12 -04001613 stktable_release(t, ts);
1614 return !!ptr;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001615}
1616
Emeric Brun4d7ada82021-06-30 19:04:16 +02001617/* Casts sample <smp> to the type of the table specified in arg_p(1), and looks
1618 * it up into this table. Returns the value of the GPC[arg_p(0)] counter for the key
1619 * if the key is present in the table, otherwise zero, so that comparisons can
1620 * be easily performed. If the inspected parameter is not stored in the table,
1621 * <not found> is returned.
1622 */
1623static int sample_conv_table_gpc(const struct arg *arg_p, struct sample *smp, void *private)
1624{
1625 struct stktable *t;
1626 struct stktable_key *key;
1627 struct stksess *ts;
1628 void *ptr;
1629 unsigned int idx;
1630
1631 idx = arg_p[0].data.sint;
1632
1633 t = arg_p[1].data.t;
1634
1635 key = smp_to_stkey(smp, t);
1636 if (!key)
1637 return 0;
1638
1639 ts = stktable_lookup_key(t, key);
1640
1641 smp->flags = SMP_F_VOL_TEST;
1642 smp->data.type = SMP_T_SINT;
1643 smp->data.u.sint = 0;
1644
1645 if (!ts) /* key not present */
1646 return 1;
1647
1648 ptr = stktable_data_ptr_idx(t, ts, STKTABLE_DT_GPC, idx);
1649 if (ptr)
1650 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
1651
1652 stktable_release(t, ts);
1653 return !!ptr;
1654}
1655
1656/* Casts sample <smp> to the type of the table specified in arg_p(1), and looks
1657 * it up into this table. Returns the event rate of the GPC[arg_p(0)] counter
1658 * for the key if the key is present in the table, otherwise zero, so that
1659 * comparisons can be easily performed. If the inspected parameter is not
1660 * stored in the table, <not found> is returned.
1661 */
1662static int sample_conv_table_gpc_rate(const struct arg *arg_p, struct sample *smp, void *private)
1663{
1664 struct stktable *t;
1665 struct stktable_key *key;
1666 struct stksess *ts;
1667 void *ptr;
1668 unsigned int idx;
1669
1670 idx = arg_p[0].data.sint;
1671
1672 t = arg_p[1].data.t;
1673
1674 key = smp_to_stkey(smp, t);
1675 if (!key)
1676 return 0;
1677
1678 ts = stktable_lookup_key(t, key);
1679
1680 smp->flags = SMP_F_VOL_TEST;
1681 smp->data.type = SMP_T_SINT;
1682 smp->data.u.sint = 0;
1683
1684 if (!ts) /* key not present */
1685 return 1;
1686
1687 ptr = stktable_data_ptr_idx(t, ts, STKTABLE_DT_GPC_RATE, idx);
1688 if (ptr)
1689 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
1690 t->data_arg[STKTABLE_DT_GPC_RATE].u);
1691
1692 stktable_release(t, ts);
1693 return !!ptr;
1694}
1695
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001696/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001697 * it up into this table. Returns the value of the GPC0 counter for the key
1698 * if the key is present in the table, otherwise zero, so that comparisons can
1699 * be easily performed. If the inspected parameter is not stored in the table,
1700 * <not found> is returned.
1701 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001702static int sample_conv_table_gpc0(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001703{
1704 struct stktable *t;
1705 struct stktable_key *key;
1706 struct stksess *ts;
1707 void *ptr;
1708
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001709 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001710
1711 key = smp_to_stkey(smp, t);
1712 if (!key)
1713 return 0;
1714
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001715 ts = stktable_lookup_key(t, key);
1716
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001717 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001718 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001719 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001720
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001721 if (!ts) /* key not present */
1722 return 1;
1723
1724 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPC0);
Emeric Brun726783d2021-06-30 19:06:43 +02001725 if (!ptr) {
1726 /* fallback on the gpc array */
1727 ptr = stktable_data_ptr_idx(t, ts, STKTABLE_DT_GPC, 0);
1728 }
1729
Daniel Corbett3e60b112018-05-27 09:47:12 -04001730 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001731 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001732
Daniel Corbett3e60b112018-05-27 09:47:12 -04001733 stktable_release(t, ts);
1734 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001735}
1736
1737/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1738 * it up into this table. Returns the event rate of the GPC0 counter for the key
1739 * if the key is present in the table, otherwise zero, so that comparisons can
1740 * be easily performed. If the inspected parameter is not stored in the table,
1741 * <not found> is returned.
1742 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001743static int sample_conv_table_gpc0_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001744{
1745 struct stktable *t;
1746 struct stktable_key *key;
1747 struct stksess *ts;
1748 void *ptr;
1749
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001750 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001751
1752 key = smp_to_stkey(smp, t);
1753 if (!key)
1754 return 0;
1755
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001756 ts = stktable_lookup_key(t, key);
1757
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001758 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001759 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001760 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001761
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001762 if (!ts) /* key not present */
1763 return 1;
1764
1765 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPC0_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001766 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001767 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Daniel Corbett3e60b112018-05-27 09:47:12 -04001768 t->data_arg[STKTABLE_DT_GPC0_RATE].u);
Emeric Brun726783d2021-06-30 19:06:43 +02001769 else {
1770 /* fallback on the gpc array */
1771 ptr = stktable_data_ptr_idx(t, ts, STKTABLE_DT_GPC_RATE, 0);
1772 if (ptr)
1773 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
1774 t->data_arg[STKTABLE_DT_GPC_RATE].u);
1775 }
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001776
Daniel Corbett3e60b112018-05-27 09:47:12 -04001777 stktable_release(t, ts);
1778 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001779}
1780
1781/* 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 +01001782 * it up into this table. Returns the value of the GPC1 counter for the key
1783 * if the key is present in the table, otherwise zero, so that comparisons can
1784 * be easily performed. If the inspected parameter is not stored in the table,
1785 * <not found> is returned.
1786 */
1787static int sample_conv_table_gpc1(const struct arg *arg_p, struct sample *smp, void *private)
1788{
1789 struct stktable *t;
1790 struct stktable_key *key;
1791 struct stksess *ts;
1792 void *ptr;
1793
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001794 t = arg_p[0].data.t;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001795
1796 key = smp_to_stkey(smp, t);
1797 if (!key)
1798 return 0;
1799
1800 ts = stktable_lookup_key(t, key);
1801
1802 smp->flags = SMP_F_VOL_TEST;
1803 smp->data.type = SMP_T_SINT;
1804 smp->data.u.sint = 0;
1805
1806 if (!ts) /* key not present */
1807 return 1;
1808
1809 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPC1);
Emeric Brun726783d2021-06-30 19:06:43 +02001810 if (!ptr) {
1811 /* fallback on the gpc array */
1812 ptr = stktable_data_ptr_idx(t, ts, STKTABLE_DT_GPC, 1);
1813 }
1814
Daniel Corbett3e60b112018-05-27 09:47:12 -04001815 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001816 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001817
Daniel Corbett3e60b112018-05-27 09:47:12 -04001818 stktable_release(t, ts);
1819 return !!ptr;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001820}
1821
1822/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1823 * it up into this table. Returns the event rate of the GPC1 counter for the key
1824 * if the key is present in the table, otherwise zero, so that comparisons can
1825 * be easily performed. If the inspected parameter is not stored in the table,
1826 * <not found> is returned.
1827 */
1828static int sample_conv_table_gpc1_rate(const struct arg *arg_p, struct sample *smp, void *private)
1829{
1830 struct stktable *t;
1831 struct stktable_key *key;
1832 struct stksess *ts;
1833 void *ptr;
1834
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001835 t = arg_p[0].data.t;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001836
1837 key = smp_to_stkey(smp, t);
1838 if (!key)
1839 return 0;
1840
1841 ts = stktable_lookup_key(t, key);
1842
1843 smp->flags = SMP_F_VOL_TEST;
1844 smp->data.type = SMP_T_SINT;
1845 smp->data.u.sint = 0;
1846
1847 if (!ts) /* key not present */
1848 return 1;
1849
1850 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPC1_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001851 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001852 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Daniel Corbett3e60b112018-05-27 09:47:12 -04001853 t->data_arg[STKTABLE_DT_GPC1_RATE].u);
Emeric Brun726783d2021-06-30 19:06:43 +02001854 else {
1855 /* fallback on the gpc array */
1856 ptr = stktable_data_ptr_idx(t, ts, STKTABLE_DT_GPC_RATE, 1);
1857 if (ptr)
1858 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
1859 t->data_arg[STKTABLE_DT_GPC_RATE].u);
1860 }
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001861
Daniel Corbett3e60b112018-05-27 09:47:12 -04001862 stktable_release(t, ts);
1863 return !!ptr;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001864}
1865
1866/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001867 * it up into this table. Returns the cumulated number of HTTP request errors
1868 * for the key if the key is present in the table, otherwise zero, so that
1869 * comparisons can be easily performed. If the inspected parameter is not stored
1870 * in the table, <not found> is returned.
1871 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001872static int sample_conv_table_http_err_cnt(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001873{
1874 struct stktable *t;
1875 struct stktable_key *key;
1876 struct stksess *ts;
1877 void *ptr;
1878
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001879 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001880
1881 key = smp_to_stkey(smp, t);
1882 if (!key)
1883 return 0;
1884
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001885 ts = stktable_lookup_key(t, key);
1886
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001887 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001888 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001889 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001890
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001891 if (!ts) /* key not present */
1892 return 1;
1893
1894 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_ERR_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001895 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001896 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001897
Daniel Corbett3e60b112018-05-27 09:47:12 -04001898 stktable_release(t, ts);
1899 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001900}
1901
1902/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1903 * it up into this table. Returns the HTTP request error rate the key
1904 * if the key is present in the table, otherwise zero, so that comparisons can
1905 * be easily performed. If the inspected parameter is not stored in the table,
1906 * <not found> is returned.
1907 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001908static int sample_conv_table_http_err_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001909{
1910 struct stktable *t;
1911 struct stktable_key *key;
1912 struct stksess *ts;
1913 void *ptr;
1914
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001915 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001916
1917 key = smp_to_stkey(smp, t);
1918 if (!key)
1919 return 0;
1920
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001921 ts = stktable_lookup_key(t, key);
1922
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001923 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001924 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001925 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001926
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001927 if (!ts) /* key not present */
1928 return 1;
1929
1930 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_ERR_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001931 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001932 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Daniel Corbett3e60b112018-05-27 09:47:12 -04001933 t->data_arg[STKTABLE_DT_HTTP_ERR_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001934
Daniel Corbett3e60b112018-05-27 09:47:12 -04001935 stktable_release(t, ts);
1936 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001937}
1938
1939/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Willy Tarreau826f3ab2021-02-10 12:07:15 +01001940 * it up into this table. Returns the cumulated number of HTTP response failures
1941 * for the key if the key is present in the table, otherwise zero, so that
1942 * comparisons can be easily performed. If the inspected parameter is not stored
1943 * in the table, <not found> is returned.
1944 */
1945static int sample_conv_table_http_fail_cnt(const struct arg *arg_p, struct sample *smp, void *private)
1946{
1947 struct stktable *t;
1948 struct stktable_key *key;
1949 struct stksess *ts;
1950 void *ptr;
1951
1952 t = arg_p[0].data.t;
1953
1954 key = smp_to_stkey(smp, t);
1955 if (!key)
1956 return 0;
1957
1958 ts = stktable_lookup_key(t, key);
1959
1960 smp->flags = SMP_F_VOL_TEST;
1961 smp->data.type = SMP_T_SINT;
1962 smp->data.u.sint = 0;
1963
1964 if (!ts) /* key not present */
1965 return 1;
1966
1967 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_FAIL_CNT);
1968 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001969 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Willy Tarreau826f3ab2021-02-10 12:07:15 +01001970
1971 stktable_release(t, ts);
1972 return !!ptr;
1973}
1974
1975/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1976 * it up into this table. Returns the HTTP response failure rate for the key
1977 * if the key is present in the table, otherwise zero, so that comparisons can
1978 * be easily performed. If the inspected parameter is not stored in the table,
1979 * <not found> is returned.
1980 */
1981static int sample_conv_table_http_fail_rate(const struct arg *arg_p, struct sample *smp, void *private)
1982{
1983 struct stktable *t;
1984 struct stktable_key *key;
1985 struct stksess *ts;
1986 void *ptr;
1987
1988 t = arg_p[0].data.t;
1989
1990 key = smp_to_stkey(smp, t);
1991 if (!key)
1992 return 0;
1993
1994 ts = stktable_lookup_key(t, key);
1995
1996 smp->flags = SMP_F_VOL_TEST;
1997 smp->data.type = SMP_T_SINT;
1998 smp->data.u.sint = 0;
1999
2000 if (!ts) /* key not present */
2001 return 1;
2002
2003 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_FAIL_RATE);
2004 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002005 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Willy Tarreau826f3ab2021-02-10 12:07:15 +01002006 t->data_arg[STKTABLE_DT_HTTP_FAIL_RATE].u);
2007
2008 stktable_release(t, ts);
2009 return !!ptr;
2010}
2011
2012/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002013 * it up into this table. Returns the cumulated number of HTTP request for the
2014 * key if the key is present in the table, otherwise zero, so that comparisons
2015 * can be easily performed. If the inspected parameter is not stored in the
2016 * table, <not found> is returned.
2017 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02002018static int sample_conv_table_http_req_cnt(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002019{
2020 struct stktable *t;
2021 struct stktable_key *key;
2022 struct stksess *ts;
2023 void *ptr;
2024
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002025 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002026
2027 key = smp_to_stkey(smp, t);
2028 if (!key)
2029 return 0;
2030
Willy Tarreauf0c730a2016-05-25 17:07:56 +02002031 ts = stktable_lookup_key(t, key);
2032
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002033 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02002034 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02002035 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002036
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002037 if (!ts) /* key not present */
2038 return 1;
2039
2040 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_REQ_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04002041 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002042 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002043
Daniel Corbett3e60b112018-05-27 09:47:12 -04002044 stktable_release(t, ts);
2045 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002046}
2047
2048/* Casts sample <smp> to the type of the table specified in arg(0), and looks
2049 * it up into this table. Returns the HTTP request rate the key if the key is
2050 * present in the table, otherwise zero, so that comparisons can be easily
2051 * performed. If the inspected parameter is not stored in the table, <not found>
2052 * is returned.
2053 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02002054static int sample_conv_table_http_req_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002055{
2056 struct stktable *t;
2057 struct stktable_key *key;
2058 struct stksess *ts;
2059 void *ptr;
2060
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002061 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002062
2063 key = smp_to_stkey(smp, t);
2064 if (!key)
2065 return 0;
2066
Willy Tarreauf0c730a2016-05-25 17:07:56 +02002067 ts = stktable_lookup_key(t, key);
2068
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002069 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02002070 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02002071 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002072
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002073 if (!ts) /* key not present */
2074 return 1;
2075
2076 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_REQ_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04002077 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002078 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Daniel Corbett3e60b112018-05-27 09:47:12 -04002079 t->data_arg[STKTABLE_DT_HTTP_REQ_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002080
Daniel Corbett3e60b112018-05-27 09:47:12 -04002081 stktable_release(t, ts);
2082 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002083}
2084
2085/* Casts sample <smp> to the type of the table specified in arg(0), and looks
2086 * it up into this table. Returns the volume of datareceived from clients in kbytes
2087 * if the key is present in the table, otherwise zero, so that comparisons can
2088 * be easily performed. If the inspected parameter is not stored in the table,
2089 * <not found> is returned.
2090 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02002091static int sample_conv_table_kbytes_in(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002092{
2093 struct stktable *t;
2094 struct stktable_key *key;
2095 struct stksess *ts;
2096 void *ptr;
2097
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002098 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002099
2100 key = smp_to_stkey(smp, t);
2101 if (!key)
2102 return 0;
2103
Willy Tarreauf0c730a2016-05-25 17:07:56 +02002104 ts = stktable_lookup_key(t, key);
2105
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002106 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02002107 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02002108 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002109
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002110 if (!ts) /* key not present */
2111 return 1;
2112
2113 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_IN_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04002114 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002115 smp->data.u.sint = stktable_data_cast(ptr, std_t_ull) >> 10;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002116
Daniel Corbett3e60b112018-05-27 09:47:12 -04002117 stktable_release(t, ts);
2118 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002119}
2120
2121/* Casts sample <smp> to the type of the table specified in arg(0), and looks
2122 * it up into this table. Returns the volume of data sent to clients in kbytes
2123 * if the key is present in the table, otherwise zero, so that comparisons can
2124 * be easily performed. If the inspected parameter is not stored in the table,
2125 * <not found> is returned.
2126 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02002127static int sample_conv_table_kbytes_out(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002128{
2129 struct stktable *t;
2130 struct stktable_key *key;
2131 struct stksess *ts;
2132 void *ptr;
2133
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002134 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002135
2136 key = smp_to_stkey(smp, t);
2137 if (!key)
2138 return 0;
2139
Willy Tarreauf0c730a2016-05-25 17:07:56 +02002140 ts = stktable_lookup_key(t, key);
2141
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002142 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02002143 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02002144 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002145
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002146 if (!ts) /* key not present */
2147 return 1;
2148
2149 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_OUT_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04002150 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002151 smp->data.u.sint = stktable_data_cast(ptr, std_t_ull) >> 10;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002152
Daniel Corbett3e60b112018-05-27 09:47:12 -04002153 stktable_release(t, ts);
2154 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002155}
2156
2157/* Casts sample <smp> to the type of the table specified in arg(0), and looks
2158 * it up into this table. Returns the server ID associated with the key if the
2159 * key is present in the table, otherwise zero, so that comparisons can be
2160 * easily performed. If the inspected parameter is not stored in the table,
2161 * <not found> is returned.
2162 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02002163static int sample_conv_table_server_id(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002164{
2165 struct stktable *t;
2166 struct stktable_key *key;
2167 struct stksess *ts;
2168 void *ptr;
2169
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002170 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002171
2172 key = smp_to_stkey(smp, t);
2173 if (!key)
2174 return 0;
2175
Willy Tarreauf0c730a2016-05-25 17:07:56 +02002176 ts = stktable_lookup_key(t, key);
2177
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002178 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02002179 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02002180 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002181
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002182 if (!ts) /* key not present */
2183 return 1;
2184
2185 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_SERVER_ID);
Daniel Corbett3e60b112018-05-27 09:47:12 -04002186 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002187 smp->data.u.sint = stktable_data_cast(ptr, std_t_sint);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002188
Daniel Corbett3e60b112018-05-27 09:47:12 -04002189 stktable_release(t, ts);
2190 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002191}
2192
2193/* Casts sample <smp> to the type of the table specified in arg(0), and looks
2194 * it up into this table. Returns the cumulated number of sessions for the
2195 * key if the key is present in the table, otherwise zero, so that comparisons
2196 * can be easily performed. If the inspected parameter is not stored in the
2197 * table, <not found> is returned.
2198 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02002199static int sample_conv_table_sess_cnt(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002200{
2201 struct stktable *t;
2202 struct stktable_key *key;
2203 struct stksess *ts;
2204 void *ptr;
2205
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002206 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002207
2208 key = smp_to_stkey(smp, t);
2209 if (!key)
2210 return 0;
2211
Willy Tarreauf0c730a2016-05-25 17:07:56 +02002212 ts = stktable_lookup_key(t, key);
2213
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002214 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02002215 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02002216 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002217
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002218 if (!ts) /* key not present */
2219 return 1;
2220
2221 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_SESS_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04002222 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002223 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002224
Daniel Corbett3e60b112018-05-27 09:47:12 -04002225 stktable_release(t, ts);
2226 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002227}
2228
2229/* Casts sample <smp> to the type of the table specified in arg(0), and looks
2230 * it up into this table. Returns the session rate the key if the key is
2231 * present in the table, otherwise zero, so that comparisons can be easily
2232 * performed. If the inspected parameter is not stored in the table, <not found>
2233 * is returned.
2234 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02002235static int sample_conv_table_sess_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002236{
2237 struct stktable *t;
2238 struct stktable_key *key;
2239 struct stksess *ts;
2240 void *ptr;
2241
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002242 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002243
2244 key = smp_to_stkey(smp, t);
2245 if (!key)
2246 return 0;
2247
Willy Tarreauf0c730a2016-05-25 17:07:56 +02002248 ts = stktable_lookup_key(t, key);
2249
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002250 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02002251 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02002252 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002253
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002254 if (!ts) /* key not present */
2255 return 1;
2256
2257 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_SESS_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04002258 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002259 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Daniel Corbett3e60b112018-05-27 09:47:12 -04002260 t->data_arg[STKTABLE_DT_SESS_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002261
Daniel Corbett3e60b112018-05-27 09:47:12 -04002262 stktable_release(t, ts);
2263 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002264}
2265
2266/* Casts sample <smp> to the type of the table specified in arg(0), and looks
2267 * it up into this table. Returns the amount of concurrent connections tracking
2268 * the same key if the key is present in the table, otherwise zero, so that
2269 * comparisons can be easily performed. If the inspected parameter is not
2270 * stored in the table, <not found> is returned.
2271 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02002272static int sample_conv_table_trackers(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002273{
2274 struct stktable *t;
2275 struct stktable_key *key;
2276 struct stksess *ts;
2277
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002278 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002279
2280 key = smp_to_stkey(smp, t);
2281 if (!key)
2282 return 0;
2283
Willy Tarreauf0c730a2016-05-25 17:07:56 +02002284 ts = stktable_lookup_key(t, key);
2285
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002286 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02002287 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02002288 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002289
Tim Duesterhus65189c12018-06-26 15:57:29 +02002290 if (!ts)
2291 return 1;
2292
2293 smp->data.u.sint = ts->ref_cnt;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002294
Daniel Corbett3e60b112018-05-27 09:47:12 -04002295 stktable_release(t, ts);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002296 return 1;
2297}
2298
Emeric Brun4d7ada82021-06-30 19:04:16 +02002299/* This function increments the gpc counter at index 'rule->arg.gpc.idx' of the
2300 * array on the tracksc counter of index 'rule->arg.gpc.sc' stored into the
2301 * <stream> or directly in the session <sess> if <stream> is set to NULL
2302 *
2303 * This function always returns ACT_RET_CONT and parameter flags is unused.
2304 */
2305static enum act_return action_inc_gpc(struct act_rule *rule, struct proxy *px,
2306 struct session *sess, struct stream *s, int flags)
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002307{
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002308 struct stksess *ts;
2309 struct stkctr *stkctr;
2310
2311 /* Extract the stksess, return OK if no stksess available. */
2312 if (s)
2313 stkctr = &s->stkctr[rule->arg.gpc.sc];
2314 else
2315 stkctr = &sess->stkctr[rule->arg.gpc.sc];
Willy Tarreau79c1e912016-01-25 14:54:45 +01002316
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002317 ts = stkctr_entry(stkctr);
Willy Tarreau79c1e912016-01-25 14:54:45 +01002318 if (ts) {
2319 void *ptr1, *ptr2;
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002320
Emeric Brun4d7ada82021-06-30 19:04:16 +02002321 /* First, update gpc_rate if it's tracked. Second, update its gpc if tracked. */
2322 ptr1 = stktable_data_ptr_idx(stkctr->table, ts, STKTABLE_DT_GPC_RATE, rule->arg.gpc.idx);
2323 ptr2 = stktable_data_ptr_idx(stkctr->table, ts, STKTABLE_DT_GPC, rule->arg.gpc.idx);
2324
Emeric Brun819fc6f2017-06-13 19:37:32 +02002325 if (ptr1 || ptr2) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002326 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002327
2328 if (ptr1)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002329 update_freq_ctr_period(&stktable_data_cast(ptr1, std_t_frqp),
Emeric Brun4d7ada82021-06-30 19:04:16 +02002330 stkctr->table->data_arg[STKTABLE_DT_GPC_RATE].u, 1);
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002331
Emeric Brun819fc6f2017-06-13 19:37:32 +02002332 if (ptr2)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002333 stktable_data_cast(ptr2, std_t_uint)++;
Willy Tarreau79c1e912016-01-25 14:54:45 +01002334
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002335 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002336
2337 /* If data was modified, we need to touch to re-schedule sync */
2338 stktable_touch_local(stkctr->table, ts, 0);
2339 }
Willy Tarreau79c1e912016-01-25 14:54:45 +01002340 }
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002341 return ACT_RET_CONT;
2342}
2343
Emeric Brun4d7ada82021-06-30 19:04:16 +02002344/* Same as action_inc_gpc() but for gpc0 only */
2345static enum act_return action_inc_gpc0(struct act_rule *rule, struct proxy *px,
2346 struct session *sess, struct stream *s, int flags)
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002347{
Emeric Brun4d7ada82021-06-30 19:04:16 +02002348 struct stksess *ts;
2349 struct stkctr *stkctr;
Willy Tarreau5b654ad2021-07-06 18:51:12 +02002350 unsigned int period = 0;
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002351
Emeric Brun4d7ada82021-06-30 19:04:16 +02002352 /* Extract the stksess, return OK if no stksess available. */
2353 if (s)
2354 stkctr = &s->stkctr[rule->arg.gpc.sc];
2355 else
2356 stkctr = &sess->stkctr[rule->arg.gpc.sc];
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002357
Emeric Brun4d7ada82021-06-30 19:04:16 +02002358 ts = stkctr_entry(stkctr);
2359 if (ts) {
2360 void *ptr1, *ptr2;
2361
2362 /* First, update gpc0_rate if it's tracked. Second, update its gpc0 if tracked. */
2363 ptr1 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC0_RATE);
Emeric Brun726783d2021-06-30 19:06:43 +02002364 if (ptr1) {
2365 period = stkctr->table->data_arg[STKTABLE_DT_GPC0_RATE].u;
2366 }
2367 else {
2368 /* fallback on the gpc array */
2369 ptr1 = stktable_data_ptr_idx(stkctr->table, ts, STKTABLE_DT_GPC_RATE, 0);
2370 if (ptr1)
2371 period = stkctr->table->data_arg[STKTABLE_DT_GPC_RATE].u;
2372 }
2373
Emeric Brun4d7ada82021-06-30 19:04:16 +02002374 ptr2 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC0);
Emeric Brun726783d2021-06-30 19:06:43 +02002375 if (!ptr2) {
2376 /* fallback on the gpc array */
2377 ptr2 = stktable_data_ptr_idx(stkctr->table, ts, STKTABLE_DT_GPC, 0);
2378 }
2379
Emeric Brun4d7ada82021-06-30 19:04:16 +02002380 if (ptr1 || ptr2) {
2381 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
2382
2383 if (ptr1)
2384 update_freq_ctr_period(&stktable_data_cast(ptr1, std_t_frqp),
Emeric Brun726783d2021-06-30 19:06:43 +02002385 period, 1);
Emeric Brun4d7ada82021-06-30 19:04:16 +02002386
2387 if (ptr2)
2388 stktable_data_cast(ptr2, std_t_uint)++;
2389
2390 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
2391
2392 /* If data was modified, we need to touch to re-schedule sync */
2393 stktable_touch_local(stkctr->table, ts, 0);
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002394 }
2395 }
Emeric Brun4d7ada82021-06-30 19:04:16 +02002396 return ACT_RET_CONT;
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002397}
2398
Emeric Brun4d7ada82021-06-30 19:04:16 +02002399/* Same as action_inc_gpc() but for gpc1 only */
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002400static enum act_return action_inc_gpc1(struct act_rule *rule, struct proxy *px,
2401 struct session *sess, struct stream *s, int flags)
2402{
2403 struct stksess *ts;
2404 struct stkctr *stkctr;
Willy Tarreau5b654ad2021-07-06 18:51:12 +02002405 unsigned int period = 0;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002406
2407 /* Extract the stksess, return OK if no stksess available. */
2408 if (s)
2409 stkctr = &s->stkctr[rule->arg.gpc.sc];
2410 else
2411 stkctr = &sess->stkctr[rule->arg.gpc.sc];
2412
2413 ts = stkctr_entry(stkctr);
2414 if (ts) {
2415 void *ptr1, *ptr2;
2416
2417 /* First, update gpc1_rate if it's tracked. Second, update its gpc1 if tracked. */
2418 ptr1 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC1_RATE);
Emeric Brun726783d2021-06-30 19:06:43 +02002419 if (ptr1) {
2420 period = stkctr->table->data_arg[STKTABLE_DT_GPC1_RATE].u;
2421 }
2422 else {
2423 /* fallback on the gpc array */
2424 ptr1 = stktable_data_ptr_idx(stkctr->table, ts, STKTABLE_DT_GPC_RATE, 1);
2425 if (ptr1)
2426 period = stkctr->table->data_arg[STKTABLE_DT_GPC_RATE].u;
2427 }
2428
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002429 ptr2 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC1);
Emeric Brun726783d2021-06-30 19:06:43 +02002430 if (!ptr2) {
2431 /* fallback on the gpc array */
2432 ptr2 = stktable_data_ptr_idx(stkctr->table, ts, STKTABLE_DT_GPC, 1);
2433 }
2434
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002435 if (ptr1 || ptr2) {
2436 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
2437
2438 if (ptr1)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002439 update_freq_ctr_period(&stktable_data_cast(ptr1, std_t_frqp),
Emeric Brun726783d2021-06-30 19:06:43 +02002440 period, 1);
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002441
2442 if (ptr2)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002443 stktable_data_cast(ptr2, std_t_uint)++;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002444
2445 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
2446
2447 /* If data was modified, we need to touch to re-schedule sync */
2448 stktable_touch_local(stkctr->table, ts, 0);
2449 }
2450 }
2451 return ACT_RET_CONT;
2452}
2453
Emeric Brun4d7ada82021-06-30 19:04:16 +02002454/* This function is a common parser for actions incrementing the GPC
2455 * (General Purpose Counters). It understands the formats:
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002456 *
Emeric Brun4d7ada82021-06-30 19:04:16 +02002457 * sc-inc-gpc(<gpc IDX>,<track ID>)
2458 * sc-inc-gpc0([<track ID>])
2459 * sc-inc-gpc1([<track ID>])
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002460 *
Emeric Brun4d7ada82021-06-30 19:04:16 +02002461 * It returns ACT_RET_PRS_ERR if fails and <err> is filled with an error
2462 * message. Otherwise it returns ACT_RET_PRS_OK.
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002463 */
Emeric Brun4d7ada82021-06-30 19:04:16 +02002464static enum act_parse_ret parse_inc_gpc(const char **args, int *arg, struct proxy *px,
2465 struct act_rule *rule, char **err)
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002466{
2467 const char *cmd_name = args[*arg-1];
2468 char *error;
2469
Emeric Brun4d7ada82021-06-30 19:04:16 +02002470 cmd_name += strlen("sc-inc-gpc");
2471 if (*cmd_name == '(') {
2472 cmd_name++; /* skip the '(' */
2473 rule->arg.gpc.idx = strtoul(cmd_name, &error, 10); /* Convert stick table id. */
2474 if (*error != ',') {
2475 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 +01002476 return ACT_RET_PRS_ERR;
2477 }
Emeric Brun4d7ada82021-06-30 19:04:16 +02002478 else {
2479 cmd_name = error + 1; /* skip the ',' */
2480 rule->arg.gpc.sc = strtol(cmd_name, &error, 10); /* Convert stick table id. */
2481 if (*error != ')') {
2482 memprintf(err, "invalid stick table track ID '%s'. Expects sc-inc-gpc(<GPC ID>,<Track ID>)", args[*arg-1]);
2483 return ACT_RET_PRS_ERR;
2484 }
2485
2486 if (rule->arg.gpc.sc >= MAX_SESS_STKCTR) {
2487 memprintf(err, "invalid stick table track ID '%s'. The max allowed ID is %d",
2488 args[*arg-1], MAX_SESS_STKCTR-1);
2489 return ACT_RET_PRS_ERR;
2490 }
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002491 }
Emeric Brun4d7ada82021-06-30 19:04:16 +02002492 rule->action_ptr = action_inc_gpc;
2493 }
2494 else if (*cmd_name == '0' ||*cmd_name == '1') {
2495 char c = *cmd_name;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002496
Emeric Brun4d7ada82021-06-30 19:04:16 +02002497 cmd_name++;
2498 if (*cmd_name == '\0') {
2499 /* default stick table id. */
2500 rule->arg.gpc.sc = 0;
2501 } else {
2502 /* parse the stick table id. */
2503 if (*cmd_name != '(') {
2504 memprintf(err, "invalid stick table track ID. Expects %s(<Track ID>)", args[*arg-1]);
2505 return ACT_RET_PRS_ERR;
2506 }
2507 cmd_name++; /* jump the '(' */
2508 rule->arg.gpc.sc = strtol(cmd_name, &error, 10); /* Convert stick table id. */
2509 if (*error != ')') {
2510 memprintf(err, "invalid stick table track ID. Expects %s(<Track ID>)", args[*arg-1]);
2511 return ACT_RET_PRS_ERR;
2512 }
2513
2514 if (rule->arg.gpc.sc >= MAX_SESS_STKCTR) {
2515 memprintf(err, "invalid stick table track ID. The max allowed ID is %d",
2516 MAX_SESS_STKCTR-1);
2517 return ACT_RET_PRS_ERR;
2518 }
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002519 }
Emeric Brun4d7ada82021-06-30 19:04:16 +02002520 if (c == '1')
2521 rule->action_ptr = action_inc_gpc1;
2522 else
2523 rule->action_ptr = action_inc_gpc0;
2524 }
2525 else {
2526 /* default stick table id. */
2527 memprintf(err, "invalid gpc ID '%s'. Expects sc-set-gpc(<GPC ID>,<Track ID>)", args[*arg-1]);
2528 return ACT_RET_PRS_ERR;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002529 }
2530 rule->action = ACT_CUSTOM;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002531 return ACT_RET_PRS_OK;
2532}
2533
Emeric Brun877b0b52021-06-30 18:57:49 +02002534/* This function sets the gpt at index 'rule->arg.gpt.idx' of the array on the
2535 * tracksc counter of index 'rule->arg.gpt.sc' stored into the <stream> or
2536 * directly in the session <sess> if <stream> is set to NULL. This gpt is
2537 * set to the value computed by the expression 'rule->arg.gpt.expr' or if
2538 * 'rule->arg.gpt.expr' is null directly to the value of 'rule->arg.gpt.value'.
2539 *
2540 * This function always returns ACT_RET_CONT and parameter flags is unused.
2541 */
2542static enum act_return action_set_gpt(struct act_rule *rule, struct proxy *px,
2543 struct session *sess, struct stream *s, int flags)
2544{
2545 void *ptr;
2546 struct stksess *ts;
2547 struct stkctr *stkctr;
2548 unsigned int value = 0;
2549 struct sample *smp;
2550 int smp_opt_dir;
2551
2552 /* Extract the stksess, return OK if no stksess available. */
2553 if (s)
2554 stkctr = &s->stkctr[rule->arg.gpt.sc];
2555 else
2556 stkctr = &sess->stkctr[rule->arg.gpt.sc];
2557
2558 ts = stkctr_entry(stkctr);
2559 if (!ts)
2560 return ACT_RET_CONT;
2561
2562 /* Store the sample in the required sc, and ignore errors. */
2563 ptr = stktable_data_ptr_idx(stkctr->table, ts, STKTABLE_DT_GPT, rule->arg.gpt.idx);
2564 if (ptr) {
2565
2566 if (!rule->arg.gpt.expr)
2567 value = (unsigned int)(rule->arg.gpt.value);
2568 else {
2569 switch (rule->from) {
2570 case ACT_F_TCP_REQ_SES: smp_opt_dir = SMP_OPT_DIR_REQ; break;
2571 case ACT_F_TCP_REQ_CNT: smp_opt_dir = SMP_OPT_DIR_REQ; break;
2572 case ACT_F_TCP_RES_CNT: smp_opt_dir = SMP_OPT_DIR_RES; break;
2573 case ACT_F_HTTP_REQ: smp_opt_dir = SMP_OPT_DIR_REQ; break;
2574 case ACT_F_HTTP_RES: smp_opt_dir = SMP_OPT_DIR_RES; break;
2575 default:
2576 send_log(px, LOG_ERR, "stick table: internal error while setting gpt%u.", rule->arg.gpt.idx);
2577 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))
2578 ha_alert("stick table: internal error while executing setting gpt%u.\n", rule->arg.gpt.idx);
2579 return ACT_RET_CONT;
2580 }
2581
2582 /* Fetch and cast the expression. */
2583 smp = sample_fetch_as_type(px, sess, s, smp_opt_dir|SMP_OPT_FINAL, rule->arg.gpt.expr, SMP_T_SINT);
2584 if (!smp) {
2585 send_log(px, LOG_WARNING, "stick table: invalid expression or data type while setting gpt%u.", rule->arg.gpt.idx);
2586 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))
2587 ha_alert("stick table: invalid expression or data type while setting gpt%u.\n", rule->arg.gpt.idx);
2588 return ACT_RET_CONT;
2589 }
2590 value = (unsigned int)(smp->data.u.sint);
2591 }
2592
2593 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
2594
2595 stktable_data_cast(ptr, std_t_uint) = value;
2596
2597 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
2598
2599 stktable_touch_local(stkctr->table, ts, 0);
2600 }
2601
2602 return ACT_RET_CONT;
2603}
2604
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002605/* Always returns 1. */
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002606static enum act_return action_set_gpt0(struct act_rule *rule, struct proxy *px,
Willy Tarreau658b85b2015-09-27 10:00:49 +02002607 struct session *sess, struct stream *s, int flags)
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002608{
2609 void *ptr;
2610 struct stksess *ts;
2611 struct stkctr *stkctr;
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002612 unsigned int value = 0;
2613 struct sample *smp;
2614 int smp_opt_dir;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002615
2616 /* Extract the stksess, return OK if no stksess available. */
2617 if (s)
2618 stkctr = &s->stkctr[rule->arg.gpt.sc];
2619 else
2620 stkctr = &sess->stkctr[rule->arg.gpt.sc];
Willy Tarreau79c1e912016-01-25 14:54:45 +01002621
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002622 ts = stkctr_entry(stkctr);
2623 if (!ts)
2624 return ACT_RET_CONT;
2625
2626 /* Store the sample in the required sc, and ignore errors. */
2627 ptr = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPT0);
Emeric Brunf7ab0bf2021-06-30 18:58:22 +02002628 if (!ptr)
2629 ptr = stktable_data_ptr_idx(stkctr->table, ts, STKTABLE_DT_GPT, 0);
2630
Willy Tarreau79c1e912016-01-25 14:54:45 +01002631 if (ptr) {
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002632 if (!rule->arg.gpt.expr)
2633 value = (unsigned int)(rule->arg.gpt.value);
2634 else {
2635 switch (rule->from) {
2636 case ACT_F_TCP_REQ_SES: smp_opt_dir = SMP_OPT_DIR_REQ; break;
2637 case ACT_F_TCP_REQ_CNT: smp_opt_dir = SMP_OPT_DIR_REQ; break;
2638 case ACT_F_TCP_RES_CNT: smp_opt_dir = SMP_OPT_DIR_RES; break;
2639 case ACT_F_HTTP_REQ: smp_opt_dir = SMP_OPT_DIR_REQ; break;
2640 case ACT_F_HTTP_RES: smp_opt_dir = SMP_OPT_DIR_RES; break;
2641 default:
2642 send_log(px, LOG_ERR, "stick table: internal error while setting gpt0.");
2643 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))
2644 ha_alert("stick table: internal error while executing setting gpt0.\n");
2645 return ACT_RET_CONT;
2646 }
2647
2648 /* Fetch and cast the expression. */
2649 smp = sample_fetch_as_type(px, sess, s, smp_opt_dir|SMP_OPT_FINAL, rule->arg.gpt.expr, SMP_T_SINT);
2650 if (!smp) {
2651 send_log(px, LOG_WARNING, "stick table: invalid expression or data type while setting gpt0.");
2652 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))
2653 ha_alert("stick table: invalid expression or data type while setting gpt0.\n");
2654 return ACT_RET_CONT;
2655 }
2656 value = (unsigned int)(smp->data.u.sint);
2657 }
2658
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002659 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002660
Emeric Brun0e3457b2021-06-30 17:18:28 +02002661 stktable_data_cast(ptr, std_t_uint) = value;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002662
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002663 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002664
2665 stktable_touch_local(stkctr->table, ts, 0);
Willy Tarreau79c1e912016-01-25 14:54:45 +01002666 }
2667
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002668 return ACT_RET_CONT;
2669}
2670
Emeric Brun877b0b52021-06-30 18:57:49 +02002671/* This function is a parser for the "sc-set-gpt" and "sc-set-gpt0" actions.
2672 * It understands the formats:
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002673 *
Emeric Brun877b0b52021-06-30 18:57:49 +02002674 * sc-set-gpt(<gpt IDX>,<track ID>) <expression>
2675 * sc-set-gpt0(<track ID>) <expression>
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002676 *
Emeric Brun877b0b52021-06-30 18:57:49 +02002677 * It returns ACT_RET_PRS_ERR if fails and <err> is filled with an error message.
2678 * Otherwise, it returns ACT_RET_PRS_OK and the variable 'rule->arg.gpt.expr'
2679 * is filled with the pointer to the expression to execute or NULL if the arg
2680 * is directly an integer stored into 'rule->arg.gpt.value'.
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002681 */
Emeric Brun877b0b52021-06-30 18:57:49 +02002682static enum act_parse_ret parse_set_gpt(const char **args, int *arg, struct proxy *px,
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002683 struct act_rule *rule, char **err)
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002684{
2685 const char *cmd_name = args[*arg-1];
2686 char *error;
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002687 int smp_val;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002688
Emeric Brun877b0b52021-06-30 18:57:49 +02002689 cmd_name += strlen("sc-set-gpt");
2690 if (*cmd_name == '(') {
2691 cmd_name++; /* skip the '(' */
2692 rule->arg.gpt.idx = strtoul(cmd_name, &error, 10); /* Convert stick table id. */
2693 if (*error != ',') {
2694 memprintf(err, "Missing gpt ID '%s'. Expects sc-set-gpt(<GPT ID>,<Track ID>)", args[*arg-1]);
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002695 return ACT_RET_PRS_ERR;
2696 }
Emeric Brun877b0b52021-06-30 18:57:49 +02002697 else {
2698 cmd_name = error + 1; /* skip the ',' */
2699 rule->arg.gpt.sc = strtol(cmd_name, &error, 10); /* Convert stick table id. */
2700 if (*error != ')') {
2701 memprintf(err, "invalid stick table track ID '%s'. Expects sc-set-gpt(<GPT ID>,<Track ID>)", args[*arg-1]);
2702 return ACT_RET_PRS_ERR;
2703 }
2704
2705 if (rule->arg.gpt.sc >= MAX_SESS_STKCTR) {
2706 memprintf(err, "invalid stick table track ID '%s'. The max allowed ID is %d",
2707 args[*arg-1], MAX_SESS_STKCTR-1);
2708 return ACT_RET_PRS_ERR;
2709 }
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002710 }
Emeric Brun877b0b52021-06-30 18:57:49 +02002711 rule->action_ptr = action_set_gpt;
2712 }
2713 else if (*cmd_name == '0') {
2714 cmd_name++;
2715 if (*cmd_name == '\0') {
2716 /* default stick table id. */
2717 rule->arg.gpt.sc = 0;
2718 } else {
2719 /* parse the stick table id. */
2720 if (*cmd_name != '(') {
2721 memprintf(err, "invalid stick table track ID '%s'. Expects sc-set-gpt0(<Track ID>)", args[*arg-1]);
2722 return ACT_RET_PRS_ERR;
2723 }
2724 cmd_name++; /* jump the '(' */
2725 rule->arg.gpt.sc = strtol(cmd_name, &error, 10); /* Convert stick table id. */
2726 if (*error != ')') {
2727 memprintf(err, "invalid stick table track ID '%s'. Expects sc-set-gpt0(<Track ID>)", args[*arg-1]);
2728 return ACT_RET_PRS_ERR;
2729 }
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002730
Emeric Brun877b0b52021-06-30 18:57:49 +02002731 if (rule->arg.gpt.sc >= MAX_SESS_STKCTR) {
2732 memprintf(err, "invalid stick table track ID '%s'. The max allowed ID is %d",
2733 args[*arg-1], MAX_SESS_STKCTR-1);
2734 return ACT_RET_PRS_ERR;
2735 }
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002736 }
Emeric Brun877b0b52021-06-30 18:57:49 +02002737 rule->action_ptr = action_set_gpt0;
2738 }
2739 else {
2740 /* default stick table id. */
2741 memprintf(err, "invalid gpt ID '%s'. Expects sc-set-gpt(<GPT ID>,<Track ID>)", args[*arg-1]);
2742 return ACT_RET_PRS_ERR;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002743 }
2744
Willy Tarreauece4c4a2021-08-24 14:57:28 +02002745 /* value may be either an integer or an expression */
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002746 rule->arg.gpt.expr = NULL;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002747 rule->arg.gpt.value = strtol(args[*arg], &error, 10);
Willy Tarreauece4c4a2021-08-24 14:57:28 +02002748 if (*error == '\0') {
2749 /* valid integer, skip it */
2750 (*arg)++;
2751 } else {
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002752 rule->arg.gpt.expr = sample_parse_expr((char **)args, arg, px->conf.args.file,
Willy Tarreaue3b57bf2020-02-14 16:50:14 +01002753 px->conf.args.line, err, &px->conf.args, NULL);
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002754 if (!rule->arg.gpt.expr)
2755 return ACT_RET_PRS_ERR;
2756
2757 switch (rule->from) {
2758 case ACT_F_TCP_REQ_SES: smp_val = SMP_VAL_FE_SES_ACC; break;
2759 case ACT_F_TCP_REQ_CNT: smp_val = SMP_VAL_FE_REQ_CNT; break;
2760 case ACT_F_TCP_RES_CNT: smp_val = SMP_VAL_BE_RES_CNT; break;
2761 case ACT_F_HTTP_REQ: smp_val = SMP_VAL_FE_HRQ_HDR; break;
2762 case ACT_F_HTTP_RES: smp_val = SMP_VAL_BE_HRS_HDR; break;
2763 default:
2764 memprintf(err, "internal error, unexpected rule->from=%d, please report this bug!", rule->from);
2765 return ACT_RET_PRS_ERR;
2766 }
2767 if (!(rule->arg.gpt.expr->fetch->val & smp_val)) {
2768 memprintf(err, "fetch method '%s' extracts information from '%s', none of which is available here", args[*arg-1],
2769 sample_src_names(rule->arg.gpt.expr->fetch->use));
2770 free(rule->arg.gpt.expr);
2771 return ACT_RET_PRS_ERR;
2772 }
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002773 }
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002774
Thierry FOURNIER42148732015-09-02 17:17:33 +02002775 rule->action = ACT_CUSTOM;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002776
2777 return ACT_RET_PRS_OK;
2778}
2779
Willy Tarreau7d562212016-11-25 16:10:05 +01002780/* set temp integer to the number of used entries in the table pointed to by expr.
2781 * Accepts exactly 1 argument of type table.
2782 */
2783static int
2784smp_fetch_table_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
2785{
2786 smp->flags = SMP_F_VOL_TEST;
2787 smp->data.type = SMP_T_SINT;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002788 smp->data.u.sint = args->data.t->current;
Willy Tarreau7d562212016-11-25 16:10:05 +01002789 return 1;
2790}
2791
2792/* set temp integer to the number of free entries in the table pointed to by expr.
2793 * Accepts exactly 1 argument of type table.
2794 */
2795static int
2796smp_fetch_table_avl(const struct arg *args, struct sample *smp, const char *kw, void *private)
2797{
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002798 struct stktable *t;
Willy Tarreau7d562212016-11-25 16:10:05 +01002799
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002800 t = args->data.t;
Willy Tarreau7d562212016-11-25 16:10:05 +01002801 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 = t->size - t->current;
Willy Tarreau7d562212016-11-25 16:10:05 +01002804 return 1;
2805}
2806
2807/* Returns a pointer to a stkctr depending on the fetch keyword name.
2808 * It is designed to be called as sc[0-9]_* sc_* or src_* exclusively.
2809 * sc[0-9]_* will return a pointer to the respective field in the
2810 * stream <l4>. sc_* requires an UINT argument specifying the stick
2811 * counter number. src_* will fill a locally allocated structure with
2812 * the table and entry corresponding to what is specified with src_*.
2813 * NULL may be returned if the designated stkctr is not tracked. For
2814 * the sc_* and sc[0-9]_* forms, an optional table argument may be
2815 * passed. When present, the currently tracked key is then looked up
2816 * in the specified table instead of the current table. The purpose is
Ilya Shipitsin47d17182020-06-21 21:42:57 +05002817 * to be able to convert multiple values per key (eg: have gpc0 from
Willy Tarreau7d562212016-11-25 16:10:05 +01002818 * multiple tables). <strm> is allowed to be NULL, in which case only
2819 * the session will be consulted.
2820 */
2821struct stkctr *
Emeric Brun819fc6f2017-06-13 19:37:32 +02002822smp_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 +01002823{
Willy Tarreau7d562212016-11-25 16:10:05 +01002824 struct stkctr *stkptr;
2825 struct stksess *stksess;
2826 unsigned int num = kw[2] - '0';
2827 int arg = 0;
2828
2829 if (num == '_' - '0') {
2830 /* sc_* variant, args[0] = ctr# (mandatory) */
2831 num = args[arg++].data.sint;
Willy Tarreau7d562212016-11-25 16:10:05 +01002832 }
2833 else if (num > 9) { /* src_* variant, args[0] = table */
2834 struct stktable_key *key;
2835 struct connection *conn = objt_conn(sess->origin);
2836 struct sample smp;
2837
2838 if (!conn)
2839 return NULL;
2840
Joseph Herlant5662fa42018-11-15 13:43:28 -08002841 /* Fetch source address in a sample. */
Willy Tarreau7d562212016-11-25 16:10:05 +01002842 smp.px = NULL;
2843 smp.sess = sess;
2844 smp.strm = strm;
Amaury Denoyellec460c702021-05-12 10:17:47 +02002845 if (!smp_fetch_src || !smp_fetch_src(empty_arg_list, &smp, "src", NULL))
Willy Tarreau7d562212016-11-25 16:10:05 +01002846 return NULL;
2847
2848 /* Converts into key. */
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002849 key = smp_to_stkey(&smp, args->data.t);
Willy Tarreau7d562212016-11-25 16:10:05 +01002850 if (!key)
2851 return NULL;
2852
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002853 stkctr->table = args->data.t;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002854 stkctr_set_entry(stkctr, stktable_lookup_key(stkctr->table, key));
2855 return stkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002856 }
2857
2858 /* Here, <num> contains the counter number from 0 to 9 for
2859 * the sc[0-9]_ form, or even higher using sc_(num) if needed.
2860 * args[arg] is the first optional argument. We first lookup the
2861 * ctr form the stream, then from the session if it was not there.
Christopher Fauleta9fa88a2019-10-21 10:53:34 +02002862 * But we must be sure the counter does not exceed MAX_SESS_STKCTR.
Willy Tarreau7d562212016-11-25 16:10:05 +01002863 */
Christopher Fauleta9fa88a2019-10-21 10:53:34 +02002864 if (num >= MAX_SESS_STKCTR)
2865 return NULL;
Willy Tarreau7d562212016-11-25 16:10:05 +01002866
2867 if (strm)
2868 stkptr = &strm->stkctr[num];
2869 if (!strm || !stkctr_entry(stkptr)) {
2870 stkptr = &sess->stkctr[num];
2871 if (!stkctr_entry(stkptr))
2872 return NULL;
2873 }
2874
2875 stksess = stkctr_entry(stkptr);
2876 if (!stksess)
2877 return NULL;
2878
2879 if (unlikely(args[arg].type == ARGT_TAB)) {
2880 /* an alternate table was specified, let's look up the same key there */
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002881 stkctr->table = args[arg].data.t;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002882 stkctr_set_entry(stkctr, stktable_lookup(stkctr->table, stksess));
2883 return stkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002884 }
2885 return stkptr;
2886}
2887
2888/* same as smp_fetch_sc_stkctr() but dedicated to src_* and can create
2889 * the entry if it doesn't exist yet. This is needed for a few fetch
2890 * functions which need to create an entry, such as src_inc_gpc* and
2891 * src_clr_gpc*.
2892 */
2893struct stkctr *
Emeric Brun819fc6f2017-06-13 19:37:32 +02002894smp_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 +01002895{
Willy Tarreau7d562212016-11-25 16:10:05 +01002896 struct stktable_key *key;
2897 struct connection *conn = objt_conn(sess->origin);
2898 struct sample smp;
2899
2900 if (strncmp(kw, "src_", 4) != 0)
2901 return NULL;
2902
2903 if (!conn)
2904 return NULL;
2905
Joseph Herlant5662fa42018-11-15 13:43:28 -08002906 /* Fetch source address in a sample. */
Willy Tarreau7d562212016-11-25 16:10:05 +01002907 smp.px = NULL;
2908 smp.sess = sess;
2909 smp.strm = strm;
Amaury Denoyellec460c702021-05-12 10:17:47 +02002910 if (!smp_fetch_src || !smp_fetch_src(empty_arg_list, &smp, "src", NULL))
Willy Tarreau7d562212016-11-25 16:10:05 +01002911 return NULL;
2912
2913 /* Converts into key. */
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002914 key = smp_to_stkey(&smp, args->data.t);
Willy Tarreau7d562212016-11-25 16:10:05 +01002915 if (!key)
2916 return NULL;
2917
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002918 stkctr->table = args->data.t;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002919 stkctr_set_entry(stkctr, stktable_get_entry(stkctr->table, key));
2920 return stkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002921}
2922
2923/* set return a boolean indicating if the requested stream counter is
2924 * currently being tracked or not.
2925 * Supports being called as "sc[0-9]_tracked" only.
2926 */
2927static int
2928smp_fetch_sc_tracked(const struct arg *args, struct sample *smp, const char *kw, void *private)
2929{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002930 struct stkctr tmpstkctr;
2931 struct stkctr *stkctr;
2932
Willy Tarreau7d562212016-11-25 16:10:05 +01002933 smp->flags = SMP_F_VOL_TEST;
2934 smp->data.type = SMP_T_BOOL;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002935 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2936 smp->data.u.sint = !!stkctr;
2937
2938 /* release the ref count */
Dirkjan Bussinkff57f1b2018-09-14 14:31:22 +02002939 if (stkctr == &tmpstkctr)
Emeric Brun819fc6f2017-06-13 19:37:32 +02002940 stktable_release(stkctr->table, stkctr_entry(stkctr));
2941
Emeric Brun877b0b52021-06-30 18:57:49 +02002942 return 1;
2943}
2944
2945/* set <smp> to the General Purpose Tag of index set as first arg
2946 * to value from the stream's tracked frontend counters or from the src.
2947 * Supports being called as "sc_get_gpt(<gpt-idx>,<sc-idx>[,<table>])" or
2948 * "src_get_gpt(<gpt-idx>[,<table>])" only. Value zero is returned if
2949 * the key is new or gpt is not stored.
2950 */
2951static int
2952smp_fetch_sc_get_gpt(const struct arg *args, struct sample *smp, const char *kw, void *private)
2953{
2954 struct stkctr tmpstkctr;
2955 struct stkctr *stkctr;
2956 unsigned int idx;
2957
2958 idx = args[0].data.sint;
2959
2960 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args + 1, kw, &tmpstkctr);
2961 if (!stkctr)
2962 return 0;
2963
2964 smp->flags = SMP_F_VOL_TEST;
2965 smp->data.type = SMP_T_SINT;
2966 smp->data.u.sint = 0;
2967
2968 if (stkctr_entry(stkctr)) {
2969 void *ptr;
2970
2971 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPT, idx);
2972 if (!ptr) {
2973 if (stkctr == &tmpstkctr)
2974 stktable_release(stkctr->table, stkctr_entry(stkctr));
2975 return 0; /* parameter not stored */
2976 }
2977
2978 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2979
2980 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
2981
2982 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2983
2984 if (stkctr == &tmpstkctr)
2985 stktable_release(stkctr->table, stkctr_entry(stkctr));
2986 }
Willy Tarreau7d562212016-11-25 16:10:05 +01002987 return 1;
2988}
2989
2990/* set <smp> to the General Purpose Flag 0 value from the stream's tracked
2991 * frontend counters or from the src.
2992 * Supports being called as "sc[0-9]_get_gpc0" or "src_get_gpt0" only. Value
2993 * zero is returned if the key is new.
2994 */
2995static int
2996smp_fetch_sc_get_gpt0(const struct arg *args, struct sample *smp, const char *kw, void *private)
2997{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002998 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002999 struct stkctr *stkctr;
3000
Emeric Brun819fc6f2017-06-13 19:37:32 +02003001 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003002 if (!stkctr)
3003 return 0;
3004
3005 smp->flags = SMP_F_VOL_TEST;
3006 smp->data.type = SMP_T_SINT;
3007 smp->data.u.sint = 0;
3008
Emeric Brun819fc6f2017-06-13 19:37:32 +02003009 if (stkctr_entry(stkctr)) {
3010 void *ptr;
3011
3012 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPT0);
Emeric Brunf7ab0bf2021-06-30 18:58:22 +02003013 if (!ptr)
3014 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPT, 0);
3015
Emeric Brun4d7ada82021-06-30 19:04:16 +02003016 if (!ptr) {
3017 if (stkctr == &tmpstkctr)
3018 stktable_release(stkctr->table, stkctr_entry(stkctr));
3019 return 0; /* parameter not stored */
3020 }
3021
3022 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3023
3024 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
3025
3026 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3027
3028 if (stkctr == &tmpstkctr)
3029 stktable_release(stkctr->table, stkctr_entry(stkctr));
3030 }
3031 return 1;
3032}
3033
3034/* set <smp> to the GPC[args(0)]'s value from the stream's tracked
3035 * frontend counters or from the src.
3036 * Supports being called as "sc_get_gpc(<gpc-idx>,<sc-idx>[,<table>])" or
3037 * "src_get_gpc(<gpc-idx>[,<table>])" only. Value
3038 * Value zero is returned if the key is new or gpc is not stored.
3039 */
3040static int
3041smp_fetch_sc_get_gpc(const struct arg *args, struct sample *smp, const char *kw, void *private)
3042{
3043 struct stkctr tmpstkctr;
3044 struct stkctr *stkctr;
3045 unsigned int idx;
3046
3047 idx = args[0].data.sint;
3048
3049 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args + 1, kw, &tmpstkctr);
3050 if (!stkctr)
3051 return 0;
3052
3053 smp->flags = SMP_F_VOL_TEST;
3054 smp->data.type = SMP_T_SINT;
3055 smp->data.u.sint = 0;
3056
3057 if (stkctr_entry(stkctr) != NULL) {
3058 void *ptr;
3059
3060 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC, idx);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003061 if (!ptr) {
3062 if (stkctr == &tmpstkctr)
3063 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003064 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003065 }
3066
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003067 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003068
Emeric Brun0e3457b2021-06-30 17:18:28 +02003069 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003070
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003071 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003072
3073 if (stkctr == &tmpstkctr)
3074 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003075 }
3076 return 1;
3077}
3078
3079/* set <smp> to the General Purpose Counter 0 value from the stream's tracked
3080 * frontend counters or from the src.
3081 * Supports being called as "sc[0-9]_get_gpc0" or "src_get_gpc0" only. Value
3082 * zero is returned if the key is new.
3083 */
3084static int
3085smp_fetch_sc_get_gpc0(const struct arg *args, struct sample *smp, const char *kw, void *private)
3086{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003087 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003088 struct stkctr *stkctr;
3089
Emeric Brun819fc6f2017-06-13 19:37:32 +02003090 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003091 if (!stkctr)
3092 return 0;
3093
3094 smp->flags = SMP_F_VOL_TEST;
3095 smp->data.type = SMP_T_SINT;
3096 smp->data.u.sint = 0;
3097
3098 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003099 void *ptr;
3100
3101 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0);
3102 if (!ptr) {
Emeric Brun726783d2021-06-30 19:06:43 +02003103 /* fallback on the gpc array */
3104 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC, 0);
3105 }
3106
3107 if (!ptr) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003108 if (stkctr == &tmpstkctr)
3109 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003110 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003111 }
3112
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003113 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003114
Emeric Brun0e3457b2021-06-30 17:18:28 +02003115 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003116
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003117 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003118
3119 if (stkctr == &tmpstkctr)
3120 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003121 }
3122 return 1;
3123}
3124
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003125/* set <smp> to the General Purpose Counter 1 value from the stream's tracked
3126 * frontend counters or from the src.
3127 * Supports being called as "sc[0-9]_get_gpc1" or "src_get_gpc1" only. Value
3128 * zero is returned if the key is new.
3129 */
3130static int
3131smp_fetch_sc_get_gpc1(const struct arg *args, struct sample *smp, const char *kw, void *private)
3132{
3133 struct stkctr tmpstkctr;
3134 struct stkctr *stkctr;
3135
3136 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
3137 if (!stkctr)
3138 return 0;
3139
3140 smp->flags = SMP_F_VOL_TEST;
3141 smp->data.type = SMP_T_SINT;
3142 smp->data.u.sint = 0;
3143
3144 if (stkctr_entry(stkctr) != NULL) {
3145 void *ptr;
3146
3147 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1);
3148 if (!ptr) {
Emeric Brun726783d2021-06-30 19:06:43 +02003149 /* fallback on the gpc array */
3150 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC, 1);
3151 }
3152
3153 if (!ptr) {
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003154 if (stkctr == &tmpstkctr)
3155 stktable_release(stkctr->table, stkctr_entry(stkctr));
3156 return 0; /* parameter not stored */
3157 }
3158
3159 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3160
Emeric Brun0e3457b2021-06-30 17:18:28 +02003161 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003162
3163 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3164
3165 if (stkctr == &tmpstkctr)
3166 stktable_release(stkctr->table, stkctr_entry(stkctr));
3167 }
3168 return 1;
3169}
3170
Emeric Brun4d7ada82021-06-30 19:04:16 +02003171/* set <smp> to the GPC[args(0)]'s event rate from the stream's
3172 * tracked frontend counters or from the src.
3173 * Supports being called as "sc_gpc_rate(<gpc-idx>,<sc-idx>[,<table])"
3174 * or "src_gpc_rate(<gpc-idx>[,<table>])" only.
3175 * Value zero is returned if the key is new or gpc_rate is not stored.
3176 */
3177static int
3178smp_fetch_sc_gpc_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3179{
3180 struct stkctr tmpstkctr;
3181 struct stkctr *stkctr;
3182 unsigned int idx;
3183
3184 idx = args[0].data.sint;
3185
3186 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args + 1, kw, &tmpstkctr);
3187 if (!stkctr)
3188 return 0;
3189
3190 smp->flags = SMP_F_VOL_TEST;
3191 smp->data.type = SMP_T_SINT;
3192 smp->data.u.sint = 0;
3193 if (stkctr_entry(stkctr) != NULL) {
3194 void *ptr;
3195
3196 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC_RATE, idx);
3197 if (!ptr) {
3198 if (stkctr == &tmpstkctr)
3199 stktable_release(stkctr->table, stkctr_entry(stkctr));
3200 return 0; /* parameter not stored */
3201 }
3202
3203 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3204
3205 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
3206 stkctr->table->data_arg[STKTABLE_DT_GPC_RATE].u);
3207
3208 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3209
3210 if (stkctr == &tmpstkctr)
3211 stktable_release(stkctr->table, stkctr_entry(stkctr));
3212 }
3213 return 1;
3214}
3215
Willy Tarreau7d562212016-11-25 16:10:05 +01003216/* set <smp> to the General Purpose Counter 0's event rate from the stream's
3217 * tracked frontend counters or from the src.
3218 * Supports being called as "sc[0-9]_gpc0_rate" or "src_gpc0_rate" only.
3219 * Value zero is returned if the key is new.
3220 */
3221static int
3222smp_fetch_sc_gpc0_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3223{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003224 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003225 struct stkctr *stkctr;
Emeric Brun726783d2021-06-30 19:06:43 +02003226 unsigned int period;
Willy Tarreau7d562212016-11-25 16:10:05 +01003227
Emeric Brun819fc6f2017-06-13 19:37:32 +02003228 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003229 if (!stkctr)
3230 return 0;
3231
3232 smp->flags = SMP_F_VOL_TEST;
3233 smp->data.type = SMP_T_SINT;
3234 smp->data.u.sint = 0;
3235 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003236 void *ptr;
3237
3238 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0_RATE);
Emeric Brun726783d2021-06-30 19:06:43 +02003239 if (ptr) {
3240 period = stkctr->table->data_arg[STKTABLE_DT_GPC0_RATE].u;
3241 }
3242 else {
3243 /* fallback on the gpc array */
3244 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC_RATE, 0);
3245 if (ptr)
3246 period = stkctr->table->data_arg[STKTABLE_DT_GPC_RATE].u;
3247 }
3248
Emeric Brun819fc6f2017-06-13 19:37:32 +02003249 if (!ptr) {
3250 if (stkctr == &tmpstkctr)
3251 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003252 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003253 }
3254
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003255 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003256
Emeric Brun726783d2021-06-30 19:06:43 +02003257 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp), period);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003258
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003259 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003260
3261 if (stkctr == &tmpstkctr)
3262 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003263 }
3264 return 1;
3265}
3266
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003267/* set <smp> to the General Purpose Counter 1's event rate from the stream's
3268 * tracked frontend counters or from the src.
3269 * Supports being called as "sc[0-9]_gpc1_rate" or "src_gpc1_rate" only.
3270 * Value zero is returned if the key is new.
3271 */
3272static int
3273smp_fetch_sc_gpc1_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3274{
3275 struct stkctr tmpstkctr;
3276 struct stkctr *stkctr;
Emeric Brun726783d2021-06-30 19:06:43 +02003277 unsigned int period;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003278
3279 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
3280 if (!stkctr)
3281 return 0;
3282
3283 smp->flags = SMP_F_VOL_TEST;
3284 smp->data.type = SMP_T_SINT;
3285 smp->data.u.sint = 0;
3286 if (stkctr_entry(stkctr) != NULL) {
3287 void *ptr;
3288
3289 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1_RATE);
Emeric Brun726783d2021-06-30 19:06:43 +02003290 if (ptr) {
3291 period = stkctr->table->data_arg[STKTABLE_DT_GPC1_RATE].u;
3292 }
3293 else {
3294 /* fallback on the gpc array */
3295 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC_RATE, 1);
3296 if (ptr)
3297 period = stkctr->table->data_arg[STKTABLE_DT_GPC_RATE].u;
3298 }
3299
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003300 if (!ptr) {
3301 if (stkctr == &tmpstkctr)
3302 stktable_release(stkctr->table, stkctr_entry(stkctr));
3303 return 0; /* parameter not stored */
3304 }
3305
3306 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3307
Emeric Brun726783d2021-06-30 19:06:43 +02003308 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 +01003309
3310 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3311
3312 if (stkctr == &tmpstkctr)
3313 stktable_release(stkctr->table, stkctr_entry(stkctr));
3314 }
3315 return 1;
3316}
3317
Emeric Brun4d7ada82021-06-30 19:04:16 +02003318/* Increment the GPC[args(0)] value from the stream's tracked
3319 * frontend counters and return it into temp integer.
3320 * Supports being called as "sc_inc_gpc(<gpc-idx>,<sc-idx>[,<table>])"
3321 * or "src_inc_gpc(<gpc-idx>[,<table>])" only.
3322 */
3323static int
3324smp_fetch_sc_inc_gpc(const struct arg *args, struct sample *smp, const char *kw, void *private)
3325{
3326 struct stkctr tmpstkctr;
3327 struct stkctr *stkctr;
3328 unsigned int idx;
3329
3330 idx = args[0].data.sint;
3331
3332 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args + 1, kw, &tmpstkctr);
3333 if (!stkctr)
3334 return 0;
3335
3336 smp->flags = SMP_F_VOL_TEST;
3337 smp->data.type = SMP_T_SINT;
3338 smp->data.u.sint = 0;
3339
3340 if (!stkctr_entry(stkctr))
3341 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
3342
3343 if (stkctr && stkctr_entry(stkctr)) {
3344 void *ptr1,*ptr2;
3345
3346
3347 /* First, update gpc0_rate if it's tracked. Second, update its
3348 * gpc0 if tracked. Returns gpc0's value otherwise the curr_ctr.
3349 */
3350 ptr1 = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC_RATE, idx);
3351 ptr2 = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC, idx);
3352 if (ptr1 || ptr2) {
3353 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3354
3355 if (ptr1) {
3356 update_freq_ctr_period(&stktable_data_cast(ptr1, std_t_frqp),
3357 stkctr->table->data_arg[STKTABLE_DT_GPC_RATE].u, 1);
3358 smp->data.u.sint = (&stktable_data_cast(ptr1, std_t_frqp))->curr_ctr;
3359 }
3360
3361 if (ptr2)
3362 smp->data.u.sint = ++stktable_data_cast(ptr2, std_t_uint);
3363
3364 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3365
3366 /* If data was modified, we need to touch to re-schedule sync */
3367 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
3368 }
3369 else if (stkctr == &tmpstkctr)
3370 stktable_release(stkctr->table, stkctr_entry(stkctr));
3371 }
3372 return 1;
3373}
3374
Willy Tarreau7d562212016-11-25 16:10:05 +01003375/* Increment the General Purpose Counter 0 value from the stream's tracked
3376 * frontend counters and return it into temp integer.
3377 * Supports being called as "sc[0-9]_inc_gpc0" or "src_inc_gpc0" only.
3378 */
3379static int
3380smp_fetch_sc_inc_gpc0(const struct arg *args, struct sample *smp, const char *kw, void *private)
3381{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003382 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003383 struct stkctr *stkctr;
Willy Tarreau5b654ad2021-07-06 18:51:12 +02003384 unsigned int period = 0;
Willy Tarreau7d562212016-11-25 16:10:05 +01003385
Emeric Brun819fc6f2017-06-13 19:37:32 +02003386 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003387 if (!stkctr)
3388 return 0;
3389
3390 smp->flags = SMP_F_VOL_TEST;
3391 smp->data.type = SMP_T_SINT;
3392 smp->data.u.sint = 0;
3393
Emeric Brun819fc6f2017-06-13 19:37:32 +02003394 if (!stkctr_entry(stkctr))
3395 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003396
3397 if (stkctr && stkctr_entry(stkctr)) {
3398 void *ptr1,*ptr2;
3399
Emeric Brun819fc6f2017-06-13 19:37:32 +02003400
Willy Tarreau7d562212016-11-25 16:10:05 +01003401 /* First, update gpc0_rate if it's tracked. Second, update its
3402 * gpc0 if tracked. Returns gpc0's value otherwise the curr_ctr.
3403 */
3404 ptr1 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0_RATE);
Emeric Brun726783d2021-06-30 19:06:43 +02003405 if (ptr1) {
3406 period = stkctr->table->data_arg[STKTABLE_DT_GPC0_RATE].u;
3407 }
3408 else {
3409 /* fallback on the gpc array */
3410 ptr1 = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC_RATE, 0);
3411 if (ptr1)
3412 period = stkctr->table->data_arg[STKTABLE_DT_GPC_RATE].u;
3413 }
3414
Willy Tarreau7d562212016-11-25 16:10:05 +01003415 ptr2 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0);
Emeric Brun726783d2021-06-30 19:06:43 +02003416 if (!ptr2) {
3417 /* fallback on the gpc array */
3418 ptr2 = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC, 0);
3419 }
3420
Emeric Brun819fc6f2017-06-13 19:37:32 +02003421 if (ptr1 || ptr2) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003422 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Willy Tarreau7d562212016-11-25 16:10:05 +01003423
Emeric Brun819fc6f2017-06-13 19:37:32 +02003424 if (ptr1) {
Emeric Brun0e3457b2021-06-30 17:18:28 +02003425 update_freq_ctr_period(&stktable_data_cast(ptr1, std_t_frqp),
Emeric Brun726783d2021-06-30 19:06:43 +02003426 period, 1);
Emeric Brun0e3457b2021-06-30 17:18:28 +02003427 smp->data.u.sint = (&stktable_data_cast(ptr1, std_t_frqp))->curr_ctr;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003428 }
3429
3430 if (ptr2)
Emeric Brun0e3457b2021-06-30 17:18:28 +02003431 smp->data.u.sint = ++stktable_data_cast(ptr2, std_t_uint);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003432
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003433 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003434
3435 /* If data was modified, we need to touch to re-schedule sync */
3436 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
3437 }
3438 else if (stkctr == &tmpstkctr)
3439 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003440 }
3441 return 1;
3442}
3443
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003444/* Increment the General Purpose Counter 1 value from the stream's tracked
3445 * frontend counters and return it into temp integer.
3446 * Supports being called as "sc[0-9]_inc_gpc1" or "src_inc_gpc1" only.
3447 */
3448static int
3449smp_fetch_sc_inc_gpc1(const struct arg *args, struct sample *smp, const char *kw, void *private)
3450{
3451 struct stkctr tmpstkctr;
3452 struct stkctr *stkctr;
Willy Tarreau5b654ad2021-07-06 18:51:12 +02003453 unsigned int period = 0;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003454
3455 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
3456 if (!stkctr)
3457 return 0;
3458
3459 smp->flags = SMP_F_VOL_TEST;
3460 smp->data.type = SMP_T_SINT;
3461 smp->data.u.sint = 0;
3462
3463 if (!stkctr_entry(stkctr))
3464 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
3465
3466 if (stkctr && stkctr_entry(stkctr)) {
3467 void *ptr1,*ptr2;
3468
3469
3470 /* First, update gpc1_rate if it's tracked. Second, update its
3471 * gpc1 if tracked. Returns gpc1's value otherwise the curr_ctr.
3472 */
3473 ptr1 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1_RATE);
Emeric Brun726783d2021-06-30 19:06:43 +02003474 if (ptr1) {
3475 period = stkctr->table->data_arg[STKTABLE_DT_GPC1_RATE].u;
3476 }
3477 else {
3478 /* fallback on the gpc array */
3479 ptr1 = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC_RATE, 1);
3480 if (ptr1)
3481 period = stkctr->table->data_arg[STKTABLE_DT_GPC_RATE].u;
3482 }
3483
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003484 ptr2 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1);
Emeric Brun726783d2021-06-30 19:06:43 +02003485 if (!ptr2) {
3486 /* fallback on the gpc array */
3487 ptr2 = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC, 1);
3488 }
3489
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003490 if (ptr1 || ptr2) {
3491 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3492
3493 if (ptr1) {
Emeric Brun0e3457b2021-06-30 17:18:28 +02003494 update_freq_ctr_period(&stktable_data_cast(ptr1, std_t_frqp),
Emeric Brun726783d2021-06-30 19:06:43 +02003495 period, 1);
Emeric Brun0e3457b2021-06-30 17:18:28 +02003496 smp->data.u.sint = (&stktable_data_cast(ptr1, std_t_frqp))->curr_ctr;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003497 }
3498
3499 if (ptr2)
Emeric Brun0e3457b2021-06-30 17:18:28 +02003500 smp->data.u.sint = ++stktable_data_cast(ptr2, std_t_uint);
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003501
3502 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3503
3504 /* If data was modified, we need to touch to re-schedule sync */
3505 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
3506 }
3507 else if (stkctr == &tmpstkctr)
3508 stktable_release(stkctr->table, stkctr_entry(stkctr));
3509 }
3510 return 1;
3511}
3512
Emeric Brun4d7ada82021-06-30 19:04:16 +02003513/* Clear the GPC[args(0)] value from the stream's tracked
3514 * frontend counters and return its previous value into temp integer.
3515 * Supports being called as "sc_clr_gpc(<gpc-idx>,<sc-idx>[,<table>])"
3516 * or "src_clr_gpc(<gpc-idx>[,<table>])" only.
3517 */
3518static int
3519smp_fetch_sc_clr_gpc(const struct arg *args, struct sample *smp, const char *kw, void *private)
3520{
3521 struct stkctr tmpstkctr;
3522 struct stkctr *stkctr;
3523 unsigned int idx;
3524
3525 idx = args[0].data.sint;
3526
3527 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args + 1, kw, &tmpstkctr);
3528 if (!stkctr)
3529 return 0;
3530
3531 smp->flags = SMP_F_VOL_TEST;
3532 smp->data.type = SMP_T_SINT;
3533 smp->data.u.sint = 0;
3534
3535 if (!stkctr_entry(stkctr))
3536 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
3537
3538 if (stkctr && stkctr_entry(stkctr)) {
3539 void *ptr;
3540
3541 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC, idx);
3542 if (!ptr) {
3543 if (stkctr == &tmpstkctr)
3544 stktable_release(stkctr->table, stkctr_entry(stkctr));
3545 return 0; /* parameter not stored */
3546 }
3547
3548 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3549
3550 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
3551 stktable_data_cast(ptr, std_t_uint) = 0;
3552
3553 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3554
3555 /* If data was modified, we need to touch to re-schedule sync */
3556 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
3557 }
3558 return 1;
3559}
3560
Willy Tarreau7d562212016-11-25 16:10:05 +01003561/* Clear the General Purpose Counter 0 value from the stream's tracked
3562 * frontend counters and return its previous value into temp integer.
3563 * Supports being called as "sc[0-9]_clr_gpc0" or "src_clr_gpc0" only.
3564 */
3565static int
3566smp_fetch_sc_clr_gpc0(const struct arg *args, struct sample *smp, const char *kw, void *private)
3567{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003568 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003569 struct stkctr *stkctr;
3570
Emeric Brun819fc6f2017-06-13 19:37:32 +02003571 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003572 if (!stkctr)
3573 return 0;
3574
3575 smp->flags = SMP_F_VOL_TEST;
3576 smp->data.type = SMP_T_SINT;
3577 smp->data.u.sint = 0;
3578
Emeric Brun819fc6f2017-06-13 19:37:32 +02003579 if (!stkctr_entry(stkctr))
3580 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003581
Emeric Brun819fc6f2017-06-13 19:37:32 +02003582 if (stkctr && stkctr_entry(stkctr)) {
3583 void *ptr;
3584
3585 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0);
3586 if (!ptr) {
Emeric Brun726783d2021-06-30 19:06:43 +02003587 /* fallback on the gpc array */
3588 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC, 0);
3589 }
3590
3591 if (!ptr) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003592 if (stkctr == &tmpstkctr)
3593 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003594 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003595 }
3596
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003597 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003598
Emeric Brun0e3457b2021-06-30 17:18:28 +02003599 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
3600 stktable_data_cast(ptr, std_t_uint) = 0;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003601
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003602 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003603
Willy Tarreau7d562212016-11-25 16:10:05 +01003604 /* If data was modified, we need to touch to re-schedule sync */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003605 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
Willy Tarreau7d562212016-11-25 16:10:05 +01003606 }
3607 return 1;
3608}
3609
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003610/* Clear the General Purpose Counter 1 value from the stream's tracked
3611 * frontend counters and return its previous value into temp integer.
3612 * Supports being called as "sc[0-9]_clr_gpc1" or "src_clr_gpc1" only.
3613 */
3614static int
3615smp_fetch_sc_clr_gpc1(const struct arg *args, struct sample *smp, const char *kw, void *private)
3616{
3617 struct stkctr tmpstkctr;
3618 struct stkctr *stkctr;
3619
3620 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
3621 if (!stkctr)
3622 return 0;
3623
3624 smp->flags = SMP_F_VOL_TEST;
3625 smp->data.type = SMP_T_SINT;
3626 smp->data.u.sint = 0;
3627
3628 if (!stkctr_entry(stkctr))
3629 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
3630
3631 if (stkctr && stkctr_entry(stkctr)) {
3632 void *ptr;
3633
3634 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1);
3635 if (!ptr) {
Emeric Brun726783d2021-06-30 19:06:43 +02003636 /* fallback on the gpc array */
3637 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC, 1);
3638 }
3639
3640 if (!ptr) {
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003641 if (stkctr == &tmpstkctr)
3642 stktable_release(stkctr->table, stkctr_entry(stkctr));
3643 return 0; /* parameter not stored */
3644 }
3645
3646 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3647
Emeric Brun0e3457b2021-06-30 17:18:28 +02003648 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
3649 stktable_data_cast(ptr, std_t_uint) = 0;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003650
3651 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3652
3653 /* If data was modified, we need to touch to re-schedule sync */
3654 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
3655 }
3656 return 1;
3657}
3658
Willy Tarreau7d562212016-11-25 16:10:05 +01003659/* set <smp> to the cumulated number of connections from the stream's tracked
3660 * frontend counters. Supports being called as "sc[0-9]_conn_cnt" or
3661 * "src_conn_cnt" only.
3662 */
3663static int
3664smp_fetch_sc_conn_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
3665{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003666 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003667 struct stkctr *stkctr;
3668
Emeric Brun819fc6f2017-06-13 19:37:32 +02003669 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003670 if (!stkctr)
3671 return 0;
3672
3673 smp->flags = SMP_F_VOL_TEST;
3674 smp->data.type = SMP_T_SINT;
3675 smp->data.u.sint = 0;
3676 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003677 void *ptr;
3678
3679 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_CONN_CNT);
3680 if (!ptr) {
3681 if (stkctr == &tmpstkctr)
3682 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003683 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003684 }
3685
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003686 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003687
Emeric Brun0e3457b2021-06-30 17:18:28 +02003688 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003689
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003690 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003691
3692 if (stkctr == &tmpstkctr)
3693 stktable_release(stkctr->table, stkctr_entry(stkctr));
3694
3695
Willy Tarreau7d562212016-11-25 16:10:05 +01003696 }
3697 return 1;
3698}
3699
3700/* set <smp> to the connection rate from the stream's tracked frontend
3701 * counters. Supports being called as "sc[0-9]_conn_rate" or "src_conn_rate"
3702 * only.
3703 */
3704static int
3705smp_fetch_sc_conn_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3706{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003707 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003708 struct stkctr *stkctr;
3709
Emeric Brun819fc6f2017-06-13 19:37:32 +02003710 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003711 if (!stkctr)
3712 return 0;
3713
3714 smp->flags = SMP_F_VOL_TEST;
3715 smp->data.type = SMP_T_SINT;
3716 smp->data.u.sint = 0;
3717 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003718 void *ptr;
3719
3720 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_CONN_RATE);
3721 if (!ptr) {
3722 if (stkctr == &tmpstkctr)
3723 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003724 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003725 }
3726
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003727 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003728
Emeric Brun0e3457b2021-06-30 17:18:28 +02003729 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Willy Tarreau7d562212016-11-25 16:10:05 +01003730 stkctr->table->data_arg[STKTABLE_DT_CONN_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003731
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003732 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003733
3734 if (stkctr == &tmpstkctr)
3735 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003736 }
3737 return 1;
3738}
3739
3740/* set temp integer to the number of connections from the stream's source address
3741 * in the table pointed to by expr, after updating it.
3742 * Accepts exactly 1 argument of type table.
3743 */
3744static int
3745smp_fetch_src_updt_conn_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
3746{
3747 struct connection *conn = objt_conn(smp->sess->origin);
3748 struct stksess *ts;
3749 struct stktable_key *key;
3750 void *ptr;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003751 struct stktable *t;
Willy Tarreau7d562212016-11-25 16:10:05 +01003752
3753 if (!conn)
3754 return 0;
3755
Joseph Herlant5662fa42018-11-15 13:43:28 -08003756 /* Fetch source address in a sample. */
Amaury Denoyellec460c702021-05-12 10:17:47 +02003757 if (!smp_fetch_src || !smp_fetch_src(empty_arg_list, smp, "src", NULL))
Willy Tarreau7d562212016-11-25 16:10:05 +01003758 return 0;
3759
3760 /* Converts into key. */
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003761 key = smp_to_stkey(smp, args->data.t);
Willy Tarreau7d562212016-11-25 16:10:05 +01003762 if (!key)
3763 return 0;
3764
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003765 t = args->data.t;
Willy Tarreau7d562212016-11-25 16:10:05 +01003766
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003767 if ((ts = stktable_get_entry(t, key)) == NULL)
Willy Tarreau7d562212016-11-25 16:10:05 +01003768 /* entry does not exist and could not be created */
3769 return 0;
3770
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003771 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_CONN_CNT);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003772 if (!ptr) {
Willy Tarreau7d562212016-11-25 16:10:05 +01003773 return 0; /* parameter not stored in this table */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003774 }
Willy Tarreau7d562212016-11-25 16:10:05 +01003775
3776 smp->data.type = SMP_T_SINT;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003777
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003778 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003779
Emeric Brun0e3457b2021-06-30 17:18:28 +02003780 smp->data.u.sint = ++stktable_data_cast(ptr, std_t_uint);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003781
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003782 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003783
Willy Tarreau7d562212016-11-25 16:10:05 +01003784 smp->flags = SMP_F_VOL_TEST;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003785
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003786 stktable_touch_local(t, ts, 1);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003787
3788 /* Touch was previously performed by stktable_update_key */
Willy Tarreau7d562212016-11-25 16:10:05 +01003789 return 1;
3790}
3791
3792/* set <smp> to the number of concurrent connections from the stream's tracked
3793 * frontend counters. Supports being called as "sc[0-9]_conn_cur" or
3794 * "src_conn_cur" only.
3795 */
3796static int
3797smp_fetch_sc_conn_cur(const struct arg *args, struct sample *smp, const char *kw, void *private)
3798{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003799 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003800 struct stkctr *stkctr;
3801
Emeric Brun819fc6f2017-06-13 19:37:32 +02003802 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003803 if (!stkctr)
3804 return 0;
3805
3806 smp->flags = SMP_F_VOL_TEST;
3807 smp->data.type = SMP_T_SINT;
3808 smp->data.u.sint = 0;
3809 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003810 void *ptr;
3811
3812 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_CONN_CUR);
3813 if (!ptr) {
3814 if (stkctr == &tmpstkctr)
3815 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003816 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003817 }
3818
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003819 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003820
Emeric Brun0e3457b2021-06-30 17:18:28 +02003821 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003822
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003823 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003824
3825 if (stkctr == &tmpstkctr)
3826 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003827 }
3828 return 1;
3829}
3830
3831/* set <smp> to the cumulated number of streams from the stream's tracked
3832 * frontend counters. Supports being called as "sc[0-9]_sess_cnt" or
3833 * "src_sess_cnt" only.
3834 */
3835static int
3836smp_fetch_sc_sess_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
3837{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003838 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003839 struct stkctr *stkctr;
3840
Emeric Brun819fc6f2017-06-13 19:37:32 +02003841 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003842 if (!stkctr)
3843 return 0;
3844
3845 smp->flags = SMP_F_VOL_TEST;
3846 smp->data.type = SMP_T_SINT;
3847 smp->data.u.sint = 0;
3848 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003849 void *ptr;
3850
3851 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_SESS_CNT);
3852 if (!ptr) {
3853 if (stkctr == &tmpstkctr)
3854 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003855 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003856 }
3857
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003858 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003859
Emeric Brun0e3457b2021-06-30 17:18:28 +02003860 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003861
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003862 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003863
3864 if (stkctr == &tmpstkctr)
3865 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003866 }
3867 return 1;
3868}
3869
3870/* set <smp> to the stream rate from the stream's tracked frontend counters.
3871 * Supports being called as "sc[0-9]_sess_rate" or "src_sess_rate" only.
3872 */
3873static int
3874smp_fetch_sc_sess_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3875{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003876 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003877 struct stkctr *stkctr;
3878
Emeric Brun819fc6f2017-06-13 19:37:32 +02003879 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003880 if (!stkctr)
3881 return 0;
3882
3883 smp->flags = SMP_F_VOL_TEST;
3884 smp->data.type = SMP_T_SINT;
3885 smp->data.u.sint = 0;
3886 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003887 void *ptr;
3888
3889 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_SESS_RATE);
3890 if (!ptr) {
3891 if (stkctr == &tmpstkctr)
3892 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003893 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003894 }
3895
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003896 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003897
Emeric Brun0e3457b2021-06-30 17:18:28 +02003898 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Willy Tarreau7d562212016-11-25 16:10:05 +01003899 stkctr->table->data_arg[STKTABLE_DT_SESS_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003900
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003901 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003902
3903 if (stkctr == &tmpstkctr)
3904 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003905 }
3906 return 1;
3907}
3908
3909/* set <smp> to the cumulated number of HTTP requests from the stream's tracked
3910 * frontend counters. Supports being called as "sc[0-9]_http_req_cnt" or
3911 * "src_http_req_cnt" only.
3912 */
3913static int
3914smp_fetch_sc_http_req_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
3915{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003916 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003917 struct stkctr *stkctr;
3918
Emeric Brun819fc6f2017-06-13 19:37:32 +02003919 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003920 if (!stkctr)
3921 return 0;
3922
3923 smp->flags = SMP_F_VOL_TEST;
3924 smp->data.type = SMP_T_SINT;
3925 smp->data.u.sint = 0;
3926 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003927 void *ptr;
3928
3929 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_REQ_CNT);
3930 if (!ptr) {
3931 if (stkctr == &tmpstkctr)
3932 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003933 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003934 }
3935
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003936 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003937
Emeric Brun0e3457b2021-06-30 17:18:28 +02003938 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003939
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003940 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003941
3942 if (stkctr == &tmpstkctr)
3943 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003944 }
3945 return 1;
3946}
3947
3948/* set <smp> to the HTTP request rate from the stream's tracked frontend
3949 * counters. Supports being called as "sc[0-9]_http_req_rate" or
3950 * "src_http_req_rate" only.
3951 */
3952static int
3953smp_fetch_sc_http_req_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3954{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003955 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003956 struct stkctr *stkctr;
3957
Emeric Brun819fc6f2017-06-13 19:37:32 +02003958 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003959 if (!stkctr)
3960 return 0;
3961
3962 smp->flags = SMP_F_VOL_TEST;
3963 smp->data.type = SMP_T_SINT;
3964 smp->data.u.sint = 0;
3965 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003966 void *ptr;
3967
3968 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_REQ_RATE);
3969 if (!ptr) {
3970 if (stkctr == &tmpstkctr)
3971 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003972 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003973 }
3974
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003975 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003976
Emeric Brun0e3457b2021-06-30 17:18:28 +02003977 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Willy Tarreau7d562212016-11-25 16:10:05 +01003978 stkctr->table->data_arg[STKTABLE_DT_HTTP_REQ_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003979
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003980 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003981
3982 if (stkctr == &tmpstkctr)
3983 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003984 }
3985 return 1;
3986}
3987
3988/* set <smp> to the cumulated number of HTTP requests errors from the stream's
3989 * tracked frontend counters. Supports being called as "sc[0-9]_http_err_cnt" or
3990 * "src_http_err_cnt" only.
3991 */
3992static int
3993smp_fetch_sc_http_err_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
3994{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003995 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003996 struct stkctr *stkctr;
3997
Emeric Brun819fc6f2017-06-13 19:37:32 +02003998 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003999 if (!stkctr)
4000 return 0;
4001
4002 smp->flags = SMP_F_VOL_TEST;
4003 smp->data.type = SMP_T_SINT;
4004 smp->data.u.sint = 0;
4005 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02004006 void *ptr;
4007
4008 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_ERR_CNT);
4009 if (!ptr) {
4010 if (stkctr == &tmpstkctr)
4011 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004012 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02004013 }
4014
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004015 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004016
Emeric Brun0e3457b2021-06-30 17:18:28 +02004017 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004018
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004019 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004020
4021 if (stkctr == &tmpstkctr)
4022 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004023 }
4024 return 1;
4025}
4026
4027/* set <smp> to the HTTP request error rate from the stream's tracked frontend
4028 * counters. Supports being called as "sc[0-9]_http_err_rate" or
4029 * "src_http_err_rate" only.
4030 */
4031static int
4032smp_fetch_sc_http_err_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
4033{
Emeric Brun819fc6f2017-06-13 19:37:32 +02004034 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01004035 struct stkctr *stkctr;
4036
Emeric Brun819fc6f2017-06-13 19:37:32 +02004037 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01004038 if (!stkctr)
4039 return 0;
4040
4041 smp->flags = SMP_F_VOL_TEST;
4042 smp->data.type = SMP_T_SINT;
4043 smp->data.u.sint = 0;
4044 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02004045 void *ptr;
4046
4047 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_ERR_RATE);
4048 if (!ptr) {
4049 if (stkctr == &tmpstkctr)
4050 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004051 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02004052 }
4053
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004054 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004055
Emeric Brun0e3457b2021-06-30 17:18:28 +02004056 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Willy Tarreau7d562212016-11-25 16:10:05 +01004057 stkctr->table->data_arg[STKTABLE_DT_HTTP_ERR_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004058
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004059 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004060
4061 if (stkctr == &tmpstkctr)
4062 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004063 }
4064 return 1;
4065}
4066
Willy Tarreau826f3ab2021-02-10 12:07:15 +01004067/* set <smp> to the cumulated number of HTTP response failures from the stream's
4068 * tracked frontend counters. Supports being called as "sc[0-9]_http_fail_cnt" or
4069 * "src_http_fail_cnt" only.
4070 */
4071static int
4072smp_fetch_sc_http_fail_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
4073{
4074 struct stkctr tmpstkctr;
4075 struct stkctr *stkctr;
4076
4077 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
4078 if (!stkctr)
4079 return 0;
4080
4081 smp->flags = SMP_F_VOL_TEST;
4082 smp->data.type = SMP_T_SINT;
4083 smp->data.u.sint = 0;
4084 if (stkctr_entry(stkctr) != NULL) {
4085 void *ptr;
4086
4087 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_FAIL_CNT);
4088 if (!ptr) {
4089 if (stkctr == &tmpstkctr)
4090 stktable_release(stkctr->table, stkctr_entry(stkctr));
4091 return 0; /* parameter not stored */
4092 }
4093
4094 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
4095
Emeric Brun0e3457b2021-06-30 17:18:28 +02004096 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Willy Tarreau826f3ab2021-02-10 12:07:15 +01004097
4098 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
4099
4100 if (stkctr == &tmpstkctr)
4101 stktable_release(stkctr->table, stkctr_entry(stkctr));
4102 }
4103 return 1;
4104}
4105
4106/* set <smp> to the HTTP response failure rate from the stream's tracked frontend
4107 * counters. Supports being called as "sc[0-9]_http_fail_rate" or
4108 * "src_http_fail_rate" only.
4109 */
4110static int
4111smp_fetch_sc_http_fail_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
4112{
4113 struct stkctr tmpstkctr;
4114 struct stkctr *stkctr;
4115
4116 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
4117 if (!stkctr)
4118 return 0;
4119
4120 smp->flags = SMP_F_VOL_TEST;
4121 smp->data.type = SMP_T_SINT;
4122 smp->data.u.sint = 0;
4123 if (stkctr_entry(stkctr) != NULL) {
4124 void *ptr;
4125
4126 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_FAIL_RATE);
4127 if (!ptr) {
4128 if (stkctr == &tmpstkctr)
4129 stktable_release(stkctr->table, stkctr_entry(stkctr));
4130 return 0; /* parameter not stored */
4131 }
4132
4133 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
4134
Emeric Brun0e3457b2021-06-30 17:18:28 +02004135 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Willy Tarreau826f3ab2021-02-10 12:07:15 +01004136 stkctr->table->data_arg[STKTABLE_DT_HTTP_FAIL_RATE].u);
4137
4138 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
4139
4140 if (stkctr == &tmpstkctr)
4141 stktable_release(stkctr->table, stkctr_entry(stkctr));
4142 }
4143 return 1;
4144}
4145
Willy Tarreau7d562212016-11-25 16:10:05 +01004146/* set <smp> to the number of kbytes received from clients, as found in the
4147 * stream's tracked frontend counters. Supports being called as
4148 * "sc[0-9]_kbytes_in" or "src_kbytes_in" only.
4149 */
4150static int
4151smp_fetch_sc_kbytes_in(const struct arg *args, struct sample *smp, const char *kw, void *private)
4152{
Emeric Brun819fc6f2017-06-13 19:37:32 +02004153 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01004154 struct stkctr *stkctr;
4155
Emeric Brun819fc6f2017-06-13 19:37:32 +02004156 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01004157 if (!stkctr)
4158 return 0;
4159
4160 smp->flags = SMP_F_VOL_TEST;
4161 smp->data.type = SMP_T_SINT;
4162 smp->data.u.sint = 0;
4163 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02004164 void *ptr;
4165
4166 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_IN_CNT);
4167 if (!ptr) {
4168 if (stkctr == &tmpstkctr)
4169 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004170 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02004171 }
4172
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004173 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004174
Emeric Brun0e3457b2021-06-30 17:18:28 +02004175 smp->data.u.sint = stktable_data_cast(ptr, std_t_ull) >> 10;
Emeric Brun819fc6f2017-06-13 19:37:32 +02004176
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004177 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004178
4179 if (stkctr == &tmpstkctr)
4180 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004181 }
4182 return 1;
4183}
4184
4185/* set <smp> to the data rate received from clients in bytes/s, as found
4186 * in the stream's tracked frontend counters. Supports being called as
4187 * "sc[0-9]_bytes_in_rate" or "src_bytes_in_rate" only.
4188 */
4189static int
4190smp_fetch_sc_bytes_in_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
4191{
Emeric Brun819fc6f2017-06-13 19:37:32 +02004192 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01004193 struct stkctr *stkctr;
4194
Emeric Brun819fc6f2017-06-13 19:37:32 +02004195 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01004196 if (!stkctr)
4197 return 0;
4198
4199 smp->flags = SMP_F_VOL_TEST;
4200 smp->data.type = SMP_T_SINT;
4201 smp->data.u.sint = 0;
4202 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02004203 void *ptr;
4204
4205 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_IN_RATE);
4206 if (!ptr) {
4207 if (stkctr == &tmpstkctr)
4208 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004209 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02004210 }
4211
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004212 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004213
Emeric Brun0e3457b2021-06-30 17:18:28 +02004214 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Willy Tarreau7d562212016-11-25 16:10:05 +01004215 stkctr->table->data_arg[STKTABLE_DT_BYTES_IN_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004216
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004217 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004218
4219 if (stkctr == &tmpstkctr)
4220 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004221 }
4222 return 1;
4223}
4224
4225/* set <smp> to the number of kbytes sent to clients, as found in the
4226 * stream's tracked frontend counters. Supports being called as
4227 * "sc[0-9]_kbytes_out" or "src_kbytes_out" only.
4228 */
4229static int
4230smp_fetch_sc_kbytes_out(const struct arg *args, struct sample *smp, const char *kw, void *private)
4231{
Emeric Brun819fc6f2017-06-13 19:37:32 +02004232 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01004233 struct stkctr *stkctr;
4234
Emeric Brun819fc6f2017-06-13 19:37:32 +02004235 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01004236 if (!stkctr)
4237 return 0;
4238
4239 smp->flags = SMP_F_VOL_TEST;
4240 smp->data.type = SMP_T_SINT;
4241 smp->data.u.sint = 0;
4242 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02004243 void *ptr;
4244
4245 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_OUT_CNT);
4246 if (!ptr) {
4247 if (stkctr == &tmpstkctr)
4248 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004249 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02004250 }
4251
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004252 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004253
Emeric Brun0e3457b2021-06-30 17:18:28 +02004254 smp->data.u.sint = stktable_data_cast(ptr, std_t_ull) >> 10;
Emeric Brun819fc6f2017-06-13 19:37:32 +02004255
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004256 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004257
4258 if (stkctr == &tmpstkctr)
4259 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004260 }
4261 return 1;
4262}
4263
4264/* set <smp> to the data rate sent to clients in bytes/s, as found in the
4265 * stream's tracked frontend counters. Supports being called as
4266 * "sc[0-9]_bytes_out_rate" or "src_bytes_out_rate" only.
4267 */
4268static int
4269smp_fetch_sc_bytes_out_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
4270{
Emeric Brun819fc6f2017-06-13 19:37:32 +02004271 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01004272 struct stkctr *stkctr;
4273
Emeric Brun819fc6f2017-06-13 19:37:32 +02004274 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01004275 if (!stkctr)
4276 return 0;
4277
4278 smp->flags = SMP_F_VOL_TEST;
4279 smp->data.type = SMP_T_SINT;
4280 smp->data.u.sint = 0;
4281 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02004282 void *ptr;
4283
4284 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_OUT_RATE);
4285 if (!ptr) {
4286 if (stkctr == &tmpstkctr)
4287 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004288 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02004289 }
4290
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004291 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004292
Emeric Brun0e3457b2021-06-30 17:18:28 +02004293 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Willy Tarreau7d562212016-11-25 16:10:05 +01004294 stkctr->table->data_arg[STKTABLE_DT_BYTES_OUT_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004295
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004296 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004297
4298 if (stkctr == &tmpstkctr)
4299 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004300 }
4301 return 1;
4302}
4303
4304/* set <smp> to the number of active trackers on the SC entry in the stream's
4305 * tracked frontend counters. Supports being called as "sc[0-9]_trackers" only.
4306 */
4307static int
4308smp_fetch_sc_trackers(const struct arg *args, struct sample *smp, const char *kw, void *private)
4309{
Emeric Brun819fc6f2017-06-13 19:37:32 +02004310 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01004311 struct stkctr *stkctr;
4312
Emeric Brun819fc6f2017-06-13 19:37:32 +02004313 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01004314 if (!stkctr)
4315 return 0;
4316
4317 smp->flags = SMP_F_VOL_TEST;
4318 smp->data.type = SMP_T_SINT;
Emeric Brun819fc6f2017-06-13 19:37:32 +02004319 if (stkctr == &tmpstkctr) {
4320 smp->data.u.sint = stkctr_entry(stkctr) ? (stkctr_entry(stkctr)->ref_cnt-1) : 0;
4321 stktable_release(stkctr->table, stkctr_entry(stkctr));
4322 }
4323 else {
4324 smp->data.u.sint = stkctr_entry(stkctr) ? stkctr_entry(stkctr)->ref_cnt : 0;
4325 }
4326
Willy Tarreau7d562212016-11-25 16:10:05 +01004327 return 1;
4328}
4329
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004330
4331/* The functions below are used to manipulate table contents from the CLI.
4332 * There are 3 main actions, "clear", "set" and "show". The code is shared
4333 * between all actions, and the action is encoded in the void *private in
4334 * the appctx as well as in the keyword registration, among one of the
4335 * following values.
4336 */
4337
4338enum {
4339 STK_CLI_ACT_CLR,
4340 STK_CLI_ACT_SET,
4341 STK_CLI_ACT_SHOW,
4342};
4343
Willy Tarreau4596fe22022-05-17 19:07:51 +02004344/* Dump the status of a table to a stream connector's
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004345 * read buffer. It returns 0 if the output buffer is full
4346 * and needs to be called again, otherwise non-zero.
4347 */
Willy Tarreau83061a82018-07-13 11:56:34 +02004348static int table_dump_head_to_buffer(struct buffer *msg,
Willy Tarreaud0a06d52022-05-18 15:07:19 +02004349 struct appctx *appctx,
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004350 struct stktable *t, struct stktable *target)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004351{
Willy Tarreauc12b3212022-05-27 11:08:15 +02004352 struct stream *s = __sc_strm(appctx_sc(appctx));
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004353
4354 chunk_appendf(msg, "# table: %s, type: %s, size:%d, used:%d\n",
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004355 t->id, stktable_types[t->type].kw, t->size, t->current);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004356
4357 /* any other information should be dumped here */
4358
William Lallemand07a62f72017-05-24 00:57:40 +02004359 if (target && (strm_li(s)->bind_conf->level & ACCESS_LVL_MASK) < ACCESS_LVL_OPER)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004360 chunk_appendf(msg, "# contents not dumped due to insufficient privileges\n");
4361
Willy Tarreaud0a06d52022-05-18 15:07:19 +02004362 if (applet_putchk(appctx, msg) == -1)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004363 return 0;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004364
4365 return 1;
4366}
4367
Willy Tarreau4596fe22022-05-17 19:07:51 +02004368/* Dump a table entry to a stream connector's
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004369 * read buffer. It returns 0 if the output buffer is full
4370 * and needs to be called again, otherwise non-zero.
4371 */
Willy Tarreau83061a82018-07-13 11:56:34 +02004372static int table_dump_entry_to_buffer(struct buffer *msg,
Willy Tarreaud0a06d52022-05-18 15:07:19 +02004373 struct appctx *appctx,
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004374 struct stktable *t, struct stksess *entry)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004375{
4376 int dt;
4377
4378 chunk_appendf(msg, "%p:", entry);
4379
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004380 if (t->type == SMP_T_IPV4) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004381 char addr[INET_ADDRSTRLEN];
4382 inet_ntop(AF_INET, (const void *)&entry->key.key, addr, sizeof(addr));
4383 chunk_appendf(msg, " key=%s", addr);
4384 }
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004385 else if (t->type == SMP_T_IPV6) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004386 char addr[INET6_ADDRSTRLEN];
4387 inet_ntop(AF_INET6, (const void *)&entry->key.key, addr, sizeof(addr));
4388 chunk_appendf(msg, " key=%s", addr);
4389 }
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004390 else if (t->type == SMP_T_SINT) {
Willy Tarreau6cde5d82020-02-25 09:41:22 +01004391 chunk_appendf(msg, " key=%u", read_u32(entry->key.key));
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004392 }
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004393 else if (t->type == SMP_T_STR) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004394 chunk_appendf(msg, " key=");
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004395 dump_text(msg, (const char *)entry->key.key, t->key_size);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004396 }
4397 else {
4398 chunk_appendf(msg, " key=");
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004399 dump_binary(msg, (const char *)entry->key.key, t->key_size);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004400 }
4401
4402 chunk_appendf(msg, " use=%d exp=%d", entry->ref_cnt - 1, tick_remain(now_ms, entry->expire));
4403
4404 for (dt = 0; dt < STKTABLE_DATA_TYPES; dt++) {
4405 void *ptr;
4406
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004407 if (t->data_ofs[dt] == 0)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004408 continue;
Emeric Brunc64a2a32021-06-30 18:01:02 +02004409 if (stktable_data_types[dt].is_array) {
4410 char tmp[16] = {};
4411 const char *name_pfx = stktable_data_types[dt].name;
4412 const char *name_sfx = NULL;
4413 unsigned int idx = 0;
4414 int i = 0;
4415
4416 /* split name to show index before first _ of the name
4417 * for example: 'gpc3_rate' if array name is 'gpc_rate'.
4418 */
4419 for (i = 0 ; i < (sizeof(tmp) - 1); i++) {
4420 if (!name_pfx[i])
4421 break;
4422 if (name_pfx[i] == '_') {
4423 name_pfx = &tmp[0];
4424 name_sfx = &stktable_data_types[dt].name[i];
4425 break;
4426 }
4427 tmp[i] = name_pfx[i];
4428 }
4429
4430 ptr = stktable_data_ptr_idx(t, entry, dt, idx);
4431 while (ptr) {
4432 if (stktable_data_types[dt].arg_type == ARG_T_DELAY)
4433 chunk_appendf(msg, " %s%u%s(%u)=", name_pfx, idx, name_sfx ? name_sfx : "", t->data_arg[dt].u);
4434 else
4435 chunk_appendf(msg, " %s%u%s=", name_pfx, idx, name_sfx ? name_sfx : "");
4436 switch (stktable_data_types[dt].std_type) {
4437 case STD_T_SINT:
4438 chunk_appendf(msg, "%d", stktable_data_cast(ptr, std_t_sint));
4439 break;
4440 case STD_T_UINT:
4441 chunk_appendf(msg, "%u", stktable_data_cast(ptr, std_t_uint));
4442 break;
4443 case STD_T_ULL:
4444 chunk_appendf(msg, "%llu", stktable_data_cast(ptr, std_t_ull));
4445 break;
4446 case STD_T_FRQP:
4447 chunk_appendf(msg, "%u",
4448 read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
4449 t->data_arg[dt].u));
4450 break;
4451 }
4452 ptr = stktable_data_ptr_idx(t, entry, dt, ++idx);
4453 }
4454 continue;
4455 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004456 if (stktable_data_types[dt].arg_type == ARG_T_DELAY)
Emeric Brun01928ae2021-06-30 16:24:04 +02004457 chunk_appendf(msg, " %s(%u)=", stktable_data_types[dt].name, t->data_arg[dt].u);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004458 else
4459 chunk_appendf(msg, " %s=", stktable_data_types[dt].name);
4460
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004461 ptr = stktable_data_ptr(t, entry, dt);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004462 switch (stktable_data_types[dt].std_type) {
4463 case STD_T_SINT:
4464 chunk_appendf(msg, "%d", stktable_data_cast(ptr, std_t_sint));
4465 break;
4466 case STD_T_UINT:
4467 chunk_appendf(msg, "%u", stktable_data_cast(ptr, std_t_uint));
4468 break;
4469 case STD_T_ULL:
Emeric Brun01928ae2021-06-30 16:24:04 +02004470 chunk_appendf(msg, "%llu", stktable_data_cast(ptr, std_t_ull));
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004471 break;
4472 case STD_T_FRQP:
Emeric Brun01928ae2021-06-30 16:24:04 +02004473 chunk_appendf(msg, "%u",
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004474 read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004475 t->data_arg[dt].u));
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004476 break;
Frédéric Lécaille16b4f542019-05-23 12:15:04 +02004477 case STD_T_DICT: {
4478 struct dict_entry *de;
4479 de = stktable_data_cast(ptr, std_t_dict);
4480 chunk_appendf(msg, "%s", de ? (char *)de->value.key : "-");
4481 break;
4482 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004483 }
4484 }
4485 chunk_appendf(msg, "\n");
4486
Willy Tarreaud0a06d52022-05-18 15:07:19 +02004487 if (applet_putchk(appctx, msg) == -1)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004488 return 0;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004489
4490 return 1;
4491}
4492
Willy Tarreau3c69e082022-05-03 11:35:07 +02004493/* appctx context used by the "show table" command */
4494struct show_table_ctx {
4495 void *target; /* table we want to dump, or NULL for all */
4496 struct stktable *t; /* table being currently dumped (first if NULL) */
4497 struct stksess *entry; /* last entry we were trying to dump (or first if NULL) */
4498 long long value[STKTABLE_FILTER_LEN]; /* value to compare against */
4499 signed char data_type[STKTABLE_FILTER_LEN]; /* type of data to compare, or -1 if none */
4500 signed char data_op[STKTABLE_FILTER_LEN]; /* operator (STD_OP_*) when data_type set */
Willy Tarreau7849d4c2022-05-03 11:45:02 +02004501 enum {
Willy Tarreau0f154ed2022-05-03 12:02:36 +02004502 STATE_NEXT = 0, /* px points to next table, entry=NULL */
Willy Tarreau7849d4c2022-05-03 11:45:02 +02004503 STATE_DUMP, /* px points to curr table, entry is valid, refcount held */
4504 STATE_DONE, /* done dumping */
4505 } state;
Willy Tarreau3c69e082022-05-03 11:35:07 +02004506 char action; /* action on the table : one of STK_CLI_ACT_* */
4507};
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004508
4509/* Processes a single table entry matching a specific key passed in argument.
4510 * returns 0 if wants to be called again, 1 if has ended processing.
4511 */
4512static int table_process_entry_per_key(struct appctx *appctx, char **args)
4513{
Willy Tarreau3c69e082022-05-03 11:35:07 +02004514 struct show_table_ctx *ctx = appctx->svcctx;
4515 struct stktable *t = ctx->target;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004516 struct stksess *ts;
4517 uint32_t uint32_key;
4518 unsigned char ip6_key[sizeof(struct in6_addr)];
4519 long long value;
4520 int data_type;
4521 int cur_arg;
4522 void *ptr;
Willy Tarreaufa1258f2021-04-10 23:00:53 +02004523 struct freq_ctr *frqp;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004524
Willy Tarreau9d008692019-08-09 11:21:01 +02004525 if (!*args[4])
4526 return cli_err(appctx, "Key value expected\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004527
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004528 switch (t->type) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004529 case SMP_T_IPV4:
4530 uint32_key = htonl(inetaddr_host(args[4]));
Christopher Fauletca20d022017-08-29 15:30:31 +02004531 static_table_key.key = &uint32_key;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004532 break;
4533 case SMP_T_IPV6:
Christopher Fauletb7c962b2021-11-15 09:17:25 +01004534 if (inet_pton(AF_INET6, args[4], ip6_key) <= 0)
4535 return cli_err(appctx, "Invalid key\n");
Christopher Fauletca20d022017-08-29 15:30:31 +02004536 static_table_key.key = &ip6_key;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004537 break;
4538 case SMP_T_SINT:
4539 {
4540 char *endptr;
4541 unsigned long val;
4542 errno = 0;
4543 val = strtoul(args[4], &endptr, 10);
4544 if ((errno == ERANGE && val == ULONG_MAX) ||
4545 (errno != 0 && val == 0) || endptr == args[4] ||
Willy Tarreau9d008692019-08-09 11:21:01 +02004546 val > 0xffffffff)
4547 return cli_err(appctx, "Invalid key\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004548 uint32_key = (uint32_t) val;
Christopher Fauletca20d022017-08-29 15:30:31 +02004549 static_table_key.key = &uint32_key;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004550 break;
4551 }
4552 break;
4553 case SMP_T_STR:
Christopher Fauletca20d022017-08-29 15:30:31 +02004554 static_table_key.key = args[4];
4555 static_table_key.key_len = strlen(args[4]);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004556 break;
4557 default:
Willy Tarreau3c69e082022-05-03 11:35:07 +02004558 switch (ctx->action) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004559 case STK_CLI_ACT_SHOW:
Willy Tarreau9d008692019-08-09 11:21:01 +02004560 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 +01004561 case STK_CLI_ACT_CLR:
Willy Tarreau9d008692019-08-09 11:21:01 +02004562 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 +01004563 case STK_CLI_ACT_SET:
Willy Tarreau9d008692019-08-09 11:21:01 +02004564 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 +01004565 default:
Willy Tarreau9d008692019-08-09 11:21:01 +02004566 return cli_err(appctx, "Unknown action\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004567 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004568 }
4569
4570 /* check permissions */
4571 if (!cli_has_level(appctx, ACCESS_LVL_OPER))
4572 return 1;
4573
Willy Tarreau3c69e082022-05-03 11:35:07 +02004574 switch (ctx->action) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004575 case STK_CLI_ACT_SHOW:
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004576 ts = stktable_lookup_key(t, &static_table_key);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004577 if (!ts)
4578 return 1;
4579 chunk_reset(&trash);
Willy Tarreaud0a06d52022-05-18 15:07:19 +02004580 if (!table_dump_head_to_buffer(&trash, appctx, t, t)) {
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004581 stktable_release(t, ts);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004582 return 0;
Emeric Brun819fc6f2017-06-13 19:37:32 +02004583 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004584 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &ts->lock);
Willy Tarreaud0a06d52022-05-18 15:07:19 +02004585 if (!table_dump_entry_to_buffer(&trash, appctx, t, ts)) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004586 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004587 stktable_release(t, ts);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004588 return 0;
Emeric Brun819fc6f2017-06-13 19:37:32 +02004589 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004590 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004591 stktable_release(t, ts);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004592 break;
4593
4594 case STK_CLI_ACT_CLR:
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004595 ts = stktable_lookup_key(t, &static_table_key);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004596 if (!ts)
4597 return 1;
Emeric Brun819fc6f2017-06-13 19:37:32 +02004598
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004599 if (!stksess_kill(t, ts, 1)) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004600 /* don't delete an entry which is currently referenced */
Willy Tarreau9d008692019-08-09 11:21:01 +02004601 return cli_err(appctx, "Entry currently in use, cannot remove\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004602 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004603 break;
4604
4605 case STK_CLI_ACT_SET:
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004606 ts = stktable_get_entry(t, &static_table_key);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004607 if (!ts) {
4608 /* don't delete an entry which is currently referenced */
Willy Tarreau9d008692019-08-09 11:21:01 +02004609 return cli_err(appctx, "Unable to allocate a new entry\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004610 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004611 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004612 for (cur_arg = 5; *args[cur_arg]; cur_arg += 2) {
4613 if (strncmp(args[cur_arg], "data.", 5) != 0) {
Willy Tarreau9d008692019-08-09 11:21:01 +02004614 cli_err(appctx, "\"data.<type>\" followed by a value expected\n");
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004615 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004616 stktable_touch_local(t, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004617 return 1;
4618 }
4619
4620 data_type = stktable_get_data_type(args[cur_arg] + 5);
4621 if (data_type < 0) {
Willy Tarreau9d008692019-08-09 11:21:01 +02004622 cli_err(appctx, "Unknown data type\n");
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004623 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004624 stktable_touch_local(t, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004625 return 1;
4626 }
4627
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004628 if (!t->data_ofs[data_type]) {
Willy Tarreau9d008692019-08-09 11:21:01 +02004629 cli_err(appctx, "Data type not stored in this table\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 if (!*args[cur_arg+1] || strl2llrc(args[cur_arg+1], strlen(args[cur_arg+1]), &value) != 0) {
Willy Tarreau9d008692019-08-09 11:21:01 +02004636 cli_err(appctx, "Require a valid integer value to store\n");
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004637 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004638 stktable_touch_local(t, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004639 return 1;
4640 }
4641
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004642 ptr = stktable_data_ptr(t, ts, data_type);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004643
4644 switch (stktable_data_types[data_type].std_type) {
4645 case STD_T_SINT:
4646 stktable_data_cast(ptr, std_t_sint) = value;
4647 break;
4648 case STD_T_UINT:
4649 stktable_data_cast(ptr, std_t_uint) = value;
4650 break;
4651 case STD_T_ULL:
4652 stktable_data_cast(ptr, std_t_ull) = value;
4653 break;
4654 case STD_T_FRQP:
4655 /* We set both the current and previous values. That way
4656 * the reported frequency is stable during all the period
4657 * then slowly fades out. This allows external tools to
4658 * push measures without having to update them too often.
4659 */
4660 frqp = &stktable_data_cast(ptr, std_t_frqp);
Willy Tarreaufa1258f2021-04-10 23:00:53 +02004661 /* First bit is reserved for the freq_ctr lock
Emeric Brunf2fc1fd2017-11-02 17:32:43 +01004662 Note: here we're still protected by the stksess lock
Willy Tarreaufa1258f2021-04-10 23:00:53 +02004663 so we don't need to update the update the freq_ctr
Emeric Brunf2fc1fd2017-11-02 17:32:43 +01004664 using its internal lock */
4665 frqp->curr_tick = now_ms & ~0x1;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004666 frqp->prev_ctr = 0;
4667 frqp->curr_ctr = value;
4668 break;
4669 }
4670 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004671 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004672 stktable_touch_local(t, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004673 break;
4674
4675 default:
Willy Tarreau9d008692019-08-09 11:21:01 +02004676 return cli_err(appctx, "Unknown action\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004677 }
4678 return 1;
4679}
4680
4681/* Prepares the appctx fields with the data-based filters from the command line.
4682 * Returns 0 if the dump can proceed, 1 if has ended processing.
4683 */
4684static int table_prepare_data_request(struct appctx *appctx, char **args)
4685{
Willy Tarreau3c69e082022-05-03 11:35:07 +02004686 struct show_table_ctx *ctx = appctx->svcctx;
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004687 int i;
Adis Nezirovicd0142e72020-01-22 16:50:27 +01004688 char *err = NULL;
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004689
Willy Tarreau3c69e082022-05-03 11:35:07 +02004690 if (ctx->action != STK_CLI_ACT_SHOW && ctx->action != STK_CLI_ACT_CLR)
Willy Tarreau9d008692019-08-09 11:21:01 +02004691 return cli_err(appctx, "content-based lookup is only supported with the \"show\" and \"clear\" actions\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004692
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004693 for (i = 0; i < STKTABLE_FILTER_LEN; i++) {
4694 if (i > 0 && !*args[3+3*i]) // number of filter entries can be less than STKTABLE_FILTER_LEN
4695 break;
4696 /* condition on stored data value */
Willy Tarreau3c69e082022-05-03 11:35:07 +02004697 ctx->data_type[i] = stktable_get_data_type(args[3+3*i] + 5);
4698 if (ctx->data_type[i] < 0)
Adis Nezirovicd0142e72020-01-22 16:50:27 +01004699 return cli_dynerr(appctx, memprintf(&err, "Filter entry #%i: Unknown data type\n", i + 1));
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004700
Willy Tarreau3c69e082022-05-03 11:35:07 +02004701 if (!((struct stktable *)ctx->target)->data_ofs[ctx->data_type[i]])
Adis Nezirovicd0142e72020-01-22 16:50:27 +01004702 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 +01004703
Willy Tarreau3c69e082022-05-03 11:35:07 +02004704 ctx->data_op[i] = get_std_op(args[4+3*i]);
4705 if (ctx->data_op[i] < 0)
Adis Nezirovicd0142e72020-01-22 16:50:27 +01004706 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 +01004707
Willy Tarreau3c69e082022-05-03 11:35:07 +02004708 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 +01004709 return cli_dynerr(appctx, memprintf(&err, "Filter entry #%i: Require a valid integer value to compare against\n", i + 1));
4710 }
4711
4712 if (*args[3+3*i]) {
4713 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 +01004714 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004715
4716 /* OK we're done, all the fields are set */
4717 return 0;
4718}
4719
4720/* returns 0 if wants to be called, 1 if has ended processing */
Aurélien Nephtaliabbf6072018-04-18 13:26:46 +02004721static int cli_parse_table_req(char **args, char *payload, struct appctx *appctx, void *private)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004722{
Willy Tarreau3c69e082022-05-03 11:35:07 +02004723 struct show_table_ctx *ctx = applet_reserve_svcctx(appctx, sizeof(*ctx));
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004724 int i;
4725
4726 for (i = 0; i < STKTABLE_FILTER_LEN; i++)
Willy Tarreau3c69e082022-05-03 11:35:07 +02004727 ctx->data_type[i] = -1;
4728 ctx->target = NULL;
4729 ctx->entry = NULL;
4730 ctx->action = (long)private; // keyword argument, one of STK_CLI_ACT_*
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004731
4732 if (*args[2]) {
Willy Tarreau0f154ed2022-05-03 12:02:36 +02004733 ctx->t = ctx->target = stktable_find_by_name(args[2]);
Willy Tarreau3c69e082022-05-03 11:35:07 +02004734 if (!ctx->target)
Willy Tarreau9d008692019-08-09 11:21:01 +02004735 return cli_err(appctx, "No such table\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004736 }
4737 else {
Willy Tarreau0f154ed2022-05-03 12:02:36 +02004738 ctx->t = stktables_list;
Willy Tarreau3c69e082022-05-03 11:35:07 +02004739 if (ctx->action != STK_CLI_ACT_SHOW)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004740 goto err_args;
4741 return 0;
4742 }
4743
4744 if (strcmp(args[3], "key") == 0)
4745 return table_process_entry_per_key(appctx, args);
4746 else if (strncmp(args[3], "data.", 5) == 0)
4747 return table_prepare_data_request(appctx, args);
4748 else if (*args[3])
4749 goto err_args;
4750
4751 return 0;
4752
4753err_args:
Willy Tarreau3c69e082022-05-03 11:35:07 +02004754 switch (ctx->action) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004755 case STK_CLI_ACT_SHOW:
Willy Tarreau9d008692019-08-09 11:21:01 +02004756 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 +01004757 case STK_CLI_ACT_CLR:
Willy Tarreau9d008692019-08-09 11:21:01 +02004758 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 +01004759 case STK_CLI_ACT_SET:
Willy Tarreau9d008692019-08-09 11:21:01 +02004760 return cli_err(appctx, "Required arguments: <table> key <key> [data.<store_data_type> <value>]*\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004761 default:
Willy Tarreau9d008692019-08-09 11:21:01 +02004762 return cli_err(appctx, "Unknown action\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004763 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004764}
4765
4766/* This function is used to deal with table operations (dump or clear depending
4767 * on the action stored in appctx->private). It returns 0 if the output buffer is
4768 * full and it needs to be called again, otherwise non-zero.
4769 */
4770static int cli_io_handler_table(struct appctx *appctx)
4771{
Willy Tarreau3c69e082022-05-03 11:35:07 +02004772 struct show_table_ctx *ctx = appctx->svcctx;
Willy Tarreauc12b3212022-05-27 11:08:15 +02004773 struct stconn *sc = appctx_sc(appctx);
Willy Tarreau475e4632022-05-27 10:26:46 +02004774 struct stream *s = __sc_strm(sc);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004775 struct ebmb_node *eb;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004776 int skip_entry;
Willy Tarreau3c69e082022-05-03 11:35:07 +02004777 int show = ctx->action == STK_CLI_ACT_SHOW;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004778
4779 /*
Willy Tarreau0f154ed2022-05-03 12:02:36 +02004780 * We have 3 possible states in ctx->state :
Willy Tarreau7849d4c2022-05-03 11:45:02 +02004781 * - STATE_NEXT : the proxy pointer points to the next table to
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004782 * dump, the entry pointer is NULL ;
Willy Tarreau7849d4c2022-05-03 11:45:02 +02004783 * - STATE_DUMP : the proxy pointer points to the current table
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004784 * and the entry pointer points to the next entry to be dumped,
4785 * and the refcount on the next entry is held ;
Willy Tarreau7849d4c2022-05-03 11:45:02 +02004786 * - STATE_DONE : nothing left to dump, the buffer may contain some
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004787 * data though.
4788 */
4789
Willy Tarreau475e4632022-05-27 10:26:46 +02004790 if (unlikely(sc_ic(sc)->flags & (CF_WRITE_ERROR|CF_SHUTW))) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004791 /* in case of abort, remove any refcount we might have set on an entry */
Willy Tarreau7849d4c2022-05-03 11:45:02 +02004792 if (ctx->state == STATE_DUMP) {
Willy Tarreau3c69e082022-05-03 11:35:07 +02004793 stksess_kill_if_expired(ctx->t, ctx->entry, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004794 }
4795 return 1;
4796 }
4797
4798 chunk_reset(&trash);
4799
Willy Tarreau7849d4c2022-05-03 11:45:02 +02004800 while (ctx->state != STATE_DONE) {
4801 switch (ctx->state) {
Willy Tarreau7849d4c2022-05-03 11:45:02 +02004802 case STATE_NEXT:
Willy Tarreau3c69e082022-05-03 11:35:07 +02004803 if (!ctx->t ||
4804 (ctx->target &&
4805 ctx->t != ctx->target)) {
Willy Tarreau7849d4c2022-05-03 11:45:02 +02004806 ctx->state = STATE_DONE;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004807 break;
4808 }
4809
Willy Tarreau3c69e082022-05-03 11:35:07 +02004810 if (ctx->t->size) {
Willy Tarreaud0a06d52022-05-18 15:07:19 +02004811 if (show && !table_dump_head_to_buffer(&trash, appctx, ctx->t, ctx->target))
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004812 return 0;
4813
Willy Tarreau3c69e082022-05-03 11:35:07 +02004814 if (ctx->target &&
William Lallemand07a62f72017-05-24 00:57:40 +02004815 (strm_li(s)->bind_conf->level & ACCESS_LVL_MASK) >= ACCESS_LVL_OPER) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004816 /* dump entries only if table explicitly requested */
Willy Tarreau76642222022-10-11 12:02:50 +02004817 HA_RWLOCK_WRLOCK(STK_TABLE_LOCK, &ctx->t->lock);
Willy Tarreau3c69e082022-05-03 11:35:07 +02004818 eb = ebmb_first(&ctx->t->keys);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004819 if (eb) {
Willy Tarreau3c69e082022-05-03 11:35:07 +02004820 ctx->entry = ebmb_entry(eb, struct stksess, key);
4821 ctx->entry->ref_cnt++;
Willy Tarreau7849d4c2022-05-03 11:45:02 +02004822 ctx->state = STATE_DUMP;
Willy Tarreau76642222022-10-11 12:02:50 +02004823 HA_RWLOCK_WRUNLOCK(STK_TABLE_LOCK, &ctx->t->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004824 break;
4825 }
Willy Tarreau76642222022-10-11 12:02:50 +02004826 HA_RWLOCK_WRUNLOCK(STK_TABLE_LOCK, &ctx->t->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004827 }
4828 }
Willy Tarreau3c69e082022-05-03 11:35:07 +02004829 ctx->t = ctx->t->next;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004830 break;
4831
Willy Tarreau7849d4c2022-05-03 11:45:02 +02004832 case STATE_DUMP:
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004833 skip_entry = 0;
4834
Willy Tarreau3c69e082022-05-03 11:35:07 +02004835 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &ctx->entry->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004836
Willy Tarreau3c69e082022-05-03 11:35:07 +02004837 if (ctx->data_type[0] >= 0) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004838 /* we're filtering on some data contents */
4839 void *ptr;
Willy Tarreau2b64a352020-01-22 17:09:47 +01004840 int dt, i;
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004841 signed char op;
4842 long long data, value;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004843
Emeric Brun819fc6f2017-06-13 19:37:32 +02004844
Willy Tarreau2b64a352020-01-22 17:09:47 +01004845 for (i = 0; i < STKTABLE_FILTER_LEN; i++) {
Willy Tarreau3c69e082022-05-03 11:35:07 +02004846 if (ctx->data_type[i] == -1)
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004847 break;
Willy Tarreau3c69e082022-05-03 11:35:07 +02004848 dt = ctx->data_type[i];
4849 ptr = stktable_data_ptr(ctx->t,
4850 ctx->entry,
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004851 dt);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004852
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004853 data = 0;
4854 switch (stktable_data_types[dt].std_type) {
4855 case STD_T_SINT:
4856 data = stktable_data_cast(ptr, std_t_sint);
4857 break;
4858 case STD_T_UINT:
4859 data = stktable_data_cast(ptr, std_t_uint);
4860 break;
4861 case STD_T_ULL:
4862 data = stktable_data_cast(ptr, std_t_ull);
4863 break;
4864 case STD_T_FRQP:
4865 data = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Willy Tarreau3c69e082022-05-03 11:35:07 +02004866 ctx->t->data_arg[dt].u);
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004867 break;
4868 }
4869
Willy Tarreau3c69e082022-05-03 11:35:07 +02004870 op = ctx->data_op[i];
4871 value = ctx->value[i];
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004872
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004873 /* skip the entry if the data does not match the test and the value */
4874 if ((data < value &&
4875 (op == STD_OP_EQ || op == STD_OP_GT || op == STD_OP_GE)) ||
4876 (data == value &&
4877 (op == STD_OP_NE || op == STD_OP_GT || op == STD_OP_LT)) ||
4878 (data > value &&
4879 (op == STD_OP_EQ || op == STD_OP_LT || op == STD_OP_LE))) {
4880 skip_entry = 1;
4881 break;
4882 }
4883 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004884 }
4885
4886 if (show && !skip_entry &&
Willy Tarreaud0a06d52022-05-18 15:07:19 +02004887 !table_dump_entry_to_buffer(&trash, appctx, ctx->t, ctx->entry)) {
Willy Tarreau3c69e082022-05-03 11:35:07 +02004888 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &ctx->entry->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004889 return 0;
4890 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004891
Willy Tarreau3c69e082022-05-03 11:35:07 +02004892 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &ctx->entry->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004893
Willy Tarreau76642222022-10-11 12:02:50 +02004894 HA_RWLOCK_WRLOCK(STK_TABLE_LOCK, &ctx->t->lock);
Willy Tarreau3c69e082022-05-03 11:35:07 +02004895 ctx->entry->ref_cnt--;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004896
Willy Tarreau3c69e082022-05-03 11:35:07 +02004897 eb = ebmb_next(&ctx->entry->key);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004898 if (eb) {
Willy Tarreau3c69e082022-05-03 11:35:07 +02004899 struct stksess *old = ctx->entry;
4900 ctx->entry = ebmb_entry(eb, struct stksess, key);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004901 if (show)
Willy Tarreau3c69e082022-05-03 11:35:07 +02004902 __stksess_kill_if_expired(ctx->t, old);
4903 else if (!skip_entry && !ctx->entry->ref_cnt)
4904 __stksess_kill(ctx->t, old);
4905 ctx->entry->ref_cnt++;
Willy Tarreau76642222022-10-11 12:02:50 +02004906 HA_RWLOCK_WRUNLOCK(STK_TABLE_LOCK, &ctx->t->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004907 break;
4908 }
4909
4910
4911 if (show)
Willy Tarreau3c69e082022-05-03 11:35:07 +02004912 __stksess_kill_if_expired(ctx->t, ctx->entry);
4913 else if (!skip_entry && !ctx->entry->ref_cnt)
4914 __stksess_kill(ctx->t, ctx->entry);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004915
Willy Tarreau76642222022-10-11 12:02:50 +02004916 HA_RWLOCK_WRUNLOCK(STK_TABLE_LOCK, &ctx->t->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004917
Willy Tarreau3c69e082022-05-03 11:35:07 +02004918 ctx->t = ctx->t->next;
Willy Tarreau7849d4c2022-05-03 11:45:02 +02004919 ctx->state = STATE_NEXT;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004920 break;
4921
Willy Tarreau7849d4c2022-05-03 11:45:02 +02004922 default:
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004923 break;
4924 }
4925 }
4926 return 1;
4927}
4928
4929static void cli_release_show_table(struct appctx *appctx)
4930{
Willy Tarreau3c69e082022-05-03 11:35:07 +02004931 struct show_table_ctx *ctx = appctx->svcctx;
4932
Willy Tarreau7849d4c2022-05-03 11:45:02 +02004933 if (ctx->state == STATE_DUMP) {
Willy Tarreau3c69e082022-05-03 11:35:07 +02004934 stksess_kill_if_expired(ctx->t, ctx->entry, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004935 }
4936}
4937
Willy Tarreau478331d2020-08-28 11:31:31 +02004938static void stkt_late_init(void)
4939{
4940 struct sample_fetch *f;
4941
4942 f = find_sample_fetch("src", strlen("src"));
4943 if (f)
4944 smp_fetch_src = f->process;
4945}
4946
4947INITCALL0(STG_INIT, stkt_late_init);
4948
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004949/* register cli keywords */
4950static struct cli_kw_list cli_kws = {{ },{
Willy Tarreaub205bfd2021-05-07 11:38:37 +02004951 { { "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 },
4952 { { "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 },
4953 { { "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 +01004954 {{},}
4955}};
4956
Willy Tarreau0108d902018-11-25 19:14:37 +01004957INITCALL1(STG_REGISTER, cli_register_kw, &cli_kws);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004958
Thierry FOURNIER236657b2015-08-19 08:25:14 +02004959static struct action_kw_list tcp_conn_kws = { { }, {
Emeric Brun4d7ada82021-06-30 19:04:16 +02004960 { "sc-inc-gpc", parse_inc_gpc, KWF_MATCH_PREFIX },
4961 { "sc-inc-gpc0", parse_inc_gpc, KWF_MATCH_PREFIX },
4962 { "sc-inc-gpc1", parse_inc_gpc, KWF_MATCH_PREFIX },
Emeric Brun877b0b52021-06-30 18:57:49 +02004963 { "sc-set-gpt", parse_set_gpt, KWF_MATCH_PREFIX },
4964 { "sc-set-gpt0", parse_set_gpt, KWF_MATCH_PREFIX },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02004965 { /* END */ }
4966}};
4967
Willy Tarreau0108d902018-11-25 19:14:37 +01004968INITCALL1(STG_REGISTER, tcp_req_conn_keywords_register, &tcp_conn_kws);
4969
Willy Tarreau620408f2016-10-21 16:37:51 +02004970static struct action_kw_list tcp_sess_kws = { { }, {
Emeric Brun4d7ada82021-06-30 19:04:16 +02004971 { "sc-inc-gpc", parse_inc_gpc, KWF_MATCH_PREFIX },
4972 { "sc-inc-gpc0", parse_inc_gpc, KWF_MATCH_PREFIX },
4973 { "sc-inc-gpc1", parse_inc_gpc, KWF_MATCH_PREFIX },
Emeric Brun877b0b52021-06-30 18:57:49 +02004974 { "sc-set-gpt", parse_set_gpt, KWF_MATCH_PREFIX },
4975 { "sc-set-gpt0", parse_set_gpt, KWF_MATCH_PREFIX },
Willy Tarreau620408f2016-10-21 16:37:51 +02004976 { /* END */ }
4977}};
4978
Willy Tarreau0108d902018-11-25 19:14:37 +01004979INITCALL1(STG_REGISTER, tcp_req_sess_keywords_register, &tcp_sess_kws);
4980
Thierry FOURNIER236657b2015-08-19 08:25:14 +02004981static struct action_kw_list tcp_req_kws = { { }, {
Emeric Brun4d7ada82021-06-30 19:04:16 +02004982 { "sc-inc-gpc", parse_inc_gpc, KWF_MATCH_PREFIX },
4983 { "sc-inc-gpc0", parse_inc_gpc, KWF_MATCH_PREFIX },
4984 { "sc-inc-gpc1", parse_inc_gpc, KWF_MATCH_PREFIX },
Emeric Brun877b0b52021-06-30 18:57:49 +02004985 { "sc-set-gpt", parse_set_gpt, KWF_MATCH_PREFIX },
4986 { "sc-set-gpt0", parse_set_gpt, KWF_MATCH_PREFIX },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02004987 { /* END */ }
4988}};
4989
Willy Tarreau0108d902018-11-25 19:14:37 +01004990INITCALL1(STG_REGISTER, tcp_req_cont_keywords_register, &tcp_req_kws);
4991
Thierry FOURNIER236657b2015-08-19 08:25:14 +02004992static struct action_kw_list tcp_res_kws = { { }, {
Emeric Brun4d7ada82021-06-30 19:04:16 +02004993 { "sc-inc-gpc", parse_inc_gpc, KWF_MATCH_PREFIX },
4994 { "sc-inc-gpc0", parse_inc_gpc, KWF_MATCH_PREFIX },
4995 { "sc-inc-gpc1", parse_inc_gpc, KWF_MATCH_PREFIX },
Emeric Brun877b0b52021-06-30 18:57:49 +02004996 { "sc-set-gpt", parse_set_gpt, KWF_MATCH_PREFIX },
4997 { "sc-set-gpt0", parse_set_gpt, KWF_MATCH_PREFIX },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02004998 { /* END */ }
4999}};
5000
Willy Tarreau0108d902018-11-25 19:14:37 +01005001INITCALL1(STG_REGISTER, tcp_res_cont_keywords_register, &tcp_res_kws);
5002
Thierry FOURNIER236657b2015-08-19 08:25:14 +02005003static struct action_kw_list http_req_kws = { { }, {
Emeric Brun4d7ada82021-06-30 19:04:16 +02005004 { "sc-inc-gpc", parse_inc_gpc, KWF_MATCH_PREFIX },
5005 { "sc-inc-gpc0", parse_inc_gpc, KWF_MATCH_PREFIX },
5006 { "sc-inc-gpc1", parse_inc_gpc, KWF_MATCH_PREFIX },
Emeric Brun877b0b52021-06-30 18:57:49 +02005007 { "sc-set-gpt", parse_set_gpt, KWF_MATCH_PREFIX },
5008 { "sc-set-gpt0", parse_set_gpt, KWF_MATCH_PREFIX },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02005009 { /* END */ }
5010}};
5011
Willy Tarreau0108d902018-11-25 19:14:37 +01005012INITCALL1(STG_REGISTER, http_req_keywords_register, &http_req_kws);
5013
Thierry FOURNIER236657b2015-08-19 08:25:14 +02005014static struct action_kw_list http_res_kws = { { }, {
Emeric Brun4d7ada82021-06-30 19:04:16 +02005015 { "sc-inc-gpc", parse_inc_gpc, KWF_MATCH_PREFIX },
5016 { "sc-inc-gpc0", parse_inc_gpc, KWF_MATCH_PREFIX },
5017 { "sc-inc-gpc1", parse_inc_gpc, KWF_MATCH_PREFIX },
Emeric Brun877b0b52021-06-30 18:57:49 +02005018 { "sc-set-gpt", parse_set_gpt, KWF_MATCH_PREFIX },
5019 { "sc-set-gpt0", parse_set_gpt, KWF_MATCH_PREFIX },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02005020 { /* END */ }
5021}};
5022
Willy Tarreau0108d902018-11-25 19:14:37 +01005023INITCALL1(STG_REGISTER, http_res_keywords_register, &http_res_kws);
5024
Willy Tarreau7d562212016-11-25 16:10:05 +01005025/* Note: must not be declared <const> as its list will be overwritten.
5026 * Please take care of keeping this list alphabetically sorted.
5027 */
5028static struct sample_fetch_kw_list smp_fetch_keywords = {ILH, {
5029 { "sc_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5030 { "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 +02005031 { "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 +01005032 { "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 +01005033 { "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 +01005034 { "sc_conn_cnt", smp_fetch_sc_conn_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5035 { "sc_conn_cur", smp_fetch_sc_conn_cur, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5036 { "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 +02005037 { "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 +01005038 { "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 +02005039 { "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 +01005040 { "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 +01005041 { "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 +02005042 { "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 +01005043 { "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 +01005044 { "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 +01005045 { "sc_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5046 { "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 +01005047 { "sc_http_fail_cnt", smp_fetch_sc_http_fail_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5048 { "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 +01005049 { "sc_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5050 { "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 +02005051 { "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 +01005052 { "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 +01005053 { "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 +01005054 { "sc_kbytes_in", smp_fetch_sc_kbytes_in, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5055 { "sc_kbytes_out", smp_fetch_sc_kbytes_out, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5056 { "sc_sess_cnt", smp_fetch_sc_sess_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5057 { "sc_sess_rate", smp_fetch_sc_sess_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5058 { "sc_tracked", smp_fetch_sc_tracked, ARG2(1,SINT,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
5059 { "sc_trackers", smp_fetch_sc_trackers, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5060 { "sc0_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5061 { "sc0_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5062 { "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 +01005063 { "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 +01005064 { "sc0_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5065 { "sc0_conn_cur", smp_fetch_sc_conn_cur, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5066 { "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 +01005067 { "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 +01005068 { "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 +01005069 { "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 +01005070 { "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 +01005071 { "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 +01005072 { "sc0_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5073 { "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 +01005074 { "sc0_http_fail_cnt", smp_fetch_sc_http_fail_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5075 { "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 +01005076 { "sc0_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5077 { "sc0_http_req_rate", smp_fetch_sc_http_req_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5078 { "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 +01005079 { "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 +01005080 { "sc0_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5081 { "sc0_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5082 { "sc0_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5083 { "sc0_sess_rate", smp_fetch_sc_sess_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5084 { "sc0_tracked", smp_fetch_sc_tracked, ARG1(0,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
5085 { "sc0_trackers", smp_fetch_sc_trackers, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5086 { "sc1_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5087 { "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 +02005088 { "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 +01005089 { "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 +01005090 { "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 +01005091 { "sc1_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5092 { "sc1_conn_cur", smp_fetch_sc_conn_cur, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5093 { "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 +01005094 { "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 +01005095 { "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 +01005096 { "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 +01005097 { "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 +01005098 { "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 +01005099 { "sc1_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5100 { "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 +01005101 { "sc1_http_fail_cnt", smp_fetch_sc_http_fail_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5102 { "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 +01005103 { "sc1_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5104 { "sc1_http_req_rate", smp_fetch_sc_http_req_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5105 { "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 +01005106 { "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 +01005107 { "sc1_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5108 { "sc1_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5109 { "sc1_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5110 { "sc1_sess_rate", smp_fetch_sc_sess_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5111 { "sc1_tracked", smp_fetch_sc_tracked, ARG1(0,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
5112 { "sc1_trackers", smp_fetch_sc_trackers, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5113 { "sc2_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5114 { "sc2_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5115 { "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 +01005116 { "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 +01005117 { "sc2_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5118 { "sc2_conn_cur", smp_fetch_sc_conn_cur, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5119 { "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 +01005120 { "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 +01005121 { "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 +01005122 { "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 +01005123 { "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 +01005124 { "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 +01005125 { "sc2_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5126 { "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 +01005127 { "sc2_http_fail_cnt", smp_fetch_sc_http_fail_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5128 { "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 +01005129 { "sc2_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5130 { "sc2_http_req_rate", smp_fetch_sc_http_req_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5131 { "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 +01005132 { "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 +01005133 { "sc2_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5134 { "sc2_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5135 { "sc2_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5136 { "sc2_sess_rate", smp_fetch_sc_sess_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5137 { "sc2_tracked", smp_fetch_sc_tracked, ARG1(0,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
5138 { "sc2_trackers", smp_fetch_sc_trackers, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5139 { "src_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5140 { "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 +02005141 { "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 +01005142 { "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 +01005143 { "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 +01005144 { "src_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5145 { "src_conn_cur", smp_fetch_sc_conn_cur, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5146 { "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 +02005147 { "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 +01005148 { "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 +02005149 { "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 +01005150 { "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 +01005151 { "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 +02005152 { "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 +01005153 { "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 +01005154 { "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 +01005155 { "src_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5156 { "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 +01005157 { "src_http_fail_cnt", smp_fetch_sc_http_fail_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5158 { "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 +01005159 { "src_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5160 { "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 +02005161 { "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 +01005162 { "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 +01005163 { "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 +01005164 { "src_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5165 { "src_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5166 { "src_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5167 { "src_sess_rate", smp_fetch_sc_sess_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5168 { "src_updt_conn_cnt", smp_fetch_src_updt_conn_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5169 { "table_avl", smp_fetch_table_avl, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5170 { "table_cnt", smp_fetch_table_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5171 { /* END */ },
5172}};
5173
Willy Tarreau0108d902018-11-25 19:14:37 +01005174INITCALL1(STG_REGISTER, sample_register_fetches, &smp_fetch_keywords);
Willy Tarreau7d562212016-11-25 16:10:05 +01005175
Willy Tarreaud9f316a2014-07-10 14:03:38 +02005176/* Note: must not be declared <const> as its list will be overwritten */
5177static struct sample_conv_kw_list sample_conv_kws = {ILH, {
Willy Tarreau2d17db52016-05-25 17:16:38 +02005178 { "in_table", sample_conv_in_table, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_BOOL },
5179 { "table_bytes_in_rate", sample_conv_table_bytes_in_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5180 { "table_bytes_out_rate", sample_conv_table_bytes_out_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5181 { "table_conn_cnt", sample_conv_table_conn_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5182 { "table_conn_cur", sample_conv_table_conn_cur, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5183 { "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 +02005184 { "table_expire", sample_conv_table_expire, ARG2(1,TAB,SINT), NULL, SMP_T_ANY, SMP_T_SINT },
Emeric Brun877b0b52021-06-30 18:57:49 +02005185 { "table_gpt", sample_conv_table_gpt, ARG2(2,SINT,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
Willy Tarreau2d17db52016-05-25 17:16:38 +02005186 { "table_gpt0", sample_conv_table_gpt0, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
Emeric Brun4d7ada82021-06-30 19:04:16 +02005187 { "table_gpc", sample_conv_table_gpc, ARG2(2,SINT,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
Willy Tarreau2d17db52016-05-25 17:16:38 +02005188 { "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 +01005189 { "table_gpc1", sample_conv_table_gpc1, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
Emeric Brun4d7ada82021-06-30 19:04:16 +02005190 { "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 +02005191 { "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 +01005192 { "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 +02005193 { "table_http_err_cnt", sample_conv_table_http_err_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5194 { "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 +01005195 { "table_http_fail_cnt", sample_conv_table_http_fail_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5196 { "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 +02005197 { "table_http_req_cnt", sample_conv_table_http_req_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5198 { "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 +02005199 { "table_idle", sample_conv_table_idle, ARG2(1,TAB,SINT), NULL, SMP_T_ANY, SMP_T_SINT },
Willy Tarreau2d17db52016-05-25 17:16:38 +02005200 { "table_kbytes_in", sample_conv_table_kbytes_in, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5201 { "table_kbytes_out", sample_conv_table_kbytes_out, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5202 { "table_server_id", sample_conv_table_server_id, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5203 { "table_sess_cnt", sample_conv_table_sess_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5204 { "table_sess_rate", sample_conv_table_sess_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5205 { "table_trackers", sample_conv_table_trackers, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
Willy Tarreaud9f316a2014-07-10 14:03:38 +02005206 { /* END */ },
5207}};
5208
Willy Tarreau0108d902018-11-25 19:14:37 +01005209INITCALL1(STG_REGISTER, sample_register_convs, &sample_conv_kws);