blob: 3aaa6fd50a703fae7a09426af4a6480fe38b0927 [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 Tarreaub2551052020-06-09 09:07:15 +020022#include <haproxy/arg.h>
Willy Tarreau6be78492020-06-05 00:00:29 +020023#include <haproxy/cfgparse.h>
Willy Tarreau83487a82020-06-04 20:19:54 +020024#include <haproxy/cli.h>
Christopher Faulet908628c2022-03-25 16:43:49 +010025#include <haproxy/conn_stream.h>
26#include <haproxy/cs_utils.h>
Thayne McCombs92149f92020-11-20 01:28:26 -070027#include <haproxy/dict.h>
Willy Tarreau36979d92020-06-05 17:27:29 +020028#include <haproxy/errors.h>
Willy Tarreauf268ee82020-06-04 17:05:57 +020029#include <haproxy/global.h>
Willy Tarreauc761f842020-06-04 11:40:28 +020030#include <haproxy/http_rules.h>
Willy Tarreau853b2972020-05-27 18:01:47 +020031#include <haproxy/list.h>
Willy Tarreauaeed4a82020-06-04 22:01:04 +020032#include <haproxy/log.h>
Willy Tarreau6131d6a2020-06-02 16:48:09 +020033#include <haproxy/net_helper.h>
Willy Tarreau3c2a7c22020-06-04 18:38:21 +020034#include <haproxy/peers.h>
Willy Tarreaub2551052020-06-09 09:07:15 +020035#include <haproxy/pool.h>
36#include <haproxy/proto_tcp.h>
Willy Tarreaua264d962020-06-04 22:29:18 +020037#include <haproxy/proxy.h>
Willy Tarreaub2551052020-06-09 09:07:15 +020038#include <haproxy/sample.h>
Willy Tarreau2eec9b52020-06-04 19:58:55 +020039#include <haproxy/stats-t.h>
Willy Tarreaub2551052020-06-09 09:07:15 +020040#include <haproxy/stick_table.h>
Willy Tarreaudfd3de82020-06-04 23:46:14 +020041#include <haproxy/stream.h>
Willy Tarreaucea0e1b2020-06-04 17:25:40 +020042#include <haproxy/task.h>
Willy Tarreau8b550af2020-06-04 17:42:48 +020043#include <haproxy/tcp_rules.h>
Willy Tarreau9310f482021-10-06 16:18:40 +020044#include <haproxy/ticks.h>
Willy Tarreaub2551052020-06-09 09:07:15 +020045#include <haproxy/tools.h>
Emeric Brun3bd697e2010-01-04 15:23:48 +010046
Emeric Brun3bd697e2010-01-04 15:23:48 +010047
Willy Tarreau12785782012-04-27 21:37:17 +020048/* structure used to return a table key built from a sample */
Emeric Brun819fc6f2017-06-13 19:37:32 +020049static THREAD_LOCAL struct stktable_key static_table_key;
Willy Tarreau478331d2020-08-28 11:31:31 +020050static int (*smp_fetch_src)(const struct arg *, struct sample *, const char *, void *);
Willy Tarreauf0b38bf2010-06-06 13:22:23 +020051
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +010052struct stktable *stktables_list;
53struct eb_root stktable_by_name = EB_ROOT;
54
Olivier Houchard52dabbc2018-11-14 17:54:36 +010055#define round_ptr_size(i) (((i) + (sizeof(void *) - 1)) &~ (sizeof(void *) - 1))
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +010056
57/* This function inserts stktable <t> into the tree of known stick-table.
58 * The stick-table ID is used as the storing key so it must already have
59 * been initialized.
60 */
61void stktable_store_name(struct stktable *t)
62{
63 t->name.key = t->id;
64 ebis_insert(&stktable_by_name, &t->name);
65}
66
67struct stktable *stktable_find_by_name(const char *name)
68{
69 struct ebpt_node *node;
70 struct stktable *t;
71
72 node = ebis_lookup(&stktable_by_name, name);
73 if (node) {
74 t = container_of(node, struct stktable, name);
Tim Duesterhuse5ff1412021-01-02 22:31:53 +010075 if (strcmp(t->id, name) == 0)
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +010076 return t;
77 }
78
79 return NULL;
80}
81
Emeric Brun3bd697e2010-01-04 15:23:48 +010082/*
Willy Tarreauaea940e2010-06-06 11:56:36 +020083 * Free an allocated sticky session <ts>, and decrease sticky sessions counter
84 * in table <t>.
Emeric Brun3bd697e2010-01-04 15:23:48 +010085 */
Emeric Brun819fc6f2017-06-13 19:37:32 +020086void __stksess_free(struct stktable *t, struct stksess *ts)
Emeric Brun3bd697e2010-01-04 15:23:48 +010087{
88 t->current--;
Olivier Houchard52dabbc2018-11-14 17:54:36 +010089 pool_free(t->pool, (void *)ts - round_ptr_size(t->data_size));
Emeric Brun3bd697e2010-01-04 15:23:48 +010090}
91
92/*
Emeric Brun819fc6f2017-06-13 19:37:32 +020093 * Free an allocated sticky session <ts>, and decrease sticky sessions counter
94 * in table <t>.
95 * This function locks the table
96 */
97void stksess_free(struct stktable *t, struct stksess *ts)
98{
Thayne McCombs92149f92020-11-20 01:28:26 -070099 void *data;
100 data = stktable_data_ptr(t, ts, STKTABLE_DT_SERVER_KEY);
101 if (data) {
Emeric Brun0e3457b2021-06-30 17:18:28 +0200102 dict_entry_unref(&server_key_dict, stktable_data_cast(data, std_t_dict));
103 stktable_data_cast(data, std_t_dict) = NULL;
Thayne McCombs92149f92020-11-20 01:28:26 -0700104 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100105 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200106 __stksess_free(t, ts);
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100107 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200108}
109
110/*
Willy Tarreauf6efda12010-08-03 20:34:06 +0200111 * Kill an stksess (only if its ref_cnt is zero).
112 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200113int __stksess_kill(struct stktable *t, struct stksess *ts)
Willy Tarreauf6efda12010-08-03 20:34:06 +0200114{
115 if (ts->ref_cnt)
Emeric Brun819fc6f2017-06-13 19:37:32 +0200116 return 0;
Willy Tarreauf6efda12010-08-03 20:34:06 +0200117
118 eb32_delete(&ts->exp);
Emeric Brun85e77c72010-09-23 18:16:52 +0200119 eb32_delete(&ts->upd);
Willy Tarreauf6efda12010-08-03 20:34:06 +0200120 ebmb_delete(&ts->key);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200121 __stksess_free(t, ts);
122 return 1;
Willy Tarreauf6efda12010-08-03 20:34:06 +0200123}
124
125/*
Emeric Brun819fc6f2017-06-13 19:37:32 +0200126 * Decrease the refcount if decrefcnt is not 0.
127 * and try to kill the stksess
128 * This function locks the table
129 */
130int stksess_kill(struct stktable *t, struct stksess *ts, int decrefcnt)
131{
132 int ret;
133
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100134 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200135 if (decrefcnt)
136 ts->ref_cnt--;
137 ret = __stksess_kill(t, ts);
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100138 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200139
140 return ret;
141}
142
143/*
Willy Tarreauaea940e2010-06-06 11:56:36 +0200144 * Initialize or update the key in the sticky session <ts> present in table <t>
145 * from the value present in <key>.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100146 */
Willy Tarreau393379c2010-06-06 12:11:37 +0200147void stksess_setkey(struct stktable *t, struct stksess *ts, struct stktable_key *key)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100148{
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200149 if (t->type != SMP_T_STR)
Willy Tarreau86257dc2010-06-06 12:57:10 +0200150 memcpy(ts->key.key, key->key, t->key_size);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100151 else {
Willy Tarreau86257dc2010-06-06 12:57:10 +0200152 memcpy(ts->key.key, key->key, MIN(t->key_size - 1, key->key_len));
153 ts->key.key[MIN(t->key_size - 1, key->key_len)] = 0;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100154 }
155}
156
157
158/*
Willy Tarreau393379c2010-06-06 12:11:37 +0200159 * Init sticky session <ts> of table <t>. The data parts are cleared and <ts>
160 * is returned.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100161 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200162static struct stksess *__stksess_init(struct stktable *t, struct stksess * ts)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100163{
Willy Tarreau393379c2010-06-06 12:11:37 +0200164 memset((void *)ts - t->data_size, 0, t->data_size);
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200165 ts->ref_cnt = 0;
Willy Tarreau86257dc2010-06-06 12:57:10 +0200166 ts->key.node.leaf_p = NULL;
167 ts->exp.node.leaf_p = NULL;
Emeric Brun85e77c72010-09-23 18:16:52 +0200168 ts->upd.node.leaf_p = NULL;
Emeric Brun819fc6f2017-06-13 19:37:32 +0200169 ts->expire = tick_add(now_ms, MS_TO_TICKS(t->expire));
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100170 HA_RWLOCK_INIT(&ts->lock);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100171 return ts;
172}
173
174/*
Willy Tarreauaea940e2010-06-06 11:56:36 +0200175 * Trash oldest <to_batch> sticky sessions from table <t>
Willy Tarreaudfe79252020-11-03 17:47:41 +0100176 * Returns number of trashed sticky sessions. It may actually trash less
177 * than expected if finding these requires too long a search time (e.g.
178 * most of them have ts->ref_cnt>0).
Emeric Brun3bd697e2010-01-04 15:23:48 +0100179 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200180int __stktable_trash_oldest(struct stktable *t, int to_batch)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100181{
182 struct stksess *ts;
183 struct eb32_node *eb;
Willy Tarreaudfe79252020-11-03 17:47:41 +0100184 int max_search = to_batch * 2; // no more than 50% misses
Emeric Brun3bd697e2010-01-04 15:23:48 +0100185 int batched = 0;
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200186 int looped = 0;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100187
188 eb = eb32_lookup_ge(&t->exps, now_ms - TIMER_LOOK_BACK);
189
190 while (batched < to_batch) {
191
192 if (unlikely(!eb)) {
193 /* we might have reached the end of the tree, typically because
194 * <now_ms> is in the first half and we're first scanning the last
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200195 * half. Let's loop back to the beginning of the tree now if we
196 * have not yet visited it.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100197 */
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200198 if (looped)
199 break;
200 looped = 1;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100201 eb = eb32_first(&t->exps);
202 if (likely(!eb))
203 break;
204 }
205
Willy Tarreaudfe79252020-11-03 17:47:41 +0100206 if (--max_search < 0)
207 break;
208
Emeric Brun3bd697e2010-01-04 15:23:48 +0100209 /* timer looks expired, detach it from the queue */
Willy Tarreau86257dc2010-06-06 12:57:10 +0200210 ts = eb32_entry(eb, struct stksess, exp);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100211 eb = eb32_next(eb);
212
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200213 /* don't delete an entry which is currently referenced */
214 if (ts->ref_cnt)
215 continue;
216
Willy Tarreau86257dc2010-06-06 12:57:10 +0200217 eb32_delete(&ts->exp);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100218
Willy Tarreau86257dc2010-06-06 12:57:10 +0200219 if (ts->expire != ts->exp.key) {
Emeric Brun3bd697e2010-01-04 15:23:48 +0100220 if (!tick_isset(ts->expire))
221 continue;
222
Willy Tarreau86257dc2010-06-06 12:57:10 +0200223 ts->exp.key = ts->expire;
224 eb32_insert(&t->exps, &ts->exp);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100225
Willy Tarreau86257dc2010-06-06 12:57:10 +0200226 if (!eb || eb->key > ts->exp.key)
227 eb = &ts->exp;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100228
229 continue;
230 }
Emeric Brun3bd697e2010-01-04 15:23:48 +0100231
Willy Tarreauaea940e2010-06-06 11:56:36 +0200232 /* session expired, trash it */
Willy Tarreau86257dc2010-06-06 12:57:10 +0200233 ebmb_delete(&ts->key);
Emeric Brun85e77c72010-09-23 18:16:52 +0200234 eb32_delete(&ts->upd);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200235 __stksess_free(t, ts);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100236 batched++;
237 }
238
239 return batched;
240}
241
242/*
Emeric Brun819fc6f2017-06-13 19:37:32 +0200243 * Trash oldest <to_batch> sticky sessions from table <t>
244 * Returns number of trashed sticky sessions.
245 * This function locks the table
246 */
247int stktable_trash_oldest(struct stktable *t, int to_batch)
248{
249 int ret;
250
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100251 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200252 ret = __stktable_trash_oldest(t, to_batch);
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100253 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200254
255 return ret;
256}
257/*
Willy Tarreauaea940e2010-06-06 11:56:36 +0200258 * Allocate and initialise a new sticky session.
259 * The new sticky session is returned or NULL in case of lack of memory.
260 * Sticky sessions should only be allocated this way, and must be freed using
Willy Tarreaua7b46b52013-04-11 16:55:37 +0200261 * stksess_free(). Table <t>'s sticky session counter is increased. If <key>
262 * is not NULL, it is assigned to the new session.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100263 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200264struct stksess *__stksess_new(struct stktable *t, struct stktable_key *key)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100265{
266 struct stksess *ts;
267
268 if (unlikely(t->current == t->size)) {
269 if ( t->nopurge )
270 return NULL;
271
Emeric Brun819fc6f2017-06-13 19:37:32 +0200272 if (!__stktable_trash_oldest(t, (t->size >> 8) + 1))
Emeric Brun3bd697e2010-01-04 15:23:48 +0100273 return NULL;
274 }
275
Willy Tarreaubafbe012017-11-24 17:34:44 +0100276 ts = pool_alloc(t->pool);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100277 if (ts) {
278 t->current++;
Olivier Houchard52dabbc2018-11-14 17:54:36 +0100279 ts = (void *)ts + round_ptr_size(t->data_size);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200280 __stksess_init(t, ts);
Willy Tarreaua7b46b52013-04-11 16:55:37 +0200281 if (key)
282 stksess_setkey(t, ts, key);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100283 }
284
285 return ts;
286}
Emeric Brun819fc6f2017-06-13 19:37:32 +0200287/*
288 * Allocate and initialise a new sticky session.
289 * The new sticky session is returned or NULL in case of lack of memory.
290 * Sticky sessions should only be allocated this way, and must be freed using
291 * stksess_free(). Table <t>'s sticky session counter is increased. If <key>
292 * is not NULL, it is assigned to the new session.
293 * This function locks the table
294 */
295struct stksess *stksess_new(struct stktable *t, struct stktable_key *key)
296{
297 struct stksess *ts;
298
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100299 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200300 ts = __stksess_new(t, key);
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100301 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200302
303 return ts;
304}
Emeric Brun3bd697e2010-01-04 15:23:48 +0100305
306/*
Willy Tarreauf16d2b82010-06-06 15:38:59 +0200307 * Looks in table <t> for a sticky session matching key <key>.
Willy Tarreauaea940e2010-06-06 11:56:36 +0200308 * Returns pointer on requested sticky session or NULL if none was found.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100309 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200310struct stksess *__stktable_lookup_key(struct stktable *t, struct stktable_key *key)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100311{
312 struct ebmb_node *eb;
313
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200314 if (t->type == SMP_T_STR)
Emeric Brun485479d2010-09-23 18:02:19 +0200315 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 +0100316 else
317 eb = ebmb_lookup(&t->keys, key->key, t->key_size);
318
319 if (unlikely(!eb)) {
320 /* no session found */
321 return NULL;
322 }
323
Willy Tarreau86257dc2010-06-06 12:57:10 +0200324 return ebmb_entry(eb, struct stksess, key);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100325}
326
Emeric Brun819fc6f2017-06-13 19:37:32 +0200327/*
328 * Looks in table <t> for a sticky session matching key <key>.
329 * Returns pointer on requested sticky session or NULL if none was found.
330 * The refcount of the found entry is increased and this function
331 * is protected using the table lock
Willy Tarreau1f7e9252010-06-20 12:27:21 +0200332 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200333struct stksess *stktable_lookup_key(struct stktable *t, struct stktable_key *key)
Willy Tarreau1f7e9252010-06-20 12:27:21 +0200334{
335 struct stksess *ts;
336
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100337 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200338 ts = __stktable_lookup_key(t, key);
339 if (ts)
340 ts->ref_cnt++;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100341 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Willy Tarreau1f7e9252010-06-20 12:27:21 +0200342
Willy Tarreau1f7e9252010-06-20 12:27:21 +0200343 return ts;
344}
345
Willy Tarreauf16d2b82010-06-06 15:38:59 +0200346/*
347 * Looks in table <t> for a sticky session with same key as <ts>.
348 * Returns pointer on requested sticky session or NULL if none was found.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100349 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200350struct stksess *__stktable_lookup(struct stktable *t, struct stksess *ts)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100351{
Emeric Brun3bd697e2010-01-04 15:23:48 +0100352 struct ebmb_node *eb;
353
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200354 if (t->type == SMP_T_STR)
Willy Tarreau86257dc2010-06-06 12:57:10 +0200355 eb = ebst_lookup(&(t->keys), (char *)ts->key.key);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100356 else
Willy Tarreau86257dc2010-06-06 12:57:10 +0200357 eb = ebmb_lookup(&(t->keys), ts->key.key, t->key_size);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100358
Willy Tarreauf16d2b82010-06-06 15:38:59 +0200359 if (unlikely(!eb))
360 return NULL;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100361
Willy Tarreauf16d2b82010-06-06 15:38:59 +0200362 return ebmb_entry(eb, struct stksess, key);
363}
Emeric Brun3bd697e2010-01-04 15:23:48 +0100364
Emeric Brun819fc6f2017-06-13 19:37:32 +0200365/*
366 * Looks in table <t> for a sticky session with same key as <ts>.
367 * Returns pointer on requested sticky session or NULL if none was found.
368 * The refcount of the found entry is increased and this function
369 * is protected using the table lock
370 */
371struct stksess *stktable_lookup(struct stktable *t, struct stksess *ts)
372{
373 struct stksess *lts;
374
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100375 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200376 lts = __stktable_lookup(t, ts);
377 if (lts)
378 lts->ref_cnt++;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100379 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200380
381 return lts;
382}
383
Willy Tarreaucb183642010-06-06 17:58:34 +0200384/* Update the expiration timer for <ts> but do not touch its expiration node.
385 * The table's expiration timer is updated if set.
Emeric Brun819fc6f2017-06-13 19:37:32 +0200386 * The node will be also inserted into the update tree if needed, at a position
387 * depending if the update is a local or coming from a remote node
Willy Tarreaucb183642010-06-06 17:58:34 +0200388 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200389void __stktable_touch_with_exp(struct stktable *t, struct stksess *ts, int local, int expire)
Willy Tarreaucb183642010-06-06 17:58:34 +0200390{
Emeric Brun85e77c72010-09-23 18:16:52 +0200391 struct eb32_node * eb;
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200392 ts->expire = expire;
Willy Tarreaucb183642010-06-06 17:58:34 +0200393 if (t->expire) {
394 t->exp_task->expire = t->exp_next = tick_first(ts->expire, t->exp_next);
395 task_queue(t->exp_task);
396 }
Emeric Brun85e77c72010-09-23 18:16:52 +0200397
Emeric Brun819fc6f2017-06-13 19:37:32 +0200398 /* If sync is enabled */
399 if (t->sync_task) {
400 if (local) {
401 /* If this entry is not in the tree
402 or not scheduled for at least one peer */
403 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 */
419 if (!ts->upd.node.leaf_p) {
420 ts->upd.key= (++t->update)+(2147483648U);
421 eb = eb32_insert(&t->updates, &ts->upd);
422 if (eb != &ts->upd) {
423 eb32_delete(eb);
424 eb32_insert(&t->updates, &ts->upd);
425 }
426 }
427 }
Emeric Brun85e77c72010-09-23 18:16:52 +0200428 }
Willy Tarreaucb183642010-06-06 17:58:34 +0200429}
430
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200431/* Update the expiration timer for <ts> but do not touch its expiration node.
Emeric Brun819fc6f2017-06-13 19:37:32 +0200432 * The table's expiration timer is updated using the date of expiration coming from
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200433 * <t> stick-table configuration.
Emeric Brun819fc6f2017-06-13 19:37:32 +0200434 * The node will be also inserted into the update tree if needed, at a position
435 * considering the update is coming from a remote node
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200436 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200437void stktable_touch_remote(struct stktable *t, struct stksess *ts, int decrefcnt)
438{
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100439 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200440 __stktable_touch_with_exp(t, ts, 0, ts->expire);
441 if (decrefcnt)
442 ts->ref_cnt--;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100443 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200444}
445
446/* Update the expiration timer for <ts> but do not touch its expiration node.
447 * The table's expiration timer is updated using the date of expiration coming from
448 * <t> stick-table configuration.
449 * The node will be also inserted into the update tree if needed, at a position
450 * considering the update was made locally
451 */
452void stktable_touch_local(struct stktable *t, struct stksess *ts, int decrefcnt)
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200453{
454 int expire = tick_add(now_ms, MS_TO_TICKS(t->expire));
455
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100456 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200457 __stktable_touch_with_exp(t, ts, 1, expire);
458 if (decrefcnt)
459 ts->ref_cnt--;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100460 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200461}
Willy Tarreau43e90352018-06-27 06:25:57 +0200462/* Just decrease the ref_cnt of the current session. Does nothing if <ts> is NULL */
463static void stktable_release(struct stktable *t, struct stksess *ts)
Emeric Brun819fc6f2017-06-13 19:37:32 +0200464{
Willy Tarreau43e90352018-06-27 06:25:57 +0200465 if (!ts)
466 return;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100467 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200468 ts->ref_cnt--;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100469 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200470}
471
Willy Tarreauf16d2b82010-06-06 15:38:59 +0200472/* Insert new sticky session <ts> in the table. It is assumed that it does not
473 * yet exist (the caller must check this). The table's timeout is updated if it
474 * is set. <ts> is returned.
475 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200476void __stktable_store(struct stktable *t, struct stksess *ts)
Willy Tarreauf16d2b82010-06-06 15:38:59 +0200477{
Emeric Brun3bd697e2010-01-04 15:23:48 +0100478
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200479 ebmb_insert(&t->keys, &ts->key, t->key_size);
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200480 ts->exp.key = ts->expire;
481 eb32_insert(&t->exps, &ts->exp);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200482 if (t->expire) {
483 t->exp_task->expire = t->exp_next = tick_first(ts->expire, t->exp_next);
484 task_queue(t->exp_task);
485 }
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200486}
487
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200488/* Returns a valid or initialized stksess for the specified stktable_key in the
489 * specified table, or NULL if the key was NULL, or if no entry was found nor
490 * could be created. The entry's expiration is updated.
491 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200492struct stksess *__stktable_get_entry(struct stktable *table, struct stktable_key *key)
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200493{
494 struct stksess *ts;
495
496 if (!key)
497 return NULL;
498
Emeric Brun819fc6f2017-06-13 19:37:32 +0200499 ts = __stktable_lookup_key(table, key);
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200500 if (ts == NULL) {
501 /* entry does not exist, initialize a new one */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200502 ts = __stksess_new(table, key);
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200503 if (!ts)
504 return NULL;
Emeric Brun819fc6f2017-06-13 19:37:32 +0200505 __stktable_store(table, ts);
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200506 }
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200507 return ts;
508}
Emeric Brun819fc6f2017-06-13 19:37:32 +0200509/* Returns a valid or initialized stksess for the specified stktable_key in the
510 * specified table, or NULL if the key was NULL, or if no entry was found nor
511 * could be created. The entry's expiration is updated.
512 * This function locks the table, and the refcount of the entry is increased.
513 */
514struct stksess *stktable_get_entry(struct stktable *table, struct stktable_key *key)
515{
516 struct stksess *ts;
517
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100518 HA_SPIN_LOCK(STK_TABLE_LOCK, &table->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200519 ts = __stktable_get_entry(table, key);
520 if (ts)
521 ts->ref_cnt++;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100522 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &table->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200523
524 return ts;
525}
526
527/* Lookup for an entry with the same key and store the submitted
528 * stksess if not found.
529 */
530struct stksess *__stktable_set_entry(struct stktable *table, struct stksess *nts)
531{
532 struct stksess *ts;
533
534 ts = __stktable_lookup(table, nts);
535 if (ts == NULL) {
536 ts = nts;
537 __stktable_store(table, ts);
538 }
539 return ts;
540}
541
542/* Lookup for an entry with the same key and store the submitted
543 * stksess if not found.
544 * This function locks the table, and the refcount of the entry is increased.
545 */
546struct stksess *stktable_set_entry(struct stktable *table, struct stksess *nts)
547{
548 struct stksess *ts;
549
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100550 HA_SPIN_LOCK(STK_TABLE_LOCK, &table->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200551 ts = __stktable_set_entry(table, nts);
552 ts->ref_cnt++;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100553 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &table->lock);
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200554
Emeric Brun819fc6f2017-06-13 19:37:32 +0200555 return ts;
556}
Emeric Brun3bd697e2010-01-04 15:23:48 +0100557/*
Willy Tarreauaea940e2010-06-06 11:56:36 +0200558 * Trash expired sticky sessions from table <t>. The next expiration date is
559 * returned.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100560 */
561static int stktable_trash_expired(struct stktable *t)
562{
563 struct stksess *ts;
564 struct eb32_node *eb;
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200565 int looped = 0;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100566
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100567 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100568 eb = eb32_lookup_ge(&t->exps, now_ms - TIMER_LOOK_BACK);
569
570 while (1) {
571 if (unlikely(!eb)) {
572 /* we might have reached the end of the tree, typically because
573 * <now_ms> is in the first half and we're first scanning the last
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200574 * half. Let's loop back to the beginning of the tree now if we
575 * have not yet visited it.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100576 */
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200577 if (looped)
578 break;
579 looped = 1;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100580 eb = eb32_first(&t->exps);
581 if (likely(!eb))
582 break;
583 }
584
585 if (likely(tick_is_lt(now_ms, eb->key))) {
586 /* timer not expired yet, revisit it later */
587 t->exp_next = eb->key;
Willy Tarreau4d5f13c2017-11-05 11:04:47 +0100588 goto out_unlock;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100589 }
590
591 /* timer looks expired, detach it from the queue */
Willy Tarreau86257dc2010-06-06 12:57:10 +0200592 ts = eb32_entry(eb, struct stksess, exp);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100593 eb = eb32_next(eb);
594
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200595 /* don't delete an entry which is currently referenced */
596 if (ts->ref_cnt)
597 continue;
598
Willy Tarreau86257dc2010-06-06 12:57:10 +0200599 eb32_delete(&ts->exp);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100600
601 if (!tick_is_expired(ts->expire, now_ms)) {
602 if (!tick_isset(ts->expire))
603 continue;
604
Willy Tarreau86257dc2010-06-06 12:57:10 +0200605 ts->exp.key = ts->expire;
606 eb32_insert(&t->exps, &ts->exp);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100607
Willy Tarreau86257dc2010-06-06 12:57:10 +0200608 if (!eb || eb->key > ts->exp.key)
609 eb = &ts->exp;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100610 continue;
611 }
612
613 /* session expired, trash it */
Willy Tarreau86257dc2010-06-06 12:57:10 +0200614 ebmb_delete(&ts->key);
Emeric Brun85e77c72010-09-23 18:16:52 +0200615 eb32_delete(&ts->upd);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200616 __stksess_free(t, ts);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100617 }
618
619 /* We have found no task to expire in any tree */
620 t->exp_next = TICK_ETERNITY;
Willy Tarreau4d5f13c2017-11-05 11:04:47 +0100621out_unlock:
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100622 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100623 return t->exp_next;
624}
625
626/*
Willy Tarreauaea940e2010-06-06 11:56:36 +0200627 * Task processing function to trash expired sticky sessions. A pointer to the
628 * task itself is returned since it never dies.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100629 */
Willy Tarreau144f84a2021-03-02 16:09:26 +0100630struct task *process_table_expire(struct task *task, void *context, unsigned int state)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100631{
Olivier Houchard9f6af332018-05-25 14:04:04 +0200632 struct stktable *t = context;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100633
634 task->expire = stktable_trash_expired(t);
635 return task;
636}
637
Willy Tarreauaea940e2010-06-06 11:56:36 +0200638/* Perform minimal stick table intializations, report 0 in case of error, 1 if OK. */
Emeric Brun3bd697e2010-01-04 15:23:48 +0100639int stktable_init(struct stktable *t)
640{
Remi Tricot-Le Breton208ff012021-05-12 17:39:04 +0200641 int peers_retval = 0;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100642 if (t->size) {
Emeric Brun819fc6f2017-06-13 19:37:32 +0200643 t->keys = EB_ROOT_UNIQUE;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100644 memset(&t->exps, 0, sizeof(t->exps));
Emeric Brun1c6235d2015-12-16 15:28:12 +0100645 t->updates = EB_ROOT_UNIQUE;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100646 HA_SPIN_INIT(&t->lock);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100647
Olivier Houchard52dabbc2018-11-14 17:54:36 +0100648 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 +0100649
650 t->exp_next = TICK_ETERNITY;
651 if ( t->expire ) {
Willy Tarreaubeeabf52021-10-01 18:23:30 +0200652 t->exp_task = task_new_anywhere();
Willy Tarreau848522f2018-10-15 11:12:15 +0200653 if (!t->exp_task)
654 return 0;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100655 t->exp_task->process = process_table_expire;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100656 t->exp_task->context = (void *)t;
657 }
Christopher Fauletdfd10ab2021-10-06 14:24:19 +0200658 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 +0200659 peers_retval = peers_register_table(t->peers.p, t);
Emeric Brun32da3c42010-09-23 18:39:19 +0200660 }
661
Remi Tricot-Le Breton208ff012021-05-12 17:39:04 +0200662 return (t->pool != NULL) && !peers_retval;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100663 }
664 return 1;
665}
666
667/*
668 * Configuration keywords of known table types
669 */
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200670struct stktable_type stktable_types[SMP_TYPES] = {
671 [SMP_T_SINT] = { "integer", 0, 4 },
672 [SMP_T_IPV4] = { "ip", 0, 4 },
673 [SMP_T_IPV6] = { "ipv6", 0, 16 },
674 [SMP_T_STR] = { "string", STK_F_CUSTOM_KEYSIZE, 32 },
675 [SMP_T_BIN] = { "binary", STK_F_CUSTOM_KEYSIZE, 32 }
676};
Emeric Brun3bd697e2010-01-04 15:23:48 +0100677
678/*
679 * Parse table type configuration.
680 * Returns 0 on successful parsing, else 1.
681 * <myidx> is set at next configuration <args> index.
682 */
683int stktable_parse_type(char **args, int *myidx, unsigned long *type, size_t *key_size)
684{
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200685 for (*type = 0; *type < SMP_TYPES; (*type)++) {
686 if (!stktable_types[*type].kw)
687 continue;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100688 if (strcmp(args[*myidx], stktable_types[*type].kw) != 0)
689 continue;
690
691 *key_size = stktable_types[*type].default_size;
692 (*myidx)++;
693
Willy Tarreauaea940e2010-06-06 11:56:36 +0200694 if (stktable_types[*type].flags & STK_F_CUSTOM_KEYSIZE) {
Emeric Brun3bd697e2010-01-04 15:23:48 +0100695 if (strcmp("len", args[*myidx]) == 0) {
696 (*myidx)++;
697 *key_size = atol(args[*myidx]);
Emeric Brun485479d2010-09-23 18:02:19 +0200698 if (!*key_size)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100699 break;
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200700 if (*type == SMP_T_STR) {
Emeric Brun485479d2010-09-23 18:02:19 +0200701 /* null terminated string needs +1 for '\0'. */
702 (*key_size)++;
703 }
Emeric Brun3bd697e2010-01-04 15:23:48 +0100704 (*myidx)++;
705 }
706 }
707 return 0;
708 }
709 return 1;
710}
711
Emeric Brunc64a2a32021-06-30 18:01:02 +0200712/* reserve some space for data type <type>, there is 2 optionnals
713 * argument at <sa> and <sa2> to configure this data type and
714 * they can be NULL if unused for a given type.
715 * Returns PE_NONE (0) if OK or an error code among :
Willy Tarreau3b63ca22021-05-08 14:10:42 +0200716 * - PE_ENUM_OOR if <type> does not exist
717 * - PE_EXIST if <type> is already registered
Emeric Brunc64a2a32021-06-30 18:01:02 +0200718 * - PE_ARG_NOT_USE if <sa>/<sa2> was provided but not expected
719 * - PE_ARG_MISSING if <sa>/<sa2> was expected but not provided
720 * - PE_ARG_VALUE_OOR if type is an array and <sa> it out of array size range.
Willy Tarreau3b63ca22021-05-08 14:10:42 +0200721 */
Emeric Brunc64a2a32021-06-30 18:01:02 +0200722int stktable_alloc_data_type(struct stktable *t, int type, const char *sa, const char *sa2)
723
Willy Tarreau3b63ca22021-05-08 14:10:42 +0200724{
725 if (type >= STKTABLE_DATA_TYPES)
726 return PE_ENUM_OOR;
727
728 if (t->data_ofs[type])
729 /* already allocated */
730 return PE_EXIST;
731
Emeric Brunc64a2a32021-06-30 18:01:02 +0200732 t->data_nbelem[type] = 1;
733 if (stktable_data_types[type].is_array) {
734 /* arrays take their element count on first argument */
735 if (!sa)
736 return PE_ARG_MISSING;
737 t->data_nbelem[type] = atoi(sa);
738 if (!t->data_nbelem[type] || (t->data_nbelem[type] > STKTABLE_MAX_DT_ARRAY_SIZE))
739 return PE_ARG_VALUE_OOR;
740 sa = sa2;
741 }
742
Willy Tarreau3b63ca22021-05-08 14:10:42 +0200743 switch (stktable_data_types[type].arg_type) {
744 case ARG_T_NONE:
745 if (sa)
746 return PE_ARG_NOT_USED;
747 break;
748 case ARG_T_INT:
749 if (!sa)
750 return PE_ARG_MISSING;
751 t->data_arg[type].i = atoi(sa);
752 break;
753 case ARG_T_DELAY:
754 if (!sa)
755 return PE_ARG_MISSING;
756 sa = parse_time_err(sa, &t->data_arg[type].u, TIME_UNIT_MS);
757 if (sa)
758 return PE_ARG_INVC; /* invalid char */
759 break;
760 }
761
Emeric Brunc64a2a32021-06-30 18:01:02 +0200762 t->data_size += t->data_nbelem[type] * stktable_type_size(stktable_data_types[type].std_type);
Willy Tarreau3b63ca22021-05-08 14:10:42 +0200763 t->data_ofs[type] = -t->data_size;
764 return PE_NONE;
765}
766
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100767/*
Frédéric Lécaillec02766a2019-03-20 15:06:55 +0100768 * Parse a line with <linenum> as number in <file> configuration file to configure
769 * the stick-table with <t> as address and <id> as ID.
770 * <peers> provides the "peers" section pointer only if this function is called
771 * from a "peers" section.
772 * <nid> is the stick-table name which is sent over the network. It must be equal
773 * to <id> if this stick-table is parsed from a proxy section, and prefixed by <peers>
774 * "peers" section name followed by a '/' character if parsed from a "peers" section.
Ilya Shipitsind4259502020-04-08 01:07:56 +0500775 * This is the responsibility of the caller to check this.
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100776 * Return an error status with ERR_* flags set if required, 0 if no error was encountered.
777 */
778int parse_stick_table(const char *file, int linenum, char **args,
Frédéric Lécaillec02766a2019-03-20 15:06:55 +0100779 struct stktable *t, char *id, char *nid, struct peers *peers)
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100780{
781 int err_code = 0;
782 int idx = 1;
783 unsigned int val;
784
785 if (!id || !*id) {
786 ha_alert("parsing [%s:%d] : %s: ID not provided.\n", file, linenum, args[0]);
787 err_code |= ERR_ALERT | ERR_ABORT;
788 goto out;
789 }
790
791 /* Store the "peers" section if this function is called from a "peers" section. */
792 if (peers) {
793 t->peers.p = peers;
794 idx++;
795 }
796
797 t->id = id;
Frédéric Lécaillec02766a2019-03-20 15:06:55 +0100798 t->nid = nid;
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100799 t->type = (unsigned int)-1;
800 t->conf.file = file;
801 t->conf.line = linenum;
802
803 while (*args[idx]) {
804 const char *err;
805
806 if (strcmp(args[idx], "size") == 0) {
807 idx++;
808 if (!*(args[idx])) {
809 ha_alert("parsing [%s:%d] : %s: missing argument after '%s'.\n",
810 file, linenum, args[0], args[idx-1]);
811 err_code |= ERR_ALERT | ERR_FATAL;
812 goto out;
813 }
814 if ((err = parse_size_err(args[idx], &t->size))) {
815 ha_alert("parsing [%s:%d] : %s: unexpected character '%c' in argument of '%s'.\n",
816 file, linenum, args[0], *err, args[idx-1]);
817 err_code |= ERR_ALERT | ERR_FATAL;
818 goto out;
819 }
820 idx++;
821 }
822 /* This argument does not exit in "peers" section. */
823 else if (!peers && strcmp(args[idx], "peers") == 0) {
824 idx++;
825 if (!*(args[idx])) {
826 ha_alert("parsing [%s:%d] : %s: missing argument after '%s'.\n",
827 file, linenum, args[0], args[idx-1]);
828 err_code |= ERR_ALERT | ERR_FATAL;
829 goto out;
830 }
831 t->peers.name = strdup(args[idx++]);
832 }
833 else if (strcmp(args[idx], "expire") == 0) {
834 idx++;
835 if (!*(args[idx])) {
836 ha_alert("parsing [%s:%d] : %s: missing argument after '%s'.\n",
837 file, linenum, args[0], args[idx-1]);
838 err_code |= ERR_ALERT | ERR_FATAL;
839 goto out;
840 }
841 err = parse_time_err(args[idx], &val, TIME_UNIT_MS);
Willy Tarreau9faebe32019-06-07 19:00:37 +0200842 if (err == PARSE_TIME_OVER) {
843 ha_alert("parsing [%s:%d]: %s: timer overflow in argument <%s> to <%s>, maximum value is 2147483647 ms (~24.8 days).\n",
844 file, linenum, args[0], args[idx], args[idx-1]);
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100845 err_code |= ERR_ALERT | ERR_FATAL;
846 goto out;
847 }
Willy Tarreau9faebe32019-06-07 19:00:37 +0200848 else if (err == PARSE_TIME_UNDER) {
849 ha_alert("parsing [%s:%d]: %s: timer underflow in argument <%s> to <%s>, minimum non-null value is 1 ms.\n",
850 file, linenum, args[0], args[idx], args[idx-1]);
851 err_code |= ERR_ALERT | ERR_FATAL;
852 goto out;
853 }
854 else if (err) {
855 ha_alert("parsing [%s:%d] : %s: unexpected character '%c' in argument of '%s'.\n",
856 file, linenum, args[0], *err, args[idx-1]);
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100857 err_code |= ERR_ALERT | ERR_FATAL;
858 goto out;
859 }
860 t->expire = val;
861 idx++;
862 }
863 else if (strcmp(args[idx], "nopurge") == 0) {
864 t->nopurge = 1;
865 idx++;
866 }
867 else if (strcmp(args[idx], "type") == 0) {
868 idx++;
869 if (stktable_parse_type(args, &idx, &t->type, &t->key_size) != 0) {
870 ha_alert("parsing [%s:%d] : %s: unknown type '%s'.\n",
871 file, linenum, args[0], args[idx]);
872 err_code |= ERR_ALERT | ERR_FATAL;
873 goto out;
874 }
875 /* idx already points to next arg */
876 }
877 else if (strcmp(args[idx], "store") == 0) {
878 int type, err;
Emeric Brunc64a2a32021-06-30 18:01:02 +0200879 char *cw, *nw, *sa, *sa2;
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100880
881 idx++;
882 nw = args[idx];
883 while (*nw) {
884 /* the "store" keyword supports a comma-separated list */
885 cw = nw;
886 sa = NULL; /* store arg */
Emeric Brunc64a2a32021-06-30 18:01:02 +0200887 sa2 = NULL;
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100888 while (*nw && *nw != ',') {
889 if (*nw == '(') {
890 *nw = 0;
891 sa = ++nw;
892 while (*nw != ')') {
893 if (!*nw) {
894 ha_alert("parsing [%s:%d] : %s: missing closing parenthesis after store option '%s'.\n",
895 file, linenum, args[0], cw);
896 err_code |= ERR_ALERT | ERR_FATAL;
897 goto out;
898 }
Emeric Brunc64a2a32021-06-30 18:01:02 +0200899 if (*nw == ',') {
900 *nw = '\0';
901 sa2 = nw + 1;
902 }
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100903 nw++;
904 }
905 *nw = '\0';
906 }
907 nw++;
908 }
909 if (*nw)
910 *nw++ = '\0';
911 type = stktable_get_data_type(cw);
912 if (type < 0) {
913 ha_alert("parsing [%s:%d] : %s: unknown store option '%s'.\n",
914 file, linenum, args[0], cw);
915 err_code |= ERR_ALERT | ERR_FATAL;
916 goto out;
917 }
918
Emeric Brunc64a2a32021-06-30 18:01:02 +0200919 err = stktable_alloc_data_type(t, type, sa, sa2);
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100920 switch (err) {
921 case PE_NONE: break;
922 case PE_EXIST:
923 ha_warning("parsing [%s:%d]: %s: store option '%s' already enabled, ignored.\n",
924 file, linenum, args[0], cw);
925 err_code |= ERR_WARN;
926 break;
927
928 case PE_ARG_MISSING:
929 ha_alert("parsing [%s:%d] : %s: missing argument to store option '%s'.\n",
930 file, linenum, args[0], cw);
931 err_code |= ERR_ALERT | ERR_FATAL;
932 goto out;
933
934 case PE_ARG_NOT_USED:
935 ha_alert("parsing [%s:%d] : %s: unexpected argument to store option '%s'.\n",
936 file, linenum, args[0], cw);
937 err_code |= ERR_ALERT | ERR_FATAL;
938 goto out;
Emeric Brunc64a2a32021-06-30 18:01:02 +0200939 case PE_ARG_VALUE_OOR:
940 ha_alert("parsing [%s:%d] : %s: array size is out of allowed range (1-%d) for store option '%s'.\n",
941 file, linenum, args[0], STKTABLE_MAX_DT_ARRAY_SIZE, cw);
942 err_code |= ERR_ALERT | ERR_FATAL;
943 goto out;
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100944
945 default:
946 ha_alert("parsing [%s:%d] : %s: error when processing store option '%s'.\n",
947 file, linenum, args[0], cw);
948 err_code |= ERR_ALERT | ERR_FATAL;
949 goto out;
950 }
951 }
952 idx++;
Emeric Brunf7ab0bf2021-06-30 18:58:22 +0200953 if (t->data_ofs[STKTABLE_DT_GPT] && t->data_ofs[STKTABLE_DT_GPT0]) {
954 ha_alert("parsing [%s:%d] : %s: simultaneous usage of 'gpt' and 'gpt0' in a same table is not permitted as 'gpt' overrides 'gpt0'.\n",
955 file, linenum, args[0]);
956 err_code |= ERR_ALERT | ERR_FATAL;
957 goto out;
958 }
Emeric Brun726783d2021-06-30 19:06:43 +0200959 else if (t->data_ofs[STKTABLE_DT_GPC] && (t->data_ofs[STKTABLE_DT_GPC0] || t->data_ofs[STKTABLE_DT_GPC1])) {
960 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",
961 file, linenum, args[0]);
962 err_code |= ERR_ALERT | ERR_FATAL;
963 goto out;
964 }
965 else if (t->data_ofs[STKTABLE_DT_GPC_RATE] && (t->data_ofs[STKTABLE_DT_GPC0_RATE] || t->data_ofs[STKTABLE_DT_GPC1_RATE])) {
966 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",
967 file, linenum, args[0]);
968 err_code |= ERR_ALERT | ERR_FATAL;
969 goto out;
970 }
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100971 }
Thayne McCombs92149f92020-11-20 01:28:26 -0700972 else if (strcmp(args[idx], "srvkey") == 0) {
973 char *keytype;
974 idx++;
975 keytype = args[idx];
976 if (strcmp(keytype, "name") == 0) {
977 t->server_key_type = STKTABLE_SRV_NAME;
978 }
979 else if (strcmp(keytype, "addr") == 0) {
980 t->server_key_type = STKTABLE_SRV_ADDR;
981 }
982 else {
983 ha_alert("parsing [%s:%d] : %s : unknown server key type '%s'.\n",
984 file, linenum, args[0], keytype);
985 err_code |= ERR_ALERT | ERR_FATAL;
986 goto out;
987
988 }
989 idx++;
990 }
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100991 else {
992 ha_alert("parsing [%s:%d] : %s: unknown argument '%s'.\n",
993 file, linenum, args[0], args[idx]);
994 err_code |= ERR_ALERT | ERR_FATAL;
995 goto out;
996 }
997 }
998
999 if (!t->size) {
1000 ha_alert("parsing [%s:%d] : %s: missing size.\n",
1001 file, linenum, args[0]);
1002 err_code |= ERR_ALERT | ERR_FATAL;
1003 goto out;
1004 }
1005
1006 if (t->type == (unsigned int)-1) {
1007 ha_alert("parsing [%s:%d] : %s: missing type.\n",
1008 file, linenum, args[0]);
1009 err_code |= ERR_ALERT | ERR_FATAL;
1010 goto out;
1011 }
1012
1013 out:
1014 return err_code;
1015}
1016
Willy Tarreau8fed9032014-07-03 17:02:46 +02001017/* Prepares a stktable_key from a sample <smp> to search into table <t>.
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001018 * Note that the sample *is* modified and that the returned key may point
1019 * to it, so the sample must not be modified afterwards before the lookup.
Willy Tarreau8fed9032014-07-03 17:02:46 +02001020 * Returns NULL if the sample could not be converted (eg: no matching type),
1021 * otherwise a pointer to the static stktable_key filled with what is needed
1022 * for the lookup.
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001023 */
Willy Tarreau8fed9032014-07-03 17:02:46 +02001024struct stktable_key *smp_to_stkey(struct sample *smp, struct stktable *t)
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001025{
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001026 /* Convert sample. */
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +02001027 if (!sample_convert(smp, t->type))
Willy Tarreau7fc1c6e2012-04-26 11:03:17 +02001028 return NULL;
1029
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001030 /* Fill static_table_key. */
1031 switch (t->type) {
Emeric Brun485479d2010-09-23 18:02:19 +02001032
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +02001033 case SMP_T_IPV4:
Christopher Fauletca20d022017-08-29 15:30:31 +02001034 static_table_key.key = &smp->data.u.ipv4;
1035 static_table_key.key_len = 4;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001036 break;
Emeric Brun485479d2010-09-23 18:02:19 +02001037
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +02001038 case SMP_T_IPV6:
Christopher Fauletca20d022017-08-29 15:30:31 +02001039 static_table_key.key = &smp->data.u.ipv6;
1040 static_table_key.key_len = 16;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001041 break;
Emeric Brun485479d2010-09-23 18:02:19 +02001042
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +02001043 case SMP_T_SINT:
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001044 /* The stick table require a 32bit unsigned int, "sint" is a
1045 * signed 64 it, so we can convert it inplace.
1046 */
Willy Tarreau28c63c12019-10-23 06:21:05 +02001047 smp->data.u.sint = (unsigned int)smp->data.u.sint;
Christopher Fauletca20d022017-08-29 15:30:31 +02001048 static_table_key.key = &smp->data.u.sint;
1049 static_table_key.key_len = 4;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001050 break;
1051
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +02001052 case SMP_T_STR:
Willy Tarreauce6955e2016-08-09 11:59:12 +02001053 if (!smp_make_safe(smp))
1054 return NULL;
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001055 static_table_key.key = smp->data.u.str.area;
1056 static_table_key.key_len = smp->data.u.str.data;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001057 break;
Emeric Brun485479d2010-09-23 18:02:19 +02001058
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +02001059 case SMP_T_BIN:
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001060 if (smp->data.u.str.data < t->key_size) {
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001061 /* This type needs padding with 0. */
Willy Tarreauf65c6c02016-08-09 12:08:41 +02001062 if (!smp_make_rw(smp))
1063 return NULL;
1064
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001065 if (smp->data.u.str.size < t->key_size)
1066 if (!smp_dup(smp))
1067 return NULL;
1068 if (smp->data.u.str.size < t->key_size)
1069 return NULL;
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001070 memset(smp->data.u.str.area + smp->data.u.str.data, 0,
1071 t->key_size - smp->data.u.str.data);
1072 smp->data.u.str.data = t->key_size;
Emeric Brun485479d2010-09-23 18:02:19 +02001073 }
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001074 static_table_key.key = smp->data.u.str.area;
1075 static_table_key.key_len = smp->data.u.str.data;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001076 break;
Emeric Brun485479d2010-09-23 18:02:19 +02001077
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001078 default: /* impossible case. */
1079 return NULL;
Emeric Brun485479d2010-09-23 18:02:19 +02001080 }
1081
Christopher Fauletca20d022017-08-29 15:30:31 +02001082 return &static_table_key;
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001083}
1084
1085/*
Willy Tarreau8fed9032014-07-03 17:02:46 +02001086 * Process a fetch + format conversion as defined by the sample expression <expr>
1087 * on request or response considering the <opt> parameter. Returns either NULL if
1088 * no key could be extracted, or a pointer to the converted result stored in
1089 * static_table_key in format <table_type>. If <smp> is not NULL, it will be reset
1090 * and its flags will be initialized so that the caller gets a copy of the input
Willy Tarreau6bcb0a82014-07-30 08:56:35 +02001091 * sample, and knows why it was not accepted (eg: SMP_F_MAY_CHANGE is present
1092 * without SMP_OPT_FINAL). The output will be usable like this :
1093 *
1094 * return MAY_CHANGE FINAL Meaning for the sample
1095 * NULL 0 * Not present and will never be (eg: header)
1096 * NULL 1 0 Not present or unstable, could change (eg: req_len)
1097 * NULL 1 1 Not present, will not change anymore
1098 * smp 0 * Present and will not change (eg: header)
1099 * smp 1 0 not possible
1100 * smp 1 1 Present, last known value (eg: request length)
Willy Tarreau8fed9032014-07-03 17:02:46 +02001101 */
Willy Tarreau192252e2015-04-04 01:47:55 +02001102struct stktable_key *stktable_fetch_key(struct stktable *t, struct proxy *px, struct session *sess, struct stream *strm,
Willy Tarreau8fed9032014-07-03 17:02:46 +02001103 unsigned int opt, struct sample_expr *expr, struct sample *smp)
1104{
1105 if (smp)
1106 memset(smp, 0, sizeof(*smp));
1107
Willy Tarreau192252e2015-04-04 01:47:55 +02001108 smp = sample_process(px, sess, strm, opt, expr, smp);
Willy Tarreau8fed9032014-07-03 17:02:46 +02001109 if (!smp)
1110 return NULL;
1111
1112 if ((smp->flags & SMP_F_MAY_CHANGE) && !(opt & SMP_OPT_FINAL))
1113 return NULL; /* we can only use stable samples */
1114
1115 return smp_to_stkey(smp, t);
1116}
1117
1118/*
Willy Tarreau12785782012-04-27 21:37:17 +02001119 * Returns 1 if sample expression <expr> result can be converted to table key of
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001120 * type <table_type>, otherwise zero. Used in configuration check.
1121 */
Willy Tarreau12785782012-04-27 21:37:17 +02001122int stktable_compatible_sample(struct sample_expr *expr, unsigned long table_type)
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001123{
Thierry FOURNIERf73eb8f2013-11-27 15:30:55 +01001124 int out_type;
1125
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +02001126 if (table_type >= SMP_TYPES || !stktable_types[table_type].kw)
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001127 return 0;
1128
Thierry FOURNIERf73eb8f2013-11-27 15:30:55 +01001129 out_type = smp_expr_output_type(expr);
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001130
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001131 /* Convert sample. */
1132 if (!sample_casts[out_type][table_type])
Thierry FOURNIERf73eb8f2013-11-27 15:30:55 +01001133 return 0;
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001134
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001135 return 1;
1136}
Emeric Brun3bd697e2010-01-04 15:23:48 +01001137
Willy Tarreauedee1d62014-07-15 16:44:27 +02001138/* Extra data types processing : after the last one, some room may remain
1139 * before STKTABLE_DATA_TYPES that may be used to register extra data types
1140 * at run time.
1141 */
Willy Tarreau08d5f982010-06-06 13:34:54 +02001142struct stktable_data_type stktable_data_types[STKTABLE_DATA_TYPES] = {
Willy Tarreau3b9c6e02010-07-18 08:04:30 +02001143 [STKTABLE_DT_SERVER_ID] = { .name = "server_id", .std_type = STD_T_SINT },
Thierry FOURNIER3cf11112015-07-28 08:57:05 +02001144 [STKTABLE_DT_GPT0] = { .name = "gpt0", .std_type = STD_T_UINT },
Willy Tarreau3b9c6e02010-07-18 08:04:30 +02001145 [STKTABLE_DT_GPC0] = { .name = "gpc0", .std_type = STD_T_UINT },
Willy Tarreauba2ffd12013-05-29 15:54:14 +02001146 [STKTABLE_DT_GPC0_RATE] = { .name = "gpc0_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
Willy Tarreau3b9c6e02010-07-18 08:04:30 +02001147 [STKTABLE_DT_CONN_CNT] = { .name = "conn_cnt", .std_type = STD_T_UINT },
1148 [STKTABLE_DT_CONN_RATE] = { .name = "conn_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
Willy Tarreaudb2ab822021-10-08 17:53:12 +02001149 [STKTABLE_DT_CONN_CUR] = { .name = "conn_cur", .std_type = STD_T_UINT, .is_local = 1 },
Willy Tarreau3b9c6e02010-07-18 08:04:30 +02001150 [STKTABLE_DT_SESS_CNT] = { .name = "sess_cnt", .std_type = STD_T_UINT },
1151 [STKTABLE_DT_SESS_RATE] = { .name = "sess_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
1152 [STKTABLE_DT_HTTP_REQ_CNT] = { .name = "http_req_cnt", .std_type = STD_T_UINT },
1153 [STKTABLE_DT_HTTP_REQ_RATE] = { .name = "http_req_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
1154 [STKTABLE_DT_HTTP_ERR_CNT] = { .name = "http_err_cnt", .std_type = STD_T_UINT },
1155 [STKTABLE_DT_HTTP_ERR_RATE] = { .name = "http_err_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
1156 [STKTABLE_DT_BYTES_IN_CNT] = { .name = "bytes_in_cnt", .std_type = STD_T_ULL },
1157 [STKTABLE_DT_BYTES_IN_RATE] = { .name = "bytes_in_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
1158 [STKTABLE_DT_BYTES_OUT_CNT] = { .name = "bytes_out_cnt", .std_type = STD_T_ULL },
1159 [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 +01001160 [STKTABLE_DT_GPC1] = { .name = "gpc1", .std_type = STD_T_UINT },
1161 [STKTABLE_DT_GPC1_RATE] = { .name = "gpc1_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
Thayne McCombs92149f92020-11-20 01:28:26 -07001162 [STKTABLE_DT_SERVER_KEY] = { .name = "server_key", .std_type = STD_T_DICT },
Willy Tarreau826f3ab2021-02-10 12:07:15 +01001163 [STKTABLE_DT_HTTP_FAIL_CNT] = { .name = "http_fail_cnt", .std_type = STD_T_UINT },
1164 [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 +02001165 [STKTABLE_DT_GPT] = { .name = "gpt", .std_type = STD_T_UINT, .is_array = 1 },
Emeric Brun4d7ada82021-06-30 19:04:16 +02001166 [STKTABLE_DT_GPC] = { .name = "gpc", .std_type = STD_T_UINT, .is_array = 1 },
1167 [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 +02001168};
1169
Willy Tarreauedee1d62014-07-15 16:44:27 +02001170/* Registers stick-table extra data type with index <idx>, name <name>, type
1171 * <std_type> and arg type <arg_type>. If the index is negative, the next free
1172 * index is automatically allocated. The allocated index is returned, or -1 if
1173 * no free index was found or <name> was already registered. The <name> is used
1174 * directly as a pointer, so if it's not stable, the caller must allocate it.
1175 */
1176int stktable_register_data_store(int idx, const char *name, int std_type, int arg_type)
1177{
1178 if (idx < 0) {
1179 for (idx = 0; idx < STKTABLE_DATA_TYPES; idx++) {
1180 if (!stktable_data_types[idx].name)
1181 break;
1182
1183 if (strcmp(stktable_data_types[idx].name, name) == 0)
1184 return -1;
1185 }
1186 }
1187
1188 if (idx >= STKTABLE_DATA_TYPES)
1189 return -1;
1190
1191 if (stktable_data_types[idx].name != NULL)
1192 return -1;
1193
1194 stktable_data_types[idx].name = name;
1195 stktable_data_types[idx].std_type = std_type;
1196 stktable_data_types[idx].arg_type = arg_type;
1197 return idx;
1198}
1199
Willy Tarreau08d5f982010-06-06 13:34:54 +02001200/*
1201 * Returns the data type number for the stktable_data_type whose name is <name>,
1202 * or <0 if not found.
1203 */
1204int stktable_get_data_type(char *name)
1205{
1206 int type;
1207
1208 for (type = 0; type < STKTABLE_DATA_TYPES; type++) {
Willy Tarreauedee1d62014-07-15 16:44:27 +02001209 if (!stktable_data_types[type].name)
1210 continue;
Willy Tarreau08d5f982010-06-06 13:34:54 +02001211 if (strcmp(name, stktable_data_types[type].name) == 0)
1212 return type;
1213 }
Thayne McCombs92149f92020-11-20 01:28:26 -07001214 /* For backwards compatibility */
1215 if (strcmp(name, "server_name") == 0)
1216 return STKTABLE_DT_SERVER_KEY;
Willy Tarreau08d5f982010-06-06 13:34:54 +02001217 return -1;
1218}
1219
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001220/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1221 * it up into this table. Returns true if found, false otherwise. The input
1222 * type is STR so that input samples are converted to string (since all types
1223 * can be converted to strings), then the function casts the string again into
1224 * the table's type. This is a double conversion, but in the future we might
1225 * support automatic input types to perform the cast on the fly.
1226 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001227static int sample_conv_in_table(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001228{
1229 struct stktable *t;
1230 struct stktable_key *key;
1231 struct stksess *ts;
1232
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001233 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001234
1235 key = smp_to_stkey(smp, t);
1236 if (!key)
1237 return 0;
1238
1239 ts = stktable_lookup_key(t, key);
1240
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001241 smp->data.type = SMP_T_BOOL;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001242 smp->data.u.sint = !!ts;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001243 smp->flags = SMP_F_VOL_TEST;
Willy Tarreau43e90352018-06-27 06:25:57 +02001244 stktable_release(t, ts);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001245 return 1;
1246}
1247
1248/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1249 * it up into this table. Returns the data rate received from clients in bytes/s
1250 * if the key is present in the table, otherwise zero, so that comparisons can
1251 * be easily performed. If the inspected parameter is not stored in the table,
1252 * <not found> is returned.
1253 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001254static int sample_conv_table_bytes_in_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001255{
1256 struct stktable *t;
1257 struct stktable_key *key;
1258 struct stksess *ts;
1259 void *ptr;
1260
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001261 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001262
1263 key = smp_to_stkey(smp, t);
1264 if (!key)
1265 return 0;
1266
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001267 ts = stktable_lookup_key(t, key);
1268
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001269 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001270 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001271 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001272
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001273 if (!ts) /* key not present */
1274 return 1;
1275
1276 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_IN_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001277 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001278 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Daniel Corbett3e60b112018-05-27 09:47:12 -04001279 t->data_arg[STKTABLE_DT_BYTES_IN_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001280
Daniel Corbett3e60b112018-05-27 09:47:12 -04001281 stktable_release(t, ts);
1282 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001283}
1284
1285/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1286 * it up into this table. Returns the cumulated number of connections for the key
1287 * if the key is present in the table, otherwise zero, so that comparisons can
1288 * be easily performed. If the inspected parameter is not stored in the table,
1289 * <not found> is returned.
1290 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001291static int sample_conv_table_conn_cnt(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001292{
1293 struct stktable *t;
1294 struct stktable_key *key;
1295 struct stksess *ts;
1296 void *ptr;
1297
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001298 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001299
1300 key = smp_to_stkey(smp, t);
1301 if (!key)
1302 return 0;
1303
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001304 ts = stktable_lookup_key(t, key);
1305
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001306 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001307 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001308 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001309
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001310 if (!ts) /* key not present */
1311 return 1;
1312
1313 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_CONN_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001314 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001315 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001316
Daniel Corbett3e60b112018-05-27 09:47:12 -04001317 stktable_release(t, ts);
1318 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001319}
1320
1321/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1322 * it up into this table. Returns the number of concurrent connections for the
1323 * key if the key is present in the table, otherwise zero, so that comparisons
1324 * can be easily performed. If the inspected parameter is not stored in the
1325 * table, <not found> is returned.
1326 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001327static int sample_conv_table_conn_cur(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001328{
1329 struct stktable *t;
1330 struct stktable_key *key;
1331 struct stksess *ts;
1332 void *ptr;
1333
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001334 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001335
1336 key = smp_to_stkey(smp, t);
1337 if (!key)
1338 return 0;
1339
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001340 ts = stktable_lookup_key(t, key);
1341
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001342 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001343 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001344 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001345
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001346 if (!ts) /* key not present */
1347 return 1;
1348
1349 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_CONN_CUR);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001350 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001351 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001352
Daniel Corbett3e60b112018-05-27 09:47:12 -04001353 stktable_release(t, ts);
1354 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001355}
1356
1357/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1358 * it up into this table. Returns the rate of incoming connections from the key
1359 * if the key is present in the table, otherwise zero, so that comparisons can
1360 * be easily performed. If the inspected parameter is not stored in the table,
1361 * <not found> is returned.
1362 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001363static int sample_conv_table_conn_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001364{
1365 struct stktable *t;
1366 struct stktable_key *key;
1367 struct stksess *ts;
1368 void *ptr;
1369
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001370 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001371
1372 key = smp_to_stkey(smp, t);
1373 if (!key)
1374 return 0;
1375
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001376 ts = stktable_lookup_key(t, key);
1377
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001378 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001379 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001380 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001381
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001382 if (!ts) /* key not present */
1383 return 1;
1384
1385 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_CONN_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001386 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001387 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Daniel Corbett3e60b112018-05-27 09:47:12 -04001388 t->data_arg[STKTABLE_DT_CONN_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001389
Daniel Corbett3e60b112018-05-27 09:47:12 -04001390 stktable_release(t, ts);
1391 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001392}
1393
1394/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1395 * it up into this table. Returns the data rate sent to clients in bytes/s
1396 * if the key is present in the table, otherwise zero, so that comparisons can
1397 * be easily performed. If the inspected parameter is not stored in the table,
1398 * <not found> is returned.
1399 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001400static int sample_conv_table_bytes_out_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001401{
1402 struct stktable *t;
1403 struct stktable_key *key;
1404 struct stksess *ts;
1405 void *ptr;
1406
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001407 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001408
1409 key = smp_to_stkey(smp, t);
1410 if (!key)
1411 return 0;
1412
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001413 ts = stktable_lookup_key(t, key);
1414
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001415 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001416 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001417 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001418
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001419 if (!ts) /* key not present */
1420 return 1;
1421
1422 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_OUT_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001423 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001424 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Daniel Corbett3e60b112018-05-27 09:47:12 -04001425 t->data_arg[STKTABLE_DT_BYTES_OUT_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001426
Daniel Corbett3e60b112018-05-27 09:47:12 -04001427 stktable_release(t, ts);
1428 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001429}
1430
Emeric Brun877b0b52021-06-30 18:57:49 +02001431/* Casts sample <smp> to the type of the table specified in arg_p(1), and looks
1432 * it up into this table. Returns the value of the GPT[arg_p(0)] tag for the key
1433 * if the key is present in the table, otherwise false, so that comparisons can
1434 * be easily performed. If the inspected parameter is not stored in the table,
1435 * <not found> is returned.
1436 */
1437static int sample_conv_table_gpt(const struct arg *arg_p, struct sample *smp, void *private)
1438{
1439 struct stktable *t;
1440 struct stktable_key *key;
1441 struct stksess *ts;
1442 void *ptr;
1443 unsigned int idx;
1444
1445 idx = arg_p[0].data.sint;
1446
1447 t = arg_p[1].data.t;
1448
1449 key = smp_to_stkey(smp, t);
1450 if (!key)
1451 return 0;
1452
1453 ts = stktable_lookup_key(t, key);
1454
1455 smp->flags = SMP_F_VOL_TEST;
1456 smp->data.type = SMP_T_SINT;
1457 smp->data.u.sint = 0;
1458
1459 if (!ts) /* key not present */
1460 return 1;
1461
1462 ptr = stktable_data_ptr_idx(t, ts, STKTABLE_DT_GPT, idx);
1463 if (ptr)
1464 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
1465
1466 stktable_release(t, ts);
1467 return !!ptr;
1468}
1469
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001470/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001471 * it up into this table. Returns the value of the GPT0 tag for the key
1472 * if the key is present in the table, otherwise false, so that comparisons can
1473 * be easily performed. If the inspected parameter is not stored in the table,
1474 * <not found> is returned.
1475 */
1476static int sample_conv_table_gpt0(const struct arg *arg_p, struct sample *smp, void *private)
1477{
1478 struct stktable *t;
1479 struct stktable_key *key;
1480 struct stksess *ts;
1481 void *ptr;
1482
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001483 t = arg_p[0].data.t;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001484
1485 key = smp_to_stkey(smp, t);
1486 if (!key)
1487 return 0;
1488
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001489 ts = stktable_lookup_key(t, key);
1490
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001491 smp->flags = SMP_F_VOL_TEST;
1492 smp->data.type = SMP_T_SINT;
1493 smp->data.u.sint = 0;
1494
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001495 if (!ts) /* key not present */
1496 return 1;
1497
1498 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPT0);
Emeric Brunf7ab0bf2021-06-30 18:58:22 +02001499 if (!ptr)
1500 ptr = stktable_data_ptr_idx(t, ts, STKTABLE_DT_GPT, 0);
1501
Daniel Corbett3e60b112018-05-27 09:47:12 -04001502 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001503 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001504
Daniel Corbett3e60b112018-05-27 09:47:12 -04001505 stktable_release(t, ts);
1506 return !!ptr;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001507}
1508
Emeric Brun4d7ada82021-06-30 19:04:16 +02001509/* Casts sample <smp> to the type of the table specified in arg_p(1), and looks
1510 * it up into this table. Returns the value of the GPC[arg_p(0)] counter for the key
1511 * if the key is present in the table, otherwise zero, so that comparisons can
1512 * be easily performed. If the inspected parameter is not stored in the table,
1513 * <not found> is returned.
1514 */
1515static int sample_conv_table_gpc(const struct arg *arg_p, struct sample *smp, void *private)
1516{
1517 struct stktable *t;
1518 struct stktable_key *key;
1519 struct stksess *ts;
1520 void *ptr;
1521 unsigned int idx;
1522
1523 idx = arg_p[0].data.sint;
1524
1525 t = arg_p[1].data.t;
1526
1527 key = smp_to_stkey(smp, t);
1528 if (!key)
1529 return 0;
1530
1531 ts = stktable_lookup_key(t, key);
1532
1533 smp->flags = SMP_F_VOL_TEST;
1534 smp->data.type = SMP_T_SINT;
1535 smp->data.u.sint = 0;
1536
1537 if (!ts) /* key not present */
1538 return 1;
1539
1540 ptr = stktable_data_ptr_idx(t, ts, STKTABLE_DT_GPC, idx);
1541 if (ptr)
1542 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
1543
1544 stktable_release(t, ts);
1545 return !!ptr;
1546}
1547
1548/* Casts sample <smp> to the type of the table specified in arg_p(1), and looks
1549 * it up into this table. Returns the event rate of the GPC[arg_p(0)] counter
1550 * for the key if the key is present in the table, otherwise zero, so that
1551 * comparisons can be easily performed. If the inspected parameter is not
1552 * stored in the table, <not found> is returned.
1553 */
1554static int sample_conv_table_gpc_rate(const struct arg *arg_p, struct sample *smp, void *private)
1555{
1556 struct stktable *t;
1557 struct stktable_key *key;
1558 struct stksess *ts;
1559 void *ptr;
1560 unsigned int idx;
1561
1562 idx = arg_p[0].data.sint;
1563
1564 t = arg_p[1].data.t;
1565
1566 key = smp_to_stkey(smp, t);
1567 if (!key)
1568 return 0;
1569
1570 ts = stktable_lookup_key(t, key);
1571
1572 smp->flags = SMP_F_VOL_TEST;
1573 smp->data.type = SMP_T_SINT;
1574 smp->data.u.sint = 0;
1575
1576 if (!ts) /* key not present */
1577 return 1;
1578
1579 ptr = stktable_data_ptr_idx(t, ts, STKTABLE_DT_GPC_RATE, idx);
1580 if (ptr)
1581 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
1582 t->data_arg[STKTABLE_DT_GPC_RATE].u);
1583
1584 stktable_release(t, ts);
1585 return !!ptr;
1586}
1587
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001588/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001589 * it up into this table. Returns the value of the GPC0 counter for the key
1590 * if the key is present in the table, otherwise zero, so that comparisons can
1591 * be easily performed. If the inspected parameter is not stored in the table,
1592 * <not found> is returned.
1593 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001594static int sample_conv_table_gpc0(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001595{
1596 struct stktable *t;
1597 struct stktable_key *key;
1598 struct stksess *ts;
1599 void *ptr;
1600
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001601 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001602
1603 key = smp_to_stkey(smp, t);
1604 if (!key)
1605 return 0;
1606
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001607 ts = stktable_lookup_key(t, key);
1608
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001609 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001610 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001611 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001612
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001613 if (!ts) /* key not present */
1614 return 1;
1615
1616 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPC0);
Emeric Brun726783d2021-06-30 19:06:43 +02001617 if (!ptr) {
1618 /* fallback on the gpc array */
1619 ptr = stktable_data_ptr_idx(t, ts, STKTABLE_DT_GPC, 0);
1620 }
1621
Daniel Corbett3e60b112018-05-27 09:47:12 -04001622 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001623 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001624
Daniel Corbett3e60b112018-05-27 09:47:12 -04001625 stktable_release(t, ts);
1626 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001627}
1628
1629/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1630 * it up into this table. Returns the event rate of the GPC0 counter for the key
1631 * if the key is present in the table, otherwise zero, so that comparisons can
1632 * be easily performed. If the inspected parameter is not stored in the table,
1633 * <not found> is returned.
1634 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001635static int sample_conv_table_gpc0_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001636{
1637 struct stktable *t;
1638 struct stktable_key *key;
1639 struct stksess *ts;
1640 void *ptr;
1641
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001642 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001643
1644 key = smp_to_stkey(smp, t);
1645 if (!key)
1646 return 0;
1647
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001648 ts = stktable_lookup_key(t, key);
1649
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001650 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001651 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001652 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001653
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001654 if (!ts) /* key not present */
1655 return 1;
1656
1657 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPC0_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001658 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001659 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Daniel Corbett3e60b112018-05-27 09:47:12 -04001660 t->data_arg[STKTABLE_DT_GPC0_RATE].u);
Emeric Brun726783d2021-06-30 19:06:43 +02001661 else {
1662 /* fallback on the gpc array */
1663 ptr = stktable_data_ptr_idx(t, ts, STKTABLE_DT_GPC_RATE, 0);
1664 if (ptr)
1665 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
1666 t->data_arg[STKTABLE_DT_GPC_RATE].u);
1667 }
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001668
Daniel Corbett3e60b112018-05-27 09:47:12 -04001669 stktable_release(t, ts);
1670 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001671}
1672
1673/* 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 +01001674 * it up into this table. Returns the value of the GPC1 counter for the key
1675 * if the key is present in the table, otherwise zero, so that comparisons can
1676 * be easily performed. If the inspected parameter is not stored in the table,
1677 * <not found> is returned.
1678 */
1679static int sample_conv_table_gpc1(const struct arg *arg_p, struct sample *smp, void *private)
1680{
1681 struct stktable *t;
1682 struct stktable_key *key;
1683 struct stksess *ts;
1684 void *ptr;
1685
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001686 t = arg_p[0].data.t;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001687
1688 key = smp_to_stkey(smp, t);
1689 if (!key)
1690 return 0;
1691
1692 ts = stktable_lookup_key(t, key);
1693
1694 smp->flags = SMP_F_VOL_TEST;
1695 smp->data.type = SMP_T_SINT;
1696 smp->data.u.sint = 0;
1697
1698 if (!ts) /* key not present */
1699 return 1;
1700
1701 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPC1);
Emeric Brun726783d2021-06-30 19:06:43 +02001702 if (!ptr) {
1703 /* fallback on the gpc array */
1704 ptr = stktable_data_ptr_idx(t, ts, STKTABLE_DT_GPC, 1);
1705 }
1706
Daniel Corbett3e60b112018-05-27 09:47:12 -04001707 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001708 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001709
Daniel Corbett3e60b112018-05-27 09:47:12 -04001710 stktable_release(t, ts);
1711 return !!ptr;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001712}
1713
1714/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1715 * it up into this table. Returns the event rate of the GPC1 counter for the key
1716 * if the key is present in the table, otherwise zero, so that comparisons can
1717 * be easily performed. If the inspected parameter is not stored in the table,
1718 * <not found> is returned.
1719 */
1720static int sample_conv_table_gpc1_rate(const struct arg *arg_p, struct sample *smp, void *private)
1721{
1722 struct stktable *t;
1723 struct stktable_key *key;
1724 struct stksess *ts;
1725 void *ptr;
1726
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001727 t = arg_p[0].data.t;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001728
1729 key = smp_to_stkey(smp, t);
1730 if (!key)
1731 return 0;
1732
1733 ts = stktable_lookup_key(t, key);
1734
1735 smp->flags = SMP_F_VOL_TEST;
1736 smp->data.type = SMP_T_SINT;
1737 smp->data.u.sint = 0;
1738
1739 if (!ts) /* key not present */
1740 return 1;
1741
1742 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPC1_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001743 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001744 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Daniel Corbett3e60b112018-05-27 09:47:12 -04001745 t->data_arg[STKTABLE_DT_GPC1_RATE].u);
Emeric Brun726783d2021-06-30 19:06:43 +02001746 else {
1747 /* fallback on the gpc array */
1748 ptr = stktable_data_ptr_idx(t, ts, STKTABLE_DT_GPC_RATE, 1);
1749 if (ptr)
1750 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
1751 t->data_arg[STKTABLE_DT_GPC_RATE].u);
1752 }
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001753
Daniel Corbett3e60b112018-05-27 09:47:12 -04001754 stktable_release(t, ts);
1755 return !!ptr;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001756}
1757
1758/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001759 * it up into this table. Returns the cumulated number of HTTP request errors
1760 * for the key if the key is present in the table, otherwise zero, so that
1761 * comparisons can be easily performed. If the inspected parameter is not stored
1762 * in the table, <not found> is returned.
1763 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001764static int sample_conv_table_http_err_cnt(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001765{
1766 struct stktable *t;
1767 struct stktable_key *key;
1768 struct stksess *ts;
1769 void *ptr;
1770
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001771 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001772
1773 key = smp_to_stkey(smp, t);
1774 if (!key)
1775 return 0;
1776
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001777 ts = stktable_lookup_key(t, key);
1778
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001779 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001780 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001781 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001782
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001783 if (!ts) /* key not present */
1784 return 1;
1785
1786 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_ERR_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001787 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001788 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001789
Daniel Corbett3e60b112018-05-27 09:47:12 -04001790 stktable_release(t, ts);
1791 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001792}
1793
1794/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1795 * it up into this table. Returns the HTTP request error rate the key
1796 * if the key is present in the table, otherwise zero, so that comparisons can
1797 * be easily performed. If the inspected parameter is not stored in the table,
1798 * <not found> is returned.
1799 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001800static int sample_conv_table_http_err_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001801{
1802 struct stktable *t;
1803 struct stktable_key *key;
1804 struct stksess *ts;
1805 void *ptr;
1806
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001807 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001808
1809 key = smp_to_stkey(smp, t);
1810 if (!key)
1811 return 0;
1812
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001813 ts = stktable_lookup_key(t, key);
1814
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001815 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001816 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001817 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001818
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001819 if (!ts) /* key not present */
1820 return 1;
1821
1822 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_ERR_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001823 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001824 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Daniel Corbett3e60b112018-05-27 09:47:12 -04001825 t->data_arg[STKTABLE_DT_HTTP_ERR_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001826
Daniel Corbett3e60b112018-05-27 09:47:12 -04001827 stktable_release(t, ts);
1828 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001829}
1830
1831/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Willy Tarreau826f3ab2021-02-10 12:07:15 +01001832 * it up into this table. Returns the cumulated number of HTTP response failures
1833 * for the key if the key is present in the table, otherwise zero, so that
1834 * comparisons can be easily performed. If the inspected parameter is not stored
1835 * in the table, <not found> is returned.
1836 */
1837static int sample_conv_table_http_fail_cnt(const struct arg *arg_p, struct sample *smp, void *private)
1838{
1839 struct stktable *t;
1840 struct stktable_key *key;
1841 struct stksess *ts;
1842 void *ptr;
1843
1844 t = arg_p[0].data.t;
1845
1846 key = smp_to_stkey(smp, t);
1847 if (!key)
1848 return 0;
1849
1850 ts = stktable_lookup_key(t, key);
1851
1852 smp->flags = SMP_F_VOL_TEST;
1853 smp->data.type = SMP_T_SINT;
1854 smp->data.u.sint = 0;
1855
1856 if (!ts) /* key not present */
1857 return 1;
1858
1859 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_FAIL_CNT);
1860 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001861 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Willy Tarreau826f3ab2021-02-10 12:07:15 +01001862
1863 stktable_release(t, ts);
1864 return !!ptr;
1865}
1866
1867/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1868 * it up into this table. Returns the HTTP response failure rate for the key
1869 * if the key is present in the table, otherwise zero, so that comparisons can
1870 * be easily performed. If the inspected parameter is not stored in the table,
1871 * <not found> is returned.
1872 */
1873static int sample_conv_table_http_fail_rate(const struct arg *arg_p, struct sample *smp, void *private)
1874{
1875 struct stktable *t;
1876 struct stktable_key *key;
1877 struct stksess *ts;
1878 void *ptr;
1879
1880 t = arg_p[0].data.t;
1881
1882 key = smp_to_stkey(smp, t);
1883 if (!key)
1884 return 0;
1885
1886 ts = stktable_lookup_key(t, key);
1887
1888 smp->flags = SMP_F_VOL_TEST;
1889 smp->data.type = SMP_T_SINT;
1890 smp->data.u.sint = 0;
1891
1892 if (!ts) /* key not present */
1893 return 1;
1894
1895 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_FAIL_RATE);
1896 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001897 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Willy Tarreau826f3ab2021-02-10 12:07:15 +01001898 t->data_arg[STKTABLE_DT_HTTP_FAIL_RATE].u);
1899
1900 stktable_release(t, ts);
1901 return !!ptr;
1902}
1903
1904/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001905 * it up into this table. Returns the cumulated number of HTTP request for the
1906 * key if the key is present in the table, otherwise zero, so that comparisons
1907 * can be easily performed. If the inspected parameter is not stored in the
1908 * table, <not found> is returned.
1909 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001910static int sample_conv_table_http_req_cnt(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001911{
1912 struct stktable *t;
1913 struct stktable_key *key;
1914 struct stksess *ts;
1915 void *ptr;
1916
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001917 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001918
1919 key = smp_to_stkey(smp, t);
1920 if (!key)
1921 return 0;
1922
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001923 ts = stktable_lookup_key(t, key);
1924
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001925 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001926 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001927 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001928
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001929 if (!ts) /* key not present */
1930 return 1;
1931
1932 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_REQ_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001933 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001934 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001935
Daniel Corbett3e60b112018-05-27 09:47:12 -04001936 stktable_release(t, ts);
1937 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001938}
1939
1940/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1941 * it up into this table. Returns the HTTP request rate the key if the key is
1942 * present in the table, otherwise zero, so that comparisons can be easily
1943 * performed. If the inspected parameter is not stored in the table, <not found>
1944 * is returned.
1945 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001946static int sample_conv_table_http_req_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001947{
1948 struct stktable *t;
1949 struct stktable_key *key;
1950 struct stksess *ts;
1951 void *ptr;
1952
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001953 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001954
1955 key = smp_to_stkey(smp, t);
1956 if (!key)
1957 return 0;
1958
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001959 ts = stktable_lookup_key(t, key);
1960
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001961 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001962 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001963 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001964
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001965 if (!ts) /* key not present */
1966 return 1;
1967
1968 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_REQ_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001969 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001970 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Daniel Corbett3e60b112018-05-27 09:47:12 -04001971 t->data_arg[STKTABLE_DT_HTTP_REQ_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001972
Daniel Corbett3e60b112018-05-27 09:47:12 -04001973 stktable_release(t, ts);
1974 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001975}
1976
1977/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1978 * it up into this table. Returns the volume of datareceived from clients in kbytes
1979 * if the key is present in the table, otherwise zero, so that comparisons can
1980 * be easily performed. If the inspected parameter is not stored in the table,
1981 * <not found> is returned.
1982 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001983static int sample_conv_table_kbytes_in(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001984{
1985 struct stktable *t;
1986 struct stktable_key *key;
1987 struct stksess *ts;
1988 void *ptr;
1989
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001990 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001991
1992 key = smp_to_stkey(smp, t);
1993 if (!key)
1994 return 0;
1995
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001996 ts = stktable_lookup_key(t, key);
1997
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001998 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001999 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02002000 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002001
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002002 if (!ts) /* key not present */
2003 return 1;
2004
2005 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_IN_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04002006 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002007 smp->data.u.sint = stktable_data_cast(ptr, std_t_ull) >> 10;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002008
Daniel Corbett3e60b112018-05-27 09:47:12 -04002009 stktable_release(t, ts);
2010 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002011}
2012
2013/* Casts sample <smp> to the type of the table specified in arg(0), and looks
2014 * it up into this table. Returns the volume of data sent to clients in kbytes
2015 * if the key is present in the table, otherwise zero, so that comparisons can
2016 * be easily performed. If the inspected parameter is not stored in the table,
2017 * <not found> is returned.
2018 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02002019static int sample_conv_table_kbytes_out(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002020{
2021 struct stktable *t;
2022 struct stktable_key *key;
2023 struct stksess *ts;
2024 void *ptr;
2025
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002026 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002027
2028 key = smp_to_stkey(smp, t);
2029 if (!key)
2030 return 0;
2031
Willy Tarreauf0c730a2016-05-25 17:07:56 +02002032 ts = stktable_lookup_key(t, key);
2033
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002034 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02002035 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02002036 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002037
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002038 if (!ts) /* key not present */
2039 return 1;
2040
2041 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_OUT_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04002042 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002043 smp->data.u.sint = stktable_data_cast(ptr, std_t_ull) >> 10;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002044
Daniel Corbett3e60b112018-05-27 09:47:12 -04002045 stktable_release(t, ts);
2046 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002047}
2048
2049/* Casts sample <smp> to the type of the table specified in arg(0), and looks
2050 * it up into this table. Returns the server ID associated with the key if the
2051 * key is present in the table, otherwise zero, so that comparisons can be
2052 * easily performed. If the inspected parameter is not stored in the table,
2053 * <not found> is returned.
2054 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02002055static int sample_conv_table_server_id(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002056{
2057 struct stktable *t;
2058 struct stktable_key *key;
2059 struct stksess *ts;
2060 void *ptr;
2061
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002062 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002063
2064 key = smp_to_stkey(smp, t);
2065 if (!key)
2066 return 0;
2067
Willy Tarreauf0c730a2016-05-25 17:07:56 +02002068 ts = stktable_lookup_key(t, key);
2069
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002070 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02002071 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02002072 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002073
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002074 if (!ts) /* key not present */
2075 return 1;
2076
2077 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_SERVER_ID);
Daniel Corbett3e60b112018-05-27 09:47:12 -04002078 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002079 smp->data.u.sint = stktable_data_cast(ptr, std_t_sint);
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 cumulated number of sessions for the
2087 * key if the key is present in the table, otherwise zero, so that comparisons
2088 * can be easily performed. If the inspected parameter is not stored in the
2089 * table, <not found> is returned.
2090 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02002091static int sample_conv_table_sess_cnt(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_SESS_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_uint);
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 session rate the key if the key is
2123 * present in the table, otherwise zero, so that comparisons can be easily
2124 * performed. If the inspected parameter is not stored in the table, <not found>
2125 * is returned.
2126 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02002127static int sample_conv_table_sess_rate(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_SESS_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04002150 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002151 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Daniel Corbett3e60b112018-05-27 09:47:12 -04002152 t->data_arg[STKTABLE_DT_SESS_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002153
Daniel Corbett3e60b112018-05-27 09:47:12 -04002154 stktable_release(t, ts);
2155 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002156}
2157
2158/* Casts sample <smp> to the type of the table specified in arg(0), and looks
2159 * it up into this table. Returns the amount of concurrent connections tracking
2160 * the same key if the key is present in the table, otherwise zero, so that
2161 * comparisons can be easily performed. If the inspected parameter is not
2162 * stored in the table, <not found> is returned.
2163 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02002164static int sample_conv_table_trackers(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002165{
2166 struct stktable *t;
2167 struct stktable_key *key;
2168 struct stksess *ts;
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
Tim Duesterhus65189c12018-06-26 15:57:29 +02002182 if (!ts)
2183 return 1;
2184
2185 smp->data.u.sint = ts->ref_cnt;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002186
Daniel Corbett3e60b112018-05-27 09:47:12 -04002187 stktable_release(t, ts);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002188 return 1;
2189}
2190
Emeric Brun4d7ada82021-06-30 19:04:16 +02002191/* This function increments the gpc counter at index 'rule->arg.gpc.idx' of the
2192 * array on the tracksc counter of index 'rule->arg.gpc.sc' stored into the
2193 * <stream> or directly in the session <sess> if <stream> is set to NULL
2194 *
2195 * This function always returns ACT_RET_CONT and parameter flags is unused.
2196 */
2197static enum act_return action_inc_gpc(struct act_rule *rule, struct proxy *px,
2198 struct session *sess, struct stream *s, int flags)
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002199{
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002200 struct stksess *ts;
2201 struct stkctr *stkctr;
2202
2203 /* Extract the stksess, return OK if no stksess available. */
2204 if (s)
2205 stkctr = &s->stkctr[rule->arg.gpc.sc];
2206 else
2207 stkctr = &sess->stkctr[rule->arg.gpc.sc];
Willy Tarreau79c1e912016-01-25 14:54:45 +01002208
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002209 ts = stkctr_entry(stkctr);
Willy Tarreau79c1e912016-01-25 14:54:45 +01002210 if (ts) {
2211 void *ptr1, *ptr2;
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002212
Emeric Brun4d7ada82021-06-30 19:04:16 +02002213 /* First, update gpc_rate if it's tracked. Second, update its gpc if tracked. */
2214 ptr1 = stktable_data_ptr_idx(stkctr->table, ts, STKTABLE_DT_GPC_RATE, rule->arg.gpc.idx);
2215 ptr2 = stktable_data_ptr_idx(stkctr->table, ts, STKTABLE_DT_GPC, rule->arg.gpc.idx);
2216
Emeric Brun819fc6f2017-06-13 19:37:32 +02002217 if (ptr1 || ptr2) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002218 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002219
2220 if (ptr1)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002221 update_freq_ctr_period(&stktable_data_cast(ptr1, std_t_frqp),
Emeric Brun4d7ada82021-06-30 19:04:16 +02002222 stkctr->table->data_arg[STKTABLE_DT_GPC_RATE].u, 1);
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002223
Emeric Brun819fc6f2017-06-13 19:37:32 +02002224 if (ptr2)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002225 stktable_data_cast(ptr2, std_t_uint)++;
Willy Tarreau79c1e912016-01-25 14:54:45 +01002226
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002227 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002228
2229 /* If data was modified, we need to touch to re-schedule sync */
2230 stktable_touch_local(stkctr->table, ts, 0);
2231 }
Willy Tarreau79c1e912016-01-25 14:54:45 +01002232 }
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002233 return ACT_RET_CONT;
2234}
2235
Emeric Brun4d7ada82021-06-30 19:04:16 +02002236/* Same as action_inc_gpc() but for gpc0 only */
2237static enum act_return action_inc_gpc0(struct act_rule *rule, struct proxy *px,
2238 struct session *sess, struct stream *s, int flags)
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002239{
Emeric Brun4d7ada82021-06-30 19:04:16 +02002240 struct stksess *ts;
2241 struct stkctr *stkctr;
Willy Tarreau5b654ad2021-07-06 18:51:12 +02002242 unsigned int period = 0;
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002243
Emeric Brun4d7ada82021-06-30 19:04:16 +02002244 /* Extract the stksess, return OK if no stksess available. */
2245 if (s)
2246 stkctr = &s->stkctr[rule->arg.gpc.sc];
2247 else
2248 stkctr = &sess->stkctr[rule->arg.gpc.sc];
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002249
Emeric Brun4d7ada82021-06-30 19:04:16 +02002250 ts = stkctr_entry(stkctr);
2251 if (ts) {
2252 void *ptr1, *ptr2;
2253
2254 /* First, update gpc0_rate if it's tracked. Second, update its gpc0 if tracked. */
2255 ptr1 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC0_RATE);
Emeric Brun726783d2021-06-30 19:06:43 +02002256 if (ptr1) {
2257 period = stkctr->table->data_arg[STKTABLE_DT_GPC0_RATE].u;
2258 }
2259 else {
2260 /* fallback on the gpc array */
2261 ptr1 = stktable_data_ptr_idx(stkctr->table, ts, STKTABLE_DT_GPC_RATE, 0);
2262 if (ptr1)
2263 period = stkctr->table->data_arg[STKTABLE_DT_GPC_RATE].u;
2264 }
2265
Emeric Brun4d7ada82021-06-30 19:04:16 +02002266 ptr2 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC0);
Emeric Brun726783d2021-06-30 19:06:43 +02002267 if (!ptr2) {
2268 /* fallback on the gpc array */
2269 ptr2 = stktable_data_ptr_idx(stkctr->table, ts, STKTABLE_DT_GPC, 0);
2270 }
2271
Emeric Brun4d7ada82021-06-30 19:04:16 +02002272 if (ptr1 || ptr2) {
2273 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
2274
2275 if (ptr1)
2276 update_freq_ctr_period(&stktable_data_cast(ptr1, std_t_frqp),
Emeric Brun726783d2021-06-30 19:06:43 +02002277 period, 1);
Emeric Brun4d7ada82021-06-30 19:04:16 +02002278
2279 if (ptr2)
2280 stktable_data_cast(ptr2, std_t_uint)++;
2281
2282 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
2283
2284 /* If data was modified, we need to touch to re-schedule sync */
2285 stktable_touch_local(stkctr->table, ts, 0);
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002286 }
2287 }
Emeric Brun4d7ada82021-06-30 19:04:16 +02002288 return ACT_RET_CONT;
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002289}
2290
Emeric Brun4d7ada82021-06-30 19:04:16 +02002291/* Same as action_inc_gpc() but for gpc1 only */
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002292static enum act_return action_inc_gpc1(struct act_rule *rule, struct proxy *px,
2293 struct session *sess, struct stream *s, int flags)
2294{
2295 struct stksess *ts;
2296 struct stkctr *stkctr;
Willy Tarreau5b654ad2021-07-06 18:51:12 +02002297 unsigned int period = 0;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002298
2299 /* Extract the stksess, return OK if no stksess available. */
2300 if (s)
2301 stkctr = &s->stkctr[rule->arg.gpc.sc];
2302 else
2303 stkctr = &sess->stkctr[rule->arg.gpc.sc];
2304
2305 ts = stkctr_entry(stkctr);
2306 if (ts) {
2307 void *ptr1, *ptr2;
2308
2309 /* First, update gpc1_rate if it's tracked. Second, update its gpc1 if tracked. */
2310 ptr1 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC1_RATE);
Emeric Brun726783d2021-06-30 19:06:43 +02002311 if (ptr1) {
2312 period = stkctr->table->data_arg[STKTABLE_DT_GPC1_RATE].u;
2313 }
2314 else {
2315 /* fallback on the gpc array */
2316 ptr1 = stktable_data_ptr_idx(stkctr->table, ts, STKTABLE_DT_GPC_RATE, 1);
2317 if (ptr1)
2318 period = stkctr->table->data_arg[STKTABLE_DT_GPC_RATE].u;
2319 }
2320
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002321 ptr2 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC1);
Emeric Brun726783d2021-06-30 19:06:43 +02002322 if (!ptr2) {
2323 /* fallback on the gpc array */
2324 ptr2 = stktable_data_ptr_idx(stkctr->table, ts, STKTABLE_DT_GPC, 1);
2325 }
2326
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002327 if (ptr1 || ptr2) {
2328 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
2329
2330 if (ptr1)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002331 update_freq_ctr_period(&stktable_data_cast(ptr1, std_t_frqp),
Emeric Brun726783d2021-06-30 19:06:43 +02002332 period, 1);
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002333
2334 if (ptr2)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002335 stktable_data_cast(ptr2, std_t_uint)++;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002336
2337 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
2338
2339 /* If data was modified, we need to touch to re-schedule sync */
2340 stktable_touch_local(stkctr->table, ts, 0);
2341 }
2342 }
2343 return ACT_RET_CONT;
2344}
2345
Emeric Brun4d7ada82021-06-30 19:04:16 +02002346/* This function is a common parser for actions incrementing the GPC
2347 * (General Purpose Counters). It understands the formats:
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002348 *
Emeric Brun4d7ada82021-06-30 19:04:16 +02002349 * sc-inc-gpc(<gpc IDX>,<track ID>)
2350 * sc-inc-gpc0([<track ID>])
2351 * sc-inc-gpc1([<track ID>])
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002352 *
Emeric Brun4d7ada82021-06-30 19:04:16 +02002353 * It returns ACT_RET_PRS_ERR if fails and <err> is filled with an error
2354 * message. Otherwise it returns ACT_RET_PRS_OK.
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002355 */
Emeric Brun4d7ada82021-06-30 19:04:16 +02002356static enum act_parse_ret parse_inc_gpc(const char **args, int *arg, struct proxy *px,
2357 struct act_rule *rule, char **err)
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002358{
2359 const char *cmd_name = args[*arg-1];
2360 char *error;
2361
Emeric Brun4d7ada82021-06-30 19:04:16 +02002362 cmd_name += strlen("sc-inc-gpc");
2363 if (*cmd_name == '(') {
2364 cmd_name++; /* skip the '(' */
2365 rule->arg.gpc.idx = strtoul(cmd_name, &error, 10); /* Convert stick table id. */
2366 if (*error != ',') {
2367 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 +01002368 return ACT_RET_PRS_ERR;
2369 }
Emeric Brun4d7ada82021-06-30 19:04:16 +02002370 else {
2371 cmd_name = error + 1; /* skip the ',' */
2372 rule->arg.gpc.sc = strtol(cmd_name, &error, 10); /* Convert stick table id. */
2373 if (*error != ')') {
2374 memprintf(err, "invalid stick table track ID '%s'. Expects sc-inc-gpc(<GPC ID>,<Track ID>)", args[*arg-1]);
2375 return ACT_RET_PRS_ERR;
2376 }
2377
2378 if (rule->arg.gpc.sc >= MAX_SESS_STKCTR) {
2379 memprintf(err, "invalid stick table track ID '%s'. The max allowed ID is %d",
2380 args[*arg-1], MAX_SESS_STKCTR-1);
2381 return ACT_RET_PRS_ERR;
2382 }
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002383 }
Emeric Brun4d7ada82021-06-30 19:04:16 +02002384 rule->action_ptr = action_inc_gpc;
2385 }
2386 else if (*cmd_name == '0' ||*cmd_name == '1') {
2387 char c = *cmd_name;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002388
Emeric Brun4d7ada82021-06-30 19:04:16 +02002389 cmd_name++;
2390 if (*cmd_name == '\0') {
2391 /* default stick table id. */
2392 rule->arg.gpc.sc = 0;
2393 } else {
2394 /* parse the stick table id. */
2395 if (*cmd_name != '(') {
2396 memprintf(err, "invalid stick table track ID. Expects %s(<Track ID>)", args[*arg-1]);
2397 return ACT_RET_PRS_ERR;
2398 }
2399 cmd_name++; /* jump the '(' */
2400 rule->arg.gpc.sc = strtol(cmd_name, &error, 10); /* Convert stick table id. */
2401 if (*error != ')') {
2402 memprintf(err, "invalid stick table track ID. Expects %s(<Track ID>)", args[*arg-1]);
2403 return ACT_RET_PRS_ERR;
2404 }
2405
2406 if (rule->arg.gpc.sc >= MAX_SESS_STKCTR) {
2407 memprintf(err, "invalid stick table track ID. The max allowed ID is %d",
2408 MAX_SESS_STKCTR-1);
2409 return ACT_RET_PRS_ERR;
2410 }
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002411 }
Emeric Brun4d7ada82021-06-30 19:04:16 +02002412 if (c == '1')
2413 rule->action_ptr = action_inc_gpc1;
2414 else
2415 rule->action_ptr = action_inc_gpc0;
2416 }
2417 else {
2418 /* default stick table id. */
2419 memprintf(err, "invalid gpc ID '%s'. Expects sc-set-gpc(<GPC ID>,<Track ID>)", args[*arg-1]);
2420 return ACT_RET_PRS_ERR;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002421 }
2422 rule->action = ACT_CUSTOM;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002423 return ACT_RET_PRS_OK;
2424}
2425
Emeric Brun877b0b52021-06-30 18:57:49 +02002426/* This function sets the gpt at index 'rule->arg.gpt.idx' of the array on the
2427 * tracksc counter of index 'rule->arg.gpt.sc' stored into the <stream> or
2428 * directly in the session <sess> if <stream> is set to NULL. This gpt is
2429 * set to the value computed by the expression 'rule->arg.gpt.expr' or if
2430 * 'rule->arg.gpt.expr' is null directly to the value of 'rule->arg.gpt.value'.
2431 *
2432 * This function always returns ACT_RET_CONT and parameter flags is unused.
2433 */
2434static enum act_return action_set_gpt(struct act_rule *rule, struct proxy *px,
2435 struct session *sess, struct stream *s, int flags)
2436{
2437 void *ptr;
2438 struct stksess *ts;
2439 struct stkctr *stkctr;
2440 unsigned int value = 0;
2441 struct sample *smp;
2442 int smp_opt_dir;
2443
2444 /* Extract the stksess, return OK if no stksess available. */
2445 if (s)
2446 stkctr = &s->stkctr[rule->arg.gpt.sc];
2447 else
2448 stkctr = &sess->stkctr[rule->arg.gpt.sc];
2449
2450 ts = stkctr_entry(stkctr);
2451 if (!ts)
2452 return ACT_RET_CONT;
2453
2454 /* Store the sample in the required sc, and ignore errors. */
2455 ptr = stktable_data_ptr_idx(stkctr->table, ts, STKTABLE_DT_GPT, rule->arg.gpt.idx);
2456 if (ptr) {
2457
2458 if (!rule->arg.gpt.expr)
2459 value = (unsigned int)(rule->arg.gpt.value);
2460 else {
2461 switch (rule->from) {
2462 case ACT_F_TCP_REQ_SES: smp_opt_dir = SMP_OPT_DIR_REQ; break;
2463 case ACT_F_TCP_REQ_CNT: smp_opt_dir = SMP_OPT_DIR_REQ; break;
2464 case ACT_F_TCP_RES_CNT: smp_opt_dir = SMP_OPT_DIR_RES; break;
2465 case ACT_F_HTTP_REQ: smp_opt_dir = SMP_OPT_DIR_REQ; break;
2466 case ACT_F_HTTP_RES: smp_opt_dir = SMP_OPT_DIR_RES; break;
2467 default:
2468 send_log(px, LOG_ERR, "stick table: internal error while setting gpt%u.", rule->arg.gpt.idx);
2469 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))
2470 ha_alert("stick table: internal error while executing setting gpt%u.\n", rule->arg.gpt.idx);
2471 return ACT_RET_CONT;
2472 }
2473
2474 /* Fetch and cast the expression. */
2475 smp = sample_fetch_as_type(px, sess, s, smp_opt_dir|SMP_OPT_FINAL, rule->arg.gpt.expr, SMP_T_SINT);
2476 if (!smp) {
2477 send_log(px, LOG_WARNING, "stick table: invalid expression or data type while setting gpt%u.", rule->arg.gpt.idx);
2478 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))
2479 ha_alert("stick table: invalid expression or data type while setting gpt%u.\n", rule->arg.gpt.idx);
2480 return ACT_RET_CONT;
2481 }
2482 value = (unsigned int)(smp->data.u.sint);
2483 }
2484
2485 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
2486
2487 stktable_data_cast(ptr, std_t_uint) = value;
2488
2489 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
2490
2491 stktable_touch_local(stkctr->table, ts, 0);
2492 }
2493
2494 return ACT_RET_CONT;
2495}
2496
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002497/* Always returns 1. */
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002498static enum act_return action_set_gpt0(struct act_rule *rule, struct proxy *px,
Willy Tarreau658b85b2015-09-27 10:00:49 +02002499 struct session *sess, struct stream *s, int flags)
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002500{
2501 void *ptr;
2502 struct stksess *ts;
2503 struct stkctr *stkctr;
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002504 unsigned int value = 0;
2505 struct sample *smp;
2506 int smp_opt_dir;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002507
2508 /* Extract the stksess, return OK if no stksess available. */
2509 if (s)
2510 stkctr = &s->stkctr[rule->arg.gpt.sc];
2511 else
2512 stkctr = &sess->stkctr[rule->arg.gpt.sc];
Willy Tarreau79c1e912016-01-25 14:54:45 +01002513
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002514 ts = stkctr_entry(stkctr);
2515 if (!ts)
2516 return ACT_RET_CONT;
2517
2518 /* Store the sample in the required sc, and ignore errors. */
2519 ptr = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPT0);
Emeric Brunf7ab0bf2021-06-30 18:58:22 +02002520 if (!ptr)
2521 ptr = stktable_data_ptr_idx(stkctr->table, ts, STKTABLE_DT_GPT, 0);
2522
Willy Tarreau79c1e912016-01-25 14:54:45 +01002523 if (ptr) {
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002524 if (!rule->arg.gpt.expr)
2525 value = (unsigned int)(rule->arg.gpt.value);
2526 else {
2527 switch (rule->from) {
2528 case ACT_F_TCP_REQ_SES: smp_opt_dir = SMP_OPT_DIR_REQ; break;
2529 case ACT_F_TCP_REQ_CNT: smp_opt_dir = SMP_OPT_DIR_REQ; break;
2530 case ACT_F_TCP_RES_CNT: smp_opt_dir = SMP_OPT_DIR_RES; break;
2531 case ACT_F_HTTP_REQ: smp_opt_dir = SMP_OPT_DIR_REQ; break;
2532 case ACT_F_HTTP_RES: smp_opt_dir = SMP_OPT_DIR_RES; break;
2533 default:
2534 send_log(px, LOG_ERR, "stick table: internal error while setting gpt0.");
2535 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))
2536 ha_alert("stick table: internal error while executing setting gpt0.\n");
2537 return ACT_RET_CONT;
2538 }
2539
2540 /* Fetch and cast the expression. */
2541 smp = sample_fetch_as_type(px, sess, s, smp_opt_dir|SMP_OPT_FINAL, rule->arg.gpt.expr, SMP_T_SINT);
2542 if (!smp) {
2543 send_log(px, LOG_WARNING, "stick table: invalid expression or data type while setting gpt0.");
2544 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))
2545 ha_alert("stick table: invalid expression or data type while setting gpt0.\n");
2546 return ACT_RET_CONT;
2547 }
2548 value = (unsigned int)(smp->data.u.sint);
2549 }
2550
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002551 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002552
Emeric Brun0e3457b2021-06-30 17:18:28 +02002553 stktable_data_cast(ptr, std_t_uint) = value;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002554
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002555 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002556
2557 stktable_touch_local(stkctr->table, ts, 0);
Willy Tarreau79c1e912016-01-25 14:54:45 +01002558 }
2559
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002560 return ACT_RET_CONT;
2561}
2562
Emeric Brun877b0b52021-06-30 18:57:49 +02002563/* This function is a parser for the "sc-set-gpt" and "sc-set-gpt0" actions.
2564 * It understands the formats:
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002565 *
Emeric Brun877b0b52021-06-30 18:57:49 +02002566 * sc-set-gpt(<gpt IDX>,<track ID>) <expression>
2567 * sc-set-gpt0(<track ID>) <expression>
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002568 *
Emeric Brun877b0b52021-06-30 18:57:49 +02002569 * It returns ACT_RET_PRS_ERR if fails and <err> is filled with an error message.
2570 * Otherwise, it returns ACT_RET_PRS_OK and the variable 'rule->arg.gpt.expr'
2571 * is filled with the pointer to the expression to execute or NULL if the arg
2572 * is directly an integer stored into 'rule->arg.gpt.value'.
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002573 */
Emeric Brun877b0b52021-06-30 18:57:49 +02002574static enum act_parse_ret parse_set_gpt(const char **args, int *arg, struct proxy *px,
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002575 struct act_rule *rule, char **err)
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002576{
2577 const char *cmd_name = args[*arg-1];
2578 char *error;
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002579 int smp_val;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002580
Emeric Brun877b0b52021-06-30 18:57:49 +02002581 cmd_name += strlen("sc-set-gpt");
2582 if (*cmd_name == '(') {
2583 cmd_name++; /* skip the '(' */
2584 rule->arg.gpt.idx = strtoul(cmd_name, &error, 10); /* Convert stick table id. */
2585 if (*error != ',') {
2586 memprintf(err, "Missing gpt ID '%s'. Expects sc-set-gpt(<GPT ID>,<Track ID>)", args[*arg-1]);
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002587 return ACT_RET_PRS_ERR;
2588 }
Emeric Brun877b0b52021-06-30 18:57:49 +02002589 else {
2590 cmd_name = error + 1; /* skip the ',' */
2591 rule->arg.gpt.sc = strtol(cmd_name, &error, 10); /* Convert stick table id. */
2592 if (*error != ')') {
2593 memprintf(err, "invalid stick table track ID '%s'. Expects sc-set-gpt(<GPT ID>,<Track ID>)", args[*arg-1]);
2594 return ACT_RET_PRS_ERR;
2595 }
2596
2597 if (rule->arg.gpt.sc >= MAX_SESS_STKCTR) {
2598 memprintf(err, "invalid stick table track ID '%s'. The max allowed ID is %d",
2599 args[*arg-1], MAX_SESS_STKCTR-1);
2600 return ACT_RET_PRS_ERR;
2601 }
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002602 }
Emeric Brun877b0b52021-06-30 18:57:49 +02002603 rule->action_ptr = action_set_gpt;
2604 }
2605 else if (*cmd_name == '0') {
2606 cmd_name++;
2607 if (*cmd_name == '\0') {
2608 /* default stick table id. */
2609 rule->arg.gpt.sc = 0;
2610 } else {
2611 /* parse the stick table id. */
2612 if (*cmd_name != '(') {
2613 memprintf(err, "invalid stick table track ID '%s'. Expects sc-set-gpt0(<Track ID>)", args[*arg-1]);
2614 return ACT_RET_PRS_ERR;
2615 }
2616 cmd_name++; /* jump the '(' */
2617 rule->arg.gpt.sc = strtol(cmd_name, &error, 10); /* Convert stick table id. */
2618 if (*error != ')') {
2619 memprintf(err, "invalid stick table track ID '%s'. Expects sc-set-gpt0(<Track ID>)", args[*arg-1]);
2620 return ACT_RET_PRS_ERR;
2621 }
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002622
Emeric Brun877b0b52021-06-30 18:57:49 +02002623 if (rule->arg.gpt.sc >= MAX_SESS_STKCTR) {
2624 memprintf(err, "invalid stick table track ID '%s'. The max allowed ID is %d",
2625 args[*arg-1], MAX_SESS_STKCTR-1);
2626 return ACT_RET_PRS_ERR;
2627 }
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002628 }
Emeric Brun877b0b52021-06-30 18:57:49 +02002629 rule->action_ptr = action_set_gpt0;
2630 }
2631 else {
2632 /* default stick table id. */
2633 memprintf(err, "invalid gpt ID '%s'. Expects sc-set-gpt(<GPT ID>,<Track ID>)", args[*arg-1]);
2634 return ACT_RET_PRS_ERR;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002635 }
2636
Willy Tarreauece4c4a2021-08-24 14:57:28 +02002637 /* value may be either an integer or an expression */
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002638 rule->arg.gpt.expr = NULL;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002639 rule->arg.gpt.value = strtol(args[*arg], &error, 10);
Willy Tarreauece4c4a2021-08-24 14:57:28 +02002640 if (*error == '\0') {
2641 /* valid integer, skip it */
2642 (*arg)++;
2643 } else {
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002644 rule->arg.gpt.expr = sample_parse_expr((char **)args, arg, px->conf.args.file,
Willy Tarreaue3b57bf2020-02-14 16:50:14 +01002645 px->conf.args.line, err, &px->conf.args, NULL);
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002646 if (!rule->arg.gpt.expr)
2647 return ACT_RET_PRS_ERR;
2648
2649 switch (rule->from) {
2650 case ACT_F_TCP_REQ_SES: smp_val = SMP_VAL_FE_SES_ACC; break;
2651 case ACT_F_TCP_REQ_CNT: smp_val = SMP_VAL_FE_REQ_CNT; break;
2652 case ACT_F_TCP_RES_CNT: smp_val = SMP_VAL_BE_RES_CNT; break;
2653 case ACT_F_HTTP_REQ: smp_val = SMP_VAL_FE_HRQ_HDR; break;
2654 case ACT_F_HTTP_RES: smp_val = SMP_VAL_BE_HRS_HDR; break;
2655 default:
2656 memprintf(err, "internal error, unexpected rule->from=%d, please report this bug!", rule->from);
2657 return ACT_RET_PRS_ERR;
2658 }
2659 if (!(rule->arg.gpt.expr->fetch->val & smp_val)) {
2660 memprintf(err, "fetch method '%s' extracts information from '%s', none of which is available here", args[*arg-1],
2661 sample_src_names(rule->arg.gpt.expr->fetch->use));
2662 free(rule->arg.gpt.expr);
2663 return ACT_RET_PRS_ERR;
2664 }
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002665 }
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002666
Thierry FOURNIER42148732015-09-02 17:17:33 +02002667 rule->action = ACT_CUSTOM;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002668
2669 return ACT_RET_PRS_OK;
2670}
2671
Willy Tarreau7d562212016-11-25 16:10:05 +01002672/* set temp integer to the number of used entries in the table pointed to by expr.
2673 * Accepts exactly 1 argument of type table.
2674 */
2675static int
2676smp_fetch_table_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
2677{
2678 smp->flags = SMP_F_VOL_TEST;
2679 smp->data.type = SMP_T_SINT;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002680 smp->data.u.sint = args->data.t->current;
Willy Tarreau7d562212016-11-25 16:10:05 +01002681 return 1;
2682}
2683
2684/* set temp integer to the number of free entries in the table pointed to by expr.
2685 * Accepts exactly 1 argument of type table.
2686 */
2687static int
2688smp_fetch_table_avl(const struct arg *args, struct sample *smp, const char *kw, void *private)
2689{
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002690 struct stktable *t;
Willy Tarreau7d562212016-11-25 16:10:05 +01002691
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002692 t = args->data.t;
Willy Tarreau7d562212016-11-25 16:10:05 +01002693 smp->flags = SMP_F_VOL_TEST;
2694 smp->data.type = SMP_T_SINT;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002695 smp->data.u.sint = t->size - t->current;
Willy Tarreau7d562212016-11-25 16:10:05 +01002696 return 1;
2697}
2698
2699/* Returns a pointer to a stkctr depending on the fetch keyword name.
2700 * It is designed to be called as sc[0-9]_* sc_* or src_* exclusively.
2701 * sc[0-9]_* will return a pointer to the respective field in the
2702 * stream <l4>. sc_* requires an UINT argument specifying the stick
2703 * counter number. src_* will fill a locally allocated structure with
2704 * the table and entry corresponding to what is specified with src_*.
2705 * NULL may be returned if the designated stkctr is not tracked. For
2706 * the sc_* and sc[0-9]_* forms, an optional table argument may be
2707 * passed. When present, the currently tracked key is then looked up
2708 * in the specified table instead of the current table. The purpose is
Ilya Shipitsin47d17182020-06-21 21:42:57 +05002709 * to be able to convert multiple values per key (eg: have gpc0 from
Willy Tarreau7d562212016-11-25 16:10:05 +01002710 * multiple tables). <strm> is allowed to be NULL, in which case only
2711 * the session will be consulted.
2712 */
2713struct stkctr *
Emeric Brun819fc6f2017-06-13 19:37:32 +02002714smp_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 +01002715{
Willy Tarreau7d562212016-11-25 16:10:05 +01002716 struct stkctr *stkptr;
2717 struct stksess *stksess;
2718 unsigned int num = kw[2] - '0';
2719 int arg = 0;
2720
2721 if (num == '_' - '0') {
2722 /* sc_* variant, args[0] = ctr# (mandatory) */
2723 num = args[arg++].data.sint;
Willy Tarreau7d562212016-11-25 16:10:05 +01002724 }
2725 else if (num > 9) { /* src_* variant, args[0] = table */
2726 struct stktable_key *key;
2727 struct connection *conn = objt_conn(sess->origin);
2728 struct sample smp;
2729
2730 if (!conn)
2731 return NULL;
2732
Joseph Herlant5662fa42018-11-15 13:43:28 -08002733 /* Fetch source address in a sample. */
Willy Tarreau7d562212016-11-25 16:10:05 +01002734 smp.px = NULL;
2735 smp.sess = sess;
2736 smp.strm = strm;
Amaury Denoyellec460c702021-05-12 10:17:47 +02002737 if (!smp_fetch_src || !smp_fetch_src(empty_arg_list, &smp, "src", NULL))
Willy Tarreau7d562212016-11-25 16:10:05 +01002738 return NULL;
2739
2740 /* Converts into key. */
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002741 key = smp_to_stkey(&smp, args->data.t);
Willy Tarreau7d562212016-11-25 16:10:05 +01002742 if (!key)
2743 return NULL;
2744
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002745 stkctr->table = args->data.t;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002746 stkctr_set_entry(stkctr, stktable_lookup_key(stkctr->table, key));
2747 return stkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002748 }
2749
2750 /* Here, <num> contains the counter number from 0 to 9 for
2751 * the sc[0-9]_ form, or even higher using sc_(num) if needed.
2752 * args[arg] is the first optional argument. We first lookup the
2753 * ctr form the stream, then from the session if it was not there.
Christopher Fauleta9fa88a2019-10-21 10:53:34 +02002754 * But we must be sure the counter does not exceed MAX_SESS_STKCTR.
Willy Tarreau7d562212016-11-25 16:10:05 +01002755 */
Christopher Fauleta9fa88a2019-10-21 10:53:34 +02002756 if (num >= MAX_SESS_STKCTR)
2757 return NULL;
Willy Tarreau7d562212016-11-25 16:10:05 +01002758
2759 if (strm)
2760 stkptr = &strm->stkctr[num];
2761 if (!strm || !stkctr_entry(stkptr)) {
2762 stkptr = &sess->stkctr[num];
2763 if (!stkctr_entry(stkptr))
2764 return NULL;
2765 }
2766
2767 stksess = stkctr_entry(stkptr);
2768 if (!stksess)
2769 return NULL;
2770
2771 if (unlikely(args[arg].type == ARGT_TAB)) {
2772 /* an alternate table was specified, let's look up the same key there */
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002773 stkctr->table = args[arg].data.t;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002774 stkctr_set_entry(stkctr, stktable_lookup(stkctr->table, stksess));
2775 return stkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002776 }
2777 return stkptr;
2778}
2779
2780/* same as smp_fetch_sc_stkctr() but dedicated to src_* and can create
2781 * the entry if it doesn't exist yet. This is needed for a few fetch
2782 * functions which need to create an entry, such as src_inc_gpc* and
2783 * src_clr_gpc*.
2784 */
2785struct stkctr *
Emeric Brun819fc6f2017-06-13 19:37:32 +02002786smp_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 +01002787{
Willy Tarreau7d562212016-11-25 16:10:05 +01002788 struct stktable_key *key;
2789 struct connection *conn = objt_conn(sess->origin);
2790 struct sample smp;
2791
2792 if (strncmp(kw, "src_", 4) != 0)
2793 return NULL;
2794
2795 if (!conn)
2796 return NULL;
2797
Joseph Herlant5662fa42018-11-15 13:43:28 -08002798 /* Fetch source address in a sample. */
Willy Tarreau7d562212016-11-25 16:10:05 +01002799 smp.px = NULL;
2800 smp.sess = sess;
2801 smp.strm = strm;
Amaury Denoyellec460c702021-05-12 10:17:47 +02002802 if (!smp_fetch_src || !smp_fetch_src(empty_arg_list, &smp, "src", NULL))
Willy Tarreau7d562212016-11-25 16:10:05 +01002803 return NULL;
2804
2805 /* Converts into key. */
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002806 key = smp_to_stkey(&smp, args->data.t);
Willy Tarreau7d562212016-11-25 16:10:05 +01002807 if (!key)
2808 return NULL;
2809
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002810 stkctr->table = args->data.t;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002811 stkctr_set_entry(stkctr, stktable_get_entry(stkctr->table, key));
2812 return stkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002813}
2814
2815/* set return a boolean indicating if the requested stream counter is
2816 * currently being tracked or not.
2817 * Supports being called as "sc[0-9]_tracked" only.
2818 */
2819static int
2820smp_fetch_sc_tracked(const struct arg *args, struct sample *smp, const char *kw, void *private)
2821{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002822 struct stkctr tmpstkctr;
2823 struct stkctr *stkctr;
2824
Willy Tarreau7d562212016-11-25 16:10:05 +01002825 smp->flags = SMP_F_VOL_TEST;
2826 smp->data.type = SMP_T_BOOL;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002827 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2828 smp->data.u.sint = !!stkctr;
2829
2830 /* release the ref count */
Dirkjan Bussinkff57f1b2018-09-14 14:31:22 +02002831 if (stkctr == &tmpstkctr)
Emeric Brun819fc6f2017-06-13 19:37:32 +02002832 stktable_release(stkctr->table, stkctr_entry(stkctr));
2833
Emeric Brun877b0b52021-06-30 18:57:49 +02002834 return 1;
2835}
2836
2837/* set <smp> to the General Purpose Tag of index set as first arg
2838 * to value from the stream's tracked frontend counters or from the src.
2839 * Supports being called as "sc_get_gpt(<gpt-idx>,<sc-idx>[,<table>])" or
2840 * "src_get_gpt(<gpt-idx>[,<table>])" only. Value zero is returned if
2841 * the key is new or gpt is not stored.
2842 */
2843static int
2844smp_fetch_sc_get_gpt(const struct arg *args, struct sample *smp, const char *kw, void *private)
2845{
2846 struct stkctr tmpstkctr;
2847 struct stkctr *stkctr;
2848 unsigned int idx;
2849
2850 idx = args[0].data.sint;
2851
2852 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args + 1, kw, &tmpstkctr);
2853 if (!stkctr)
2854 return 0;
2855
2856 smp->flags = SMP_F_VOL_TEST;
2857 smp->data.type = SMP_T_SINT;
2858 smp->data.u.sint = 0;
2859
2860 if (stkctr_entry(stkctr)) {
2861 void *ptr;
2862
2863 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPT, idx);
2864 if (!ptr) {
2865 if (stkctr == &tmpstkctr)
2866 stktable_release(stkctr->table, stkctr_entry(stkctr));
2867 return 0; /* parameter not stored */
2868 }
2869
2870 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2871
2872 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
2873
2874 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2875
2876 if (stkctr == &tmpstkctr)
2877 stktable_release(stkctr->table, stkctr_entry(stkctr));
2878 }
Willy Tarreau7d562212016-11-25 16:10:05 +01002879 return 1;
2880}
2881
2882/* set <smp> to the General Purpose Flag 0 value from the stream's tracked
2883 * frontend counters or from the src.
2884 * Supports being called as "sc[0-9]_get_gpc0" or "src_get_gpt0" only. Value
2885 * zero is returned if the key is new.
2886 */
2887static int
2888smp_fetch_sc_get_gpt0(const struct arg *args, struct sample *smp, const char *kw, void *private)
2889{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002890 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002891 struct stkctr *stkctr;
2892
Emeric Brun819fc6f2017-06-13 19:37:32 +02002893 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002894 if (!stkctr)
2895 return 0;
2896
2897 smp->flags = SMP_F_VOL_TEST;
2898 smp->data.type = SMP_T_SINT;
2899 smp->data.u.sint = 0;
2900
Emeric Brun819fc6f2017-06-13 19:37:32 +02002901 if (stkctr_entry(stkctr)) {
2902 void *ptr;
2903
2904 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPT0);
Emeric Brunf7ab0bf2021-06-30 18:58:22 +02002905 if (!ptr)
2906 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPT, 0);
2907
Emeric Brun4d7ada82021-06-30 19:04:16 +02002908 if (!ptr) {
2909 if (stkctr == &tmpstkctr)
2910 stktable_release(stkctr->table, stkctr_entry(stkctr));
2911 return 0; /* parameter not stored */
2912 }
2913
2914 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2915
2916 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
2917
2918 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2919
2920 if (stkctr == &tmpstkctr)
2921 stktable_release(stkctr->table, stkctr_entry(stkctr));
2922 }
2923 return 1;
2924}
2925
2926/* set <smp> to the GPC[args(0)]'s value from the stream's tracked
2927 * frontend counters or from the src.
2928 * Supports being called as "sc_get_gpc(<gpc-idx>,<sc-idx>[,<table>])" or
2929 * "src_get_gpc(<gpc-idx>[,<table>])" only. Value
2930 * Value zero is returned if the key is new or gpc is not stored.
2931 */
2932static int
2933smp_fetch_sc_get_gpc(const struct arg *args, struct sample *smp, const char *kw, void *private)
2934{
2935 struct stkctr tmpstkctr;
2936 struct stkctr *stkctr;
2937 unsigned int idx;
2938
2939 idx = args[0].data.sint;
2940
2941 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args + 1, kw, &tmpstkctr);
2942 if (!stkctr)
2943 return 0;
2944
2945 smp->flags = SMP_F_VOL_TEST;
2946 smp->data.type = SMP_T_SINT;
2947 smp->data.u.sint = 0;
2948
2949 if (stkctr_entry(stkctr) != NULL) {
2950 void *ptr;
2951
2952 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC, idx);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002953 if (!ptr) {
2954 if (stkctr == &tmpstkctr)
2955 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002956 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002957 }
2958
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002959 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002960
Emeric Brun0e3457b2021-06-30 17:18:28 +02002961 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002962
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002963 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002964
2965 if (stkctr == &tmpstkctr)
2966 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002967 }
2968 return 1;
2969}
2970
2971/* set <smp> to the General Purpose Counter 0 value from the stream's tracked
2972 * frontend counters or from the src.
2973 * Supports being called as "sc[0-9]_get_gpc0" or "src_get_gpc0" only. Value
2974 * zero is returned if the key is new.
2975 */
2976static int
2977smp_fetch_sc_get_gpc0(const struct arg *args, struct sample *smp, const char *kw, void *private)
2978{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002979 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002980 struct stkctr *stkctr;
2981
Emeric Brun819fc6f2017-06-13 19:37:32 +02002982 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002983 if (!stkctr)
2984 return 0;
2985
2986 smp->flags = SMP_F_VOL_TEST;
2987 smp->data.type = SMP_T_SINT;
2988 smp->data.u.sint = 0;
2989
2990 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002991 void *ptr;
2992
2993 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0);
2994 if (!ptr) {
Emeric Brun726783d2021-06-30 19:06:43 +02002995 /* fallback on the gpc array */
2996 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC, 0);
2997 }
2998
2999 if (!ptr) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003000 if (stkctr == &tmpstkctr)
3001 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003002 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003003 }
3004
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003005 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003006
Emeric Brun0e3457b2021-06-30 17:18:28 +02003007 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003008
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003009 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003010
3011 if (stkctr == &tmpstkctr)
3012 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003013 }
3014 return 1;
3015}
3016
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003017/* set <smp> to the General Purpose Counter 1 value from the stream's tracked
3018 * frontend counters or from the src.
3019 * Supports being called as "sc[0-9]_get_gpc1" or "src_get_gpc1" only. Value
3020 * zero is returned if the key is new.
3021 */
3022static int
3023smp_fetch_sc_get_gpc1(const struct arg *args, struct sample *smp, const char *kw, void *private)
3024{
3025 struct stkctr tmpstkctr;
3026 struct stkctr *stkctr;
3027
3028 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
3029 if (!stkctr)
3030 return 0;
3031
3032 smp->flags = SMP_F_VOL_TEST;
3033 smp->data.type = SMP_T_SINT;
3034 smp->data.u.sint = 0;
3035
3036 if (stkctr_entry(stkctr) != NULL) {
3037 void *ptr;
3038
3039 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1);
3040 if (!ptr) {
Emeric Brun726783d2021-06-30 19:06:43 +02003041 /* fallback on the gpc array */
3042 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC, 1);
3043 }
3044
3045 if (!ptr) {
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003046 if (stkctr == &tmpstkctr)
3047 stktable_release(stkctr->table, stkctr_entry(stkctr));
3048 return 0; /* parameter not stored */
3049 }
3050
3051 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3052
Emeric Brun0e3457b2021-06-30 17:18:28 +02003053 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003054
3055 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3056
3057 if (stkctr == &tmpstkctr)
3058 stktable_release(stkctr->table, stkctr_entry(stkctr));
3059 }
3060 return 1;
3061}
3062
Emeric Brun4d7ada82021-06-30 19:04:16 +02003063/* set <smp> to the GPC[args(0)]'s event rate from the stream's
3064 * tracked frontend counters or from the src.
3065 * Supports being called as "sc_gpc_rate(<gpc-idx>,<sc-idx>[,<table])"
3066 * or "src_gpc_rate(<gpc-idx>[,<table>])" only.
3067 * Value zero is returned if the key is new or gpc_rate is not stored.
3068 */
3069static int
3070smp_fetch_sc_gpc_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3071{
3072 struct stkctr tmpstkctr;
3073 struct stkctr *stkctr;
3074 unsigned int idx;
3075
3076 idx = args[0].data.sint;
3077
3078 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args + 1, kw, &tmpstkctr);
3079 if (!stkctr)
3080 return 0;
3081
3082 smp->flags = SMP_F_VOL_TEST;
3083 smp->data.type = SMP_T_SINT;
3084 smp->data.u.sint = 0;
3085 if (stkctr_entry(stkctr) != NULL) {
3086 void *ptr;
3087
3088 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC_RATE, idx);
3089 if (!ptr) {
3090 if (stkctr == &tmpstkctr)
3091 stktable_release(stkctr->table, stkctr_entry(stkctr));
3092 return 0; /* parameter not stored */
3093 }
3094
3095 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3096
3097 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
3098 stkctr->table->data_arg[STKTABLE_DT_GPC_RATE].u);
3099
3100 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3101
3102 if (stkctr == &tmpstkctr)
3103 stktable_release(stkctr->table, stkctr_entry(stkctr));
3104 }
3105 return 1;
3106}
3107
Willy Tarreau7d562212016-11-25 16:10:05 +01003108/* set <smp> to the General Purpose Counter 0's event rate from the stream's
3109 * tracked frontend counters or from the src.
3110 * Supports being called as "sc[0-9]_gpc0_rate" or "src_gpc0_rate" only.
3111 * Value zero is returned if the key is new.
3112 */
3113static int
3114smp_fetch_sc_gpc0_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3115{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003116 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003117 struct stkctr *stkctr;
Emeric Brun726783d2021-06-30 19:06:43 +02003118 unsigned int period;
Willy Tarreau7d562212016-11-25 16:10:05 +01003119
Emeric Brun819fc6f2017-06-13 19:37:32 +02003120 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003121 if (!stkctr)
3122 return 0;
3123
3124 smp->flags = SMP_F_VOL_TEST;
3125 smp->data.type = SMP_T_SINT;
3126 smp->data.u.sint = 0;
3127 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003128 void *ptr;
3129
3130 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0_RATE);
Emeric Brun726783d2021-06-30 19:06:43 +02003131 if (ptr) {
3132 period = stkctr->table->data_arg[STKTABLE_DT_GPC0_RATE].u;
3133 }
3134 else {
3135 /* fallback on the gpc array */
3136 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC_RATE, 0);
3137 if (ptr)
3138 period = stkctr->table->data_arg[STKTABLE_DT_GPC_RATE].u;
3139 }
3140
Emeric Brun819fc6f2017-06-13 19:37:32 +02003141 if (!ptr) {
3142 if (stkctr == &tmpstkctr)
3143 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003144 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003145 }
3146
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003147 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003148
Emeric Brun726783d2021-06-30 19:06:43 +02003149 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp), period);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003150
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003151 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003152
3153 if (stkctr == &tmpstkctr)
3154 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003155 }
3156 return 1;
3157}
3158
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003159/* set <smp> to the General Purpose Counter 1's event rate from the stream's
3160 * tracked frontend counters or from the src.
3161 * Supports being called as "sc[0-9]_gpc1_rate" or "src_gpc1_rate" only.
3162 * Value zero is returned if the key is new.
3163 */
3164static int
3165smp_fetch_sc_gpc1_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3166{
3167 struct stkctr tmpstkctr;
3168 struct stkctr *stkctr;
Emeric Brun726783d2021-06-30 19:06:43 +02003169 unsigned int period;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003170
3171 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
3172 if (!stkctr)
3173 return 0;
3174
3175 smp->flags = SMP_F_VOL_TEST;
3176 smp->data.type = SMP_T_SINT;
3177 smp->data.u.sint = 0;
3178 if (stkctr_entry(stkctr) != NULL) {
3179 void *ptr;
3180
3181 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1_RATE);
Emeric Brun726783d2021-06-30 19:06:43 +02003182 if (ptr) {
3183 period = stkctr->table->data_arg[STKTABLE_DT_GPC1_RATE].u;
3184 }
3185 else {
3186 /* fallback on the gpc array */
3187 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC_RATE, 1);
3188 if (ptr)
3189 period = stkctr->table->data_arg[STKTABLE_DT_GPC_RATE].u;
3190 }
3191
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003192 if (!ptr) {
3193 if (stkctr == &tmpstkctr)
3194 stktable_release(stkctr->table, stkctr_entry(stkctr));
3195 return 0; /* parameter not stored */
3196 }
3197
3198 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3199
Emeric Brun726783d2021-06-30 19:06:43 +02003200 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 +01003201
3202 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3203
3204 if (stkctr == &tmpstkctr)
3205 stktable_release(stkctr->table, stkctr_entry(stkctr));
3206 }
3207 return 1;
3208}
3209
Emeric Brun4d7ada82021-06-30 19:04:16 +02003210/* Increment the GPC[args(0)] value from the stream's tracked
3211 * frontend counters and return it into temp integer.
3212 * Supports being called as "sc_inc_gpc(<gpc-idx>,<sc-idx>[,<table>])"
3213 * or "src_inc_gpc(<gpc-idx>[,<table>])" only.
3214 */
3215static int
3216smp_fetch_sc_inc_gpc(const struct arg *args, struct sample *smp, const char *kw, void *private)
3217{
3218 struct stkctr tmpstkctr;
3219 struct stkctr *stkctr;
3220 unsigned int idx;
3221
3222 idx = args[0].data.sint;
3223
3224 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args + 1, kw, &tmpstkctr);
3225 if (!stkctr)
3226 return 0;
3227
3228 smp->flags = SMP_F_VOL_TEST;
3229 smp->data.type = SMP_T_SINT;
3230 smp->data.u.sint = 0;
3231
3232 if (!stkctr_entry(stkctr))
3233 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
3234
3235 if (stkctr && stkctr_entry(stkctr)) {
3236 void *ptr1,*ptr2;
3237
3238
3239 /* First, update gpc0_rate if it's tracked. Second, update its
3240 * gpc0 if tracked. Returns gpc0's value otherwise the curr_ctr.
3241 */
3242 ptr1 = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC_RATE, idx);
3243 ptr2 = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC, idx);
3244 if (ptr1 || ptr2) {
3245 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3246
3247 if (ptr1) {
3248 update_freq_ctr_period(&stktable_data_cast(ptr1, std_t_frqp),
3249 stkctr->table->data_arg[STKTABLE_DT_GPC_RATE].u, 1);
3250 smp->data.u.sint = (&stktable_data_cast(ptr1, std_t_frqp))->curr_ctr;
3251 }
3252
3253 if (ptr2)
3254 smp->data.u.sint = ++stktable_data_cast(ptr2, std_t_uint);
3255
3256 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3257
3258 /* If data was modified, we need to touch to re-schedule sync */
3259 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
3260 }
3261 else if (stkctr == &tmpstkctr)
3262 stktable_release(stkctr->table, stkctr_entry(stkctr));
3263 }
3264 return 1;
3265}
3266
Willy Tarreau7d562212016-11-25 16:10:05 +01003267/* Increment the General Purpose Counter 0 value from the stream's tracked
3268 * frontend counters and return it into temp integer.
3269 * Supports being called as "sc[0-9]_inc_gpc0" or "src_inc_gpc0" only.
3270 */
3271static int
3272smp_fetch_sc_inc_gpc0(const struct arg *args, struct sample *smp, const char *kw, void *private)
3273{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003274 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003275 struct stkctr *stkctr;
Willy Tarreau5b654ad2021-07-06 18:51:12 +02003276 unsigned int period = 0;
Willy Tarreau7d562212016-11-25 16:10:05 +01003277
Emeric Brun819fc6f2017-06-13 19:37:32 +02003278 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003279 if (!stkctr)
3280 return 0;
3281
3282 smp->flags = SMP_F_VOL_TEST;
3283 smp->data.type = SMP_T_SINT;
3284 smp->data.u.sint = 0;
3285
Emeric Brun819fc6f2017-06-13 19:37:32 +02003286 if (!stkctr_entry(stkctr))
3287 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003288
3289 if (stkctr && stkctr_entry(stkctr)) {
3290 void *ptr1,*ptr2;
3291
Emeric Brun819fc6f2017-06-13 19:37:32 +02003292
Willy Tarreau7d562212016-11-25 16:10:05 +01003293 /* First, update gpc0_rate if it's tracked. Second, update its
3294 * gpc0 if tracked. Returns gpc0's value otherwise the curr_ctr.
3295 */
3296 ptr1 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0_RATE);
Emeric Brun726783d2021-06-30 19:06:43 +02003297 if (ptr1) {
3298 period = stkctr->table->data_arg[STKTABLE_DT_GPC0_RATE].u;
3299 }
3300 else {
3301 /* fallback on the gpc array */
3302 ptr1 = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC_RATE, 0);
3303 if (ptr1)
3304 period = stkctr->table->data_arg[STKTABLE_DT_GPC_RATE].u;
3305 }
3306
Willy Tarreau7d562212016-11-25 16:10:05 +01003307 ptr2 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0);
Emeric Brun726783d2021-06-30 19:06:43 +02003308 if (!ptr2) {
3309 /* fallback on the gpc array */
3310 ptr2 = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC, 0);
3311 }
3312
Emeric Brun819fc6f2017-06-13 19:37:32 +02003313 if (ptr1 || ptr2) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003314 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Willy Tarreau7d562212016-11-25 16:10:05 +01003315
Emeric Brun819fc6f2017-06-13 19:37:32 +02003316 if (ptr1) {
Emeric Brun0e3457b2021-06-30 17:18:28 +02003317 update_freq_ctr_period(&stktable_data_cast(ptr1, std_t_frqp),
Emeric Brun726783d2021-06-30 19:06:43 +02003318 period, 1);
Emeric Brun0e3457b2021-06-30 17:18:28 +02003319 smp->data.u.sint = (&stktable_data_cast(ptr1, std_t_frqp))->curr_ctr;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003320 }
3321
3322 if (ptr2)
Emeric Brun0e3457b2021-06-30 17:18:28 +02003323 smp->data.u.sint = ++stktable_data_cast(ptr2, std_t_uint);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003324
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003325 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003326
3327 /* If data was modified, we need to touch to re-schedule sync */
3328 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
3329 }
3330 else if (stkctr == &tmpstkctr)
3331 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003332 }
3333 return 1;
3334}
3335
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003336/* Increment the General Purpose Counter 1 value from the stream's tracked
3337 * frontend counters and return it into temp integer.
3338 * Supports being called as "sc[0-9]_inc_gpc1" or "src_inc_gpc1" only.
3339 */
3340static int
3341smp_fetch_sc_inc_gpc1(const struct arg *args, struct sample *smp, const char *kw, void *private)
3342{
3343 struct stkctr tmpstkctr;
3344 struct stkctr *stkctr;
Willy Tarreau5b654ad2021-07-06 18:51:12 +02003345 unsigned int period = 0;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003346
3347 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
3348 if (!stkctr)
3349 return 0;
3350
3351 smp->flags = SMP_F_VOL_TEST;
3352 smp->data.type = SMP_T_SINT;
3353 smp->data.u.sint = 0;
3354
3355 if (!stkctr_entry(stkctr))
3356 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
3357
3358 if (stkctr && stkctr_entry(stkctr)) {
3359 void *ptr1,*ptr2;
3360
3361
3362 /* First, update gpc1_rate if it's tracked. Second, update its
3363 * gpc1 if tracked. Returns gpc1's value otherwise the curr_ctr.
3364 */
3365 ptr1 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1_RATE);
Emeric Brun726783d2021-06-30 19:06:43 +02003366 if (ptr1) {
3367 period = stkctr->table->data_arg[STKTABLE_DT_GPC1_RATE].u;
3368 }
3369 else {
3370 /* fallback on the gpc array */
3371 ptr1 = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC_RATE, 1);
3372 if (ptr1)
3373 period = stkctr->table->data_arg[STKTABLE_DT_GPC_RATE].u;
3374 }
3375
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003376 ptr2 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1);
Emeric Brun726783d2021-06-30 19:06:43 +02003377 if (!ptr2) {
3378 /* fallback on the gpc array */
3379 ptr2 = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC, 1);
3380 }
3381
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003382 if (ptr1 || ptr2) {
3383 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3384
3385 if (ptr1) {
Emeric Brun0e3457b2021-06-30 17:18:28 +02003386 update_freq_ctr_period(&stktable_data_cast(ptr1, std_t_frqp),
Emeric Brun726783d2021-06-30 19:06:43 +02003387 period, 1);
Emeric Brun0e3457b2021-06-30 17:18:28 +02003388 smp->data.u.sint = (&stktable_data_cast(ptr1, std_t_frqp))->curr_ctr;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003389 }
3390
3391 if (ptr2)
Emeric Brun0e3457b2021-06-30 17:18:28 +02003392 smp->data.u.sint = ++stktable_data_cast(ptr2, std_t_uint);
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003393
3394 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3395
3396 /* If data was modified, we need to touch to re-schedule sync */
3397 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
3398 }
3399 else if (stkctr == &tmpstkctr)
3400 stktable_release(stkctr->table, stkctr_entry(stkctr));
3401 }
3402 return 1;
3403}
3404
Emeric Brun4d7ada82021-06-30 19:04:16 +02003405/* Clear the GPC[args(0)] value from the stream's tracked
3406 * frontend counters and return its previous value into temp integer.
3407 * Supports being called as "sc_clr_gpc(<gpc-idx>,<sc-idx>[,<table>])"
3408 * or "src_clr_gpc(<gpc-idx>[,<table>])" only.
3409 */
3410static int
3411smp_fetch_sc_clr_gpc(const struct arg *args, struct sample *smp, const char *kw, void *private)
3412{
3413 struct stkctr tmpstkctr;
3414 struct stkctr *stkctr;
3415 unsigned int idx;
3416
3417 idx = args[0].data.sint;
3418
3419 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args + 1, kw, &tmpstkctr);
3420 if (!stkctr)
3421 return 0;
3422
3423 smp->flags = SMP_F_VOL_TEST;
3424 smp->data.type = SMP_T_SINT;
3425 smp->data.u.sint = 0;
3426
3427 if (!stkctr_entry(stkctr))
3428 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
3429
3430 if (stkctr && stkctr_entry(stkctr)) {
3431 void *ptr;
3432
3433 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC, idx);
3434 if (!ptr) {
3435 if (stkctr == &tmpstkctr)
3436 stktable_release(stkctr->table, stkctr_entry(stkctr));
3437 return 0; /* parameter not stored */
3438 }
3439
3440 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3441
3442 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
3443 stktable_data_cast(ptr, std_t_uint) = 0;
3444
3445 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3446
3447 /* If data was modified, we need to touch to re-schedule sync */
3448 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
3449 }
3450 return 1;
3451}
3452
Willy Tarreau7d562212016-11-25 16:10:05 +01003453/* Clear the General Purpose Counter 0 value from the stream's tracked
3454 * frontend counters and return its previous value into temp integer.
3455 * Supports being called as "sc[0-9]_clr_gpc0" or "src_clr_gpc0" only.
3456 */
3457static int
3458smp_fetch_sc_clr_gpc0(const struct arg *args, struct sample *smp, const char *kw, void *private)
3459{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003460 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003461 struct stkctr *stkctr;
3462
Emeric Brun819fc6f2017-06-13 19:37:32 +02003463 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003464 if (!stkctr)
3465 return 0;
3466
3467 smp->flags = SMP_F_VOL_TEST;
3468 smp->data.type = SMP_T_SINT;
3469 smp->data.u.sint = 0;
3470
Emeric Brun819fc6f2017-06-13 19:37:32 +02003471 if (!stkctr_entry(stkctr))
3472 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003473
Emeric Brun819fc6f2017-06-13 19:37:32 +02003474 if (stkctr && stkctr_entry(stkctr)) {
3475 void *ptr;
3476
3477 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0);
3478 if (!ptr) {
Emeric Brun726783d2021-06-30 19:06:43 +02003479 /* fallback on the gpc array */
3480 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC, 0);
3481 }
3482
3483 if (!ptr) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003484 if (stkctr == &tmpstkctr)
3485 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003486 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003487 }
3488
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003489 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003490
Emeric Brun0e3457b2021-06-30 17:18:28 +02003491 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
3492 stktable_data_cast(ptr, std_t_uint) = 0;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003493
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003494 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003495
Willy Tarreau7d562212016-11-25 16:10:05 +01003496 /* If data was modified, we need to touch to re-schedule sync */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003497 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
Willy Tarreau7d562212016-11-25 16:10:05 +01003498 }
3499 return 1;
3500}
3501
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003502/* Clear the General Purpose Counter 1 value from the stream's tracked
3503 * frontend counters and return its previous value into temp integer.
3504 * Supports being called as "sc[0-9]_clr_gpc1" or "src_clr_gpc1" only.
3505 */
3506static int
3507smp_fetch_sc_clr_gpc1(const struct arg *args, struct sample *smp, const char *kw, void *private)
3508{
3509 struct stkctr tmpstkctr;
3510 struct stkctr *stkctr;
3511
3512 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
3513 if (!stkctr)
3514 return 0;
3515
3516 smp->flags = SMP_F_VOL_TEST;
3517 smp->data.type = SMP_T_SINT;
3518 smp->data.u.sint = 0;
3519
3520 if (!stkctr_entry(stkctr))
3521 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
3522
3523 if (stkctr && stkctr_entry(stkctr)) {
3524 void *ptr;
3525
3526 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1);
3527 if (!ptr) {
Emeric Brun726783d2021-06-30 19:06:43 +02003528 /* fallback on the gpc array */
3529 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC, 1);
3530 }
3531
3532 if (!ptr) {
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003533 if (stkctr == &tmpstkctr)
3534 stktable_release(stkctr->table, stkctr_entry(stkctr));
3535 return 0; /* parameter not stored */
3536 }
3537
3538 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3539
Emeric Brun0e3457b2021-06-30 17:18:28 +02003540 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
3541 stktable_data_cast(ptr, std_t_uint) = 0;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003542
3543 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3544
3545 /* If data was modified, we need to touch to re-schedule sync */
3546 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
3547 }
3548 return 1;
3549}
3550
Willy Tarreau7d562212016-11-25 16:10:05 +01003551/* set <smp> to the cumulated number of connections from the stream's tracked
3552 * frontend counters. Supports being called as "sc[0-9]_conn_cnt" or
3553 * "src_conn_cnt" only.
3554 */
3555static int
3556smp_fetch_sc_conn_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
3557{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003558 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003559 struct stkctr *stkctr;
3560
Emeric Brun819fc6f2017-06-13 19:37:32 +02003561 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003562 if (!stkctr)
3563 return 0;
3564
3565 smp->flags = SMP_F_VOL_TEST;
3566 smp->data.type = SMP_T_SINT;
3567 smp->data.u.sint = 0;
3568 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003569 void *ptr;
3570
3571 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_CONN_CNT);
3572 if (!ptr) {
3573 if (stkctr == &tmpstkctr)
3574 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003575 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003576 }
3577
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003578 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003579
Emeric Brun0e3457b2021-06-30 17:18:28 +02003580 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003581
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003582 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003583
3584 if (stkctr == &tmpstkctr)
3585 stktable_release(stkctr->table, stkctr_entry(stkctr));
3586
3587
Willy Tarreau7d562212016-11-25 16:10:05 +01003588 }
3589 return 1;
3590}
3591
3592/* set <smp> to the connection rate from the stream's tracked frontend
3593 * counters. Supports being called as "sc[0-9]_conn_rate" or "src_conn_rate"
3594 * only.
3595 */
3596static int
3597smp_fetch_sc_conn_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3598{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003599 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003600 struct stkctr *stkctr;
3601
Emeric Brun819fc6f2017-06-13 19:37:32 +02003602 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003603 if (!stkctr)
3604 return 0;
3605
3606 smp->flags = SMP_F_VOL_TEST;
3607 smp->data.type = SMP_T_SINT;
3608 smp->data.u.sint = 0;
3609 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003610 void *ptr;
3611
3612 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_CONN_RATE);
3613 if (!ptr) {
3614 if (stkctr == &tmpstkctr)
3615 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003616 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003617 }
3618
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003619 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003620
Emeric Brun0e3457b2021-06-30 17:18:28 +02003621 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Willy Tarreau7d562212016-11-25 16:10:05 +01003622 stkctr->table->data_arg[STKTABLE_DT_CONN_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003623
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003624 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003625
3626 if (stkctr == &tmpstkctr)
3627 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003628 }
3629 return 1;
3630}
3631
3632/* set temp integer to the number of connections from the stream's source address
3633 * in the table pointed to by expr, after updating it.
3634 * Accepts exactly 1 argument of type table.
3635 */
3636static int
3637smp_fetch_src_updt_conn_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
3638{
3639 struct connection *conn = objt_conn(smp->sess->origin);
3640 struct stksess *ts;
3641 struct stktable_key *key;
3642 void *ptr;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003643 struct stktable *t;
Willy Tarreau7d562212016-11-25 16:10:05 +01003644
3645 if (!conn)
3646 return 0;
3647
Joseph Herlant5662fa42018-11-15 13:43:28 -08003648 /* Fetch source address in a sample. */
Amaury Denoyellec460c702021-05-12 10:17:47 +02003649 if (!smp_fetch_src || !smp_fetch_src(empty_arg_list, smp, "src", NULL))
Willy Tarreau7d562212016-11-25 16:10:05 +01003650 return 0;
3651
3652 /* Converts into key. */
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003653 key = smp_to_stkey(smp, args->data.t);
Willy Tarreau7d562212016-11-25 16:10:05 +01003654 if (!key)
3655 return 0;
3656
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003657 t = args->data.t;
Willy Tarreau7d562212016-11-25 16:10:05 +01003658
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003659 if ((ts = stktable_get_entry(t, key)) == NULL)
Willy Tarreau7d562212016-11-25 16:10:05 +01003660 /* entry does not exist and could not be created */
3661 return 0;
3662
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003663 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_CONN_CNT);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003664 if (!ptr) {
Willy Tarreau7d562212016-11-25 16:10:05 +01003665 return 0; /* parameter not stored in this table */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003666 }
Willy Tarreau7d562212016-11-25 16:10:05 +01003667
3668 smp->data.type = SMP_T_SINT;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003669
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003670 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003671
Emeric Brun0e3457b2021-06-30 17:18:28 +02003672 smp->data.u.sint = ++stktable_data_cast(ptr, std_t_uint);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003673
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003674 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003675
Willy Tarreau7d562212016-11-25 16:10:05 +01003676 smp->flags = SMP_F_VOL_TEST;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003677
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003678 stktable_touch_local(t, ts, 1);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003679
3680 /* Touch was previously performed by stktable_update_key */
Willy Tarreau7d562212016-11-25 16:10:05 +01003681 return 1;
3682}
3683
3684/* set <smp> to the number of concurrent connections from the stream's tracked
3685 * frontend counters. Supports being called as "sc[0-9]_conn_cur" or
3686 * "src_conn_cur" only.
3687 */
3688static int
3689smp_fetch_sc_conn_cur(const struct arg *args, struct sample *smp, const char *kw, void *private)
3690{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003691 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003692 struct stkctr *stkctr;
3693
Emeric Brun819fc6f2017-06-13 19:37:32 +02003694 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003695 if (!stkctr)
3696 return 0;
3697
3698 smp->flags = SMP_F_VOL_TEST;
3699 smp->data.type = SMP_T_SINT;
3700 smp->data.u.sint = 0;
3701 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003702 void *ptr;
3703
3704 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_CONN_CUR);
3705 if (!ptr) {
3706 if (stkctr == &tmpstkctr)
3707 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003708 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003709 }
3710
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003711 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003712
Emeric Brun0e3457b2021-06-30 17:18:28 +02003713 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003714
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003715 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003716
3717 if (stkctr == &tmpstkctr)
3718 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003719 }
3720 return 1;
3721}
3722
3723/* set <smp> to the cumulated number of streams from the stream's tracked
3724 * frontend counters. Supports being called as "sc[0-9]_sess_cnt" or
3725 * "src_sess_cnt" only.
3726 */
3727static int
3728smp_fetch_sc_sess_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
3729{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003730 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003731 struct stkctr *stkctr;
3732
Emeric Brun819fc6f2017-06-13 19:37:32 +02003733 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003734 if (!stkctr)
3735 return 0;
3736
3737 smp->flags = SMP_F_VOL_TEST;
3738 smp->data.type = SMP_T_SINT;
3739 smp->data.u.sint = 0;
3740 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003741 void *ptr;
3742
3743 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_SESS_CNT);
3744 if (!ptr) {
3745 if (stkctr == &tmpstkctr)
3746 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003747 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003748 }
3749
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003750 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003751
Emeric Brun0e3457b2021-06-30 17:18:28 +02003752 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003753
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003754 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003755
3756 if (stkctr == &tmpstkctr)
3757 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003758 }
3759 return 1;
3760}
3761
3762/* set <smp> to the stream rate from the stream's tracked frontend counters.
3763 * Supports being called as "sc[0-9]_sess_rate" or "src_sess_rate" only.
3764 */
3765static int
3766smp_fetch_sc_sess_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3767{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003768 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003769 struct stkctr *stkctr;
3770
Emeric Brun819fc6f2017-06-13 19:37:32 +02003771 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003772 if (!stkctr)
3773 return 0;
3774
3775 smp->flags = SMP_F_VOL_TEST;
3776 smp->data.type = SMP_T_SINT;
3777 smp->data.u.sint = 0;
3778 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003779 void *ptr;
3780
3781 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_SESS_RATE);
3782 if (!ptr) {
3783 if (stkctr == &tmpstkctr)
3784 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003785 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003786 }
3787
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003788 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003789
Emeric Brun0e3457b2021-06-30 17:18:28 +02003790 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Willy Tarreau7d562212016-11-25 16:10:05 +01003791 stkctr->table->data_arg[STKTABLE_DT_SESS_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003792
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003793 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003794
3795 if (stkctr == &tmpstkctr)
3796 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003797 }
3798 return 1;
3799}
3800
3801/* set <smp> to the cumulated number of HTTP requests from the stream's tracked
3802 * frontend counters. Supports being called as "sc[0-9]_http_req_cnt" or
3803 * "src_http_req_cnt" only.
3804 */
3805static int
3806smp_fetch_sc_http_req_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
3807{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003808 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003809 struct stkctr *stkctr;
3810
Emeric Brun819fc6f2017-06-13 19:37:32 +02003811 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003812 if (!stkctr)
3813 return 0;
3814
3815 smp->flags = SMP_F_VOL_TEST;
3816 smp->data.type = SMP_T_SINT;
3817 smp->data.u.sint = 0;
3818 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003819 void *ptr;
3820
3821 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_REQ_CNT);
3822 if (!ptr) {
3823 if (stkctr == &tmpstkctr)
3824 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003825 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003826 }
3827
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003828 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003829
Emeric Brun0e3457b2021-06-30 17:18:28 +02003830 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003831
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003832 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003833
3834 if (stkctr == &tmpstkctr)
3835 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003836 }
3837 return 1;
3838}
3839
3840/* set <smp> to the HTTP request rate from the stream's tracked frontend
3841 * counters. Supports being called as "sc[0-9]_http_req_rate" or
3842 * "src_http_req_rate" only.
3843 */
3844static int
3845smp_fetch_sc_http_req_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3846{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003847 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003848 struct stkctr *stkctr;
3849
Emeric Brun819fc6f2017-06-13 19:37:32 +02003850 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003851 if (!stkctr)
3852 return 0;
3853
3854 smp->flags = SMP_F_VOL_TEST;
3855 smp->data.type = SMP_T_SINT;
3856 smp->data.u.sint = 0;
3857 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003858 void *ptr;
3859
3860 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_REQ_RATE);
3861 if (!ptr) {
3862 if (stkctr == &tmpstkctr)
3863 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003864 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003865 }
3866
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003867 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003868
Emeric Brun0e3457b2021-06-30 17:18:28 +02003869 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Willy Tarreau7d562212016-11-25 16:10:05 +01003870 stkctr->table->data_arg[STKTABLE_DT_HTTP_REQ_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003871
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003872 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003873
3874 if (stkctr == &tmpstkctr)
3875 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003876 }
3877 return 1;
3878}
3879
3880/* set <smp> to the cumulated number of HTTP requests errors from the stream's
3881 * tracked frontend counters. Supports being called as "sc[0-9]_http_err_cnt" or
3882 * "src_http_err_cnt" only.
3883 */
3884static int
3885smp_fetch_sc_http_err_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
3886{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003887 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003888 struct stkctr *stkctr;
3889
Emeric Brun819fc6f2017-06-13 19:37:32 +02003890 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003891 if (!stkctr)
3892 return 0;
3893
3894 smp->flags = SMP_F_VOL_TEST;
3895 smp->data.type = SMP_T_SINT;
3896 smp->data.u.sint = 0;
3897 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003898 void *ptr;
3899
3900 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_ERR_CNT);
3901 if (!ptr) {
3902 if (stkctr == &tmpstkctr)
3903 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003904 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003905 }
3906
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003907 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003908
Emeric Brun0e3457b2021-06-30 17:18:28 +02003909 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003910
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003911 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003912
3913 if (stkctr == &tmpstkctr)
3914 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003915 }
3916 return 1;
3917}
3918
3919/* set <smp> to the HTTP request error rate from the stream's tracked frontend
3920 * counters. Supports being called as "sc[0-9]_http_err_rate" or
3921 * "src_http_err_rate" only.
3922 */
3923static int
3924smp_fetch_sc_http_err_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3925{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003926 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003927 struct stkctr *stkctr;
3928
Emeric Brun819fc6f2017-06-13 19:37:32 +02003929 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003930 if (!stkctr)
3931 return 0;
3932
3933 smp->flags = SMP_F_VOL_TEST;
3934 smp->data.type = SMP_T_SINT;
3935 smp->data.u.sint = 0;
3936 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003937 void *ptr;
3938
3939 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_ERR_RATE);
3940 if (!ptr) {
3941 if (stkctr == &tmpstkctr)
3942 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003943 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003944 }
3945
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003946 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003947
Emeric Brun0e3457b2021-06-30 17:18:28 +02003948 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Willy Tarreau7d562212016-11-25 16:10:05 +01003949 stkctr->table->data_arg[STKTABLE_DT_HTTP_ERR_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003950
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003951 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003952
3953 if (stkctr == &tmpstkctr)
3954 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003955 }
3956 return 1;
3957}
3958
Willy Tarreau826f3ab2021-02-10 12:07:15 +01003959/* set <smp> to the cumulated number of HTTP response failures from the stream's
3960 * tracked frontend counters. Supports being called as "sc[0-9]_http_fail_cnt" or
3961 * "src_http_fail_cnt" only.
3962 */
3963static int
3964smp_fetch_sc_http_fail_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
3965{
3966 struct stkctr tmpstkctr;
3967 struct stkctr *stkctr;
3968
3969 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
3970 if (!stkctr)
3971 return 0;
3972
3973 smp->flags = SMP_F_VOL_TEST;
3974 smp->data.type = SMP_T_SINT;
3975 smp->data.u.sint = 0;
3976 if (stkctr_entry(stkctr) != NULL) {
3977 void *ptr;
3978
3979 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_FAIL_CNT);
3980 if (!ptr) {
3981 if (stkctr == &tmpstkctr)
3982 stktable_release(stkctr->table, stkctr_entry(stkctr));
3983 return 0; /* parameter not stored */
3984 }
3985
3986 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3987
Emeric Brun0e3457b2021-06-30 17:18:28 +02003988 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Willy Tarreau826f3ab2021-02-10 12:07:15 +01003989
3990 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3991
3992 if (stkctr == &tmpstkctr)
3993 stktable_release(stkctr->table, stkctr_entry(stkctr));
3994 }
3995 return 1;
3996}
3997
3998/* set <smp> to the HTTP response failure rate from the stream's tracked frontend
3999 * counters. Supports being called as "sc[0-9]_http_fail_rate" or
4000 * "src_http_fail_rate" only.
4001 */
4002static int
4003smp_fetch_sc_http_fail_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
4004{
4005 struct stkctr tmpstkctr;
4006 struct stkctr *stkctr;
4007
4008 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
4009 if (!stkctr)
4010 return 0;
4011
4012 smp->flags = SMP_F_VOL_TEST;
4013 smp->data.type = SMP_T_SINT;
4014 smp->data.u.sint = 0;
4015 if (stkctr_entry(stkctr) != NULL) {
4016 void *ptr;
4017
4018 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_FAIL_RATE);
4019 if (!ptr) {
4020 if (stkctr == &tmpstkctr)
4021 stktable_release(stkctr->table, stkctr_entry(stkctr));
4022 return 0; /* parameter not stored */
4023 }
4024
4025 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
4026
Emeric Brun0e3457b2021-06-30 17:18:28 +02004027 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Willy Tarreau826f3ab2021-02-10 12:07:15 +01004028 stkctr->table->data_arg[STKTABLE_DT_HTTP_FAIL_RATE].u);
4029
4030 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
4031
4032 if (stkctr == &tmpstkctr)
4033 stktable_release(stkctr->table, stkctr_entry(stkctr));
4034 }
4035 return 1;
4036}
4037
Willy Tarreau7d562212016-11-25 16:10:05 +01004038/* set <smp> to the number of kbytes received from clients, as found in the
4039 * stream's tracked frontend counters. Supports being called as
4040 * "sc[0-9]_kbytes_in" or "src_kbytes_in" only.
4041 */
4042static int
4043smp_fetch_sc_kbytes_in(const struct arg *args, struct sample *smp, const char *kw, void *private)
4044{
Emeric Brun819fc6f2017-06-13 19:37:32 +02004045 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01004046 struct stkctr *stkctr;
4047
Emeric Brun819fc6f2017-06-13 19:37:32 +02004048 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01004049 if (!stkctr)
4050 return 0;
4051
4052 smp->flags = SMP_F_VOL_TEST;
4053 smp->data.type = SMP_T_SINT;
4054 smp->data.u.sint = 0;
4055 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02004056 void *ptr;
4057
4058 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_IN_CNT);
4059 if (!ptr) {
4060 if (stkctr == &tmpstkctr)
4061 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004062 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02004063 }
4064
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004065 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004066
Emeric Brun0e3457b2021-06-30 17:18:28 +02004067 smp->data.u.sint = stktable_data_cast(ptr, std_t_ull) >> 10;
Emeric Brun819fc6f2017-06-13 19:37:32 +02004068
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004069 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004070
4071 if (stkctr == &tmpstkctr)
4072 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004073 }
4074 return 1;
4075}
4076
4077/* set <smp> to the data rate received from clients in bytes/s, as found
4078 * in the stream's tracked frontend counters. Supports being called as
4079 * "sc[0-9]_bytes_in_rate" or "src_bytes_in_rate" only.
4080 */
4081static int
4082smp_fetch_sc_bytes_in_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
4083{
Emeric Brun819fc6f2017-06-13 19:37:32 +02004084 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01004085 struct stkctr *stkctr;
4086
Emeric Brun819fc6f2017-06-13 19:37:32 +02004087 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01004088 if (!stkctr)
4089 return 0;
4090
4091 smp->flags = SMP_F_VOL_TEST;
4092 smp->data.type = SMP_T_SINT;
4093 smp->data.u.sint = 0;
4094 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02004095 void *ptr;
4096
4097 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_IN_RATE);
4098 if (!ptr) {
4099 if (stkctr == &tmpstkctr)
4100 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004101 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02004102 }
4103
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004104 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004105
Emeric Brun0e3457b2021-06-30 17:18:28 +02004106 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Willy Tarreau7d562212016-11-25 16:10:05 +01004107 stkctr->table->data_arg[STKTABLE_DT_BYTES_IN_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004108
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004109 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004110
4111 if (stkctr == &tmpstkctr)
4112 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004113 }
4114 return 1;
4115}
4116
4117/* set <smp> to the number of kbytes sent to clients, as found in the
4118 * stream's tracked frontend counters. Supports being called as
4119 * "sc[0-9]_kbytes_out" or "src_kbytes_out" only.
4120 */
4121static int
4122smp_fetch_sc_kbytes_out(const struct arg *args, struct sample *smp, const char *kw, void *private)
4123{
Emeric Brun819fc6f2017-06-13 19:37:32 +02004124 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01004125 struct stkctr *stkctr;
4126
Emeric Brun819fc6f2017-06-13 19:37:32 +02004127 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01004128 if (!stkctr)
4129 return 0;
4130
4131 smp->flags = SMP_F_VOL_TEST;
4132 smp->data.type = SMP_T_SINT;
4133 smp->data.u.sint = 0;
4134 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02004135 void *ptr;
4136
4137 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_OUT_CNT);
4138 if (!ptr) {
4139 if (stkctr == &tmpstkctr)
4140 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004141 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02004142 }
4143
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004144 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004145
Emeric Brun0e3457b2021-06-30 17:18:28 +02004146 smp->data.u.sint = stktable_data_cast(ptr, std_t_ull) >> 10;
Emeric Brun819fc6f2017-06-13 19:37:32 +02004147
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004148 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004149
4150 if (stkctr == &tmpstkctr)
4151 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004152 }
4153 return 1;
4154}
4155
4156/* set <smp> to the data rate sent to clients in bytes/s, as found in the
4157 * stream's tracked frontend counters. Supports being called as
4158 * "sc[0-9]_bytes_out_rate" or "src_bytes_out_rate" only.
4159 */
4160static int
4161smp_fetch_sc_bytes_out_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
4162{
Emeric Brun819fc6f2017-06-13 19:37:32 +02004163 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01004164 struct stkctr *stkctr;
4165
Emeric Brun819fc6f2017-06-13 19:37:32 +02004166 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01004167 if (!stkctr)
4168 return 0;
4169
4170 smp->flags = SMP_F_VOL_TEST;
4171 smp->data.type = SMP_T_SINT;
4172 smp->data.u.sint = 0;
4173 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02004174 void *ptr;
4175
4176 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_OUT_RATE);
4177 if (!ptr) {
4178 if (stkctr == &tmpstkctr)
4179 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004180 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02004181 }
4182
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004183 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004184
Emeric Brun0e3457b2021-06-30 17:18:28 +02004185 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Willy Tarreau7d562212016-11-25 16:10:05 +01004186 stkctr->table->data_arg[STKTABLE_DT_BYTES_OUT_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004187
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004188 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004189
4190 if (stkctr == &tmpstkctr)
4191 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004192 }
4193 return 1;
4194}
4195
4196/* set <smp> to the number of active trackers on the SC entry in the stream's
4197 * tracked frontend counters. Supports being called as "sc[0-9]_trackers" only.
4198 */
4199static int
4200smp_fetch_sc_trackers(const struct arg *args, struct sample *smp, const char *kw, void *private)
4201{
Emeric Brun819fc6f2017-06-13 19:37:32 +02004202 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01004203 struct stkctr *stkctr;
4204
Emeric Brun819fc6f2017-06-13 19:37:32 +02004205 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01004206 if (!stkctr)
4207 return 0;
4208
4209 smp->flags = SMP_F_VOL_TEST;
4210 smp->data.type = SMP_T_SINT;
Emeric Brun819fc6f2017-06-13 19:37:32 +02004211 if (stkctr == &tmpstkctr) {
4212 smp->data.u.sint = stkctr_entry(stkctr) ? (stkctr_entry(stkctr)->ref_cnt-1) : 0;
4213 stktable_release(stkctr->table, stkctr_entry(stkctr));
4214 }
4215 else {
4216 smp->data.u.sint = stkctr_entry(stkctr) ? stkctr_entry(stkctr)->ref_cnt : 0;
4217 }
4218
Willy Tarreau7d562212016-11-25 16:10:05 +01004219 return 1;
4220}
4221
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004222
4223/* The functions below are used to manipulate table contents from the CLI.
4224 * There are 3 main actions, "clear", "set" and "show". The code is shared
4225 * between all actions, and the action is encoded in the void *private in
4226 * the appctx as well as in the keyword registration, among one of the
4227 * following values.
4228 */
4229
4230enum {
4231 STK_CLI_ACT_CLR,
4232 STK_CLI_ACT_SET,
4233 STK_CLI_ACT_SHOW,
4234};
4235
Christopher Faulet6b0a0fb2022-04-04 11:29:28 +02004236/* Dump the status of a table to a conn-stream's
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004237 * read buffer. It returns 0 if the output buffer is full
4238 * and needs to be called again, otherwise non-zero.
4239 */
Willy Tarreau83061a82018-07-13 11:56:34 +02004240static int table_dump_head_to_buffer(struct buffer *msg,
Christopher Faulet908628c2022-03-25 16:43:49 +01004241 struct conn_stream *cs,
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004242 struct stktable *t, struct stktable *target)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004243{
Christopher Faulet908628c2022-03-25 16:43:49 +01004244 struct stream *s = __cs_strm(cs);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004245
4246 chunk_appendf(msg, "# table: %s, type: %s, size:%d, used:%d\n",
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004247 t->id, stktable_types[t->type].kw, t->size, t->current);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004248
4249 /* any other information should be dumped here */
4250
William Lallemand07a62f72017-05-24 00:57:40 +02004251 if (target && (strm_li(s)->bind_conf->level & ACCESS_LVL_MASK) < ACCESS_LVL_OPER)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004252 chunk_appendf(msg, "# contents not dumped due to insufficient privileges\n");
4253
Christopher Faulet908628c2022-03-25 16:43:49 +01004254 if (ci_putchk(cs_ic(cs), msg) == -1) {
Christopher Fauleta0bdec32022-04-04 07:51:21 +02004255 cs_rx_room_blk(cs);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004256 return 0;
4257 }
4258
4259 return 1;
4260}
4261
Christopher Faulet6b0a0fb2022-04-04 11:29:28 +02004262/* Dump a table entry to a conn-stream's
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004263 * read buffer. It returns 0 if the output buffer is full
4264 * and needs to be called again, otherwise non-zero.
4265 */
Willy Tarreau83061a82018-07-13 11:56:34 +02004266static int table_dump_entry_to_buffer(struct buffer *msg,
Christopher Faulet908628c2022-03-25 16:43:49 +01004267 struct conn_stream *cs,
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004268 struct stktable *t, struct stksess *entry)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004269{
4270 int dt;
4271
4272 chunk_appendf(msg, "%p:", entry);
4273
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004274 if (t->type == SMP_T_IPV4) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004275 char addr[INET_ADDRSTRLEN];
4276 inet_ntop(AF_INET, (const void *)&entry->key.key, addr, sizeof(addr));
4277 chunk_appendf(msg, " key=%s", addr);
4278 }
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004279 else if (t->type == SMP_T_IPV6) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004280 char addr[INET6_ADDRSTRLEN];
4281 inet_ntop(AF_INET6, (const void *)&entry->key.key, addr, sizeof(addr));
4282 chunk_appendf(msg, " key=%s", addr);
4283 }
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004284 else if (t->type == SMP_T_SINT) {
Willy Tarreau6cde5d82020-02-25 09:41:22 +01004285 chunk_appendf(msg, " key=%u", read_u32(entry->key.key));
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004286 }
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004287 else if (t->type == SMP_T_STR) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004288 chunk_appendf(msg, " key=");
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004289 dump_text(msg, (const char *)entry->key.key, t->key_size);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004290 }
4291 else {
4292 chunk_appendf(msg, " key=");
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004293 dump_binary(msg, (const char *)entry->key.key, t->key_size);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004294 }
4295
4296 chunk_appendf(msg, " use=%d exp=%d", entry->ref_cnt - 1, tick_remain(now_ms, entry->expire));
4297
4298 for (dt = 0; dt < STKTABLE_DATA_TYPES; dt++) {
4299 void *ptr;
4300
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004301 if (t->data_ofs[dt] == 0)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004302 continue;
Emeric Brunc64a2a32021-06-30 18:01:02 +02004303 if (stktable_data_types[dt].is_array) {
4304 char tmp[16] = {};
4305 const char *name_pfx = stktable_data_types[dt].name;
4306 const char *name_sfx = NULL;
4307 unsigned int idx = 0;
4308 int i = 0;
4309
4310 /* split name to show index before first _ of the name
4311 * for example: 'gpc3_rate' if array name is 'gpc_rate'.
4312 */
4313 for (i = 0 ; i < (sizeof(tmp) - 1); i++) {
4314 if (!name_pfx[i])
4315 break;
4316 if (name_pfx[i] == '_') {
4317 name_pfx = &tmp[0];
4318 name_sfx = &stktable_data_types[dt].name[i];
4319 break;
4320 }
4321 tmp[i] = name_pfx[i];
4322 }
4323
4324 ptr = stktable_data_ptr_idx(t, entry, dt, idx);
4325 while (ptr) {
4326 if (stktable_data_types[dt].arg_type == ARG_T_DELAY)
4327 chunk_appendf(msg, " %s%u%s(%u)=", name_pfx, idx, name_sfx ? name_sfx : "", t->data_arg[dt].u);
4328 else
4329 chunk_appendf(msg, " %s%u%s=", name_pfx, idx, name_sfx ? name_sfx : "");
4330 switch (stktable_data_types[dt].std_type) {
4331 case STD_T_SINT:
4332 chunk_appendf(msg, "%d", stktable_data_cast(ptr, std_t_sint));
4333 break;
4334 case STD_T_UINT:
4335 chunk_appendf(msg, "%u", stktable_data_cast(ptr, std_t_uint));
4336 break;
4337 case STD_T_ULL:
4338 chunk_appendf(msg, "%llu", stktable_data_cast(ptr, std_t_ull));
4339 break;
4340 case STD_T_FRQP:
4341 chunk_appendf(msg, "%u",
4342 read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
4343 t->data_arg[dt].u));
4344 break;
4345 }
4346 ptr = stktable_data_ptr_idx(t, entry, dt, ++idx);
4347 }
4348 continue;
4349 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004350 if (stktable_data_types[dt].arg_type == ARG_T_DELAY)
Emeric Brun01928ae2021-06-30 16:24:04 +02004351 chunk_appendf(msg, " %s(%u)=", stktable_data_types[dt].name, t->data_arg[dt].u);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004352 else
4353 chunk_appendf(msg, " %s=", stktable_data_types[dt].name);
4354
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004355 ptr = stktable_data_ptr(t, entry, dt);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004356 switch (stktable_data_types[dt].std_type) {
4357 case STD_T_SINT:
4358 chunk_appendf(msg, "%d", stktable_data_cast(ptr, std_t_sint));
4359 break;
4360 case STD_T_UINT:
4361 chunk_appendf(msg, "%u", stktable_data_cast(ptr, std_t_uint));
4362 break;
4363 case STD_T_ULL:
Emeric Brun01928ae2021-06-30 16:24:04 +02004364 chunk_appendf(msg, "%llu", stktable_data_cast(ptr, std_t_ull));
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004365 break;
4366 case STD_T_FRQP:
Emeric Brun01928ae2021-06-30 16:24:04 +02004367 chunk_appendf(msg, "%u",
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004368 read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004369 t->data_arg[dt].u));
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004370 break;
Frédéric Lécaille16b4f542019-05-23 12:15:04 +02004371 case STD_T_DICT: {
4372 struct dict_entry *de;
4373 de = stktable_data_cast(ptr, std_t_dict);
4374 chunk_appendf(msg, "%s", de ? (char *)de->value.key : "-");
4375 break;
4376 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004377 }
4378 }
4379 chunk_appendf(msg, "\n");
4380
Christopher Faulet908628c2022-03-25 16:43:49 +01004381 if (ci_putchk(cs_ic(cs), msg) == -1) {
Christopher Fauleta0bdec32022-04-04 07:51:21 +02004382 cs_rx_room_blk(cs);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004383 return 0;
4384 }
4385
4386 return 1;
4387}
4388
4389
4390/* Processes a single table entry matching a specific key passed in argument.
4391 * returns 0 if wants to be called again, 1 if has ended processing.
4392 */
4393static int table_process_entry_per_key(struct appctx *appctx, char **args)
4394{
Christopher Faulet908628c2022-03-25 16:43:49 +01004395 struct conn_stream *cs = appctx->owner;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004396 struct stktable *t = appctx->ctx.table.target;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004397 struct stksess *ts;
4398 uint32_t uint32_key;
4399 unsigned char ip6_key[sizeof(struct in6_addr)];
4400 long long value;
4401 int data_type;
4402 int cur_arg;
4403 void *ptr;
Willy Tarreaufa1258f2021-04-10 23:00:53 +02004404 struct freq_ctr *frqp;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004405
Willy Tarreau9d008692019-08-09 11:21:01 +02004406 if (!*args[4])
4407 return cli_err(appctx, "Key value expected\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004408
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004409 switch (t->type) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004410 case SMP_T_IPV4:
4411 uint32_key = htonl(inetaddr_host(args[4]));
Christopher Fauletca20d022017-08-29 15:30:31 +02004412 static_table_key.key = &uint32_key;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004413 break;
4414 case SMP_T_IPV6:
Christopher Fauletb7c962b2021-11-15 09:17:25 +01004415 if (inet_pton(AF_INET6, args[4], ip6_key) <= 0)
4416 return cli_err(appctx, "Invalid key\n");
Christopher Fauletca20d022017-08-29 15:30:31 +02004417 static_table_key.key = &ip6_key;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004418 break;
4419 case SMP_T_SINT:
4420 {
4421 char *endptr;
4422 unsigned long val;
4423 errno = 0;
4424 val = strtoul(args[4], &endptr, 10);
4425 if ((errno == ERANGE && val == ULONG_MAX) ||
4426 (errno != 0 && val == 0) || endptr == args[4] ||
Willy Tarreau9d008692019-08-09 11:21:01 +02004427 val > 0xffffffff)
4428 return cli_err(appctx, "Invalid key\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004429 uint32_key = (uint32_t) val;
Christopher Fauletca20d022017-08-29 15:30:31 +02004430 static_table_key.key = &uint32_key;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004431 break;
4432 }
4433 break;
4434 case SMP_T_STR:
Christopher Fauletca20d022017-08-29 15:30:31 +02004435 static_table_key.key = args[4];
4436 static_table_key.key_len = strlen(args[4]);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004437 break;
4438 default:
Willy Tarreaua24bc782016-12-14 15:50:35 +01004439 switch (appctx->ctx.table.action) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004440 case STK_CLI_ACT_SHOW:
Willy Tarreau9d008692019-08-09 11:21:01 +02004441 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 +01004442 case STK_CLI_ACT_CLR:
Willy Tarreau9d008692019-08-09 11:21:01 +02004443 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 +01004444 case STK_CLI_ACT_SET:
Willy Tarreau9d008692019-08-09 11:21:01 +02004445 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 +01004446 default:
Willy Tarreau9d008692019-08-09 11:21:01 +02004447 return cli_err(appctx, "Unknown action\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004448 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004449 }
4450
4451 /* check permissions */
4452 if (!cli_has_level(appctx, ACCESS_LVL_OPER))
4453 return 1;
4454
Willy Tarreaua24bc782016-12-14 15:50:35 +01004455 switch (appctx->ctx.table.action) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004456 case STK_CLI_ACT_SHOW:
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004457 ts = stktable_lookup_key(t, &static_table_key);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004458 if (!ts)
4459 return 1;
4460 chunk_reset(&trash);
Christopher Faulet908628c2022-03-25 16:43:49 +01004461 if (!table_dump_head_to_buffer(&trash, cs, t, t)) {
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004462 stktable_release(t, ts);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004463 return 0;
Emeric Brun819fc6f2017-06-13 19:37:32 +02004464 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004465 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &ts->lock);
Christopher Faulet908628c2022-03-25 16:43:49 +01004466 if (!table_dump_entry_to_buffer(&trash, cs, t, ts)) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004467 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004468 stktable_release(t, ts);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004469 return 0;
Emeric Brun819fc6f2017-06-13 19:37:32 +02004470 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004471 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004472 stktable_release(t, ts);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004473 break;
4474
4475 case STK_CLI_ACT_CLR:
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004476 ts = stktable_lookup_key(t, &static_table_key);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004477 if (!ts)
4478 return 1;
Emeric Brun819fc6f2017-06-13 19:37:32 +02004479
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004480 if (!stksess_kill(t, ts, 1)) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004481 /* don't delete an entry which is currently referenced */
Willy Tarreau9d008692019-08-09 11:21:01 +02004482 return cli_err(appctx, "Entry currently in use, cannot remove\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004483 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004484 break;
4485
4486 case STK_CLI_ACT_SET:
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004487 ts = stktable_get_entry(t, &static_table_key);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004488 if (!ts) {
4489 /* don't delete an entry which is currently referenced */
Willy Tarreau9d008692019-08-09 11:21:01 +02004490 return cli_err(appctx, "Unable to allocate a new entry\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004491 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004492 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004493 for (cur_arg = 5; *args[cur_arg]; cur_arg += 2) {
4494 if (strncmp(args[cur_arg], "data.", 5) != 0) {
Willy Tarreau9d008692019-08-09 11:21:01 +02004495 cli_err(appctx, "\"data.<type>\" followed by a value expected\n");
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004496 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004497 stktable_touch_local(t, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004498 return 1;
4499 }
4500
4501 data_type = stktable_get_data_type(args[cur_arg] + 5);
4502 if (data_type < 0) {
Willy Tarreau9d008692019-08-09 11:21:01 +02004503 cli_err(appctx, "Unknown data type\n");
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004504 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004505 stktable_touch_local(t, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004506 return 1;
4507 }
4508
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004509 if (!t->data_ofs[data_type]) {
Willy Tarreau9d008692019-08-09 11:21:01 +02004510 cli_err(appctx, "Data type not stored in this table\n");
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004511 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004512 stktable_touch_local(t, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004513 return 1;
4514 }
4515
4516 if (!*args[cur_arg+1] || strl2llrc(args[cur_arg+1], strlen(args[cur_arg+1]), &value) != 0) {
Willy Tarreau9d008692019-08-09 11:21:01 +02004517 cli_err(appctx, "Require a valid integer value to store\n");
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004518 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004519 stktable_touch_local(t, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004520 return 1;
4521 }
4522
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004523 ptr = stktable_data_ptr(t, ts, data_type);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004524
4525 switch (stktable_data_types[data_type].std_type) {
4526 case STD_T_SINT:
4527 stktable_data_cast(ptr, std_t_sint) = value;
4528 break;
4529 case STD_T_UINT:
4530 stktable_data_cast(ptr, std_t_uint) = value;
4531 break;
4532 case STD_T_ULL:
4533 stktable_data_cast(ptr, std_t_ull) = value;
4534 break;
4535 case STD_T_FRQP:
4536 /* We set both the current and previous values. That way
4537 * the reported frequency is stable during all the period
4538 * then slowly fades out. This allows external tools to
4539 * push measures without having to update them too often.
4540 */
4541 frqp = &stktable_data_cast(ptr, std_t_frqp);
Willy Tarreaufa1258f2021-04-10 23:00:53 +02004542 /* First bit is reserved for the freq_ctr lock
Emeric Brunf2fc1fd2017-11-02 17:32:43 +01004543 Note: here we're still protected by the stksess lock
Willy Tarreaufa1258f2021-04-10 23:00:53 +02004544 so we don't need to update the update the freq_ctr
Emeric Brunf2fc1fd2017-11-02 17:32:43 +01004545 using its internal lock */
4546 frqp->curr_tick = now_ms & ~0x1;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004547 frqp->prev_ctr = 0;
4548 frqp->curr_ctr = value;
4549 break;
4550 }
4551 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004552 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004553 stktable_touch_local(t, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004554 break;
4555
4556 default:
Willy Tarreau9d008692019-08-09 11:21:01 +02004557 return cli_err(appctx, "Unknown action\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004558 }
4559 return 1;
4560}
4561
4562/* Prepares the appctx fields with the data-based filters from the command line.
4563 * Returns 0 if the dump can proceed, 1 if has ended processing.
4564 */
4565static int table_prepare_data_request(struct appctx *appctx, char **args)
4566{
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004567 int i;
Adis Nezirovicd0142e72020-01-22 16:50:27 +01004568 char *err = NULL;
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004569
Willy Tarreau9d008692019-08-09 11:21:01 +02004570 if (appctx->ctx.table.action != STK_CLI_ACT_SHOW && appctx->ctx.table.action != STK_CLI_ACT_CLR)
4571 return cli_err(appctx, "content-based lookup is only supported with the \"show\" and \"clear\" actions\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004572
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004573 for (i = 0; i < STKTABLE_FILTER_LEN; i++) {
4574 if (i > 0 && !*args[3+3*i]) // number of filter entries can be less than STKTABLE_FILTER_LEN
4575 break;
4576 /* condition on stored data value */
4577 appctx->ctx.table.data_type[i] = stktable_get_data_type(args[3+3*i] + 5);
4578 if (appctx->ctx.table.data_type[i] < 0)
Adis Nezirovicd0142e72020-01-22 16:50:27 +01004579 return cli_dynerr(appctx, memprintf(&err, "Filter entry #%i: Unknown data type\n", i + 1));
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004580
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004581 if (!((struct stktable *)appctx->ctx.table.target)->data_ofs[appctx->ctx.table.data_type[i]])
Adis Nezirovicd0142e72020-01-22 16:50:27 +01004582 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 +01004583
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004584 appctx->ctx.table.data_op[i] = get_std_op(args[4+3*i]);
Willy Tarreau2b64a352020-01-22 17:09:47 +01004585 if (appctx->ctx.table.data_op[i] < 0)
Adis Nezirovicd0142e72020-01-22 16:50:27 +01004586 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 +01004587
Adis Nezirovic56dd3542020-01-22 16:16:48 +01004588 if (!*args[5+3*i] || strl2llrc(args[5+3*i], strlen(args[5+3*i]), &appctx->ctx.table.value[i]) != 0)
Adis Nezirovicd0142e72020-01-22 16:50:27 +01004589 return cli_dynerr(appctx, memprintf(&err, "Filter entry #%i: Require a valid integer value to compare against\n", i + 1));
4590 }
4591
4592 if (*args[3+3*i]) {
4593 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 +01004594 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004595
4596 /* OK we're done, all the fields are set */
4597 return 0;
4598}
4599
4600/* returns 0 if wants to be called, 1 if has ended processing */
Aurélien Nephtaliabbf6072018-04-18 13:26:46 +02004601static int cli_parse_table_req(char **args, char *payload, struct appctx *appctx, void *private)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004602{
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004603 int i;
4604
4605 for (i = 0; i < STKTABLE_FILTER_LEN; i++)
4606 appctx->ctx.table.data_type[i] = -1;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004607 appctx->ctx.table.target = NULL;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004608 appctx->ctx.table.entry = NULL;
Willy Tarreaua24bc782016-12-14 15:50:35 +01004609 appctx->ctx.table.action = (long)private; // keyword argument, one of STK_CLI_ACT_*
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004610
4611 if (*args[2]) {
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004612 appctx->ctx.table.target = stktable_find_by_name(args[2]);
Willy Tarreau9d008692019-08-09 11:21:01 +02004613 if (!appctx->ctx.table.target)
4614 return cli_err(appctx, "No such table\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004615 }
4616 else {
Willy Tarreaua24bc782016-12-14 15:50:35 +01004617 if (appctx->ctx.table.action != STK_CLI_ACT_SHOW)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004618 goto err_args;
4619 return 0;
4620 }
4621
4622 if (strcmp(args[3], "key") == 0)
4623 return table_process_entry_per_key(appctx, args);
4624 else if (strncmp(args[3], "data.", 5) == 0)
4625 return table_prepare_data_request(appctx, args);
4626 else if (*args[3])
4627 goto err_args;
4628
4629 return 0;
4630
4631err_args:
Willy Tarreaua24bc782016-12-14 15:50:35 +01004632 switch (appctx->ctx.table.action) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004633 case STK_CLI_ACT_SHOW:
Willy Tarreau9d008692019-08-09 11:21:01 +02004634 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 +01004635 case STK_CLI_ACT_CLR:
Willy Tarreau9d008692019-08-09 11:21:01 +02004636 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 +01004637 case STK_CLI_ACT_SET:
Willy Tarreau9d008692019-08-09 11:21:01 +02004638 return cli_err(appctx, "Required arguments: <table> key <key> [data.<store_data_type> <value>]*\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004639 default:
Willy Tarreau9d008692019-08-09 11:21:01 +02004640 return cli_err(appctx, "Unknown action\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004641 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004642}
4643
4644/* This function is used to deal with table operations (dump or clear depending
4645 * on the action stored in appctx->private). It returns 0 if the output buffer is
4646 * full and it needs to be called again, otherwise non-zero.
4647 */
4648static int cli_io_handler_table(struct appctx *appctx)
4649{
Christopher Faulet908628c2022-03-25 16:43:49 +01004650 struct conn_stream *cs = appctx->owner;
4651 struct stream *s = __cs_strm(cs);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004652 struct ebmb_node *eb;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004653 int skip_entry;
Willy Tarreaua24bc782016-12-14 15:50:35 +01004654 int show = appctx->ctx.table.action == STK_CLI_ACT_SHOW;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004655
4656 /*
4657 * We have 3 possible states in appctx->st2 :
4658 * - STAT_ST_INIT : the first call
4659 * - STAT_ST_INFO : the proxy pointer points to the next table to
4660 * dump, the entry pointer is NULL ;
4661 * - STAT_ST_LIST : the proxy pointer points to the current table
4662 * and the entry pointer points to the next entry to be dumped,
4663 * and the refcount on the next entry is held ;
4664 * - STAT_ST_END : nothing left to dump, the buffer may contain some
4665 * data though.
4666 */
4667
Christopher Faulet908628c2022-03-25 16:43:49 +01004668 if (unlikely(cs_ic(cs)->flags & (CF_WRITE_ERROR|CF_SHUTW))) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004669 /* in case of abort, remove any refcount we might have set on an entry */
4670 if (appctx->st2 == STAT_ST_LIST) {
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004671 stksess_kill_if_expired(appctx->ctx.table.t, appctx->ctx.table.entry, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004672 }
4673 return 1;
4674 }
4675
4676 chunk_reset(&trash);
4677
4678 while (appctx->st2 != STAT_ST_FIN) {
4679 switch (appctx->st2) {
4680 case STAT_ST_INIT:
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004681 appctx->ctx.table.t = appctx->ctx.table.target;
4682 if (!appctx->ctx.table.t)
4683 appctx->ctx.table.t = stktables_list;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004684
4685 appctx->ctx.table.entry = NULL;
4686 appctx->st2 = STAT_ST_INFO;
4687 break;
4688
4689 case STAT_ST_INFO:
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004690 if (!appctx->ctx.table.t ||
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004691 (appctx->ctx.table.target &&
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004692 appctx->ctx.table.t != appctx->ctx.table.target)) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004693 appctx->st2 = STAT_ST_END;
4694 break;
4695 }
4696
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004697 if (appctx->ctx.table.t->size) {
Christopher Faulet908628c2022-03-25 16:43:49 +01004698 if (show && !table_dump_head_to_buffer(&trash, cs, appctx->ctx.table.t, appctx->ctx.table.target))
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004699 return 0;
4700
4701 if (appctx->ctx.table.target &&
William Lallemand07a62f72017-05-24 00:57:40 +02004702 (strm_li(s)->bind_conf->level & ACCESS_LVL_MASK) >= ACCESS_LVL_OPER) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004703 /* dump entries only if table explicitly requested */
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004704 HA_SPIN_LOCK(STK_TABLE_LOCK, &appctx->ctx.table.t->lock);
4705 eb = ebmb_first(&appctx->ctx.table.t->keys);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004706 if (eb) {
4707 appctx->ctx.table.entry = ebmb_entry(eb, struct stksess, key);
4708 appctx->ctx.table.entry->ref_cnt++;
4709 appctx->st2 = STAT_ST_LIST;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004710 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &appctx->ctx.table.t->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004711 break;
4712 }
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004713 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &appctx->ctx.table.t->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004714 }
4715 }
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004716 appctx->ctx.table.t = appctx->ctx.table.t->next;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004717 break;
4718
4719 case STAT_ST_LIST:
4720 skip_entry = 0;
4721
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004722 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &appctx->ctx.table.entry->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004723
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004724 if (appctx->ctx.table.data_type[0] >= 0) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004725 /* we're filtering on some data contents */
4726 void *ptr;
Willy Tarreau2b64a352020-01-22 17:09:47 +01004727 int dt, i;
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004728 signed char op;
4729 long long data, value;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004730
Emeric Brun819fc6f2017-06-13 19:37:32 +02004731
Willy Tarreau2b64a352020-01-22 17:09:47 +01004732 for (i = 0; i < STKTABLE_FILTER_LEN; i++) {
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004733 if (appctx->ctx.table.data_type[i] == -1)
4734 break;
4735 dt = appctx->ctx.table.data_type[i];
4736 ptr = stktable_data_ptr(appctx->ctx.table.t,
4737 appctx->ctx.table.entry,
4738 dt);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004739
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004740 data = 0;
4741 switch (stktable_data_types[dt].std_type) {
4742 case STD_T_SINT:
4743 data = stktable_data_cast(ptr, std_t_sint);
4744 break;
4745 case STD_T_UINT:
4746 data = stktable_data_cast(ptr, std_t_uint);
4747 break;
4748 case STD_T_ULL:
4749 data = stktable_data_cast(ptr, std_t_ull);
4750 break;
4751 case STD_T_FRQP:
4752 data = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
4753 appctx->ctx.table.t->data_arg[dt].u);
4754 break;
4755 }
4756
4757 op = appctx->ctx.table.data_op[i];
4758 value = appctx->ctx.table.value[i];
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004759
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004760 /* skip the entry if the data does not match the test and the value */
4761 if ((data < value &&
4762 (op == STD_OP_EQ || op == STD_OP_GT || op == STD_OP_GE)) ||
4763 (data == value &&
4764 (op == STD_OP_NE || op == STD_OP_GT || op == STD_OP_LT)) ||
4765 (data > value &&
4766 (op == STD_OP_EQ || op == STD_OP_LT || op == STD_OP_LE))) {
4767 skip_entry = 1;
4768 break;
4769 }
4770 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004771 }
4772
4773 if (show && !skip_entry &&
Christopher Faulet908628c2022-03-25 16:43:49 +01004774 !table_dump_entry_to_buffer(&trash, cs, appctx->ctx.table.t, appctx->ctx.table.entry)) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004775 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &appctx->ctx.table.entry->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004776 return 0;
4777 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004778
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004779 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &appctx->ctx.table.entry->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004780
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004781 HA_SPIN_LOCK(STK_TABLE_LOCK, &appctx->ctx.table.t->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004782 appctx->ctx.table.entry->ref_cnt--;
4783
4784 eb = ebmb_next(&appctx->ctx.table.entry->key);
4785 if (eb) {
4786 struct stksess *old = appctx->ctx.table.entry;
4787 appctx->ctx.table.entry = ebmb_entry(eb, struct stksess, key);
4788 if (show)
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004789 __stksess_kill_if_expired(appctx->ctx.table.t, old);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004790 else if (!skip_entry && !appctx->ctx.table.entry->ref_cnt)
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004791 __stksess_kill(appctx->ctx.table.t, old);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004792 appctx->ctx.table.entry->ref_cnt++;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004793 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &appctx->ctx.table.t->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004794 break;
4795 }
4796
4797
4798 if (show)
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004799 __stksess_kill_if_expired(appctx->ctx.table.t, appctx->ctx.table.entry);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004800 else if (!skip_entry && !appctx->ctx.table.entry->ref_cnt)
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004801 __stksess_kill(appctx->ctx.table.t, appctx->ctx.table.entry);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004802
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004803 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &appctx->ctx.table.t->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004804
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004805 appctx->ctx.table.t = appctx->ctx.table.t->next;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004806 appctx->st2 = STAT_ST_INFO;
4807 break;
4808
4809 case STAT_ST_END:
4810 appctx->st2 = STAT_ST_FIN;
4811 break;
4812 }
4813 }
4814 return 1;
4815}
4816
4817static void cli_release_show_table(struct appctx *appctx)
4818{
4819 if (appctx->st2 == STAT_ST_LIST) {
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004820 stksess_kill_if_expired(appctx->ctx.table.t, appctx->ctx.table.entry, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004821 }
4822}
4823
Willy Tarreau478331d2020-08-28 11:31:31 +02004824static void stkt_late_init(void)
4825{
4826 struct sample_fetch *f;
4827
4828 f = find_sample_fetch("src", strlen("src"));
4829 if (f)
4830 smp_fetch_src = f->process;
4831}
4832
4833INITCALL0(STG_INIT, stkt_late_init);
4834
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004835/* register cli keywords */
4836static struct cli_kw_list cli_kws = {{ },{
Willy Tarreaub205bfd2021-05-07 11:38:37 +02004837 { { "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 },
4838 { { "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 },
4839 { { "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 +01004840 {{},}
4841}};
4842
Willy Tarreau0108d902018-11-25 19:14:37 +01004843INITCALL1(STG_REGISTER, cli_register_kw, &cli_kws);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004844
Thierry FOURNIER236657b2015-08-19 08:25:14 +02004845static struct action_kw_list tcp_conn_kws = { { }, {
Emeric Brun4d7ada82021-06-30 19:04:16 +02004846 { "sc-inc-gpc", parse_inc_gpc, KWF_MATCH_PREFIX },
4847 { "sc-inc-gpc0", parse_inc_gpc, KWF_MATCH_PREFIX },
4848 { "sc-inc-gpc1", parse_inc_gpc, KWF_MATCH_PREFIX },
Emeric Brun877b0b52021-06-30 18:57:49 +02004849 { "sc-set-gpt", parse_set_gpt, KWF_MATCH_PREFIX },
4850 { "sc-set-gpt0", parse_set_gpt, KWF_MATCH_PREFIX },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02004851 { /* END */ }
4852}};
4853
Willy Tarreau0108d902018-11-25 19:14:37 +01004854INITCALL1(STG_REGISTER, tcp_req_conn_keywords_register, &tcp_conn_kws);
4855
Willy Tarreau620408f2016-10-21 16:37:51 +02004856static struct action_kw_list tcp_sess_kws = { { }, {
Emeric Brun4d7ada82021-06-30 19:04:16 +02004857 { "sc-inc-gpc", parse_inc_gpc, KWF_MATCH_PREFIX },
4858 { "sc-inc-gpc0", parse_inc_gpc, KWF_MATCH_PREFIX },
4859 { "sc-inc-gpc1", parse_inc_gpc, KWF_MATCH_PREFIX },
Emeric Brun877b0b52021-06-30 18:57:49 +02004860 { "sc-set-gpt", parse_set_gpt, KWF_MATCH_PREFIX },
4861 { "sc-set-gpt0", parse_set_gpt, KWF_MATCH_PREFIX },
Willy Tarreau620408f2016-10-21 16:37:51 +02004862 { /* END */ }
4863}};
4864
Willy Tarreau0108d902018-11-25 19:14:37 +01004865INITCALL1(STG_REGISTER, tcp_req_sess_keywords_register, &tcp_sess_kws);
4866
Thierry FOURNIER236657b2015-08-19 08:25:14 +02004867static struct action_kw_list tcp_req_kws = { { }, {
Emeric Brun4d7ada82021-06-30 19:04:16 +02004868 { "sc-inc-gpc", parse_inc_gpc, KWF_MATCH_PREFIX },
4869 { "sc-inc-gpc0", parse_inc_gpc, KWF_MATCH_PREFIX },
4870 { "sc-inc-gpc1", parse_inc_gpc, KWF_MATCH_PREFIX },
Emeric Brun877b0b52021-06-30 18:57:49 +02004871 { "sc-set-gpt", parse_set_gpt, KWF_MATCH_PREFIX },
4872 { "sc-set-gpt0", parse_set_gpt, KWF_MATCH_PREFIX },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02004873 { /* END */ }
4874}};
4875
Willy Tarreau0108d902018-11-25 19:14:37 +01004876INITCALL1(STG_REGISTER, tcp_req_cont_keywords_register, &tcp_req_kws);
4877
Thierry FOURNIER236657b2015-08-19 08:25:14 +02004878static struct action_kw_list tcp_res_kws = { { }, {
Emeric Brun4d7ada82021-06-30 19:04:16 +02004879 { "sc-inc-gpc", parse_inc_gpc, KWF_MATCH_PREFIX },
4880 { "sc-inc-gpc0", parse_inc_gpc, KWF_MATCH_PREFIX },
4881 { "sc-inc-gpc1", parse_inc_gpc, KWF_MATCH_PREFIX },
Emeric Brun877b0b52021-06-30 18:57:49 +02004882 { "sc-set-gpt", parse_set_gpt, KWF_MATCH_PREFIX },
4883 { "sc-set-gpt0", parse_set_gpt, KWF_MATCH_PREFIX },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02004884 { /* END */ }
4885}};
4886
Willy Tarreau0108d902018-11-25 19:14:37 +01004887INITCALL1(STG_REGISTER, tcp_res_cont_keywords_register, &tcp_res_kws);
4888
Thierry FOURNIER236657b2015-08-19 08:25:14 +02004889static struct action_kw_list http_req_kws = { { }, {
Emeric Brun4d7ada82021-06-30 19:04:16 +02004890 { "sc-inc-gpc", parse_inc_gpc, KWF_MATCH_PREFIX },
4891 { "sc-inc-gpc0", parse_inc_gpc, KWF_MATCH_PREFIX },
4892 { "sc-inc-gpc1", parse_inc_gpc, KWF_MATCH_PREFIX },
Emeric Brun877b0b52021-06-30 18:57:49 +02004893 { "sc-set-gpt", parse_set_gpt, KWF_MATCH_PREFIX },
4894 { "sc-set-gpt0", parse_set_gpt, KWF_MATCH_PREFIX },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02004895 { /* END */ }
4896}};
4897
Willy Tarreau0108d902018-11-25 19:14:37 +01004898INITCALL1(STG_REGISTER, http_req_keywords_register, &http_req_kws);
4899
Thierry FOURNIER236657b2015-08-19 08:25:14 +02004900static struct action_kw_list http_res_kws = { { }, {
Emeric Brun4d7ada82021-06-30 19:04:16 +02004901 { "sc-inc-gpc", parse_inc_gpc, KWF_MATCH_PREFIX },
4902 { "sc-inc-gpc0", parse_inc_gpc, KWF_MATCH_PREFIX },
4903 { "sc-inc-gpc1", parse_inc_gpc, KWF_MATCH_PREFIX },
Emeric Brun877b0b52021-06-30 18:57:49 +02004904 { "sc-set-gpt", parse_set_gpt, KWF_MATCH_PREFIX },
4905 { "sc-set-gpt0", parse_set_gpt, KWF_MATCH_PREFIX },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02004906 { /* END */ }
4907}};
4908
Willy Tarreau0108d902018-11-25 19:14:37 +01004909INITCALL1(STG_REGISTER, http_res_keywords_register, &http_res_kws);
4910
Willy Tarreau7d562212016-11-25 16:10:05 +01004911/* Note: must not be declared <const> as its list will be overwritten.
4912 * Please take care of keeping this list alphabetically sorted.
4913 */
4914static struct sample_fetch_kw_list smp_fetch_keywords = {ILH, {
4915 { "sc_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4916 { "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 +02004917 { "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 +01004918 { "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 +01004919 { "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 +01004920 { "sc_conn_cnt", smp_fetch_sc_conn_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4921 { "sc_conn_cur", smp_fetch_sc_conn_cur, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4922 { "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 +02004923 { "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 +01004924 { "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 +02004925 { "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 +01004926 { "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 +01004927 { "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 +02004928 { "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 +01004929 { "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 +01004930 { "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 +01004931 { "sc_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4932 { "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 +01004933 { "sc_http_fail_cnt", smp_fetch_sc_http_fail_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4934 { "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 +01004935 { "sc_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4936 { "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 +02004937 { "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 +01004938 { "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 +01004939 { "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 +01004940 { "sc_kbytes_in", smp_fetch_sc_kbytes_in, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4941 { "sc_kbytes_out", smp_fetch_sc_kbytes_out, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4942 { "sc_sess_cnt", smp_fetch_sc_sess_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4943 { "sc_sess_rate", smp_fetch_sc_sess_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4944 { "sc_tracked", smp_fetch_sc_tracked, ARG2(1,SINT,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
4945 { "sc_trackers", smp_fetch_sc_trackers, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4946 { "sc0_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4947 { "sc0_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4948 { "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 +01004949 { "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 +01004950 { "sc0_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4951 { "sc0_conn_cur", smp_fetch_sc_conn_cur, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4952 { "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 +01004953 { "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 +01004954 { "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 +01004955 { "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 +01004956 { "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 +01004957 { "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 +01004958 { "sc0_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4959 { "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 +01004960 { "sc0_http_fail_cnt", smp_fetch_sc_http_fail_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4961 { "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 +01004962 { "sc0_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4963 { "sc0_http_req_rate", smp_fetch_sc_http_req_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4964 { "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 +01004965 { "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 +01004966 { "sc0_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4967 { "sc0_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4968 { "sc0_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4969 { "sc0_sess_rate", smp_fetch_sc_sess_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4970 { "sc0_tracked", smp_fetch_sc_tracked, ARG1(0,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
4971 { "sc0_trackers", smp_fetch_sc_trackers, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4972 { "sc1_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4973 { "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 +02004974 { "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 +01004975 { "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 +01004976 { "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 +01004977 { "sc1_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4978 { "sc1_conn_cur", smp_fetch_sc_conn_cur, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4979 { "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 +01004980 { "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 +01004981 { "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 +01004982 { "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 +01004983 { "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 +01004984 { "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 +01004985 { "sc1_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4986 { "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 +01004987 { "sc1_http_fail_cnt", smp_fetch_sc_http_fail_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4988 { "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 +01004989 { "sc1_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4990 { "sc1_http_req_rate", smp_fetch_sc_http_req_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4991 { "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 +01004992 { "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 +01004993 { "sc1_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4994 { "sc1_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4995 { "sc1_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4996 { "sc1_sess_rate", smp_fetch_sc_sess_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4997 { "sc1_tracked", smp_fetch_sc_tracked, ARG1(0,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
4998 { "sc1_trackers", smp_fetch_sc_trackers, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4999 { "sc2_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5000 { "sc2_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5001 { "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 +01005002 { "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 +01005003 { "sc2_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5004 { "sc2_conn_cur", smp_fetch_sc_conn_cur, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5005 { "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 +01005006 { "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 +01005007 { "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 +01005008 { "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 +01005009 { "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 +01005010 { "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 +01005011 { "sc2_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5012 { "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 +01005013 { "sc2_http_fail_cnt", smp_fetch_sc_http_fail_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5014 { "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 +01005015 { "sc2_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5016 { "sc2_http_req_rate", smp_fetch_sc_http_req_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5017 { "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 +01005018 { "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 +01005019 { "sc2_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5020 { "sc2_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5021 { "sc2_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5022 { "sc2_sess_rate", smp_fetch_sc_sess_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5023 { "sc2_tracked", smp_fetch_sc_tracked, ARG1(0,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
5024 { "sc2_trackers", smp_fetch_sc_trackers, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5025 { "src_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5026 { "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 +02005027 { "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 +01005028 { "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 +01005029 { "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 +01005030 { "src_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5031 { "src_conn_cur", smp_fetch_sc_conn_cur, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5032 { "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 +02005033 { "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 +01005034 { "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 +02005035 { "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 +01005036 { "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 +01005037 { "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 +02005038 { "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 +01005039 { "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 +01005040 { "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 +01005041 { "src_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5042 { "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 +01005043 { "src_http_fail_cnt", smp_fetch_sc_http_fail_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5044 { "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 +01005045 { "src_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5046 { "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 +02005047 { "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 +01005048 { "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 +01005049 { "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 +01005050 { "src_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5051 { "src_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5052 { "src_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5053 { "src_sess_rate", smp_fetch_sc_sess_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5054 { "src_updt_conn_cnt", smp_fetch_src_updt_conn_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5055 { "table_avl", smp_fetch_table_avl, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5056 { "table_cnt", smp_fetch_table_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5057 { /* END */ },
5058}};
5059
Willy Tarreau0108d902018-11-25 19:14:37 +01005060INITCALL1(STG_REGISTER, sample_register_fetches, &smp_fetch_keywords);
Willy Tarreau7d562212016-11-25 16:10:05 +01005061
Willy Tarreaud9f316a2014-07-10 14:03:38 +02005062/* Note: must not be declared <const> as its list will be overwritten */
5063static struct sample_conv_kw_list sample_conv_kws = {ILH, {
Willy Tarreau2d17db52016-05-25 17:16:38 +02005064 { "in_table", sample_conv_in_table, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_BOOL },
5065 { "table_bytes_in_rate", sample_conv_table_bytes_in_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5066 { "table_bytes_out_rate", sample_conv_table_bytes_out_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5067 { "table_conn_cnt", sample_conv_table_conn_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5068 { "table_conn_cur", sample_conv_table_conn_cur, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5069 { "table_conn_rate", sample_conv_table_conn_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
Emeric Brun877b0b52021-06-30 18:57:49 +02005070 { "table_gpt", sample_conv_table_gpt, ARG2(2,SINT,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
Willy Tarreau2d17db52016-05-25 17:16:38 +02005071 { "table_gpt0", sample_conv_table_gpt0, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
Emeric Brun4d7ada82021-06-30 19:04:16 +02005072 { "table_gpc", sample_conv_table_gpc, ARG2(2,SINT,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
Willy Tarreau2d17db52016-05-25 17:16:38 +02005073 { "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 +01005074 { "table_gpc1", sample_conv_table_gpc1, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
Emeric Brun4d7ada82021-06-30 19:04:16 +02005075 { "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 +02005076 { "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 +01005077 { "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 +02005078 { "table_http_err_cnt", sample_conv_table_http_err_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5079 { "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 +01005080 { "table_http_fail_cnt", sample_conv_table_http_fail_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5081 { "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 +02005082 { "table_http_req_cnt", sample_conv_table_http_req_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5083 { "table_http_req_rate", sample_conv_table_http_req_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5084 { "table_kbytes_in", sample_conv_table_kbytes_in, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5085 { "table_kbytes_out", sample_conv_table_kbytes_out, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5086 { "table_server_id", sample_conv_table_server_id, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5087 { "table_sess_cnt", sample_conv_table_sess_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5088 { "table_sess_rate", sample_conv_table_sess_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5089 { "table_trackers", sample_conv_table_trackers, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
Willy Tarreaud9f316a2014-07-10 14:03:38 +02005090 { /* END */ },
5091}};
5092
Willy Tarreau0108d902018-11-25 19:14:37 +01005093INITCALL1(STG_REGISTER, sample_register_convs, &sample_conv_kws);