blob: d351a10ca1d11595cb5ac095be4c2af84b990876 [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) {
101 dict_entry_unref(&server_key_dict, stktable_data_cast(data, server_key));
102 stktable_data_cast(data, server_key) = NULL;
103 }
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
Aleksey Ponomaryovb38ad122023-02-07 19:27:06 +0100225 /* the update might have jumped beyond the next element,
226 * possibly causing a wrapping. We need to check whether
227 * the next element should be used instead. If the next
228 * element doesn't exist it means we're on the right
229 * side and have to check the first one then. If it
230 * exists and is closer, we must use it, otherwise we
231 * use the current one.
232 */
233 if (!eb)
234 eb = eb32_first(&t->exps);
235
236 if (!eb || tick_is_lt(ts->exp.key, eb->key))
Willy Tarreau86257dc2010-06-06 12:57:10 +0200237 eb = &ts->exp;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100238
239 continue;
240 }
Emeric Brun3bd697e2010-01-04 15:23:48 +0100241
Willy Tarreauaea940e2010-06-06 11:56:36 +0200242 /* session expired, trash it */
Willy Tarreau86257dc2010-06-06 12:57:10 +0200243 ebmb_delete(&ts->key);
Emeric Brun85e77c72010-09-23 18:16:52 +0200244 eb32_delete(&ts->upd);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200245 __stksess_free(t, ts);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100246 batched++;
247 }
248
249 return batched;
250}
251
252/*
Emeric Brun819fc6f2017-06-13 19:37:32 +0200253 * Trash oldest <to_batch> sticky sessions from table <t>
254 * Returns number of trashed sticky sessions.
255 * This function locks the table
256 */
257int stktable_trash_oldest(struct stktable *t, int to_batch)
258{
259 int ret;
260
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100261 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200262 ret = __stktable_trash_oldest(t, to_batch);
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100263 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200264
265 return ret;
266}
267/*
Willy Tarreauaea940e2010-06-06 11:56:36 +0200268 * Allocate and initialise a new sticky session.
269 * The new sticky session is returned or NULL in case of lack of memory.
270 * Sticky sessions should only be allocated this way, and must be freed using
Willy Tarreaua7b46b52013-04-11 16:55:37 +0200271 * stksess_free(). Table <t>'s sticky session counter is increased. If <key>
272 * is not NULL, it is assigned to the new session.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100273 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200274struct stksess *__stksess_new(struct stktable *t, struct stktable_key *key)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100275{
276 struct stksess *ts;
277
278 if (unlikely(t->current == t->size)) {
279 if ( t->nopurge )
280 return NULL;
281
Emeric Brun819fc6f2017-06-13 19:37:32 +0200282 if (!__stktable_trash_oldest(t, (t->size >> 8) + 1))
Emeric Brun3bd697e2010-01-04 15:23:48 +0100283 return NULL;
284 }
285
Willy Tarreaubafbe012017-11-24 17:34:44 +0100286 ts = pool_alloc(t->pool);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100287 if (ts) {
288 t->current++;
Olivier Houchard52dabbc2018-11-14 17:54:36 +0100289 ts = (void *)ts + round_ptr_size(t->data_size);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200290 __stksess_init(t, ts);
Willy Tarreaua7b46b52013-04-11 16:55:37 +0200291 if (key)
292 stksess_setkey(t, ts, key);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100293 }
294
295 return ts;
296}
Emeric Brun819fc6f2017-06-13 19:37:32 +0200297/*
298 * Allocate and initialise a new sticky session.
299 * The new sticky session is returned or NULL in case of lack of memory.
300 * Sticky sessions should only be allocated this way, and must be freed using
301 * stksess_free(). Table <t>'s sticky session counter is increased. If <key>
302 * is not NULL, it is assigned to the new session.
303 * This function locks the table
304 */
305struct stksess *stksess_new(struct stktable *t, struct stktable_key *key)
306{
307 struct stksess *ts;
308
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100309 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200310 ts = __stksess_new(t, key);
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100311 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200312
313 return ts;
314}
Emeric Brun3bd697e2010-01-04 15:23:48 +0100315
316/*
Willy Tarreauf16d2b82010-06-06 15:38:59 +0200317 * Looks in table <t> for a sticky session matching key <key>.
Willy Tarreauaea940e2010-06-06 11:56:36 +0200318 * Returns pointer on requested sticky session or NULL if none was found.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100319 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200320struct stksess *__stktable_lookup_key(struct stktable *t, struct stktable_key *key)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100321{
322 struct ebmb_node *eb;
323
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200324 if (t->type == SMP_T_STR)
Emeric Brun485479d2010-09-23 18:02:19 +0200325 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 +0100326 else
327 eb = ebmb_lookup(&t->keys, key->key, t->key_size);
328
329 if (unlikely(!eb)) {
330 /* no session found */
331 return NULL;
332 }
333
Willy Tarreau86257dc2010-06-06 12:57:10 +0200334 return ebmb_entry(eb, struct stksess, key);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100335}
336
Emeric Brun819fc6f2017-06-13 19:37:32 +0200337/*
338 * Looks in table <t> for a sticky session matching key <key>.
339 * Returns pointer on requested sticky session or NULL if none was found.
340 * The refcount of the found entry is increased and this function
341 * is protected using the table lock
Willy Tarreau1f7e9252010-06-20 12:27:21 +0200342 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200343struct stksess *stktable_lookup_key(struct stktable *t, struct stktable_key *key)
Willy Tarreau1f7e9252010-06-20 12:27:21 +0200344{
345 struct stksess *ts;
346
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100347 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200348 ts = __stktable_lookup_key(t, key);
349 if (ts)
350 ts->ref_cnt++;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100351 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Willy Tarreau1f7e9252010-06-20 12:27:21 +0200352
Willy Tarreau1f7e9252010-06-20 12:27:21 +0200353 return ts;
354}
355
Willy Tarreauf16d2b82010-06-06 15:38:59 +0200356/*
357 * Looks in table <t> for a sticky session with same key as <ts>.
358 * Returns pointer on requested sticky session or NULL if none was found.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100359 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200360struct stksess *__stktable_lookup(struct stktable *t, struct stksess *ts)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100361{
Emeric Brun3bd697e2010-01-04 15:23:48 +0100362 struct ebmb_node *eb;
363
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200364 if (t->type == SMP_T_STR)
Willy Tarreau86257dc2010-06-06 12:57:10 +0200365 eb = ebst_lookup(&(t->keys), (char *)ts->key.key);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100366 else
Willy Tarreau86257dc2010-06-06 12:57:10 +0200367 eb = ebmb_lookup(&(t->keys), ts->key.key, t->key_size);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100368
Willy Tarreauf16d2b82010-06-06 15:38:59 +0200369 if (unlikely(!eb))
370 return NULL;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100371
Willy Tarreauf16d2b82010-06-06 15:38:59 +0200372 return ebmb_entry(eb, struct stksess, key);
373}
Emeric Brun3bd697e2010-01-04 15:23:48 +0100374
Emeric Brun819fc6f2017-06-13 19:37:32 +0200375/*
376 * Looks in table <t> for a sticky session with same key as <ts>.
377 * Returns pointer on requested sticky session or NULL if none was found.
378 * The refcount of the found entry is increased and this function
379 * is protected using the table lock
380 */
381struct stksess *stktable_lookup(struct stktable *t, struct stksess *ts)
382{
383 struct stksess *lts;
384
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100385 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200386 lts = __stktable_lookup(t, ts);
387 if (lts)
388 lts->ref_cnt++;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100389 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200390
391 return lts;
392}
393
Willy Tarreaucb183642010-06-06 17:58:34 +0200394/* Update the expiration timer for <ts> but do not touch its expiration node.
395 * The table's expiration timer is updated if set.
Emeric Brun819fc6f2017-06-13 19:37:32 +0200396 * The node will be also inserted into the update tree if needed, at a position
397 * depending if the update is a local or coming from a remote node
Willy Tarreaucb183642010-06-06 17:58:34 +0200398 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200399void __stktable_touch_with_exp(struct stktable *t, struct stksess *ts, int local, int expire)
Willy Tarreaucb183642010-06-06 17:58:34 +0200400{
Emeric Brun85e77c72010-09-23 18:16:52 +0200401 struct eb32_node * eb;
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200402 ts->expire = expire;
Willy Tarreaucb183642010-06-06 17:58:34 +0200403 if (t->expire) {
404 t->exp_task->expire = t->exp_next = tick_first(ts->expire, t->exp_next);
405 task_queue(t->exp_task);
406 }
Emeric Brun85e77c72010-09-23 18:16:52 +0200407
Emeric Brun819fc6f2017-06-13 19:37:32 +0200408 /* If sync is enabled */
409 if (t->sync_task) {
410 if (local) {
411 /* If this entry is not in the tree
412 or not scheduled for at least one peer */
413 if (!ts->upd.node.leaf_p
414 || (int)(t->commitupdate - ts->upd.key) >= 0
415 || (int)(ts->upd.key - t->localupdate) >= 0) {
416 ts->upd.key = ++t->update;
417 t->localupdate = t->update;
418 eb32_delete(&ts->upd);
419 eb = eb32_insert(&t->updates, &ts->upd);
420 if (eb != &ts->upd) {
421 eb32_delete(eb);
422 eb32_insert(&t->updates, &ts->upd);
423 }
Emeric Brunaaf58602015-06-15 17:23:30 +0200424 }
Emeric Brun819fc6f2017-06-13 19:37:32 +0200425 task_wakeup(t->sync_task, TASK_WOKEN_MSG);
Emeric Brun85e77c72010-09-23 18:16:52 +0200426 }
Emeric Brun819fc6f2017-06-13 19:37:32 +0200427 else {
428 /* If this entry is not in the tree */
429 if (!ts->upd.node.leaf_p) {
430 ts->upd.key= (++t->update)+(2147483648U);
431 eb = eb32_insert(&t->updates, &ts->upd);
432 if (eb != &ts->upd) {
433 eb32_delete(eb);
434 eb32_insert(&t->updates, &ts->upd);
435 }
436 }
437 }
Emeric Brun85e77c72010-09-23 18:16:52 +0200438 }
Willy Tarreaucb183642010-06-06 17:58:34 +0200439}
440
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200441/* Update the expiration timer for <ts> but do not touch its expiration node.
Emeric Brun819fc6f2017-06-13 19:37:32 +0200442 * The table's expiration timer is updated using the date of expiration coming from
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200443 * <t> stick-table configuration.
Emeric Brun819fc6f2017-06-13 19:37:32 +0200444 * The node will be also inserted into the update tree if needed, at a position
445 * considering the update is coming from a remote node
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200446 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200447void stktable_touch_remote(struct stktable *t, struct stksess *ts, int decrefcnt)
448{
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100449 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200450 __stktable_touch_with_exp(t, ts, 0, ts->expire);
451 if (decrefcnt)
452 ts->ref_cnt--;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100453 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200454}
455
456/* Update the expiration timer for <ts> but do not touch its expiration node.
457 * The table's expiration timer is updated using the date of expiration coming from
458 * <t> stick-table configuration.
459 * The node will be also inserted into the update tree if needed, at a position
460 * considering the update was made locally
461 */
462void stktable_touch_local(struct stktable *t, struct stksess *ts, int decrefcnt)
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200463{
464 int expire = tick_add(now_ms, MS_TO_TICKS(t->expire));
465
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100466 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200467 __stktable_touch_with_exp(t, ts, 1, expire);
468 if (decrefcnt)
469 ts->ref_cnt--;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100470 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200471}
Willy Tarreau43e90352018-06-27 06:25:57 +0200472/* Just decrease the ref_cnt of the current session. Does nothing if <ts> is NULL */
473static void stktable_release(struct stktable *t, struct stksess *ts)
Emeric Brun819fc6f2017-06-13 19:37:32 +0200474{
Willy Tarreau43e90352018-06-27 06:25:57 +0200475 if (!ts)
476 return;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100477 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200478 ts->ref_cnt--;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100479 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200480}
481
Willy Tarreauf16d2b82010-06-06 15:38:59 +0200482/* Insert new sticky session <ts> in the table. It is assumed that it does not
483 * yet exist (the caller must check this). The table's timeout is updated if it
484 * is set. <ts> is returned.
485 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200486void __stktable_store(struct stktable *t, struct stksess *ts)
Willy Tarreauf16d2b82010-06-06 15:38:59 +0200487{
Emeric Brun3bd697e2010-01-04 15:23:48 +0100488
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200489 ebmb_insert(&t->keys, &ts->key, t->key_size);
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200490 ts->exp.key = ts->expire;
491 eb32_insert(&t->exps, &ts->exp);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200492 if (t->expire) {
493 t->exp_task->expire = t->exp_next = tick_first(ts->expire, t->exp_next);
494 task_queue(t->exp_task);
495 }
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200496}
497
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200498/* Returns a valid or initialized stksess for the specified stktable_key in the
499 * specified table, or NULL if the key was NULL, or if no entry was found nor
500 * could be created. The entry's expiration is updated.
501 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200502struct stksess *__stktable_get_entry(struct stktable *table, struct stktable_key *key)
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200503{
504 struct stksess *ts;
505
506 if (!key)
507 return NULL;
508
Emeric Brun819fc6f2017-06-13 19:37:32 +0200509 ts = __stktable_lookup_key(table, key);
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200510 if (ts == NULL) {
511 /* entry does not exist, initialize a new one */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200512 ts = __stksess_new(table, key);
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200513 if (!ts)
514 return NULL;
Emeric Brun819fc6f2017-06-13 19:37:32 +0200515 __stktable_store(table, ts);
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200516 }
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200517 return ts;
518}
Emeric Brun819fc6f2017-06-13 19:37:32 +0200519/* Returns a valid or initialized stksess for the specified stktable_key in the
520 * specified table, or NULL if the key was NULL, or if no entry was found nor
521 * could be created. The entry's expiration is updated.
522 * This function locks the table, and the refcount of the entry is increased.
523 */
524struct stksess *stktable_get_entry(struct stktable *table, struct stktable_key *key)
525{
526 struct stksess *ts;
527
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100528 HA_SPIN_LOCK(STK_TABLE_LOCK, &table->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200529 ts = __stktable_get_entry(table, key);
530 if (ts)
531 ts->ref_cnt++;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100532 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &table->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200533
534 return ts;
535}
536
537/* Lookup for an entry with the same key and store the submitted
538 * stksess if not found.
539 */
540struct stksess *__stktable_set_entry(struct stktable *table, struct stksess *nts)
541{
542 struct stksess *ts;
543
544 ts = __stktable_lookup(table, nts);
545 if (ts == NULL) {
546 ts = nts;
547 __stktable_store(table, ts);
548 }
549 return ts;
550}
551
552/* Lookup for an entry with the same key and store the submitted
553 * stksess if not found.
554 * This function locks the table, and the refcount of the entry is increased.
555 */
556struct stksess *stktable_set_entry(struct stktable *table, struct stksess *nts)
557{
558 struct stksess *ts;
559
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100560 HA_SPIN_LOCK(STK_TABLE_LOCK, &table->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200561 ts = __stktable_set_entry(table, nts);
562 ts->ref_cnt++;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100563 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &table->lock);
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200564
Emeric Brun819fc6f2017-06-13 19:37:32 +0200565 return ts;
566}
Emeric Brun3bd697e2010-01-04 15:23:48 +0100567/*
Willy Tarreaud2636522022-11-14 18:02:44 +0100568 * Task processing function to trash expired sticky sessions. A pointer to the
569 * task itself is returned since it never dies.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100570 */
Willy Tarreaud2636522022-11-14 18:02:44 +0100571struct task *process_table_expire(struct task *task, void *context, unsigned int state)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100572{
Willy Tarreaud2636522022-11-14 18:02:44 +0100573 struct stktable *t = context;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100574 struct stksess *ts;
575 struct eb32_node *eb;
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200576 int looped = 0;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100577
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100578 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100579 eb = eb32_lookup_ge(&t->exps, now_ms - TIMER_LOOK_BACK);
580
581 while (1) {
582 if (unlikely(!eb)) {
583 /* we might have reached the end of the tree, typically because
584 * <now_ms> is in the first half and we're first scanning the last
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200585 * half. Let's loop back to the beginning of the tree now if we
586 * have not yet visited it.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100587 */
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200588 if (looped)
589 break;
590 looped = 1;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100591 eb = eb32_first(&t->exps);
592 if (likely(!eb))
593 break;
594 }
595
596 if (likely(tick_is_lt(now_ms, eb->key))) {
597 /* timer not expired yet, revisit it later */
598 t->exp_next = eb->key;
Willy Tarreau4d5f13c2017-11-05 11:04:47 +0100599 goto out_unlock;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100600 }
601
602 /* timer looks expired, detach it from the queue */
Willy Tarreau86257dc2010-06-06 12:57:10 +0200603 ts = eb32_entry(eb, struct stksess, exp);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100604 eb = eb32_next(eb);
605
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200606 /* don't delete an entry which is currently referenced */
607 if (ts->ref_cnt)
608 continue;
609
Willy Tarreau86257dc2010-06-06 12:57:10 +0200610 eb32_delete(&ts->exp);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100611
612 if (!tick_is_expired(ts->expire, now_ms)) {
613 if (!tick_isset(ts->expire))
614 continue;
615
Willy Tarreau86257dc2010-06-06 12:57:10 +0200616 ts->exp.key = ts->expire;
617 eb32_insert(&t->exps, &ts->exp);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100618
Aleksey Ponomaryovb38ad122023-02-07 19:27:06 +0100619 /* the update might have jumped beyond the next element,
620 * possibly causing a wrapping. We need to check whether
621 * the next element should be used instead. If the next
622 * element doesn't exist it means we're on the right
623 * side and have to check the first one then. If it
624 * exists and is closer, we must use it, otherwise we
625 * use the current one.
626 */
627 if (!eb)
628 eb = eb32_first(&t->exps);
629
630 if (!eb || tick_is_lt(ts->exp.key, eb->key))
Willy Tarreau86257dc2010-06-06 12:57:10 +0200631 eb = &ts->exp;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100632 continue;
633 }
634
635 /* session expired, trash it */
Willy Tarreau86257dc2010-06-06 12:57:10 +0200636 ebmb_delete(&ts->key);
Emeric Brun85e77c72010-09-23 18:16:52 +0200637 eb32_delete(&ts->upd);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200638 __stksess_free(t, ts);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100639 }
640
641 /* We have found no task to expire in any tree */
642 t->exp_next = TICK_ETERNITY;
Willy Tarreau4d5f13c2017-11-05 11:04:47 +0100643out_unlock:
Willy Tarreaud2636522022-11-14 18:02:44 +0100644 task->expire = t->exp_next;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100645 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100646 return task;
647}
648
Willy Tarreauaea940e2010-06-06 11:56:36 +0200649/* Perform minimal stick table intializations, report 0 in case of error, 1 if OK. */
Emeric Brun3bd697e2010-01-04 15:23:48 +0100650int stktable_init(struct stktable *t)
651{
Remi Tricot-Le Bretonbe5b1bb2021-05-12 17:39:04 +0200652 int peers_retval = 0;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100653 if (t->size) {
Emeric Brun819fc6f2017-06-13 19:37:32 +0200654 t->keys = EB_ROOT_UNIQUE;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100655 memset(&t->exps, 0, sizeof(t->exps));
Emeric Brun1c6235d2015-12-16 15:28:12 +0100656 t->updates = EB_ROOT_UNIQUE;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100657 HA_SPIN_INIT(&t->lock);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100658
Olivier Houchard52dabbc2018-11-14 17:54:36 +0100659 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 +0100660
661 t->exp_next = TICK_ETERNITY;
662 if ( t->expire ) {
Emeric Brunc60def82017-09-27 14:59:38 +0200663 t->exp_task = task_new(MAX_THREADS_MASK);
Willy Tarreau848522f2018-10-15 11:12:15 +0200664 if (!t->exp_task)
665 return 0;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100666 t->exp_task->process = process_table_expire;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100667 t->exp_task->context = (void *)t;
668 }
Willy Tarreauc3914d42020-09-24 08:39:22 +0200669 if (t->peers.p && t->peers.p->peers_fe && !t->peers.p->peers_fe->disabled) {
Remi Tricot-Le Bretonbe5b1bb2021-05-12 17:39:04 +0200670 peers_retval = peers_register_table(t->peers.p, t);
Emeric Brun32da3c42010-09-23 18:39:19 +0200671 }
672
Remi Tricot-Le Bretonbe5b1bb2021-05-12 17:39:04 +0200673 return (t->pool != NULL) && !peers_retval;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100674 }
675 return 1;
676}
677
678/*
679 * Configuration keywords of known table types
680 */
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200681struct stktable_type stktable_types[SMP_TYPES] = {
682 [SMP_T_SINT] = { "integer", 0, 4 },
683 [SMP_T_IPV4] = { "ip", 0, 4 },
684 [SMP_T_IPV6] = { "ipv6", 0, 16 },
685 [SMP_T_STR] = { "string", STK_F_CUSTOM_KEYSIZE, 32 },
686 [SMP_T_BIN] = { "binary", STK_F_CUSTOM_KEYSIZE, 32 }
687};
Emeric Brun3bd697e2010-01-04 15:23:48 +0100688
689/*
690 * Parse table type configuration.
691 * Returns 0 on successful parsing, else 1.
692 * <myidx> is set at next configuration <args> index.
693 */
William Lallemand42b46252023-04-13 14:33:52 +0200694int stktable_parse_type(char **args, int *myidx, unsigned long *type, size_t *key_size, const char *file, int linenum)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100695{
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200696 for (*type = 0; *type < SMP_TYPES; (*type)++) {
697 if (!stktable_types[*type].kw)
698 continue;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100699 if (strcmp(args[*myidx], stktable_types[*type].kw) != 0)
700 continue;
701
702 *key_size = stktable_types[*type].default_size;
703 (*myidx)++;
704
Willy Tarreauaea940e2010-06-06 11:56:36 +0200705 if (stktable_types[*type].flags & STK_F_CUSTOM_KEYSIZE) {
Emeric Brun3bd697e2010-01-04 15:23:48 +0100706 if (strcmp("len", args[*myidx]) == 0) {
William Lallemand42b46252023-04-13 14:33:52 +0200707 char *stop;
708
Emeric Brun3bd697e2010-01-04 15:23:48 +0100709 (*myidx)++;
William Lallemand42b46252023-04-13 14:33:52 +0200710 *key_size = strtol(args[*myidx], &stop, 10);
711 if (*stop != '\0' || !*key_size) {
712 ha_alert("parsing [%s:%d] : 'len' expects a positive integer argument.\n", file, linenum);
713 return 1;
714 }
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200715 if (*type == SMP_T_STR) {
Emeric Brun485479d2010-09-23 18:02:19 +0200716 /* null terminated string needs +1 for '\0'. */
717 (*key_size)++;
718 }
Emeric Brun3bd697e2010-01-04 15:23:48 +0100719 (*myidx)++;
720 }
721 }
722 return 0;
723 }
William Lallemand42b46252023-04-13 14:33:52 +0200724 ha_alert("parsing [%s:%d] : %s: unknown type '%s'.\n", file, linenum, args[0], args[*myidx]);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100725 return 1;
726}
727
Willy Tarreau3b63ca22021-05-08 14:10:42 +0200728/* reserve some space for data type <type>, and associate argument at <sa> if
729 * not NULL. Returns PE_NONE (0) if OK or an error code among :
730 * - PE_ENUM_OOR if <type> does not exist
731 * - PE_EXIST if <type> is already registered
732 * - PE_ARG_NOT_USE if <sa> was provided but not expected
733 * - PE_ARG_MISSING if <sa> was expected but not provided
734 */
735int stktable_alloc_data_type(struct stktable *t, int type, const char *sa)
736{
737 if (type >= STKTABLE_DATA_TYPES)
738 return PE_ENUM_OOR;
739
740 if (t->data_ofs[type])
741 /* already allocated */
742 return PE_EXIST;
743
744 switch (stktable_data_types[type].arg_type) {
745 case ARG_T_NONE:
746 if (sa)
747 return PE_ARG_NOT_USED;
748 break;
749 case ARG_T_INT:
750 if (!sa)
751 return PE_ARG_MISSING;
752 t->data_arg[type].i = atoi(sa);
753 break;
754 case ARG_T_DELAY:
755 if (!sa)
756 return PE_ARG_MISSING;
757 sa = parse_time_err(sa, &t->data_arg[type].u, TIME_UNIT_MS);
758 if (sa)
759 return PE_ARG_INVC; /* invalid char */
760 break;
761 }
762
763 t->data_size += stktable_type_size(stktable_data_types[type].std_type);
764 t->data_ofs[type] = -t->data_size;
765 return PE_NONE;
766}
767
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100768/*
Frédéric Lécaillec02766a2019-03-20 15:06:55 +0100769 * Parse a line with <linenum> as number in <file> configuration file to configure
770 * the stick-table with <t> as address and <id> as ID.
771 * <peers> provides the "peers" section pointer only if this function is called
772 * from a "peers" section.
773 * <nid> is the stick-table name which is sent over the network. It must be equal
774 * to <id> if this stick-table is parsed from a proxy section, and prefixed by <peers>
775 * "peers" section name followed by a '/' character if parsed from a "peers" section.
Ilya Shipitsind4259502020-04-08 01:07:56 +0500776 * This is the responsibility of the caller to check this.
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100777 * Return an error status with ERR_* flags set if required, 0 if no error was encountered.
778 */
779int parse_stick_table(const char *file, int linenum, char **args,
Frédéric Lécaillec02766a2019-03-20 15:06:55 +0100780 struct stktable *t, char *id, char *nid, struct peers *peers)
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100781{
782 int err_code = 0;
783 int idx = 1;
784 unsigned int val;
785
786 if (!id || !*id) {
787 ha_alert("parsing [%s:%d] : %s: ID not provided.\n", file, linenum, args[0]);
788 err_code |= ERR_ALERT | ERR_ABORT;
789 goto out;
790 }
791
792 /* Store the "peers" section if this function is called from a "peers" section. */
793 if (peers) {
794 t->peers.p = peers;
795 idx++;
796 }
797
798 t->id = id;
Frédéric Lécaillec02766a2019-03-20 15:06:55 +0100799 t->nid = nid;
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100800 t->type = (unsigned int)-1;
801 t->conf.file = file;
802 t->conf.line = linenum;
803
804 while (*args[idx]) {
805 const char *err;
806
807 if (strcmp(args[idx], "size") == 0) {
808 idx++;
809 if (!*(args[idx])) {
810 ha_alert("parsing [%s:%d] : %s: missing argument after '%s'.\n",
811 file, linenum, args[0], args[idx-1]);
812 err_code |= ERR_ALERT | ERR_FATAL;
813 goto out;
814 }
815 if ((err = parse_size_err(args[idx], &t->size))) {
816 ha_alert("parsing [%s:%d] : %s: unexpected character '%c' in argument of '%s'.\n",
817 file, linenum, args[0], *err, args[idx-1]);
818 err_code |= ERR_ALERT | ERR_FATAL;
819 goto out;
820 }
821 idx++;
822 }
823 /* This argument does not exit in "peers" section. */
824 else if (!peers && strcmp(args[idx], "peers") == 0) {
825 idx++;
826 if (!*(args[idx])) {
827 ha_alert("parsing [%s:%d] : %s: missing argument after '%s'.\n",
828 file, linenum, args[0], args[idx-1]);
829 err_code |= ERR_ALERT | ERR_FATAL;
830 goto out;
831 }
Aurelien DARRAGON7228dfd2023-11-02 09:18:55 +0100832 ha_free(&t->peers.name);
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100833 t->peers.name = strdup(args[idx++]);
834 }
835 else if (strcmp(args[idx], "expire") == 0) {
836 idx++;
837 if (!*(args[idx])) {
838 ha_alert("parsing [%s:%d] : %s: missing argument after '%s'.\n",
839 file, linenum, args[0], args[idx-1]);
840 err_code |= ERR_ALERT | ERR_FATAL;
841 goto out;
842 }
843 err = parse_time_err(args[idx], &val, TIME_UNIT_MS);
Willy Tarreau9faebe32019-06-07 19:00:37 +0200844 if (err == PARSE_TIME_OVER) {
845 ha_alert("parsing [%s:%d]: %s: timer overflow in argument <%s> to <%s>, maximum value is 2147483647 ms (~24.8 days).\n",
846 file, linenum, args[0], args[idx], args[idx-1]);
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100847 err_code |= ERR_ALERT | ERR_FATAL;
848 goto out;
849 }
Willy Tarreau9faebe32019-06-07 19:00:37 +0200850 else if (err == PARSE_TIME_UNDER) {
851 ha_alert("parsing [%s:%d]: %s: timer underflow in argument <%s> to <%s>, minimum non-null value is 1 ms.\n",
852 file, linenum, args[0], args[idx], args[idx-1]);
853 err_code |= ERR_ALERT | ERR_FATAL;
854 goto out;
855 }
856 else if (err) {
857 ha_alert("parsing [%s:%d] : %s: unexpected character '%c' in argument of '%s'.\n",
858 file, linenum, args[0], *err, args[idx-1]);
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100859 err_code |= ERR_ALERT | ERR_FATAL;
860 goto out;
861 }
862 t->expire = val;
863 idx++;
864 }
865 else if (strcmp(args[idx], "nopurge") == 0) {
866 t->nopurge = 1;
867 idx++;
868 }
869 else if (strcmp(args[idx], "type") == 0) {
870 idx++;
William Lallemand42b46252023-04-13 14:33:52 +0200871 if (stktable_parse_type(args, &idx, &t->type, &t->key_size, file, linenum) != 0) {
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100872 err_code |= ERR_ALERT | ERR_FATAL;
873 goto out;
874 }
875 /* idx already points to next arg */
876 }
877 else if (strcmp(args[idx], "store") == 0) {
878 int type, err;
879 char *cw, *nw, *sa;
880
881 idx++;
882 nw = args[idx];
883 while (*nw) {
884 /* the "store" keyword supports a comma-separated list */
885 cw = nw;
886 sa = NULL; /* store arg */
887 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 }
898 nw++;
899 }
900 *nw = '\0';
901 }
902 nw++;
903 }
904 if (*nw)
905 *nw++ = '\0';
906 type = stktable_get_data_type(cw);
907 if (type < 0) {
908 ha_alert("parsing [%s:%d] : %s: unknown store option '%s'.\n",
909 file, linenum, args[0], cw);
910 err_code |= ERR_ALERT | ERR_FATAL;
911 goto out;
912 }
913
914 err = stktable_alloc_data_type(t, type, sa);
915 switch (err) {
916 case PE_NONE: break;
917 case PE_EXIST:
918 ha_warning("parsing [%s:%d]: %s: store option '%s' already enabled, ignored.\n",
919 file, linenum, args[0], cw);
920 err_code |= ERR_WARN;
921 break;
922
923 case PE_ARG_MISSING:
924 ha_alert("parsing [%s:%d] : %s: missing argument to store option '%s'.\n",
925 file, linenum, args[0], cw);
926 err_code |= ERR_ALERT | ERR_FATAL;
927 goto out;
928
929 case PE_ARG_NOT_USED:
930 ha_alert("parsing [%s:%d] : %s: unexpected argument to store option '%s'.\n",
931 file, linenum, args[0], cw);
932 err_code |= ERR_ALERT | ERR_FATAL;
933 goto out;
934
935 default:
936 ha_alert("parsing [%s:%d] : %s: error when processing store option '%s'.\n",
937 file, linenum, args[0], cw);
938 err_code |= ERR_ALERT | ERR_FATAL;
939 goto out;
940 }
941 }
942 idx++;
943 }
Thayne McCombs92149f92020-11-20 01:28:26 -0700944 else if (strcmp(args[idx], "srvkey") == 0) {
945 char *keytype;
946 idx++;
947 keytype = args[idx];
948 if (strcmp(keytype, "name") == 0) {
949 t->server_key_type = STKTABLE_SRV_NAME;
950 }
951 else if (strcmp(keytype, "addr") == 0) {
952 t->server_key_type = STKTABLE_SRV_ADDR;
953 }
954 else {
955 ha_alert("parsing [%s:%d] : %s : unknown server key type '%s'.\n",
956 file, linenum, args[0], keytype);
957 err_code |= ERR_ALERT | ERR_FATAL;
958 goto out;
959
960 }
961 idx++;
962 }
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100963 else {
964 ha_alert("parsing [%s:%d] : %s: unknown argument '%s'.\n",
965 file, linenum, args[0], args[idx]);
966 err_code |= ERR_ALERT | ERR_FATAL;
967 goto out;
968 }
969 }
970
971 if (!t->size) {
972 ha_alert("parsing [%s:%d] : %s: missing size.\n",
973 file, linenum, args[0]);
974 err_code |= ERR_ALERT | ERR_FATAL;
975 goto out;
976 }
977
978 if (t->type == (unsigned int)-1) {
979 ha_alert("parsing [%s:%d] : %s: missing type.\n",
980 file, linenum, args[0]);
981 err_code |= ERR_ALERT | ERR_FATAL;
982 goto out;
983 }
984
985 out:
986 return err_code;
987}
988
Willy Tarreau8fed9032014-07-03 17:02:46 +0200989/* Prepares a stktable_key from a sample <smp> to search into table <t>.
Willy Tarreauf0c730a2016-05-25 17:07:56 +0200990 * Note that the sample *is* modified and that the returned key may point
991 * to it, so the sample must not be modified afterwards before the lookup.
Willy Tarreau8fed9032014-07-03 17:02:46 +0200992 * Returns NULL if the sample could not be converted (eg: no matching type),
993 * otherwise a pointer to the static stktable_key filled with what is needed
994 * for the lookup.
Willy Tarreauf0b38bf2010-06-06 13:22:23 +0200995 */
Willy Tarreau8fed9032014-07-03 17:02:46 +0200996struct stktable_key *smp_to_stkey(struct sample *smp, struct stktable *t)
Willy Tarreauf0b38bf2010-06-06 13:22:23 +0200997{
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200998 /* Convert sample. */
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200999 if (!sample_convert(smp, t->type))
Willy Tarreau7fc1c6e2012-04-26 11:03:17 +02001000 return NULL;
1001
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001002 /* Fill static_table_key. */
1003 switch (t->type) {
Emeric Brun485479d2010-09-23 18:02:19 +02001004
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +02001005 case SMP_T_IPV4:
Christopher Fauletca20d022017-08-29 15:30:31 +02001006 static_table_key.key = &smp->data.u.ipv4;
1007 static_table_key.key_len = 4;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001008 break;
Emeric Brun485479d2010-09-23 18:02:19 +02001009
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +02001010 case SMP_T_IPV6:
Christopher Fauletca20d022017-08-29 15:30:31 +02001011 static_table_key.key = &smp->data.u.ipv6;
1012 static_table_key.key_len = 16;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001013 break;
Emeric Brun485479d2010-09-23 18:02:19 +02001014
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +02001015 case SMP_T_SINT:
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001016 /* The stick table require a 32bit unsigned int, "sint" is a
1017 * signed 64 it, so we can convert it inplace.
1018 */
Willy Tarreau28c63c12019-10-23 06:21:05 +02001019 smp->data.u.sint = (unsigned int)smp->data.u.sint;
Christopher Fauletca20d022017-08-29 15:30:31 +02001020 static_table_key.key = &smp->data.u.sint;
1021 static_table_key.key_len = 4;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001022 break;
1023
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +02001024 case SMP_T_STR:
Willy Tarreauce6955e2016-08-09 11:59:12 +02001025 if (!smp_make_safe(smp))
1026 return NULL;
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001027 static_table_key.key = smp->data.u.str.area;
1028 static_table_key.key_len = smp->data.u.str.data;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001029 break;
Emeric Brun485479d2010-09-23 18:02:19 +02001030
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +02001031 case SMP_T_BIN:
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001032 if (smp->data.u.str.data < t->key_size) {
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001033 /* This type needs padding with 0. */
Willy Tarreauf65c6c02016-08-09 12:08:41 +02001034 if (!smp_make_rw(smp))
1035 return NULL;
1036
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001037 if (smp->data.u.str.size < t->key_size)
1038 if (!smp_dup(smp))
1039 return NULL;
1040 if (smp->data.u.str.size < t->key_size)
1041 return NULL;
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001042 memset(smp->data.u.str.area + smp->data.u.str.data, 0,
1043 t->key_size - smp->data.u.str.data);
1044 smp->data.u.str.data = t->key_size;
Emeric Brun485479d2010-09-23 18:02:19 +02001045 }
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001046 static_table_key.key = smp->data.u.str.area;
1047 static_table_key.key_len = smp->data.u.str.data;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001048 break;
Emeric Brun485479d2010-09-23 18:02:19 +02001049
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001050 default: /* impossible case. */
1051 return NULL;
Emeric Brun485479d2010-09-23 18:02:19 +02001052 }
1053
Christopher Fauletca20d022017-08-29 15:30:31 +02001054 return &static_table_key;
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001055}
1056
1057/*
Willy Tarreau8fed9032014-07-03 17:02:46 +02001058 * Process a fetch + format conversion as defined by the sample expression <expr>
1059 * on request or response considering the <opt> parameter. Returns either NULL if
1060 * no key could be extracted, or a pointer to the converted result stored in
1061 * static_table_key in format <table_type>. If <smp> is not NULL, it will be reset
1062 * and its flags will be initialized so that the caller gets a copy of the input
Willy Tarreau6bcb0a82014-07-30 08:56:35 +02001063 * sample, and knows why it was not accepted (eg: SMP_F_MAY_CHANGE is present
1064 * without SMP_OPT_FINAL). The output will be usable like this :
1065 *
1066 * return MAY_CHANGE FINAL Meaning for the sample
1067 * NULL 0 * Not present and will never be (eg: header)
1068 * NULL 1 0 Not present or unstable, could change (eg: req_len)
1069 * NULL 1 1 Not present, will not change anymore
1070 * smp 0 * Present and will not change (eg: header)
1071 * smp 1 0 not possible
1072 * smp 1 1 Present, last known value (eg: request length)
Willy Tarreau8fed9032014-07-03 17:02:46 +02001073 */
Willy Tarreau192252e2015-04-04 01:47:55 +02001074struct stktable_key *stktable_fetch_key(struct stktable *t, struct proxy *px, struct session *sess, struct stream *strm,
Willy Tarreau8fed9032014-07-03 17:02:46 +02001075 unsigned int opt, struct sample_expr *expr, struct sample *smp)
1076{
1077 if (smp)
1078 memset(smp, 0, sizeof(*smp));
1079
Willy Tarreau192252e2015-04-04 01:47:55 +02001080 smp = sample_process(px, sess, strm, opt, expr, smp);
Willy Tarreau8fed9032014-07-03 17:02:46 +02001081 if (!smp)
1082 return NULL;
1083
1084 if ((smp->flags & SMP_F_MAY_CHANGE) && !(opt & SMP_OPT_FINAL))
1085 return NULL; /* we can only use stable samples */
1086
1087 return smp_to_stkey(smp, t);
1088}
1089
1090/*
Willy Tarreau12785782012-04-27 21:37:17 +02001091 * Returns 1 if sample expression <expr> result can be converted to table key of
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001092 * type <table_type>, otherwise zero. Used in configuration check.
1093 */
Willy Tarreau12785782012-04-27 21:37:17 +02001094int stktable_compatible_sample(struct sample_expr *expr, unsigned long table_type)
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001095{
Thierry FOURNIERf73eb8f2013-11-27 15:30:55 +01001096 int out_type;
1097
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +02001098 if (table_type >= SMP_TYPES || !stktable_types[table_type].kw)
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001099 return 0;
1100
Thierry FOURNIERf73eb8f2013-11-27 15:30:55 +01001101 out_type = smp_expr_output_type(expr);
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001102
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001103 /* Convert sample. */
1104 if (!sample_casts[out_type][table_type])
Thierry FOURNIERf73eb8f2013-11-27 15:30:55 +01001105 return 0;
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001106
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001107 return 1;
1108}
Emeric Brun3bd697e2010-01-04 15:23:48 +01001109
Willy Tarreauedee1d62014-07-15 16:44:27 +02001110/* Extra data types processing : after the last one, some room may remain
1111 * before STKTABLE_DATA_TYPES that may be used to register extra data types
1112 * at run time.
1113 */
Willy Tarreau08d5f982010-06-06 13:34:54 +02001114struct stktable_data_type stktable_data_types[STKTABLE_DATA_TYPES] = {
Willy Tarreau3b9c6e02010-07-18 08:04:30 +02001115 [STKTABLE_DT_SERVER_ID] = { .name = "server_id", .std_type = STD_T_SINT },
Thierry FOURNIER3cf11112015-07-28 08:57:05 +02001116 [STKTABLE_DT_GPT0] = { .name = "gpt0", .std_type = STD_T_UINT },
Willy Tarreau3b9c6e02010-07-18 08:04:30 +02001117 [STKTABLE_DT_GPC0] = { .name = "gpc0", .std_type = STD_T_UINT },
Willy Tarreauba2ffd12013-05-29 15:54:14 +02001118 [STKTABLE_DT_GPC0_RATE] = { .name = "gpc0_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
Willy Tarreau3b9c6e02010-07-18 08:04:30 +02001119 [STKTABLE_DT_CONN_CNT] = { .name = "conn_cnt", .std_type = STD_T_UINT },
1120 [STKTABLE_DT_CONN_RATE] = { .name = "conn_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
1121 [STKTABLE_DT_CONN_CUR] = { .name = "conn_cur", .std_type = STD_T_UINT },
1122 [STKTABLE_DT_SESS_CNT] = { .name = "sess_cnt", .std_type = STD_T_UINT },
1123 [STKTABLE_DT_SESS_RATE] = { .name = "sess_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
1124 [STKTABLE_DT_HTTP_REQ_CNT] = { .name = "http_req_cnt", .std_type = STD_T_UINT },
1125 [STKTABLE_DT_HTTP_REQ_RATE] = { .name = "http_req_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
1126 [STKTABLE_DT_HTTP_ERR_CNT] = { .name = "http_err_cnt", .std_type = STD_T_UINT },
1127 [STKTABLE_DT_HTTP_ERR_RATE] = { .name = "http_err_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
1128 [STKTABLE_DT_BYTES_IN_CNT] = { .name = "bytes_in_cnt", .std_type = STD_T_ULL },
1129 [STKTABLE_DT_BYTES_IN_RATE] = { .name = "bytes_in_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
1130 [STKTABLE_DT_BYTES_OUT_CNT] = { .name = "bytes_out_cnt", .std_type = STD_T_ULL },
1131 [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 +01001132 [STKTABLE_DT_GPC1] = { .name = "gpc1", .std_type = STD_T_UINT },
1133 [STKTABLE_DT_GPC1_RATE] = { .name = "gpc1_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
Thayne McCombs92149f92020-11-20 01:28:26 -07001134 [STKTABLE_DT_SERVER_KEY] = { .name = "server_key", .std_type = STD_T_DICT },
Willy Tarreau826f3ab2021-02-10 12:07:15 +01001135 [STKTABLE_DT_HTTP_FAIL_CNT] = { .name = "http_fail_cnt", .std_type = STD_T_UINT },
1136 [STKTABLE_DT_HTTP_FAIL_RATE]= { .name = "http_fail_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
Willy Tarreau08d5f982010-06-06 13:34:54 +02001137};
1138
Willy Tarreauedee1d62014-07-15 16:44:27 +02001139/* Registers stick-table extra data type with index <idx>, name <name>, type
1140 * <std_type> and arg type <arg_type>. If the index is negative, the next free
1141 * index is automatically allocated. The allocated index is returned, or -1 if
1142 * no free index was found or <name> was already registered. The <name> is used
1143 * directly as a pointer, so if it's not stable, the caller must allocate it.
1144 */
1145int stktable_register_data_store(int idx, const char *name, int std_type, int arg_type)
1146{
1147 if (idx < 0) {
1148 for (idx = 0; idx < STKTABLE_DATA_TYPES; idx++) {
1149 if (!stktable_data_types[idx].name)
1150 break;
1151
1152 if (strcmp(stktable_data_types[idx].name, name) == 0)
1153 return -1;
1154 }
1155 }
1156
1157 if (idx >= STKTABLE_DATA_TYPES)
1158 return -1;
1159
1160 if (stktable_data_types[idx].name != NULL)
1161 return -1;
1162
1163 stktable_data_types[idx].name = name;
1164 stktable_data_types[idx].std_type = std_type;
1165 stktable_data_types[idx].arg_type = arg_type;
1166 return idx;
1167}
1168
Willy Tarreau08d5f982010-06-06 13:34:54 +02001169/*
1170 * Returns the data type number for the stktable_data_type whose name is <name>,
1171 * or <0 if not found.
1172 */
1173int stktable_get_data_type(char *name)
1174{
1175 int type;
1176
1177 for (type = 0; type < STKTABLE_DATA_TYPES; type++) {
Willy Tarreauedee1d62014-07-15 16:44:27 +02001178 if (!stktable_data_types[type].name)
1179 continue;
Willy Tarreau08d5f982010-06-06 13:34:54 +02001180 if (strcmp(name, stktable_data_types[type].name) == 0)
1181 return type;
1182 }
Thayne McCombs92149f92020-11-20 01:28:26 -07001183 /* For backwards compatibility */
1184 if (strcmp(name, "server_name") == 0)
1185 return STKTABLE_DT_SERVER_KEY;
Willy Tarreau08d5f982010-06-06 13:34:54 +02001186 return -1;
1187}
1188
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001189/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1190 * it up into this table. Returns true if found, false otherwise. The input
1191 * type is STR so that input samples are converted to string (since all types
1192 * can be converted to strings), then the function casts the string again into
1193 * the table's type. This is a double conversion, but in the future we might
1194 * support automatic input types to perform the cast on the fly.
1195 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001196static int sample_conv_in_table(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001197{
1198 struct stktable *t;
1199 struct stktable_key *key;
1200 struct stksess *ts;
1201
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001202 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001203
1204 key = smp_to_stkey(smp, t);
1205 if (!key)
1206 return 0;
1207
1208 ts = stktable_lookup_key(t, key);
1209
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001210 smp->data.type = SMP_T_BOOL;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001211 smp->data.u.sint = !!ts;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001212 smp->flags = SMP_F_VOL_TEST;
Willy Tarreau43e90352018-06-27 06:25:57 +02001213 stktable_release(t, ts);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001214 return 1;
1215}
1216
1217/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1218 * it up into this table. Returns the data rate received from clients in bytes/s
1219 * if the key is present in the table, otherwise zero, so that comparisons can
1220 * be easily performed. If the inspected parameter is not stored in the table,
1221 * <not found> is returned.
1222 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001223static int sample_conv_table_bytes_in_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001224{
1225 struct stktable *t;
1226 struct stktable_key *key;
1227 struct stksess *ts;
1228 void *ptr;
1229
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001230 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001231
1232 key = smp_to_stkey(smp, t);
1233 if (!key)
1234 return 0;
1235
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001236 ts = stktable_lookup_key(t, key);
1237
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001238 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001239 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001240 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001241
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001242 if (!ts) /* key not present */
1243 return 1;
1244
1245 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_IN_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001246 if (ptr)
1247 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, bytes_in_rate),
1248 t->data_arg[STKTABLE_DT_BYTES_IN_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001249
Daniel Corbett3e60b112018-05-27 09:47:12 -04001250 stktable_release(t, ts);
1251 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001252}
1253
1254/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1255 * it up into this table. Returns the cumulated number of connections for the key
1256 * if the key is present in the table, otherwise zero, so that comparisons can
1257 * be easily performed. If the inspected parameter is not stored in the table,
1258 * <not found> is returned.
1259 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001260static int sample_conv_table_conn_cnt(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001261{
1262 struct stktable *t;
1263 struct stktable_key *key;
1264 struct stksess *ts;
1265 void *ptr;
1266
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001267 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001268
1269 key = smp_to_stkey(smp, t);
1270 if (!key)
1271 return 0;
1272
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001273 ts = stktable_lookup_key(t, key);
1274
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001275 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001276 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001277 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001278
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001279 if (!ts) /* key not present */
1280 return 1;
1281
1282 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_CONN_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001283 if (ptr)
1284 smp->data.u.sint = stktable_data_cast(ptr, conn_cnt);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001285
Daniel Corbett3e60b112018-05-27 09:47:12 -04001286 stktable_release(t, ts);
1287 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001288}
1289
1290/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1291 * it up into this table. Returns the number of concurrent connections for the
1292 * key if the key is present in the table, otherwise zero, so that comparisons
1293 * can be easily performed. If the inspected parameter is not stored in the
1294 * table, <not found> is returned.
1295 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001296static int sample_conv_table_conn_cur(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001297{
1298 struct stktable *t;
1299 struct stktable_key *key;
1300 struct stksess *ts;
1301 void *ptr;
1302
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001303 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001304
1305 key = smp_to_stkey(smp, t);
1306 if (!key)
1307 return 0;
1308
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001309 ts = stktable_lookup_key(t, key);
1310
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001311 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001312 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001313 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001314
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001315 if (!ts) /* key not present */
1316 return 1;
1317
1318 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_CONN_CUR);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001319 if (ptr)
1320 smp->data.u.sint = stktable_data_cast(ptr, conn_cur);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001321
Daniel Corbett3e60b112018-05-27 09:47:12 -04001322 stktable_release(t, ts);
1323 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001324}
1325
1326/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1327 * it up into this table. Returns the rate of incoming connections from the key
1328 * if the key is present in the table, otherwise zero, so that comparisons can
1329 * be easily performed. If the inspected parameter is not stored in the table,
1330 * <not found> is returned.
1331 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001332static int sample_conv_table_conn_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001333{
1334 struct stktable *t;
1335 struct stktable_key *key;
1336 struct stksess *ts;
1337 void *ptr;
1338
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001339 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001340
1341 key = smp_to_stkey(smp, t);
1342 if (!key)
1343 return 0;
1344
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001345 ts = stktable_lookup_key(t, key);
1346
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001347 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001348 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001349 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001350
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001351 if (!ts) /* key not present */
1352 return 1;
1353
1354 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_CONN_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001355 if (ptr)
1356 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, conn_rate),
1357 t->data_arg[STKTABLE_DT_CONN_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001358
Daniel Corbett3e60b112018-05-27 09:47:12 -04001359 stktable_release(t, ts);
1360 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001361}
1362
1363/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1364 * it up into this table. Returns the data rate sent to clients in bytes/s
1365 * if the key is present in the table, otherwise zero, so that comparisons can
1366 * be easily performed. If the inspected parameter is not stored in the table,
1367 * <not found> is returned.
1368 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001369static int sample_conv_table_bytes_out_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001370{
1371 struct stktable *t;
1372 struct stktable_key *key;
1373 struct stksess *ts;
1374 void *ptr;
1375
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001376 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001377
1378 key = smp_to_stkey(smp, t);
1379 if (!key)
1380 return 0;
1381
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001382 ts = stktable_lookup_key(t, key);
1383
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001384 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001385 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001386 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001387
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001388 if (!ts) /* key not present */
1389 return 1;
1390
1391 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_OUT_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001392 if (ptr)
1393 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, bytes_out_rate),
1394 t->data_arg[STKTABLE_DT_BYTES_OUT_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001395
Daniel Corbett3e60b112018-05-27 09:47:12 -04001396 stktable_release(t, ts);
1397 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001398}
1399
1400/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001401 * it up into this table. Returns the value of the GPT0 tag for the key
1402 * if the key is present in the table, otherwise false, so that comparisons can
1403 * be easily performed. If the inspected parameter is not stored in the table,
1404 * <not found> is returned.
1405 */
1406static int sample_conv_table_gpt0(const struct arg *arg_p, struct sample *smp, void *private)
1407{
1408 struct stktable *t;
1409 struct stktable_key *key;
1410 struct stksess *ts;
1411 void *ptr;
1412
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001413 t = arg_p[0].data.t;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001414
1415 key = smp_to_stkey(smp, t);
1416 if (!key)
1417 return 0;
1418
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001419 ts = stktable_lookup_key(t, key);
1420
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001421 smp->flags = SMP_F_VOL_TEST;
1422 smp->data.type = SMP_T_SINT;
1423 smp->data.u.sint = 0;
1424
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001425 if (!ts) /* key not present */
1426 return 1;
1427
1428 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPT0);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001429 if (ptr)
1430 smp->data.u.sint = stktable_data_cast(ptr, gpt0);
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001431
Daniel Corbett3e60b112018-05-27 09:47:12 -04001432 stktable_release(t, ts);
1433 return !!ptr;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001434}
1435
1436/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001437 * it up into this table. Returns the value of the GPC0 counter for the key
1438 * if the key is present in the table, otherwise zero, so that comparisons can
1439 * be easily performed. If the inspected parameter is not stored in the table,
1440 * <not found> is returned.
1441 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001442static int sample_conv_table_gpc0(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001443{
1444 struct stktable *t;
1445 struct stktable_key *key;
1446 struct stksess *ts;
1447 void *ptr;
1448
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001449 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001450
1451 key = smp_to_stkey(smp, t);
1452 if (!key)
1453 return 0;
1454
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001455 ts = stktable_lookup_key(t, key);
1456
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001457 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001458 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001459 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001460
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001461 if (!ts) /* key not present */
1462 return 1;
1463
1464 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPC0);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001465 if (ptr)
1466 smp->data.u.sint = stktable_data_cast(ptr, gpc0);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001467
Daniel Corbett3e60b112018-05-27 09:47:12 -04001468 stktable_release(t, ts);
1469 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001470}
1471
1472/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1473 * it up into this table. Returns the event rate of the GPC0 counter for the key
1474 * if the key is present in the table, otherwise zero, so that comparisons can
1475 * be easily performed. If the inspected parameter is not stored in the table,
1476 * <not found> is returned.
1477 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001478static int sample_conv_table_gpc0_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001479{
1480 struct stktable *t;
1481 struct stktable_key *key;
1482 struct stksess *ts;
1483 void *ptr;
1484
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001485 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001486
1487 key = smp_to_stkey(smp, t);
1488 if (!key)
1489 return 0;
1490
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001491 ts = stktable_lookup_key(t, key);
1492
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001493 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001494 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001495 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001496
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001497 if (!ts) /* key not present */
1498 return 1;
1499
1500 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPC0_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001501 if (ptr)
1502 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, gpc0_rate),
1503 t->data_arg[STKTABLE_DT_GPC0_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001504
Daniel Corbett3e60b112018-05-27 09:47:12 -04001505 stktable_release(t, ts);
1506 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001507}
1508
1509/* 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 +01001510 * it up into this table. Returns the value of the GPC1 counter for the key
1511 * if the key is present in the table, otherwise zero, so that comparisons can
1512 * be easily performed. If the inspected parameter is not stored in the table,
1513 * <not found> is returned.
1514 */
1515static int sample_conv_table_gpc1(const struct arg *arg_p, struct sample *smp, void *private)
1516{
1517 struct stktable *t;
1518 struct stktable_key *key;
1519 struct stksess *ts;
1520 void *ptr;
1521
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001522 t = arg_p[0].data.t;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001523
1524 key = smp_to_stkey(smp, t);
1525 if (!key)
1526 return 0;
1527
1528 ts = stktable_lookup_key(t, key);
1529
1530 smp->flags = SMP_F_VOL_TEST;
1531 smp->data.type = SMP_T_SINT;
1532 smp->data.u.sint = 0;
1533
1534 if (!ts) /* key not present */
1535 return 1;
1536
1537 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPC1);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001538 if (ptr)
1539 smp->data.u.sint = stktable_data_cast(ptr, gpc1);
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001540
Daniel Corbett3e60b112018-05-27 09:47:12 -04001541 stktable_release(t, ts);
1542 return !!ptr;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001543}
1544
1545/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1546 * it up into this table. Returns the event rate of the GPC1 counter for the key
1547 * if the key is present in the table, otherwise zero, so that comparisons can
1548 * be easily performed. If the inspected parameter is not stored in the table,
1549 * <not found> is returned.
1550 */
1551static int sample_conv_table_gpc1_rate(const struct arg *arg_p, struct sample *smp, void *private)
1552{
1553 struct stktable *t;
1554 struct stktable_key *key;
1555 struct stksess *ts;
1556 void *ptr;
1557
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001558 t = arg_p[0].data.t;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001559
1560 key = smp_to_stkey(smp, t);
1561 if (!key)
1562 return 0;
1563
1564 ts = stktable_lookup_key(t, key);
1565
1566 smp->flags = SMP_F_VOL_TEST;
1567 smp->data.type = SMP_T_SINT;
1568 smp->data.u.sint = 0;
1569
1570 if (!ts) /* key not present */
1571 return 1;
1572
1573 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPC1_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001574 if (ptr)
1575 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, gpc1_rate),
1576 t->data_arg[STKTABLE_DT_GPC1_RATE].u);
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001577
Daniel Corbett3e60b112018-05-27 09:47:12 -04001578 stktable_release(t, ts);
1579 return !!ptr;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001580}
1581
1582/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001583 * it up into this table. Returns the cumulated number of HTTP request errors
1584 * for the key if the key is present in the table, otherwise zero, so that
1585 * comparisons can be easily performed. If the inspected parameter is not stored
1586 * in the table, <not found> is returned.
1587 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001588static int sample_conv_table_http_err_cnt(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001589{
1590 struct stktable *t;
1591 struct stktable_key *key;
1592 struct stksess *ts;
1593 void *ptr;
1594
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001595 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001596
1597 key = smp_to_stkey(smp, t);
1598 if (!key)
1599 return 0;
1600
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001601 ts = stktable_lookup_key(t, key);
1602
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001603 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001604 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001605 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001606
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001607 if (!ts) /* key not present */
1608 return 1;
1609
1610 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_ERR_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001611 if (ptr)
1612 smp->data.u.sint = stktable_data_cast(ptr, http_err_cnt);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001613
Daniel Corbett3e60b112018-05-27 09:47:12 -04001614 stktable_release(t, ts);
1615 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001616}
1617
1618/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1619 * it up into this table. Returns the HTTP request error rate the key
1620 * if the key is present in the table, otherwise zero, so that comparisons can
1621 * be easily performed. If the inspected parameter is not stored in the table,
1622 * <not found> is returned.
1623 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001624static int sample_conv_table_http_err_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001625{
1626 struct stktable *t;
1627 struct stktable_key *key;
1628 struct stksess *ts;
1629 void *ptr;
1630
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001631 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001632
1633 key = smp_to_stkey(smp, t);
1634 if (!key)
1635 return 0;
1636
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001637 ts = stktable_lookup_key(t, key);
1638
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001639 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001640 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001641 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001642
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001643 if (!ts) /* key not present */
1644 return 1;
1645
1646 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_ERR_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001647 if (ptr)
1648 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, http_err_rate),
1649 t->data_arg[STKTABLE_DT_HTTP_ERR_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001650
Daniel Corbett3e60b112018-05-27 09:47:12 -04001651 stktable_release(t, ts);
1652 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001653}
1654
1655/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Willy Tarreau826f3ab2021-02-10 12:07:15 +01001656 * it up into this table. Returns the cumulated number of HTTP response failures
1657 * for the key if the key is present in the table, otherwise zero, so that
1658 * comparisons can be easily performed. If the inspected parameter is not stored
1659 * in the table, <not found> is returned.
1660 */
1661static int sample_conv_table_http_fail_cnt(const struct arg *arg_p, struct sample *smp, void *private)
1662{
1663 struct stktable *t;
1664 struct stktable_key *key;
1665 struct stksess *ts;
1666 void *ptr;
1667
1668 t = arg_p[0].data.t;
1669
1670 key = smp_to_stkey(smp, t);
1671 if (!key)
1672 return 0;
1673
1674 ts = stktable_lookup_key(t, key);
1675
1676 smp->flags = SMP_F_VOL_TEST;
1677 smp->data.type = SMP_T_SINT;
1678 smp->data.u.sint = 0;
1679
1680 if (!ts) /* key not present */
1681 return 1;
1682
1683 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_FAIL_CNT);
1684 if (ptr)
1685 smp->data.u.sint = stktable_data_cast(ptr, http_fail_cnt);
1686
1687 stktable_release(t, ts);
1688 return !!ptr;
1689}
1690
1691/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1692 * it up into this table. Returns the HTTP response failure rate for the key
1693 * if the key is present in the table, otherwise zero, so that comparisons can
1694 * be easily performed. If the inspected parameter is not stored in the table,
1695 * <not found> is returned.
1696 */
1697static int sample_conv_table_http_fail_rate(const struct arg *arg_p, struct sample *smp, void *private)
1698{
1699 struct stktable *t;
1700 struct stktable_key *key;
1701 struct stksess *ts;
1702 void *ptr;
1703
1704 t = arg_p[0].data.t;
1705
1706 key = smp_to_stkey(smp, t);
1707 if (!key)
1708 return 0;
1709
1710 ts = stktable_lookup_key(t, key);
1711
1712 smp->flags = SMP_F_VOL_TEST;
1713 smp->data.type = SMP_T_SINT;
1714 smp->data.u.sint = 0;
1715
1716 if (!ts) /* key not present */
1717 return 1;
1718
1719 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_FAIL_RATE);
1720 if (ptr)
1721 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, http_fail_rate),
1722 t->data_arg[STKTABLE_DT_HTTP_FAIL_RATE].u);
1723
1724 stktable_release(t, ts);
1725 return !!ptr;
1726}
1727
1728/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001729 * it up into this table. Returns the cumulated number of HTTP request for the
1730 * key if the key is present in the table, otherwise zero, so that comparisons
1731 * can be easily performed. If the inspected parameter is not stored in the
1732 * table, <not found> is returned.
1733 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001734static int sample_conv_table_http_req_cnt(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001735{
1736 struct stktable *t;
1737 struct stktable_key *key;
1738 struct stksess *ts;
1739 void *ptr;
1740
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001741 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001742
1743 key = smp_to_stkey(smp, t);
1744 if (!key)
1745 return 0;
1746
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001747 ts = stktable_lookup_key(t, key);
1748
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001749 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001750 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001751 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001752
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001753 if (!ts) /* key not present */
1754 return 1;
1755
1756 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_REQ_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001757 if (ptr)
1758 smp->data.u.sint = stktable_data_cast(ptr, http_req_cnt);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001759
Daniel Corbett3e60b112018-05-27 09:47:12 -04001760 stktable_release(t, ts);
1761 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001762}
1763
1764/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1765 * it up into this table. Returns the HTTP request rate the key if the key is
1766 * present in the table, otherwise zero, so that comparisons can be easily
1767 * performed. If the inspected parameter is not stored in the table, <not found>
1768 * is returned.
1769 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001770static int sample_conv_table_http_req_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001771{
1772 struct stktable *t;
1773 struct stktable_key *key;
1774 struct stksess *ts;
1775 void *ptr;
1776
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001777 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001778
1779 key = smp_to_stkey(smp, t);
1780 if (!key)
1781 return 0;
1782
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001783 ts = stktable_lookup_key(t, key);
1784
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001785 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001786 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001787 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001788
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001789 if (!ts) /* key not present */
1790 return 1;
1791
1792 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_REQ_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001793 if (ptr)
1794 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, http_req_rate),
1795 t->data_arg[STKTABLE_DT_HTTP_REQ_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001796
Daniel Corbett3e60b112018-05-27 09:47:12 -04001797 stktable_release(t, ts);
1798 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001799}
1800
1801/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1802 * it up into this table. Returns the volume of datareceived from clients in kbytes
1803 * if the key is present in the table, otherwise zero, so that comparisons can
1804 * be easily performed. If the inspected parameter is not stored in the table,
1805 * <not found> is returned.
1806 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001807static int sample_conv_table_kbytes_in(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001808{
1809 struct stktable *t;
1810 struct stktable_key *key;
1811 struct stksess *ts;
1812 void *ptr;
1813
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001814 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001815
1816 key = smp_to_stkey(smp, t);
1817 if (!key)
1818 return 0;
1819
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001820 ts = stktable_lookup_key(t, key);
1821
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001822 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001823 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001824 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001825
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001826 if (!ts) /* key not present */
1827 return 1;
1828
1829 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_IN_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001830 if (ptr)
1831 smp->data.u.sint = stktable_data_cast(ptr, bytes_in_cnt) >> 10;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001832
Daniel Corbett3e60b112018-05-27 09:47:12 -04001833 stktable_release(t, ts);
1834 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001835}
1836
1837/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1838 * it up into this table. Returns the volume of data sent to clients in kbytes
1839 * if the key is present in the table, otherwise zero, so that comparisons can
1840 * be easily performed. If the inspected parameter is not stored in the table,
1841 * <not found> is returned.
1842 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001843static int sample_conv_table_kbytes_out(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001844{
1845 struct stktable *t;
1846 struct stktable_key *key;
1847 struct stksess *ts;
1848 void *ptr;
1849
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001850 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001851
1852 key = smp_to_stkey(smp, t);
1853 if (!key)
1854 return 0;
1855
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001856 ts = stktable_lookup_key(t, key);
1857
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001858 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001859 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001860 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001861
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001862 if (!ts) /* key not present */
1863 return 1;
1864
1865 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_OUT_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001866 if (ptr)
1867 smp->data.u.sint = stktable_data_cast(ptr, bytes_out_cnt) >> 10;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001868
Daniel Corbett3e60b112018-05-27 09:47:12 -04001869 stktable_release(t, ts);
1870 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001871}
1872
1873/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1874 * it up into this table. Returns the server ID associated with the key if the
1875 * key is present in the table, otherwise zero, so that comparisons can be
1876 * easily performed. If the inspected parameter is not stored in the table,
1877 * <not found> is returned.
1878 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001879static int sample_conv_table_server_id(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001880{
1881 struct stktable *t;
1882 struct stktable_key *key;
1883 struct stksess *ts;
1884 void *ptr;
1885
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001886 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001887
1888 key = smp_to_stkey(smp, t);
1889 if (!key)
1890 return 0;
1891
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001892 ts = stktable_lookup_key(t, key);
1893
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001894 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001895 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001896 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001897
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001898 if (!ts) /* key not present */
1899 return 1;
1900
1901 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_SERVER_ID);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001902 if (ptr)
1903 smp->data.u.sint = stktable_data_cast(ptr, server_id);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001904
Daniel Corbett3e60b112018-05-27 09:47:12 -04001905 stktable_release(t, ts);
1906 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001907}
1908
1909/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1910 * it up into this table. Returns the cumulated number of sessions for the
1911 * key if the key is present in the table, otherwise zero, so that comparisons
1912 * can be easily performed. If the inspected parameter is not stored in the
1913 * table, <not found> is returned.
1914 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001915static int sample_conv_table_sess_cnt(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001916{
1917 struct stktable *t;
1918 struct stktable_key *key;
1919 struct stksess *ts;
1920 void *ptr;
1921
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001922 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001923
1924 key = smp_to_stkey(smp, t);
1925 if (!key)
1926 return 0;
1927
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001928 ts = stktable_lookup_key(t, key);
1929
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001930 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001931 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001932 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001933
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001934 if (!ts) /* key not present */
1935 return 1;
1936
1937 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_SESS_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001938 if (ptr)
1939 smp->data.u.sint = stktable_data_cast(ptr, sess_cnt);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001940
Daniel Corbett3e60b112018-05-27 09:47:12 -04001941 stktable_release(t, ts);
1942 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001943}
1944
1945/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1946 * it up into this table. Returns the session rate the key if the key is
1947 * present in the table, otherwise zero, so that comparisons can be easily
1948 * performed. If the inspected parameter is not stored in the table, <not found>
1949 * is returned.
1950 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001951static int sample_conv_table_sess_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001952{
1953 struct stktable *t;
1954 struct stktable_key *key;
1955 struct stksess *ts;
1956 void *ptr;
1957
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001958 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001959
1960 key = smp_to_stkey(smp, t);
1961 if (!key)
1962 return 0;
1963
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001964 ts = stktable_lookup_key(t, key);
1965
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001966 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001967 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001968 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001969
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001970 if (!ts) /* key not present */
1971 return 1;
1972
1973 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_SESS_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001974 if (ptr)
1975 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, sess_rate),
1976 t->data_arg[STKTABLE_DT_SESS_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001977
Daniel Corbett3e60b112018-05-27 09:47:12 -04001978 stktable_release(t, ts);
1979 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001980}
1981
1982/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1983 * it up into this table. Returns the amount of concurrent connections tracking
1984 * the same key if the key is present in the table, otherwise zero, so that
1985 * comparisons can be easily performed. If the inspected parameter is not
1986 * stored in the table, <not found> is returned.
1987 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001988static int sample_conv_table_trackers(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001989{
1990 struct stktable *t;
1991 struct stktable_key *key;
1992 struct stksess *ts;
1993
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001994 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001995
1996 key = smp_to_stkey(smp, t);
1997 if (!key)
1998 return 0;
1999
Willy Tarreauf0c730a2016-05-25 17:07:56 +02002000 ts = stktable_lookup_key(t, key);
2001
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002002 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02002003 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02002004 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002005
Tim Duesterhus65189c12018-06-26 15:57:29 +02002006 if (!ts)
2007 return 1;
2008
2009 smp->data.u.sint = ts->ref_cnt;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002010
Daniel Corbett3e60b112018-05-27 09:47:12 -04002011 stktable_release(t, ts);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002012 return 1;
2013}
2014
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002015/* Always returns 1. */
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002016static enum act_return action_inc_gpc0(struct act_rule *rule, struct proxy *px,
Willy Tarreau658b85b2015-09-27 10:00:49 +02002017 struct session *sess, struct stream *s, int flags)
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002018{
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002019 struct stksess *ts;
2020 struct stkctr *stkctr;
2021
2022 /* Extract the stksess, return OK if no stksess available. */
2023 if (s)
2024 stkctr = &s->stkctr[rule->arg.gpc.sc];
2025 else
2026 stkctr = &sess->stkctr[rule->arg.gpc.sc];
Willy Tarreau79c1e912016-01-25 14:54:45 +01002027
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002028 ts = stkctr_entry(stkctr);
Willy Tarreau79c1e912016-01-25 14:54:45 +01002029 if (ts) {
2030 void *ptr1, *ptr2;
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002031
Willy Tarreau79c1e912016-01-25 14:54:45 +01002032 /* First, update gpc0_rate if it's tracked. Second, update its gpc0 if tracked. */
2033 ptr1 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC0_RATE);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002034 ptr2 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC0);
2035 if (ptr1 || ptr2) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002036 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002037
2038 if (ptr1)
2039 update_freq_ctr_period(&stktable_data_cast(ptr1, gpc0_rate),
Willy Tarreau79c1e912016-01-25 14:54:45 +01002040 stkctr->table->data_arg[STKTABLE_DT_GPC0_RATE].u, 1);
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002041
Emeric Brun819fc6f2017-06-13 19:37:32 +02002042 if (ptr2)
2043 stktable_data_cast(ptr2, gpc0)++;
Willy Tarreau79c1e912016-01-25 14:54:45 +01002044
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002045 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002046
2047 /* If data was modified, we need to touch to re-schedule sync */
2048 stktable_touch_local(stkctr->table, ts, 0);
2049 }
Willy Tarreau79c1e912016-01-25 14:54:45 +01002050 }
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002051 return ACT_RET_CONT;
2052}
2053
2054/* This function is a common parser for using variables. It understands
2055 * the formats:
2056 *
2057 * sc-inc-gpc0(<stick-table ID>)
2058 *
2059 * It returns 0 if fails and <err> is filled with an error message. Otherwise,
2060 * it returns 1 and the variable <expr> is filled with the pointer to the
2061 * expression to execute.
2062 */
2063static enum act_parse_ret parse_inc_gpc0(const char **args, int *arg, struct proxy *px,
2064 struct act_rule *rule, char **err)
2065{
2066 const char *cmd_name = args[*arg-1];
2067 char *error;
2068
2069 cmd_name += strlen("sc-inc-gpc0");
2070 if (*cmd_name == '\0') {
2071 /* default stick table id. */
2072 rule->arg.gpc.sc = 0;
2073 } else {
2074 /* parse the stick table id. */
2075 if (*cmd_name != '(') {
2076 memprintf(err, "invalid stick table track ID. Expects %s(<Track ID>)", args[*arg-1]);
2077 return ACT_RET_PRS_ERR;
2078 }
2079 cmd_name++; /* jump the '(' */
2080 rule->arg.gpc.sc = strtol(cmd_name, &error, 10); /* Convert stick table id. */
2081 if (*error != ')') {
2082 memprintf(err, "invalid stick table track ID. Expects %s(<Track ID>)", args[*arg-1]);
2083 return ACT_RET_PRS_ERR;
2084 }
2085
Christopher Faulet28436e22019-12-18 10:25:46 +01002086 if (rule->arg.gpc.sc >= MAX_SESS_STKCTR) {
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002087 memprintf(err, "invalid stick table track ID. The max allowed ID is %d",
Christopher Faulet28436e22019-12-18 10:25:46 +01002088 MAX_SESS_STKCTR-1);
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002089 return ACT_RET_PRS_ERR;
2090 }
2091 }
Thierry FOURNIER42148732015-09-02 17:17:33 +02002092 rule->action = ACT_CUSTOM;
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002093 rule->action_ptr = action_inc_gpc0;
2094 return ACT_RET_PRS_OK;
2095}
2096
2097/* Always returns 1. */
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002098static enum act_return action_inc_gpc1(struct act_rule *rule, struct proxy *px,
2099 struct session *sess, struct stream *s, int flags)
2100{
2101 struct stksess *ts;
2102 struct stkctr *stkctr;
2103
2104 /* Extract the stksess, return OK if no stksess available. */
2105 if (s)
2106 stkctr = &s->stkctr[rule->arg.gpc.sc];
2107 else
2108 stkctr = &sess->stkctr[rule->arg.gpc.sc];
2109
2110 ts = stkctr_entry(stkctr);
2111 if (ts) {
2112 void *ptr1, *ptr2;
2113
2114 /* First, update gpc1_rate if it's tracked. Second, update its gpc1 if tracked. */
2115 ptr1 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC1_RATE);
2116 ptr2 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC1);
2117 if (ptr1 || ptr2) {
2118 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
2119
2120 if (ptr1)
2121 update_freq_ctr_period(&stktable_data_cast(ptr1, gpc1_rate),
2122 stkctr->table->data_arg[STKTABLE_DT_GPC1_RATE].u, 1);
2123
2124 if (ptr2)
2125 stktable_data_cast(ptr2, gpc1)++;
2126
2127 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
2128
2129 /* If data was modified, we need to touch to re-schedule sync */
2130 stktable_touch_local(stkctr->table, ts, 0);
2131 }
2132 }
2133 return ACT_RET_CONT;
2134}
2135
2136/* This function is a common parser for using variables. It understands
2137 * the formats:
2138 *
2139 * sc-inc-gpc1(<stick-table ID>)
2140 *
2141 * It returns 0 if fails and <err> is filled with an error message. Otherwise,
2142 * it returns 1 and the variable <expr> is filled with the pointer to the
2143 * expression to execute.
2144 */
2145static enum act_parse_ret parse_inc_gpc1(const char **args, int *arg, struct proxy *px,
2146 struct act_rule *rule, char **err)
2147{
2148 const char *cmd_name = args[*arg-1];
2149 char *error;
2150
2151 cmd_name += strlen("sc-inc-gpc1");
2152 if (*cmd_name == '\0') {
2153 /* default stick table id. */
2154 rule->arg.gpc.sc = 0;
2155 } else {
2156 /* parse the stick table id. */
2157 if (*cmd_name != '(') {
2158 memprintf(err, "invalid stick table track ID. Expects %s(<Track ID>)", args[*arg-1]);
2159 return ACT_RET_PRS_ERR;
2160 }
2161 cmd_name++; /* jump the '(' */
2162 rule->arg.gpc.sc = strtol(cmd_name, &error, 10); /* Convert stick table id. */
2163 if (*error != ')') {
2164 memprintf(err, "invalid stick table track ID. Expects %s(<Track ID>)", args[*arg-1]);
2165 return ACT_RET_PRS_ERR;
2166 }
2167
Christopher Faulet28436e22019-12-18 10:25:46 +01002168 if (rule->arg.gpc.sc >= MAX_SESS_STKCTR) {
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002169 memprintf(err, "invalid stick table track ID. The max allowed ID is %d",
Christopher Faulet28436e22019-12-18 10:25:46 +01002170 MAX_SESS_STKCTR-1);
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002171 return ACT_RET_PRS_ERR;
2172 }
2173 }
2174 rule->action = ACT_CUSTOM;
2175 rule->action_ptr = action_inc_gpc1;
2176 return ACT_RET_PRS_OK;
2177}
2178
2179/* Always returns 1. */
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002180static enum act_return action_set_gpt0(struct act_rule *rule, struct proxy *px,
Willy Tarreau658b85b2015-09-27 10:00:49 +02002181 struct session *sess, struct stream *s, int flags)
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002182{
2183 void *ptr;
2184 struct stksess *ts;
2185 struct stkctr *stkctr;
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002186 unsigned int value = 0;
2187 struct sample *smp;
2188 int smp_opt_dir;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002189
2190 /* Extract the stksess, return OK if no stksess available. */
2191 if (s)
2192 stkctr = &s->stkctr[rule->arg.gpt.sc];
2193 else
2194 stkctr = &sess->stkctr[rule->arg.gpt.sc];
Willy Tarreau79c1e912016-01-25 14:54:45 +01002195
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002196 ts = stkctr_entry(stkctr);
2197 if (!ts)
2198 return ACT_RET_CONT;
2199
2200 /* Store the sample in the required sc, and ignore errors. */
2201 ptr = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPT0);
Willy Tarreau79c1e912016-01-25 14:54:45 +01002202 if (ptr) {
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002203 if (!rule->arg.gpt.expr)
2204 value = (unsigned int)(rule->arg.gpt.value);
2205 else {
2206 switch (rule->from) {
Aurelien DARRAGONa3d46bd2023-08-09 17:23:32 +02002207 case ACT_F_TCP_REQ_CON: smp_opt_dir = SMP_OPT_DIR_REQ; break;
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002208 case ACT_F_TCP_REQ_SES: smp_opt_dir = SMP_OPT_DIR_REQ; break;
2209 case ACT_F_TCP_REQ_CNT: smp_opt_dir = SMP_OPT_DIR_REQ; break;
2210 case ACT_F_TCP_RES_CNT: smp_opt_dir = SMP_OPT_DIR_RES; break;
2211 case ACT_F_HTTP_REQ: smp_opt_dir = SMP_OPT_DIR_REQ; break;
2212 case ACT_F_HTTP_RES: smp_opt_dir = SMP_OPT_DIR_RES; break;
2213 default:
2214 send_log(px, LOG_ERR, "stick table: internal error while setting gpt0.");
2215 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))
2216 ha_alert("stick table: internal error while executing setting gpt0.\n");
2217 return ACT_RET_CONT;
2218 }
2219
2220 /* Fetch and cast the expression. */
2221 smp = sample_fetch_as_type(px, sess, s, smp_opt_dir|SMP_OPT_FINAL, rule->arg.gpt.expr, SMP_T_SINT);
2222 if (!smp) {
2223 send_log(px, LOG_WARNING, "stick table: invalid expression or data type while setting gpt0.");
2224 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))
2225 ha_alert("stick table: invalid expression or data type while setting gpt0.\n");
2226 return ACT_RET_CONT;
2227 }
2228 value = (unsigned int)(smp->data.u.sint);
2229 }
2230
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002231 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002232
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002233 stktable_data_cast(ptr, gpt0) = value;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002234
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002235 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002236
2237 stktable_touch_local(stkctr->table, ts, 0);
Willy Tarreau79c1e912016-01-25 14:54:45 +01002238 }
2239
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002240 return ACT_RET_CONT;
2241}
2242
2243/* This function is a common parser for using variables. It understands
2244 * the format:
2245 *
2246 * set-gpt0(<stick-table ID>) <expression>
2247 *
2248 * It returns 0 if fails and <err> is filled with an error message. Otherwise,
2249 * it returns 1 and the variable <expr> is filled with the pointer to the
2250 * expression to execute.
2251 */
2252static enum act_parse_ret parse_set_gpt0(const char **args, int *arg, struct proxy *px,
2253 struct act_rule *rule, char **err)
2254
2255
2256{
2257 const char *cmd_name = args[*arg-1];
2258 char *error;
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002259 int smp_val;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002260
2261 cmd_name += strlen("sc-set-gpt0");
2262 if (*cmd_name == '\0') {
2263 /* default stick table id. */
2264 rule->arg.gpt.sc = 0;
2265 } else {
2266 /* parse the stick table id. */
2267 if (*cmd_name != '(') {
2268 memprintf(err, "invalid stick table track ID '%s'. Expects sc-set-gpt0(<Track ID>)", args[*arg-1]);
2269 return ACT_RET_PRS_ERR;
2270 }
2271 cmd_name++; /* jump the '(' */
2272 rule->arg.gpt.sc = strtol(cmd_name, &error, 10); /* Convert stick table id. */
2273 if (*error != ')') {
2274 memprintf(err, "invalid stick table track ID '%s'. Expects sc-set-gpt0(<Track ID>)", args[*arg-1]);
2275 return ACT_RET_PRS_ERR;
2276 }
2277
Christopher Faulet28436e22019-12-18 10:25:46 +01002278 if (rule->arg.gpt.sc >= MAX_SESS_STKCTR) {
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002279 memprintf(err, "invalid stick table track ID '%s'. The max allowed ID is %d",
Christopher Faulet28436e22019-12-18 10:25:46 +01002280 args[*arg-1], MAX_SESS_STKCTR-1);
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002281 return ACT_RET_PRS_ERR;
2282 }
2283 }
2284
Willy Tarreauf1e1c912021-08-24 14:57:28 +02002285 /* value may be either an integer or an expression */
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002286 rule->arg.gpt.expr = NULL;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002287 rule->arg.gpt.value = strtol(args[*arg], &error, 10);
Willy Tarreauf1e1c912021-08-24 14:57:28 +02002288 if (*error == '\0') {
2289 /* valid integer, skip it */
2290 (*arg)++;
2291 } else {
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002292 rule->arg.gpt.expr = sample_parse_expr((char **)args, arg, px->conf.args.file,
Willy Tarreaue3b57bf2020-02-14 16:50:14 +01002293 px->conf.args.line, err, &px->conf.args, NULL);
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002294 if (!rule->arg.gpt.expr)
2295 return ACT_RET_PRS_ERR;
2296
2297 switch (rule->from) {
Aurelien DARRAGONa3d46bd2023-08-09 17:23:32 +02002298 case ACT_F_TCP_REQ_CON: smp_val = SMP_VAL_FE_CON_ACC; break;
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002299 case ACT_F_TCP_REQ_SES: smp_val = SMP_VAL_FE_SES_ACC; break;
2300 case ACT_F_TCP_REQ_CNT: smp_val = SMP_VAL_FE_REQ_CNT; break;
2301 case ACT_F_TCP_RES_CNT: smp_val = SMP_VAL_BE_RES_CNT; break;
2302 case ACT_F_HTTP_REQ: smp_val = SMP_VAL_FE_HRQ_HDR; break;
2303 case ACT_F_HTTP_RES: smp_val = SMP_VAL_BE_HRS_HDR; break;
2304 default:
2305 memprintf(err, "internal error, unexpected rule->from=%d, please report this bug!", rule->from);
2306 return ACT_RET_PRS_ERR;
2307 }
2308 if (!(rule->arg.gpt.expr->fetch->val & smp_val)) {
2309 memprintf(err, "fetch method '%s' extracts information from '%s', none of which is available here", args[*arg-1],
2310 sample_src_names(rule->arg.gpt.expr->fetch->use));
2311 free(rule->arg.gpt.expr);
2312 return ACT_RET_PRS_ERR;
2313 }
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002314 }
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002315
Thierry FOURNIER42148732015-09-02 17:17:33 +02002316 rule->action = ACT_CUSTOM;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002317 rule->action_ptr = action_set_gpt0;
2318
2319 return ACT_RET_PRS_OK;
2320}
2321
Willy Tarreau7d562212016-11-25 16:10:05 +01002322/* set temp integer to the number of used entries in the table pointed to by expr.
2323 * Accepts exactly 1 argument of type table.
2324 */
2325static int
2326smp_fetch_table_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
2327{
2328 smp->flags = SMP_F_VOL_TEST;
2329 smp->data.type = SMP_T_SINT;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002330 smp->data.u.sint = args->data.t->current;
Willy Tarreau7d562212016-11-25 16:10:05 +01002331 return 1;
2332}
2333
2334/* set temp integer to the number of free entries in the table pointed to by expr.
2335 * Accepts exactly 1 argument of type table.
2336 */
2337static int
2338smp_fetch_table_avl(const struct arg *args, struct sample *smp, const char *kw, void *private)
2339{
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002340 struct stktable *t;
Willy Tarreau7d562212016-11-25 16:10:05 +01002341
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002342 t = args->data.t;
Willy Tarreau7d562212016-11-25 16:10:05 +01002343 smp->flags = SMP_F_VOL_TEST;
2344 smp->data.type = SMP_T_SINT;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002345 smp->data.u.sint = t->size - t->current;
Willy Tarreau7d562212016-11-25 16:10:05 +01002346 return 1;
2347}
2348
2349/* Returns a pointer to a stkctr depending on the fetch keyword name.
2350 * It is designed to be called as sc[0-9]_* sc_* or src_* exclusively.
2351 * sc[0-9]_* will return a pointer to the respective field in the
2352 * stream <l4>. sc_* requires an UINT argument specifying the stick
2353 * counter number. src_* will fill a locally allocated structure with
2354 * the table and entry corresponding to what is specified with src_*.
2355 * NULL may be returned if the designated stkctr is not tracked. For
2356 * the sc_* and sc[0-9]_* forms, an optional table argument may be
2357 * passed. When present, the currently tracked key is then looked up
2358 * in the specified table instead of the current table. The purpose is
Ilya Shipitsin47d17182020-06-21 21:42:57 +05002359 * to be able to convert multiple values per key (eg: have gpc0 from
Willy Tarreau7d562212016-11-25 16:10:05 +01002360 * multiple tables). <strm> is allowed to be NULL, in which case only
2361 * the session will be consulted.
2362 */
2363struct stkctr *
Emeric Brun819fc6f2017-06-13 19:37:32 +02002364smp_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 +01002365{
Willy Tarreau7d562212016-11-25 16:10:05 +01002366 struct stkctr *stkptr;
2367 struct stksess *stksess;
2368 unsigned int num = kw[2] - '0';
2369 int arg = 0;
2370
2371 if (num == '_' - '0') {
2372 /* sc_* variant, args[0] = ctr# (mandatory) */
2373 num = args[arg++].data.sint;
Willy Tarreau7d562212016-11-25 16:10:05 +01002374 }
2375 else if (num > 9) { /* src_* variant, args[0] = table */
2376 struct stktable_key *key;
2377 struct connection *conn = objt_conn(sess->origin);
2378 struct sample smp;
2379
2380 if (!conn)
2381 return NULL;
2382
Joseph Herlant5662fa42018-11-15 13:43:28 -08002383 /* Fetch source address in a sample. */
Willy Tarreau7d562212016-11-25 16:10:05 +01002384 smp.px = NULL;
2385 smp.sess = sess;
2386 smp.strm = strm;
Amaury Denoyellec460c702021-05-12 10:17:47 +02002387 if (!smp_fetch_src || !smp_fetch_src(empty_arg_list, &smp, "src", NULL))
Willy Tarreau7d562212016-11-25 16:10:05 +01002388 return NULL;
2389
2390 /* Converts into key. */
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002391 key = smp_to_stkey(&smp, args->data.t);
Willy Tarreau7d562212016-11-25 16:10:05 +01002392 if (!key)
2393 return NULL;
2394
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002395 stkctr->table = args->data.t;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002396 stkctr_set_entry(stkctr, stktable_lookup_key(stkctr->table, key));
2397 return stkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002398 }
2399
2400 /* Here, <num> contains the counter number from 0 to 9 for
2401 * the sc[0-9]_ form, or even higher using sc_(num) if needed.
2402 * args[arg] is the first optional argument. We first lookup the
2403 * ctr form the stream, then from the session if it was not there.
Christopher Fauleta9fa88a2019-10-21 10:53:34 +02002404 * But we must be sure the counter does not exceed MAX_SESS_STKCTR.
Willy Tarreau7d562212016-11-25 16:10:05 +01002405 */
Christopher Fauleta9fa88a2019-10-21 10:53:34 +02002406 if (num >= MAX_SESS_STKCTR)
2407 return NULL;
Willy Tarreau7d562212016-11-25 16:10:05 +01002408
2409 if (strm)
2410 stkptr = &strm->stkctr[num];
2411 if (!strm || !stkctr_entry(stkptr)) {
2412 stkptr = &sess->stkctr[num];
2413 if (!stkctr_entry(stkptr))
2414 return NULL;
2415 }
2416
2417 stksess = stkctr_entry(stkptr);
2418 if (!stksess)
2419 return NULL;
2420
2421 if (unlikely(args[arg].type == ARGT_TAB)) {
2422 /* an alternate table was specified, let's look up the same key there */
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002423 stkctr->table = args[arg].data.t;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002424 stkctr_set_entry(stkctr, stktable_lookup(stkctr->table, stksess));
2425 return stkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002426 }
2427 return stkptr;
2428}
2429
2430/* same as smp_fetch_sc_stkctr() but dedicated to src_* and can create
2431 * the entry if it doesn't exist yet. This is needed for a few fetch
2432 * functions which need to create an entry, such as src_inc_gpc* and
2433 * src_clr_gpc*.
2434 */
2435struct stkctr *
Emeric Brun819fc6f2017-06-13 19:37:32 +02002436smp_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 +01002437{
Willy Tarreau7d562212016-11-25 16:10:05 +01002438 struct stktable_key *key;
2439 struct connection *conn = objt_conn(sess->origin);
2440 struct sample smp;
2441
2442 if (strncmp(kw, "src_", 4) != 0)
2443 return NULL;
2444
2445 if (!conn)
2446 return NULL;
2447
Joseph Herlant5662fa42018-11-15 13:43:28 -08002448 /* Fetch source address in a sample. */
Willy Tarreau7d562212016-11-25 16:10:05 +01002449 smp.px = NULL;
2450 smp.sess = sess;
2451 smp.strm = strm;
Amaury Denoyellec460c702021-05-12 10:17:47 +02002452 if (!smp_fetch_src || !smp_fetch_src(empty_arg_list, &smp, "src", NULL))
Willy Tarreau7d562212016-11-25 16:10:05 +01002453 return NULL;
2454
2455 /* Converts into key. */
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002456 key = smp_to_stkey(&smp, args->data.t);
Willy Tarreau7d562212016-11-25 16:10:05 +01002457 if (!key)
2458 return NULL;
2459
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002460 stkctr->table = args->data.t;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002461 stkctr_set_entry(stkctr, stktable_get_entry(stkctr->table, key));
2462 return stkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002463}
2464
2465/* set return a boolean indicating if the requested stream counter is
2466 * currently being tracked or not.
2467 * Supports being called as "sc[0-9]_tracked" only.
2468 */
2469static int
2470smp_fetch_sc_tracked(const struct arg *args, struct sample *smp, const char *kw, void *private)
2471{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002472 struct stkctr tmpstkctr;
2473 struct stkctr *stkctr;
2474
Willy Tarreau7d562212016-11-25 16:10:05 +01002475 smp->flags = SMP_F_VOL_TEST;
2476 smp->data.type = SMP_T_BOOL;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002477 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2478 smp->data.u.sint = !!stkctr;
2479
2480 /* release the ref count */
Dirkjan Bussinkff57f1b2018-09-14 14:31:22 +02002481 if (stkctr == &tmpstkctr)
Emeric Brun819fc6f2017-06-13 19:37:32 +02002482 stktable_release(stkctr->table, stkctr_entry(stkctr));
2483
Willy Tarreau7d562212016-11-25 16:10:05 +01002484 return 1;
2485}
2486
2487/* set <smp> to the General Purpose Flag 0 value from the stream's tracked
2488 * frontend counters or from the src.
2489 * Supports being called as "sc[0-9]_get_gpc0" or "src_get_gpt0" only. Value
2490 * zero is returned if the key is new.
2491 */
2492static int
2493smp_fetch_sc_get_gpt0(const struct arg *args, struct sample *smp, const char *kw, void *private)
2494{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002495 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002496 struct stkctr *stkctr;
2497
Emeric Brun819fc6f2017-06-13 19:37:32 +02002498 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002499 if (!stkctr)
2500 return 0;
2501
2502 smp->flags = SMP_F_VOL_TEST;
2503 smp->data.type = SMP_T_SINT;
2504 smp->data.u.sint = 0;
2505
Emeric Brun819fc6f2017-06-13 19:37:32 +02002506 if (stkctr_entry(stkctr)) {
2507 void *ptr;
2508
2509 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPT0);
2510 if (!ptr) {
2511 if (stkctr == &tmpstkctr)
2512 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002513 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002514 }
2515
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002516 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002517
Willy Tarreau7d562212016-11-25 16:10:05 +01002518 smp->data.u.sint = stktable_data_cast(ptr, gpt0);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002519
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002520 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002521
2522 if (stkctr == &tmpstkctr)
2523 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002524 }
2525 return 1;
2526}
2527
2528/* set <smp> to the General Purpose Counter 0 value from the stream's tracked
2529 * frontend counters or from the src.
2530 * Supports being called as "sc[0-9]_get_gpc0" or "src_get_gpc0" only. Value
2531 * zero is returned if the key is new.
2532 */
2533static int
2534smp_fetch_sc_get_gpc0(const struct arg *args, struct sample *smp, const char *kw, void *private)
2535{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002536 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002537 struct stkctr *stkctr;
2538
Emeric Brun819fc6f2017-06-13 19:37:32 +02002539 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002540 if (!stkctr)
2541 return 0;
2542
2543 smp->flags = SMP_F_VOL_TEST;
2544 smp->data.type = SMP_T_SINT;
2545 smp->data.u.sint = 0;
2546
2547 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002548 void *ptr;
2549
2550 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0);
2551 if (!ptr) {
2552 if (stkctr == &tmpstkctr)
2553 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002554 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002555 }
2556
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002557 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002558
Willy Tarreau7d562212016-11-25 16:10:05 +01002559 smp->data.u.sint = stktable_data_cast(ptr, gpc0);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002560
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002561 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002562
2563 if (stkctr == &tmpstkctr)
2564 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002565 }
2566 return 1;
2567}
2568
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002569/* set <smp> to the General Purpose Counter 1 value from the stream's tracked
2570 * frontend counters or from the src.
2571 * Supports being called as "sc[0-9]_get_gpc1" or "src_get_gpc1" only. Value
2572 * zero is returned if the key is new.
2573 */
2574static int
2575smp_fetch_sc_get_gpc1(const struct arg *args, struct sample *smp, const char *kw, void *private)
2576{
2577 struct stkctr tmpstkctr;
2578 struct stkctr *stkctr;
2579
2580 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2581 if (!stkctr)
2582 return 0;
2583
2584 smp->flags = SMP_F_VOL_TEST;
2585 smp->data.type = SMP_T_SINT;
2586 smp->data.u.sint = 0;
2587
2588 if (stkctr_entry(stkctr) != NULL) {
2589 void *ptr;
2590
2591 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1);
2592 if (!ptr) {
2593 if (stkctr == &tmpstkctr)
2594 stktable_release(stkctr->table, stkctr_entry(stkctr));
2595 return 0; /* parameter not stored */
2596 }
2597
2598 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2599
2600 smp->data.u.sint = stktable_data_cast(ptr, gpc1);
2601
2602 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2603
2604 if (stkctr == &tmpstkctr)
2605 stktable_release(stkctr->table, stkctr_entry(stkctr));
2606 }
2607 return 1;
2608}
2609
Willy Tarreau7d562212016-11-25 16:10:05 +01002610/* set <smp> to the General Purpose Counter 0's event rate from the stream's
2611 * tracked frontend counters or from the src.
2612 * Supports being called as "sc[0-9]_gpc0_rate" or "src_gpc0_rate" only.
2613 * Value zero is returned if the key is new.
2614 */
2615static int
2616smp_fetch_sc_gpc0_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
2617{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002618 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002619 struct stkctr *stkctr;
2620
Emeric Brun819fc6f2017-06-13 19:37:32 +02002621 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002622 if (!stkctr)
2623 return 0;
2624
2625 smp->flags = SMP_F_VOL_TEST;
2626 smp->data.type = SMP_T_SINT;
2627 smp->data.u.sint = 0;
2628 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002629 void *ptr;
2630
2631 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0_RATE);
2632 if (!ptr) {
2633 if (stkctr == &tmpstkctr)
2634 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002635 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002636 }
2637
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002638 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002639
Willy Tarreau7d562212016-11-25 16:10:05 +01002640 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, gpc0_rate),
2641 stkctr->table->data_arg[STKTABLE_DT_GPC0_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002642
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002643 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002644
2645 if (stkctr == &tmpstkctr)
2646 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002647 }
2648 return 1;
2649}
2650
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002651/* set <smp> to the General Purpose Counter 1's event rate from the stream's
2652 * tracked frontend counters or from the src.
2653 * Supports being called as "sc[0-9]_gpc1_rate" or "src_gpc1_rate" only.
2654 * Value zero is returned if the key is new.
2655 */
2656static int
2657smp_fetch_sc_gpc1_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
2658{
2659 struct stkctr tmpstkctr;
2660 struct stkctr *stkctr;
2661
2662 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2663 if (!stkctr)
2664 return 0;
2665
2666 smp->flags = SMP_F_VOL_TEST;
2667 smp->data.type = SMP_T_SINT;
2668 smp->data.u.sint = 0;
2669 if (stkctr_entry(stkctr) != NULL) {
2670 void *ptr;
2671
2672 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1_RATE);
2673 if (!ptr) {
2674 if (stkctr == &tmpstkctr)
2675 stktable_release(stkctr->table, stkctr_entry(stkctr));
2676 return 0; /* parameter not stored */
2677 }
2678
2679 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2680
2681 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, gpc1_rate),
2682 stkctr->table->data_arg[STKTABLE_DT_GPC1_RATE].u);
2683
2684 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2685
2686 if (stkctr == &tmpstkctr)
2687 stktable_release(stkctr->table, stkctr_entry(stkctr));
2688 }
2689 return 1;
2690}
2691
Willy Tarreau7d562212016-11-25 16:10:05 +01002692/* Increment the General Purpose Counter 0 value from the stream's tracked
2693 * frontend counters and return it into temp integer.
2694 * Supports being called as "sc[0-9]_inc_gpc0" or "src_inc_gpc0" only.
2695 */
2696static int
2697smp_fetch_sc_inc_gpc0(const struct arg *args, struct sample *smp, const char *kw, void *private)
2698{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002699 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002700 struct stkctr *stkctr;
2701
Emeric Brun819fc6f2017-06-13 19:37:32 +02002702 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002703 if (!stkctr)
2704 return 0;
2705
2706 smp->flags = SMP_F_VOL_TEST;
2707 smp->data.type = SMP_T_SINT;
2708 smp->data.u.sint = 0;
2709
Emeric Brun819fc6f2017-06-13 19:37:32 +02002710 if (!stkctr_entry(stkctr))
2711 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002712
2713 if (stkctr && stkctr_entry(stkctr)) {
2714 void *ptr1,*ptr2;
2715
Emeric Brun819fc6f2017-06-13 19:37:32 +02002716
Willy Tarreau7d562212016-11-25 16:10:05 +01002717 /* First, update gpc0_rate if it's tracked. Second, update its
2718 * gpc0 if tracked. Returns gpc0's value otherwise the curr_ctr.
2719 */
2720 ptr1 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0_RATE);
Willy Tarreau7d562212016-11-25 16:10:05 +01002721 ptr2 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002722 if (ptr1 || ptr2) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002723 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Willy Tarreau7d562212016-11-25 16:10:05 +01002724
Emeric Brun819fc6f2017-06-13 19:37:32 +02002725 if (ptr1) {
2726 update_freq_ctr_period(&stktable_data_cast(ptr1, gpc0_rate),
2727 stkctr->table->data_arg[STKTABLE_DT_GPC0_RATE].u, 1);
2728 smp->data.u.sint = (&stktable_data_cast(ptr1, gpc0_rate))->curr_ctr;
2729 }
2730
2731 if (ptr2)
2732 smp->data.u.sint = ++stktable_data_cast(ptr2, gpc0);
2733
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002734 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002735
2736 /* If data was modified, we need to touch to re-schedule sync */
2737 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
2738 }
2739 else if (stkctr == &tmpstkctr)
2740 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002741 }
2742 return 1;
2743}
2744
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002745/* Increment the General Purpose Counter 1 value from the stream's tracked
2746 * frontend counters and return it into temp integer.
2747 * Supports being called as "sc[0-9]_inc_gpc1" or "src_inc_gpc1" only.
2748 */
2749static int
2750smp_fetch_sc_inc_gpc1(const struct arg *args, struct sample *smp, const char *kw, void *private)
2751{
2752 struct stkctr tmpstkctr;
2753 struct stkctr *stkctr;
2754
2755 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2756 if (!stkctr)
2757 return 0;
2758
2759 smp->flags = SMP_F_VOL_TEST;
2760 smp->data.type = SMP_T_SINT;
2761 smp->data.u.sint = 0;
2762
2763 if (!stkctr_entry(stkctr))
2764 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2765
2766 if (stkctr && stkctr_entry(stkctr)) {
2767 void *ptr1,*ptr2;
2768
2769
2770 /* First, update gpc1_rate if it's tracked. Second, update its
2771 * gpc1 if tracked. Returns gpc1's value otherwise the curr_ctr.
2772 */
2773 ptr1 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1_RATE);
2774 ptr2 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1);
2775 if (ptr1 || ptr2) {
2776 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2777
2778 if (ptr1) {
2779 update_freq_ctr_period(&stktable_data_cast(ptr1, gpc1_rate),
2780 stkctr->table->data_arg[STKTABLE_DT_GPC1_RATE].u, 1);
2781 smp->data.u.sint = (&stktable_data_cast(ptr1, gpc1_rate))->curr_ctr;
2782 }
2783
2784 if (ptr2)
2785 smp->data.u.sint = ++stktable_data_cast(ptr2, gpc1);
2786
2787 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2788
2789 /* If data was modified, we need to touch to re-schedule sync */
2790 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
2791 }
2792 else if (stkctr == &tmpstkctr)
2793 stktable_release(stkctr->table, stkctr_entry(stkctr));
2794 }
2795 return 1;
2796}
2797
Willy Tarreau7d562212016-11-25 16:10:05 +01002798/* Clear the General Purpose Counter 0 value from the stream's tracked
2799 * frontend counters and return its previous value into temp integer.
2800 * Supports being called as "sc[0-9]_clr_gpc0" or "src_clr_gpc0" only.
2801 */
2802static int
2803smp_fetch_sc_clr_gpc0(const struct arg *args, struct sample *smp, const char *kw, void *private)
2804{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002805 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002806 struct stkctr *stkctr;
2807
Emeric Brun819fc6f2017-06-13 19:37:32 +02002808 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002809 if (!stkctr)
2810 return 0;
2811
2812 smp->flags = SMP_F_VOL_TEST;
2813 smp->data.type = SMP_T_SINT;
2814 smp->data.u.sint = 0;
2815
Emeric Brun819fc6f2017-06-13 19:37:32 +02002816 if (!stkctr_entry(stkctr))
2817 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002818
Emeric Brun819fc6f2017-06-13 19:37:32 +02002819 if (stkctr && stkctr_entry(stkctr)) {
2820 void *ptr;
2821
2822 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0);
2823 if (!ptr) {
2824 if (stkctr == &tmpstkctr)
2825 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002826 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002827 }
2828
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002829 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002830
Willy Tarreau7d562212016-11-25 16:10:05 +01002831 smp->data.u.sint = stktable_data_cast(ptr, gpc0);
2832 stktable_data_cast(ptr, gpc0) = 0;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002833
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002834 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002835
Willy Tarreau7d562212016-11-25 16:10:05 +01002836 /* If data was modified, we need to touch to re-schedule sync */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002837 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
Willy Tarreau7d562212016-11-25 16:10:05 +01002838 }
2839 return 1;
2840}
2841
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002842/* Clear the General Purpose Counter 1 value from the stream's tracked
2843 * frontend counters and return its previous value into temp integer.
2844 * Supports being called as "sc[0-9]_clr_gpc1" or "src_clr_gpc1" only.
2845 */
2846static int
2847smp_fetch_sc_clr_gpc1(const struct arg *args, struct sample *smp, const char *kw, void *private)
2848{
2849 struct stkctr tmpstkctr;
2850 struct stkctr *stkctr;
2851
2852 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2853 if (!stkctr)
2854 return 0;
2855
2856 smp->flags = SMP_F_VOL_TEST;
2857 smp->data.type = SMP_T_SINT;
2858 smp->data.u.sint = 0;
2859
2860 if (!stkctr_entry(stkctr))
2861 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2862
2863 if (stkctr && stkctr_entry(stkctr)) {
2864 void *ptr;
2865
2866 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1);
2867 if (!ptr) {
2868 if (stkctr == &tmpstkctr)
2869 stktable_release(stkctr->table, stkctr_entry(stkctr));
2870 return 0; /* parameter not stored */
2871 }
2872
2873 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2874
2875 smp->data.u.sint = stktable_data_cast(ptr, gpc1);
2876 stktable_data_cast(ptr, gpc1) = 0;
2877
2878 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2879
2880 /* If data was modified, we need to touch to re-schedule sync */
2881 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
2882 }
2883 return 1;
2884}
2885
Willy Tarreau7d562212016-11-25 16:10:05 +01002886/* set <smp> to the cumulated number of connections from the stream's tracked
2887 * frontend counters. Supports being called as "sc[0-9]_conn_cnt" or
2888 * "src_conn_cnt" only.
2889 */
2890static int
2891smp_fetch_sc_conn_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
2892{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002893 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002894 struct stkctr *stkctr;
2895
Emeric Brun819fc6f2017-06-13 19:37:32 +02002896 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002897 if (!stkctr)
2898 return 0;
2899
2900 smp->flags = SMP_F_VOL_TEST;
2901 smp->data.type = SMP_T_SINT;
2902 smp->data.u.sint = 0;
2903 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002904 void *ptr;
2905
2906 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_CONN_CNT);
2907 if (!ptr) {
2908 if (stkctr == &tmpstkctr)
2909 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002910 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002911 }
2912
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002913 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002914
Willy Tarreau7d562212016-11-25 16:10:05 +01002915 smp->data.u.sint = stktable_data_cast(ptr, conn_cnt);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002916
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002917 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002918
2919 if (stkctr == &tmpstkctr)
2920 stktable_release(stkctr->table, stkctr_entry(stkctr));
2921
2922
Willy Tarreau7d562212016-11-25 16:10:05 +01002923 }
2924 return 1;
2925}
2926
2927/* set <smp> to the connection rate from the stream's tracked frontend
2928 * counters. Supports being called as "sc[0-9]_conn_rate" or "src_conn_rate"
2929 * only.
2930 */
2931static int
2932smp_fetch_sc_conn_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
2933{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002934 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002935 struct stkctr *stkctr;
2936
Emeric Brun819fc6f2017-06-13 19:37:32 +02002937 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002938 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 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002945 void *ptr;
2946
2947 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_CONN_RATE);
2948 if (!ptr) {
2949 if (stkctr == &tmpstkctr)
2950 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002951 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002952 }
2953
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002954 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002955
Willy Tarreau7d562212016-11-25 16:10:05 +01002956 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, conn_rate),
2957 stkctr->table->data_arg[STKTABLE_DT_CONN_RATE].u);
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 temp integer to the number of connections from the stream's source address
2968 * in the table pointed to by expr, after updating it.
2969 * Accepts exactly 1 argument of type table.
2970 */
2971static int
2972smp_fetch_src_updt_conn_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
2973{
2974 struct connection *conn = objt_conn(smp->sess->origin);
2975 struct stksess *ts;
2976 struct stktable_key *key;
2977 void *ptr;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002978 struct stktable *t;
Willy Tarreau7d562212016-11-25 16:10:05 +01002979
2980 if (!conn)
2981 return 0;
2982
Joseph Herlant5662fa42018-11-15 13:43:28 -08002983 /* Fetch source address in a sample. */
Amaury Denoyellec460c702021-05-12 10:17:47 +02002984 if (!smp_fetch_src || !smp_fetch_src(empty_arg_list, smp, "src", NULL))
Willy Tarreau7d562212016-11-25 16:10:05 +01002985 return 0;
2986
2987 /* Converts into key. */
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002988 key = smp_to_stkey(smp, args->data.t);
Willy Tarreau7d562212016-11-25 16:10:05 +01002989 if (!key)
2990 return 0;
2991
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002992 t = args->data.t;
Willy Tarreau7d562212016-11-25 16:10:05 +01002993
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002994 if ((ts = stktable_get_entry(t, key)) == NULL)
Willy Tarreau7d562212016-11-25 16:10:05 +01002995 /* entry does not exist and could not be created */
2996 return 0;
2997
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002998 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_CONN_CNT);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002999 if (!ptr) {
Willy Tarreau7d562212016-11-25 16:10:05 +01003000 return 0; /* parameter not stored in this table */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003001 }
Willy Tarreau7d562212016-11-25 16:10:05 +01003002
3003 smp->data.type = SMP_T_SINT;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003004
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003005 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003006
Willy Tarreau7d562212016-11-25 16:10:05 +01003007 smp->data.u.sint = ++stktable_data_cast(ptr, conn_cnt);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003008
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003009 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003010
Willy Tarreau7d562212016-11-25 16:10:05 +01003011 smp->flags = SMP_F_VOL_TEST;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003012
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003013 stktable_touch_local(t, ts, 1);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003014
3015 /* Touch was previously performed by stktable_update_key */
Willy Tarreau7d562212016-11-25 16:10:05 +01003016 return 1;
3017}
3018
3019/* set <smp> to the number of concurrent connections from the stream's tracked
3020 * frontend counters. Supports being called as "sc[0-9]_conn_cur" or
3021 * "src_conn_cur" only.
3022 */
3023static int
3024smp_fetch_sc_conn_cur(const struct arg *args, struct sample *smp, const char *kw, void *private)
3025{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003026 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003027 struct stkctr *stkctr;
3028
Emeric Brun819fc6f2017-06-13 19:37:32 +02003029 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003030 if (!stkctr)
3031 return 0;
3032
3033 smp->flags = SMP_F_VOL_TEST;
3034 smp->data.type = SMP_T_SINT;
3035 smp->data.u.sint = 0;
3036 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003037 void *ptr;
3038
3039 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_CONN_CUR);
3040 if (!ptr) {
3041 if (stkctr == &tmpstkctr)
3042 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003043 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003044 }
3045
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003046 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003047
Willy Tarreau7d562212016-11-25 16:10:05 +01003048 smp->data.u.sint = stktable_data_cast(ptr, conn_cur);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003049
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003050 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003051
3052 if (stkctr == &tmpstkctr)
3053 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003054 }
3055 return 1;
3056}
3057
3058/* set <smp> to the cumulated number of streams from the stream's tracked
3059 * frontend counters. Supports being called as "sc[0-9]_sess_cnt" or
3060 * "src_sess_cnt" only.
3061 */
3062static int
3063smp_fetch_sc_sess_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
3064{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003065 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003066 struct stkctr *stkctr;
3067
Emeric Brun819fc6f2017-06-13 19:37:32 +02003068 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003069 if (!stkctr)
3070 return 0;
3071
3072 smp->flags = SMP_F_VOL_TEST;
3073 smp->data.type = SMP_T_SINT;
3074 smp->data.u.sint = 0;
3075 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003076 void *ptr;
3077
3078 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_SESS_CNT);
3079 if (!ptr) {
3080 if (stkctr == &tmpstkctr)
3081 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003082 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003083 }
3084
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003085 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003086
Willy Tarreau7d562212016-11-25 16:10:05 +01003087 smp->data.u.sint = stktable_data_cast(ptr, sess_cnt);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003088
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003089 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003090
3091 if (stkctr == &tmpstkctr)
3092 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003093 }
3094 return 1;
3095}
3096
3097/* set <smp> to the stream rate from the stream's tracked frontend counters.
3098 * Supports being called as "sc[0-9]_sess_rate" or "src_sess_rate" only.
3099 */
3100static int
3101smp_fetch_sc_sess_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3102{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003103 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003104 struct stkctr *stkctr;
3105
Emeric Brun819fc6f2017-06-13 19:37:32 +02003106 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003107 if (!stkctr)
3108 return 0;
3109
3110 smp->flags = SMP_F_VOL_TEST;
3111 smp->data.type = SMP_T_SINT;
3112 smp->data.u.sint = 0;
3113 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003114 void *ptr;
3115
3116 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_SESS_RATE);
3117 if (!ptr) {
3118 if (stkctr == &tmpstkctr)
3119 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003120 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003121 }
3122
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003123 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003124
Willy Tarreau7d562212016-11-25 16:10:05 +01003125 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, sess_rate),
3126 stkctr->table->data_arg[STKTABLE_DT_SESS_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003127
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003128 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003129
3130 if (stkctr == &tmpstkctr)
3131 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003132 }
3133 return 1;
3134}
3135
3136/* set <smp> to the cumulated number of HTTP requests from the stream's tracked
3137 * frontend counters. Supports being called as "sc[0-9]_http_req_cnt" or
3138 * "src_http_req_cnt" only.
3139 */
3140static int
3141smp_fetch_sc_http_req_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
3142{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003143 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003144 struct stkctr *stkctr;
3145
Emeric Brun819fc6f2017-06-13 19:37:32 +02003146 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003147 if (!stkctr)
3148 return 0;
3149
3150 smp->flags = SMP_F_VOL_TEST;
3151 smp->data.type = SMP_T_SINT;
3152 smp->data.u.sint = 0;
3153 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003154 void *ptr;
3155
3156 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_REQ_CNT);
3157 if (!ptr) {
3158 if (stkctr == &tmpstkctr)
3159 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003160 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003161 }
3162
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003163 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003164
Willy Tarreau7d562212016-11-25 16:10:05 +01003165 smp->data.u.sint = stktable_data_cast(ptr, http_req_cnt);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003166
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003167 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003168
3169 if (stkctr == &tmpstkctr)
3170 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003171 }
3172 return 1;
3173}
3174
3175/* set <smp> to the HTTP request rate from the stream's tracked frontend
3176 * counters. Supports being called as "sc[0-9]_http_req_rate" or
3177 * "src_http_req_rate" only.
3178 */
3179static int
3180smp_fetch_sc_http_req_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3181{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003182 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003183 struct stkctr *stkctr;
3184
Emeric Brun819fc6f2017-06-13 19:37:32 +02003185 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003186 if (!stkctr)
3187 return 0;
3188
3189 smp->flags = SMP_F_VOL_TEST;
3190 smp->data.type = SMP_T_SINT;
3191 smp->data.u.sint = 0;
3192 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003193 void *ptr;
3194
3195 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_REQ_RATE);
3196 if (!ptr) {
3197 if (stkctr == &tmpstkctr)
3198 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003199 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003200 }
3201
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003202 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003203
Willy Tarreau7d562212016-11-25 16:10:05 +01003204 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, http_req_rate),
3205 stkctr->table->data_arg[STKTABLE_DT_HTTP_REQ_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003206
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003207 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003208
3209 if (stkctr == &tmpstkctr)
3210 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003211 }
3212 return 1;
3213}
3214
3215/* set <smp> to the cumulated number of HTTP requests errors from the stream's
3216 * tracked frontend counters. Supports being called as "sc[0-9]_http_err_cnt" or
3217 * "src_http_err_cnt" only.
3218 */
3219static int
3220smp_fetch_sc_http_err_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
3221{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003222 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003223 struct stkctr *stkctr;
3224
Emeric Brun819fc6f2017-06-13 19:37:32 +02003225 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003226 if (!stkctr)
3227 return 0;
3228
3229 smp->flags = SMP_F_VOL_TEST;
3230 smp->data.type = SMP_T_SINT;
3231 smp->data.u.sint = 0;
3232 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003233 void *ptr;
3234
3235 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_ERR_CNT);
3236 if (!ptr) {
3237 if (stkctr == &tmpstkctr)
3238 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003239 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003240 }
3241
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003242 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003243
Willy Tarreau7d562212016-11-25 16:10:05 +01003244 smp->data.u.sint = stktable_data_cast(ptr, http_err_cnt);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003245
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003246 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003247
3248 if (stkctr == &tmpstkctr)
3249 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003250 }
3251 return 1;
3252}
3253
3254/* set <smp> to the HTTP request error rate from the stream's tracked frontend
3255 * counters. Supports being called as "sc[0-9]_http_err_rate" or
3256 * "src_http_err_rate" only.
3257 */
3258static int
3259smp_fetch_sc_http_err_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3260{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003261 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003262 struct stkctr *stkctr;
3263
Emeric Brun819fc6f2017-06-13 19:37:32 +02003264 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003265 if (!stkctr)
3266 return 0;
3267
3268 smp->flags = SMP_F_VOL_TEST;
3269 smp->data.type = SMP_T_SINT;
3270 smp->data.u.sint = 0;
3271 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003272 void *ptr;
3273
3274 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_ERR_RATE);
3275 if (!ptr) {
3276 if (stkctr == &tmpstkctr)
3277 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003278 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003279 }
3280
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003281 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003282
Willy Tarreau7d562212016-11-25 16:10:05 +01003283 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, http_err_rate),
3284 stkctr->table->data_arg[STKTABLE_DT_HTTP_ERR_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003285
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003286 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003287
3288 if (stkctr == &tmpstkctr)
3289 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003290 }
3291 return 1;
3292}
3293
Willy Tarreau826f3ab2021-02-10 12:07:15 +01003294/* set <smp> to the cumulated number of HTTP response failures from the stream's
3295 * tracked frontend counters. Supports being called as "sc[0-9]_http_fail_cnt" or
3296 * "src_http_fail_cnt" only.
3297 */
3298static int
3299smp_fetch_sc_http_fail_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
3300{
3301 struct stkctr tmpstkctr;
3302 struct stkctr *stkctr;
3303
3304 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
3305 if (!stkctr)
3306 return 0;
3307
3308 smp->flags = SMP_F_VOL_TEST;
3309 smp->data.type = SMP_T_SINT;
3310 smp->data.u.sint = 0;
3311 if (stkctr_entry(stkctr) != NULL) {
3312 void *ptr;
3313
3314 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_FAIL_CNT);
3315 if (!ptr) {
3316 if (stkctr == &tmpstkctr)
3317 stktable_release(stkctr->table, stkctr_entry(stkctr));
3318 return 0; /* parameter not stored */
3319 }
3320
3321 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3322
3323 smp->data.u.sint = stktable_data_cast(ptr, http_fail_cnt);
3324
3325 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3326
3327 if (stkctr == &tmpstkctr)
3328 stktable_release(stkctr->table, stkctr_entry(stkctr));
3329 }
3330 return 1;
3331}
3332
3333/* set <smp> to the HTTP response failure rate from the stream's tracked frontend
3334 * counters. Supports being called as "sc[0-9]_http_fail_rate" or
3335 * "src_http_fail_rate" only.
3336 */
3337static int
3338smp_fetch_sc_http_fail_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3339{
3340 struct stkctr tmpstkctr;
3341 struct stkctr *stkctr;
3342
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 if (stkctr_entry(stkctr) != NULL) {
3351 void *ptr;
3352
3353 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_FAIL_RATE);
3354 if (!ptr) {
3355 if (stkctr == &tmpstkctr)
3356 stktable_release(stkctr->table, stkctr_entry(stkctr));
3357 return 0; /* parameter not stored */
3358 }
3359
3360 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3361
3362 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, http_fail_rate),
3363 stkctr->table->data_arg[STKTABLE_DT_HTTP_FAIL_RATE].u);
3364
3365 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3366
3367 if (stkctr == &tmpstkctr)
3368 stktable_release(stkctr->table, stkctr_entry(stkctr));
3369 }
3370 return 1;
3371}
3372
Willy Tarreau7d562212016-11-25 16:10:05 +01003373/* set <smp> to the number of kbytes received from clients, as found in the
3374 * stream's tracked frontend counters. Supports being called as
3375 * "sc[0-9]_kbytes_in" or "src_kbytes_in" only.
3376 */
3377static int
3378smp_fetch_sc_kbytes_in(const struct arg *args, struct sample *smp, const char *kw, void *private)
3379{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003380 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003381 struct stkctr *stkctr;
3382
Emeric Brun819fc6f2017-06-13 19:37:32 +02003383 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003384 if (!stkctr)
3385 return 0;
3386
3387 smp->flags = SMP_F_VOL_TEST;
3388 smp->data.type = SMP_T_SINT;
3389 smp->data.u.sint = 0;
3390 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003391 void *ptr;
3392
3393 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_IN_CNT);
3394 if (!ptr) {
3395 if (stkctr == &tmpstkctr)
3396 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003397 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003398 }
3399
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003400 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003401
Willy Tarreau7d562212016-11-25 16:10:05 +01003402 smp->data.u.sint = stktable_data_cast(ptr, bytes_in_cnt) >> 10;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003403
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003404 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003405
3406 if (stkctr == &tmpstkctr)
3407 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003408 }
3409 return 1;
3410}
3411
3412/* set <smp> to the data rate received from clients in bytes/s, as found
3413 * in the stream's tracked frontend counters. Supports being called as
3414 * "sc[0-9]_bytes_in_rate" or "src_bytes_in_rate" only.
3415 */
3416static int
3417smp_fetch_sc_bytes_in_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3418{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003419 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003420 struct stkctr *stkctr;
3421
Emeric Brun819fc6f2017-06-13 19:37:32 +02003422 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003423 if (!stkctr)
3424 return 0;
3425
3426 smp->flags = SMP_F_VOL_TEST;
3427 smp->data.type = SMP_T_SINT;
3428 smp->data.u.sint = 0;
3429 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003430 void *ptr;
3431
3432 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_IN_RATE);
3433 if (!ptr) {
3434 if (stkctr == &tmpstkctr)
3435 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003436 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003437 }
3438
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003439 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003440
Willy Tarreau7d562212016-11-25 16:10:05 +01003441 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, bytes_in_rate),
3442 stkctr->table->data_arg[STKTABLE_DT_BYTES_IN_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003443
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003444 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003445
3446 if (stkctr == &tmpstkctr)
3447 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003448 }
3449 return 1;
3450}
3451
3452/* set <smp> to the number of kbytes sent to clients, as found in the
3453 * stream's tracked frontend counters. Supports being called as
3454 * "sc[0-9]_kbytes_out" or "src_kbytes_out" only.
3455 */
3456static int
3457smp_fetch_sc_kbytes_out(const struct arg *args, struct sample *smp, const char *kw, void *private)
3458{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003459 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003460 struct stkctr *stkctr;
3461
Emeric Brun819fc6f2017-06-13 19:37:32 +02003462 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003463 if (!stkctr)
3464 return 0;
3465
3466 smp->flags = SMP_F_VOL_TEST;
3467 smp->data.type = SMP_T_SINT;
3468 smp->data.u.sint = 0;
3469 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003470 void *ptr;
3471
3472 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_OUT_CNT);
3473 if (!ptr) {
3474 if (stkctr == &tmpstkctr)
3475 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003476 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003477 }
3478
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003479 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003480
Willy Tarreau7d562212016-11-25 16:10:05 +01003481 smp->data.u.sint = stktable_data_cast(ptr, bytes_out_cnt) >> 10;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003482
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003483 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003484
3485 if (stkctr == &tmpstkctr)
3486 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003487 }
3488 return 1;
3489}
3490
3491/* set <smp> to the data rate sent to clients in bytes/s, as found in the
3492 * stream's tracked frontend counters. Supports being called as
3493 * "sc[0-9]_bytes_out_rate" or "src_bytes_out_rate" only.
3494 */
3495static int
3496smp_fetch_sc_bytes_out_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3497{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003498 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003499 struct stkctr *stkctr;
3500
Emeric Brun819fc6f2017-06-13 19:37:32 +02003501 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003502 if (!stkctr)
3503 return 0;
3504
3505 smp->flags = SMP_F_VOL_TEST;
3506 smp->data.type = SMP_T_SINT;
3507 smp->data.u.sint = 0;
3508 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003509 void *ptr;
3510
3511 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_OUT_RATE);
3512 if (!ptr) {
3513 if (stkctr == &tmpstkctr)
3514 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003515 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003516 }
3517
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003518 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003519
Willy Tarreau7d562212016-11-25 16:10:05 +01003520 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, bytes_out_rate),
3521 stkctr->table->data_arg[STKTABLE_DT_BYTES_OUT_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003522
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003523 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003524
3525 if (stkctr == &tmpstkctr)
3526 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003527 }
3528 return 1;
3529}
3530
3531/* set <smp> to the number of active trackers on the SC entry in the stream's
3532 * tracked frontend counters. Supports being called as "sc[0-9]_trackers" only.
3533 */
3534static int
3535smp_fetch_sc_trackers(const struct arg *args, struct sample *smp, const char *kw, void *private)
3536{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003537 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003538 struct stkctr *stkctr;
3539
Emeric Brun819fc6f2017-06-13 19:37:32 +02003540 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003541 if (!stkctr)
3542 return 0;
3543
3544 smp->flags = SMP_F_VOL_TEST;
3545 smp->data.type = SMP_T_SINT;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003546 if (stkctr == &tmpstkctr) {
3547 smp->data.u.sint = stkctr_entry(stkctr) ? (stkctr_entry(stkctr)->ref_cnt-1) : 0;
3548 stktable_release(stkctr->table, stkctr_entry(stkctr));
3549 }
3550 else {
3551 smp->data.u.sint = stkctr_entry(stkctr) ? stkctr_entry(stkctr)->ref_cnt : 0;
3552 }
3553
Willy Tarreau7d562212016-11-25 16:10:05 +01003554 return 1;
3555}
3556
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003557
3558/* The functions below are used to manipulate table contents from the CLI.
3559 * There are 3 main actions, "clear", "set" and "show". The code is shared
3560 * between all actions, and the action is encoded in the void *private in
3561 * the appctx as well as in the keyword registration, among one of the
3562 * following values.
3563 */
3564
3565enum {
3566 STK_CLI_ACT_CLR,
3567 STK_CLI_ACT_SET,
3568 STK_CLI_ACT_SHOW,
3569};
3570
3571/* Dump the status of a table to a stream interface's
3572 * read buffer. It returns 0 if the output buffer is full
3573 * and needs to be called again, otherwise non-zero.
3574 */
Willy Tarreau83061a82018-07-13 11:56:34 +02003575static int table_dump_head_to_buffer(struct buffer *msg,
3576 struct stream_interface *si,
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003577 struct stktable *t, struct stktable *target)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003578{
3579 struct stream *s = si_strm(si);
3580
3581 chunk_appendf(msg, "# table: %s, type: %s, size:%d, used:%d\n",
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003582 t->id, stktable_types[t->type].kw, t->size, t->current);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003583
3584 /* any other information should be dumped here */
3585
William Lallemand07a62f72017-05-24 00:57:40 +02003586 if (target && (strm_li(s)->bind_conf->level & ACCESS_LVL_MASK) < ACCESS_LVL_OPER)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003587 chunk_appendf(msg, "# contents not dumped due to insufficient privileges\n");
3588
Willy Tarreau06d80a92017-10-19 14:32:15 +02003589 if (ci_putchk(si_ic(si), msg) == -1) {
Willy Tarreaudb398432018-11-15 11:08:52 +01003590 si_rx_room_blk(si);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003591 return 0;
3592 }
3593
3594 return 1;
3595}
3596
3597/* Dump a table entry to a stream interface's
3598 * read buffer. It returns 0 if the output buffer is full
3599 * and needs to be called again, otherwise non-zero.
3600 */
Willy Tarreau83061a82018-07-13 11:56:34 +02003601static int table_dump_entry_to_buffer(struct buffer *msg,
3602 struct stream_interface *si,
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003603 struct stktable *t, struct stksess *entry)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003604{
3605 int dt;
3606
3607 chunk_appendf(msg, "%p:", entry);
3608
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003609 if (t->type == SMP_T_IPV4) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003610 char addr[INET_ADDRSTRLEN];
3611 inet_ntop(AF_INET, (const void *)&entry->key.key, addr, sizeof(addr));
3612 chunk_appendf(msg, " key=%s", addr);
3613 }
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003614 else if (t->type == SMP_T_IPV6) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003615 char addr[INET6_ADDRSTRLEN];
3616 inet_ntop(AF_INET6, (const void *)&entry->key.key, addr, sizeof(addr));
3617 chunk_appendf(msg, " key=%s", addr);
3618 }
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003619 else if (t->type == SMP_T_SINT) {
Willy Tarreau6cde5d82020-02-25 09:41:22 +01003620 chunk_appendf(msg, " key=%u", read_u32(entry->key.key));
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003621 }
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003622 else if (t->type == SMP_T_STR) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003623 chunk_appendf(msg, " key=");
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003624 dump_text(msg, (const char *)entry->key.key, t->key_size);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003625 }
3626 else {
3627 chunk_appendf(msg, " key=");
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003628 dump_binary(msg, (const char *)entry->key.key, t->key_size);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003629 }
3630
3631 chunk_appendf(msg, " use=%d exp=%d", entry->ref_cnt - 1, tick_remain(now_ms, entry->expire));
3632
3633 for (dt = 0; dt < STKTABLE_DATA_TYPES; dt++) {
3634 void *ptr;
3635
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003636 if (t->data_ofs[dt] == 0)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003637 continue;
3638 if (stktable_data_types[dt].arg_type == ARG_T_DELAY)
Emeric Brunc24b4142021-06-30 16:24:04 +02003639 chunk_appendf(msg, " %s(%u)=", stktable_data_types[dt].name, t->data_arg[dt].u);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003640 else
3641 chunk_appendf(msg, " %s=", stktable_data_types[dt].name);
3642
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003643 ptr = stktable_data_ptr(t, entry, dt);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003644 switch (stktable_data_types[dt].std_type) {
3645 case STD_T_SINT:
3646 chunk_appendf(msg, "%d", stktable_data_cast(ptr, std_t_sint));
3647 break;
3648 case STD_T_UINT:
3649 chunk_appendf(msg, "%u", stktable_data_cast(ptr, std_t_uint));
3650 break;
3651 case STD_T_ULL:
Emeric Brunc24b4142021-06-30 16:24:04 +02003652 chunk_appendf(msg, "%llu", stktable_data_cast(ptr, std_t_ull));
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003653 break;
3654 case STD_T_FRQP:
Emeric Brunc24b4142021-06-30 16:24:04 +02003655 chunk_appendf(msg, "%u",
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003656 read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003657 t->data_arg[dt].u));
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003658 break;
Frédéric Lécaille16b4f542019-05-23 12:15:04 +02003659 case STD_T_DICT: {
3660 struct dict_entry *de;
3661 de = stktable_data_cast(ptr, std_t_dict);
3662 chunk_appendf(msg, "%s", de ? (char *)de->value.key : "-");
3663 break;
3664 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003665 }
3666 }
3667 chunk_appendf(msg, "\n");
3668
Willy Tarreau06d80a92017-10-19 14:32:15 +02003669 if (ci_putchk(si_ic(si), msg) == -1) {
Willy Tarreaudb398432018-11-15 11:08:52 +01003670 si_rx_room_blk(si);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003671 return 0;
3672 }
3673
3674 return 1;
3675}
3676
3677
3678/* Processes a single table entry matching a specific key passed in argument.
3679 * returns 0 if wants to be called again, 1 if has ended processing.
3680 */
3681static int table_process_entry_per_key(struct appctx *appctx, char **args)
3682{
3683 struct stream_interface *si = appctx->owner;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003684 struct stktable *t = appctx->ctx.table.target;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003685 struct stksess *ts;
3686 uint32_t uint32_key;
3687 unsigned char ip6_key[sizeof(struct in6_addr)];
3688 long long value;
3689 int data_type;
3690 int cur_arg;
3691 void *ptr;
Willy Tarreaufa1258f2021-04-10 23:00:53 +02003692 struct freq_ctr *frqp;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003693
Willy Tarreau9d008692019-08-09 11:21:01 +02003694 if (!*args[4])
3695 return cli_err(appctx, "Key value expected\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003696
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003697 switch (t->type) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003698 case SMP_T_IPV4:
3699 uint32_key = htonl(inetaddr_host(args[4]));
Christopher Fauletca20d022017-08-29 15:30:31 +02003700 static_table_key.key = &uint32_key;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003701 break;
3702 case SMP_T_IPV6:
Christopher Faulet1e850b52021-11-15 09:17:25 +01003703 if (inet_pton(AF_INET6, args[4], ip6_key) <= 0)
3704 return cli_err(appctx, "Invalid key\n");
Christopher Fauletca20d022017-08-29 15:30:31 +02003705 static_table_key.key = &ip6_key;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003706 break;
3707 case SMP_T_SINT:
3708 {
3709 char *endptr;
3710 unsigned long val;
3711 errno = 0;
3712 val = strtoul(args[4], &endptr, 10);
3713 if ((errno == ERANGE && val == ULONG_MAX) ||
3714 (errno != 0 && val == 0) || endptr == args[4] ||
Willy Tarreau9d008692019-08-09 11:21:01 +02003715 val > 0xffffffff)
3716 return cli_err(appctx, "Invalid key\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003717 uint32_key = (uint32_t) val;
Christopher Fauletca20d022017-08-29 15:30:31 +02003718 static_table_key.key = &uint32_key;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003719 break;
3720 }
3721 break;
3722 case SMP_T_STR:
Christopher Fauletca20d022017-08-29 15:30:31 +02003723 static_table_key.key = args[4];
3724 static_table_key.key_len = strlen(args[4]);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003725 break;
3726 default:
Willy Tarreaua24bc782016-12-14 15:50:35 +01003727 switch (appctx->ctx.table.action) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003728 case STK_CLI_ACT_SHOW:
Willy Tarreau9d008692019-08-09 11:21:01 +02003729 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 +01003730 case STK_CLI_ACT_CLR:
Willy Tarreau9d008692019-08-09 11:21:01 +02003731 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 +01003732 case STK_CLI_ACT_SET:
Willy Tarreau9d008692019-08-09 11:21:01 +02003733 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 +01003734 default:
Willy Tarreau9d008692019-08-09 11:21:01 +02003735 return cli_err(appctx, "Unknown action\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003736 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003737 }
3738
3739 /* check permissions */
3740 if (!cli_has_level(appctx, ACCESS_LVL_OPER))
3741 return 1;
3742
Willy Tarreaua24bc782016-12-14 15:50:35 +01003743 switch (appctx->ctx.table.action) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003744 case STK_CLI_ACT_SHOW:
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003745 ts = stktable_lookup_key(t, &static_table_key);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003746 if (!ts)
3747 return 1;
3748 chunk_reset(&trash);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003749 if (!table_dump_head_to_buffer(&trash, si, t, t)) {
3750 stktable_release(t, ts);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003751 return 0;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003752 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003753 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003754 if (!table_dump_entry_to_buffer(&trash, si, t, ts)) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003755 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003756 stktable_release(t, ts);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003757 return 0;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003758 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003759 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003760 stktable_release(t, ts);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003761 break;
3762
3763 case STK_CLI_ACT_CLR:
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003764 ts = stktable_lookup_key(t, &static_table_key);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003765 if (!ts)
3766 return 1;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003767
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003768 if (!stksess_kill(t, ts, 1)) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003769 /* don't delete an entry which is currently referenced */
Willy Tarreau9d008692019-08-09 11:21:01 +02003770 return cli_err(appctx, "Entry currently in use, cannot remove\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003771 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003772 break;
3773
3774 case STK_CLI_ACT_SET:
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003775 ts = stktable_get_entry(t, &static_table_key);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003776 if (!ts) {
3777 /* don't delete an entry which is currently referenced */
Willy Tarreau9d008692019-08-09 11:21:01 +02003778 return cli_err(appctx, "Unable to allocate a new entry\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003779 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003780 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003781 for (cur_arg = 5; *args[cur_arg]; cur_arg += 2) {
3782 if (strncmp(args[cur_arg], "data.", 5) != 0) {
Willy Tarreau9d008692019-08-09 11:21:01 +02003783 cli_err(appctx, "\"data.<type>\" followed by a value expected\n");
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003784 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003785 stktable_touch_local(t, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003786 return 1;
3787 }
3788
3789 data_type = stktable_get_data_type(args[cur_arg] + 5);
3790 if (data_type < 0) {
Willy Tarreau9d008692019-08-09 11:21:01 +02003791 cli_err(appctx, "Unknown data type\n");
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003792 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003793 stktable_touch_local(t, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003794 return 1;
3795 }
3796
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003797 if (!t->data_ofs[data_type]) {
Willy Tarreau9d008692019-08-09 11:21:01 +02003798 cli_err(appctx, "Data type not stored in this table\n");
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003799 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003800 stktable_touch_local(t, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003801 return 1;
3802 }
3803
3804 if (!*args[cur_arg+1] || strl2llrc(args[cur_arg+1], strlen(args[cur_arg+1]), &value) != 0) {
Willy Tarreau9d008692019-08-09 11:21:01 +02003805 cli_err(appctx, "Require a valid integer value to store\n");
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003806 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003807 stktable_touch_local(t, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003808 return 1;
3809 }
3810
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003811 ptr = stktable_data_ptr(t, ts, data_type);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003812
3813 switch (stktable_data_types[data_type].std_type) {
3814 case STD_T_SINT:
3815 stktable_data_cast(ptr, std_t_sint) = value;
3816 break;
3817 case STD_T_UINT:
3818 stktable_data_cast(ptr, std_t_uint) = value;
3819 break;
3820 case STD_T_ULL:
3821 stktable_data_cast(ptr, std_t_ull) = value;
3822 break;
3823 case STD_T_FRQP:
3824 /* We set both the current and previous values. That way
3825 * the reported frequency is stable during all the period
3826 * then slowly fades out. This allows external tools to
3827 * push measures without having to update them too often.
3828 */
3829 frqp = &stktable_data_cast(ptr, std_t_frqp);
Willy Tarreaufa1258f2021-04-10 23:00:53 +02003830 /* First bit is reserved for the freq_ctr lock
Emeric Brunf2fc1fd2017-11-02 17:32:43 +01003831 Note: here we're still protected by the stksess lock
Willy Tarreaufa1258f2021-04-10 23:00:53 +02003832 so we don't need to update the update the freq_ctr
Emeric Brunf2fc1fd2017-11-02 17:32:43 +01003833 using its internal lock */
3834 frqp->curr_tick = now_ms & ~0x1;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003835 frqp->prev_ctr = 0;
3836 frqp->curr_ctr = value;
3837 break;
3838 }
3839 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003840 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003841 stktable_touch_local(t, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003842 break;
3843
3844 default:
Willy Tarreau9d008692019-08-09 11:21:01 +02003845 return cli_err(appctx, "Unknown action\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003846 }
3847 return 1;
3848}
3849
3850/* Prepares the appctx fields with the data-based filters from the command line.
3851 * Returns 0 if the dump can proceed, 1 if has ended processing.
3852 */
3853static int table_prepare_data_request(struct appctx *appctx, char **args)
3854{
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01003855 int i;
Adis Nezirovicd0142e72020-01-22 16:50:27 +01003856 char *err = NULL;
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01003857
Willy Tarreau9d008692019-08-09 11:21:01 +02003858 if (appctx->ctx.table.action != STK_CLI_ACT_SHOW && appctx->ctx.table.action != STK_CLI_ACT_CLR)
3859 return cli_err(appctx, "content-based lookup is only supported with the \"show\" and \"clear\" actions\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003860
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01003861 for (i = 0; i < STKTABLE_FILTER_LEN; i++) {
3862 if (i > 0 && !*args[3+3*i]) // number of filter entries can be less than STKTABLE_FILTER_LEN
3863 break;
3864 /* condition on stored data value */
3865 appctx->ctx.table.data_type[i] = stktable_get_data_type(args[3+3*i] + 5);
3866 if (appctx->ctx.table.data_type[i] < 0)
Adis Nezirovicd0142e72020-01-22 16:50:27 +01003867 return cli_dynerr(appctx, memprintf(&err, "Filter entry #%i: Unknown data type\n", i + 1));
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003868
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01003869 if (!((struct stktable *)appctx->ctx.table.target)->data_ofs[appctx->ctx.table.data_type[i]])
Adis Nezirovicd0142e72020-01-22 16:50:27 +01003870 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 +01003871
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01003872 appctx->ctx.table.data_op[i] = get_std_op(args[4+3*i]);
Willy Tarreau2b64a352020-01-22 17:09:47 +01003873 if (appctx->ctx.table.data_op[i] < 0)
Adis Nezirovicd0142e72020-01-22 16:50:27 +01003874 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 +01003875
Adis Nezirovic56dd3542020-01-22 16:16:48 +01003876 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 +01003877 return cli_dynerr(appctx, memprintf(&err, "Filter entry #%i: Require a valid integer value to compare against\n", i + 1));
3878 }
3879
3880 if (*args[3+3*i]) {
3881 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 +01003882 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003883
3884 /* OK we're done, all the fields are set */
3885 return 0;
3886}
3887
3888/* returns 0 if wants to be called, 1 if has ended processing */
Aurélien Nephtaliabbf6072018-04-18 13:26:46 +02003889static int cli_parse_table_req(char **args, char *payload, struct appctx *appctx, void *private)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003890{
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01003891 int i;
3892
3893 for (i = 0; i < STKTABLE_FILTER_LEN; i++)
3894 appctx->ctx.table.data_type[i] = -1;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003895 appctx->ctx.table.target = NULL;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003896 appctx->ctx.table.entry = NULL;
Willy Tarreaua24bc782016-12-14 15:50:35 +01003897 appctx->ctx.table.action = (long)private; // keyword argument, one of STK_CLI_ACT_*
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003898
3899 if (*args[2]) {
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003900 appctx->ctx.table.target = stktable_find_by_name(args[2]);
Willy Tarreau9d008692019-08-09 11:21:01 +02003901 if (!appctx->ctx.table.target)
3902 return cli_err(appctx, "No such table\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003903 }
3904 else {
Willy Tarreaua24bc782016-12-14 15:50:35 +01003905 if (appctx->ctx.table.action != STK_CLI_ACT_SHOW)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003906 goto err_args;
3907 return 0;
3908 }
3909
3910 if (strcmp(args[3], "key") == 0)
3911 return table_process_entry_per_key(appctx, args);
3912 else if (strncmp(args[3], "data.", 5) == 0)
3913 return table_prepare_data_request(appctx, args);
3914 else if (*args[3])
3915 goto err_args;
3916
3917 return 0;
3918
3919err_args:
Willy Tarreaua24bc782016-12-14 15:50:35 +01003920 switch (appctx->ctx.table.action) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003921 case STK_CLI_ACT_SHOW:
Willy Tarreau9d008692019-08-09 11:21:01 +02003922 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 +01003923 case STK_CLI_ACT_CLR:
Willy Tarreau9d008692019-08-09 11:21:01 +02003924 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 +01003925 case STK_CLI_ACT_SET:
Willy Tarreau9d008692019-08-09 11:21:01 +02003926 return cli_err(appctx, "Required arguments: <table> key <key> [data.<store_data_type> <value>]*\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003927 default:
Willy Tarreau9d008692019-08-09 11:21:01 +02003928 return cli_err(appctx, "Unknown action\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003929 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003930}
3931
3932/* This function is used to deal with table operations (dump or clear depending
3933 * on the action stored in appctx->private). It returns 0 if the output buffer is
3934 * full and it needs to be called again, otherwise non-zero.
3935 */
3936static int cli_io_handler_table(struct appctx *appctx)
3937{
3938 struct stream_interface *si = appctx->owner;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003939 struct stream *s = si_strm(si);
3940 struct ebmb_node *eb;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003941 int skip_entry;
Willy Tarreaua24bc782016-12-14 15:50:35 +01003942 int show = appctx->ctx.table.action == STK_CLI_ACT_SHOW;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003943
3944 /*
3945 * We have 3 possible states in appctx->st2 :
3946 * - STAT_ST_INIT : the first call
3947 * - STAT_ST_INFO : the proxy pointer points to the next table to
3948 * dump, the entry pointer is NULL ;
3949 * - STAT_ST_LIST : the proxy pointer points to the current table
3950 * and the entry pointer points to the next entry to be dumped,
3951 * and the refcount on the next entry is held ;
3952 * - STAT_ST_END : nothing left to dump, the buffer may contain some
3953 * data though.
3954 */
3955
3956 if (unlikely(si_ic(si)->flags & (CF_WRITE_ERROR|CF_SHUTW))) {
3957 /* in case of abort, remove any refcount we might have set on an entry */
3958 if (appctx->st2 == STAT_ST_LIST) {
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003959 stksess_kill_if_expired(appctx->ctx.table.t, appctx->ctx.table.entry, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003960 }
3961 return 1;
3962 }
3963
3964 chunk_reset(&trash);
3965
3966 while (appctx->st2 != STAT_ST_FIN) {
3967 switch (appctx->st2) {
3968 case STAT_ST_INIT:
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003969 appctx->ctx.table.t = appctx->ctx.table.target;
3970 if (!appctx->ctx.table.t)
3971 appctx->ctx.table.t = stktables_list;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003972
3973 appctx->ctx.table.entry = NULL;
3974 appctx->st2 = STAT_ST_INFO;
3975 break;
3976
3977 case STAT_ST_INFO:
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003978 if (!appctx->ctx.table.t ||
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003979 (appctx->ctx.table.target &&
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003980 appctx->ctx.table.t != appctx->ctx.table.target)) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003981 appctx->st2 = STAT_ST_END;
3982 break;
3983 }
3984
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003985 if (appctx->ctx.table.t->size) {
3986 if (show && !table_dump_head_to_buffer(&trash, si, appctx->ctx.table.t, appctx->ctx.table.target))
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003987 return 0;
3988
3989 if (appctx->ctx.table.target &&
William Lallemand07a62f72017-05-24 00:57:40 +02003990 (strm_li(s)->bind_conf->level & ACCESS_LVL_MASK) >= ACCESS_LVL_OPER) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003991 /* dump entries only if table explicitly requested */
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003992 HA_SPIN_LOCK(STK_TABLE_LOCK, &appctx->ctx.table.t->lock);
3993 eb = ebmb_first(&appctx->ctx.table.t->keys);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003994 if (eb) {
3995 appctx->ctx.table.entry = ebmb_entry(eb, struct stksess, key);
3996 appctx->ctx.table.entry->ref_cnt++;
3997 appctx->st2 = STAT_ST_LIST;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003998 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &appctx->ctx.table.t->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003999 break;
4000 }
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004001 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &appctx->ctx.table.t->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004002 }
4003 }
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004004 appctx->ctx.table.t = appctx->ctx.table.t->next;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004005 break;
4006
4007 case STAT_ST_LIST:
4008 skip_entry = 0;
4009
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004010 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &appctx->ctx.table.entry->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004011
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004012 if (appctx->ctx.table.data_type[0] >= 0) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004013 /* we're filtering on some data contents */
4014 void *ptr;
Willy Tarreau2b64a352020-01-22 17:09:47 +01004015 int dt, i;
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004016 signed char op;
4017 long long data, value;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004018
Emeric Brun819fc6f2017-06-13 19:37:32 +02004019
Willy Tarreau2b64a352020-01-22 17:09:47 +01004020 for (i = 0; i < STKTABLE_FILTER_LEN; i++) {
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004021 if (appctx->ctx.table.data_type[i] == -1)
4022 break;
4023 dt = appctx->ctx.table.data_type[i];
4024 ptr = stktable_data_ptr(appctx->ctx.table.t,
4025 appctx->ctx.table.entry,
4026 dt);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004027
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004028 data = 0;
4029 switch (stktable_data_types[dt].std_type) {
4030 case STD_T_SINT:
4031 data = stktable_data_cast(ptr, std_t_sint);
4032 break;
4033 case STD_T_UINT:
4034 data = stktable_data_cast(ptr, std_t_uint);
4035 break;
4036 case STD_T_ULL:
4037 data = stktable_data_cast(ptr, std_t_ull);
4038 break;
4039 case STD_T_FRQP:
4040 data = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
4041 appctx->ctx.table.t->data_arg[dt].u);
4042 break;
4043 }
4044
4045 op = appctx->ctx.table.data_op[i];
4046 value = appctx->ctx.table.value[i];
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004047
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004048 /* skip the entry if the data does not match the test and the value */
4049 if ((data < value &&
4050 (op == STD_OP_EQ || op == STD_OP_GT || op == STD_OP_GE)) ||
4051 (data == value &&
4052 (op == STD_OP_NE || op == STD_OP_GT || op == STD_OP_LT)) ||
4053 (data > value &&
4054 (op == STD_OP_EQ || op == STD_OP_LT || op == STD_OP_LE))) {
4055 skip_entry = 1;
4056 break;
4057 }
4058 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004059 }
4060
4061 if (show && !skip_entry &&
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004062 !table_dump_entry_to_buffer(&trash, si, appctx->ctx.table.t, appctx->ctx.table.entry)) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004063 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &appctx->ctx.table.entry->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004064 return 0;
4065 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004066
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004067 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &appctx->ctx.table.entry->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004068
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004069 HA_SPIN_LOCK(STK_TABLE_LOCK, &appctx->ctx.table.t->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004070 appctx->ctx.table.entry->ref_cnt--;
4071
4072 eb = ebmb_next(&appctx->ctx.table.entry->key);
4073 if (eb) {
4074 struct stksess *old = appctx->ctx.table.entry;
4075 appctx->ctx.table.entry = ebmb_entry(eb, struct stksess, key);
4076 if (show)
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004077 __stksess_kill_if_expired(appctx->ctx.table.t, old);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004078 else if (!skip_entry && !appctx->ctx.table.entry->ref_cnt)
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004079 __stksess_kill(appctx->ctx.table.t, old);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004080 appctx->ctx.table.entry->ref_cnt++;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004081 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &appctx->ctx.table.t->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004082 break;
4083 }
4084
4085
4086 if (show)
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004087 __stksess_kill_if_expired(appctx->ctx.table.t, appctx->ctx.table.entry);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004088 else if (!skip_entry && !appctx->ctx.table.entry->ref_cnt)
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004089 __stksess_kill(appctx->ctx.table.t, appctx->ctx.table.entry);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004090
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004091 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &appctx->ctx.table.t->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004092
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004093 appctx->ctx.table.t = appctx->ctx.table.t->next;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004094 appctx->st2 = STAT_ST_INFO;
4095 break;
4096
4097 case STAT_ST_END:
4098 appctx->st2 = STAT_ST_FIN;
4099 break;
4100 }
4101 }
4102 return 1;
4103}
4104
4105static void cli_release_show_table(struct appctx *appctx)
4106{
4107 if (appctx->st2 == STAT_ST_LIST) {
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004108 stksess_kill_if_expired(appctx->ctx.table.t, appctx->ctx.table.entry, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004109 }
4110}
4111
Willy Tarreau478331d2020-08-28 11:31:31 +02004112static void stkt_late_init(void)
4113{
4114 struct sample_fetch *f;
4115
4116 f = find_sample_fetch("src", strlen("src"));
4117 if (f)
4118 smp_fetch_src = f->process;
4119}
4120
4121INITCALL0(STG_INIT, stkt_late_init);
4122
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004123/* register cli keywords */
4124static struct cli_kw_list cli_kws = {{ },{
Willy Tarreaub205bfd2021-05-07 11:38:37 +02004125 { { "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 },
4126 { { "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 },
4127 { { "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 +01004128 {{},}
4129}};
4130
Willy Tarreau0108d902018-11-25 19:14:37 +01004131INITCALL1(STG_REGISTER, cli_register_kw, &cli_kws);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004132
Thierry FOURNIER236657b2015-08-19 08:25:14 +02004133static struct action_kw_list tcp_conn_kws = { { }, {
Amaury Denoyellee4a617c2021-05-06 15:33:09 +02004134 { "sc-inc-gpc0", parse_inc_gpc0, KWF_MATCH_PREFIX },
4135 { "sc-inc-gpc1", parse_inc_gpc1, KWF_MATCH_PREFIX },
4136 { "sc-set-gpt0", parse_set_gpt0, KWF_MATCH_PREFIX },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02004137 { /* END */ }
4138}};
4139
Willy Tarreau0108d902018-11-25 19:14:37 +01004140INITCALL1(STG_REGISTER, tcp_req_conn_keywords_register, &tcp_conn_kws);
4141
Willy Tarreau620408f2016-10-21 16:37:51 +02004142static struct action_kw_list tcp_sess_kws = { { }, {
Amaury Denoyellee4a617c2021-05-06 15:33:09 +02004143 { "sc-inc-gpc0", parse_inc_gpc0, KWF_MATCH_PREFIX },
4144 { "sc-inc-gpc1", parse_inc_gpc1, KWF_MATCH_PREFIX },
4145 { "sc-set-gpt0", parse_set_gpt0, KWF_MATCH_PREFIX },
Willy Tarreau620408f2016-10-21 16:37:51 +02004146 { /* END */ }
4147}};
4148
Willy Tarreau0108d902018-11-25 19:14:37 +01004149INITCALL1(STG_REGISTER, tcp_req_sess_keywords_register, &tcp_sess_kws);
4150
Thierry FOURNIER236657b2015-08-19 08:25:14 +02004151static struct action_kw_list tcp_req_kws = { { }, {
Amaury Denoyellee4a617c2021-05-06 15:33:09 +02004152 { "sc-inc-gpc0", parse_inc_gpc0, KWF_MATCH_PREFIX },
4153 { "sc-inc-gpc1", parse_inc_gpc1, KWF_MATCH_PREFIX },
4154 { "sc-set-gpt0", parse_set_gpt0, KWF_MATCH_PREFIX },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02004155 { /* END */ }
4156}};
4157
Willy Tarreau0108d902018-11-25 19:14:37 +01004158INITCALL1(STG_REGISTER, tcp_req_cont_keywords_register, &tcp_req_kws);
4159
Thierry FOURNIER236657b2015-08-19 08:25:14 +02004160static struct action_kw_list tcp_res_kws = { { }, {
Amaury Denoyellee4a617c2021-05-06 15:33:09 +02004161 { "sc-inc-gpc0", parse_inc_gpc0, KWF_MATCH_PREFIX },
4162 { "sc-inc-gpc1", parse_inc_gpc1, KWF_MATCH_PREFIX },
4163 { "sc-set-gpt0", parse_set_gpt0, KWF_MATCH_PREFIX },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02004164 { /* END */ }
4165}};
4166
Willy Tarreau0108d902018-11-25 19:14:37 +01004167INITCALL1(STG_REGISTER, tcp_res_cont_keywords_register, &tcp_res_kws);
4168
Thierry FOURNIER236657b2015-08-19 08:25:14 +02004169static struct action_kw_list http_req_kws = { { }, {
Amaury Denoyellee4a617c2021-05-06 15:33:09 +02004170 { "sc-inc-gpc0", parse_inc_gpc0, KWF_MATCH_PREFIX },
4171 { "sc-inc-gpc1", parse_inc_gpc1, KWF_MATCH_PREFIX },
4172 { "sc-set-gpt0", parse_set_gpt0, KWF_MATCH_PREFIX },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02004173 { /* END */ }
4174}};
4175
Willy Tarreau0108d902018-11-25 19:14:37 +01004176INITCALL1(STG_REGISTER, http_req_keywords_register, &http_req_kws);
4177
Thierry FOURNIER236657b2015-08-19 08:25:14 +02004178static struct action_kw_list http_res_kws = { { }, {
Amaury Denoyellee4a617c2021-05-06 15:33:09 +02004179 { "sc-inc-gpc0", parse_inc_gpc0, KWF_MATCH_PREFIX },
4180 { "sc-inc-gpc1", parse_inc_gpc1, KWF_MATCH_PREFIX },
4181 { "sc-set-gpt0", parse_set_gpt0, KWF_MATCH_PREFIX },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02004182 { /* END */ }
4183}};
4184
Willy Tarreau0108d902018-11-25 19:14:37 +01004185INITCALL1(STG_REGISTER, http_res_keywords_register, &http_res_kws);
4186
Willy Tarreau7d562212016-11-25 16:10:05 +01004187/* Note: must not be declared <const> as its list will be overwritten.
4188 * Please take care of keeping this list alphabetically sorted.
4189 */
4190static struct sample_fetch_kw_list smp_fetch_keywords = {ILH, {
4191 { "sc_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4192 { "sc_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4193 { "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 +01004194 { "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 +01004195 { "sc_conn_cnt", smp_fetch_sc_conn_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4196 { "sc_conn_cur", smp_fetch_sc_conn_cur, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4197 { "sc_conn_rate", smp_fetch_sc_conn_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
Thierry FOURNIER401c64b2017-01-05 11:44:09 +01004198 { "sc_get_gpt0", smp_fetch_sc_get_gpt0, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
Willy Tarreau7d562212016-11-25 16:10:05 +01004199 { "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 +01004200 { "sc_get_gpc1", smp_fetch_sc_get_gpc1, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN },
Willy Tarreau7d562212016-11-25 16:10:05 +01004201 { "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 +01004202 { "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 +01004203 { "sc_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4204 { "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 +01004205 { "sc_http_fail_cnt", smp_fetch_sc_http_fail_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4206 { "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 +01004207 { "sc_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4208 { "sc_http_req_rate", smp_fetch_sc_http_req_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4209 { "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 +01004210 { "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 +01004211 { "sc_kbytes_in", smp_fetch_sc_kbytes_in, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4212 { "sc_kbytes_out", smp_fetch_sc_kbytes_out, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4213 { "sc_sess_cnt", smp_fetch_sc_sess_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4214 { "sc_sess_rate", smp_fetch_sc_sess_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4215 { "sc_tracked", smp_fetch_sc_tracked, ARG2(1,SINT,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
4216 { "sc_trackers", smp_fetch_sc_trackers, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4217 { "sc0_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4218 { "sc0_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4219 { "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 +01004220 { "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 +01004221 { "sc0_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4222 { "sc0_conn_cur", smp_fetch_sc_conn_cur, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4223 { "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 +01004224 { "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 +01004225 { "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 +01004226 { "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 +01004227 { "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 +01004228 { "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 +01004229 { "sc0_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4230 { "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 +01004231 { "sc0_http_fail_cnt", smp_fetch_sc_http_fail_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4232 { "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 +01004233 { "sc0_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4234 { "sc0_http_req_rate", smp_fetch_sc_http_req_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4235 { "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 +01004236 { "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 +01004237 { "sc0_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4238 { "sc0_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4239 { "sc0_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4240 { "sc0_sess_rate", smp_fetch_sc_sess_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4241 { "sc0_tracked", smp_fetch_sc_tracked, ARG1(0,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
4242 { "sc0_trackers", smp_fetch_sc_trackers, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4243 { "sc1_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4244 { "sc1_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4245 { "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 +01004246 { "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 +01004247 { "sc1_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4248 { "sc1_conn_cur", smp_fetch_sc_conn_cur, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4249 { "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 +01004250 { "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 +01004251 { "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 +01004252 { "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 +01004253 { "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 +01004254 { "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 +01004255 { "sc1_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4256 { "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 +01004257 { "sc1_http_fail_cnt", smp_fetch_sc_http_fail_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4258 { "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 +01004259 { "sc1_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4260 { "sc1_http_req_rate", smp_fetch_sc_http_req_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4261 { "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 +01004262 { "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 +01004263 { "sc1_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4264 { "sc1_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4265 { "sc1_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4266 { "sc1_sess_rate", smp_fetch_sc_sess_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4267 { "sc1_tracked", smp_fetch_sc_tracked, ARG1(0,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
4268 { "sc1_trackers", smp_fetch_sc_trackers, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4269 { "sc2_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4270 { "sc2_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4271 { "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 +01004272 { "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 +01004273 { "sc2_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4274 { "sc2_conn_cur", smp_fetch_sc_conn_cur, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4275 { "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 +01004276 { "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 +01004277 { "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 +01004278 { "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 +01004279 { "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 +01004280 { "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 +01004281 { "sc2_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4282 { "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 +01004283 { "sc2_http_fail_cnt", smp_fetch_sc_http_fail_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4284 { "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 +01004285 { "sc2_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4286 { "sc2_http_req_rate", smp_fetch_sc_http_req_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4287 { "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 +01004288 { "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 +01004289 { "sc2_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4290 { "sc2_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4291 { "sc2_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4292 { "sc2_sess_rate", smp_fetch_sc_sess_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4293 { "sc2_tracked", smp_fetch_sc_tracked, ARG1(0,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
4294 { "sc2_trackers", smp_fetch_sc_trackers, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4295 { "src_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4296 { "src_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4297 { "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 +01004298 { "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 +01004299 { "src_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4300 { "src_conn_cur", smp_fetch_sc_conn_cur, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4301 { "src_conn_rate", smp_fetch_sc_conn_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
Thierry FOURNIER401c64b2017-01-05 11:44:09 +01004302 { "src_get_gpt0", smp_fetch_sc_get_gpt0, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
Willy Tarreau7d562212016-11-25 16:10:05 +01004303 { "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 +01004304 { "src_get_gpc1", smp_fetch_sc_get_gpc1, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
Willy Tarreau7d562212016-11-25 16:10:05 +01004305 { "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 +01004306 { "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 +01004307 { "src_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4308 { "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 +01004309 { "src_http_fail_cnt", smp_fetch_sc_http_fail_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4310 { "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 +01004311 { "src_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4312 { "src_http_req_rate", smp_fetch_sc_http_req_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4313 { "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 +01004314 { "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 +01004315 { "src_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4316 { "src_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4317 { "src_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4318 { "src_sess_rate", smp_fetch_sc_sess_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4319 { "src_updt_conn_cnt", smp_fetch_src_updt_conn_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4320 { "table_avl", smp_fetch_table_avl, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4321 { "table_cnt", smp_fetch_table_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4322 { /* END */ },
4323}};
4324
Willy Tarreau0108d902018-11-25 19:14:37 +01004325INITCALL1(STG_REGISTER, sample_register_fetches, &smp_fetch_keywords);
Willy Tarreau7d562212016-11-25 16:10:05 +01004326
Willy Tarreaud9f316a2014-07-10 14:03:38 +02004327/* Note: must not be declared <const> as its list will be overwritten */
4328static struct sample_conv_kw_list sample_conv_kws = {ILH, {
Willy Tarreau2d17db52016-05-25 17:16:38 +02004329 { "in_table", sample_conv_in_table, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_BOOL },
4330 { "table_bytes_in_rate", sample_conv_table_bytes_in_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4331 { "table_bytes_out_rate", sample_conv_table_bytes_out_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4332 { "table_conn_cnt", sample_conv_table_conn_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4333 { "table_conn_cur", sample_conv_table_conn_cur, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4334 { "table_conn_rate", sample_conv_table_conn_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4335 { "table_gpt0", sample_conv_table_gpt0, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4336 { "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 +01004337 { "table_gpc1", sample_conv_table_gpc1, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
Willy Tarreau2d17db52016-05-25 17:16:38 +02004338 { "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 +01004339 { "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 +02004340 { "table_http_err_cnt", sample_conv_table_http_err_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4341 { "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 +01004342 { "table_http_fail_cnt", sample_conv_table_http_fail_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4343 { "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 +02004344 { "table_http_req_cnt", sample_conv_table_http_req_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4345 { "table_http_req_rate", sample_conv_table_http_req_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4346 { "table_kbytes_in", sample_conv_table_kbytes_in, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4347 { "table_kbytes_out", sample_conv_table_kbytes_out, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4348 { "table_server_id", sample_conv_table_server_id, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4349 { "table_sess_cnt", sample_conv_table_sess_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4350 { "table_sess_rate", sample_conv_table_sess_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4351 { "table_trackers", sample_conv_table_trackers, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
Willy Tarreaud9f316a2014-07-10 14:03:38 +02004352 { /* END */ },
4353}};
4354
Willy Tarreau0108d902018-11-25 19:14:37 +01004355INITCALL1(STG_REGISTER, sample_register_convs, &sample_conv_kws);