blob: e50ef2571e92812030501d969e2ca9d244b29613 [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>
Thayne McCombs92149f92020-11-20 01:28:26 -070025#include <haproxy/dict.h>
Willy Tarreau36979d92020-06-05 17:27:29 +020026#include <haproxy/errors.h>
Willy Tarreauf268ee82020-06-04 17:05:57 +020027#include <haproxy/global.h>
Willy Tarreauc761f842020-06-04 11:40:28 +020028#include <haproxy/http_rules.h>
Willy Tarreau853b2972020-05-27 18:01:47 +020029#include <haproxy/list.h>
Willy Tarreauaeed4a82020-06-04 22:01:04 +020030#include <haproxy/log.h>
Willy Tarreau6131d6a2020-06-02 16:48:09 +020031#include <haproxy/net_helper.h>
Willy Tarreau3c2a7c22020-06-04 18:38:21 +020032#include <haproxy/peers.h>
Willy Tarreaub2551052020-06-09 09:07:15 +020033#include <haproxy/pool.h>
34#include <haproxy/proto_tcp.h>
Willy Tarreaua264d962020-06-04 22:29:18 +020035#include <haproxy/proxy.h>
Willy Tarreaub2551052020-06-09 09:07:15 +020036#include <haproxy/sample.h>
Willy Tarreau2eec9b52020-06-04 19:58:55 +020037#include <haproxy/stats-t.h>
Willy Tarreaub2551052020-06-09 09:07:15 +020038#include <haproxy/stick_table.h>
Willy Tarreaudfd3de82020-06-04 23:46:14 +020039#include <haproxy/stream.h>
Willy Tarreau5e539c92020-06-04 20:45:39 +020040#include <haproxy/stream_interface.h>
Willy Tarreaucea0e1b2020-06-04 17:25:40 +020041#include <haproxy/task.h>
Willy Tarreau8b550af2020-06-04 17:42:48 +020042#include <haproxy/tcp_rules.h>
Willy Tarreau92b4f132020-06-01 11:05:15 +020043#include <haproxy/time.h>
Willy Tarreaub2551052020-06-09 09:07:15 +020044#include <haproxy/tools.h>
Emeric Brun3bd697e2010-01-04 15:23:48 +010045
Emeric Brun3bd697e2010-01-04 15:23:48 +010046
Willy Tarreau12785782012-04-27 21:37:17 +020047/* structure used to return a table key built from a sample */
Emeric Brun819fc6f2017-06-13 19:37:32 +020048static THREAD_LOCAL struct stktable_key static_table_key;
Willy Tarreau478331d2020-08-28 11:31:31 +020049static int (*smp_fetch_src)(const struct arg *, struct sample *, const char *, void *);
Willy Tarreauf0b38bf2010-06-06 13:22:23 +020050
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +010051struct stktable *stktables_list;
52struct eb_root stktable_by_name = EB_ROOT;
53
Olivier Houchard52dabbc2018-11-14 17:54:36 +010054#define round_ptr_size(i) (((i) + (sizeof(void *) - 1)) &~ (sizeof(void *) - 1))
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +010055
56/* This function inserts stktable <t> into the tree of known stick-table.
57 * The stick-table ID is used as the storing key so it must already have
58 * been initialized.
59 */
60void stktable_store_name(struct stktable *t)
61{
62 t->name.key = t->id;
63 ebis_insert(&stktable_by_name, &t->name);
64}
65
66struct stktable *stktable_find_by_name(const char *name)
67{
68 struct ebpt_node *node;
69 struct stktable *t;
70
71 node = ebis_lookup(&stktable_by_name, name);
72 if (node) {
73 t = container_of(node, struct stktable, name);
Tim Duesterhuse5ff1412021-01-02 22:31:53 +010074 if (strcmp(t->id, name) == 0)
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +010075 return t;
76 }
77
78 return NULL;
79}
80
Emeric Brun3bd697e2010-01-04 15:23:48 +010081/*
Willy Tarreauaea940e2010-06-06 11:56:36 +020082 * Free an allocated sticky session <ts>, and decrease sticky sessions counter
83 * in table <t>.
Emeric Brun3bd697e2010-01-04 15:23:48 +010084 */
Emeric Brun819fc6f2017-06-13 19:37:32 +020085void __stksess_free(struct stktable *t, struct stksess *ts)
Emeric Brun3bd697e2010-01-04 15:23:48 +010086{
87 t->current--;
Olivier Houchard52dabbc2018-11-14 17:54:36 +010088 pool_free(t->pool, (void *)ts - round_ptr_size(t->data_size));
Emeric Brun3bd697e2010-01-04 15:23:48 +010089}
90
91/*
Emeric Brun819fc6f2017-06-13 19:37:32 +020092 * Free an allocated sticky session <ts>, and decrease sticky sessions counter
93 * in table <t>.
94 * This function locks the table
95 */
96void stksess_free(struct stktable *t, struct stksess *ts)
97{
Thayne McCombs92149f92020-11-20 01:28:26 -070098 void *data;
99 data = stktable_data_ptr(t, ts, STKTABLE_DT_SERVER_KEY);
100 if (data) {
Emeric Brun0e3457b2021-06-30 17:18:28 +0200101 dict_entry_unref(&server_key_dict, stktable_data_cast(data, std_t_dict));
102 stktable_data_cast(data, std_t_dict) = NULL;
Thayne McCombs92149f92020-11-20 01:28:26 -0700103 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100104 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200105 __stksess_free(t, ts);
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100106 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200107}
108
109/*
Willy Tarreauf6efda12010-08-03 20:34:06 +0200110 * Kill an stksess (only if its ref_cnt is zero).
111 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200112int __stksess_kill(struct stktable *t, struct stksess *ts)
Willy Tarreauf6efda12010-08-03 20:34:06 +0200113{
114 if (ts->ref_cnt)
Emeric Brun819fc6f2017-06-13 19:37:32 +0200115 return 0;
Willy Tarreauf6efda12010-08-03 20:34:06 +0200116
117 eb32_delete(&ts->exp);
Emeric Brun85e77c72010-09-23 18:16:52 +0200118 eb32_delete(&ts->upd);
Willy Tarreauf6efda12010-08-03 20:34:06 +0200119 ebmb_delete(&ts->key);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200120 __stksess_free(t, ts);
121 return 1;
Willy Tarreauf6efda12010-08-03 20:34:06 +0200122}
123
124/*
Emeric Brun819fc6f2017-06-13 19:37:32 +0200125 * Decrease the refcount if decrefcnt is not 0.
126 * and try to kill the stksess
127 * This function locks the table
128 */
129int stksess_kill(struct stktable *t, struct stksess *ts, int decrefcnt)
130{
131 int ret;
132
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100133 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200134 if (decrefcnt)
135 ts->ref_cnt--;
136 ret = __stksess_kill(t, ts);
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100137 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200138
139 return ret;
140}
141
142/*
Willy Tarreauaea940e2010-06-06 11:56:36 +0200143 * Initialize or update the key in the sticky session <ts> present in table <t>
144 * from the value present in <key>.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100145 */
Willy Tarreau393379c2010-06-06 12:11:37 +0200146void stksess_setkey(struct stktable *t, struct stksess *ts, struct stktable_key *key)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100147{
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200148 if (t->type != SMP_T_STR)
Willy Tarreau86257dc2010-06-06 12:57:10 +0200149 memcpy(ts->key.key, key->key, t->key_size);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100150 else {
Willy Tarreau86257dc2010-06-06 12:57:10 +0200151 memcpy(ts->key.key, key->key, MIN(t->key_size - 1, key->key_len));
152 ts->key.key[MIN(t->key_size - 1, key->key_len)] = 0;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100153 }
154}
155
156
157/*
Willy Tarreau393379c2010-06-06 12:11:37 +0200158 * Init sticky session <ts> of table <t>. The data parts are cleared and <ts>
159 * is returned.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100160 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200161static struct stksess *__stksess_init(struct stktable *t, struct stksess * ts)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100162{
Willy Tarreau393379c2010-06-06 12:11:37 +0200163 memset((void *)ts - t->data_size, 0, t->data_size);
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200164 ts->ref_cnt = 0;
Willy Tarreau86257dc2010-06-06 12:57:10 +0200165 ts->key.node.leaf_p = NULL;
166 ts->exp.node.leaf_p = NULL;
Emeric Brun85e77c72010-09-23 18:16:52 +0200167 ts->upd.node.leaf_p = NULL;
Emeric Brun819fc6f2017-06-13 19:37:32 +0200168 ts->expire = tick_add(now_ms, MS_TO_TICKS(t->expire));
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100169 HA_RWLOCK_INIT(&ts->lock);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100170 return ts;
171}
172
173/*
Willy Tarreauaea940e2010-06-06 11:56:36 +0200174 * Trash oldest <to_batch> sticky sessions from table <t>
Willy Tarreaudfe79252020-11-03 17:47:41 +0100175 * Returns number of trashed sticky sessions. It may actually trash less
176 * than expected if finding these requires too long a search time (e.g.
177 * most of them have ts->ref_cnt>0).
Emeric Brun3bd697e2010-01-04 15:23:48 +0100178 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200179int __stktable_trash_oldest(struct stktable *t, int to_batch)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100180{
181 struct stksess *ts;
182 struct eb32_node *eb;
Willy Tarreaudfe79252020-11-03 17:47:41 +0100183 int max_search = to_batch * 2; // no more than 50% misses
Emeric Brun3bd697e2010-01-04 15:23:48 +0100184 int batched = 0;
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200185 int looped = 0;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100186
187 eb = eb32_lookup_ge(&t->exps, now_ms - TIMER_LOOK_BACK);
188
189 while (batched < to_batch) {
190
191 if (unlikely(!eb)) {
192 /* we might have reached the end of the tree, typically because
193 * <now_ms> is in the first half and we're first scanning the last
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200194 * half. Let's loop back to the beginning of the tree now if we
195 * have not yet visited it.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100196 */
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200197 if (looped)
198 break;
199 looped = 1;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100200 eb = eb32_first(&t->exps);
201 if (likely(!eb))
202 break;
203 }
204
Willy Tarreaudfe79252020-11-03 17:47:41 +0100205 if (--max_search < 0)
206 break;
207
Emeric Brun3bd697e2010-01-04 15:23:48 +0100208 /* timer looks expired, detach it from the queue */
Willy Tarreau86257dc2010-06-06 12:57:10 +0200209 ts = eb32_entry(eb, struct stksess, exp);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100210 eb = eb32_next(eb);
211
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200212 /* don't delete an entry which is currently referenced */
213 if (ts->ref_cnt)
214 continue;
215
Willy Tarreau86257dc2010-06-06 12:57:10 +0200216 eb32_delete(&ts->exp);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100217
Willy Tarreau86257dc2010-06-06 12:57:10 +0200218 if (ts->expire != ts->exp.key) {
Emeric Brun3bd697e2010-01-04 15:23:48 +0100219 if (!tick_isset(ts->expire))
220 continue;
221
Willy Tarreau86257dc2010-06-06 12:57:10 +0200222 ts->exp.key = ts->expire;
223 eb32_insert(&t->exps, &ts->exp);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100224
Willy Tarreau86257dc2010-06-06 12:57:10 +0200225 if (!eb || eb->key > ts->exp.key)
226 eb = &ts->exp;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100227
228 continue;
229 }
Emeric Brun3bd697e2010-01-04 15:23:48 +0100230
Willy Tarreauaea940e2010-06-06 11:56:36 +0200231 /* session expired, trash it */
Willy Tarreau86257dc2010-06-06 12:57:10 +0200232 ebmb_delete(&ts->key);
Emeric Brun85e77c72010-09-23 18:16:52 +0200233 eb32_delete(&ts->upd);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200234 __stksess_free(t, ts);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100235 batched++;
236 }
237
238 return batched;
239}
240
241/*
Emeric Brun819fc6f2017-06-13 19:37:32 +0200242 * Trash oldest <to_batch> sticky sessions from table <t>
243 * Returns number of trashed sticky sessions.
244 * This function locks the table
245 */
246int stktable_trash_oldest(struct stktable *t, int to_batch)
247{
248 int ret;
249
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100250 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200251 ret = __stktable_trash_oldest(t, to_batch);
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100252 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200253
254 return ret;
255}
256/*
Willy Tarreauaea940e2010-06-06 11:56:36 +0200257 * Allocate and initialise a new sticky session.
258 * The new sticky session is returned or NULL in case of lack of memory.
259 * Sticky sessions should only be allocated this way, and must be freed using
Willy Tarreaua7b46b52013-04-11 16:55:37 +0200260 * stksess_free(). Table <t>'s sticky session counter is increased. If <key>
261 * is not NULL, it is assigned to the new session.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100262 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200263struct stksess *__stksess_new(struct stktable *t, struct stktable_key *key)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100264{
265 struct stksess *ts;
266
267 if (unlikely(t->current == t->size)) {
268 if ( t->nopurge )
269 return NULL;
270
Emeric Brun819fc6f2017-06-13 19:37:32 +0200271 if (!__stktable_trash_oldest(t, (t->size >> 8) + 1))
Emeric Brun3bd697e2010-01-04 15:23:48 +0100272 return NULL;
273 }
274
Willy Tarreaubafbe012017-11-24 17:34:44 +0100275 ts = pool_alloc(t->pool);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100276 if (ts) {
277 t->current++;
Olivier Houchard52dabbc2018-11-14 17:54:36 +0100278 ts = (void *)ts + round_ptr_size(t->data_size);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200279 __stksess_init(t, ts);
Willy Tarreaua7b46b52013-04-11 16:55:37 +0200280 if (key)
281 stksess_setkey(t, ts, key);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100282 }
283
284 return ts;
285}
Emeric Brun819fc6f2017-06-13 19:37:32 +0200286/*
287 * Allocate and initialise a new sticky session.
288 * The new sticky session is returned or NULL in case of lack of memory.
289 * Sticky sessions should only be allocated this way, and must be freed using
290 * stksess_free(). Table <t>'s sticky session counter is increased. If <key>
291 * is not NULL, it is assigned to the new session.
292 * This function locks the table
293 */
294struct stksess *stksess_new(struct stktable *t, struct stktable_key *key)
295{
296 struct stksess *ts;
297
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100298 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200299 ts = __stksess_new(t, key);
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100300 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200301
302 return ts;
303}
Emeric Brun3bd697e2010-01-04 15:23:48 +0100304
305/*
Willy Tarreauf16d2b82010-06-06 15:38:59 +0200306 * Looks in table <t> for a sticky session matching key <key>.
Willy Tarreauaea940e2010-06-06 11:56:36 +0200307 * Returns pointer on requested sticky session or NULL if none was found.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100308 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200309struct stksess *__stktable_lookup_key(struct stktable *t, struct stktable_key *key)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100310{
311 struct ebmb_node *eb;
312
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200313 if (t->type == SMP_T_STR)
Emeric Brun485479d2010-09-23 18:02:19 +0200314 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 +0100315 else
316 eb = ebmb_lookup(&t->keys, key->key, t->key_size);
317
318 if (unlikely(!eb)) {
319 /* no session found */
320 return NULL;
321 }
322
Willy Tarreau86257dc2010-06-06 12:57:10 +0200323 return ebmb_entry(eb, struct stksess, key);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100324}
325
Emeric Brun819fc6f2017-06-13 19:37:32 +0200326/*
327 * Looks in table <t> for a sticky session matching key <key>.
328 * Returns pointer on requested sticky session or NULL if none was found.
329 * The refcount of the found entry is increased and this function
330 * is protected using the table lock
Willy Tarreau1f7e9252010-06-20 12:27:21 +0200331 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200332struct stksess *stktable_lookup_key(struct stktable *t, struct stktable_key *key)
Willy Tarreau1f7e9252010-06-20 12:27:21 +0200333{
334 struct stksess *ts;
335
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100336 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200337 ts = __stktable_lookup_key(t, key);
338 if (ts)
339 ts->ref_cnt++;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100340 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Willy Tarreau1f7e9252010-06-20 12:27:21 +0200341
Willy Tarreau1f7e9252010-06-20 12:27:21 +0200342 return ts;
343}
344
Willy Tarreauf16d2b82010-06-06 15:38:59 +0200345/*
346 * Looks in table <t> for a sticky session with same key as <ts>.
347 * Returns pointer on requested sticky session or NULL if none was found.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100348 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200349struct stksess *__stktable_lookup(struct stktable *t, struct stksess *ts)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100350{
Emeric Brun3bd697e2010-01-04 15:23:48 +0100351 struct ebmb_node *eb;
352
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200353 if (t->type == SMP_T_STR)
Willy Tarreau86257dc2010-06-06 12:57:10 +0200354 eb = ebst_lookup(&(t->keys), (char *)ts->key.key);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100355 else
Willy Tarreau86257dc2010-06-06 12:57:10 +0200356 eb = ebmb_lookup(&(t->keys), ts->key.key, t->key_size);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100357
Willy Tarreauf16d2b82010-06-06 15:38:59 +0200358 if (unlikely(!eb))
359 return NULL;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100360
Willy Tarreauf16d2b82010-06-06 15:38:59 +0200361 return ebmb_entry(eb, struct stksess, key);
362}
Emeric Brun3bd697e2010-01-04 15:23:48 +0100363
Emeric Brun819fc6f2017-06-13 19:37:32 +0200364/*
365 * Looks in table <t> for a sticky session with same key as <ts>.
366 * Returns pointer on requested sticky session or NULL if none was found.
367 * The refcount of the found entry is increased and this function
368 * is protected using the table lock
369 */
370struct stksess *stktable_lookup(struct stktable *t, struct stksess *ts)
371{
372 struct stksess *lts;
373
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100374 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200375 lts = __stktable_lookup(t, ts);
376 if (lts)
377 lts->ref_cnt++;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100378 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200379
380 return lts;
381}
382
Willy Tarreaucb183642010-06-06 17:58:34 +0200383/* Update the expiration timer for <ts> but do not touch its expiration node.
384 * The table's expiration timer is updated if set.
Emeric Brun819fc6f2017-06-13 19:37:32 +0200385 * The node will be also inserted into the update tree if needed, at a position
386 * depending if the update is a local or coming from a remote node
Willy Tarreaucb183642010-06-06 17:58:34 +0200387 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200388void __stktable_touch_with_exp(struct stktable *t, struct stksess *ts, int local, int expire)
Willy Tarreaucb183642010-06-06 17:58:34 +0200389{
Emeric Brun85e77c72010-09-23 18:16:52 +0200390 struct eb32_node * eb;
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200391 ts->expire = expire;
Willy Tarreaucb183642010-06-06 17:58:34 +0200392 if (t->expire) {
393 t->exp_task->expire = t->exp_next = tick_first(ts->expire, t->exp_next);
394 task_queue(t->exp_task);
395 }
Emeric Brun85e77c72010-09-23 18:16:52 +0200396
Emeric Brun819fc6f2017-06-13 19:37:32 +0200397 /* If sync is enabled */
398 if (t->sync_task) {
399 if (local) {
400 /* If this entry is not in the tree
401 or not scheduled for at least one peer */
402 if (!ts->upd.node.leaf_p
403 || (int)(t->commitupdate - ts->upd.key) >= 0
404 || (int)(ts->upd.key - t->localupdate) >= 0) {
405 ts->upd.key = ++t->update;
406 t->localupdate = t->update;
407 eb32_delete(&ts->upd);
408 eb = eb32_insert(&t->updates, &ts->upd);
409 if (eb != &ts->upd) {
410 eb32_delete(eb);
411 eb32_insert(&t->updates, &ts->upd);
412 }
Emeric Brunaaf58602015-06-15 17:23:30 +0200413 }
Emeric Brun819fc6f2017-06-13 19:37:32 +0200414 task_wakeup(t->sync_task, TASK_WOKEN_MSG);
Emeric Brun85e77c72010-09-23 18:16:52 +0200415 }
Emeric Brun819fc6f2017-06-13 19:37:32 +0200416 else {
417 /* If this entry is not in the tree */
418 if (!ts->upd.node.leaf_p) {
419 ts->upd.key= (++t->update)+(2147483648U);
420 eb = eb32_insert(&t->updates, &ts->upd);
421 if (eb != &ts->upd) {
422 eb32_delete(eb);
423 eb32_insert(&t->updates, &ts->upd);
424 }
425 }
426 }
Emeric Brun85e77c72010-09-23 18:16:52 +0200427 }
Willy Tarreaucb183642010-06-06 17:58:34 +0200428}
429
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200430/* Update the expiration timer for <ts> but do not touch its expiration node.
Emeric Brun819fc6f2017-06-13 19:37:32 +0200431 * The table's expiration timer is updated using the date of expiration coming from
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200432 * <t> stick-table configuration.
Emeric Brun819fc6f2017-06-13 19:37:32 +0200433 * The node will be also inserted into the update tree if needed, at a position
434 * considering the update is coming from a remote node
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200435 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200436void stktable_touch_remote(struct stktable *t, struct stksess *ts, int decrefcnt)
437{
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100438 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200439 __stktable_touch_with_exp(t, ts, 0, ts->expire);
440 if (decrefcnt)
441 ts->ref_cnt--;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100442 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200443}
444
445/* Update the expiration timer for <ts> but do not touch its expiration node.
446 * The table's expiration timer is updated using the date of expiration coming from
447 * <t> stick-table configuration.
448 * The node will be also inserted into the update tree if needed, at a position
449 * considering the update was made locally
450 */
451void stktable_touch_local(struct stktable *t, struct stksess *ts, int decrefcnt)
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200452{
453 int expire = tick_add(now_ms, MS_TO_TICKS(t->expire));
454
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100455 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200456 __stktable_touch_with_exp(t, ts, 1, expire);
457 if (decrefcnt)
458 ts->ref_cnt--;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100459 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200460}
Willy Tarreau43e90352018-06-27 06:25:57 +0200461/* Just decrease the ref_cnt of the current session. Does nothing if <ts> is NULL */
462static void stktable_release(struct stktable *t, struct stksess *ts)
Emeric Brun819fc6f2017-06-13 19:37:32 +0200463{
Willy Tarreau43e90352018-06-27 06:25:57 +0200464 if (!ts)
465 return;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100466 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200467 ts->ref_cnt--;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100468 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200469}
470
Willy Tarreauf16d2b82010-06-06 15:38:59 +0200471/* Insert new sticky session <ts> in the table. It is assumed that it does not
472 * yet exist (the caller must check this). The table's timeout is updated if it
473 * is set. <ts> is returned.
474 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200475void __stktable_store(struct stktable *t, struct stksess *ts)
Willy Tarreauf16d2b82010-06-06 15:38:59 +0200476{
Emeric Brun3bd697e2010-01-04 15:23:48 +0100477
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200478 ebmb_insert(&t->keys, &ts->key, t->key_size);
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200479 ts->exp.key = ts->expire;
480 eb32_insert(&t->exps, &ts->exp);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200481 if (t->expire) {
482 t->exp_task->expire = t->exp_next = tick_first(ts->expire, t->exp_next);
483 task_queue(t->exp_task);
484 }
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200485}
486
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200487/* Returns a valid or initialized stksess for the specified stktable_key in the
488 * specified table, or NULL if the key was NULL, or if no entry was found nor
489 * could be created. The entry's expiration is updated.
490 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200491struct stksess *__stktable_get_entry(struct stktable *table, struct stktable_key *key)
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200492{
493 struct stksess *ts;
494
495 if (!key)
496 return NULL;
497
Emeric Brun819fc6f2017-06-13 19:37:32 +0200498 ts = __stktable_lookup_key(table, key);
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200499 if (ts == NULL) {
500 /* entry does not exist, initialize a new one */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200501 ts = __stksess_new(table, key);
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200502 if (!ts)
503 return NULL;
Emeric Brun819fc6f2017-06-13 19:37:32 +0200504 __stktable_store(table, ts);
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200505 }
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200506 return ts;
507}
Emeric Brun819fc6f2017-06-13 19:37:32 +0200508/* Returns a valid or initialized stksess for the specified stktable_key in the
509 * specified table, or NULL if the key was NULL, or if no entry was found nor
510 * could be created. The entry's expiration is updated.
511 * This function locks the table, and the refcount of the entry is increased.
512 */
513struct stksess *stktable_get_entry(struct stktable *table, struct stktable_key *key)
514{
515 struct stksess *ts;
516
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100517 HA_SPIN_LOCK(STK_TABLE_LOCK, &table->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200518 ts = __stktable_get_entry(table, key);
519 if (ts)
520 ts->ref_cnt++;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100521 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &table->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200522
523 return ts;
524}
525
526/* Lookup for an entry with the same key and store the submitted
527 * stksess if not found.
528 */
529struct stksess *__stktable_set_entry(struct stktable *table, struct stksess *nts)
530{
531 struct stksess *ts;
532
533 ts = __stktable_lookup(table, nts);
534 if (ts == NULL) {
535 ts = nts;
536 __stktable_store(table, ts);
537 }
538 return ts;
539}
540
541/* Lookup for an entry with the same key and store the submitted
542 * stksess if not found.
543 * This function locks the table, and the refcount of the entry is increased.
544 */
545struct stksess *stktable_set_entry(struct stktable *table, struct stksess *nts)
546{
547 struct stksess *ts;
548
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100549 HA_SPIN_LOCK(STK_TABLE_LOCK, &table->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200550 ts = __stktable_set_entry(table, nts);
551 ts->ref_cnt++;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100552 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &table->lock);
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200553
Emeric Brun819fc6f2017-06-13 19:37:32 +0200554 return ts;
555}
Emeric Brun3bd697e2010-01-04 15:23:48 +0100556/*
Willy Tarreauaea940e2010-06-06 11:56:36 +0200557 * Trash expired sticky sessions from table <t>. The next expiration date is
558 * returned.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100559 */
560static int stktable_trash_expired(struct stktable *t)
561{
562 struct stksess *ts;
563 struct eb32_node *eb;
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200564 int looped = 0;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100565
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100566 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100567 eb = eb32_lookup_ge(&t->exps, now_ms - TIMER_LOOK_BACK);
568
569 while (1) {
570 if (unlikely(!eb)) {
571 /* we might have reached the end of the tree, typically because
572 * <now_ms> is in the first half and we're first scanning the last
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200573 * half. Let's loop back to the beginning of the tree now if we
574 * have not yet visited it.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100575 */
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200576 if (looped)
577 break;
578 looped = 1;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100579 eb = eb32_first(&t->exps);
580 if (likely(!eb))
581 break;
582 }
583
584 if (likely(tick_is_lt(now_ms, eb->key))) {
585 /* timer not expired yet, revisit it later */
586 t->exp_next = eb->key;
Willy Tarreau4d5f13c2017-11-05 11:04:47 +0100587 goto out_unlock;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100588 }
589
590 /* timer looks expired, detach it from the queue */
Willy Tarreau86257dc2010-06-06 12:57:10 +0200591 ts = eb32_entry(eb, struct stksess, exp);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100592 eb = eb32_next(eb);
593
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200594 /* don't delete an entry which is currently referenced */
595 if (ts->ref_cnt)
596 continue;
597
Willy Tarreau86257dc2010-06-06 12:57:10 +0200598 eb32_delete(&ts->exp);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100599
600 if (!tick_is_expired(ts->expire, now_ms)) {
601 if (!tick_isset(ts->expire))
602 continue;
603
Willy Tarreau86257dc2010-06-06 12:57:10 +0200604 ts->exp.key = ts->expire;
605 eb32_insert(&t->exps, &ts->exp);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100606
Willy Tarreau86257dc2010-06-06 12:57:10 +0200607 if (!eb || eb->key > ts->exp.key)
608 eb = &ts->exp;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100609 continue;
610 }
611
612 /* session expired, trash it */
Willy Tarreau86257dc2010-06-06 12:57:10 +0200613 ebmb_delete(&ts->key);
Emeric Brun85e77c72010-09-23 18:16:52 +0200614 eb32_delete(&ts->upd);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200615 __stksess_free(t, ts);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100616 }
617
618 /* We have found no task to expire in any tree */
619 t->exp_next = TICK_ETERNITY;
Willy Tarreau4d5f13c2017-11-05 11:04:47 +0100620out_unlock:
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100621 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100622 return t->exp_next;
623}
624
625/*
Willy Tarreauaea940e2010-06-06 11:56:36 +0200626 * Task processing function to trash expired sticky sessions. A pointer to the
627 * task itself is returned since it never dies.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100628 */
Willy Tarreau144f84a2021-03-02 16:09:26 +0100629struct task *process_table_expire(struct task *task, void *context, unsigned int state)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100630{
Olivier Houchard9f6af332018-05-25 14:04:04 +0200631 struct stktable *t = context;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100632
633 task->expire = stktable_trash_expired(t);
634 return task;
635}
636
Willy Tarreauaea940e2010-06-06 11:56:36 +0200637/* Perform minimal stick table intializations, report 0 in case of error, 1 if OK. */
Emeric Brun3bd697e2010-01-04 15:23:48 +0100638int stktable_init(struct stktable *t)
639{
Remi Tricot-Le Breton208ff012021-05-12 17:39:04 +0200640 int peers_retval = 0;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100641 if (t->size) {
Emeric Brun819fc6f2017-06-13 19:37:32 +0200642 t->keys = EB_ROOT_UNIQUE;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100643 memset(&t->exps, 0, sizeof(t->exps));
Emeric Brun1c6235d2015-12-16 15:28:12 +0100644 t->updates = EB_ROOT_UNIQUE;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100645 HA_SPIN_INIT(&t->lock);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100646
Olivier Houchard52dabbc2018-11-14 17:54:36 +0100647 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 +0100648
649 t->exp_next = TICK_ETERNITY;
650 if ( t->expire ) {
Emeric Brunc60def82017-09-27 14:59:38 +0200651 t->exp_task = task_new(MAX_THREADS_MASK);
Willy Tarreau848522f2018-10-15 11:12:15 +0200652 if (!t->exp_task)
653 return 0;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100654 t->exp_task->process = process_table_expire;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100655 t->exp_task->context = (void *)t;
656 }
Willy Tarreauc3914d42020-09-24 08:39:22 +0200657 if (t->peers.p && t->peers.p->peers_fe && !t->peers.p->peers_fe->disabled) {
Remi Tricot-Le Breton208ff012021-05-12 17:39:04 +0200658 peers_retval = peers_register_table(t->peers.p, t);
Emeric Brun32da3c42010-09-23 18:39:19 +0200659 }
660
Remi Tricot-Le Breton208ff012021-05-12 17:39:04 +0200661 return (t->pool != NULL) && !peers_retval;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100662 }
663 return 1;
664}
665
666/*
667 * Configuration keywords of known table types
668 */
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200669struct stktable_type stktable_types[SMP_TYPES] = {
670 [SMP_T_SINT] = { "integer", 0, 4 },
671 [SMP_T_IPV4] = { "ip", 0, 4 },
672 [SMP_T_IPV6] = { "ipv6", 0, 16 },
673 [SMP_T_STR] = { "string", STK_F_CUSTOM_KEYSIZE, 32 },
674 [SMP_T_BIN] = { "binary", STK_F_CUSTOM_KEYSIZE, 32 }
675};
Emeric Brun3bd697e2010-01-04 15:23:48 +0100676
677/*
678 * Parse table type configuration.
679 * Returns 0 on successful parsing, else 1.
680 * <myidx> is set at next configuration <args> index.
681 */
682int stktable_parse_type(char **args, int *myidx, unsigned long *type, size_t *key_size)
683{
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200684 for (*type = 0; *type < SMP_TYPES; (*type)++) {
685 if (!stktable_types[*type].kw)
686 continue;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100687 if (strcmp(args[*myidx], stktable_types[*type].kw) != 0)
688 continue;
689
690 *key_size = stktable_types[*type].default_size;
691 (*myidx)++;
692
Willy Tarreauaea940e2010-06-06 11:56:36 +0200693 if (stktable_types[*type].flags & STK_F_CUSTOM_KEYSIZE) {
Emeric Brun3bd697e2010-01-04 15:23:48 +0100694 if (strcmp("len", args[*myidx]) == 0) {
695 (*myidx)++;
696 *key_size = atol(args[*myidx]);
Emeric Brun485479d2010-09-23 18:02:19 +0200697 if (!*key_size)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100698 break;
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200699 if (*type == SMP_T_STR) {
Emeric Brun485479d2010-09-23 18:02:19 +0200700 /* null terminated string needs +1 for '\0'. */
701 (*key_size)++;
702 }
Emeric Brun3bd697e2010-01-04 15:23:48 +0100703 (*myidx)++;
704 }
705 }
706 return 0;
707 }
708 return 1;
709}
710
Emeric Brunc64a2a32021-06-30 18:01:02 +0200711/* reserve some space for data type <type>, there is 2 optionnals
712 * argument at <sa> and <sa2> to configure this data type and
713 * they can be NULL if unused for a given type.
714 * Returns PE_NONE (0) if OK or an error code among :
Willy Tarreau3b63ca22021-05-08 14:10:42 +0200715 * - PE_ENUM_OOR if <type> does not exist
716 * - PE_EXIST if <type> is already registered
Emeric Brunc64a2a32021-06-30 18:01:02 +0200717 * - PE_ARG_NOT_USE if <sa>/<sa2> was provided but not expected
718 * - PE_ARG_MISSING if <sa>/<sa2> was expected but not provided
719 * - PE_ARG_VALUE_OOR if type is an array and <sa> it out of array size range.
Willy Tarreau3b63ca22021-05-08 14:10:42 +0200720 */
Emeric Brunc64a2a32021-06-30 18:01:02 +0200721int stktable_alloc_data_type(struct stktable *t, int type, const char *sa, const char *sa2)
722
Willy Tarreau3b63ca22021-05-08 14:10:42 +0200723{
724 if (type >= STKTABLE_DATA_TYPES)
725 return PE_ENUM_OOR;
726
727 if (t->data_ofs[type])
728 /* already allocated */
729 return PE_EXIST;
730
Emeric Brunc64a2a32021-06-30 18:01:02 +0200731 t->data_nbelem[type] = 1;
732 if (stktable_data_types[type].is_array) {
733 /* arrays take their element count on first argument */
734 if (!sa)
735 return PE_ARG_MISSING;
736 t->data_nbelem[type] = atoi(sa);
737 if (!t->data_nbelem[type] || (t->data_nbelem[type] > STKTABLE_MAX_DT_ARRAY_SIZE))
738 return PE_ARG_VALUE_OOR;
739 sa = sa2;
740 }
741
Willy Tarreau3b63ca22021-05-08 14:10:42 +0200742 switch (stktable_data_types[type].arg_type) {
743 case ARG_T_NONE:
744 if (sa)
745 return PE_ARG_NOT_USED;
746 break;
747 case ARG_T_INT:
748 if (!sa)
749 return PE_ARG_MISSING;
750 t->data_arg[type].i = atoi(sa);
751 break;
752 case ARG_T_DELAY:
753 if (!sa)
754 return PE_ARG_MISSING;
755 sa = parse_time_err(sa, &t->data_arg[type].u, TIME_UNIT_MS);
756 if (sa)
757 return PE_ARG_INVC; /* invalid char */
758 break;
759 }
760
Emeric Brunc64a2a32021-06-30 18:01:02 +0200761 t->data_size += t->data_nbelem[type] * stktable_type_size(stktable_data_types[type].std_type);
Willy Tarreau3b63ca22021-05-08 14:10:42 +0200762 t->data_ofs[type] = -t->data_size;
763 return PE_NONE;
764}
765
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100766/*
Frédéric Lécaillec02766a2019-03-20 15:06:55 +0100767 * Parse a line with <linenum> as number in <file> configuration file to configure
768 * the stick-table with <t> as address and <id> as ID.
769 * <peers> provides the "peers" section pointer only if this function is called
770 * from a "peers" section.
771 * <nid> is the stick-table name which is sent over the network. It must be equal
772 * to <id> if this stick-table is parsed from a proxy section, and prefixed by <peers>
773 * "peers" section name followed by a '/' character if parsed from a "peers" section.
Ilya Shipitsind4259502020-04-08 01:07:56 +0500774 * This is the responsibility of the caller to check this.
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100775 * Return an error status with ERR_* flags set if required, 0 if no error was encountered.
776 */
777int parse_stick_table(const char *file, int linenum, char **args,
Frédéric Lécaillec02766a2019-03-20 15:06:55 +0100778 struct stktable *t, char *id, char *nid, struct peers *peers)
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100779{
780 int err_code = 0;
781 int idx = 1;
782 unsigned int val;
783
784 if (!id || !*id) {
785 ha_alert("parsing [%s:%d] : %s: ID not provided.\n", file, linenum, args[0]);
786 err_code |= ERR_ALERT | ERR_ABORT;
787 goto out;
788 }
789
790 /* Store the "peers" section if this function is called from a "peers" section. */
791 if (peers) {
792 t->peers.p = peers;
793 idx++;
794 }
795
796 t->id = id;
Frédéric Lécaillec02766a2019-03-20 15:06:55 +0100797 t->nid = nid;
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100798 t->type = (unsigned int)-1;
799 t->conf.file = file;
800 t->conf.line = linenum;
801
802 while (*args[idx]) {
803 const char *err;
804
805 if (strcmp(args[idx], "size") == 0) {
806 idx++;
807 if (!*(args[idx])) {
808 ha_alert("parsing [%s:%d] : %s: missing argument after '%s'.\n",
809 file, linenum, args[0], args[idx-1]);
810 err_code |= ERR_ALERT | ERR_FATAL;
811 goto out;
812 }
813 if ((err = parse_size_err(args[idx], &t->size))) {
814 ha_alert("parsing [%s:%d] : %s: unexpected character '%c' in argument of '%s'.\n",
815 file, linenum, args[0], *err, args[idx-1]);
816 err_code |= ERR_ALERT | ERR_FATAL;
817 goto out;
818 }
819 idx++;
820 }
821 /* This argument does not exit in "peers" section. */
822 else if (!peers && strcmp(args[idx], "peers") == 0) {
823 idx++;
824 if (!*(args[idx])) {
825 ha_alert("parsing [%s:%d] : %s: missing argument after '%s'.\n",
826 file, linenum, args[0], args[idx-1]);
827 err_code |= ERR_ALERT | ERR_FATAL;
828 goto out;
829 }
830 t->peers.name = strdup(args[idx++]);
831 }
832 else if (strcmp(args[idx], "expire") == 0) {
833 idx++;
834 if (!*(args[idx])) {
835 ha_alert("parsing [%s:%d] : %s: missing argument after '%s'.\n",
836 file, linenum, args[0], args[idx-1]);
837 err_code |= ERR_ALERT | ERR_FATAL;
838 goto out;
839 }
840 err = parse_time_err(args[idx], &val, TIME_UNIT_MS);
Willy Tarreau9faebe32019-06-07 19:00:37 +0200841 if (err == PARSE_TIME_OVER) {
842 ha_alert("parsing [%s:%d]: %s: timer overflow in argument <%s> to <%s>, maximum value is 2147483647 ms (~24.8 days).\n",
843 file, linenum, args[0], args[idx], args[idx-1]);
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100844 err_code |= ERR_ALERT | ERR_FATAL;
845 goto out;
846 }
Willy Tarreau9faebe32019-06-07 19:00:37 +0200847 else if (err == PARSE_TIME_UNDER) {
848 ha_alert("parsing [%s:%d]: %s: timer underflow in argument <%s> to <%s>, minimum non-null value is 1 ms.\n",
849 file, linenum, args[0], args[idx], args[idx-1]);
850 err_code |= ERR_ALERT | ERR_FATAL;
851 goto out;
852 }
853 else if (err) {
854 ha_alert("parsing [%s:%d] : %s: unexpected character '%c' in argument of '%s'.\n",
855 file, linenum, args[0], *err, args[idx-1]);
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100856 err_code |= ERR_ALERT | ERR_FATAL;
857 goto out;
858 }
859 t->expire = val;
860 idx++;
861 }
862 else if (strcmp(args[idx], "nopurge") == 0) {
863 t->nopurge = 1;
864 idx++;
865 }
866 else if (strcmp(args[idx], "type") == 0) {
867 idx++;
868 if (stktable_parse_type(args, &idx, &t->type, &t->key_size) != 0) {
869 ha_alert("parsing [%s:%d] : %s: unknown type '%s'.\n",
870 file, linenum, args[0], args[idx]);
871 err_code |= ERR_ALERT | ERR_FATAL;
872 goto out;
873 }
874 /* idx already points to next arg */
875 }
876 else if (strcmp(args[idx], "store") == 0) {
877 int type, err;
Emeric Brunc64a2a32021-06-30 18:01:02 +0200878 char *cw, *nw, *sa, *sa2;
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100879
880 idx++;
881 nw = args[idx];
882 while (*nw) {
883 /* the "store" keyword supports a comma-separated list */
884 cw = nw;
885 sa = NULL; /* store arg */
Emeric Brunc64a2a32021-06-30 18:01:02 +0200886 sa2 = NULL;
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100887 while (*nw && *nw != ',') {
888 if (*nw == '(') {
889 *nw = 0;
890 sa = ++nw;
891 while (*nw != ')') {
892 if (!*nw) {
893 ha_alert("parsing [%s:%d] : %s: missing closing parenthesis after store option '%s'.\n",
894 file, linenum, args[0], cw);
895 err_code |= ERR_ALERT | ERR_FATAL;
896 goto out;
897 }
Emeric Brunc64a2a32021-06-30 18:01:02 +0200898 if (*nw == ',') {
899 *nw = '\0';
900 sa2 = nw + 1;
901 }
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100902 nw++;
903 }
904 *nw = '\0';
905 }
906 nw++;
907 }
908 if (*nw)
909 *nw++ = '\0';
910 type = stktable_get_data_type(cw);
911 if (type < 0) {
912 ha_alert("parsing [%s:%d] : %s: unknown store option '%s'.\n",
913 file, linenum, args[0], cw);
914 err_code |= ERR_ALERT | ERR_FATAL;
915 goto out;
916 }
917
Emeric Brunc64a2a32021-06-30 18:01:02 +0200918 err = stktable_alloc_data_type(t, type, sa, sa2);
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100919 switch (err) {
920 case PE_NONE: break;
921 case PE_EXIST:
922 ha_warning("parsing [%s:%d]: %s: store option '%s' already enabled, ignored.\n",
923 file, linenum, args[0], cw);
924 err_code |= ERR_WARN;
925 break;
926
927 case PE_ARG_MISSING:
928 ha_alert("parsing [%s:%d] : %s: missing argument to store option '%s'.\n",
929 file, linenum, args[0], cw);
930 err_code |= ERR_ALERT | ERR_FATAL;
931 goto out;
932
933 case PE_ARG_NOT_USED:
934 ha_alert("parsing [%s:%d] : %s: unexpected argument to store option '%s'.\n",
935 file, linenum, args[0], cw);
936 err_code |= ERR_ALERT | ERR_FATAL;
937 goto out;
Emeric Brunc64a2a32021-06-30 18:01:02 +0200938 case PE_ARG_VALUE_OOR:
939 ha_alert("parsing [%s:%d] : %s: array size is out of allowed range (1-%d) for store option '%s'.\n",
940 file, linenum, args[0], STKTABLE_MAX_DT_ARRAY_SIZE, cw);
941 err_code |= ERR_ALERT | ERR_FATAL;
942 goto out;
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100943
944 default:
945 ha_alert("parsing [%s:%d] : %s: error when processing store option '%s'.\n",
946 file, linenum, args[0], cw);
947 err_code |= ERR_ALERT | ERR_FATAL;
948 goto out;
949 }
950 }
951 idx++;
Emeric Brunf7ab0bf2021-06-30 18:58:22 +0200952 if (t->data_ofs[STKTABLE_DT_GPT] && t->data_ofs[STKTABLE_DT_GPT0]) {
953 ha_alert("parsing [%s:%d] : %s: simultaneous usage of 'gpt' and 'gpt0' in a same table is not permitted as 'gpt' overrides 'gpt0'.\n",
954 file, linenum, args[0]);
955 err_code |= ERR_ALERT | ERR_FATAL;
956 goto out;
957 }
Emeric Brun726783d2021-06-30 19:06:43 +0200958 else if (t->data_ofs[STKTABLE_DT_GPC] && (t->data_ofs[STKTABLE_DT_GPC0] || t->data_ofs[STKTABLE_DT_GPC1])) {
959 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",
960 file, linenum, args[0]);
961 err_code |= ERR_ALERT | ERR_FATAL;
962 goto out;
963 }
964 else if (t->data_ofs[STKTABLE_DT_GPC_RATE] && (t->data_ofs[STKTABLE_DT_GPC0_RATE] || t->data_ofs[STKTABLE_DT_GPC1_RATE])) {
965 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",
966 file, linenum, args[0]);
967 err_code |= ERR_ALERT | ERR_FATAL;
968 goto out;
969 }
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100970 }
Thayne McCombs92149f92020-11-20 01:28:26 -0700971 else if (strcmp(args[idx], "srvkey") == 0) {
972 char *keytype;
973 idx++;
974 keytype = args[idx];
975 if (strcmp(keytype, "name") == 0) {
976 t->server_key_type = STKTABLE_SRV_NAME;
977 }
978 else if (strcmp(keytype, "addr") == 0) {
979 t->server_key_type = STKTABLE_SRV_ADDR;
980 }
981 else {
982 ha_alert("parsing [%s:%d] : %s : unknown server key type '%s'.\n",
983 file, linenum, args[0], keytype);
984 err_code |= ERR_ALERT | ERR_FATAL;
985 goto out;
986
987 }
988 idx++;
989 }
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100990 else {
991 ha_alert("parsing [%s:%d] : %s: unknown argument '%s'.\n",
992 file, linenum, args[0], args[idx]);
993 err_code |= ERR_ALERT | ERR_FATAL;
994 goto out;
995 }
996 }
997
998 if (!t->size) {
999 ha_alert("parsing [%s:%d] : %s: missing size.\n",
1000 file, linenum, args[0]);
1001 err_code |= ERR_ALERT | ERR_FATAL;
1002 goto out;
1003 }
1004
1005 if (t->type == (unsigned int)-1) {
1006 ha_alert("parsing [%s:%d] : %s: missing type.\n",
1007 file, linenum, args[0]);
1008 err_code |= ERR_ALERT | ERR_FATAL;
1009 goto out;
1010 }
1011
1012 out:
1013 return err_code;
1014}
1015
Willy Tarreau8fed9032014-07-03 17:02:46 +02001016/* Prepares a stktable_key from a sample <smp> to search into table <t>.
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001017 * Note that the sample *is* modified and that the returned key may point
1018 * to it, so the sample must not be modified afterwards before the lookup.
Willy Tarreau8fed9032014-07-03 17:02:46 +02001019 * Returns NULL if the sample could not be converted (eg: no matching type),
1020 * otherwise a pointer to the static stktable_key filled with what is needed
1021 * for the lookup.
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001022 */
Willy Tarreau8fed9032014-07-03 17:02:46 +02001023struct stktable_key *smp_to_stkey(struct sample *smp, struct stktable *t)
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001024{
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001025 /* Convert sample. */
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +02001026 if (!sample_convert(smp, t->type))
Willy Tarreau7fc1c6e2012-04-26 11:03:17 +02001027 return NULL;
1028
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001029 /* Fill static_table_key. */
1030 switch (t->type) {
Emeric Brun485479d2010-09-23 18:02:19 +02001031
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +02001032 case SMP_T_IPV4:
Christopher Fauletca20d022017-08-29 15:30:31 +02001033 static_table_key.key = &smp->data.u.ipv4;
1034 static_table_key.key_len = 4;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001035 break;
Emeric Brun485479d2010-09-23 18:02:19 +02001036
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +02001037 case SMP_T_IPV6:
Christopher Fauletca20d022017-08-29 15:30:31 +02001038 static_table_key.key = &smp->data.u.ipv6;
1039 static_table_key.key_len = 16;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001040 break;
Emeric Brun485479d2010-09-23 18:02:19 +02001041
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +02001042 case SMP_T_SINT:
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001043 /* The stick table require a 32bit unsigned int, "sint" is a
1044 * signed 64 it, so we can convert it inplace.
1045 */
Willy Tarreau28c63c12019-10-23 06:21:05 +02001046 smp->data.u.sint = (unsigned int)smp->data.u.sint;
Christopher Fauletca20d022017-08-29 15:30:31 +02001047 static_table_key.key = &smp->data.u.sint;
1048 static_table_key.key_len = 4;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001049 break;
1050
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +02001051 case SMP_T_STR:
Willy Tarreauce6955e2016-08-09 11:59:12 +02001052 if (!smp_make_safe(smp))
1053 return NULL;
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001054 static_table_key.key = smp->data.u.str.area;
1055 static_table_key.key_len = smp->data.u.str.data;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001056 break;
Emeric Brun485479d2010-09-23 18:02:19 +02001057
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +02001058 case SMP_T_BIN:
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001059 if (smp->data.u.str.data < t->key_size) {
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001060 /* This type needs padding with 0. */
Willy Tarreauf65c6c02016-08-09 12:08:41 +02001061 if (!smp_make_rw(smp))
1062 return NULL;
1063
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001064 if (smp->data.u.str.size < t->key_size)
1065 if (!smp_dup(smp))
1066 return NULL;
1067 if (smp->data.u.str.size < t->key_size)
1068 return NULL;
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001069 memset(smp->data.u.str.area + smp->data.u.str.data, 0,
1070 t->key_size - smp->data.u.str.data);
1071 smp->data.u.str.data = t->key_size;
Emeric Brun485479d2010-09-23 18:02:19 +02001072 }
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001073 static_table_key.key = smp->data.u.str.area;
1074 static_table_key.key_len = smp->data.u.str.data;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001075 break;
Emeric Brun485479d2010-09-23 18:02:19 +02001076
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001077 default: /* impossible case. */
1078 return NULL;
Emeric Brun485479d2010-09-23 18:02:19 +02001079 }
1080
Christopher Fauletca20d022017-08-29 15:30:31 +02001081 return &static_table_key;
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001082}
1083
1084/*
Willy Tarreau8fed9032014-07-03 17:02:46 +02001085 * Process a fetch + format conversion as defined by the sample expression <expr>
1086 * on request or response considering the <opt> parameter. Returns either NULL if
1087 * no key could be extracted, or a pointer to the converted result stored in
1088 * static_table_key in format <table_type>. If <smp> is not NULL, it will be reset
1089 * and its flags will be initialized so that the caller gets a copy of the input
Willy Tarreau6bcb0a82014-07-30 08:56:35 +02001090 * sample, and knows why it was not accepted (eg: SMP_F_MAY_CHANGE is present
1091 * without SMP_OPT_FINAL). The output will be usable like this :
1092 *
1093 * return MAY_CHANGE FINAL Meaning for the sample
1094 * NULL 0 * Not present and will never be (eg: header)
1095 * NULL 1 0 Not present or unstable, could change (eg: req_len)
1096 * NULL 1 1 Not present, will not change anymore
1097 * smp 0 * Present and will not change (eg: header)
1098 * smp 1 0 not possible
1099 * smp 1 1 Present, last known value (eg: request length)
Willy Tarreau8fed9032014-07-03 17:02:46 +02001100 */
Willy Tarreau192252e2015-04-04 01:47:55 +02001101struct stktable_key *stktable_fetch_key(struct stktable *t, struct proxy *px, struct session *sess, struct stream *strm,
Willy Tarreau8fed9032014-07-03 17:02:46 +02001102 unsigned int opt, struct sample_expr *expr, struct sample *smp)
1103{
1104 if (smp)
1105 memset(smp, 0, sizeof(*smp));
1106
Willy Tarreau192252e2015-04-04 01:47:55 +02001107 smp = sample_process(px, sess, strm, opt, expr, smp);
Willy Tarreau8fed9032014-07-03 17:02:46 +02001108 if (!smp)
1109 return NULL;
1110
1111 if ((smp->flags & SMP_F_MAY_CHANGE) && !(opt & SMP_OPT_FINAL))
1112 return NULL; /* we can only use stable samples */
1113
1114 return smp_to_stkey(smp, t);
1115}
1116
1117/*
Willy Tarreau12785782012-04-27 21:37:17 +02001118 * Returns 1 if sample expression <expr> result can be converted to table key of
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001119 * type <table_type>, otherwise zero. Used in configuration check.
1120 */
Willy Tarreau12785782012-04-27 21:37:17 +02001121int stktable_compatible_sample(struct sample_expr *expr, unsigned long table_type)
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001122{
Thierry FOURNIERf73eb8f2013-11-27 15:30:55 +01001123 int out_type;
1124
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +02001125 if (table_type >= SMP_TYPES || !stktable_types[table_type].kw)
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001126 return 0;
1127
Thierry FOURNIERf73eb8f2013-11-27 15:30:55 +01001128 out_type = smp_expr_output_type(expr);
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001129
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001130 /* Convert sample. */
1131 if (!sample_casts[out_type][table_type])
Thierry FOURNIERf73eb8f2013-11-27 15:30:55 +01001132 return 0;
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001133
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001134 return 1;
1135}
Emeric Brun3bd697e2010-01-04 15:23:48 +01001136
Willy Tarreauedee1d62014-07-15 16:44:27 +02001137/* Extra data types processing : after the last one, some room may remain
1138 * before STKTABLE_DATA_TYPES that may be used to register extra data types
1139 * at run time.
1140 */
Willy Tarreau08d5f982010-06-06 13:34:54 +02001141struct stktable_data_type stktable_data_types[STKTABLE_DATA_TYPES] = {
Willy Tarreau3b9c6e02010-07-18 08:04:30 +02001142 [STKTABLE_DT_SERVER_ID] = { .name = "server_id", .std_type = STD_T_SINT },
Thierry FOURNIER3cf11112015-07-28 08:57:05 +02001143 [STKTABLE_DT_GPT0] = { .name = "gpt0", .std_type = STD_T_UINT },
Willy Tarreau3b9c6e02010-07-18 08:04:30 +02001144 [STKTABLE_DT_GPC0] = { .name = "gpc0", .std_type = STD_T_UINT },
Willy Tarreauba2ffd12013-05-29 15:54:14 +02001145 [STKTABLE_DT_GPC0_RATE] = { .name = "gpc0_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
Willy Tarreau3b9c6e02010-07-18 08:04:30 +02001146 [STKTABLE_DT_CONN_CNT] = { .name = "conn_cnt", .std_type = STD_T_UINT },
1147 [STKTABLE_DT_CONN_RATE] = { .name = "conn_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
1148 [STKTABLE_DT_CONN_CUR] = { .name = "conn_cur", .std_type = STD_T_UINT },
1149 [STKTABLE_DT_SESS_CNT] = { .name = "sess_cnt", .std_type = STD_T_UINT },
1150 [STKTABLE_DT_SESS_RATE] = { .name = "sess_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
1151 [STKTABLE_DT_HTTP_REQ_CNT] = { .name = "http_req_cnt", .std_type = STD_T_UINT },
1152 [STKTABLE_DT_HTTP_REQ_RATE] = { .name = "http_req_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
1153 [STKTABLE_DT_HTTP_ERR_CNT] = { .name = "http_err_cnt", .std_type = STD_T_UINT },
1154 [STKTABLE_DT_HTTP_ERR_RATE] = { .name = "http_err_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
1155 [STKTABLE_DT_BYTES_IN_CNT] = { .name = "bytes_in_cnt", .std_type = STD_T_ULL },
1156 [STKTABLE_DT_BYTES_IN_RATE] = { .name = "bytes_in_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
1157 [STKTABLE_DT_BYTES_OUT_CNT] = { .name = "bytes_out_cnt", .std_type = STD_T_ULL },
1158 [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 +01001159 [STKTABLE_DT_GPC1] = { .name = "gpc1", .std_type = STD_T_UINT },
1160 [STKTABLE_DT_GPC1_RATE] = { .name = "gpc1_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
Thayne McCombs92149f92020-11-20 01:28:26 -07001161 [STKTABLE_DT_SERVER_KEY] = { .name = "server_key", .std_type = STD_T_DICT },
Willy Tarreau826f3ab2021-02-10 12:07:15 +01001162 [STKTABLE_DT_HTTP_FAIL_CNT] = { .name = "http_fail_cnt", .std_type = STD_T_UINT },
1163 [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 +02001164 [STKTABLE_DT_GPT] = { .name = "gpt", .std_type = STD_T_UINT, .is_array = 1 },
Emeric Brun4d7ada82021-06-30 19:04:16 +02001165 [STKTABLE_DT_GPC] = { .name = "gpc", .std_type = STD_T_UINT, .is_array = 1 },
1166 [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 +02001167};
1168
Willy Tarreauedee1d62014-07-15 16:44:27 +02001169/* Registers stick-table extra data type with index <idx>, name <name>, type
1170 * <std_type> and arg type <arg_type>. If the index is negative, the next free
1171 * index is automatically allocated. The allocated index is returned, or -1 if
1172 * no free index was found or <name> was already registered. The <name> is used
1173 * directly as a pointer, so if it's not stable, the caller must allocate it.
1174 */
1175int stktable_register_data_store(int idx, const char *name, int std_type, int arg_type)
1176{
1177 if (idx < 0) {
1178 for (idx = 0; idx < STKTABLE_DATA_TYPES; idx++) {
1179 if (!stktable_data_types[idx].name)
1180 break;
1181
1182 if (strcmp(stktable_data_types[idx].name, name) == 0)
1183 return -1;
1184 }
1185 }
1186
1187 if (idx >= STKTABLE_DATA_TYPES)
1188 return -1;
1189
1190 if (stktable_data_types[idx].name != NULL)
1191 return -1;
1192
1193 stktable_data_types[idx].name = name;
1194 stktable_data_types[idx].std_type = std_type;
1195 stktable_data_types[idx].arg_type = arg_type;
1196 return idx;
1197}
1198
Willy Tarreau08d5f982010-06-06 13:34:54 +02001199/*
1200 * Returns the data type number for the stktable_data_type whose name is <name>,
1201 * or <0 if not found.
1202 */
1203int stktable_get_data_type(char *name)
1204{
1205 int type;
1206
1207 for (type = 0; type < STKTABLE_DATA_TYPES; type++) {
Willy Tarreauedee1d62014-07-15 16:44:27 +02001208 if (!stktable_data_types[type].name)
1209 continue;
Willy Tarreau08d5f982010-06-06 13:34:54 +02001210 if (strcmp(name, stktable_data_types[type].name) == 0)
1211 return type;
1212 }
Thayne McCombs92149f92020-11-20 01:28:26 -07001213 /* For backwards compatibility */
1214 if (strcmp(name, "server_name") == 0)
1215 return STKTABLE_DT_SERVER_KEY;
Willy Tarreau08d5f982010-06-06 13:34:54 +02001216 return -1;
1217}
1218
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001219/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1220 * it up into this table. Returns true if found, false otherwise. The input
1221 * type is STR so that input samples are converted to string (since all types
1222 * can be converted to strings), then the function casts the string again into
1223 * the table's type. This is a double conversion, but in the future we might
1224 * support automatic input types to perform the cast on the fly.
1225 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001226static int sample_conv_in_table(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001227{
1228 struct stktable *t;
1229 struct stktable_key *key;
1230 struct stksess *ts;
1231
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001232 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001233
1234 key = smp_to_stkey(smp, t);
1235 if (!key)
1236 return 0;
1237
1238 ts = stktable_lookup_key(t, key);
1239
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001240 smp->data.type = SMP_T_BOOL;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001241 smp->data.u.sint = !!ts;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001242 smp->flags = SMP_F_VOL_TEST;
Willy Tarreau43e90352018-06-27 06:25:57 +02001243 stktable_release(t, ts);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001244 return 1;
1245}
1246
1247/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1248 * it up into this table. Returns the data rate received from clients in bytes/s
1249 * if the key is present in the table, otherwise zero, so that comparisons can
1250 * be easily performed. If the inspected parameter is not stored in the table,
1251 * <not found> is returned.
1252 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001253static int sample_conv_table_bytes_in_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001254{
1255 struct stktable *t;
1256 struct stktable_key *key;
1257 struct stksess *ts;
1258 void *ptr;
1259
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001260 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001261
1262 key = smp_to_stkey(smp, t);
1263 if (!key)
1264 return 0;
1265
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001266 ts = stktable_lookup_key(t, key);
1267
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001268 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001269 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001270 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001271
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001272 if (!ts) /* key not present */
1273 return 1;
1274
1275 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_IN_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001276 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001277 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Daniel Corbett3e60b112018-05-27 09:47:12 -04001278 t->data_arg[STKTABLE_DT_BYTES_IN_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001279
Daniel Corbett3e60b112018-05-27 09:47:12 -04001280 stktable_release(t, ts);
1281 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001282}
1283
1284/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1285 * it up into this table. Returns the cumulated number of connections for the key
1286 * if the key is present in the table, otherwise zero, so that comparisons can
1287 * be easily performed. If the inspected parameter is not stored in the table,
1288 * <not found> is returned.
1289 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001290static int sample_conv_table_conn_cnt(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001291{
1292 struct stktable *t;
1293 struct stktable_key *key;
1294 struct stksess *ts;
1295 void *ptr;
1296
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001297 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001298
1299 key = smp_to_stkey(smp, t);
1300 if (!key)
1301 return 0;
1302
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001303 ts = stktable_lookup_key(t, key);
1304
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001305 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001306 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001307 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001308
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001309 if (!ts) /* key not present */
1310 return 1;
1311
1312 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_CONN_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001313 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001314 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001315
Daniel Corbett3e60b112018-05-27 09:47:12 -04001316 stktable_release(t, ts);
1317 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001318}
1319
1320/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1321 * it up into this table. Returns the number of concurrent connections for the
1322 * key if the key is present in the table, otherwise zero, so that comparisons
1323 * can be easily performed. If the inspected parameter is not stored in the
1324 * table, <not found> is returned.
1325 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001326static int sample_conv_table_conn_cur(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001327{
1328 struct stktable *t;
1329 struct stktable_key *key;
1330 struct stksess *ts;
1331 void *ptr;
1332
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001333 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001334
1335 key = smp_to_stkey(smp, t);
1336 if (!key)
1337 return 0;
1338
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001339 ts = stktable_lookup_key(t, key);
1340
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001341 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001342 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001343 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001344
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001345 if (!ts) /* key not present */
1346 return 1;
1347
1348 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_CONN_CUR);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001349 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001350 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001351
Daniel Corbett3e60b112018-05-27 09:47:12 -04001352 stktable_release(t, ts);
1353 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001354}
1355
1356/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1357 * it up into this table. Returns the rate of incoming connections from the key
1358 * if the key is present in the table, otherwise zero, so that comparisons can
1359 * be easily performed. If the inspected parameter is not stored in the table,
1360 * <not found> is returned.
1361 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001362static int sample_conv_table_conn_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001363{
1364 struct stktable *t;
1365 struct stktable_key *key;
1366 struct stksess *ts;
1367 void *ptr;
1368
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001369 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001370
1371 key = smp_to_stkey(smp, t);
1372 if (!key)
1373 return 0;
1374
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001375 ts = stktable_lookup_key(t, key);
1376
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001377 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001378 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001379 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001380
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001381 if (!ts) /* key not present */
1382 return 1;
1383
1384 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_CONN_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001385 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001386 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Daniel Corbett3e60b112018-05-27 09:47:12 -04001387 t->data_arg[STKTABLE_DT_CONN_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001388
Daniel Corbett3e60b112018-05-27 09:47:12 -04001389 stktable_release(t, ts);
1390 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001391}
1392
1393/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1394 * it up into this table. Returns the data rate sent to clients in bytes/s
1395 * if the key is present in the table, otherwise zero, so that comparisons can
1396 * be easily performed. If the inspected parameter is not stored in the table,
1397 * <not found> is returned.
1398 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001399static int sample_conv_table_bytes_out_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001400{
1401 struct stktable *t;
1402 struct stktable_key *key;
1403 struct stksess *ts;
1404 void *ptr;
1405
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001406 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001407
1408 key = smp_to_stkey(smp, t);
1409 if (!key)
1410 return 0;
1411
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001412 ts = stktable_lookup_key(t, key);
1413
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001414 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001415 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001416 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001417
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001418 if (!ts) /* key not present */
1419 return 1;
1420
1421 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_OUT_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001422 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001423 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Daniel Corbett3e60b112018-05-27 09:47:12 -04001424 t->data_arg[STKTABLE_DT_BYTES_OUT_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001425
Daniel Corbett3e60b112018-05-27 09:47:12 -04001426 stktable_release(t, ts);
1427 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001428}
1429
Emeric Brun877b0b52021-06-30 18:57:49 +02001430/* Casts sample <smp> to the type of the table specified in arg_p(1), and looks
1431 * it up into this table. Returns the value of the GPT[arg_p(0)] tag for the key
1432 * if the key is present in the table, otherwise false, so that comparisons can
1433 * be easily performed. If the inspected parameter is not stored in the table,
1434 * <not found> is returned.
1435 */
1436static int sample_conv_table_gpt(const struct arg *arg_p, struct sample *smp, void *private)
1437{
1438 struct stktable *t;
1439 struct stktable_key *key;
1440 struct stksess *ts;
1441 void *ptr;
1442 unsigned int idx;
1443
1444 idx = arg_p[0].data.sint;
1445
1446 t = arg_p[1].data.t;
1447
1448 key = smp_to_stkey(smp, t);
1449 if (!key)
1450 return 0;
1451
1452 ts = stktable_lookup_key(t, key);
1453
1454 smp->flags = SMP_F_VOL_TEST;
1455 smp->data.type = SMP_T_SINT;
1456 smp->data.u.sint = 0;
1457
1458 if (!ts) /* key not present */
1459 return 1;
1460
1461 ptr = stktable_data_ptr_idx(t, ts, STKTABLE_DT_GPT, idx);
1462 if (ptr)
1463 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
1464
1465 stktable_release(t, ts);
1466 return !!ptr;
1467}
1468
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001469/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001470 * it up into this table. Returns the value of the GPT0 tag for the key
1471 * if the key is present in the table, otherwise false, so that comparisons can
1472 * be easily performed. If the inspected parameter is not stored in the table,
1473 * <not found> is returned.
1474 */
1475static int sample_conv_table_gpt0(const struct arg *arg_p, struct sample *smp, void *private)
1476{
1477 struct stktable *t;
1478 struct stktable_key *key;
1479 struct stksess *ts;
1480 void *ptr;
1481
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001482 t = arg_p[0].data.t;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001483
1484 key = smp_to_stkey(smp, t);
1485 if (!key)
1486 return 0;
1487
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001488 ts = stktable_lookup_key(t, key);
1489
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001490 smp->flags = SMP_F_VOL_TEST;
1491 smp->data.type = SMP_T_SINT;
1492 smp->data.u.sint = 0;
1493
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001494 if (!ts) /* key not present */
1495 return 1;
1496
1497 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPT0);
Emeric Brunf7ab0bf2021-06-30 18:58:22 +02001498 if (!ptr)
1499 ptr = stktable_data_ptr_idx(t, ts, STKTABLE_DT_GPT, 0);
1500
Daniel Corbett3e60b112018-05-27 09:47:12 -04001501 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001502 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001503
Daniel Corbett3e60b112018-05-27 09:47:12 -04001504 stktable_release(t, ts);
1505 return !!ptr;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001506}
1507
Emeric Brun4d7ada82021-06-30 19:04:16 +02001508/* Casts sample <smp> to the type of the table specified in arg_p(1), and looks
1509 * it up into this table. Returns the value of the GPC[arg_p(0)] counter for the key
1510 * if the key is present in the table, otherwise zero, so that comparisons can
1511 * be easily performed. If the inspected parameter is not stored in the table,
1512 * <not found> is returned.
1513 */
1514static int sample_conv_table_gpc(const struct arg *arg_p, struct sample *smp, void *private)
1515{
1516 struct stktable *t;
1517 struct stktable_key *key;
1518 struct stksess *ts;
1519 void *ptr;
1520 unsigned int idx;
1521
1522 idx = arg_p[0].data.sint;
1523
1524 t = arg_p[1].data.t;
1525
1526 key = smp_to_stkey(smp, t);
1527 if (!key)
1528 return 0;
1529
1530 ts = stktable_lookup_key(t, key);
1531
1532 smp->flags = SMP_F_VOL_TEST;
1533 smp->data.type = SMP_T_SINT;
1534 smp->data.u.sint = 0;
1535
1536 if (!ts) /* key not present */
1537 return 1;
1538
1539 ptr = stktable_data_ptr_idx(t, ts, STKTABLE_DT_GPC, idx);
1540 if (ptr)
1541 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
1542
1543 stktable_release(t, ts);
1544 return !!ptr;
1545}
1546
1547/* Casts sample <smp> to the type of the table specified in arg_p(1), and looks
1548 * it up into this table. Returns the event rate of the GPC[arg_p(0)] counter
1549 * for the key if the key is present in the table, otherwise zero, so that
1550 * comparisons can be easily performed. If the inspected parameter is not
1551 * stored in the table, <not found> is returned.
1552 */
1553static int sample_conv_table_gpc_rate(const struct arg *arg_p, struct sample *smp, void *private)
1554{
1555 struct stktable *t;
1556 struct stktable_key *key;
1557 struct stksess *ts;
1558 void *ptr;
1559 unsigned int idx;
1560
1561 idx = arg_p[0].data.sint;
1562
1563 t = arg_p[1].data.t;
1564
1565 key = smp_to_stkey(smp, t);
1566 if (!key)
1567 return 0;
1568
1569 ts = stktable_lookup_key(t, key);
1570
1571 smp->flags = SMP_F_VOL_TEST;
1572 smp->data.type = SMP_T_SINT;
1573 smp->data.u.sint = 0;
1574
1575 if (!ts) /* key not present */
1576 return 1;
1577
1578 ptr = stktable_data_ptr_idx(t, ts, STKTABLE_DT_GPC_RATE, idx);
1579 if (ptr)
1580 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
1581 t->data_arg[STKTABLE_DT_GPC_RATE].u);
1582
1583 stktable_release(t, ts);
1584 return !!ptr;
1585}
1586
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001587/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001588 * it up into this table. Returns the value of the GPC0 counter for the key
1589 * if the key is present in the table, otherwise zero, so that comparisons can
1590 * be easily performed. If the inspected parameter is not stored in the table,
1591 * <not found> is returned.
1592 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001593static int sample_conv_table_gpc0(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001594{
1595 struct stktable *t;
1596 struct stktable_key *key;
1597 struct stksess *ts;
1598 void *ptr;
1599
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001600 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001601
1602 key = smp_to_stkey(smp, t);
1603 if (!key)
1604 return 0;
1605
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001606 ts = stktable_lookup_key(t, key);
1607
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001608 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001609 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001610 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001611
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001612 if (!ts) /* key not present */
1613 return 1;
1614
1615 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPC0);
Emeric Brun726783d2021-06-30 19:06:43 +02001616 if (!ptr) {
1617 /* fallback on the gpc array */
1618 ptr = stktable_data_ptr_idx(t, ts, STKTABLE_DT_GPC, 0);
1619 }
1620
Daniel Corbett3e60b112018-05-27 09:47:12 -04001621 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001622 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001623
Daniel Corbett3e60b112018-05-27 09:47:12 -04001624 stktable_release(t, ts);
1625 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001626}
1627
1628/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1629 * it up into this table. Returns the event rate of the GPC0 counter for the key
1630 * if the key is present in the table, otherwise zero, so that comparisons can
1631 * be easily performed. If the inspected parameter is not stored in the table,
1632 * <not found> is returned.
1633 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001634static int sample_conv_table_gpc0_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001635{
1636 struct stktable *t;
1637 struct stktable_key *key;
1638 struct stksess *ts;
1639 void *ptr;
1640
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001641 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001642
1643 key = smp_to_stkey(smp, t);
1644 if (!key)
1645 return 0;
1646
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001647 ts = stktable_lookup_key(t, key);
1648
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001649 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001650 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001651 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001652
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001653 if (!ts) /* key not present */
1654 return 1;
1655
1656 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPC0_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001657 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001658 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Daniel Corbett3e60b112018-05-27 09:47:12 -04001659 t->data_arg[STKTABLE_DT_GPC0_RATE].u);
Emeric Brun726783d2021-06-30 19:06:43 +02001660 else {
1661 /* fallback on the gpc array */
1662 ptr = stktable_data_ptr_idx(t, ts, STKTABLE_DT_GPC_RATE, 0);
1663 if (ptr)
1664 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
1665 t->data_arg[STKTABLE_DT_GPC_RATE].u);
1666 }
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001667
Daniel Corbett3e60b112018-05-27 09:47:12 -04001668 stktable_release(t, ts);
1669 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001670}
1671
1672/* 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 +01001673 * it up into this table. Returns the value of the GPC1 counter for the key
1674 * if the key is present in the table, otherwise zero, so that comparisons can
1675 * be easily performed. If the inspected parameter is not stored in the table,
1676 * <not found> is returned.
1677 */
1678static int sample_conv_table_gpc1(const struct arg *arg_p, struct sample *smp, void *private)
1679{
1680 struct stktable *t;
1681 struct stktable_key *key;
1682 struct stksess *ts;
1683 void *ptr;
1684
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001685 t = arg_p[0].data.t;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001686
1687 key = smp_to_stkey(smp, t);
1688 if (!key)
1689 return 0;
1690
1691 ts = stktable_lookup_key(t, key);
1692
1693 smp->flags = SMP_F_VOL_TEST;
1694 smp->data.type = SMP_T_SINT;
1695 smp->data.u.sint = 0;
1696
1697 if (!ts) /* key not present */
1698 return 1;
1699
1700 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPC1);
Emeric Brun726783d2021-06-30 19:06:43 +02001701 if (!ptr) {
1702 /* fallback on the gpc array */
1703 ptr = stktable_data_ptr_idx(t, ts, STKTABLE_DT_GPC, 1);
1704 }
1705
Daniel Corbett3e60b112018-05-27 09:47:12 -04001706 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001707 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001708
Daniel Corbett3e60b112018-05-27 09:47:12 -04001709 stktable_release(t, ts);
1710 return !!ptr;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001711}
1712
1713/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1714 * it up into this table. Returns the event rate of the GPC1 counter for the key
1715 * if the key is present in the table, otherwise zero, so that comparisons can
1716 * be easily performed. If the inspected parameter is not stored in the table,
1717 * <not found> is returned.
1718 */
1719static int sample_conv_table_gpc1_rate(const struct arg *arg_p, struct sample *smp, void *private)
1720{
1721 struct stktable *t;
1722 struct stktable_key *key;
1723 struct stksess *ts;
1724 void *ptr;
1725
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001726 t = arg_p[0].data.t;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001727
1728 key = smp_to_stkey(smp, t);
1729 if (!key)
1730 return 0;
1731
1732 ts = stktable_lookup_key(t, key);
1733
1734 smp->flags = SMP_F_VOL_TEST;
1735 smp->data.type = SMP_T_SINT;
1736 smp->data.u.sint = 0;
1737
1738 if (!ts) /* key not present */
1739 return 1;
1740
1741 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPC1_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001742 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001743 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Daniel Corbett3e60b112018-05-27 09:47:12 -04001744 t->data_arg[STKTABLE_DT_GPC1_RATE].u);
Emeric Brun726783d2021-06-30 19:06:43 +02001745 else {
1746 /* fallback on the gpc array */
1747 ptr = stktable_data_ptr_idx(t, ts, STKTABLE_DT_GPC_RATE, 1);
1748 if (ptr)
1749 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
1750 t->data_arg[STKTABLE_DT_GPC_RATE].u);
1751 }
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001752
Daniel Corbett3e60b112018-05-27 09:47:12 -04001753 stktable_release(t, ts);
1754 return !!ptr;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001755}
1756
1757/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001758 * it up into this table. Returns the cumulated number of HTTP request errors
1759 * for the key if the key is present in the table, otherwise zero, so that
1760 * comparisons can be easily performed. If the inspected parameter is not stored
1761 * in the table, <not found> is returned.
1762 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001763static int sample_conv_table_http_err_cnt(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001764{
1765 struct stktable *t;
1766 struct stktable_key *key;
1767 struct stksess *ts;
1768 void *ptr;
1769
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001770 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001771
1772 key = smp_to_stkey(smp, t);
1773 if (!key)
1774 return 0;
1775
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001776 ts = stktable_lookup_key(t, key);
1777
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001778 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001779 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001780 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001781
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001782 if (!ts) /* key not present */
1783 return 1;
1784
1785 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_ERR_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001786 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001787 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001788
Daniel Corbett3e60b112018-05-27 09:47:12 -04001789 stktable_release(t, ts);
1790 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001791}
1792
1793/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1794 * it up into this table. Returns the HTTP request error rate the key
1795 * if the key is present in the table, otherwise zero, so that comparisons can
1796 * be easily performed. If the inspected parameter is not stored in the table,
1797 * <not found> is returned.
1798 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001799static int sample_conv_table_http_err_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001800{
1801 struct stktable *t;
1802 struct stktable_key *key;
1803 struct stksess *ts;
1804 void *ptr;
1805
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001806 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001807
1808 key = smp_to_stkey(smp, t);
1809 if (!key)
1810 return 0;
1811
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001812 ts = stktable_lookup_key(t, key);
1813
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001814 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001815 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001816 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001817
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001818 if (!ts) /* key not present */
1819 return 1;
1820
1821 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_ERR_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001822 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001823 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Daniel Corbett3e60b112018-05-27 09:47:12 -04001824 t->data_arg[STKTABLE_DT_HTTP_ERR_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001825
Daniel Corbett3e60b112018-05-27 09:47:12 -04001826 stktable_release(t, ts);
1827 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001828}
1829
1830/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Willy Tarreau826f3ab2021-02-10 12:07:15 +01001831 * it up into this table. Returns the cumulated number of HTTP response failures
1832 * for the key if the key is present in the table, otherwise zero, so that
1833 * comparisons can be easily performed. If the inspected parameter is not stored
1834 * in the table, <not found> is returned.
1835 */
1836static int sample_conv_table_http_fail_cnt(const struct arg *arg_p, struct sample *smp, void *private)
1837{
1838 struct stktable *t;
1839 struct stktable_key *key;
1840 struct stksess *ts;
1841 void *ptr;
1842
1843 t = arg_p[0].data.t;
1844
1845 key = smp_to_stkey(smp, t);
1846 if (!key)
1847 return 0;
1848
1849 ts = stktable_lookup_key(t, key);
1850
1851 smp->flags = SMP_F_VOL_TEST;
1852 smp->data.type = SMP_T_SINT;
1853 smp->data.u.sint = 0;
1854
1855 if (!ts) /* key not present */
1856 return 1;
1857
1858 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_FAIL_CNT);
1859 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001860 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Willy Tarreau826f3ab2021-02-10 12:07:15 +01001861
1862 stktable_release(t, ts);
1863 return !!ptr;
1864}
1865
1866/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1867 * it up into this table. Returns the HTTP response failure rate for the key
1868 * if the key is present in the table, otherwise zero, so that comparisons can
1869 * be easily performed. If the inspected parameter is not stored in the table,
1870 * <not found> is returned.
1871 */
1872static int sample_conv_table_http_fail_rate(const struct arg *arg_p, struct sample *smp, void *private)
1873{
1874 struct stktable *t;
1875 struct stktable_key *key;
1876 struct stksess *ts;
1877 void *ptr;
1878
1879 t = arg_p[0].data.t;
1880
1881 key = smp_to_stkey(smp, t);
1882 if (!key)
1883 return 0;
1884
1885 ts = stktable_lookup_key(t, key);
1886
1887 smp->flags = SMP_F_VOL_TEST;
1888 smp->data.type = SMP_T_SINT;
1889 smp->data.u.sint = 0;
1890
1891 if (!ts) /* key not present */
1892 return 1;
1893
1894 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_FAIL_RATE);
1895 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001896 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Willy Tarreau826f3ab2021-02-10 12:07:15 +01001897 t->data_arg[STKTABLE_DT_HTTP_FAIL_RATE].u);
1898
1899 stktable_release(t, ts);
1900 return !!ptr;
1901}
1902
1903/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001904 * it up into this table. Returns the cumulated number of HTTP request for the
1905 * key if the key is present in the table, otherwise zero, so that comparisons
1906 * can be easily performed. If the inspected parameter is not stored in the
1907 * table, <not found> is returned.
1908 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001909static int sample_conv_table_http_req_cnt(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001910{
1911 struct stktable *t;
1912 struct stktable_key *key;
1913 struct stksess *ts;
1914 void *ptr;
1915
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001916 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001917
1918 key = smp_to_stkey(smp, t);
1919 if (!key)
1920 return 0;
1921
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001922 ts = stktable_lookup_key(t, key);
1923
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001924 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001925 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001926 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001927
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001928 if (!ts) /* key not present */
1929 return 1;
1930
1931 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_REQ_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001932 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001933 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001934
Daniel Corbett3e60b112018-05-27 09:47:12 -04001935 stktable_release(t, ts);
1936 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001937}
1938
1939/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1940 * it up into this table. Returns the HTTP request rate the key if the key is
1941 * present in the table, otherwise zero, so that comparisons can be easily
1942 * performed. If the inspected parameter is not stored in the table, <not found>
1943 * is returned.
1944 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001945static int sample_conv_table_http_req_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001946{
1947 struct stktable *t;
1948 struct stktable_key *key;
1949 struct stksess *ts;
1950 void *ptr;
1951
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001952 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001953
1954 key = smp_to_stkey(smp, t);
1955 if (!key)
1956 return 0;
1957
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001958 ts = stktable_lookup_key(t, key);
1959
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001960 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001961 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001962 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001963
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001964 if (!ts) /* key not present */
1965 return 1;
1966
1967 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_REQ_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001968 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001969 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Daniel Corbett3e60b112018-05-27 09:47:12 -04001970 t->data_arg[STKTABLE_DT_HTTP_REQ_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001971
Daniel Corbett3e60b112018-05-27 09:47:12 -04001972 stktable_release(t, ts);
1973 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001974}
1975
1976/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1977 * it up into this table. Returns the volume of datareceived from clients in kbytes
1978 * if the key is present in the table, otherwise zero, so that comparisons can
1979 * be easily performed. If the inspected parameter is not stored in the table,
1980 * <not found> is returned.
1981 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001982static int sample_conv_table_kbytes_in(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001983{
1984 struct stktable *t;
1985 struct stktable_key *key;
1986 struct stksess *ts;
1987 void *ptr;
1988
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001989 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001990
1991 key = smp_to_stkey(smp, t);
1992 if (!key)
1993 return 0;
1994
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001995 ts = stktable_lookup_key(t, key);
1996
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001997 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001998 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001999 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002000
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002001 if (!ts) /* key not present */
2002 return 1;
2003
2004 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_IN_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04002005 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002006 smp->data.u.sint = stktable_data_cast(ptr, std_t_ull) >> 10;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002007
Daniel Corbett3e60b112018-05-27 09:47:12 -04002008 stktable_release(t, ts);
2009 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002010}
2011
2012/* Casts sample <smp> to the type of the table specified in arg(0), and looks
2013 * it up into this table. Returns the volume of data sent to clients in kbytes
2014 * if the key is present in the table, otherwise zero, so that comparisons can
2015 * be easily performed. If the inspected parameter is not stored in the table,
2016 * <not found> is returned.
2017 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02002018static int sample_conv_table_kbytes_out(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002019{
2020 struct stktable *t;
2021 struct stktable_key *key;
2022 struct stksess *ts;
2023 void *ptr;
2024
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002025 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002026
2027 key = smp_to_stkey(smp, t);
2028 if (!key)
2029 return 0;
2030
Willy Tarreauf0c730a2016-05-25 17:07:56 +02002031 ts = stktable_lookup_key(t, key);
2032
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002033 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02002034 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02002035 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002036
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002037 if (!ts) /* key not present */
2038 return 1;
2039
2040 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_OUT_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04002041 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002042 smp->data.u.sint = stktable_data_cast(ptr, std_t_ull) >> 10;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002043
Daniel Corbett3e60b112018-05-27 09:47:12 -04002044 stktable_release(t, ts);
2045 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002046}
2047
2048/* Casts sample <smp> to the type of the table specified in arg(0), and looks
2049 * it up into this table. Returns the server ID associated with the key if the
2050 * key is present in the table, otherwise zero, so that comparisons can be
2051 * easily performed. If the inspected parameter is not stored in the table,
2052 * <not found> is returned.
2053 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02002054static int sample_conv_table_server_id(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002055{
2056 struct stktable *t;
2057 struct stktable_key *key;
2058 struct stksess *ts;
2059 void *ptr;
2060
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002061 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002062
2063 key = smp_to_stkey(smp, t);
2064 if (!key)
2065 return 0;
2066
Willy Tarreauf0c730a2016-05-25 17:07:56 +02002067 ts = stktable_lookup_key(t, key);
2068
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002069 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02002070 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02002071 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002072
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002073 if (!ts) /* key not present */
2074 return 1;
2075
2076 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_SERVER_ID);
Daniel Corbett3e60b112018-05-27 09:47:12 -04002077 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002078 smp->data.u.sint = stktable_data_cast(ptr, std_t_sint);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002079
Daniel Corbett3e60b112018-05-27 09:47:12 -04002080 stktable_release(t, ts);
2081 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002082}
2083
2084/* Casts sample <smp> to the type of the table specified in arg(0), and looks
2085 * it up into this table. Returns the cumulated number of sessions for the
2086 * key if the key is present in the table, otherwise zero, so that comparisons
2087 * can be easily performed. If the inspected parameter is not stored in the
2088 * table, <not found> is returned.
2089 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02002090static int sample_conv_table_sess_cnt(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002091{
2092 struct stktable *t;
2093 struct stktable_key *key;
2094 struct stksess *ts;
2095 void *ptr;
2096
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002097 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002098
2099 key = smp_to_stkey(smp, t);
2100 if (!key)
2101 return 0;
2102
Willy Tarreauf0c730a2016-05-25 17:07:56 +02002103 ts = stktable_lookup_key(t, key);
2104
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002105 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02002106 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02002107 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002108
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002109 if (!ts) /* key not present */
2110 return 1;
2111
2112 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_SESS_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04002113 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002114 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002115
Daniel Corbett3e60b112018-05-27 09:47:12 -04002116 stktable_release(t, ts);
2117 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002118}
2119
2120/* Casts sample <smp> to the type of the table specified in arg(0), and looks
2121 * it up into this table. Returns the session rate the key if the key is
2122 * present in the table, otherwise zero, so that comparisons can be easily
2123 * performed. If the inspected parameter is not stored in the table, <not found>
2124 * is returned.
2125 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02002126static int sample_conv_table_sess_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002127{
2128 struct stktable *t;
2129 struct stktable_key *key;
2130 struct stksess *ts;
2131 void *ptr;
2132
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002133 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002134
2135 key = smp_to_stkey(smp, t);
2136 if (!key)
2137 return 0;
2138
Willy Tarreauf0c730a2016-05-25 17:07:56 +02002139 ts = stktable_lookup_key(t, key);
2140
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002141 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02002142 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02002143 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002144
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002145 if (!ts) /* key not present */
2146 return 1;
2147
2148 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_SESS_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04002149 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002150 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Daniel Corbett3e60b112018-05-27 09:47:12 -04002151 t->data_arg[STKTABLE_DT_SESS_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002152
Daniel Corbett3e60b112018-05-27 09:47:12 -04002153 stktable_release(t, ts);
2154 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002155}
2156
2157/* Casts sample <smp> to the type of the table specified in arg(0), and looks
2158 * it up into this table. Returns the amount of concurrent connections tracking
2159 * the same key if the key is present in the table, otherwise zero, so that
2160 * comparisons can be easily performed. If the inspected parameter is not
2161 * stored in the table, <not found> is returned.
2162 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02002163static int sample_conv_table_trackers(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002164{
2165 struct stktable *t;
2166 struct stktable_key *key;
2167 struct stksess *ts;
2168
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002169 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002170
2171 key = smp_to_stkey(smp, t);
2172 if (!key)
2173 return 0;
2174
Willy Tarreauf0c730a2016-05-25 17:07:56 +02002175 ts = stktable_lookup_key(t, key);
2176
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002177 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02002178 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02002179 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002180
Tim Duesterhus65189c12018-06-26 15:57:29 +02002181 if (!ts)
2182 return 1;
2183
2184 smp->data.u.sint = ts->ref_cnt;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002185
Daniel Corbett3e60b112018-05-27 09:47:12 -04002186 stktable_release(t, ts);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002187 return 1;
2188}
2189
Emeric Brun4d7ada82021-06-30 19:04:16 +02002190/* This function increments the gpc counter at index 'rule->arg.gpc.idx' of the
2191 * array on the tracksc counter of index 'rule->arg.gpc.sc' stored into the
2192 * <stream> or directly in the session <sess> if <stream> is set to NULL
2193 *
2194 * This function always returns ACT_RET_CONT and parameter flags is unused.
2195 */
2196static enum act_return action_inc_gpc(struct act_rule *rule, struct proxy *px,
2197 struct session *sess, struct stream *s, int flags)
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002198{
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002199 struct stksess *ts;
2200 struct stkctr *stkctr;
2201
2202 /* Extract the stksess, return OK if no stksess available. */
2203 if (s)
2204 stkctr = &s->stkctr[rule->arg.gpc.sc];
2205 else
2206 stkctr = &sess->stkctr[rule->arg.gpc.sc];
Willy Tarreau79c1e912016-01-25 14:54:45 +01002207
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002208 ts = stkctr_entry(stkctr);
Willy Tarreau79c1e912016-01-25 14:54:45 +01002209 if (ts) {
2210 void *ptr1, *ptr2;
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002211
Emeric Brun4d7ada82021-06-30 19:04:16 +02002212 /* First, update gpc_rate if it's tracked. Second, update its gpc if tracked. */
2213 ptr1 = stktable_data_ptr_idx(stkctr->table, ts, STKTABLE_DT_GPC_RATE, rule->arg.gpc.idx);
2214 ptr2 = stktable_data_ptr_idx(stkctr->table, ts, STKTABLE_DT_GPC, rule->arg.gpc.idx);
2215
Emeric Brun819fc6f2017-06-13 19:37:32 +02002216 if (ptr1 || ptr2) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002217 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002218
2219 if (ptr1)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002220 update_freq_ctr_period(&stktable_data_cast(ptr1, std_t_frqp),
Emeric Brun4d7ada82021-06-30 19:04:16 +02002221 stkctr->table->data_arg[STKTABLE_DT_GPC_RATE].u, 1);
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002222
Emeric Brun819fc6f2017-06-13 19:37:32 +02002223 if (ptr2)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002224 stktable_data_cast(ptr2, std_t_uint)++;
Willy Tarreau79c1e912016-01-25 14:54:45 +01002225
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002226 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002227
2228 /* If data was modified, we need to touch to re-schedule sync */
2229 stktable_touch_local(stkctr->table, ts, 0);
2230 }
Willy Tarreau79c1e912016-01-25 14:54:45 +01002231 }
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002232 return ACT_RET_CONT;
2233}
2234
Emeric Brun4d7ada82021-06-30 19:04:16 +02002235/* Same as action_inc_gpc() but for gpc0 only */
2236static enum act_return action_inc_gpc0(struct act_rule *rule, struct proxy *px,
2237 struct session *sess, struct stream *s, int flags)
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002238{
Emeric Brun4d7ada82021-06-30 19:04:16 +02002239 struct stksess *ts;
2240 struct stkctr *stkctr;
Willy Tarreau5b654ad2021-07-06 18:51:12 +02002241 unsigned int period = 0;
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002242
Emeric Brun4d7ada82021-06-30 19:04:16 +02002243 /* Extract the stksess, return OK if no stksess available. */
2244 if (s)
2245 stkctr = &s->stkctr[rule->arg.gpc.sc];
2246 else
2247 stkctr = &sess->stkctr[rule->arg.gpc.sc];
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002248
Emeric Brun4d7ada82021-06-30 19:04:16 +02002249 ts = stkctr_entry(stkctr);
2250 if (ts) {
2251 void *ptr1, *ptr2;
2252
2253 /* First, update gpc0_rate if it's tracked. Second, update its gpc0 if tracked. */
2254 ptr1 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC0_RATE);
Emeric Brun726783d2021-06-30 19:06:43 +02002255 if (ptr1) {
2256 period = stkctr->table->data_arg[STKTABLE_DT_GPC0_RATE].u;
2257 }
2258 else {
2259 /* fallback on the gpc array */
2260 ptr1 = stktable_data_ptr_idx(stkctr->table, ts, STKTABLE_DT_GPC_RATE, 0);
2261 if (ptr1)
2262 period = stkctr->table->data_arg[STKTABLE_DT_GPC_RATE].u;
2263 }
2264
Emeric Brun4d7ada82021-06-30 19:04:16 +02002265 ptr2 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC0);
Emeric Brun726783d2021-06-30 19:06:43 +02002266 if (!ptr2) {
2267 /* fallback on the gpc array */
2268 ptr2 = stktable_data_ptr_idx(stkctr->table, ts, STKTABLE_DT_GPC, 0);
2269 }
2270
Emeric Brun4d7ada82021-06-30 19:04:16 +02002271 if (ptr1 || ptr2) {
2272 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
2273
2274 if (ptr1)
2275 update_freq_ctr_period(&stktable_data_cast(ptr1, std_t_frqp),
Emeric Brun726783d2021-06-30 19:06:43 +02002276 period, 1);
Emeric Brun4d7ada82021-06-30 19:04:16 +02002277
2278 if (ptr2)
2279 stktable_data_cast(ptr2, std_t_uint)++;
2280
2281 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
2282
2283 /* If data was modified, we need to touch to re-schedule sync */
2284 stktable_touch_local(stkctr->table, ts, 0);
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002285 }
2286 }
Emeric Brun4d7ada82021-06-30 19:04:16 +02002287 return ACT_RET_CONT;
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002288}
2289
Emeric Brun4d7ada82021-06-30 19:04:16 +02002290/* Same as action_inc_gpc() but for gpc1 only */
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002291static enum act_return action_inc_gpc1(struct act_rule *rule, struct proxy *px,
2292 struct session *sess, struct stream *s, int flags)
2293{
2294 struct stksess *ts;
2295 struct stkctr *stkctr;
Willy Tarreau5b654ad2021-07-06 18:51:12 +02002296 unsigned int period = 0;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002297
2298 /* Extract the stksess, return OK if no stksess available. */
2299 if (s)
2300 stkctr = &s->stkctr[rule->arg.gpc.sc];
2301 else
2302 stkctr = &sess->stkctr[rule->arg.gpc.sc];
2303
2304 ts = stkctr_entry(stkctr);
2305 if (ts) {
2306 void *ptr1, *ptr2;
2307
2308 /* First, update gpc1_rate if it's tracked. Second, update its gpc1 if tracked. */
2309 ptr1 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC1_RATE);
Emeric Brun726783d2021-06-30 19:06:43 +02002310 if (ptr1) {
2311 period = stkctr->table->data_arg[STKTABLE_DT_GPC1_RATE].u;
2312 }
2313 else {
2314 /* fallback on the gpc array */
2315 ptr1 = stktable_data_ptr_idx(stkctr->table, ts, STKTABLE_DT_GPC_RATE, 1);
2316 if (ptr1)
2317 period = stkctr->table->data_arg[STKTABLE_DT_GPC_RATE].u;
2318 }
2319
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002320 ptr2 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC1);
Emeric Brun726783d2021-06-30 19:06:43 +02002321 if (!ptr2) {
2322 /* fallback on the gpc array */
2323 ptr2 = stktable_data_ptr_idx(stkctr->table, ts, STKTABLE_DT_GPC, 1);
2324 }
2325
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002326 if (ptr1 || ptr2) {
2327 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
2328
2329 if (ptr1)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002330 update_freq_ctr_period(&stktable_data_cast(ptr1, std_t_frqp),
Emeric Brun726783d2021-06-30 19:06:43 +02002331 period, 1);
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002332
2333 if (ptr2)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002334 stktable_data_cast(ptr2, std_t_uint)++;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002335
2336 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
2337
2338 /* If data was modified, we need to touch to re-schedule sync */
2339 stktable_touch_local(stkctr->table, ts, 0);
2340 }
2341 }
2342 return ACT_RET_CONT;
2343}
2344
Emeric Brun4d7ada82021-06-30 19:04:16 +02002345/* This function is a common parser for actions incrementing the GPC
2346 * (General Purpose Counters). It understands the formats:
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002347 *
Emeric Brun4d7ada82021-06-30 19:04:16 +02002348 * sc-inc-gpc(<gpc IDX>,<track ID>)
2349 * sc-inc-gpc0([<track ID>])
2350 * sc-inc-gpc1([<track ID>])
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002351 *
Emeric Brun4d7ada82021-06-30 19:04:16 +02002352 * It returns ACT_RET_PRS_ERR if fails and <err> is filled with an error
2353 * message. Otherwise it returns ACT_RET_PRS_OK.
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002354 */
Emeric Brun4d7ada82021-06-30 19:04:16 +02002355static enum act_parse_ret parse_inc_gpc(const char **args, int *arg, struct proxy *px,
2356 struct act_rule *rule, char **err)
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002357{
2358 const char *cmd_name = args[*arg-1];
2359 char *error;
2360
Emeric Brun4d7ada82021-06-30 19:04:16 +02002361 cmd_name += strlen("sc-inc-gpc");
2362 if (*cmd_name == '(') {
2363 cmd_name++; /* skip the '(' */
2364 rule->arg.gpc.idx = strtoul(cmd_name, &error, 10); /* Convert stick table id. */
2365 if (*error != ',') {
2366 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 +01002367 return ACT_RET_PRS_ERR;
2368 }
Emeric Brun4d7ada82021-06-30 19:04:16 +02002369 else {
2370 cmd_name = error + 1; /* skip the ',' */
2371 rule->arg.gpc.sc = strtol(cmd_name, &error, 10); /* Convert stick table id. */
2372 if (*error != ')') {
2373 memprintf(err, "invalid stick table track ID '%s'. Expects sc-inc-gpc(<GPC ID>,<Track ID>)", args[*arg-1]);
2374 return ACT_RET_PRS_ERR;
2375 }
2376
2377 if (rule->arg.gpc.sc >= MAX_SESS_STKCTR) {
2378 memprintf(err, "invalid stick table track ID '%s'. The max allowed ID is %d",
2379 args[*arg-1], MAX_SESS_STKCTR-1);
2380 return ACT_RET_PRS_ERR;
2381 }
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002382 }
Emeric Brun4d7ada82021-06-30 19:04:16 +02002383 rule->action_ptr = action_inc_gpc;
2384 }
2385 else if (*cmd_name == '0' ||*cmd_name == '1') {
2386 char c = *cmd_name;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002387
Emeric Brun4d7ada82021-06-30 19:04:16 +02002388 cmd_name++;
2389 if (*cmd_name == '\0') {
2390 /* default stick table id. */
2391 rule->arg.gpc.sc = 0;
2392 } else {
2393 /* parse the stick table id. */
2394 if (*cmd_name != '(') {
2395 memprintf(err, "invalid stick table track ID. Expects %s(<Track ID>)", args[*arg-1]);
2396 return ACT_RET_PRS_ERR;
2397 }
2398 cmd_name++; /* jump the '(' */
2399 rule->arg.gpc.sc = strtol(cmd_name, &error, 10); /* Convert stick table id. */
2400 if (*error != ')') {
2401 memprintf(err, "invalid stick table track ID. Expects %s(<Track ID>)", args[*arg-1]);
2402 return ACT_RET_PRS_ERR;
2403 }
2404
2405 if (rule->arg.gpc.sc >= MAX_SESS_STKCTR) {
2406 memprintf(err, "invalid stick table track ID. The max allowed ID is %d",
2407 MAX_SESS_STKCTR-1);
2408 return ACT_RET_PRS_ERR;
2409 }
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002410 }
Emeric Brun4d7ada82021-06-30 19:04:16 +02002411 if (c == '1')
2412 rule->action_ptr = action_inc_gpc1;
2413 else
2414 rule->action_ptr = action_inc_gpc0;
2415 }
2416 else {
2417 /* default stick table id. */
2418 memprintf(err, "invalid gpc ID '%s'. Expects sc-set-gpc(<GPC ID>,<Track ID>)", args[*arg-1]);
2419 return ACT_RET_PRS_ERR;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002420 }
2421 rule->action = ACT_CUSTOM;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002422 return ACT_RET_PRS_OK;
2423}
2424
Emeric Brun877b0b52021-06-30 18:57:49 +02002425/* This function sets the gpt at index 'rule->arg.gpt.idx' of the array on the
2426 * tracksc counter of index 'rule->arg.gpt.sc' stored into the <stream> or
2427 * directly in the session <sess> if <stream> is set to NULL. This gpt is
2428 * set to the value computed by the expression 'rule->arg.gpt.expr' or if
2429 * 'rule->arg.gpt.expr' is null directly to the value of 'rule->arg.gpt.value'.
2430 *
2431 * This function always returns ACT_RET_CONT and parameter flags is unused.
2432 */
2433static enum act_return action_set_gpt(struct act_rule *rule, struct proxy *px,
2434 struct session *sess, struct stream *s, int flags)
2435{
2436 void *ptr;
2437 struct stksess *ts;
2438 struct stkctr *stkctr;
2439 unsigned int value = 0;
2440 struct sample *smp;
2441 int smp_opt_dir;
2442
2443 /* Extract the stksess, return OK if no stksess available. */
2444 if (s)
2445 stkctr = &s->stkctr[rule->arg.gpt.sc];
2446 else
2447 stkctr = &sess->stkctr[rule->arg.gpt.sc];
2448
2449 ts = stkctr_entry(stkctr);
2450 if (!ts)
2451 return ACT_RET_CONT;
2452
2453 /* Store the sample in the required sc, and ignore errors. */
2454 ptr = stktable_data_ptr_idx(stkctr->table, ts, STKTABLE_DT_GPT, rule->arg.gpt.idx);
2455 if (ptr) {
2456
2457 if (!rule->arg.gpt.expr)
2458 value = (unsigned int)(rule->arg.gpt.value);
2459 else {
2460 switch (rule->from) {
2461 case ACT_F_TCP_REQ_SES: smp_opt_dir = SMP_OPT_DIR_REQ; break;
2462 case ACT_F_TCP_REQ_CNT: smp_opt_dir = SMP_OPT_DIR_REQ; break;
2463 case ACT_F_TCP_RES_CNT: smp_opt_dir = SMP_OPT_DIR_RES; break;
2464 case ACT_F_HTTP_REQ: smp_opt_dir = SMP_OPT_DIR_REQ; break;
2465 case ACT_F_HTTP_RES: smp_opt_dir = SMP_OPT_DIR_RES; break;
2466 default:
2467 send_log(px, LOG_ERR, "stick table: internal error while setting gpt%u.", rule->arg.gpt.idx);
2468 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))
2469 ha_alert("stick table: internal error while executing setting gpt%u.\n", rule->arg.gpt.idx);
2470 return ACT_RET_CONT;
2471 }
2472
2473 /* Fetch and cast the expression. */
2474 smp = sample_fetch_as_type(px, sess, s, smp_opt_dir|SMP_OPT_FINAL, rule->arg.gpt.expr, SMP_T_SINT);
2475 if (!smp) {
2476 send_log(px, LOG_WARNING, "stick table: invalid expression or data type while setting gpt%u.", rule->arg.gpt.idx);
2477 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))
2478 ha_alert("stick table: invalid expression or data type while setting gpt%u.\n", rule->arg.gpt.idx);
2479 return ACT_RET_CONT;
2480 }
2481 value = (unsigned int)(smp->data.u.sint);
2482 }
2483
2484 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
2485
2486 stktable_data_cast(ptr, std_t_uint) = value;
2487
2488 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
2489
2490 stktable_touch_local(stkctr->table, ts, 0);
2491 }
2492
2493 return ACT_RET_CONT;
2494}
2495
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002496/* Always returns 1. */
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002497static enum act_return action_set_gpt0(struct act_rule *rule, struct proxy *px,
Willy Tarreau658b85b2015-09-27 10:00:49 +02002498 struct session *sess, struct stream *s, int flags)
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002499{
2500 void *ptr;
2501 struct stksess *ts;
2502 struct stkctr *stkctr;
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002503 unsigned int value = 0;
2504 struct sample *smp;
2505 int smp_opt_dir;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002506
2507 /* Extract the stksess, return OK if no stksess available. */
2508 if (s)
2509 stkctr = &s->stkctr[rule->arg.gpt.sc];
2510 else
2511 stkctr = &sess->stkctr[rule->arg.gpt.sc];
Willy Tarreau79c1e912016-01-25 14:54:45 +01002512
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002513 ts = stkctr_entry(stkctr);
2514 if (!ts)
2515 return ACT_RET_CONT;
2516
2517 /* Store the sample in the required sc, and ignore errors. */
2518 ptr = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPT0);
Emeric Brunf7ab0bf2021-06-30 18:58:22 +02002519 if (!ptr)
2520 ptr = stktable_data_ptr_idx(stkctr->table, ts, STKTABLE_DT_GPT, 0);
2521
Willy Tarreau79c1e912016-01-25 14:54:45 +01002522 if (ptr) {
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002523 if (!rule->arg.gpt.expr)
2524 value = (unsigned int)(rule->arg.gpt.value);
2525 else {
2526 switch (rule->from) {
2527 case ACT_F_TCP_REQ_SES: smp_opt_dir = SMP_OPT_DIR_REQ; break;
2528 case ACT_F_TCP_REQ_CNT: smp_opt_dir = SMP_OPT_DIR_REQ; break;
2529 case ACT_F_TCP_RES_CNT: smp_opt_dir = SMP_OPT_DIR_RES; break;
2530 case ACT_F_HTTP_REQ: smp_opt_dir = SMP_OPT_DIR_REQ; break;
2531 case ACT_F_HTTP_RES: smp_opt_dir = SMP_OPT_DIR_RES; break;
2532 default:
2533 send_log(px, LOG_ERR, "stick table: internal error while setting gpt0.");
2534 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))
2535 ha_alert("stick table: internal error while executing setting gpt0.\n");
2536 return ACT_RET_CONT;
2537 }
2538
2539 /* Fetch and cast the expression. */
2540 smp = sample_fetch_as_type(px, sess, s, smp_opt_dir|SMP_OPT_FINAL, rule->arg.gpt.expr, SMP_T_SINT);
2541 if (!smp) {
2542 send_log(px, LOG_WARNING, "stick table: invalid expression or data type while setting gpt0.");
2543 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))
2544 ha_alert("stick table: invalid expression or data type while setting gpt0.\n");
2545 return ACT_RET_CONT;
2546 }
2547 value = (unsigned int)(smp->data.u.sint);
2548 }
2549
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002550 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002551
Emeric Brun0e3457b2021-06-30 17:18:28 +02002552 stktable_data_cast(ptr, std_t_uint) = value;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002553
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002554 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002555
2556 stktable_touch_local(stkctr->table, ts, 0);
Willy Tarreau79c1e912016-01-25 14:54:45 +01002557 }
2558
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002559 return ACT_RET_CONT;
2560}
2561
Emeric Brun877b0b52021-06-30 18:57:49 +02002562/* This function is a parser for the "sc-set-gpt" and "sc-set-gpt0" actions.
2563 * It understands the formats:
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002564 *
Emeric Brun877b0b52021-06-30 18:57:49 +02002565 * sc-set-gpt(<gpt IDX>,<track ID>) <expression>
2566 * sc-set-gpt0(<track ID>) <expression>
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002567 *
Emeric Brun877b0b52021-06-30 18:57:49 +02002568 * It returns ACT_RET_PRS_ERR if fails and <err> is filled with an error message.
2569 * Otherwise, it returns ACT_RET_PRS_OK and the variable 'rule->arg.gpt.expr'
2570 * is filled with the pointer to the expression to execute or NULL if the arg
2571 * is directly an integer stored into 'rule->arg.gpt.value'.
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002572 */
Emeric Brun877b0b52021-06-30 18:57:49 +02002573static enum act_parse_ret parse_set_gpt(const char **args, int *arg, struct proxy *px,
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002574 struct act_rule *rule, char **err)
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002575{
2576 const char *cmd_name = args[*arg-1];
2577 char *error;
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002578 int smp_val;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002579
Emeric Brun877b0b52021-06-30 18:57:49 +02002580 cmd_name += strlen("sc-set-gpt");
2581 if (*cmd_name == '(') {
2582 cmd_name++; /* skip the '(' */
2583 rule->arg.gpt.idx = strtoul(cmd_name, &error, 10); /* Convert stick table id. */
2584 if (*error != ',') {
2585 memprintf(err, "Missing gpt ID '%s'. Expects sc-set-gpt(<GPT ID>,<Track ID>)", args[*arg-1]);
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002586 return ACT_RET_PRS_ERR;
2587 }
Emeric Brun877b0b52021-06-30 18:57:49 +02002588 else {
2589 cmd_name = error + 1; /* skip the ',' */
2590 rule->arg.gpt.sc = strtol(cmd_name, &error, 10); /* Convert stick table id. */
2591 if (*error != ')') {
2592 memprintf(err, "invalid stick table track ID '%s'. Expects sc-set-gpt(<GPT ID>,<Track ID>)", args[*arg-1]);
2593 return ACT_RET_PRS_ERR;
2594 }
2595
2596 if (rule->arg.gpt.sc >= MAX_SESS_STKCTR) {
2597 memprintf(err, "invalid stick table track ID '%s'. The max allowed ID is %d",
2598 args[*arg-1], MAX_SESS_STKCTR-1);
2599 return ACT_RET_PRS_ERR;
2600 }
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002601 }
Emeric Brun877b0b52021-06-30 18:57:49 +02002602 rule->action_ptr = action_set_gpt;
2603 }
2604 else if (*cmd_name == '0') {
2605 cmd_name++;
2606 if (*cmd_name == '\0') {
2607 /* default stick table id. */
2608 rule->arg.gpt.sc = 0;
2609 } else {
2610 /* parse the stick table id. */
2611 if (*cmd_name != '(') {
2612 memprintf(err, "invalid stick table track ID '%s'. Expects sc-set-gpt0(<Track ID>)", args[*arg-1]);
2613 return ACT_RET_PRS_ERR;
2614 }
2615 cmd_name++; /* jump the '(' */
2616 rule->arg.gpt.sc = strtol(cmd_name, &error, 10); /* Convert stick table id. */
2617 if (*error != ')') {
2618 memprintf(err, "invalid stick table track ID '%s'. Expects sc-set-gpt0(<Track ID>)", args[*arg-1]);
2619 return ACT_RET_PRS_ERR;
2620 }
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002621
Emeric Brun877b0b52021-06-30 18:57:49 +02002622 if (rule->arg.gpt.sc >= MAX_SESS_STKCTR) {
2623 memprintf(err, "invalid stick table track ID '%s'. The max allowed ID is %d",
2624 args[*arg-1], MAX_SESS_STKCTR-1);
2625 return ACT_RET_PRS_ERR;
2626 }
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002627 }
Emeric Brun877b0b52021-06-30 18:57:49 +02002628 rule->action_ptr = action_set_gpt0;
2629 }
2630 else {
2631 /* default stick table id. */
2632 memprintf(err, "invalid gpt ID '%s'. Expects sc-set-gpt(<GPT ID>,<Track ID>)", args[*arg-1]);
2633 return ACT_RET_PRS_ERR;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002634 }
2635
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002636 rule->arg.gpt.expr = NULL;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002637 rule->arg.gpt.value = strtol(args[*arg], &error, 10);
2638 if (*error != '\0') {
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002639 rule->arg.gpt.expr = sample_parse_expr((char **)args, arg, px->conf.args.file,
Willy Tarreaue3b57bf2020-02-14 16:50:14 +01002640 px->conf.args.line, err, &px->conf.args, NULL);
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002641 if (!rule->arg.gpt.expr)
2642 return ACT_RET_PRS_ERR;
2643
2644 switch (rule->from) {
2645 case ACT_F_TCP_REQ_SES: smp_val = SMP_VAL_FE_SES_ACC; break;
2646 case ACT_F_TCP_REQ_CNT: smp_val = SMP_VAL_FE_REQ_CNT; break;
2647 case ACT_F_TCP_RES_CNT: smp_val = SMP_VAL_BE_RES_CNT; break;
2648 case ACT_F_HTTP_REQ: smp_val = SMP_VAL_FE_HRQ_HDR; break;
2649 case ACT_F_HTTP_RES: smp_val = SMP_VAL_BE_HRS_HDR; break;
2650 default:
2651 memprintf(err, "internal error, unexpected rule->from=%d, please report this bug!", rule->from);
2652 return ACT_RET_PRS_ERR;
2653 }
2654 if (!(rule->arg.gpt.expr->fetch->val & smp_val)) {
2655 memprintf(err, "fetch method '%s' extracts information from '%s', none of which is available here", args[*arg-1],
2656 sample_src_names(rule->arg.gpt.expr->fetch->use));
2657 free(rule->arg.gpt.expr);
2658 return ACT_RET_PRS_ERR;
2659 }
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002660 }
2661 (*arg)++;
2662
Thierry FOURNIER42148732015-09-02 17:17:33 +02002663 rule->action = ACT_CUSTOM;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002664
2665 return ACT_RET_PRS_OK;
2666}
2667
Willy Tarreau7d562212016-11-25 16:10:05 +01002668/* set temp integer to the number of used entries in the table pointed to by expr.
2669 * Accepts exactly 1 argument of type table.
2670 */
2671static int
2672smp_fetch_table_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
2673{
2674 smp->flags = SMP_F_VOL_TEST;
2675 smp->data.type = SMP_T_SINT;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002676 smp->data.u.sint = args->data.t->current;
Willy Tarreau7d562212016-11-25 16:10:05 +01002677 return 1;
2678}
2679
2680/* set temp integer to the number of free entries in the table pointed to by expr.
2681 * Accepts exactly 1 argument of type table.
2682 */
2683static int
2684smp_fetch_table_avl(const struct arg *args, struct sample *smp, const char *kw, void *private)
2685{
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002686 struct stktable *t;
Willy Tarreau7d562212016-11-25 16:10:05 +01002687
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002688 t = args->data.t;
Willy Tarreau7d562212016-11-25 16:10:05 +01002689 smp->flags = SMP_F_VOL_TEST;
2690 smp->data.type = SMP_T_SINT;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002691 smp->data.u.sint = t->size - t->current;
Willy Tarreau7d562212016-11-25 16:10:05 +01002692 return 1;
2693}
2694
2695/* Returns a pointer to a stkctr depending on the fetch keyword name.
2696 * It is designed to be called as sc[0-9]_* sc_* or src_* exclusively.
2697 * sc[0-9]_* will return a pointer to the respective field in the
2698 * stream <l4>. sc_* requires an UINT argument specifying the stick
2699 * counter number. src_* will fill a locally allocated structure with
2700 * the table and entry corresponding to what is specified with src_*.
2701 * NULL may be returned if the designated stkctr is not tracked. For
2702 * the sc_* and sc[0-9]_* forms, an optional table argument may be
2703 * passed. When present, the currently tracked key is then looked up
2704 * in the specified table instead of the current table. The purpose is
Ilya Shipitsin47d17182020-06-21 21:42:57 +05002705 * to be able to convert multiple values per key (eg: have gpc0 from
Willy Tarreau7d562212016-11-25 16:10:05 +01002706 * multiple tables). <strm> is allowed to be NULL, in which case only
2707 * the session will be consulted.
2708 */
2709struct stkctr *
Emeric Brun819fc6f2017-06-13 19:37:32 +02002710smp_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 +01002711{
Willy Tarreau7d562212016-11-25 16:10:05 +01002712 struct stkctr *stkptr;
2713 struct stksess *stksess;
2714 unsigned int num = kw[2] - '0';
2715 int arg = 0;
2716
2717 if (num == '_' - '0') {
2718 /* sc_* variant, args[0] = ctr# (mandatory) */
2719 num = args[arg++].data.sint;
Willy Tarreau7d562212016-11-25 16:10:05 +01002720 }
2721 else if (num > 9) { /* src_* variant, args[0] = table */
2722 struct stktable_key *key;
2723 struct connection *conn = objt_conn(sess->origin);
2724 struct sample smp;
2725
2726 if (!conn)
2727 return NULL;
2728
Joseph Herlant5662fa42018-11-15 13:43:28 -08002729 /* Fetch source address in a sample. */
Willy Tarreau7d562212016-11-25 16:10:05 +01002730 smp.px = NULL;
2731 smp.sess = sess;
2732 smp.strm = strm;
Amaury Denoyellec460c702021-05-12 10:17:47 +02002733 if (!smp_fetch_src || !smp_fetch_src(empty_arg_list, &smp, "src", NULL))
Willy Tarreau7d562212016-11-25 16:10:05 +01002734 return NULL;
2735
2736 /* Converts into key. */
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002737 key = smp_to_stkey(&smp, args->data.t);
Willy Tarreau7d562212016-11-25 16:10:05 +01002738 if (!key)
2739 return NULL;
2740
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002741 stkctr->table = args->data.t;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002742 stkctr_set_entry(stkctr, stktable_lookup_key(stkctr->table, key));
2743 return stkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002744 }
2745
2746 /* Here, <num> contains the counter number from 0 to 9 for
2747 * the sc[0-9]_ form, or even higher using sc_(num) if needed.
2748 * args[arg] is the first optional argument. We first lookup the
2749 * ctr form the stream, then from the session if it was not there.
Christopher Fauleta9fa88a2019-10-21 10:53:34 +02002750 * But we must be sure the counter does not exceed MAX_SESS_STKCTR.
Willy Tarreau7d562212016-11-25 16:10:05 +01002751 */
Christopher Fauleta9fa88a2019-10-21 10:53:34 +02002752 if (num >= MAX_SESS_STKCTR)
2753 return NULL;
Willy Tarreau7d562212016-11-25 16:10:05 +01002754
2755 if (strm)
2756 stkptr = &strm->stkctr[num];
2757 if (!strm || !stkctr_entry(stkptr)) {
2758 stkptr = &sess->stkctr[num];
2759 if (!stkctr_entry(stkptr))
2760 return NULL;
2761 }
2762
2763 stksess = stkctr_entry(stkptr);
2764 if (!stksess)
2765 return NULL;
2766
2767 if (unlikely(args[arg].type == ARGT_TAB)) {
2768 /* an alternate table was specified, let's look up the same key there */
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002769 stkctr->table = args[arg].data.t;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002770 stkctr_set_entry(stkctr, stktable_lookup(stkctr->table, stksess));
2771 return stkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002772 }
2773 return stkptr;
2774}
2775
2776/* same as smp_fetch_sc_stkctr() but dedicated to src_* and can create
2777 * the entry if it doesn't exist yet. This is needed for a few fetch
2778 * functions which need to create an entry, such as src_inc_gpc* and
2779 * src_clr_gpc*.
2780 */
2781struct stkctr *
Emeric Brun819fc6f2017-06-13 19:37:32 +02002782smp_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 +01002783{
Willy Tarreau7d562212016-11-25 16:10:05 +01002784 struct stktable_key *key;
2785 struct connection *conn = objt_conn(sess->origin);
2786 struct sample smp;
2787
2788 if (strncmp(kw, "src_", 4) != 0)
2789 return NULL;
2790
2791 if (!conn)
2792 return NULL;
2793
Joseph Herlant5662fa42018-11-15 13:43:28 -08002794 /* Fetch source address in a sample. */
Willy Tarreau7d562212016-11-25 16:10:05 +01002795 smp.px = NULL;
2796 smp.sess = sess;
2797 smp.strm = strm;
Amaury Denoyellec460c702021-05-12 10:17:47 +02002798 if (!smp_fetch_src || !smp_fetch_src(empty_arg_list, &smp, "src", NULL))
Willy Tarreau7d562212016-11-25 16:10:05 +01002799 return NULL;
2800
2801 /* Converts into key. */
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002802 key = smp_to_stkey(&smp, args->data.t);
Willy Tarreau7d562212016-11-25 16:10:05 +01002803 if (!key)
2804 return NULL;
2805
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002806 stkctr->table = args->data.t;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002807 stkctr_set_entry(stkctr, stktable_get_entry(stkctr->table, key));
2808 return stkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002809}
2810
2811/* set return a boolean indicating if the requested stream counter is
2812 * currently being tracked or not.
2813 * Supports being called as "sc[0-9]_tracked" only.
2814 */
2815static int
2816smp_fetch_sc_tracked(const struct arg *args, struct sample *smp, const char *kw, void *private)
2817{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002818 struct stkctr tmpstkctr;
2819 struct stkctr *stkctr;
2820
Willy Tarreau7d562212016-11-25 16:10:05 +01002821 smp->flags = SMP_F_VOL_TEST;
2822 smp->data.type = SMP_T_BOOL;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002823 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2824 smp->data.u.sint = !!stkctr;
2825
2826 /* release the ref count */
Dirkjan Bussinkff57f1b2018-09-14 14:31:22 +02002827 if (stkctr == &tmpstkctr)
Emeric Brun819fc6f2017-06-13 19:37:32 +02002828 stktable_release(stkctr->table, stkctr_entry(stkctr));
2829
Emeric Brun877b0b52021-06-30 18:57:49 +02002830 return 1;
2831}
2832
2833/* set <smp> to the General Purpose Tag of index set as first arg
2834 * to value from the stream's tracked frontend counters or from the src.
2835 * Supports being called as "sc_get_gpt(<gpt-idx>,<sc-idx>[,<table>])" or
2836 * "src_get_gpt(<gpt-idx>[,<table>])" only. Value zero is returned if
2837 * the key is new or gpt is not stored.
2838 */
2839static int
2840smp_fetch_sc_get_gpt(const struct arg *args, struct sample *smp, const char *kw, void *private)
2841{
2842 struct stkctr tmpstkctr;
2843 struct stkctr *stkctr;
2844 unsigned int idx;
2845
2846 idx = args[0].data.sint;
2847
2848 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args + 1, kw, &tmpstkctr);
2849 if (!stkctr)
2850 return 0;
2851
2852 smp->flags = SMP_F_VOL_TEST;
2853 smp->data.type = SMP_T_SINT;
2854 smp->data.u.sint = 0;
2855
2856 if (stkctr_entry(stkctr)) {
2857 void *ptr;
2858
2859 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPT, idx);
2860 if (!ptr) {
2861 if (stkctr == &tmpstkctr)
2862 stktable_release(stkctr->table, stkctr_entry(stkctr));
2863 return 0; /* parameter not stored */
2864 }
2865
2866 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2867
2868 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
2869
2870 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2871
2872 if (stkctr == &tmpstkctr)
2873 stktable_release(stkctr->table, stkctr_entry(stkctr));
2874 }
Willy Tarreau7d562212016-11-25 16:10:05 +01002875 return 1;
2876}
2877
2878/* set <smp> to the General Purpose Flag 0 value from the stream's tracked
2879 * frontend counters or from the src.
2880 * Supports being called as "sc[0-9]_get_gpc0" or "src_get_gpt0" only. Value
2881 * zero is returned if the key is new.
2882 */
2883static int
2884smp_fetch_sc_get_gpt0(const struct arg *args, struct sample *smp, const char *kw, void *private)
2885{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002886 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002887 struct stkctr *stkctr;
2888
Emeric Brun819fc6f2017-06-13 19:37:32 +02002889 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002890 if (!stkctr)
2891 return 0;
2892
2893 smp->flags = SMP_F_VOL_TEST;
2894 smp->data.type = SMP_T_SINT;
2895 smp->data.u.sint = 0;
2896
Emeric Brun819fc6f2017-06-13 19:37:32 +02002897 if (stkctr_entry(stkctr)) {
2898 void *ptr;
2899
2900 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPT0);
Emeric Brunf7ab0bf2021-06-30 18:58:22 +02002901 if (!ptr)
2902 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPT, 0);
2903
Emeric Brun4d7ada82021-06-30 19:04:16 +02002904 if (!ptr) {
2905 if (stkctr == &tmpstkctr)
2906 stktable_release(stkctr->table, stkctr_entry(stkctr));
2907 return 0; /* parameter not stored */
2908 }
2909
2910 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2911
2912 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
2913
2914 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2915
2916 if (stkctr == &tmpstkctr)
2917 stktable_release(stkctr->table, stkctr_entry(stkctr));
2918 }
2919 return 1;
2920}
2921
2922/* set <smp> to the GPC[args(0)]'s value from the stream's tracked
2923 * frontend counters or from the src.
2924 * Supports being called as "sc_get_gpc(<gpc-idx>,<sc-idx>[,<table>])" or
2925 * "src_get_gpc(<gpc-idx>[,<table>])" only. Value
2926 * Value zero is returned if the key is new or gpc is not stored.
2927 */
2928static int
2929smp_fetch_sc_get_gpc(const struct arg *args, struct sample *smp, const char *kw, void *private)
2930{
2931 struct stkctr tmpstkctr;
2932 struct stkctr *stkctr;
2933 unsigned int idx;
2934
2935 idx = args[0].data.sint;
2936
2937 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args + 1, kw, &tmpstkctr);
2938 if (!stkctr)
2939 return 0;
2940
2941 smp->flags = SMP_F_VOL_TEST;
2942 smp->data.type = SMP_T_SINT;
2943 smp->data.u.sint = 0;
2944
2945 if (stkctr_entry(stkctr) != NULL) {
2946 void *ptr;
2947
2948 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC, idx);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002949 if (!ptr) {
2950 if (stkctr == &tmpstkctr)
2951 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002952 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002953 }
2954
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002955 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002956
Emeric Brun0e3457b2021-06-30 17:18:28 +02002957 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002958
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002959 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002960
2961 if (stkctr == &tmpstkctr)
2962 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002963 }
2964 return 1;
2965}
2966
2967/* set <smp> to the General Purpose Counter 0 value from the stream's tracked
2968 * frontend counters or from the src.
2969 * Supports being called as "sc[0-9]_get_gpc0" or "src_get_gpc0" only. Value
2970 * zero is returned if the key is new.
2971 */
2972static int
2973smp_fetch_sc_get_gpc0(const struct arg *args, struct sample *smp, const char *kw, void *private)
2974{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002975 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002976 struct stkctr *stkctr;
2977
Emeric Brun819fc6f2017-06-13 19:37:32 +02002978 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002979 if (!stkctr)
2980 return 0;
2981
2982 smp->flags = SMP_F_VOL_TEST;
2983 smp->data.type = SMP_T_SINT;
2984 smp->data.u.sint = 0;
2985
2986 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002987 void *ptr;
2988
2989 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0);
2990 if (!ptr) {
Emeric Brun726783d2021-06-30 19:06:43 +02002991 /* fallback on the gpc array */
2992 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC, 0);
2993 }
2994
2995 if (!ptr) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002996 if (stkctr == &tmpstkctr)
2997 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002998 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002999 }
3000
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003001 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003002
Emeric Brun0e3457b2021-06-30 17:18:28 +02003003 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003004
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003005 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003006
3007 if (stkctr == &tmpstkctr)
3008 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003009 }
3010 return 1;
3011}
3012
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003013/* set <smp> to the General Purpose Counter 1 value from the stream's tracked
3014 * frontend counters or from the src.
3015 * Supports being called as "sc[0-9]_get_gpc1" or "src_get_gpc1" only. Value
3016 * zero is returned if the key is new.
3017 */
3018static int
3019smp_fetch_sc_get_gpc1(const struct arg *args, struct sample *smp, const char *kw, void *private)
3020{
3021 struct stkctr tmpstkctr;
3022 struct stkctr *stkctr;
3023
3024 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
3025 if (!stkctr)
3026 return 0;
3027
3028 smp->flags = SMP_F_VOL_TEST;
3029 smp->data.type = SMP_T_SINT;
3030 smp->data.u.sint = 0;
3031
3032 if (stkctr_entry(stkctr) != NULL) {
3033 void *ptr;
3034
3035 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1);
3036 if (!ptr) {
Emeric Brun726783d2021-06-30 19:06:43 +02003037 /* fallback on the gpc array */
3038 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC, 1);
3039 }
3040
3041 if (!ptr) {
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003042 if (stkctr == &tmpstkctr)
3043 stktable_release(stkctr->table, stkctr_entry(stkctr));
3044 return 0; /* parameter not stored */
3045 }
3046
3047 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3048
Emeric Brun0e3457b2021-06-30 17:18:28 +02003049 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003050
3051 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3052
3053 if (stkctr == &tmpstkctr)
3054 stktable_release(stkctr->table, stkctr_entry(stkctr));
3055 }
3056 return 1;
3057}
3058
Emeric Brun4d7ada82021-06-30 19:04:16 +02003059/* set <smp> to the GPC[args(0)]'s event rate from the stream's
3060 * tracked frontend counters or from the src.
3061 * Supports being called as "sc_gpc_rate(<gpc-idx>,<sc-idx>[,<table])"
3062 * or "src_gpc_rate(<gpc-idx>[,<table>])" only.
3063 * Value zero is returned if the key is new or gpc_rate is not stored.
3064 */
3065static int
3066smp_fetch_sc_gpc_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3067{
3068 struct stkctr tmpstkctr;
3069 struct stkctr *stkctr;
3070 unsigned int idx;
3071
3072 idx = args[0].data.sint;
3073
3074 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args + 1, kw, &tmpstkctr);
3075 if (!stkctr)
3076 return 0;
3077
3078 smp->flags = SMP_F_VOL_TEST;
3079 smp->data.type = SMP_T_SINT;
3080 smp->data.u.sint = 0;
3081 if (stkctr_entry(stkctr) != NULL) {
3082 void *ptr;
3083
3084 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC_RATE, idx);
3085 if (!ptr) {
3086 if (stkctr == &tmpstkctr)
3087 stktable_release(stkctr->table, stkctr_entry(stkctr));
3088 return 0; /* parameter not stored */
3089 }
3090
3091 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3092
3093 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
3094 stkctr->table->data_arg[STKTABLE_DT_GPC_RATE].u);
3095
3096 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3097
3098 if (stkctr == &tmpstkctr)
3099 stktable_release(stkctr->table, stkctr_entry(stkctr));
3100 }
3101 return 1;
3102}
3103
Willy Tarreau7d562212016-11-25 16:10:05 +01003104/* set <smp> to the General Purpose Counter 0's event rate from the stream's
3105 * tracked frontend counters or from the src.
3106 * Supports being called as "sc[0-9]_gpc0_rate" or "src_gpc0_rate" only.
3107 * Value zero is returned if the key is new.
3108 */
3109static int
3110smp_fetch_sc_gpc0_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3111{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003112 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003113 struct stkctr *stkctr;
Emeric Brun726783d2021-06-30 19:06:43 +02003114 unsigned int period;
Willy Tarreau7d562212016-11-25 16:10:05 +01003115
Emeric Brun819fc6f2017-06-13 19:37:32 +02003116 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003117 if (!stkctr)
3118 return 0;
3119
3120 smp->flags = SMP_F_VOL_TEST;
3121 smp->data.type = SMP_T_SINT;
3122 smp->data.u.sint = 0;
3123 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003124 void *ptr;
3125
3126 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0_RATE);
Emeric Brun726783d2021-06-30 19:06:43 +02003127 if (ptr) {
3128 period = stkctr->table->data_arg[STKTABLE_DT_GPC0_RATE].u;
3129 }
3130 else {
3131 /* fallback on the gpc array */
3132 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC_RATE, 0);
3133 if (ptr)
3134 period = stkctr->table->data_arg[STKTABLE_DT_GPC_RATE].u;
3135 }
3136
Emeric Brun819fc6f2017-06-13 19:37:32 +02003137 if (!ptr) {
3138 if (stkctr == &tmpstkctr)
3139 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003140 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003141 }
3142
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003143 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003144
Emeric Brun726783d2021-06-30 19:06:43 +02003145 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp), period);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003146
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003147 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003148
3149 if (stkctr == &tmpstkctr)
3150 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003151 }
3152 return 1;
3153}
3154
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003155/* set <smp> to the General Purpose Counter 1's event rate from the stream's
3156 * tracked frontend counters or from the src.
3157 * Supports being called as "sc[0-9]_gpc1_rate" or "src_gpc1_rate" only.
3158 * Value zero is returned if the key is new.
3159 */
3160static int
3161smp_fetch_sc_gpc1_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3162{
3163 struct stkctr tmpstkctr;
3164 struct stkctr *stkctr;
Emeric Brun726783d2021-06-30 19:06:43 +02003165 unsigned int period;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003166
3167 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
3168 if (!stkctr)
3169 return 0;
3170
3171 smp->flags = SMP_F_VOL_TEST;
3172 smp->data.type = SMP_T_SINT;
3173 smp->data.u.sint = 0;
3174 if (stkctr_entry(stkctr) != NULL) {
3175 void *ptr;
3176
3177 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1_RATE);
Emeric Brun726783d2021-06-30 19:06:43 +02003178 if (ptr) {
3179 period = stkctr->table->data_arg[STKTABLE_DT_GPC1_RATE].u;
3180 }
3181 else {
3182 /* fallback on the gpc array */
3183 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC_RATE, 1);
3184 if (ptr)
3185 period = stkctr->table->data_arg[STKTABLE_DT_GPC_RATE].u;
3186 }
3187
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003188 if (!ptr) {
3189 if (stkctr == &tmpstkctr)
3190 stktable_release(stkctr->table, stkctr_entry(stkctr));
3191 return 0; /* parameter not stored */
3192 }
3193
3194 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3195
Emeric Brun726783d2021-06-30 19:06:43 +02003196 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 +01003197
3198 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3199
3200 if (stkctr == &tmpstkctr)
3201 stktable_release(stkctr->table, stkctr_entry(stkctr));
3202 }
3203 return 1;
3204}
3205
Emeric Brun4d7ada82021-06-30 19:04:16 +02003206/* Increment the GPC[args(0)] value from the stream's tracked
3207 * frontend counters and return it into temp integer.
3208 * Supports being called as "sc_inc_gpc(<gpc-idx>,<sc-idx>[,<table>])"
3209 * or "src_inc_gpc(<gpc-idx>[,<table>])" only.
3210 */
3211static int
3212smp_fetch_sc_inc_gpc(const struct arg *args, struct sample *smp, const char *kw, void *private)
3213{
3214 struct stkctr tmpstkctr;
3215 struct stkctr *stkctr;
3216 unsigned int idx;
3217
3218 idx = args[0].data.sint;
3219
3220 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args + 1, kw, &tmpstkctr);
3221 if (!stkctr)
3222 return 0;
3223
3224 smp->flags = SMP_F_VOL_TEST;
3225 smp->data.type = SMP_T_SINT;
3226 smp->data.u.sint = 0;
3227
3228 if (!stkctr_entry(stkctr))
3229 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
3230
3231 if (stkctr && stkctr_entry(stkctr)) {
3232 void *ptr1,*ptr2;
3233
3234
3235 /* First, update gpc0_rate if it's tracked. Second, update its
3236 * gpc0 if tracked. Returns gpc0's value otherwise the curr_ctr.
3237 */
3238 ptr1 = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC_RATE, idx);
3239 ptr2 = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC, idx);
3240 if (ptr1 || ptr2) {
3241 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3242
3243 if (ptr1) {
3244 update_freq_ctr_period(&stktable_data_cast(ptr1, std_t_frqp),
3245 stkctr->table->data_arg[STKTABLE_DT_GPC_RATE].u, 1);
3246 smp->data.u.sint = (&stktable_data_cast(ptr1, std_t_frqp))->curr_ctr;
3247 }
3248
3249 if (ptr2)
3250 smp->data.u.sint = ++stktable_data_cast(ptr2, std_t_uint);
3251
3252 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3253
3254 /* If data was modified, we need to touch to re-schedule sync */
3255 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
3256 }
3257 else if (stkctr == &tmpstkctr)
3258 stktable_release(stkctr->table, stkctr_entry(stkctr));
3259 }
3260 return 1;
3261}
3262
Willy Tarreau7d562212016-11-25 16:10:05 +01003263/* Increment the General Purpose Counter 0 value from the stream's tracked
3264 * frontend counters and return it into temp integer.
3265 * Supports being called as "sc[0-9]_inc_gpc0" or "src_inc_gpc0" only.
3266 */
3267static int
3268smp_fetch_sc_inc_gpc0(const struct arg *args, struct sample *smp, const char *kw, void *private)
3269{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003270 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003271 struct stkctr *stkctr;
Willy Tarreau5b654ad2021-07-06 18:51:12 +02003272 unsigned int period = 0;
Willy Tarreau7d562212016-11-25 16:10:05 +01003273
Emeric Brun819fc6f2017-06-13 19:37:32 +02003274 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003275 if (!stkctr)
3276 return 0;
3277
3278 smp->flags = SMP_F_VOL_TEST;
3279 smp->data.type = SMP_T_SINT;
3280 smp->data.u.sint = 0;
3281
Emeric Brun819fc6f2017-06-13 19:37:32 +02003282 if (!stkctr_entry(stkctr))
3283 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003284
3285 if (stkctr && stkctr_entry(stkctr)) {
3286 void *ptr1,*ptr2;
3287
Emeric Brun819fc6f2017-06-13 19:37:32 +02003288
Willy Tarreau7d562212016-11-25 16:10:05 +01003289 /* First, update gpc0_rate if it's tracked. Second, update its
3290 * gpc0 if tracked. Returns gpc0's value otherwise the curr_ctr.
3291 */
3292 ptr1 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0_RATE);
Emeric Brun726783d2021-06-30 19:06:43 +02003293 if (ptr1) {
3294 period = stkctr->table->data_arg[STKTABLE_DT_GPC0_RATE].u;
3295 }
3296 else {
3297 /* fallback on the gpc array */
3298 ptr1 = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC_RATE, 0);
3299 if (ptr1)
3300 period = stkctr->table->data_arg[STKTABLE_DT_GPC_RATE].u;
3301 }
3302
Willy Tarreau7d562212016-11-25 16:10:05 +01003303 ptr2 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0);
Emeric Brun726783d2021-06-30 19:06:43 +02003304 if (!ptr2) {
3305 /* fallback on the gpc array */
3306 ptr2 = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC, 0);
3307 }
3308
Emeric Brun819fc6f2017-06-13 19:37:32 +02003309 if (ptr1 || ptr2) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003310 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Willy Tarreau7d562212016-11-25 16:10:05 +01003311
Emeric Brun819fc6f2017-06-13 19:37:32 +02003312 if (ptr1) {
Emeric Brun0e3457b2021-06-30 17:18:28 +02003313 update_freq_ctr_period(&stktable_data_cast(ptr1, std_t_frqp),
Emeric Brun726783d2021-06-30 19:06:43 +02003314 period, 1);
Emeric Brun0e3457b2021-06-30 17:18:28 +02003315 smp->data.u.sint = (&stktable_data_cast(ptr1, std_t_frqp))->curr_ctr;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003316 }
3317
3318 if (ptr2)
Emeric Brun0e3457b2021-06-30 17:18:28 +02003319 smp->data.u.sint = ++stktable_data_cast(ptr2, std_t_uint);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003320
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003321 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003322
3323 /* If data was modified, we need to touch to re-schedule sync */
3324 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
3325 }
3326 else if (stkctr == &tmpstkctr)
3327 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003328 }
3329 return 1;
3330}
3331
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003332/* Increment the General Purpose Counter 1 value from the stream's tracked
3333 * frontend counters and return it into temp integer.
3334 * Supports being called as "sc[0-9]_inc_gpc1" or "src_inc_gpc1" only.
3335 */
3336static int
3337smp_fetch_sc_inc_gpc1(const struct arg *args, struct sample *smp, const char *kw, void *private)
3338{
3339 struct stkctr tmpstkctr;
3340 struct stkctr *stkctr;
Willy Tarreau5b654ad2021-07-06 18:51:12 +02003341 unsigned int period = 0;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003342
3343 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
3344 if (!stkctr)
3345 return 0;
3346
3347 smp->flags = SMP_F_VOL_TEST;
3348 smp->data.type = SMP_T_SINT;
3349 smp->data.u.sint = 0;
3350
3351 if (!stkctr_entry(stkctr))
3352 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
3353
3354 if (stkctr && stkctr_entry(stkctr)) {
3355 void *ptr1,*ptr2;
3356
3357
3358 /* First, update gpc1_rate if it's tracked. Second, update its
3359 * gpc1 if tracked. Returns gpc1's value otherwise the curr_ctr.
3360 */
3361 ptr1 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1_RATE);
Emeric Brun726783d2021-06-30 19:06:43 +02003362 if (ptr1) {
3363 period = stkctr->table->data_arg[STKTABLE_DT_GPC1_RATE].u;
3364 }
3365 else {
3366 /* fallback on the gpc array */
3367 ptr1 = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC_RATE, 1);
3368 if (ptr1)
3369 period = stkctr->table->data_arg[STKTABLE_DT_GPC_RATE].u;
3370 }
3371
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003372 ptr2 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1);
Emeric Brun726783d2021-06-30 19:06:43 +02003373 if (!ptr2) {
3374 /* fallback on the gpc array */
3375 ptr2 = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC, 1);
3376 }
3377
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003378 if (ptr1 || ptr2) {
3379 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3380
3381 if (ptr1) {
Emeric Brun0e3457b2021-06-30 17:18:28 +02003382 update_freq_ctr_period(&stktable_data_cast(ptr1, std_t_frqp),
Emeric Brun726783d2021-06-30 19:06:43 +02003383 period, 1);
Emeric Brun0e3457b2021-06-30 17:18:28 +02003384 smp->data.u.sint = (&stktable_data_cast(ptr1, std_t_frqp))->curr_ctr;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003385 }
3386
3387 if (ptr2)
Emeric Brun0e3457b2021-06-30 17:18:28 +02003388 smp->data.u.sint = ++stktable_data_cast(ptr2, std_t_uint);
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003389
3390 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3391
3392 /* If data was modified, we need to touch to re-schedule sync */
3393 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
3394 }
3395 else if (stkctr == &tmpstkctr)
3396 stktable_release(stkctr->table, stkctr_entry(stkctr));
3397 }
3398 return 1;
3399}
3400
Emeric Brun4d7ada82021-06-30 19:04:16 +02003401/* Clear the GPC[args(0)] value from the stream's tracked
3402 * frontend counters and return its previous value into temp integer.
3403 * Supports being called as "sc_clr_gpc(<gpc-idx>,<sc-idx>[,<table>])"
3404 * or "src_clr_gpc(<gpc-idx>[,<table>])" only.
3405 */
3406static int
3407smp_fetch_sc_clr_gpc(const struct arg *args, struct sample *smp, const char *kw, void *private)
3408{
3409 struct stkctr tmpstkctr;
3410 struct stkctr *stkctr;
3411 unsigned int idx;
3412
3413 idx = args[0].data.sint;
3414
3415 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args + 1, kw, &tmpstkctr);
3416 if (!stkctr)
3417 return 0;
3418
3419 smp->flags = SMP_F_VOL_TEST;
3420 smp->data.type = SMP_T_SINT;
3421 smp->data.u.sint = 0;
3422
3423 if (!stkctr_entry(stkctr))
3424 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
3425
3426 if (stkctr && stkctr_entry(stkctr)) {
3427 void *ptr;
3428
3429 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC, idx);
3430 if (!ptr) {
3431 if (stkctr == &tmpstkctr)
3432 stktable_release(stkctr->table, stkctr_entry(stkctr));
3433 return 0; /* parameter not stored */
3434 }
3435
3436 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3437
3438 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
3439 stktable_data_cast(ptr, std_t_uint) = 0;
3440
3441 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3442
3443 /* If data was modified, we need to touch to re-schedule sync */
3444 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
3445 }
3446 return 1;
3447}
3448
Willy Tarreau7d562212016-11-25 16:10:05 +01003449/* Clear the General Purpose Counter 0 value from the stream's tracked
3450 * frontend counters and return its previous value into temp integer.
3451 * Supports being called as "sc[0-9]_clr_gpc0" or "src_clr_gpc0" only.
3452 */
3453static int
3454smp_fetch_sc_clr_gpc0(const struct arg *args, struct sample *smp, const char *kw, void *private)
3455{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003456 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003457 struct stkctr *stkctr;
3458
Emeric Brun819fc6f2017-06-13 19:37:32 +02003459 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003460 if (!stkctr)
3461 return 0;
3462
3463 smp->flags = SMP_F_VOL_TEST;
3464 smp->data.type = SMP_T_SINT;
3465 smp->data.u.sint = 0;
3466
Emeric Brun819fc6f2017-06-13 19:37:32 +02003467 if (!stkctr_entry(stkctr))
3468 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003469
Emeric Brun819fc6f2017-06-13 19:37:32 +02003470 if (stkctr && stkctr_entry(stkctr)) {
3471 void *ptr;
3472
3473 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0);
3474 if (!ptr) {
Emeric Brun726783d2021-06-30 19:06:43 +02003475 /* fallback on the gpc array */
3476 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC, 0);
3477 }
3478
3479 if (!ptr) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003480 if (stkctr == &tmpstkctr)
3481 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003482 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003483 }
3484
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003485 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003486
Emeric Brun0e3457b2021-06-30 17:18:28 +02003487 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
3488 stktable_data_cast(ptr, std_t_uint) = 0;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003489
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003490 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003491
Willy Tarreau7d562212016-11-25 16:10:05 +01003492 /* If data was modified, we need to touch to re-schedule sync */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003493 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
Willy Tarreau7d562212016-11-25 16:10:05 +01003494 }
3495 return 1;
3496}
3497
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003498/* Clear the General Purpose Counter 1 value from the stream's tracked
3499 * frontend counters and return its previous value into temp integer.
3500 * Supports being called as "sc[0-9]_clr_gpc1" or "src_clr_gpc1" only.
3501 */
3502static int
3503smp_fetch_sc_clr_gpc1(const struct arg *args, struct sample *smp, const char *kw, void *private)
3504{
3505 struct stkctr tmpstkctr;
3506 struct stkctr *stkctr;
3507
3508 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
3509 if (!stkctr)
3510 return 0;
3511
3512 smp->flags = SMP_F_VOL_TEST;
3513 smp->data.type = SMP_T_SINT;
3514 smp->data.u.sint = 0;
3515
3516 if (!stkctr_entry(stkctr))
3517 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
3518
3519 if (stkctr && stkctr_entry(stkctr)) {
3520 void *ptr;
3521
3522 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1);
3523 if (!ptr) {
Emeric Brun726783d2021-06-30 19:06:43 +02003524 /* fallback on the gpc array */
3525 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC, 1);
3526 }
3527
3528 if (!ptr) {
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003529 if (stkctr == &tmpstkctr)
3530 stktable_release(stkctr->table, stkctr_entry(stkctr));
3531 return 0; /* parameter not stored */
3532 }
3533
3534 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3535
Emeric Brun0e3457b2021-06-30 17:18:28 +02003536 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
3537 stktable_data_cast(ptr, std_t_uint) = 0;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003538
3539 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3540
3541 /* If data was modified, we need to touch to re-schedule sync */
3542 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
3543 }
3544 return 1;
3545}
3546
Willy Tarreau7d562212016-11-25 16:10:05 +01003547/* set <smp> to the cumulated number of connections from the stream's tracked
3548 * frontend counters. Supports being called as "sc[0-9]_conn_cnt" or
3549 * "src_conn_cnt" only.
3550 */
3551static int
3552smp_fetch_sc_conn_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
3553{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003554 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003555 struct stkctr *stkctr;
3556
Emeric Brun819fc6f2017-06-13 19:37:32 +02003557 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003558 if (!stkctr)
3559 return 0;
3560
3561 smp->flags = SMP_F_VOL_TEST;
3562 smp->data.type = SMP_T_SINT;
3563 smp->data.u.sint = 0;
3564 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003565 void *ptr;
3566
3567 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_CONN_CNT);
3568 if (!ptr) {
3569 if (stkctr == &tmpstkctr)
3570 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003571 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003572 }
3573
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003574 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003575
Emeric Brun0e3457b2021-06-30 17:18:28 +02003576 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003577
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003578 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003579
3580 if (stkctr == &tmpstkctr)
3581 stktable_release(stkctr->table, stkctr_entry(stkctr));
3582
3583
Willy Tarreau7d562212016-11-25 16:10:05 +01003584 }
3585 return 1;
3586}
3587
3588/* set <smp> to the connection rate from the stream's tracked frontend
3589 * counters. Supports being called as "sc[0-9]_conn_rate" or "src_conn_rate"
3590 * only.
3591 */
3592static int
3593smp_fetch_sc_conn_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3594{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003595 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003596 struct stkctr *stkctr;
3597
Emeric Brun819fc6f2017-06-13 19:37:32 +02003598 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003599 if (!stkctr)
3600 return 0;
3601
3602 smp->flags = SMP_F_VOL_TEST;
3603 smp->data.type = SMP_T_SINT;
3604 smp->data.u.sint = 0;
3605 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003606 void *ptr;
3607
3608 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_CONN_RATE);
3609 if (!ptr) {
3610 if (stkctr == &tmpstkctr)
3611 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003612 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003613 }
3614
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003615 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003616
Emeric Brun0e3457b2021-06-30 17:18:28 +02003617 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Willy Tarreau7d562212016-11-25 16:10:05 +01003618 stkctr->table->data_arg[STKTABLE_DT_CONN_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003619
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003620 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003621
3622 if (stkctr == &tmpstkctr)
3623 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003624 }
3625 return 1;
3626}
3627
3628/* set temp integer to the number of connections from the stream's source address
3629 * in the table pointed to by expr, after updating it.
3630 * Accepts exactly 1 argument of type table.
3631 */
3632static int
3633smp_fetch_src_updt_conn_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
3634{
3635 struct connection *conn = objt_conn(smp->sess->origin);
3636 struct stksess *ts;
3637 struct stktable_key *key;
3638 void *ptr;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003639 struct stktable *t;
Willy Tarreau7d562212016-11-25 16:10:05 +01003640
3641 if (!conn)
3642 return 0;
3643
Joseph Herlant5662fa42018-11-15 13:43:28 -08003644 /* Fetch source address in a sample. */
Amaury Denoyellec460c702021-05-12 10:17:47 +02003645 if (!smp_fetch_src || !smp_fetch_src(empty_arg_list, smp, "src", NULL))
Willy Tarreau7d562212016-11-25 16:10:05 +01003646 return 0;
3647
3648 /* Converts into key. */
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003649 key = smp_to_stkey(smp, args->data.t);
Willy Tarreau7d562212016-11-25 16:10:05 +01003650 if (!key)
3651 return 0;
3652
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003653 t = args->data.t;
Willy Tarreau7d562212016-11-25 16:10:05 +01003654
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003655 if ((ts = stktable_get_entry(t, key)) == NULL)
Willy Tarreau7d562212016-11-25 16:10:05 +01003656 /* entry does not exist and could not be created */
3657 return 0;
3658
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003659 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_CONN_CNT);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003660 if (!ptr) {
Willy Tarreau7d562212016-11-25 16:10:05 +01003661 return 0; /* parameter not stored in this table */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003662 }
Willy Tarreau7d562212016-11-25 16:10:05 +01003663
3664 smp->data.type = SMP_T_SINT;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003665
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003666 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003667
Emeric Brun0e3457b2021-06-30 17:18:28 +02003668 smp->data.u.sint = ++stktable_data_cast(ptr, std_t_uint);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003669
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003670 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003671
Willy Tarreau7d562212016-11-25 16:10:05 +01003672 smp->flags = SMP_F_VOL_TEST;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003673
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003674 stktable_touch_local(t, ts, 1);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003675
3676 /* Touch was previously performed by stktable_update_key */
Willy Tarreau7d562212016-11-25 16:10:05 +01003677 return 1;
3678}
3679
3680/* set <smp> to the number of concurrent connections from the stream's tracked
3681 * frontend counters. Supports being called as "sc[0-9]_conn_cur" or
3682 * "src_conn_cur" only.
3683 */
3684static int
3685smp_fetch_sc_conn_cur(const struct arg *args, struct sample *smp, const char *kw, void *private)
3686{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003687 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003688 struct stkctr *stkctr;
3689
Emeric Brun819fc6f2017-06-13 19:37:32 +02003690 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003691 if (!stkctr)
3692 return 0;
3693
3694 smp->flags = SMP_F_VOL_TEST;
3695 smp->data.type = SMP_T_SINT;
3696 smp->data.u.sint = 0;
3697 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003698 void *ptr;
3699
3700 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_CONN_CUR);
3701 if (!ptr) {
3702 if (stkctr == &tmpstkctr)
3703 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003704 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003705 }
3706
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003707 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003708
Emeric Brun0e3457b2021-06-30 17:18:28 +02003709 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003710
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003711 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003712
3713 if (stkctr == &tmpstkctr)
3714 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003715 }
3716 return 1;
3717}
3718
3719/* set <smp> to the cumulated number of streams from the stream's tracked
3720 * frontend counters. Supports being called as "sc[0-9]_sess_cnt" or
3721 * "src_sess_cnt" only.
3722 */
3723static int
3724smp_fetch_sc_sess_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
3725{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003726 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003727 struct stkctr *stkctr;
3728
Emeric Brun819fc6f2017-06-13 19:37:32 +02003729 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003730 if (!stkctr)
3731 return 0;
3732
3733 smp->flags = SMP_F_VOL_TEST;
3734 smp->data.type = SMP_T_SINT;
3735 smp->data.u.sint = 0;
3736 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003737 void *ptr;
3738
3739 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_SESS_CNT);
3740 if (!ptr) {
3741 if (stkctr == &tmpstkctr)
3742 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003743 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003744 }
3745
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003746 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003747
Emeric Brun0e3457b2021-06-30 17:18:28 +02003748 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003749
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003750 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003751
3752 if (stkctr == &tmpstkctr)
3753 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003754 }
3755 return 1;
3756}
3757
3758/* set <smp> to the stream rate from the stream's tracked frontend counters.
3759 * Supports being called as "sc[0-9]_sess_rate" or "src_sess_rate" only.
3760 */
3761static int
3762smp_fetch_sc_sess_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3763{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003764 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003765 struct stkctr *stkctr;
3766
Emeric Brun819fc6f2017-06-13 19:37:32 +02003767 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003768 if (!stkctr)
3769 return 0;
3770
3771 smp->flags = SMP_F_VOL_TEST;
3772 smp->data.type = SMP_T_SINT;
3773 smp->data.u.sint = 0;
3774 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003775 void *ptr;
3776
3777 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_SESS_RATE);
3778 if (!ptr) {
3779 if (stkctr == &tmpstkctr)
3780 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003781 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003782 }
3783
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003784 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003785
Emeric Brun0e3457b2021-06-30 17:18:28 +02003786 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Willy Tarreau7d562212016-11-25 16:10:05 +01003787 stkctr->table->data_arg[STKTABLE_DT_SESS_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003788
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003789 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003790
3791 if (stkctr == &tmpstkctr)
3792 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003793 }
3794 return 1;
3795}
3796
3797/* set <smp> to the cumulated number of HTTP requests from the stream's tracked
3798 * frontend counters. Supports being called as "sc[0-9]_http_req_cnt" or
3799 * "src_http_req_cnt" only.
3800 */
3801static int
3802smp_fetch_sc_http_req_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
3803{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003804 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003805 struct stkctr *stkctr;
3806
Emeric Brun819fc6f2017-06-13 19:37:32 +02003807 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003808 if (!stkctr)
3809 return 0;
3810
3811 smp->flags = SMP_F_VOL_TEST;
3812 smp->data.type = SMP_T_SINT;
3813 smp->data.u.sint = 0;
3814 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003815 void *ptr;
3816
3817 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_REQ_CNT);
3818 if (!ptr) {
3819 if (stkctr == &tmpstkctr)
3820 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003821 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003822 }
3823
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003824 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003825
Emeric Brun0e3457b2021-06-30 17:18:28 +02003826 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003827
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003828 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003829
3830 if (stkctr == &tmpstkctr)
3831 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003832 }
3833 return 1;
3834}
3835
3836/* set <smp> to the HTTP request rate from the stream's tracked frontend
3837 * counters. Supports being called as "sc[0-9]_http_req_rate" or
3838 * "src_http_req_rate" only.
3839 */
3840static int
3841smp_fetch_sc_http_req_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3842{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003843 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003844 struct stkctr *stkctr;
3845
Emeric Brun819fc6f2017-06-13 19:37:32 +02003846 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003847 if (!stkctr)
3848 return 0;
3849
3850 smp->flags = SMP_F_VOL_TEST;
3851 smp->data.type = SMP_T_SINT;
3852 smp->data.u.sint = 0;
3853 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003854 void *ptr;
3855
3856 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_REQ_RATE);
3857 if (!ptr) {
3858 if (stkctr == &tmpstkctr)
3859 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003860 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003861 }
3862
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003863 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003864
Emeric Brun0e3457b2021-06-30 17:18:28 +02003865 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Willy Tarreau7d562212016-11-25 16:10:05 +01003866 stkctr->table->data_arg[STKTABLE_DT_HTTP_REQ_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003867
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003868 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003869
3870 if (stkctr == &tmpstkctr)
3871 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003872 }
3873 return 1;
3874}
3875
3876/* set <smp> to the cumulated number of HTTP requests errors from the stream's
3877 * tracked frontend counters. Supports being called as "sc[0-9]_http_err_cnt" or
3878 * "src_http_err_cnt" only.
3879 */
3880static int
3881smp_fetch_sc_http_err_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
3882{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003883 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003884 struct stkctr *stkctr;
3885
Emeric Brun819fc6f2017-06-13 19:37:32 +02003886 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003887 if (!stkctr)
3888 return 0;
3889
3890 smp->flags = SMP_F_VOL_TEST;
3891 smp->data.type = SMP_T_SINT;
3892 smp->data.u.sint = 0;
3893 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003894 void *ptr;
3895
3896 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_ERR_CNT);
3897 if (!ptr) {
3898 if (stkctr == &tmpstkctr)
3899 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003900 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003901 }
3902
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003903 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003904
Emeric Brun0e3457b2021-06-30 17:18:28 +02003905 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003906
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003907 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003908
3909 if (stkctr == &tmpstkctr)
3910 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003911 }
3912 return 1;
3913}
3914
3915/* set <smp> to the HTTP request error rate from the stream's tracked frontend
3916 * counters. Supports being called as "sc[0-9]_http_err_rate" or
3917 * "src_http_err_rate" only.
3918 */
3919static int
3920smp_fetch_sc_http_err_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3921{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003922 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003923 struct stkctr *stkctr;
3924
Emeric Brun819fc6f2017-06-13 19:37:32 +02003925 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003926 if (!stkctr)
3927 return 0;
3928
3929 smp->flags = SMP_F_VOL_TEST;
3930 smp->data.type = SMP_T_SINT;
3931 smp->data.u.sint = 0;
3932 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003933 void *ptr;
3934
3935 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_ERR_RATE);
3936 if (!ptr) {
3937 if (stkctr == &tmpstkctr)
3938 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003939 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003940 }
3941
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003942 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003943
Emeric Brun0e3457b2021-06-30 17:18:28 +02003944 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Willy Tarreau7d562212016-11-25 16:10:05 +01003945 stkctr->table->data_arg[STKTABLE_DT_HTTP_ERR_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003946
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003947 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003948
3949 if (stkctr == &tmpstkctr)
3950 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003951 }
3952 return 1;
3953}
3954
Willy Tarreau826f3ab2021-02-10 12:07:15 +01003955/* set <smp> to the cumulated number of HTTP response failures from the stream's
3956 * tracked frontend counters. Supports being called as "sc[0-9]_http_fail_cnt" or
3957 * "src_http_fail_cnt" only.
3958 */
3959static int
3960smp_fetch_sc_http_fail_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
3961{
3962 struct stkctr tmpstkctr;
3963 struct stkctr *stkctr;
3964
3965 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
3966 if (!stkctr)
3967 return 0;
3968
3969 smp->flags = SMP_F_VOL_TEST;
3970 smp->data.type = SMP_T_SINT;
3971 smp->data.u.sint = 0;
3972 if (stkctr_entry(stkctr) != NULL) {
3973 void *ptr;
3974
3975 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_FAIL_CNT);
3976 if (!ptr) {
3977 if (stkctr == &tmpstkctr)
3978 stktable_release(stkctr->table, stkctr_entry(stkctr));
3979 return 0; /* parameter not stored */
3980 }
3981
3982 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3983
Emeric Brun0e3457b2021-06-30 17:18:28 +02003984 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Willy Tarreau826f3ab2021-02-10 12:07:15 +01003985
3986 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3987
3988 if (stkctr == &tmpstkctr)
3989 stktable_release(stkctr->table, stkctr_entry(stkctr));
3990 }
3991 return 1;
3992}
3993
3994/* set <smp> to the HTTP response failure rate from the stream's tracked frontend
3995 * counters. Supports being called as "sc[0-9]_http_fail_rate" or
3996 * "src_http_fail_rate" only.
3997 */
3998static int
3999smp_fetch_sc_http_fail_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
4000{
4001 struct stkctr tmpstkctr;
4002 struct stkctr *stkctr;
4003
4004 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
4005 if (!stkctr)
4006 return 0;
4007
4008 smp->flags = SMP_F_VOL_TEST;
4009 smp->data.type = SMP_T_SINT;
4010 smp->data.u.sint = 0;
4011 if (stkctr_entry(stkctr) != NULL) {
4012 void *ptr;
4013
4014 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_FAIL_RATE);
4015 if (!ptr) {
4016 if (stkctr == &tmpstkctr)
4017 stktable_release(stkctr->table, stkctr_entry(stkctr));
4018 return 0; /* parameter not stored */
4019 }
4020
4021 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
4022
Emeric Brun0e3457b2021-06-30 17:18:28 +02004023 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Willy Tarreau826f3ab2021-02-10 12:07:15 +01004024 stkctr->table->data_arg[STKTABLE_DT_HTTP_FAIL_RATE].u);
4025
4026 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
4027
4028 if (stkctr == &tmpstkctr)
4029 stktable_release(stkctr->table, stkctr_entry(stkctr));
4030 }
4031 return 1;
4032}
4033
Willy Tarreau7d562212016-11-25 16:10:05 +01004034/* set <smp> to the number of kbytes received from clients, as found in the
4035 * stream's tracked frontend counters. Supports being called as
4036 * "sc[0-9]_kbytes_in" or "src_kbytes_in" only.
4037 */
4038static int
4039smp_fetch_sc_kbytes_in(const struct arg *args, struct sample *smp, const char *kw, void *private)
4040{
Emeric Brun819fc6f2017-06-13 19:37:32 +02004041 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01004042 struct stkctr *stkctr;
4043
Emeric Brun819fc6f2017-06-13 19:37:32 +02004044 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01004045 if (!stkctr)
4046 return 0;
4047
4048 smp->flags = SMP_F_VOL_TEST;
4049 smp->data.type = SMP_T_SINT;
4050 smp->data.u.sint = 0;
4051 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02004052 void *ptr;
4053
4054 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_IN_CNT);
4055 if (!ptr) {
4056 if (stkctr == &tmpstkctr)
4057 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004058 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02004059 }
4060
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004061 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004062
Emeric Brun0e3457b2021-06-30 17:18:28 +02004063 smp->data.u.sint = stktable_data_cast(ptr, std_t_ull) >> 10;
Emeric Brun819fc6f2017-06-13 19:37:32 +02004064
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004065 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004066
4067 if (stkctr == &tmpstkctr)
4068 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004069 }
4070 return 1;
4071}
4072
4073/* set <smp> to the data rate received from clients in bytes/s, as found
4074 * in the stream's tracked frontend counters. Supports being called as
4075 * "sc[0-9]_bytes_in_rate" or "src_bytes_in_rate" only.
4076 */
4077static int
4078smp_fetch_sc_bytes_in_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
4079{
Emeric Brun819fc6f2017-06-13 19:37:32 +02004080 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01004081 struct stkctr *stkctr;
4082
Emeric Brun819fc6f2017-06-13 19:37:32 +02004083 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01004084 if (!stkctr)
4085 return 0;
4086
4087 smp->flags = SMP_F_VOL_TEST;
4088 smp->data.type = SMP_T_SINT;
4089 smp->data.u.sint = 0;
4090 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02004091 void *ptr;
4092
4093 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_IN_RATE);
4094 if (!ptr) {
4095 if (stkctr == &tmpstkctr)
4096 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004097 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02004098 }
4099
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004100 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004101
Emeric Brun0e3457b2021-06-30 17:18:28 +02004102 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Willy Tarreau7d562212016-11-25 16:10:05 +01004103 stkctr->table->data_arg[STKTABLE_DT_BYTES_IN_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004104
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004105 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004106
4107 if (stkctr == &tmpstkctr)
4108 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004109 }
4110 return 1;
4111}
4112
4113/* set <smp> to the number of kbytes sent to clients, as found in the
4114 * stream's tracked frontend counters. Supports being called as
4115 * "sc[0-9]_kbytes_out" or "src_kbytes_out" only.
4116 */
4117static int
4118smp_fetch_sc_kbytes_out(const struct arg *args, struct sample *smp, const char *kw, void *private)
4119{
Emeric Brun819fc6f2017-06-13 19:37:32 +02004120 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01004121 struct stkctr *stkctr;
4122
Emeric Brun819fc6f2017-06-13 19:37:32 +02004123 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01004124 if (!stkctr)
4125 return 0;
4126
4127 smp->flags = SMP_F_VOL_TEST;
4128 smp->data.type = SMP_T_SINT;
4129 smp->data.u.sint = 0;
4130 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02004131 void *ptr;
4132
4133 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_OUT_CNT);
4134 if (!ptr) {
4135 if (stkctr == &tmpstkctr)
4136 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004137 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02004138 }
4139
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004140 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004141
Emeric Brun0e3457b2021-06-30 17:18:28 +02004142 smp->data.u.sint = stktable_data_cast(ptr, std_t_ull) >> 10;
Emeric Brun819fc6f2017-06-13 19:37:32 +02004143
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004144 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004145
4146 if (stkctr == &tmpstkctr)
4147 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004148 }
4149 return 1;
4150}
4151
4152/* set <smp> to the data rate sent to clients in bytes/s, as found in the
4153 * stream's tracked frontend counters. Supports being called as
4154 * "sc[0-9]_bytes_out_rate" or "src_bytes_out_rate" only.
4155 */
4156static int
4157smp_fetch_sc_bytes_out_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
4158{
Emeric Brun819fc6f2017-06-13 19:37:32 +02004159 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01004160 struct stkctr *stkctr;
4161
Emeric Brun819fc6f2017-06-13 19:37:32 +02004162 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01004163 if (!stkctr)
4164 return 0;
4165
4166 smp->flags = SMP_F_VOL_TEST;
4167 smp->data.type = SMP_T_SINT;
4168 smp->data.u.sint = 0;
4169 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02004170 void *ptr;
4171
4172 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_OUT_RATE);
4173 if (!ptr) {
4174 if (stkctr == &tmpstkctr)
4175 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004176 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02004177 }
4178
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004179 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004180
Emeric Brun0e3457b2021-06-30 17:18:28 +02004181 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Willy Tarreau7d562212016-11-25 16:10:05 +01004182 stkctr->table->data_arg[STKTABLE_DT_BYTES_OUT_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004183
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004184 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004185
4186 if (stkctr == &tmpstkctr)
4187 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004188 }
4189 return 1;
4190}
4191
4192/* set <smp> to the number of active trackers on the SC entry in the stream's
4193 * tracked frontend counters. Supports being called as "sc[0-9]_trackers" only.
4194 */
4195static int
4196smp_fetch_sc_trackers(const struct arg *args, struct sample *smp, const char *kw, void *private)
4197{
Emeric Brun819fc6f2017-06-13 19:37:32 +02004198 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01004199 struct stkctr *stkctr;
4200
Emeric Brun819fc6f2017-06-13 19:37:32 +02004201 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01004202 if (!stkctr)
4203 return 0;
4204
4205 smp->flags = SMP_F_VOL_TEST;
4206 smp->data.type = SMP_T_SINT;
Emeric Brun819fc6f2017-06-13 19:37:32 +02004207 if (stkctr == &tmpstkctr) {
4208 smp->data.u.sint = stkctr_entry(stkctr) ? (stkctr_entry(stkctr)->ref_cnt-1) : 0;
4209 stktable_release(stkctr->table, stkctr_entry(stkctr));
4210 }
4211 else {
4212 smp->data.u.sint = stkctr_entry(stkctr) ? stkctr_entry(stkctr)->ref_cnt : 0;
4213 }
4214
Willy Tarreau7d562212016-11-25 16:10:05 +01004215 return 1;
4216}
4217
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004218
4219/* The functions below are used to manipulate table contents from the CLI.
4220 * There are 3 main actions, "clear", "set" and "show". The code is shared
4221 * between all actions, and the action is encoded in the void *private in
4222 * the appctx as well as in the keyword registration, among one of the
4223 * following values.
4224 */
4225
4226enum {
4227 STK_CLI_ACT_CLR,
4228 STK_CLI_ACT_SET,
4229 STK_CLI_ACT_SHOW,
4230};
4231
4232/* Dump the status of a table to a stream interface's
4233 * read buffer. It returns 0 if the output buffer is full
4234 * and needs to be called again, otherwise non-zero.
4235 */
Willy Tarreau83061a82018-07-13 11:56:34 +02004236static int table_dump_head_to_buffer(struct buffer *msg,
4237 struct stream_interface *si,
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004238 struct stktable *t, struct stktable *target)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004239{
4240 struct stream *s = si_strm(si);
4241
4242 chunk_appendf(msg, "# table: %s, type: %s, size:%d, used:%d\n",
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004243 t->id, stktable_types[t->type].kw, t->size, t->current);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004244
4245 /* any other information should be dumped here */
4246
William Lallemand07a62f72017-05-24 00:57:40 +02004247 if (target && (strm_li(s)->bind_conf->level & ACCESS_LVL_MASK) < ACCESS_LVL_OPER)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004248 chunk_appendf(msg, "# contents not dumped due to insufficient privileges\n");
4249
Willy Tarreau06d80a92017-10-19 14:32:15 +02004250 if (ci_putchk(si_ic(si), msg) == -1) {
Willy Tarreaudb398432018-11-15 11:08:52 +01004251 si_rx_room_blk(si);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004252 return 0;
4253 }
4254
4255 return 1;
4256}
4257
4258/* Dump a table entry to a stream interface's
4259 * read buffer. It returns 0 if the output buffer is full
4260 * and needs to be called again, otherwise non-zero.
4261 */
Willy Tarreau83061a82018-07-13 11:56:34 +02004262static int table_dump_entry_to_buffer(struct buffer *msg,
4263 struct stream_interface *si,
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004264 struct stktable *t, struct stksess *entry)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004265{
4266 int dt;
4267
4268 chunk_appendf(msg, "%p:", entry);
4269
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004270 if (t->type == SMP_T_IPV4) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004271 char addr[INET_ADDRSTRLEN];
4272 inet_ntop(AF_INET, (const void *)&entry->key.key, addr, sizeof(addr));
4273 chunk_appendf(msg, " key=%s", addr);
4274 }
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004275 else if (t->type == SMP_T_IPV6) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004276 char addr[INET6_ADDRSTRLEN];
4277 inet_ntop(AF_INET6, (const void *)&entry->key.key, addr, sizeof(addr));
4278 chunk_appendf(msg, " key=%s", addr);
4279 }
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004280 else if (t->type == SMP_T_SINT) {
Willy Tarreau6cde5d82020-02-25 09:41:22 +01004281 chunk_appendf(msg, " key=%u", read_u32(entry->key.key));
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004282 }
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004283 else if (t->type == SMP_T_STR) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004284 chunk_appendf(msg, " key=");
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004285 dump_text(msg, (const char *)entry->key.key, t->key_size);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004286 }
4287 else {
4288 chunk_appendf(msg, " key=");
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004289 dump_binary(msg, (const char *)entry->key.key, t->key_size);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004290 }
4291
4292 chunk_appendf(msg, " use=%d exp=%d", entry->ref_cnt - 1, tick_remain(now_ms, entry->expire));
4293
4294 for (dt = 0; dt < STKTABLE_DATA_TYPES; dt++) {
4295 void *ptr;
4296
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004297 if (t->data_ofs[dt] == 0)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004298 continue;
Emeric Brunc64a2a32021-06-30 18:01:02 +02004299 if (stktable_data_types[dt].is_array) {
4300 char tmp[16] = {};
4301 const char *name_pfx = stktable_data_types[dt].name;
4302 const char *name_sfx = NULL;
4303 unsigned int idx = 0;
4304 int i = 0;
4305
4306 /* split name to show index before first _ of the name
4307 * for example: 'gpc3_rate' if array name is 'gpc_rate'.
4308 */
4309 for (i = 0 ; i < (sizeof(tmp) - 1); i++) {
4310 if (!name_pfx[i])
4311 break;
4312 if (name_pfx[i] == '_') {
4313 name_pfx = &tmp[0];
4314 name_sfx = &stktable_data_types[dt].name[i];
4315 break;
4316 }
4317 tmp[i] = name_pfx[i];
4318 }
4319
4320 ptr = stktable_data_ptr_idx(t, entry, dt, idx);
4321 while (ptr) {
4322 if (stktable_data_types[dt].arg_type == ARG_T_DELAY)
4323 chunk_appendf(msg, " %s%u%s(%u)=", name_pfx, idx, name_sfx ? name_sfx : "", t->data_arg[dt].u);
4324 else
4325 chunk_appendf(msg, " %s%u%s=", name_pfx, idx, name_sfx ? name_sfx : "");
4326 switch (stktable_data_types[dt].std_type) {
4327 case STD_T_SINT:
4328 chunk_appendf(msg, "%d", stktable_data_cast(ptr, std_t_sint));
4329 break;
4330 case STD_T_UINT:
4331 chunk_appendf(msg, "%u", stktable_data_cast(ptr, std_t_uint));
4332 break;
4333 case STD_T_ULL:
4334 chunk_appendf(msg, "%llu", stktable_data_cast(ptr, std_t_ull));
4335 break;
4336 case STD_T_FRQP:
4337 chunk_appendf(msg, "%u",
4338 read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
4339 t->data_arg[dt].u));
4340 break;
4341 }
4342 ptr = stktable_data_ptr_idx(t, entry, dt, ++idx);
4343 }
4344 continue;
4345 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004346 if (stktable_data_types[dt].arg_type == ARG_T_DELAY)
Emeric Brun01928ae2021-06-30 16:24:04 +02004347 chunk_appendf(msg, " %s(%u)=", stktable_data_types[dt].name, t->data_arg[dt].u);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004348 else
4349 chunk_appendf(msg, " %s=", stktable_data_types[dt].name);
4350
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004351 ptr = stktable_data_ptr(t, entry, dt);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004352 switch (stktable_data_types[dt].std_type) {
4353 case STD_T_SINT:
4354 chunk_appendf(msg, "%d", stktable_data_cast(ptr, std_t_sint));
4355 break;
4356 case STD_T_UINT:
4357 chunk_appendf(msg, "%u", stktable_data_cast(ptr, std_t_uint));
4358 break;
4359 case STD_T_ULL:
Emeric Brun01928ae2021-06-30 16:24:04 +02004360 chunk_appendf(msg, "%llu", stktable_data_cast(ptr, std_t_ull));
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004361 break;
4362 case STD_T_FRQP:
Emeric Brun01928ae2021-06-30 16:24:04 +02004363 chunk_appendf(msg, "%u",
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004364 read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004365 t->data_arg[dt].u));
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004366 break;
Frédéric Lécaille16b4f542019-05-23 12:15:04 +02004367 case STD_T_DICT: {
4368 struct dict_entry *de;
4369 de = stktable_data_cast(ptr, std_t_dict);
4370 chunk_appendf(msg, "%s", de ? (char *)de->value.key : "-");
4371 break;
4372 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004373 }
4374 }
4375 chunk_appendf(msg, "\n");
4376
Willy Tarreau06d80a92017-10-19 14:32:15 +02004377 if (ci_putchk(si_ic(si), msg) == -1) {
Willy Tarreaudb398432018-11-15 11:08:52 +01004378 si_rx_room_blk(si);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004379 return 0;
4380 }
4381
4382 return 1;
4383}
4384
4385
4386/* Processes a single table entry matching a specific key passed in argument.
4387 * returns 0 if wants to be called again, 1 if has ended processing.
4388 */
4389static int table_process_entry_per_key(struct appctx *appctx, char **args)
4390{
4391 struct stream_interface *si = appctx->owner;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004392 struct stktable *t = appctx->ctx.table.target;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004393 struct stksess *ts;
4394 uint32_t uint32_key;
4395 unsigned char ip6_key[sizeof(struct in6_addr)];
4396 long long value;
4397 int data_type;
4398 int cur_arg;
4399 void *ptr;
Willy Tarreaufa1258f2021-04-10 23:00:53 +02004400 struct freq_ctr *frqp;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004401
Willy Tarreau9d008692019-08-09 11:21:01 +02004402 if (!*args[4])
4403 return cli_err(appctx, "Key value expected\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004404
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004405 switch (t->type) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004406 case SMP_T_IPV4:
4407 uint32_key = htonl(inetaddr_host(args[4]));
Christopher Fauletca20d022017-08-29 15:30:31 +02004408 static_table_key.key = &uint32_key;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004409 break;
4410 case SMP_T_IPV6:
4411 inet_pton(AF_INET6, args[4], ip6_key);
Christopher Fauletca20d022017-08-29 15:30:31 +02004412 static_table_key.key = &ip6_key;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004413 break;
4414 case SMP_T_SINT:
4415 {
4416 char *endptr;
4417 unsigned long val;
4418 errno = 0;
4419 val = strtoul(args[4], &endptr, 10);
4420 if ((errno == ERANGE && val == ULONG_MAX) ||
4421 (errno != 0 && val == 0) || endptr == args[4] ||
Willy Tarreau9d008692019-08-09 11:21:01 +02004422 val > 0xffffffff)
4423 return cli_err(appctx, "Invalid key\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004424 uint32_key = (uint32_t) val;
Christopher Fauletca20d022017-08-29 15:30:31 +02004425 static_table_key.key = &uint32_key;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004426 break;
4427 }
4428 break;
4429 case SMP_T_STR:
Christopher Fauletca20d022017-08-29 15:30:31 +02004430 static_table_key.key = args[4];
4431 static_table_key.key_len = strlen(args[4]);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004432 break;
4433 default:
Willy Tarreaua24bc782016-12-14 15:50:35 +01004434 switch (appctx->ctx.table.action) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004435 case STK_CLI_ACT_SHOW:
Willy Tarreau9d008692019-08-09 11:21:01 +02004436 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 +01004437 case STK_CLI_ACT_CLR:
Willy Tarreau9d008692019-08-09 11:21:01 +02004438 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 +01004439 case STK_CLI_ACT_SET:
Willy Tarreau9d008692019-08-09 11:21:01 +02004440 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 +01004441 default:
Willy Tarreau9d008692019-08-09 11:21:01 +02004442 return cli_err(appctx, "Unknown action\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004443 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004444 }
4445
4446 /* check permissions */
4447 if (!cli_has_level(appctx, ACCESS_LVL_OPER))
4448 return 1;
4449
Willy Tarreaua24bc782016-12-14 15:50:35 +01004450 switch (appctx->ctx.table.action) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004451 case STK_CLI_ACT_SHOW:
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004452 ts = stktable_lookup_key(t, &static_table_key);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004453 if (!ts)
4454 return 1;
4455 chunk_reset(&trash);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004456 if (!table_dump_head_to_buffer(&trash, si, t, t)) {
4457 stktable_release(t, ts);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004458 return 0;
Emeric Brun819fc6f2017-06-13 19:37:32 +02004459 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004460 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004461 if (!table_dump_entry_to_buffer(&trash, si, t, ts)) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004462 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004463 stktable_release(t, ts);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004464 return 0;
Emeric Brun819fc6f2017-06-13 19:37:32 +02004465 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004466 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004467 stktable_release(t, ts);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004468 break;
4469
4470 case STK_CLI_ACT_CLR:
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004471 ts = stktable_lookup_key(t, &static_table_key);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004472 if (!ts)
4473 return 1;
Emeric Brun819fc6f2017-06-13 19:37:32 +02004474
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004475 if (!stksess_kill(t, ts, 1)) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004476 /* don't delete an entry which is currently referenced */
Willy Tarreau9d008692019-08-09 11:21:01 +02004477 return cli_err(appctx, "Entry currently in use, cannot remove\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004478 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004479 break;
4480
4481 case STK_CLI_ACT_SET:
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004482 ts = stktable_get_entry(t, &static_table_key);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004483 if (!ts) {
4484 /* don't delete an entry which is currently referenced */
Willy Tarreau9d008692019-08-09 11:21:01 +02004485 return cli_err(appctx, "Unable to allocate a new entry\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004486 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004487 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004488 for (cur_arg = 5; *args[cur_arg]; cur_arg += 2) {
4489 if (strncmp(args[cur_arg], "data.", 5) != 0) {
Willy Tarreau9d008692019-08-09 11:21:01 +02004490 cli_err(appctx, "\"data.<type>\" followed by a value expected\n");
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004491 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004492 stktable_touch_local(t, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004493 return 1;
4494 }
4495
4496 data_type = stktable_get_data_type(args[cur_arg] + 5);
4497 if (data_type < 0) {
Willy Tarreau9d008692019-08-09 11:21:01 +02004498 cli_err(appctx, "Unknown data type\n");
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004499 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004500 stktable_touch_local(t, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004501 return 1;
4502 }
4503
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004504 if (!t->data_ofs[data_type]) {
Willy Tarreau9d008692019-08-09 11:21:01 +02004505 cli_err(appctx, "Data type not stored in this table\n");
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004506 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004507 stktable_touch_local(t, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004508 return 1;
4509 }
4510
4511 if (!*args[cur_arg+1] || strl2llrc(args[cur_arg+1], strlen(args[cur_arg+1]), &value) != 0) {
Willy Tarreau9d008692019-08-09 11:21:01 +02004512 cli_err(appctx, "Require a valid integer value to store\n");
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004513 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004514 stktable_touch_local(t, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004515 return 1;
4516 }
4517
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004518 ptr = stktable_data_ptr(t, ts, data_type);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004519
4520 switch (stktable_data_types[data_type].std_type) {
4521 case STD_T_SINT:
4522 stktable_data_cast(ptr, std_t_sint) = value;
4523 break;
4524 case STD_T_UINT:
4525 stktable_data_cast(ptr, std_t_uint) = value;
4526 break;
4527 case STD_T_ULL:
4528 stktable_data_cast(ptr, std_t_ull) = value;
4529 break;
4530 case STD_T_FRQP:
4531 /* We set both the current and previous values. That way
4532 * the reported frequency is stable during all the period
4533 * then slowly fades out. This allows external tools to
4534 * push measures without having to update them too often.
4535 */
4536 frqp = &stktable_data_cast(ptr, std_t_frqp);
Willy Tarreaufa1258f2021-04-10 23:00:53 +02004537 /* First bit is reserved for the freq_ctr lock
Emeric Brunf2fc1fd2017-11-02 17:32:43 +01004538 Note: here we're still protected by the stksess lock
Willy Tarreaufa1258f2021-04-10 23:00:53 +02004539 so we don't need to update the update the freq_ctr
Emeric Brunf2fc1fd2017-11-02 17:32:43 +01004540 using its internal lock */
4541 frqp->curr_tick = now_ms & ~0x1;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004542 frqp->prev_ctr = 0;
4543 frqp->curr_ctr = value;
4544 break;
4545 }
4546 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004547 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004548 stktable_touch_local(t, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004549 break;
4550
4551 default:
Willy Tarreau9d008692019-08-09 11:21:01 +02004552 return cli_err(appctx, "Unknown action\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004553 }
4554 return 1;
4555}
4556
4557/* Prepares the appctx fields with the data-based filters from the command line.
4558 * Returns 0 if the dump can proceed, 1 if has ended processing.
4559 */
4560static int table_prepare_data_request(struct appctx *appctx, char **args)
4561{
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004562 int i;
Adis Nezirovicd0142e72020-01-22 16:50:27 +01004563 char *err = NULL;
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004564
Willy Tarreau9d008692019-08-09 11:21:01 +02004565 if (appctx->ctx.table.action != STK_CLI_ACT_SHOW && appctx->ctx.table.action != STK_CLI_ACT_CLR)
4566 return cli_err(appctx, "content-based lookup is only supported with the \"show\" and \"clear\" actions\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004567
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004568 for (i = 0; i < STKTABLE_FILTER_LEN; i++) {
4569 if (i > 0 && !*args[3+3*i]) // number of filter entries can be less than STKTABLE_FILTER_LEN
4570 break;
4571 /* condition on stored data value */
4572 appctx->ctx.table.data_type[i] = stktable_get_data_type(args[3+3*i] + 5);
4573 if (appctx->ctx.table.data_type[i] < 0)
Adis Nezirovicd0142e72020-01-22 16:50:27 +01004574 return cli_dynerr(appctx, memprintf(&err, "Filter entry #%i: Unknown data type\n", i + 1));
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004575
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004576 if (!((struct stktable *)appctx->ctx.table.target)->data_ofs[appctx->ctx.table.data_type[i]])
Adis Nezirovicd0142e72020-01-22 16:50:27 +01004577 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 +01004578
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004579 appctx->ctx.table.data_op[i] = get_std_op(args[4+3*i]);
Willy Tarreau2b64a352020-01-22 17:09:47 +01004580 if (appctx->ctx.table.data_op[i] < 0)
Adis Nezirovicd0142e72020-01-22 16:50:27 +01004581 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 +01004582
Adis Nezirovic56dd3542020-01-22 16:16:48 +01004583 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 +01004584 return cli_dynerr(appctx, memprintf(&err, "Filter entry #%i: Require a valid integer value to compare against\n", i + 1));
4585 }
4586
4587 if (*args[3+3*i]) {
4588 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 +01004589 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004590
4591 /* OK we're done, all the fields are set */
4592 return 0;
4593}
4594
4595/* returns 0 if wants to be called, 1 if has ended processing */
Aurélien Nephtaliabbf6072018-04-18 13:26:46 +02004596static int cli_parse_table_req(char **args, char *payload, struct appctx *appctx, void *private)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004597{
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004598 int i;
4599
4600 for (i = 0; i < STKTABLE_FILTER_LEN; i++)
4601 appctx->ctx.table.data_type[i] = -1;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004602 appctx->ctx.table.target = NULL;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004603 appctx->ctx.table.entry = NULL;
Willy Tarreaua24bc782016-12-14 15:50:35 +01004604 appctx->ctx.table.action = (long)private; // keyword argument, one of STK_CLI_ACT_*
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004605
4606 if (*args[2]) {
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004607 appctx->ctx.table.target = stktable_find_by_name(args[2]);
Willy Tarreau9d008692019-08-09 11:21:01 +02004608 if (!appctx->ctx.table.target)
4609 return cli_err(appctx, "No such table\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004610 }
4611 else {
Willy Tarreaua24bc782016-12-14 15:50:35 +01004612 if (appctx->ctx.table.action != STK_CLI_ACT_SHOW)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004613 goto err_args;
4614 return 0;
4615 }
4616
4617 if (strcmp(args[3], "key") == 0)
4618 return table_process_entry_per_key(appctx, args);
4619 else if (strncmp(args[3], "data.", 5) == 0)
4620 return table_prepare_data_request(appctx, args);
4621 else if (*args[3])
4622 goto err_args;
4623
4624 return 0;
4625
4626err_args:
Willy Tarreaua24bc782016-12-14 15:50:35 +01004627 switch (appctx->ctx.table.action) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004628 case STK_CLI_ACT_SHOW:
Willy Tarreau9d008692019-08-09 11:21:01 +02004629 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 +01004630 case STK_CLI_ACT_CLR:
Willy Tarreau9d008692019-08-09 11:21:01 +02004631 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 +01004632 case STK_CLI_ACT_SET:
Willy Tarreau9d008692019-08-09 11:21:01 +02004633 return cli_err(appctx, "Required arguments: <table> key <key> [data.<store_data_type> <value>]*\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004634 default:
Willy Tarreau9d008692019-08-09 11:21:01 +02004635 return cli_err(appctx, "Unknown action\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004636 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004637}
4638
4639/* This function is used to deal with table operations (dump or clear depending
4640 * on the action stored in appctx->private). It returns 0 if the output buffer is
4641 * full and it needs to be called again, otherwise non-zero.
4642 */
4643static int cli_io_handler_table(struct appctx *appctx)
4644{
4645 struct stream_interface *si = appctx->owner;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004646 struct stream *s = si_strm(si);
4647 struct ebmb_node *eb;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004648 int skip_entry;
Willy Tarreaua24bc782016-12-14 15:50:35 +01004649 int show = appctx->ctx.table.action == STK_CLI_ACT_SHOW;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004650
4651 /*
4652 * We have 3 possible states in appctx->st2 :
4653 * - STAT_ST_INIT : the first call
4654 * - STAT_ST_INFO : the proxy pointer points to the next table to
4655 * dump, the entry pointer is NULL ;
4656 * - STAT_ST_LIST : the proxy pointer points to the current table
4657 * and the entry pointer points to the next entry to be dumped,
4658 * and the refcount on the next entry is held ;
4659 * - STAT_ST_END : nothing left to dump, the buffer may contain some
4660 * data though.
4661 */
4662
4663 if (unlikely(si_ic(si)->flags & (CF_WRITE_ERROR|CF_SHUTW))) {
4664 /* in case of abort, remove any refcount we might have set on an entry */
4665 if (appctx->st2 == STAT_ST_LIST) {
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004666 stksess_kill_if_expired(appctx->ctx.table.t, appctx->ctx.table.entry, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004667 }
4668 return 1;
4669 }
4670
4671 chunk_reset(&trash);
4672
4673 while (appctx->st2 != STAT_ST_FIN) {
4674 switch (appctx->st2) {
4675 case STAT_ST_INIT:
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004676 appctx->ctx.table.t = appctx->ctx.table.target;
4677 if (!appctx->ctx.table.t)
4678 appctx->ctx.table.t = stktables_list;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004679
4680 appctx->ctx.table.entry = NULL;
4681 appctx->st2 = STAT_ST_INFO;
4682 break;
4683
4684 case STAT_ST_INFO:
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004685 if (!appctx->ctx.table.t ||
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004686 (appctx->ctx.table.target &&
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004687 appctx->ctx.table.t != appctx->ctx.table.target)) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004688 appctx->st2 = STAT_ST_END;
4689 break;
4690 }
4691
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004692 if (appctx->ctx.table.t->size) {
4693 if (show && !table_dump_head_to_buffer(&trash, si, appctx->ctx.table.t, appctx->ctx.table.target))
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004694 return 0;
4695
4696 if (appctx->ctx.table.target &&
William Lallemand07a62f72017-05-24 00:57:40 +02004697 (strm_li(s)->bind_conf->level & ACCESS_LVL_MASK) >= ACCESS_LVL_OPER) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004698 /* dump entries only if table explicitly requested */
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004699 HA_SPIN_LOCK(STK_TABLE_LOCK, &appctx->ctx.table.t->lock);
4700 eb = ebmb_first(&appctx->ctx.table.t->keys);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004701 if (eb) {
4702 appctx->ctx.table.entry = ebmb_entry(eb, struct stksess, key);
4703 appctx->ctx.table.entry->ref_cnt++;
4704 appctx->st2 = STAT_ST_LIST;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004705 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &appctx->ctx.table.t->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004706 break;
4707 }
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004708 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &appctx->ctx.table.t->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004709 }
4710 }
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004711 appctx->ctx.table.t = appctx->ctx.table.t->next;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004712 break;
4713
4714 case STAT_ST_LIST:
4715 skip_entry = 0;
4716
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004717 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &appctx->ctx.table.entry->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004718
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004719 if (appctx->ctx.table.data_type[0] >= 0) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004720 /* we're filtering on some data contents */
4721 void *ptr;
Willy Tarreau2b64a352020-01-22 17:09:47 +01004722 int dt, i;
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004723 signed char op;
4724 long long data, value;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004725
Emeric Brun819fc6f2017-06-13 19:37:32 +02004726
Willy Tarreau2b64a352020-01-22 17:09:47 +01004727 for (i = 0; i < STKTABLE_FILTER_LEN; i++) {
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004728 if (appctx->ctx.table.data_type[i] == -1)
4729 break;
4730 dt = appctx->ctx.table.data_type[i];
4731 ptr = stktable_data_ptr(appctx->ctx.table.t,
4732 appctx->ctx.table.entry,
4733 dt);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004734
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004735 data = 0;
4736 switch (stktable_data_types[dt].std_type) {
4737 case STD_T_SINT:
4738 data = stktable_data_cast(ptr, std_t_sint);
4739 break;
4740 case STD_T_UINT:
4741 data = stktable_data_cast(ptr, std_t_uint);
4742 break;
4743 case STD_T_ULL:
4744 data = stktable_data_cast(ptr, std_t_ull);
4745 break;
4746 case STD_T_FRQP:
4747 data = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
4748 appctx->ctx.table.t->data_arg[dt].u);
4749 break;
4750 }
4751
4752 op = appctx->ctx.table.data_op[i];
4753 value = appctx->ctx.table.value[i];
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004754
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004755 /* skip the entry if the data does not match the test and the value */
4756 if ((data < value &&
4757 (op == STD_OP_EQ || op == STD_OP_GT || op == STD_OP_GE)) ||
4758 (data == value &&
4759 (op == STD_OP_NE || op == STD_OP_GT || op == STD_OP_LT)) ||
4760 (data > value &&
4761 (op == STD_OP_EQ || op == STD_OP_LT || op == STD_OP_LE))) {
4762 skip_entry = 1;
4763 break;
4764 }
4765 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004766 }
4767
4768 if (show && !skip_entry &&
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004769 !table_dump_entry_to_buffer(&trash, si, appctx->ctx.table.t, appctx->ctx.table.entry)) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004770 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &appctx->ctx.table.entry->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004771 return 0;
4772 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004773
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004774 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &appctx->ctx.table.entry->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004775
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004776 HA_SPIN_LOCK(STK_TABLE_LOCK, &appctx->ctx.table.t->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004777 appctx->ctx.table.entry->ref_cnt--;
4778
4779 eb = ebmb_next(&appctx->ctx.table.entry->key);
4780 if (eb) {
4781 struct stksess *old = appctx->ctx.table.entry;
4782 appctx->ctx.table.entry = ebmb_entry(eb, struct stksess, key);
4783 if (show)
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004784 __stksess_kill_if_expired(appctx->ctx.table.t, old);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004785 else if (!skip_entry && !appctx->ctx.table.entry->ref_cnt)
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004786 __stksess_kill(appctx->ctx.table.t, old);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004787 appctx->ctx.table.entry->ref_cnt++;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004788 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &appctx->ctx.table.t->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004789 break;
4790 }
4791
4792
4793 if (show)
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004794 __stksess_kill_if_expired(appctx->ctx.table.t, appctx->ctx.table.entry);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004795 else if (!skip_entry && !appctx->ctx.table.entry->ref_cnt)
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004796 __stksess_kill(appctx->ctx.table.t, appctx->ctx.table.entry);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004797
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004798 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &appctx->ctx.table.t->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004799
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004800 appctx->ctx.table.t = appctx->ctx.table.t->next;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004801 appctx->st2 = STAT_ST_INFO;
4802 break;
4803
4804 case STAT_ST_END:
4805 appctx->st2 = STAT_ST_FIN;
4806 break;
4807 }
4808 }
4809 return 1;
4810}
4811
4812static void cli_release_show_table(struct appctx *appctx)
4813{
4814 if (appctx->st2 == STAT_ST_LIST) {
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004815 stksess_kill_if_expired(appctx->ctx.table.t, appctx->ctx.table.entry, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004816 }
4817}
4818
Willy Tarreau478331d2020-08-28 11:31:31 +02004819static void stkt_late_init(void)
4820{
4821 struct sample_fetch *f;
4822
4823 f = find_sample_fetch("src", strlen("src"));
4824 if (f)
4825 smp_fetch_src = f->process;
4826}
4827
4828INITCALL0(STG_INIT, stkt_late_init);
4829
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004830/* register cli keywords */
4831static struct cli_kw_list cli_kws = {{ },{
Willy Tarreaub205bfd2021-05-07 11:38:37 +02004832 { { "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 },
4833 { { "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 },
4834 { { "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 +01004835 {{},}
4836}};
4837
Willy Tarreau0108d902018-11-25 19:14:37 +01004838INITCALL1(STG_REGISTER, cli_register_kw, &cli_kws);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004839
Thierry FOURNIER236657b2015-08-19 08:25:14 +02004840static struct action_kw_list tcp_conn_kws = { { }, {
Emeric Brun4d7ada82021-06-30 19:04:16 +02004841 { "sc-inc-gpc", parse_inc_gpc, KWF_MATCH_PREFIX },
4842 { "sc-inc-gpc0", parse_inc_gpc, KWF_MATCH_PREFIX },
4843 { "sc-inc-gpc1", parse_inc_gpc, KWF_MATCH_PREFIX },
Emeric Brun877b0b52021-06-30 18:57:49 +02004844 { "sc-set-gpt", parse_set_gpt, KWF_MATCH_PREFIX },
4845 { "sc-set-gpt0", parse_set_gpt, KWF_MATCH_PREFIX },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02004846 { /* END */ }
4847}};
4848
Willy Tarreau0108d902018-11-25 19:14:37 +01004849INITCALL1(STG_REGISTER, tcp_req_conn_keywords_register, &tcp_conn_kws);
4850
Willy Tarreau620408f2016-10-21 16:37:51 +02004851static struct action_kw_list tcp_sess_kws = { { }, {
Emeric Brun4d7ada82021-06-30 19:04:16 +02004852 { "sc-inc-gpc", parse_inc_gpc, KWF_MATCH_PREFIX },
4853 { "sc-inc-gpc0", parse_inc_gpc, KWF_MATCH_PREFIX },
4854 { "sc-inc-gpc1", parse_inc_gpc, KWF_MATCH_PREFIX },
Emeric Brun877b0b52021-06-30 18:57:49 +02004855 { "sc-set-gpt", parse_set_gpt, KWF_MATCH_PREFIX },
4856 { "sc-set-gpt0", parse_set_gpt, KWF_MATCH_PREFIX },
Willy Tarreau620408f2016-10-21 16:37:51 +02004857 { /* END */ }
4858}};
4859
Willy Tarreau0108d902018-11-25 19:14:37 +01004860INITCALL1(STG_REGISTER, tcp_req_sess_keywords_register, &tcp_sess_kws);
4861
Thierry FOURNIER236657b2015-08-19 08:25:14 +02004862static struct action_kw_list tcp_req_kws = { { }, {
Emeric Brun4d7ada82021-06-30 19:04:16 +02004863 { "sc-inc-gpc", parse_inc_gpc, KWF_MATCH_PREFIX },
4864 { "sc-inc-gpc0", parse_inc_gpc, KWF_MATCH_PREFIX },
4865 { "sc-inc-gpc1", parse_inc_gpc, KWF_MATCH_PREFIX },
Emeric Brun877b0b52021-06-30 18:57:49 +02004866 { "sc-set-gpt", parse_set_gpt, KWF_MATCH_PREFIX },
4867 { "sc-set-gpt0", parse_set_gpt, KWF_MATCH_PREFIX },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02004868 { /* END */ }
4869}};
4870
Willy Tarreau0108d902018-11-25 19:14:37 +01004871INITCALL1(STG_REGISTER, tcp_req_cont_keywords_register, &tcp_req_kws);
4872
Thierry FOURNIER236657b2015-08-19 08:25:14 +02004873static struct action_kw_list tcp_res_kws = { { }, {
Emeric Brun4d7ada82021-06-30 19:04:16 +02004874 { "sc-inc-gpc", parse_inc_gpc, KWF_MATCH_PREFIX },
4875 { "sc-inc-gpc0", parse_inc_gpc, KWF_MATCH_PREFIX },
4876 { "sc-inc-gpc1", parse_inc_gpc, KWF_MATCH_PREFIX },
Emeric Brun877b0b52021-06-30 18:57:49 +02004877 { "sc-set-gpt", parse_set_gpt, KWF_MATCH_PREFIX },
4878 { "sc-set-gpt0", parse_set_gpt, KWF_MATCH_PREFIX },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02004879 { /* END */ }
4880}};
4881
Willy Tarreau0108d902018-11-25 19:14:37 +01004882INITCALL1(STG_REGISTER, tcp_res_cont_keywords_register, &tcp_res_kws);
4883
Thierry FOURNIER236657b2015-08-19 08:25:14 +02004884static struct action_kw_list http_req_kws = { { }, {
Emeric Brun4d7ada82021-06-30 19:04:16 +02004885 { "sc-inc-gpc", parse_inc_gpc, KWF_MATCH_PREFIX },
4886 { "sc-inc-gpc0", parse_inc_gpc, KWF_MATCH_PREFIX },
4887 { "sc-inc-gpc1", parse_inc_gpc, KWF_MATCH_PREFIX },
Emeric Brun877b0b52021-06-30 18:57:49 +02004888 { "sc-set-gpt", parse_set_gpt, KWF_MATCH_PREFIX },
4889 { "sc-set-gpt0", parse_set_gpt, KWF_MATCH_PREFIX },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02004890 { /* END */ }
4891}};
4892
Willy Tarreau0108d902018-11-25 19:14:37 +01004893INITCALL1(STG_REGISTER, http_req_keywords_register, &http_req_kws);
4894
Thierry FOURNIER236657b2015-08-19 08:25:14 +02004895static struct action_kw_list http_res_kws = { { }, {
Emeric Brun4d7ada82021-06-30 19:04:16 +02004896 { "sc-inc-gpc", parse_inc_gpc, KWF_MATCH_PREFIX },
4897 { "sc-inc-gpc0", parse_inc_gpc, KWF_MATCH_PREFIX },
4898 { "sc-inc-gpc1", parse_inc_gpc, KWF_MATCH_PREFIX },
Emeric Brun877b0b52021-06-30 18:57:49 +02004899 { "sc-set-gpt", parse_set_gpt, KWF_MATCH_PREFIX },
4900 { "sc-set-gpt0", parse_set_gpt, KWF_MATCH_PREFIX },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02004901 { /* END */ }
4902}};
4903
Willy Tarreau0108d902018-11-25 19:14:37 +01004904INITCALL1(STG_REGISTER, http_res_keywords_register, &http_res_kws);
4905
Willy Tarreau7d562212016-11-25 16:10:05 +01004906/* Note: must not be declared <const> as its list will be overwritten.
4907 * Please take care of keeping this list alphabetically sorted.
4908 */
4909static struct sample_fetch_kw_list smp_fetch_keywords = {ILH, {
4910 { "sc_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4911 { "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 +02004912 { "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 +01004913 { "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 +01004914 { "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 +01004915 { "sc_conn_cnt", smp_fetch_sc_conn_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4916 { "sc_conn_cur", smp_fetch_sc_conn_cur, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4917 { "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 +02004918 { "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 +01004919 { "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 +02004920 { "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 +01004921 { "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 +01004922 { "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 +02004923 { "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 +01004924 { "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 +01004925 { "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 +01004926 { "sc_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4927 { "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 +01004928 { "sc_http_fail_cnt", smp_fetch_sc_http_fail_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4929 { "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 +01004930 { "sc_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4931 { "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 +02004932 { "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 +01004933 { "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 +01004934 { "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 +01004935 { "sc_kbytes_in", smp_fetch_sc_kbytes_in, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4936 { "sc_kbytes_out", smp_fetch_sc_kbytes_out, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4937 { "sc_sess_cnt", smp_fetch_sc_sess_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4938 { "sc_sess_rate", smp_fetch_sc_sess_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4939 { "sc_tracked", smp_fetch_sc_tracked, ARG2(1,SINT,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
4940 { "sc_trackers", smp_fetch_sc_trackers, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4941 { "sc0_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4942 { "sc0_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4943 { "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 +01004944 { "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 +01004945 { "sc0_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4946 { "sc0_conn_cur", smp_fetch_sc_conn_cur, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4947 { "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 +01004948 { "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 +01004949 { "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 +01004950 { "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 +01004951 { "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 +01004952 { "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 +01004953 { "sc0_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4954 { "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 +01004955 { "sc0_http_fail_cnt", smp_fetch_sc_http_fail_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4956 { "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 +01004957 { "sc0_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4958 { "sc0_http_req_rate", smp_fetch_sc_http_req_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4959 { "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 +01004960 { "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 +01004961 { "sc0_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4962 { "sc0_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4963 { "sc0_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4964 { "sc0_sess_rate", smp_fetch_sc_sess_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4965 { "sc0_tracked", smp_fetch_sc_tracked, ARG1(0,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
4966 { "sc0_trackers", smp_fetch_sc_trackers, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4967 { "sc1_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4968 { "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 +02004969 { "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 +01004970 { "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 +01004971 { "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 +01004972 { "sc1_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4973 { "sc1_conn_cur", smp_fetch_sc_conn_cur, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4974 { "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 +01004975 { "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 +01004976 { "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 +01004977 { "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 +01004978 { "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 +01004979 { "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 +01004980 { "sc1_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4981 { "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 +01004982 { "sc1_http_fail_cnt", smp_fetch_sc_http_fail_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4983 { "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 +01004984 { "sc1_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4985 { "sc1_http_req_rate", smp_fetch_sc_http_req_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4986 { "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 +01004987 { "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 +01004988 { "sc1_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4989 { "sc1_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4990 { "sc1_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4991 { "sc1_sess_rate", smp_fetch_sc_sess_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4992 { "sc1_tracked", smp_fetch_sc_tracked, ARG1(0,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
4993 { "sc1_trackers", smp_fetch_sc_trackers, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4994 { "sc2_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4995 { "sc2_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4996 { "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 +01004997 { "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 +01004998 { "sc2_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4999 { "sc2_conn_cur", smp_fetch_sc_conn_cur, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5000 { "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 +01005001 { "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 +01005002 { "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 +01005003 { "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 +01005004 { "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 +01005005 { "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 +01005006 { "sc2_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5007 { "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 +01005008 { "sc2_http_fail_cnt", smp_fetch_sc_http_fail_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5009 { "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 +01005010 { "sc2_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5011 { "sc2_http_req_rate", smp_fetch_sc_http_req_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5012 { "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 +01005013 { "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 +01005014 { "sc2_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5015 { "sc2_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5016 { "sc2_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5017 { "sc2_sess_rate", smp_fetch_sc_sess_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5018 { "sc2_tracked", smp_fetch_sc_tracked, ARG1(0,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
5019 { "sc2_trackers", smp_fetch_sc_trackers, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5020 { "src_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5021 { "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 +02005022 { "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 +01005023 { "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 +01005024 { "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 +01005025 { "src_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5026 { "src_conn_cur", smp_fetch_sc_conn_cur, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5027 { "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 +02005028 { "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 +01005029 { "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 +02005030 { "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 +01005031 { "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 +01005032 { "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 +02005033 { "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 +01005034 { "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 +01005035 { "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 +01005036 { "src_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5037 { "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 +01005038 { "src_http_fail_cnt", smp_fetch_sc_http_fail_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5039 { "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 +01005040 { "src_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5041 { "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 +02005042 { "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 +01005043 { "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 +01005044 { "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 +01005045 { "src_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5046 { "src_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5047 { "src_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5048 { "src_sess_rate", smp_fetch_sc_sess_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5049 { "src_updt_conn_cnt", smp_fetch_src_updt_conn_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5050 { "table_avl", smp_fetch_table_avl, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5051 { "table_cnt", smp_fetch_table_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5052 { /* END */ },
5053}};
5054
Willy Tarreau0108d902018-11-25 19:14:37 +01005055INITCALL1(STG_REGISTER, sample_register_fetches, &smp_fetch_keywords);
Willy Tarreau7d562212016-11-25 16:10:05 +01005056
Willy Tarreaud9f316a2014-07-10 14:03:38 +02005057/* Note: must not be declared <const> as its list will be overwritten */
5058static struct sample_conv_kw_list sample_conv_kws = {ILH, {
Willy Tarreau2d17db52016-05-25 17:16:38 +02005059 { "in_table", sample_conv_in_table, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_BOOL },
5060 { "table_bytes_in_rate", sample_conv_table_bytes_in_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5061 { "table_bytes_out_rate", sample_conv_table_bytes_out_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5062 { "table_conn_cnt", sample_conv_table_conn_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5063 { "table_conn_cur", sample_conv_table_conn_cur, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5064 { "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 +02005065 { "table_gpt", sample_conv_table_gpt, ARG2(2,SINT,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
Willy Tarreau2d17db52016-05-25 17:16:38 +02005066 { "table_gpt0", sample_conv_table_gpt0, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
Emeric Brun4d7ada82021-06-30 19:04:16 +02005067 { "table_gpc", sample_conv_table_gpc, ARG2(2,SINT,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
Willy Tarreau2d17db52016-05-25 17:16:38 +02005068 { "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 +01005069 { "table_gpc1", sample_conv_table_gpc1, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
Emeric Brun4d7ada82021-06-30 19:04:16 +02005070 { "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 +02005071 { "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 +01005072 { "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 +02005073 { "table_http_err_cnt", sample_conv_table_http_err_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5074 { "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 +01005075 { "table_http_fail_cnt", sample_conv_table_http_fail_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5076 { "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 +02005077 { "table_http_req_cnt", sample_conv_table_http_req_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5078 { "table_http_req_rate", sample_conv_table_http_req_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5079 { "table_kbytes_in", sample_conv_table_kbytes_in, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5080 { "table_kbytes_out", sample_conv_table_kbytes_out, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5081 { "table_server_id", sample_conv_table_server_id, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5082 { "table_sess_cnt", sample_conv_table_sess_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5083 { "table_sess_rate", sample_conv_table_sess_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5084 { "table_trackers", sample_conv_table_trackers, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
Willy Tarreaud9f316a2014-07-10 14:03:38 +02005085 { /* END */ },
5086}};
5087
Willy Tarreau0108d902018-11-25 19:14:37 +01005088INITCALL1(STG_REGISTER, sample_register_convs, &sample_conv_kws);