blob: 6f07080f64a97253ba271fb17ad5e9a5d85f8e62 [file] [log] [blame]
Emeric Brun3bd697e2010-01-04 15:23:48 +01001/*
2 * Stick tables management functions.
3 *
4 * Copyright 2009-2010 EXCELIANCE, Emeric Brun <ebrun@exceliance.fr>
Willy Tarreau08d5f982010-06-06 13:34:54 +02005 * Copyright (C) 2010 Willy Tarreau <w@1wt.eu>
Emeric Brun3bd697e2010-01-04 15:23:48 +01006 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version
10 * 2 of the License, or (at your option) any later version.
11 *
12 */
13
14#include <string.h>
Willy Tarreauf13ebdf2016-11-22 18:00:53 +010015#include <errno.h>
Emeric Brun3bd697e2010-01-04 15:23:48 +010016
Willy Tarreaub2551052020-06-09 09:07:15 +020017#include <import/ebmbtree.h>
18#include <import/ebsttree.h>
19#include <import/ebistree.h>
20
Willy Tarreau4c7e4b72020-05-27 12:58:42 +020021#include <haproxy/api.h>
Willy Tarreaub2551052020-06-09 09:07:15 +020022#include <haproxy/arg.h>
Willy Tarreau6be78492020-06-05 00:00:29 +020023#include <haproxy/cfgparse.h>
Willy Tarreau83487a82020-06-04 20:19:54 +020024#include <haproxy/cli.h>
Thayne McCombs92149f92020-11-20 01:28:26 -070025#include <haproxy/dict.h>
Willy Tarreau36979d92020-06-05 17:27:29 +020026#include <haproxy/errors.h>
Willy Tarreauf268ee82020-06-04 17:05:57 +020027#include <haproxy/global.h>
Willy Tarreauc761f842020-06-04 11:40:28 +020028#include <haproxy/http_rules.h>
Willy Tarreau853b2972020-05-27 18:01:47 +020029#include <haproxy/list.h>
Willy Tarreauaeed4a82020-06-04 22:01:04 +020030#include <haproxy/log.h>
Willy Tarreau6131d6a2020-06-02 16:48:09 +020031#include <haproxy/net_helper.h>
Willy Tarreau3c2a7c22020-06-04 18:38:21 +020032#include <haproxy/peers.h>
Willy Tarreaub2551052020-06-09 09:07:15 +020033#include <haproxy/pool.h>
34#include <haproxy/proto_tcp.h>
Willy Tarreaua264d962020-06-04 22:29:18 +020035#include <haproxy/proxy.h>
Willy Tarreaub2551052020-06-09 09:07:15 +020036#include <haproxy/sample.h>
Willy Tarreau2eec9b52020-06-04 19:58:55 +020037#include <haproxy/stats-t.h>
Willy Tarreaub2551052020-06-09 09:07:15 +020038#include <haproxy/stick_table.h>
Willy Tarreaudfd3de82020-06-04 23:46:14 +020039#include <haproxy/stream.h>
Willy Tarreau5e539c92020-06-04 20:45:39 +020040#include <haproxy/stream_interface.h>
Willy Tarreaucea0e1b2020-06-04 17:25:40 +020041#include <haproxy/task.h>
Willy Tarreau8b550af2020-06-04 17:42:48 +020042#include <haproxy/tcp_rules.h>
Willy Tarreau92b4f132020-06-01 11:05:15 +020043#include <haproxy/time.h>
Willy Tarreaub2551052020-06-09 09:07:15 +020044#include <haproxy/tools.h>
Emeric Brun3bd697e2010-01-04 15:23:48 +010045
Emeric Brun3bd697e2010-01-04 15:23:48 +010046
Willy Tarreau12785782012-04-27 21:37:17 +020047/* structure used to return a table key built from a sample */
Emeric Brun819fc6f2017-06-13 19:37:32 +020048static THREAD_LOCAL struct stktable_key static_table_key;
Willy Tarreau478331d2020-08-28 11:31:31 +020049static int (*smp_fetch_src)(const struct arg *, struct sample *, const char *, void *);
Willy Tarreauf0b38bf2010-06-06 13:22:23 +020050
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +010051struct stktable *stktables_list;
52struct eb_root stktable_by_name = EB_ROOT;
53
Olivier Houchard52dabbc2018-11-14 17:54:36 +010054#define round_ptr_size(i) (((i) + (sizeof(void *) - 1)) &~ (sizeof(void *) - 1))
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +010055
56/* This function inserts stktable <t> into the tree of known stick-table.
57 * The stick-table ID is used as the storing key so it must already have
58 * been initialized.
59 */
60void stktable_store_name(struct stktable *t)
61{
62 t->name.key = t->id;
63 ebis_insert(&stktable_by_name, &t->name);
64}
65
66struct stktable *stktable_find_by_name(const char *name)
67{
68 struct ebpt_node *node;
69 struct stktable *t;
70
71 node = ebis_lookup(&stktable_by_name, name);
72 if (node) {
73 t = container_of(node, struct stktable, name);
Tim Duesterhuse5ff1412021-01-02 22:31:53 +010074 if (strcmp(t->id, name) == 0)
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +010075 return t;
76 }
77
78 return NULL;
79}
80
Emeric Brun3bd697e2010-01-04 15:23:48 +010081/*
Willy Tarreauaea940e2010-06-06 11:56:36 +020082 * Free an allocated sticky session <ts>, and decrease sticky sessions counter
83 * in table <t>.
Emeric Brun3bd697e2010-01-04 15:23:48 +010084 */
Emeric Brun819fc6f2017-06-13 19:37:32 +020085void __stksess_free(struct stktable *t, struct stksess *ts)
Emeric Brun3bd697e2010-01-04 15:23:48 +010086{
87 t->current--;
Olivier Houchard52dabbc2018-11-14 17:54:36 +010088 pool_free(t->pool, (void *)ts - round_ptr_size(t->data_size));
Emeric Brun3bd697e2010-01-04 15:23:48 +010089}
90
91/*
Emeric Brun819fc6f2017-06-13 19:37:32 +020092 * Free an allocated sticky session <ts>, and decrease sticky sessions counter
93 * in table <t>.
94 * This function locks the table
95 */
96void stksess_free(struct stktable *t, struct stksess *ts)
97{
Thayne McCombs92149f92020-11-20 01:28:26 -070098 void *data;
99 data = stktable_data_ptr(t, ts, STKTABLE_DT_SERVER_KEY);
100 if (data) {
Emeric Brun0e3457b2021-06-30 17:18:28 +0200101 dict_entry_unref(&server_key_dict, stktable_data_cast(data, std_t_dict));
102 stktable_data_cast(data, std_t_dict) = NULL;
Thayne McCombs92149f92020-11-20 01:28:26 -0700103 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100104 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200105 __stksess_free(t, ts);
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100106 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200107}
108
109/*
Willy Tarreauf6efda12010-08-03 20:34:06 +0200110 * Kill an stksess (only if its ref_cnt is zero).
111 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200112int __stksess_kill(struct stktable *t, struct stksess *ts)
Willy Tarreauf6efda12010-08-03 20:34:06 +0200113{
114 if (ts->ref_cnt)
Emeric Brun819fc6f2017-06-13 19:37:32 +0200115 return 0;
Willy Tarreauf6efda12010-08-03 20:34:06 +0200116
117 eb32_delete(&ts->exp);
Emeric Brun85e77c72010-09-23 18:16:52 +0200118 eb32_delete(&ts->upd);
Willy Tarreauf6efda12010-08-03 20:34:06 +0200119 ebmb_delete(&ts->key);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200120 __stksess_free(t, ts);
121 return 1;
Willy Tarreauf6efda12010-08-03 20:34:06 +0200122}
123
124/*
Emeric Brun819fc6f2017-06-13 19:37:32 +0200125 * Decrease the refcount if decrefcnt is not 0.
126 * and try to kill the stksess
127 * This function locks the table
128 */
129int stksess_kill(struct stktable *t, struct stksess *ts, int decrefcnt)
130{
131 int ret;
132
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100133 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200134 if (decrefcnt)
135 ts->ref_cnt--;
136 ret = __stksess_kill(t, ts);
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100137 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200138
139 return ret;
140}
141
142/*
Willy Tarreauaea940e2010-06-06 11:56:36 +0200143 * Initialize or update the key in the sticky session <ts> present in table <t>
144 * from the value present in <key>.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100145 */
Willy Tarreau393379c2010-06-06 12:11:37 +0200146void stksess_setkey(struct stktable *t, struct stksess *ts, struct stktable_key *key)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100147{
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200148 if (t->type != SMP_T_STR)
Willy Tarreau86257dc2010-06-06 12:57:10 +0200149 memcpy(ts->key.key, key->key, t->key_size);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100150 else {
Willy Tarreau86257dc2010-06-06 12:57:10 +0200151 memcpy(ts->key.key, key->key, MIN(t->key_size - 1, key->key_len));
152 ts->key.key[MIN(t->key_size - 1, key->key_len)] = 0;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100153 }
154}
155
156
157/*
Willy Tarreau393379c2010-06-06 12:11:37 +0200158 * Init sticky session <ts> of table <t>. The data parts are cleared and <ts>
159 * is returned.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100160 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200161static struct stksess *__stksess_init(struct stktable *t, struct stksess * ts)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100162{
Willy Tarreau393379c2010-06-06 12:11:37 +0200163 memset((void *)ts - t->data_size, 0, t->data_size);
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200164 ts->ref_cnt = 0;
Willy Tarreau86257dc2010-06-06 12:57:10 +0200165 ts->key.node.leaf_p = NULL;
166 ts->exp.node.leaf_p = NULL;
Emeric Brun85e77c72010-09-23 18:16:52 +0200167 ts->upd.node.leaf_p = NULL;
Emeric Brun819fc6f2017-06-13 19:37:32 +0200168 ts->expire = tick_add(now_ms, MS_TO_TICKS(t->expire));
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100169 HA_RWLOCK_INIT(&ts->lock);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100170 return ts;
171}
172
173/*
Willy Tarreauaea940e2010-06-06 11:56:36 +0200174 * Trash oldest <to_batch> sticky sessions from table <t>
Willy Tarreaudfe79252020-11-03 17:47:41 +0100175 * Returns number of trashed sticky sessions. It may actually trash less
176 * than expected if finding these requires too long a search time (e.g.
177 * most of them have ts->ref_cnt>0).
Emeric Brun3bd697e2010-01-04 15:23:48 +0100178 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200179int __stktable_trash_oldest(struct stktable *t, int to_batch)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100180{
181 struct stksess *ts;
182 struct eb32_node *eb;
Willy Tarreaudfe79252020-11-03 17:47:41 +0100183 int max_search = to_batch * 2; // no more than 50% misses
Emeric Brun3bd697e2010-01-04 15:23:48 +0100184 int batched = 0;
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200185 int looped = 0;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100186
187 eb = eb32_lookup_ge(&t->exps, now_ms - TIMER_LOOK_BACK);
188
189 while (batched < to_batch) {
190
191 if (unlikely(!eb)) {
192 /* we might have reached the end of the tree, typically because
193 * <now_ms> is in the first half and we're first scanning the last
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200194 * half. Let's loop back to the beginning of the tree now if we
195 * have not yet visited it.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100196 */
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200197 if (looped)
198 break;
199 looped = 1;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100200 eb = eb32_first(&t->exps);
201 if (likely(!eb))
202 break;
203 }
204
Willy Tarreaudfe79252020-11-03 17:47:41 +0100205 if (--max_search < 0)
206 break;
207
Emeric Brun3bd697e2010-01-04 15:23:48 +0100208 /* timer looks expired, detach it from the queue */
Willy Tarreau86257dc2010-06-06 12:57:10 +0200209 ts = eb32_entry(eb, struct stksess, exp);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100210 eb = eb32_next(eb);
211
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200212 /* don't delete an entry which is currently referenced */
213 if (ts->ref_cnt)
214 continue;
215
Willy Tarreau86257dc2010-06-06 12:57:10 +0200216 eb32_delete(&ts->exp);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100217
Willy Tarreau86257dc2010-06-06 12:57:10 +0200218 if (ts->expire != ts->exp.key) {
Emeric Brun3bd697e2010-01-04 15:23:48 +0100219 if (!tick_isset(ts->expire))
220 continue;
221
Willy Tarreau86257dc2010-06-06 12:57:10 +0200222 ts->exp.key = ts->expire;
223 eb32_insert(&t->exps, &ts->exp);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100224
Willy Tarreau86257dc2010-06-06 12:57:10 +0200225 if (!eb || eb->key > ts->exp.key)
226 eb = &ts->exp;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100227
228 continue;
229 }
Emeric Brun3bd697e2010-01-04 15:23:48 +0100230
Willy Tarreauaea940e2010-06-06 11:56:36 +0200231 /* session expired, trash it */
Willy Tarreau86257dc2010-06-06 12:57:10 +0200232 ebmb_delete(&ts->key);
Emeric Brun85e77c72010-09-23 18:16:52 +0200233 eb32_delete(&ts->upd);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200234 __stksess_free(t, ts);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100235 batched++;
236 }
237
238 return batched;
239}
240
241/*
Emeric Brun819fc6f2017-06-13 19:37:32 +0200242 * Trash oldest <to_batch> sticky sessions from table <t>
243 * Returns number of trashed sticky sessions.
244 * This function locks the table
245 */
246int stktable_trash_oldest(struct stktable *t, int to_batch)
247{
248 int ret;
249
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100250 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200251 ret = __stktable_trash_oldest(t, to_batch);
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100252 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200253
254 return ret;
255}
256/*
Willy Tarreauaea940e2010-06-06 11:56:36 +0200257 * Allocate and initialise a new sticky session.
258 * The new sticky session is returned or NULL in case of lack of memory.
259 * Sticky sessions should only be allocated this way, and must be freed using
Willy Tarreaua7b46b52013-04-11 16:55:37 +0200260 * stksess_free(). Table <t>'s sticky session counter is increased. If <key>
261 * is not NULL, it is assigned to the new session.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100262 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200263struct stksess *__stksess_new(struct stktable *t, struct stktable_key *key)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100264{
265 struct stksess *ts;
266
267 if (unlikely(t->current == t->size)) {
268 if ( t->nopurge )
269 return NULL;
270
Emeric Brun819fc6f2017-06-13 19:37:32 +0200271 if (!__stktable_trash_oldest(t, (t->size >> 8) + 1))
Emeric Brun3bd697e2010-01-04 15:23:48 +0100272 return NULL;
273 }
274
Willy Tarreaubafbe012017-11-24 17:34:44 +0100275 ts = pool_alloc(t->pool);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100276 if (ts) {
277 t->current++;
Olivier Houchard52dabbc2018-11-14 17:54:36 +0100278 ts = (void *)ts + round_ptr_size(t->data_size);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200279 __stksess_init(t, ts);
Willy Tarreaua7b46b52013-04-11 16:55:37 +0200280 if (key)
281 stksess_setkey(t, ts, key);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100282 }
283
284 return ts;
285}
Emeric Brun819fc6f2017-06-13 19:37:32 +0200286/*
287 * Allocate and initialise a new sticky session.
288 * The new sticky session is returned or NULL in case of lack of memory.
289 * Sticky sessions should only be allocated this way, and must be freed using
290 * stksess_free(). Table <t>'s sticky session counter is increased. If <key>
291 * is not NULL, it is assigned to the new session.
292 * This function locks the table
293 */
294struct stksess *stksess_new(struct stktable *t, struct stktable_key *key)
295{
296 struct stksess *ts;
297
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100298 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200299 ts = __stksess_new(t, key);
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100300 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200301
302 return ts;
303}
Emeric Brun3bd697e2010-01-04 15:23:48 +0100304
305/*
Willy Tarreauf16d2b82010-06-06 15:38:59 +0200306 * Looks in table <t> for a sticky session matching key <key>.
Willy Tarreauaea940e2010-06-06 11:56:36 +0200307 * Returns pointer on requested sticky session or NULL if none was found.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100308 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200309struct stksess *__stktable_lookup_key(struct stktable *t, struct stktable_key *key)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100310{
311 struct ebmb_node *eb;
312
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200313 if (t->type == SMP_T_STR)
Emeric Brun485479d2010-09-23 18:02:19 +0200314 eb = ebst_lookup_len(&t->keys, key->key, key->key_len+1 < t->key_size ? key->key_len : t->key_size-1);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100315 else
316 eb = ebmb_lookup(&t->keys, key->key, t->key_size);
317
318 if (unlikely(!eb)) {
319 /* no session found */
320 return NULL;
321 }
322
Willy Tarreau86257dc2010-06-06 12:57:10 +0200323 return ebmb_entry(eb, struct stksess, key);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100324}
325
Emeric Brun819fc6f2017-06-13 19:37:32 +0200326/*
327 * Looks in table <t> for a sticky session matching key <key>.
328 * Returns pointer on requested sticky session or NULL if none was found.
329 * The refcount of the found entry is increased and this function
330 * is protected using the table lock
Willy Tarreau1f7e9252010-06-20 12:27:21 +0200331 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200332struct stksess *stktable_lookup_key(struct stktable *t, struct stktable_key *key)
Willy Tarreau1f7e9252010-06-20 12:27:21 +0200333{
334 struct stksess *ts;
335
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100336 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200337 ts = __stktable_lookup_key(t, key);
338 if (ts)
339 ts->ref_cnt++;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100340 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Willy Tarreau1f7e9252010-06-20 12:27:21 +0200341
Willy Tarreau1f7e9252010-06-20 12:27:21 +0200342 return ts;
343}
344
Willy Tarreauf16d2b82010-06-06 15:38:59 +0200345/*
346 * Looks in table <t> for a sticky session with same key as <ts>.
347 * Returns pointer on requested sticky session or NULL if none was found.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100348 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200349struct stksess *__stktable_lookup(struct stktable *t, struct stksess *ts)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100350{
Emeric Brun3bd697e2010-01-04 15:23:48 +0100351 struct ebmb_node *eb;
352
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200353 if (t->type == SMP_T_STR)
Willy Tarreau86257dc2010-06-06 12:57:10 +0200354 eb = ebst_lookup(&(t->keys), (char *)ts->key.key);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100355 else
Willy Tarreau86257dc2010-06-06 12:57:10 +0200356 eb = ebmb_lookup(&(t->keys), ts->key.key, t->key_size);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100357
Willy Tarreauf16d2b82010-06-06 15:38:59 +0200358 if (unlikely(!eb))
359 return NULL;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100360
Willy Tarreauf16d2b82010-06-06 15:38:59 +0200361 return ebmb_entry(eb, struct stksess, key);
362}
Emeric Brun3bd697e2010-01-04 15:23:48 +0100363
Emeric Brun819fc6f2017-06-13 19:37:32 +0200364/*
365 * Looks in table <t> for a sticky session with same key as <ts>.
366 * Returns pointer on requested sticky session or NULL if none was found.
367 * The refcount of the found entry is increased and this function
368 * is protected using the table lock
369 */
370struct stksess *stktable_lookup(struct stktable *t, struct stksess *ts)
371{
372 struct stksess *lts;
373
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100374 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200375 lts = __stktable_lookup(t, ts);
376 if (lts)
377 lts->ref_cnt++;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100378 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200379
380 return lts;
381}
382
Willy Tarreaucb183642010-06-06 17:58:34 +0200383/* Update the expiration timer for <ts> but do not touch its expiration node.
384 * The table's expiration timer is updated if set.
Emeric Brun819fc6f2017-06-13 19:37:32 +0200385 * The node will be also inserted into the update tree if needed, at a position
386 * depending if the update is a local or coming from a remote node
Willy Tarreaucb183642010-06-06 17:58:34 +0200387 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200388void __stktable_touch_with_exp(struct stktable *t, struct stksess *ts, int local, int expire)
Willy Tarreaucb183642010-06-06 17:58:34 +0200389{
Emeric Brun85e77c72010-09-23 18:16:52 +0200390 struct eb32_node * eb;
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200391 ts->expire = expire;
Willy Tarreaucb183642010-06-06 17:58:34 +0200392 if (t->expire) {
393 t->exp_task->expire = t->exp_next = tick_first(ts->expire, t->exp_next);
394 task_queue(t->exp_task);
395 }
Emeric Brun85e77c72010-09-23 18:16:52 +0200396
Emeric Brun819fc6f2017-06-13 19:37:32 +0200397 /* If sync is enabled */
398 if (t->sync_task) {
399 if (local) {
400 /* If this entry is not in the tree
401 or not scheduled for at least one peer */
402 if (!ts->upd.node.leaf_p
403 || (int)(t->commitupdate - ts->upd.key) >= 0
404 || (int)(ts->upd.key - t->localupdate) >= 0) {
405 ts->upd.key = ++t->update;
406 t->localupdate = t->update;
407 eb32_delete(&ts->upd);
408 eb = eb32_insert(&t->updates, &ts->upd);
409 if (eb != &ts->upd) {
410 eb32_delete(eb);
411 eb32_insert(&t->updates, &ts->upd);
412 }
Emeric Brunaaf58602015-06-15 17:23:30 +0200413 }
Emeric Brun819fc6f2017-06-13 19:37:32 +0200414 task_wakeup(t->sync_task, TASK_WOKEN_MSG);
Emeric Brun85e77c72010-09-23 18:16:52 +0200415 }
Emeric Brun819fc6f2017-06-13 19:37:32 +0200416 else {
417 /* If this entry is not in the tree */
418 if (!ts->upd.node.leaf_p) {
419 ts->upd.key= (++t->update)+(2147483648U);
420 eb = eb32_insert(&t->updates, &ts->upd);
421 if (eb != &ts->upd) {
422 eb32_delete(eb);
423 eb32_insert(&t->updates, &ts->upd);
424 }
425 }
426 }
Emeric Brun85e77c72010-09-23 18:16:52 +0200427 }
Willy Tarreaucb183642010-06-06 17:58:34 +0200428}
429
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200430/* Update the expiration timer for <ts> but do not touch its expiration node.
Emeric Brun819fc6f2017-06-13 19:37:32 +0200431 * The table's expiration timer is updated using the date of expiration coming from
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200432 * <t> stick-table configuration.
Emeric Brun819fc6f2017-06-13 19:37:32 +0200433 * The node will be also inserted into the update tree if needed, at a position
434 * considering the update is coming from a remote node
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200435 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200436void stktable_touch_remote(struct stktable *t, struct stksess *ts, int decrefcnt)
437{
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100438 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200439 __stktable_touch_with_exp(t, ts, 0, ts->expire);
440 if (decrefcnt)
441 ts->ref_cnt--;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100442 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200443}
444
445/* Update the expiration timer for <ts> but do not touch its expiration node.
446 * The table's expiration timer is updated using the date of expiration coming from
447 * <t> stick-table configuration.
448 * The node will be also inserted into the update tree if needed, at a position
449 * considering the update was made locally
450 */
451void stktable_touch_local(struct stktable *t, struct stksess *ts, int decrefcnt)
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200452{
453 int expire = tick_add(now_ms, MS_TO_TICKS(t->expire));
454
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100455 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200456 __stktable_touch_with_exp(t, ts, 1, expire);
457 if (decrefcnt)
458 ts->ref_cnt--;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100459 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200460}
Willy Tarreau43e90352018-06-27 06:25:57 +0200461/* Just decrease the ref_cnt of the current session. Does nothing if <ts> is NULL */
462static void stktable_release(struct stktable *t, struct stksess *ts)
Emeric Brun819fc6f2017-06-13 19:37:32 +0200463{
Willy Tarreau43e90352018-06-27 06:25:57 +0200464 if (!ts)
465 return;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100466 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200467 ts->ref_cnt--;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100468 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200469}
470
Willy Tarreauf16d2b82010-06-06 15:38:59 +0200471/* Insert new sticky session <ts> in the table. It is assumed that it does not
472 * yet exist (the caller must check this). The table's timeout is updated if it
473 * is set. <ts> is returned.
474 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200475void __stktable_store(struct stktable *t, struct stksess *ts)
Willy Tarreauf16d2b82010-06-06 15:38:59 +0200476{
Emeric Brun3bd697e2010-01-04 15:23:48 +0100477
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200478 ebmb_insert(&t->keys, &ts->key, t->key_size);
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200479 ts->exp.key = ts->expire;
480 eb32_insert(&t->exps, &ts->exp);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200481 if (t->expire) {
482 t->exp_task->expire = t->exp_next = tick_first(ts->expire, t->exp_next);
483 task_queue(t->exp_task);
484 }
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200485}
486
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200487/* Returns a valid or initialized stksess for the specified stktable_key in the
488 * specified table, or NULL if the key was NULL, or if no entry was found nor
489 * could be created. The entry's expiration is updated.
490 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200491struct stksess *__stktable_get_entry(struct stktable *table, struct stktable_key *key)
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200492{
493 struct stksess *ts;
494
495 if (!key)
496 return NULL;
497
Emeric Brun819fc6f2017-06-13 19:37:32 +0200498 ts = __stktable_lookup_key(table, key);
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200499 if (ts == NULL) {
500 /* entry does not exist, initialize a new one */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200501 ts = __stksess_new(table, key);
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200502 if (!ts)
503 return NULL;
Emeric Brun819fc6f2017-06-13 19:37:32 +0200504 __stktable_store(table, ts);
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200505 }
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200506 return ts;
507}
Emeric Brun819fc6f2017-06-13 19:37:32 +0200508/* Returns a valid or initialized stksess for the specified stktable_key in the
509 * specified table, or NULL if the key was NULL, or if no entry was found nor
510 * could be created. The entry's expiration is updated.
511 * This function locks the table, and the refcount of the entry is increased.
512 */
513struct stksess *stktable_get_entry(struct stktable *table, struct stktable_key *key)
514{
515 struct stksess *ts;
516
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100517 HA_SPIN_LOCK(STK_TABLE_LOCK, &table->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200518 ts = __stktable_get_entry(table, key);
519 if (ts)
520 ts->ref_cnt++;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100521 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &table->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200522
523 return ts;
524}
525
526/* Lookup for an entry with the same key and store the submitted
527 * stksess if not found.
528 */
529struct stksess *__stktable_set_entry(struct stktable *table, struct stksess *nts)
530{
531 struct stksess *ts;
532
533 ts = __stktable_lookup(table, nts);
534 if (ts == NULL) {
535 ts = nts;
536 __stktable_store(table, ts);
537 }
538 return ts;
539}
540
541/* Lookup for an entry with the same key and store the submitted
542 * stksess if not found.
543 * This function locks the table, and the refcount of the entry is increased.
544 */
545struct stksess *stktable_set_entry(struct stktable *table, struct stksess *nts)
546{
547 struct stksess *ts;
548
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100549 HA_SPIN_LOCK(STK_TABLE_LOCK, &table->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200550 ts = __stktable_set_entry(table, nts);
551 ts->ref_cnt++;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100552 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &table->lock);
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200553
Emeric Brun819fc6f2017-06-13 19:37:32 +0200554 return ts;
555}
Emeric Brun3bd697e2010-01-04 15:23:48 +0100556/*
Willy Tarreauaea940e2010-06-06 11:56:36 +0200557 * Trash expired sticky sessions from table <t>. The next expiration date is
558 * returned.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100559 */
560static int stktable_trash_expired(struct stktable *t)
561{
562 struct stksess *ts;
563 struct eb32_node *eb;
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200564 int looped = 0;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100565
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100566 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100567 eb = eb32_lookup_ge(&t->exps, now_ms - TIMER_LOOK_BACK);
568
569 while (1) {
570 if (unlikely(!eb)) {
571 /* we might have reached the end of the tree, typically because
572 * <now_ms> is in the first half and we're first scanning the last
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200573 * half. Let's loop back to the beginning of the tree now if we
574 * have not yet visited it.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100575 */
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200576 if (looped)
577 break;
578 looped = 1;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100579 eb = eb32_first(&t->exps);
580 if (likely(!eb))
581 break;
582 }
583
584 if (likely(tick_is_lt(now_ms, eb->key))) {
585 /* timer not expired yet, revisit it later */
586 t->exp_next = eb->key;
Willy Tarreau4d5f13c2017-11-05 11:04:47 +0100587 goto out_unlock;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100588 }
589
590 /* timer looks expired, detach it from the queue */
Willy Tarreau86257dc2010-06-06 12:57:10 +0200591 ts = eb32_entry(eb, struct stksess, exp);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100592 eb = eb32_next(eb);
593
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200594 /* don't delete an entry which is currently referenced */
595 if (ts->ref_cnt)
596 continue;
597
Willy Tarreau86257dc2010-06-06 12:57:10 +0200598 eb32_delete(&ts->exp);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100599
600 if (!tick_is_expired(ts->expire, now_ms)) {
601 if (!tick_isset(ts->expire))
602 continue;
603
Willy Tarreau86257dc2010-06-06 12:57:10 +0200604 ts->exp.key = ts->expire;
605 eb32_insert(&t->exps, &ts->exp);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100606
Willy Tarreau86257dc2010-06-06 12:57:10 +0200607 if (!eb || eb->key > ts->exp.key)
608 eb = &ts->exp;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100609 continue;
610 }
611
612 /* session expired, trash it */
Willy Tarreau86257dc2010-06-06 12:57:10 +0200613 ebmb_delete(&ts->key);
Emeric Brun85e77c72010-09-23 18:16:52 +0200614 eb32_delete(&ts->upd);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200615 __stksess_free(t, ts);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100616 }
617
618 /* We have found no task to expire in any tree */
619 t->exp_next = TICK_ETERNITY;
Willy Tarreau4d5f13c2017-11-05 11:04:47 +0100620out_unlock:
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100621 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100622 return t->exp_next;
623}
624
625/*
Willy Tarreauaea940e2010-06-06 11:56:36 +0200626 * Task processing function to trash expired sticky sessions. A pointer to the
627 * task itself is returned since it never dies.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100628 */
Willy Tarreau144f84a2021-03-02 16:09:26 +0100629struct task *process_table_expire(struct task *task, void *context, unsigned int state)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100630{
Olivier Houchard9f6af332018-05-25 14:04:04 +0200631 struct stktable *t = context;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100632
633 task->expire = stktable_trash_expired(t);
634 return task;
635}
636
Willy Tarreauaea940e2010-06-06 11:56:36 +0200637/* Perform minimal stick table intializations, report 0 in case of error, 1 if OK. */
Emeric Brun3bd697e2010-01-04 15:23:48 +0100638int stktable_init(struct stktable *t)
639{
Remi Tricot-Le Breton208ff012021-05-12 17:39:04 +0200640 int peers_retval = 0;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100641 if (t->size) {
Emeric Brun819fc6f2017-06-13 19:37:32 +0200642 t->keys = EB_ROOT_UNIQUE;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100643 memset(&t->exps, 0, sizeof(t->exps));
Emeric Brun1c6235d2015-12-16 15:28:12 +0100644 t->updates = EB_ROOT_UNIQUE;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100645 HA_SPIN_INIT(&t->lock);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100646
Olivier Houchard52dabbc2018-11-14 17:54:36 +0100647 t->pool = create_pool("sticktables", sizeof(struct stksess) + round_ptr_size(t->data_size) + t->key_size, MEM_F_SHARED);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100648
649 t->exp_next = TICK_ETERNITY;
650 if ( t->expire ) {
Emeric Brunc60def82017-09-27 14:59:38 +0200651 t->exp_task = task_new(MAX_THREADS_MASK);
Willy Tarreau848522f2018-10-15 11:12:15 +0200652 if (!t->exp_task)
653 return 0;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100654 t->exp_task->process = process_table_expire;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100655 t->exp_task->context = (void *)t;
656 }
Willy Tarreauc3914d42020-09-24 08:39:22 +0200657 if (t->peers.p && t->peers.p->peers_fe && !t->peers.p->peers_fe->disabled) {
Remi Tricot-Le Breton208ff012021-05-12 17:39:04 +0200658 peers_retval = peers_register_table(t->peers.p, t);
Emeric Brun32da3c42010-09-23 18:39:19 +0200659 }
660
Remi Tricot-Le Breton208ff012021-05-12 17:39:04 +0200661 return (t->pool != NULL) && !peers_retval;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100662 }
663 return 1;
664}
665
666/*
667 * Configuration keywords of known table types
668 */
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200669struct stktable_type stktable_types[SMP_TYPES] = {
670 [SMP_T_SINT] = { "integer", 0, 4 },
671 [SMP_T_IPV4] = { "ip", 0, 4 },
672 [SMP_T_IPV6] = { "ipv6", 0, 16 },
673 [SMP_T_STR] = { "string", STK_F_CUSTOM_KEYSIZE, 32 },
674 [SMP_T_BIN] = { "binary", STK_F_CUSTOM_KEYSIZE, 32 }
675};
Emeric Brun3bd697e2010-01-04 15:23:48 +0100676
677/*
678 * Parse table type configuration.
679 * Returns 0 on successful parsing, else 1.
680 * <myidx> is set at next configuration <args> index.
681 */
682int stktable_parse_type(char **args, int *myidx, unsigned long *type, size_t *key_size)
683{
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200684 for (*type = 0; *type < SMP_TYPES; (*type)++) {
685 if (!stktable_types[*type].kw)
686 continue;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100687 if (strcmp(args[*myidx], stktable_types[*type].kw) != 0)
688 continue;
689
690 *key_size = stktable_types[*type].default_size;
691 (*myidx)++;
692
Willy Tarreauaea940e2010-06-06 11:56:36 +0200693 if (stktable_types[*type].flags & STK_F_CUSTOM_KEYSIZE) {
Emeric Brun3bd697e2010-01-04 15:23:48 +0100694 if (strcmp("len", args[*myidx]) == 0) {
695 (*myidx)++;
696 *key_size = atol(args[*myidx]);
Emeric Brun485479d2010-09-23 18:02:19 +0200697 if (!*key_size)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100698 break;
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200699 if (*type == SMP_T_STR) {
Emeric Brun485479d2010-09-23 18:02:19 +0200700 /* null terminated string needs +1 for '\0'. */
701 (*key_size)++;
702 }
Emeric Brun3bd697e2010-01-04 15:23:48 +0100703 (*myidx)++;
704 }
705 }
706 return 0;
707 }
708 return 1;
709}
710
Emeric Brunc64a2a32021-06-30 18:01:02 +0200711/* reserve some space for data type <type>, there is 2 optionnals
712 * argument at <sa> and <sa2> to configure this data type and
713 * they can be NULL if unused for a given type.
714 * Returns PE_NONE (0) if OK or an error code among :
Willy Tarreau3b63ca22021-05-08 14:10:42 +0200715 * - PE_ENUM_OOR if <type> does not exist
716 * - PE_EXIST if <type> is already registered
Emeric Brunc64a2a32021-06-30 18:01:02 +0200717 * - PE_ARG_NOT_USE if <sa>/<sa2> was provided but not expected
718 * - PE_ARG_MISSING if <sa>/<sa2> was expected but not provided
719 * - PE_ARG_VALUE_OOR if type is an array and <sa> it out of array size range.
Willy Tarreau3b63ca22021-05-08 14:10:42 +0200720 */
Emeric Brunc64a2a32021-06-30 18:01:02 +0200721int stktable_alloc_data_type(struct stktable *t, int type, const char *sa, const char *sa2)
722
Willy Tarreau3b63ca22021-05-08 14:10:42 +0200723{
724 if (type >= STKTABLE_DATA_TYPES)
725 return PE_ENUM_OOR;
726
727 if (t->data_ofs[type])
728 /* already allocated */
729 return PE_EXIST;
730
Emeric Brunc64a2a32021-06-30 18:01:02 +0200731 t->data_nbelem[type] = 1;
732 if (stktable_data_types[type].is_array) {
733 /* arrays take their element count on first argument */
734 if (!sa)
735 return PE_ARG_MISSING;
736 t->data_nbelem[type] = atoi(sa);
737 if (!t->data_nbelem[type] || (t->data_nbelem[type] > STKTABLE_MAX_DT_ARRAY_SIZE))
738 return PE_ARG_VALUE_OOR;
739 sa = sa2;
740 }
741
Willy Tarreau3b63ca22021-05-08 14:10:42 +0200742 switch (stktable_data_types[type].arg_type) {
743 case ARG_T_NONE:
744 if (sa)
745 return PE_ARG_NOT_USED;
746 break;
747 case ARG_T_INT:
748 if (!sa)
749 return PE_ARG_MISSING;
750 t->data_arg[type].i = atoi(sa);
751 break;
752 case ARG_T_DELAY:
753 if (!sa)
754 return PE_ARG_MISSING;
755 sa = parse_time_err(sa, &t->data_arg[type].u, TIME_UNIT_MS);
756 if (sa)
757 return PE_ARG_INVC; /* invalid char */
758 break;
759 }
760
Emeric Brunc64a2a32021-06-30 18:01:02 +0200761 t->data_size += t->data_nbelem[type] * stktable_type_size(stktable_data_types[type].std_type);
Willy Tarreau3b63ca22021-05-08 14:10:42 +0200762 t->data_ofs[type] = -t->data_size;
763 return PE_NONE;
764}
765
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100766/*
Frédéric Lécaillec02766a2019-03-20 15:06:55 +0100767 * Parse a line with <linenum> as number in <file> configuration file to configure
768 * the stick-table with <t> as address and <id> as ID.
769 * <peers> provides the "peers" section pointer only if this function is called
770 * from a "peers" section.
771 * <nid> is the stick-table name which is sent over the network. It must be equal
772 * to <id> if this stick-table is parsed from a proxy section, and prefixed by <peers>
773 * "peers" section name followed by a '/' character if parsed from a "peers" section.
Ilya Shipitsind4259502020-04-08 01:07:56 +0500774 * This is the responsibility of the caller to check this.
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100775 * Return an error status with ERR_* flags set if required, 0 if no error was encountered.
776 */
777int parse_stick_table(const char *file, int linenum, char **args,
Frédéric Lécaillec02766a2019-03-20 15:06:55 +0100778 struct stktable *t, char *id, char *nid, struct peers *peers)
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100779{
780 int err_code = 0;
781 int idx = 1;
782 unsigned int val;
783
784 if (!id || !*id) {
785 ha_alert("parsing [%s:%d] : %s: ID not provided.\n", file, linenum, args[0]);
786 err_code |= ERR_ALERT | ERR_ABORT;
787 goto out;
788 }
789
790 /* Store the "peers" section if this function is called from a "peers" section. */
791 if (peers) {
792 t->peers.p = peers;
793 idx++;
794 }
795
796 t->id = id;
Frédéric Lécaillec02766a2019-03-20 15:06:55 +0100797 t->nid = nid;
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100798 t->type = (unsigned int)-1;
799 t->conf.file = file;
800 t->conf.line = linenum;
801
802 while (*args[idx]) {
803 const char *err;
804
805 if (strcmp(args[idx], "size") == 0) {
806 idx++;
807 if (!*(args[idx])) {
808 ha_alert("parsing [%s:%d] : %s: missing argument after '%s'.\n",
809 file, linenum, args[0], args[idx-1]);
810 err_code |= ERR_ALERT | ERR_FATAL;
811 goto out;
812 }
813 if ((err = parse_size_err(args[idx], &t->size))) {
814 ha_alert("parsing [%s:%d] : %s: unexpected character '%c' in argument of '%s'.\n",
815 file, linenum, args[0], *err, args[idx-1]);
816 err_code |= ERR_ALERT | ERR_FATAL;
817 goto out;
818 }
819 idx++;
820 }
821 /* This argument does not exit in "peers" section. */
822 else if (!peers && strcmp(args[idx], "peers") == 0) {
823 idx++;
824 if (!*(args[idx])) {
825 ha_alert("parsing [%s:%d] : %s: missing argument after '%s'.\n",
826 file, linenum, args[0], args[idx-1]);
827 err_code |= ERR_ALERT | ERR_FATAL;
828 goto out;
829 }
830 t->peers.name = strdup(args[idx++]);
831 }
832 else if (strcmp(args[idx], "expire") == 0) {
833 idx++;
834 if (!*(args[idx])) {
835 ha_alert("parsing [%s:%d] : %s: missing argument after '%s'.\n",
836 file, linenum, args[0], args[idx-1]);
837 err_code |= ERR_ALERT | ERR_FATAL;
838 goto out;
839 }
840 err = parse_time_err(args[idx], &val, TIME_UNIT_MS);
Willy Tarreau9faebe32019-06-07 19:00:37 +0200841 if (err == PARSE_TIME_OVER) {
842 ha_alert("parsing [%s:%d]: %s: timer overflow in argument <%s> to <%s>, maximum value is 2147483647 ms (~24.8 days).\n",
843 file, linenum, args[0], args[idx], args[idx-1]);
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100844 err_code |= ERR_ALERT | ERR_FATAL;
845 goto out;
846 }
Willy Tarreau9faebe32019-06-07 19:00:37 +0200847 else if (err == PARSE_TIME_UNDER) {
848 ha_alert("parsing [%s:%d]: %s: timer underflow in argument <%s> to <%s>, minimum non-null value is 1 ms.\n",
849 file, linenum, args[0], args[idx], args[idx-1]);
850 err_code |= ERR_ALERT | ERR_FATAL;
851 goto out;
852 }
853 else if (err) {
854 ha_alert("parsing [%s:%d] : %s: unexpected character '%c' in argument of '%s'.\n",
855 file, linenum, args[0], *err, args[idx-1]);
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100856 err_code |= ERR_ALERT | ERR_FATAL;
857 goto out;
858 }
859 t->expire = val;
860 idx++;
861 }
862 else if (strcmp(args[idx], "nopurge") == 0) {
863 t->nopurge = 1;
864 idx++;
865 }
866 else if (strcmp(args[idx], "type") == 0) {
867 idx++;
868 if (stktable_parse_type(args, &idx, &t->type, &t->key_size) != 0) {
869 ha_alert("parsing [%s:%d] : %s: unknown type '%s'.\n",
870 file, linenum, args[0], args[idx]);
871 err_code |= ERR_ALERT | ERR_FATAL;
872 goto out;
873 }
874 /* idx already points to next arg */
875 }
876 else if (strcmp(args[idx], "store") == 0) {
877 int type, err;
Emeric Brunc64a2a32021-06-30 18:01:02 +0200878 char *cw, *nw, *sa, *sa2;
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100879
880 idx++;
881 nw = args[idx];
882 while (*nw) {
883 /* the "store" keyword supports a comma-separated list */
884 cw = nw;
885 sa = NULL; /* store arg */
Emeric Brunc64a2a32021-06-30 18:01:02 +0200886 sa2 = NULL;
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100887 while (*nw && *nw != ',') {
888 if (*nw == '(') {
889 *nw = 0;
890 sa = ++nw;
891 while (*nw != ')') {
892 if (!*nw) {
893 ha_alert("parsing [%s:%d] : %s: missing closing parenthesis after store option '%s'.\n",
894 file, linenum, args[0], cw);
895 err_code |= ERR_ALERT | ERR_FATAL;
896 goto out;
897 }
Emeric Brunc64a2a32021-06-30 18:01:02 +0200898 if (*nw == ',') {
899 *nw = '\0';
900 sa2 = nw + 1;
901 }
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100902 nw++;
903 }
904 *nw = '\0';
905 }
906 nw++;
907 }
908 if (*nw)
909 *nw++ = '\0';
910 type = stktable_get_data_type(cw);
911 if (type < 0) {
912 ha_alert("parsing [%s:%d] : %s: unknown store option '%s'.\n",
913 file, linenum, args[0], cw);
914 err_code |= ERR_ALERT | ERR_FATAL;
915 goto out;
916 }
917
Emeric Brunc64a2a32021-06-30 18:01:02 +0200918 err = stktable_alloc_data_type(t, type, sa, sa2);
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100919 switch (err) {
920 case PE_NONE: break;
921 case PE_EXIST:
922 ha_warning("parsing [%s:%d]: %s: store option '%s' already enabled, ignored.\n",
923 file, linenum, args[0], cw);
924 err_code |= ERR_WARN;
925 break;
926
927 case PE_ARG_MISSING:
928 ha_alert("parsing [%s:%d] : %s: missing argument to store option '%s'.\n",
929 file, linenum, args[0], cw);
930 err_code |= ERR_ALERT | ERR_FATAL;
931 goto out;
932
933 case PE_ARG_NOT_USED:
934 ha_alert("parsing [%s:%d] : %s: unexpected argument to store option '%s'.\n",
935 file, linenum, args[0], cw);
936 err_code |= ERR_ALERT | ERR_FATAL;
937 goto out;
Emeric Brunc64a2a32021-06-30 18:01:02 +0200938 case PE_ARG_VALUE_OOR:
939 ha_alert("parsing [%s:%d] : %s: array size is out of allowed range (1-%d) for store option '%s'.\n",
940 file, linenum, args[0], STKTABLE_MAX_DT_ARRAY_SIZE, cw);
941 err_code |= ERR_ALERT | ERR_FATAL;
942 goto out;
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100943
944 default:
945 ha_alert("parsing [%s:%d] : %s: error when processing store option '%s'.\n",
946 file, linenum, args[0], cw);
947 err_code |= ERR_ALERT | ERR_FATAL;
948 goto out;
949 }
950 }
951 idx++;
Emeric Brunf7ab0bf2021-06-30 18:58:22 +0200952 if (t->data_ofs[STKTABLE_DT_GPT] && t->data_ofs[STKTABLE_DT_GPT0]) {
953 ha_alert("parsing [%s:%d] : %s: simultaneous usage of 'gpt' and 'gpt0' in a same table is not permitted as 'gpt' overrides 'gpt0'.\n",
954 file, linenum, args[0]);
955 err_code |= ERR_ALERT | ERR_FATAL;
956 goto out;
957 }
Emeric Brun726783d2021-06-30 19:06:43 +0200958 else if (t->data_ofs[STKTABLE_DT_GPC] && (t->data_ofs[STKTABLE_DT_GPC0] || t->data_ofs[STKTABLE_DT_GPC1])) {
959 ha_alert("parsing [%s:%d] : %s: simultaneous usage of 'gpc' and 'gpc[0/1]' in a same table is not permitted as 'gpc' overrides 'gpc[0/1]'.\n",
960 file, linenum, args[0]);
961 err_code |= ERR_ALERT | ERR_FATAL;
962 goto out;
963 }
964 else if (t->data_ofs[STKTABLE_DT_GPC_RATE] && (t->data_ofs[STKTABLE_DT_GPC0_RATE] || t->data_ofs[STKTABLE_DT_GPC1_RATE])) {
965 ha_alert("parsing [%s:%d] : %s: simultaneous usage of 'gpc_rate' and 'gpc[0/1]_rate' in a same table is not permitted as 'gpc_rate' overrides 'gpc[0/1]_rate'.\n",
966 file, linenum, args[0]);
967 err_code |= ERR_ALERT | ERR_FATAL;
968 goto out;
969 }
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100970 }
Thayne McCombs92149f92020-11-20 01:28:26 -0700971 else if (strcmp(args[idx], "srvkey") == 0) {
972 char *keytype;
973 idx++;
974 keytype = args[idx];
975 if (strcmp(keytype, "name") == 0) {
976 t->server_key_type = STKTABLE_SRV_NAME;
977 }
978 else if (strcmp(keytype, "addr") == 0) {
979 t->server_key_type = STKTABLE_SRV_ADDR;
980 }
981 else {
982 ha_alert("parsing [%s:%d] : %s : unknown server key type '%s'.\n",
983 file, linenum, args[0], keytype);
984 err_code |= ERR_ALERT | ERR_FATAL;
985 goto out;
986
987 }
988 idx++;
989 }
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100990 else {
991 ha_alert("parsing [%s:%d] : %s: unknown argument '%s'.\n",
992 file, linenum, args[0], args[idx]);
993 err_code |= ERR_ALERT | ERR_FATAL;
994 goto out;
995 }
996 }
997
998 if (!t->size) {
999 ha_alert("parsing [%s:%d] : %s: missing size.\n",
1000 file, linenum, args[0]);
1001 err_code |= ERR_ALERT | ERR_FATAL;
1002 goto out;
1003 }
1004
1005 if (t->type == (unsigned int)-1) {
1006 ha_alert("parsing [%s:%d] : %s: missing type.\n",
1007 file, linenum, args[0]);
1008 err_code |= ERR_ALERT | ERR_FATAL;
1009 goto out;
1010 }
1011
1012 out:
1013 return err_code;
1014}
1015
Willy Tarreau8fed9032014-07-03 17:02:46 +02001016/* Prepares a stktable_key from a sample <smp> to search into table <t>.
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001017 * Note that the sample *is* modified and that the returned key may point
1018 * to it, so the sample must not be modified afterwards before the lookup.
Willy Tarreau8fed9032014-07-03 17:02:46 +02001019 * Returns NULL if the sample could not be converted (eg: no matching type),
1020 * otherwise a pointer to the static stktable_key filled with what is needed
1021 * for the lookup.
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001022 */
Willy Tarreau8fed9032014-07-03 17:02:46 +02001023struct stktable_key *smp_to_stkey(struct sample *smp, struct stktable *t)
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001024{
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001025 /* Convert sample. */
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +02001026 if (!sample_convert(smp, t->type))
Willy Tarreau7fc1c6e2012-04-26 11:03:17 +02001027 return NULL;
1028
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001029 /* Fill static_table_key. */
1030 switch (t->type) {
Emeric Brun485479d2010-09-23 18:02:19 +02001031
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +02001032 case SMP_T_IPV4:
Christopher Fauletca20d022017-08-29 15:30:31 +02001033 static_table_key.key = &smp->data.u.ipv4;
1034 static_table_key.key_len = 4;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001035 break;
Emeric Brun485479d2010-09-23 18:02:19 +02001036
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +02001037 case SMP_T_IPV6:
Christopher Fauletca20d022017-08-29 15:30:31 +02001038 static_table_key.key = &smp->data.u.ipv6;
1039 static_table_key.key_len = 16;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001040 break;
Emeric Brun485479d2010-09-23 18:02:19 +02001041
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +02001042 case SMP_T_SINT:
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001043 /* The stick table require a 32bit unsigned int, "sint" is a
1044 * signed 64 it, so we can convert it inplace.
1045 */
Willy Tarreau28c63c12019-10-23 06:21:05 +02001046 smp->data.u.sint = (unsigned int)smp->data.u.sint;
Christopher Fauletca20d022017-08-29 15:30:31 +02001047 static_table_key.key = &smp->data.u.sint;
1048 static_table_key.key_len = 4;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001049 break;
1050
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +02001051 case SMP_T_STR:
Willy Tarreauce6955e2016-08-09 11:59:12 +02001052 if (!smp_make_safe(smp))
1053 return NULL;
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001054 static_table_key.key = smp->data.u.str.area;
1055 static_table_key.key_len = smp->data.u.str.data;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001056 break;
Emeric Brun485479d2010-09-23 18:02:19 +02001057
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +02001058 case SMP_T_BIN:
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001059 if (smp->data.u.str.data < t->key_size) {
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001060 /* This type needs padding with 0. */
Willy Tarreauf65c6c02016-08-09 12:08:41 +02001061 if (!smp_make_rw(smp))
1062 return NULL;
1063
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001064 if (smp->data.u.str.size < t->key_size)
1065 if (!smp_dup(smp))
1066 return NULL;
1067 if (smp->data.u.str.size < t->key_size)
1068 return NULL;
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001069 memset(smp->data.u.str.area + smp->data.u.str.data, 0,
1070 t->key_size - smp->data.u.str.data);
1071 smp->data.u.str.data = t->key_size;
Emeric Brun485479d2010-09-23 18:02:19 +02001072 }
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001073 static_table_key.key = smp->data.u.str.area;
1074 static_table_key.key_len = smp->data.u.str.data;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001075 break;
Emeric Brun485479d2010-09-23 18:02:19 +02001076
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001077 default: /* impossible case. */
1078 return NULL;
Emeric Brun485479d2010-09-23 18:02:19 +02001079 }
1080
Christopher Fauletca20d022017-08-29 15:30:31 +02001081 return &static_table_key;
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001082}
1083
1084/*
Willy Tarreau8fed9032014-07-03 17:02:46 +02001085 * Process a fetch + format conversion as defined by the sample expression <expr>
1086 * on request or response considering the <opt> parameter. Returns either NULL if
1087 * no key could be extracted, or a pointer to the converted result stored in
1088 * static_table_key in format <table_type>. If <smp> is not NULL, it will be reset
1089 * and its flags will be initialized so that the caller gets a copy of the input
Willy Tarreau6bcb0a82014-07-30 08:56:35 +02001090 * sample, and knows why it was not accepted (eg: SMP_F_MAY_CHANGE is present
1091 * without SMP_OPT_FINAL). The output will be usable like this :
1092 *
1093 * return MAY_CHANGE FINAL Meaning for the sample
1094 * NULL 0 * Not present and will never be (eg: header)
1095 * NULL 1 0 Not present or unstable, could change (eg: req_len)
1096 * NULL 1 1 Not present, will not change anymore
1097 * smp 0 * Present and will not change (eg: header)
1098 * smp 1 0 not possible
1099 * smp 1 1 Present, last known value (eg: request length)
Willy Tarreau8fed9032014-07-03 17:02:46 +02001100 */
Willy Tarreau192252e2015-04-04 01:47:55 +02001101struct stktable_key *stktable_fetch_key(struct stktable *t, struct proxy *px, struct session *sess, struct stream *strm,
Willy Tarreau8fed9032014-07-03 17:02:46 +02001102 unsigned int opt, struct sample_expr *expr, struct sample *smp)
1103{
1104 if (smp)
1105 memset(smp, 0, sizeof(*smp));
1106
Willy Tarreau192252e2015-04-04 01:47:55 +02001107 smp = sample_process(px, sess, strm, opt, expr, smp);
Willy Tarreau8fed9032014-07-03 17:02:46 +02001108 if (!smp)
1109 return NULL;
1110
1111 if ((smp->flags & SMP_F_MAY_CHANGE) && !(opt & SMP_OPT_FINAL))
1112 return NULL; /* we can only use stable samples */
1113
1114 return smp_to_stkey(smp, t);
1115}
1116
1117/*
Willy Tarreau12785782012-04-27 21:37:17 +02001118 * Returns 1 if sample expression <expr> result can be converted to table key of
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001119 * type <table_type>, otherwise zero. Used in configuration check.
1120 */
Willy Tarreau12785782012-04-27 21:37:17 +02001121int stktable_compatible_sample(struct sample_expr *expr, unsigned long table_type)
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001122{
Thierry FOURNIERf73eb8f2013-11-27 15:30:55 +01001123 int out_type;
1124
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +02001125 if (table_type >= SMP_TYPES || !stktable_types[table_type].kw)
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001126 return 0;
1127
Thierry FOURNIERf73eb8f2013-11-27 15:30:55 +01001128 out_type = smp_expr_output_type(expr);
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001129
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001130 /* Convert sample. */
1131 if (!sample_casts[out_type][table_type])
Thierry FOURNIERf73eb8f2013-11-27 15:30:55 +01001132 return 0;
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001133
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001134 return 1;
1135}
Emeric Brun3bd697e2010-01-04 15:23:48 +01001136
Willy Tarreauedee1d62014-07-15 16:44:27 +02001137/* Extra data types processing : after the last one, some room may remain
1138 * before STKTABLE_DATA_TYPES that may be used to register extra data types
1139 * at run time.
1140 */
Willy Tarreau08d5f982010-06-06 13:34:54 +02001141struct stktable_data_type stktable_data_types[STKTABLE_DATA_TYPES] = {
Willy Tarreau3b9c6e02010-07-18 08:04:30 +02001142 [STKTABLE_DT_SERVER_ID] = { .name = "server_id", .std_type = STD_T_SINT },
Thierry FOURNIER3cf11112015-07-28 08:57:05 +02001143 [STKTABLE_DT_GPT0] = { .name = "gpt0", .std_type = STD_T_UINT },
Willy Tarreau3b9c6e02010-07-18 08:04:30 +02001144 [STKTABLE_DT_GPC0] = { .name = "gpc0", .std_type = STD_T_UINT },
Willy Tarreauba2ffd12013-05-29 15:54:14 +02001145 [STKTABLE_DT_GPC0_RATE] = { .name = "gpc0_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
Willy Tarreau3b9c6e02010-07-18 08:04:30 +02001146 [STKTABLE_DT_CONN_CNT] = { .name = "conn_cnt", .std_type = STD_T_UINT },
1147 [STKTABLE_DT_CONN_RATE] = { .name = "conn_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
1148 [STKTABLE_DT_CONN_CUR] = { .name = "conn_cur", .std_type = STD_T_UINT },
1149 [STKTABLE_DT_SESS_CNT] = { .name = "sess_cnt", .std_type = STD_T_UINT },
1150 [STKTABLE_DT_SESS_RATE] = { .name = "sess_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
1151 [STKTABLE_DT_HTTP_REQ_CNT] = { .name = "http_req_cnt", .std_type = STD_T_UINT },
1152 [STKTABLE_DT_HTTP_REQ_RATE] = { .name = "http_req_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
1153 [STKTABLE_DT_HTTP_ERR_CNT] = { .name = "http_err_cnt", .std_type = STD_T_UINT },
1154 [STKTABLE_DT_HTTP_ERR_RATE] = { .name = "http_err_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
1155 [STKTABLE_DT_BYTES_IN_CNT] = { .name = "bytes_in_cnt", .std_type = STD_T_ULL },
1156 [STKTABLE_DT_BYTES_IN_RATE] = { .name = "bytes_in_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
1157 [STKTABLE_DT_BYTES_OUT_CNT] = { .name = "bytes_out_cnt", .std_type = STD_T_ULL },
1158 [STKTABLE_DT_BYTES_OUT_RATE]= { .name = "bytes_out_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001159 [STKTABLE_DT_GPC1] = { .name = "gpc1", .std_type = STD_T_UINT },
1160 [STKTABLE_DT_GPC1_RATE] = { .name = "gpc1_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
Thayne McCombs92149f92020-11-20 01:28:26 -07001161 [STKTABLE_DT_SERVER_KEY] = { .name = "server_key", .std_type = STD_T_DICT },
Willy Tarreau826f3ab2021-02-10 12:07:15 +01001162 [STKTABLE_DT_HTTP_FAIL_CNT] = { .name = "http_fail_cnt", .std_type = STD_T_UINT },
1163 [STKTABLE_DT_HTTP_FAIL_RATE]= { .name = "http_fail_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
Emeric Brun877b0b52021-06-30 18:57:49 +02001164 [STKTABLE_DT_GPT] = { .name = "gpt", .std_type = STD_T_UINT, .is_array = 1 },
Emeric Brun4d7ada82021-06-30 19:04:16 +02001165 [STKTABLE_DT_GPC] = { .name = "gpc", .std_type = STD_T_UINT, .is_array = 1 },
1166 [STKTABLE_DT_GPC_RATE] = { .name = "gpc_rate", .std_type = STD_T_FRQP, .is_array = 1, .arg_type = ARG_T_DELAY },
Willy Tarreau08d5f982010-06-06 13:34:54 +02001167};
1168
Willy Tarreauedee1d62014-07-15 16:44:27 +02001169/* Registers stick-table extra data type with index <idx>, name <name>, type
1170 * <std_type> and arg type <arg_type>. If the index is negative, the next free
1171 * index is automatically allocated. The allocated index is returned, or -1 if
1172 * no free index was found or <name> was already registered. The <name> is used
1173 * directly as a pointer, so if it's not stable, the caller must allocate it.
1174 */
1175int stktable_register_data_store(int idx, const char *name, int std_type, int arg_type)
1176{
1177 if (idx < 0) {
1178 for (idx = 0; idx < STKTABLE_DATA_TYPES; idx++) {
1179 if (!stktable_data_types[idx].name)
1180 break;
1181
1182 if (strcmp(stktable_data_types[idx].name, name) == 0)
1183 return -1;
1184 }
1185 }
1186
1187 if (idx >= STKTABLE_DATA_TYPES)
1188 return -1;
1189
1190 if (stktable_data_types[idx].name != NULL)
1191 return -1;
1192
1193 stktable_data_types[idx].name = name;
1194 stktable_data_types[idx].std_type = std_type;
1195 stktable_data_types[idx].arg_type = arg_type;
1196 return idx;
1197}
1198
Willy Tarreau08d5f982010-06-06 13:34:54 +02001199/*
1200 * Returns the data type number for the stktable_data_type whose name is <name>,
1201 * or <0 if not found.
1202 */
1203int stktable_get_data_type(char *name)
1204{
1205 int type;
1206
1207 for (type = 0; type < STKTABLE_DATA_TYPES; type++) {
Willy Tarreauedee1d62014-07-15 16:44:27 +02001208 if (!stktable_data_types[type].name)
1209 continue;
Willy Tarreau08d5f982010-06-06 13:34:54 +02001210 if (strcmp(name, stktable_data_types[type].name) == 0)
1211 return type;
1212 }
Thayne McCombs92149f92020-11-20 01:28:26 -07001213 /* For backwards compatibility */
1214 if (strcmp(name, "server_name") == 0)
1215 return STKTABLE_DT_SERVER_KEY;
Willy Tarreau08d5f982010-06-06 13:34:54 +02001216 return -1;
1217}
1218
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001219/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1220 * it up into this table. Returns true if found, false otherwise. The input
1221 * type is STR so that input samples are converted to string (since all types
1222 * can be converted to strings), then the function casts the string again into
1223 * the table's type. This is a double conversion, but in the future we might
1224 * support automatic input types to perform the cast on the fly.
1225 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001226static int sample_conv_in_table(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001227{
1228 struct stktable *t;
1229 struct stktable_key *key;
1230 struct stksess *ts;
1231
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001232 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001233
1234 key = smp_to_stkey(smp, t);
1235 if (!key)
1236 return 0;
1237
1238 ts = stktable_lookup_key(t, key);
1239
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001240 smp->data.type = SMP_T_BOOL;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001241 smp->data.u.sint = !!ts;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001242 smp->flags = SMP_F_VOL_TEST;
Willy Tarreau43e90352018-06-27 06:25:57 +02001243 stktable_release(t, ts);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001244 return 1;
1245}
1246
1247/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1248 * it up into this table. Returns the data rate received from clients in bytes/s
1249 * if the key is present in the table, otherwise zero, so that comparisons can
1250 * be easily performed. If the inspected parameter is not stored in the table,
1251 * <not found> is returned.
1252 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001253static int sample_conv_table_bytes_in_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001254{
1255 struct stktable *t;
1256 struct stktable_key *key;
1257 struct stksess *ts;
1258 void *ptr;
1259
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001260 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001261
1262 key = smp_to_stkey(smp, t);
1263 if (!key)
1264 return 0;
1265
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001266 ts = stktable_lookup_key(t, key);
1267
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001268 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001269 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001270 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001271
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001272 if (!ts) /* key not present */
1273 return 1;
1274
1275 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_IN_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001276 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001277 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Daniel Corbett3e60b112018-05-27 09:47:12 -04001278 t->data_arg[STKTABLE_DT_BYTES_IN_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001279
Daniel Corbett3e60b112018-05-27 09:47:12 -04001280 stktable_release(t, ts);
1281 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001282}
1283
1284/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1285 * it up into this table. Returns the cumulated number of connections for the key
1286 * if the key is present in the table, otherwise zero, so that comparisons can
1287 * be easily performed. If the inspected parameter is not stored in the table,
1288 * <not found> is returned.
1289 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001290static int sample_conv_table_conn_cnt(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001291{
1292 struct stktable *t;
1293 struct stktable_key *key;
1294 struct stksess *ts;
1295 void *ptr;
1296
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001297 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001298
1299 key = smp_to_stkey(smp, t);
1300 if (!key)
1301 return 0;
1302
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001303 ts = stktable_lookup_key(t, key);
1304
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001305 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001306 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001307 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001308
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001309 if (!ts) /* key not present */
1310 return 1;
1311
1312 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_CONN_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001313 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001314 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001315
Daniel Corbett3e60b112018-05-27 09:47:12 -04001316 stktable_release(t, ts);
1317 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001318}
1319
1320/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1321 * it up into this table. Returns the number of concurrent connections for the
1322 * key if the key is present in the table, otherwise zero, so that comparisons
1323 * can be easily performed. If the inspected parameter is not stored in the
1324 * table, <not found> is returned.
1325 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001326static int sample_conv_table_conn_cur(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001327{
1328 struct stktable *t;
1329 struct stktable_key *key;
1330 struct stksess *ts;
1331 void *ptr;
1332
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001333 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001334
1335 key = smp_to_stkey(smp, t);
1336 if (!key)
1337 return 0;
1338
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001339 ts = stktable_lookup_key(t, key);
1340
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001341 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001342 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001343 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001344
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001345 if (!ts) /* key not present */
1346 return 1;
1347
1348 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_CONN_CUR);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001349 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001350 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001351
Daniel Corbett3e60b112018-05-27 09:47:12 -04001352 stktable_release(t, ts);
1353 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001354}
1355
1356/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1357 * it up into this table. Returns the rate of incoming connections from the key
1358 * if the key is present in the table, otherwise zero, so that comparisons can
1359 * be easily performed. If the inspected parameter is not stored in the table,
1360 * <not found> is returned.
1361 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001362static int sample_conv_table_conn_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001363{
1364 struct stktable *t;
1365 struct stktable_key *key;
1366 struct stksess *ts;
1367 void *ptr;
1368
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001369 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001370
1371 key = smp_to_stkey(smp, t);
1372 if (!key)
1373 return 0;
1374
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001375 ts = stktable_lookup_key(t, key);
1376
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001377 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001378 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001379 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001380
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001381 if (!ts) /* key not present */
1382 return 1;
1383
1384 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_CONN_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001385 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001386 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Daniel Corbett3e60b112018-05-27 09:47:12 -04001387 t->data_arg[STKTABLE_DT_CONN_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001388
Daniel Corbett3e60b112018-05-27 09:47:12 -04001389 stktable_release(t, ts);
1390 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001391}
1392
1393/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1394 * it up into this table. Returns the data rate sent to clients in bytes/s
1395 * if the key is present in the table, otherwise zero, so that comparisons can
1396 * be easily performed. If the inspected parameter is not stored in the table,
1397 * <not found> is returned.
1398 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001399static int sample_conv_table_bytes_out_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001400{
1401 struct stktable *t;
1402 struct stktable_key *key;
1403 struct stksess *ts;
1404 void *ptr;
1405
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001406 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001407
1408 key = smp_to_stkey(smp, t);
1409 if (!key)
1410 return 0;
1411
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001412 ts = stktable_lookup_key(t, key);
1413
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001414 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001415 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001416 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001417
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001418 if (!ts) /* key not present */
1419 return 1;
1420
1421 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_OUT_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001422 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001423 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Daniel Corbett3e60b112018-05-27 09:47:12 -04001424 t->data_arg[STKTABLE_DT_BYTES_OUT_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001425
Daniel Corbett3e60b112018-05-27 09:47:12 -04001426 stktable_release(t, ts);
1427 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001428}
1429
Emeric Brun877b0b52021-06-30 18:57:49 +02001430/* Casts sample <smp> to the type of the table specified in arg_p(1), and looks
1431 * it up into this table. Returns the value of the GPT[arg_p(0)] tag for the key
1432 * if the key is present in the table, otherwise false, so that comparisons can
1433 * be easily performed. If the inspected parameter is not stored in the table,
1434 * <not found> is returned.
1435 */
1436static int sample_conv_table_gpt(const struct arg *arg_p, struct sample *smp, void *private)
1437{
1438 struct stktable *t;
1439 struct stktable_key *key;
1440 struct stksess *ts;
1441 void *ptr;
1442 unsigned int idx;
1443
1444 idx = arg_p[0].data.sint;
1445
1446 t = arg_p[1].data.t;
1447
1448 key = smp_to_stkey(smp, t);
1449 if (!key)
1450 return 0;
1451
1452 ts = stktable_lookup_key(t, key);
1453
1454 smp->flags = SMP_F_VOL_TEST;
1455 smp->data.type = SMP_T_SINT;
1456 smp->data.u.sint = 0;
1457
1458 if (!ts) /* key not present */
1459 return 1;
1460
1461 ptr = stktable_data_ptr_idx(t, ts, STKTABLE_DT_GPT, idx);
1462 if (ptr)
1463 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
1464
1465 stktable_release(t, ts);
1466 return !!ptr;
1467}
1468
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001469/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001470 * it up into this table. Returns the value of the GPT0 tag for the key
1471 * if the key is present in the table, otherwise false, so that comparisons can
1472 * be easily performed. If the inspected parameter is not stored in the table,
1473 * <not found> is returned.
1474 */
1475static int sample_conv_table_gpt0(const struct arg *arg_p, struct sample *smp, void *private)
1476{
1477 struct stktable *t;
1478 struct stktable_key *key;
1479 struct stksess *ts;
1480 void *ptr;
1481
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001482 t = arg_p[0].data.t;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001483
1484 key = smp_to_stkey(smp, t);
1485 if (!key)
1486 return 0;
1487
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001488 ts = stktable_lookup_key(t, key);
1489
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001490 smp->flags = SMP_F_VOL_TEST;
1491 smp->data.type = SMP_T_SINT;
1492 smp->data.u.sint = 0;
1493
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001494 if (!ts) /* key not present */
1495 return 1;
1496
1497 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPT0);
Emeric Brunf7ab0bf2021-06-30 18:58:22 +02001498 if (!ptr)
1499 ptr = stktable_data_ptr_idx(t, ts, STKTABLE_DT_GPT, 0);
1500
Daniel Corbett3e60b112018-05-27 09:47:12 -04001501 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001502 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001503
Daniel Corbett3e60b112018-05-27 09:47:12 -04001504 stktable_release(t, ts);
1505 return !!ptr;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001506}
1507
Emeric Brun4d7ada82021-06-30 19:04:16 +02001508/* Casts sample <smp> to the type of the table specified in arg_p(1), and looks
1509 * it up into this table. Returns the value of the GPC[arg_p(0)] counter for the key
1510 * if the key is present in the table, otherwise zero, so that comparisons can
1511 * be easily performed. If the inspected parameter is not stored in the table,
1512 * <not found> is returned.
1513 */
1514static int sample_conv_table_gpc(const struct arg *arg_p, struct sample *smp, void *private)
1515{
1516 struct stktable *t;
1517 struct stktable_key *key;
1518 struct stksess *ts;
1519 void *ptr;
1520 unsigned int idx;
1521
1522 idx = arg_p[0].data.sint;
1523
1524 t = arg_p[1].data.t;
1525
1526 key = smp_to_stkey(smp, t);
1527 if (!key)
1528 return 0;
1529
1530 ts = stktable_lookup_key(t, key);
1531
1532 smp->flags = SMP_F_VOL_TEST;
1533 smp->data.type = SMP_T_SINT;
1534 smp->data.u.sint = 0;
1535
1536 if (!ts) /* key not present */
1537 return 1;
1538
1539 ptr = stktable_data_ptr_idx(t, ts, STKTABLE_DT_GPC, idx);
1540 if (ptr)
1541 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
1542
1543 stktable_release(t, ts);
1544 return !!ptr;
1545}
1546
1547/* Casts sample <smp> to the type of the table specified in arg_p(1), and looks
1548 * it up into this table. Returns the event rate of the GPC[arg_p(0)] counter
1549 * for the key if the key is present in the table, otherwise zero, so that
1550 * comparisons can be easily performed. If the inspected parameter is not
1551 * stored in the table, <not found> is returned.
1552 */
1553static int sample_conv_table_gpc_rate(const struct arg *arg_p, struct sample *smp, void *private)
1554{
1555 struct stktable *t;
1556 struct stktable_key *key;
1557 struct stksess *ts;
1558 void *ptr;
1559 unsigned int idx;
1560
1561 idx = arg_p[0].data.sint;
1562
1563 t = arg_p[1].data.t;
1564
1565 key = smp_to_stkey(smp, t);
1566 if (!key)
1567 return 0;
1568
1569 ts = stktable_lookup_key(t, key);
1570
1571 smp->flags = SMP_F_VOL_TEST;
1572 smp->data.type = SMP_T_SINT;
1573 smp->data.u.sint = 0;
1574
1575 if (!ts) /* key not present */
1576 return 1;
1577
1578 ptr = stktable_data_ptr_idx(t, ts, STKTABLE_DT_GPC_RATE, idx);
1579 if (ptr)
1580 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
1581 t->data_arg[STKTABLE_DT_GPC_RATE].u);
1582
1583 stktable_release(t, ts);
1584 return !!ptr;
1585}
1586
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001587/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001588 * it up into this table. Returns the value of the GPC0 counter for the key
1589 * if the key is present in the table, otherwise zero, so that comparisons can
1590 * be easily performed. If the inspected parameter is not stored in the table,
1591 * <not found> is returned.
1592 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001593static int sample_conv_table_gpc0(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001594{
1595 struct stktable *t;
1596 struct stktable_key *key;
1597 struct stksess *ts;
1598 void *ptr;
1599
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001600 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001601
1602 key = smp_to_stkey(smp, t);
1603 if (!key)
1604 return 0;
1605
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001606 ts = stktable_lookup_key(t, key);
1607
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001608 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001609 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001610 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001611
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001612 if (!ts) /* key not present */
1613 return 1;
1614
1615 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPC0);
Emeric Brun726783d2021-06-30 19:06:43 +02001616 if (!ptr) {
1617 /* fallback on the gpc array */
1618 ptr = stktable_data_ptr_idx(t, ts, STKTABLE_DT_GPC, 0);
1619 }
1620
Daniel Corbett3e60b112018-05-27 09:47:12 -04001621 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001622 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001623
Daniel Corbett3e60b112018-05-27 09:47:12 -04001624 stktable_release(t, ts);
1625 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001626}
1627
1628/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1629 * it up into this table. Returns the event rate of the GPC0 counter for the key
1630 * if the key is present in the table, otherwise zero, so that comparisons can
1631 * be easily performed. If the inspected parameter is not stored in the table,
1632 * <not found> is returned.
1633 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001634static int sample_conv_table_gpc0_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001635{
1636 struct stktable *t;
1637 struct stktable_key *key;
1638 struct stksess *ts;
1639 void *ptr;
1640
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001641 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001642
1643 key = smp_to_stkey(smp, t);
1644 if (!key)
1645 return 0;
1646
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001647 ts = stktable_lookup_key(t, key);
1648
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001649 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001650 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001651 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001652
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001653 if (!ts) /* key not present */
1654 return 1;
1655
1656 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPC0_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001657 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001658 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Daniel Corbett3e60b112018-05-27 09:47:12 -04001659 t->data_arg[STKTABLE_DT_GPC0_RATE].u);
Emeric Brun726783d2021-06-30 19:06:43 +02001660 else {
1661 /* fallback on the gpc array */
1662 ptr = stktable_data_ptr_idx(t, ts, STKTABLE_DT_GPC_RATE, 0);
1663 if (ptr)
1664 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
1665 t->data_arg[STKTABLE_DT_GPC_RATE].u);
1666 }
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001667
Daniel Corbett3e60b112018-05-27 09:47:12 -04001668 stktable_release(t, ts);
1669 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001670}
1671
1672/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001673 * it up into this table. Returns the value of the GPC1 counter for the key
1674 * if the key is present in the table, otherwise zero, so that comparisons can
1675 * be easily performed. If the inspected parameter is not stored in the table,
1676 * <not found> is returned.
1677 */
1678static int sample_conv_table_gpc1(const struct arg *arg_p, struct sample *smp, void *private)
1679{
1680 struct stktable *t;
1681 struct stktable_key *key;
1682 struct stksess *ts;
1683 void *ptr;
1684
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001685 t = arg_p[0].data.t;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001686
1687 key = smp_to_stkey(smp, t);
1688 if (!key)
1689 return 0;
1690
1691 ts = stktable_lookup_key(t, key);
1692
1693 smp->flags = SMP_F_VOL_TEST;
1694 smp->data.type = SMP_T_SINT;
1695 smp->data.u.sint = 0;
1696
1697 if (!ts) /* key not present */
1698 return 1;
1699
1700 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPC1);
Emeric Brun726783d2021-06-30 19:06:43 +02001701 if (!ptr) {
1702 /* fallback on the gpc array */
1703 ptr = stktable_data_ptr_idx(t, ts, STKTABLE_DT_GPC, 1);
1704 }
1705
Daniel Corbett3e60b112018-05-27 09:47:12 -04001706 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001707 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001708
Daniel Corbett3e60b112018-05-27 09:47:12 -04001709 stktable_release(t, ts);
1710 return !!ptr;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001711}
1712
1713/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1714 * it up into this table. Returns the event rate of the GPC1 counter for the key
1715 * if the key is present in the table, otherwise zero, so that comparisons can
1716 * be easily performed. If the inspected parameter is not stored in the table,
1717 * <not found> is returned.
1718 */
1719static int sample_conv_table_gpc1_rate(const struct arg *arg_p, struct sample *smp, void *private)
1720{
1721 struct stktable *t;
1722 struct stktable_key *key;
1723 struct stksess *ts;
1724 void *ptr;
1725
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001726 t = arg_p[0].data.t;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001727
1728 key = smp_to_stkey(smp, t);
1729 if (!key)
1730 return 0;
1731
1732 ts = stktable_lookup_key(t, key);
1733
1734 smp->flags = SMP_F_VOL_TEST;
1735 smp->data.type = SMP_T_SINT;
1736 smp->data.u.sint = 0;
1737
1738 if (!ts) /* key not present */
1739 return 1;
1740
1741 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPC1_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001742 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001743 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Daniel Corbett3e60b112018-05-27 09:47:12 -04001744 t->data_arg[STKTABLE_DT_GPC1_RATE].u);
Emeric Brun726783d2021-06-30 19:06:43 +02001745 else {
1746 /* fallback on the gpc array */
1747 ptr = stktable_data_ptr_idx(t, ts, STKTABLE_DT_GPC_RATE, 1);
1748 if (ptr)
1749 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
1750 t->data_arg[STKTABLE_DT_GPC_RATE].u);
1751 }
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001752
Daniel Corbett3e60b112018-05-27 09:47:12 -04001753 stktable_release(t, ts);
1754 return !!ptr;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001755}
1756
1757/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001758 * it up into this table. Returns the cumulated number of HTTP request errors
1759 * for the key if the key is present in the table, otherwise zero, so that
1760 * comparisons can be easily performed. If the inspected parameter is not stored
1761 * in the table, <not found> is returned.
1762 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001763static int sample_conv_table_http_err_cnt(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001764{
1765 struct stktable *t;
1766 struct stktable_key *key;
1767 struct stksess *ts;
1768 void *ptr;
1769
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001770 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001771
1772 key = smp_to_stkey(smp, t);
1773 if (!key)
1774 return 0;
1775
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001776 ts = stktable_lookup_key(t, key);
1777
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001778 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001779 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001780 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001781
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001782 if (!ts) /* key not present */
1783 return 1;
1784
1785 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_ERR_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001786 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001787 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001788
Daniel Corbett3e60b112018-05-27 09:47:12 -04001789 stktable_release(t, ts);
1790 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001791}
1792
1793/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1794 * it up into this table. Returns the HTTP request error rate the key
1795 * if the key is present in the table, otherwise zero, so that comparisons can
1796 * be easily performed. If the inspected parameter is not stored in the table,
1797 * <not found> is returned.
1798 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001799static int sample_conv_table_http_err_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001800{
1801 struct stktable *t;
1802 struct stktable_key *key;
1803 struct stksess *ts;
1804 void *ptr;
1805
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001806 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001807
1808 key = smp_to_stkey(smp, t);
1809 if (!key)
1810 return 0;
1811
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001812 ts = stktable_lookup_key(t, key);
1813
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001814 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001815 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001816 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001817
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001818 if (!ts) /* key not present */
1819 return 1;
1820
1821 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_ERR_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001822 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001823 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Daniel Corbett3e60b112018-05-27 09:47:12 -04001824 t->data_arg[STKTABLE_DT_HTTP_ERR_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001825
Daniel Corbett3e60b112018-05-27 09:47:12 -04001826 stktable_release(t, ts);
1827 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001828}
1829
1830/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Willy Tarreau826f3ab2021-02-10 12:07:15 +01001831 * it up into this table. Returns the cumulated number of HTTP response failures
1832 * for the key if the key is present in the table, otherwise zero, so that
1833 * comparisons can be easily performed. If the inspected parameter is not stored
1834 * in the table, <not found> is returned.
1835 */
1836static int sample_conv_table_http_fail_cnt(const struct arg *arg_p, struct sample *smp, void *private)
1837{
1838 struct stktable *t;
1839 struct stktable_key *key;
1840 struct stksess *ts;
1841 void *ptr;
1842
1843 t = arg_p[0].data.t;
1844
1845 key = smp_to_stkey(smp, t);
1846 if (!key)
1847 return 0;
1848
1849 ts = stktable_lookup_key(t, key);
1850
1851 smp->flags = SMP_F_VOL_TEST;
1852 smp->data.type = SMP_T_SINT;
1853 smp->data.u.sint = 0;
1854
1855 if (!ts) /* key not present */
1856 return 1;
1857
1858 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_FAIL_CNT);
1859 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001860 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Willy Tarreau826f3ab2021-02-10 12:07:15 +01001861
1862 stktable_release(t, ts);
1863 return !!ptr;
1864}
1865
1866/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1867 * it up into this table. Returns the HTTP response failure rate for the key
1868 * if the key is present in the table, otherwise zero, so that comparisons can
1869 * be easily performed. If the inspected parameter is not stored in the table,
1870 * <not found> is returned.
1871 */
1872static int sample_conv_table_http_fail_rate(const struct arg *arg_p, struct sample *smp, void *private)
1873{
1874 struct stktable *t;
1875 struct stktable_key *key;
1876 struct stksess *ts;
1877 void *ptr;
1878
1879 t = arg_p[0].data.t;
1880
1881 key = smp_to_stkey(smp, t);
1882 if (!key)
1883 return 0;
1884
1885 ts = stktable_lookup_key(t, key);
1886
1887 smp->flags = SMP_F_VOL_TEST;
1888 smp->data.type = SMP_T_SINT;
1889 smp->data.u.sint = 0;
1890
1891 if (!ts) /* key not present */
1892 return 1;
1893
1894 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_FAIL_RATE);
1895 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001896 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Willy Tarreau826f3ab2021-02-10 12:07:15 +01001897 t->data_arg[STKTABLE_DT_HTTP_FAIL_RATE].u);
1898
1899 stktable_release(t, ts);
1900 return !!ptr;
1901}
1902
1903/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001904 * it up into this table. Returns the cumulated number of HTTP request for the
1905 * key if the key is present in the table, otherwise zero, so that comparisons
1906 * can be easily performed. If the inspected parameter is not stored in the
1907 * table, <not found> is returned.
1908 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001909static int sample_conv_table_http_req_cnt(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001910{
1911 struct stktable *t;
1912 struct stktable_key *key;
1913 struct stksess *ts;
1914 void *ptr;
1915
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001916 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001917
1918 key = smp_to_stkey(smp, t);
1919 if (!key)
1920 return 0;
1921
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001922 ts = stktable_lookup_key(t, key);
1923
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001924 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001925 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001926 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001927
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001928 if (!ts) /* key not present */
1929 return 1;
1930
1931 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_REQ_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001932 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001933 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001934
Daniel Corbett3e60b112018-05-27 09:47:12 -04001935 stktable_release(t, ts);
1936 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001937}
1938
1939/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1940 * it up into this table. Returns the HTTP request rate the key if the key is
1941 * present in the table, otherwise zero, so that comparisons can be easily
1942 * performed. If the inspected parameter is not stored in the table, <not found>
1943 * is returned.
1944 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001945static int sample_conv_table_http_req_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001946{
1947 struct stktable *t;
1948 struct stktable_key *key;
1949 struct stksess *ts;
1950 void *ptr;
1951
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001952 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001953
1954 key = smp_to_stkey(smp, t);
1955 if (!key)
1956 return 0;
1957
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001958 ts = stktable_lookup_key(t, key);
1959
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001960 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001961 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001962 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001963
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001964 if (!ts) /* key not present */
1965 return 1;
1966
1967 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_REQ_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001968 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001969 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Daniel Corbett3e60b112018-05-27 09:47:12 -04001970 t->data_arg[STKTABLE_DT_HTTP_REQ_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001971
Daniel Corbett3e60b112018-05-27 09:47:12 -04001972 stktable_release(t, ts);
1973 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001974}
1975
1976/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1977 * it up into this table. Returns the volume of datareceived from clients in kbytes
1978 * if the key is present in the table, otherwise zero, so that comparisons can
1979 * be easily performed. If the inspected parameter is not stored in the table,
1980 * <not found> is returned.
1981 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001982static int sample_conv_table_kbytes_in(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001983{
1984 struct stktable *t;
1985 struct stktable_key *key;
1986 struct stksess *ts;
1987 void *ptr;
1988
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001989 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001990
1991 key = smp_to_stkey(smp, t);
1992 if (!key)
1993 return 0;
1994
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001995 ts = stktable_lookup_key(t, key);
1996
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001997 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001998 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001999 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002000
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002001 if (!ts) /* key not present */
2002 return 1;
2003
2004 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_IN_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04002005 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002006 smp->data.u.sint = stktable_data_cast(ptr, std_t_ull) >> 10;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002007
Daniel Corbett3e60b112018-05-27 09:47:12 -04002008 stktable_release(t, ts);
2009 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002010}
2011
2012/* Casts sample <smp> to the type of the table specified in arg(0), and looks
2013 * it up into this table. Returns the volume of data sent to clients in kbytes
2014 * if the key is present in the table, otherwise zero, so that comparisons can
2015 * be easily performed. If the inspected parameter is not stored in the table,
2016 * <not found> is returned.
2017 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02002018static int sample_conv_table_kbytes_out(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002019{
2020 struct stktable *t;
2021 struct stktable_key *key;
2022 struct stksess *ts;
2023 void *ptr;
2024
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002025 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002026
2027 key = smp_to_stkey(smp, t);
2028 if (!key)
2029 return 0;
2030
Willy Tarreauf0c730a2016-05-25 17:07:56 +02002031 ts = stktable_lookup_key(t, key);
2032
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002033 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02002034 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02002035 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002036
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002037 if (!ts) /* key not present */
2038 return 1;
2039
2040 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_OUT_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04002041 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002042 smp->data.u.sint = stktable_data_cast(ptr, std_t_ull) >> 10;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002043
Daniel Corbett3e60b112018-05-27 09:47:12 -04002044 stktable_release(t, ts);
2045 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002046}
2047
2048/* Casts sample <smp> to the type of the table specified in arg(0), and looks
2049 * it up into this table. Returns the server ID associated with the key if the
2050 * key is present in the table, otherwise zero, so that comparisons can be
2051 * easily performed. If the inspected parameter is not stored in the table,
2052 * <not found> is returned.
2053 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02002054static int sample_conv_table_server_id(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002055{
2056 struct stktable *t;
2057 struct stktable_key *key;
2058 struct stksess *ts;
2059 void *ptr;
2060
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002061 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002062
2063 key = smp_to_stkey(smp, t);
2064 if (!key)
2065 return 0;
2066
Willy Tarreauf0c730a2016-05-25 17:07:56 +02002067 ts = stktable_lookup_key(t, key);
2068
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002069 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02002070 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02002071 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002072
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002073 if (!ts) /* key not present */
2074 return 1;
2075
2076 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_SERVER_ID);
Daniel Corbett3e60b112018-05-27 09:47:12 -04002077 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002078 smp->data.u.sint = stktable_data_cast(ptr, std_t_sint);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002079
Daniel Corbett3e60b112018-05-27 09:47:12 -04002080 stktable_release(t, ts);
2081 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002082}
2083
2084/* Casts sample <smp> to the type of the table specified in arg(0), and looks
2085 * it up into this table. Returns the cumulated number of sessions for the
2086 * key if the key is present in the table, otherwise zero, so that comparisons
2087 * can be easily performed. If the inspected parameter is not stored in the
2088 * table, <not found> is returned.
2089 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02002090static int sample_conv_table_sess_cnt(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002091{
2092 struct stktable *t;
2093 struct stktable_key *key;
2094 struct stksess *ts;
2095 void *ptr;
2096
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002097 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002098
2099 key = smp_to_stkey(smp, t);
2100 if (!key)
2101 return 0;
2102
Willy Tarreauf0c730a2016-05-25 17:07:56 +02002103 ts = stktable_lookup_key(t, key);
2104
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002105 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02002106 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02002107 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002108
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002109 if (!ts) /* key not present */
2110 return 1;
2111
2112 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_SESS_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04002113 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002114 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002115
Daniel Corbett3e60b112018-05-27 09:47:12 -04002116 stktable_release(t, ts);
2117 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002118}
2119
2120/* Casts sample <smp> to the type of the table specified in arg(0), and looks
2121 * it up into this table. Returns the session rate the key if the key is
2122 * present in the table, otherwise zero, so that comparisons can be easily
2123 * performed. If the inspected parameter is not stored in the table, <not found>
2124 * is returned.
2125 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02002126static int sample_conv_table_sess_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002127{
2128 struct stktable *t;
2129 struct stktable_key *key;
2130 struct stksess *ts;
2131 void *ptr;
2132
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002133 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002134
2135 key = smp_to_stkey(smp, t);
2136 if (!key)
2137 return 0;
2138
Willy Tarreauf0c730a2016-05-25 17:07:56 +02002139 ts = stktable_lookup_key(t, key);
2140
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002141 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02002142 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02002143 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002144
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002145 if (!ts) /* key not present */
2146 return 1;
2147
2148 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_SESS_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04002149 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002150 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Daniel Corbett3e60b112018-05-27 09:47:12 -04002151 t->data_arg[STKTABLE_DT_SESS_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002152
Daniel Corbett3e60b112018-05-27 09:47:12 -04002153 stktable_release(t, ts);
2154 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002155}
2156
2157/* Casts sample <smp> to the type of the table specified in arg(0), and looks
2158 * it up into this table. Returns the amount of concurrent connections tracking
2159 * the same key if the key is present in the table, otherwise zero, so that
2160 * comparisons can be easily performed. If the inspected parameter is not
2161 * stored in the table, <not found> is returned.
2162 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02002163static int sample_conv_table_trackers(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002164{
2165 struct stktable *t;
2166 struct stktable_key *key;
2167 struct stksess *ts;
2168
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002169 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002170
2171 key = smp_to_stkey(smp, t);
2172 if (!key)
2173 return 0;
2174
Willy Tarreauf0c730a2016-05-25 17:07:56 +02002175 ts = stktable_lookup_key(t, key);
2176
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002177 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02002178 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02002179 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002180
Tim Duesterhus65189c12018-06-26 15:57:29 +02002181 if (!ts)
2182 return 1;
2183
2184 smp->data.u.sint = ts->ref_cnt;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002185
Daniel Corbett3e60b112018-05-27 09:47:12 -04002186 stktable_release(t, ts);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002187 return 1;
2188}
2189
Emeric Brun4d7ada82021-06-30 19:04:16 +02002190/* This function increments the gpc counter at index 'rule->arg.gpc.idx' of the
2191 * array on the tracksc counter of index 'rule->arg.gpc.sc' stored into the
2192 * <stream> or directly in the session <sess> if <stream> is set to NULL
2193 *
2194 * This function always returns ACT_RET_CONT and parameter flags is unused.
2195 */
2196static enum act_return action_inc_gpc(struct act_rule *rule, struct proxy *px,
2197 struct session *sess, struct stream *s, int flags)
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002198{
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002199 struct stksess *ts;
2200 struct stkctr *stkctr;
2201
2202 /* Extract the stksess, return OK if no stksess available. */
2203 if (s)
2204 stkctr = &s->stkctr[rule->arg.gpc.sc];
2205 else
2206 stkctr = &sess->stkctr[rule->arg.gpc.sc];
Willy Tarreau79c1e912016-01-25 14:54:45 +01002207
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002208 ts = stkctr_entry(stkctr);
Willy Tarreau79c1e912016-01-25 14:54:45 +01002209 if (ts) {
2210 void *ptr1, *ptr2;
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002211
Emeric Brun4d7ada82021-06-30 19:04:16 +02002212 /* First, update gpc_rate if it's tracked. Second, update its gpc if tracked. */
2213 ptr1 = stktable_data_ptr_idx(stkctr->table, ts, STKTABLE_DT_GPC_RATE, rule->arg.gpc.idx);
2214 ptr2 = stktable_data_ptr_idx(stkctr->table, ts, STKTABLE_DT_GPC, rule->arg.gpc.idx);
2215
Emeric Brun819fc6f2017-06-13 19:37:32 +02002216 if (ptr1 || ptr2) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002217 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002218
2219 if (ptr1)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002220 update_freq_ctr_period(&stktable_data_cast(ptr1, std_t_frqp),
Emeric Brun4d7ada82021-06-30 19:04:16 +02002221 stkctr->table->data_arg[STKTABLE_DT_GPC_RATE].u, 1);
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002222
Emeric Brun819fc6f2017-06-13 19:37:32 +02002223 if (ptr2)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002224 stktable_data_cast(ptr2, std_t_uint)++;
Willy Tarreau79c1e912016-01-25 14:54:45 +01002225
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002226 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002227
2228 /* If data was modified, we need to touch to re-schedule sync */
2229 stktable_touch_local(stkctr->table, ts, 0);
2230 }
Willy Tarreau79c1e912016-01-25 14:54:45 +01002231 }
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002232 return ACT_RET_CONT;
2233}
2234
Emeric Brun4d7ada82021-06-30 19:04:16 +02002235/* Same as action_inc_gpc() but for gpc0 only */
2236static enum act_return action_inc_gpc0(struct act_rule *rule, struct proxy *px,
2237 struct session *sess, struct stream *s, int flags)
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002238{
Emeric Brun4d7ada82021-06-30 19:04:16 +02002239 struct stksess *ts;
2240 struct stkctr *stkctr;
Willy Tarreau5b654ad2021-07-06 18:51:12 +02002241 unsigned int period = 0;
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002242
Emeric Brun4d7ada82021-06-30 19:04:16 +02002243 /* Extract the stksess, return OK if no stksess available. */
2244 if (s)
2245 stkctr = &s->stkctr[rule->arg.gpc.sc];
2246 else
2247 stkctr = &sess->stkctr[rule->arg.gpc.sc];
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002248
Emeric Brun4d7ada82021-06-30 19:04:16 +02002249 ts = stkctr_entry(stkctr);
2250 if (ts) {
2251 void *ptr1, *ptr2;
2252
2253 /* First, update gpc0_rate if it's tracked. Second, update its gpc0 if tracked. */
2254 ptr1 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC0_RATE);
Emeric Brun726783d2021-06-30 19:06:43 +02002255 if (ptr1) {
2256 period = stkctr->table->data_arg[STKTABLE_DT_GPC0_RATE].u;
2257 }
2258 else {
2259 /* fallback on the gpc array */
2260 ptr1 = stktable_data_ptr_idx(stkctr->table, ts, STKTABLE_DT_GPC_RATE, 0);
2261 if (ptr1)
2262 period = stkctr->table->data_arg[STKTABLE_DT_GPC_RATE].u;
2263 }
2264
Emeric Brun4d7ada82021-06-30 19:04:16 +02002265 ptr2 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC0);
Emeric Brun726783d2021-06-30 19:06:43 +02002266 if (!ptr2) {
2267 /* fallback on the gpc array */
2268 ptr2 = stktable_data_ptr_idx(stkctr->table, ts, STKTABLE_DT_GPC, 0);
2269 }
2270
Emeric Brun4d7ada82021-06-30 19:04:16 +02002271 if (ptr1 || ptr2) {
2272 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
2273
2274 if (ptr1)
2275 update_freq_ctr_period(&stktable_data_cast(ptr1, std_t_frqp),
Emeric Brun726783d2021-06-30 19:06:43 +02002276 period, 1);
Emeric Brun4d7ada82021-06-30 19:04:16 +02002277
2278 if (ptr2)
2279 stktable_data_cast(ptr2, std_t_uint)++;
2280
2281 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
2282
2283 /* If data was modified, we need to touch to re-schedule sync */
2284 stktable_touch_local(stkctr->table, ts, 0);
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002285 }
2286 }
Emeric Brun4d7ada82021-06-30 19:04:16 +02002287 return ACT_RET_CONT;
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002288}
2289
Emeric Brun4d7ada82021-06-30 19:04:16 +02002290/* Same as action_inc_gpc() but for gpc1 only */
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002291static enum act_return action_inc_gpc1(struct act_rule *rule, struct proxy *px,
2292 struct session *sess, struct stream *s, int flags)
2293{
2294 struct stksess *ts;
2295 struct stkctr *stkctr;
Willy Tarreau5b654ad2021-07-06 18:51:12 +02002296 unsigned int period = 0;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002297
2298 /* Extract the stksess, return OK if no stksess available. */
2299 if (s)
2300 stkctr = &s->stkctr[rule->arg.gpc.sc];
2301 else
2302 stkctr = &sess->stkctr[rule->arg.gpc.sc];
2303
2304 ts = stkctr_entry(stkctr);
2305 if (ts) {
2306 void *ptr1, *ptr2;
2307
2308 /* First, update gpc1_rate if it's tracked. Second, update its gpc1 if tracked. */
2309 ptr1 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC1_RATE);
Emeric Brun726783d2021-06-30 19:06:43 +02002310 if (ptr1) {
2311 period = stkctr->table->data_arg[STKTABLE_DT_GPC1_RATE].u;
2312 }
2313 else {
2314 /* fallback on the gpc array */
2315 ptr1 = stktable_data_ptr_idx(stkctr->table, ts, STKTABLE_DT_GPC_RATE, 1);
2316 if (ptr1)
2317 period = stkctr->table->data_arg[STKTABLE_DT_GPC_RATE].u;
2318 }
2319
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002320 ptr2 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC1);
Emeric Brun726783d2021-06-30 19:06:43 +02002321 if (!ptr2) {
2322 /* fallback on the gpc array */
2323 ptr2 = stktable_data_ptr_idx(stkctr->table, ts, STKTABLE_DT_GPC, 1);
2324 }
2325
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002326 if (ptr1 || ptr2) {
2327 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
2328
2329 if (ptr1)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002330 update_freq_ctr_period(&stktable_data_cast(ptr1, std_t_frqp),
Emeric Brun726783d2021-06-30 19:06:43 +02002331 period, 1);
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002332
2333 if (ptr2)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002334 stktable_data_cast(ptr2, std_t_uint)++;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002335
2336 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
2337
2338 /* If data was modified, we need to touch to re-schedule sync */
2339 stktable_touch_local(stkctr->table, ts, 0);
2340 }
2341 }
2342 return ACT_RET_CONT;
2343}
2344
Emeric Brun4d7ada82021-06-30 19:04:16 +02002345/* This function is a common parser for actions incrementing the GPC
2346 * (General Purpose Counters). It understands the formats:
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002347 *
Emeric Brun4d7ada82021-06-30 19:04:16 +02002348 * sc-inc-gpc(<gpc IDX>,<track ID>)
2349 * sc-inc-gpc0([<track ID>])
2350 * sc-inc-gpc1([<track ID>])
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002351 *
Emeric Brun4d7ada82021-06-30 19:04:16 +02002352 * It returns ACT_RET_PRS_ERR if fails and <err> is filled with an error
2353 * message. Otherwise it returns ACT_RET_PRS_OK.
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002354 */
Emeric Brun4d7ada82021-06-30 19:04:16 +02002355static enum act_parse_ret parse_inc_gpc(const char **args, int *arg, struct proxy *px,
2356 struct act_rule *rule, char **err)
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002357{
2358 const char *cmd_name = args[*arg-1];
2359 char *error;
2360
Emeric Brun4d7ada82021-06-30 19:04:16 +02002361 cmd_name += strlen("sc-inc-gpc");
2362 if (*cmd_name == '(') {
2363 cmd_name++; /* skip the '(' */
2364 rule->arg.gpc.idx = strtoul(cmd_name, &error, 10); /* Convert stick table id. */
2365 if (*error != ',') {
2366 memprintf(err, "Missing gpc ID '%s'. Expects sc-inc-gpc(<GPC ID>,<Track ID>)", args[*arg-1]);
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002367 return ACT_RET_PRS_ERR;
2368 }
Emeric Brun4d7ada82021-06-30 19:04:16 +02002369 else {
2370 cmd_name = error + 1; /* skip the ',' */
2371 rule->arg.gpc.sc = strtol(cmd_name, &error, 10); /* Convert stick table id. */
2372 if (*error != ')') {
2373 memprintf(err, "invalid stick table track ID '%s'. Expects sc-inc-gpc(<GPC ID>,<Track ID>)", args[*arg-1]);
2374 return ACT_RET_PRS_ERR;
2375 }
2376
2377 if (rule->arg.gpc.sc >= MAX_SESS_STKCTR) {
2378 memprintf(err, "invalid stick table track ID '%s'. The max allowed ID is %d",
2379 args[*arg-1], MAX_SESS_STKCTR-1);
2380 return ACT_RET_PRS_ERR;
2381 }
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002382 }
Emeric Brun4d7ada82021-06-30 19:04:16 +02002383 rule->action_ptr = action_inc_gpc;
2384 }
2385 else if (*cmd_name == '0' ||*cmd_name == '1') {
2386 char c = *cmd_name;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002387
Emeric Brun4d7ada82021-06-30 19:04:16 +02002388 cmd_name++;
2389 if (*cmd_name == '\0') {
2390 /* default stick table id. */
2391 rule->arg.gpc.sc = 0;
2392 } else {
2393 /* parse the stick table id. */
2394 if (*cmd_name != '(') {
2395 memprintf(err, "invalid stick table track ID. Expects %s(<Track ID>)", args[*arg-1]);
2396 return ACT_RET_PRS_ERR;
2397 }
2398 cmd_name++; /* jump the '(' */
2399 rule->arg.gpc.sc = strtol(cmd_name, &error, 10); /* Convert stick table id. */
2400 if (*error != ')') {
2401 memprintf(err, "invalid stick table track ID. Expects %s(<Track ID>)", args[*arg-1]);
2402 return ACT_RET_PRS_ERR;
2403 }
2404
2405 if (rule->arg.gpc.sc >= MAX_SESS_STKCTR) {
2406 memprintf(err, "invalid stick table track ID. The max allowed ID is %d",
2407 MAX_SESS_STKCTR-1);
2408 return ACT_RET_PRS_ERR;
2409 }
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002410 }
Emeric Brun4d7ada82021-06-30 19:04:16 +02002411 if (c == '1')
2412 rule->action_ptr = action_inc_gpc1;
2413 else
2414 rule->action_ptr = action_inc_gpc0;
2415 }
2416 else {
2417 /* default stick table id. */
2418 memprintf(err, "invalid gpc ID '%s'. Expects sc-set-gpc(<GPC ID>,<Track ID>)", args[*arg-1]);
2419 return ACT_RET_PRS_ERR;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002420 }
2421 rule->action = ACT_CUSTOM;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002422 return ACT_RET_PRS_OK;
2423}
2424
Emeric Brun877b0b52021-06-30 18:57:49 +02002425/* This function sets the gpt at index 'rule->arg.gpt.idx' of the array on the
2426 * tracksc counter of index 'rule->arg.gpt.sc' stored into the <stream> or
2427 * directly in the session <sess> if <stream> is set to NULL. This gpt is
2428 * set to the value computed by the expression 'rule->arg.gpt.expr' or if
2429 * 'rule->arg.gpt.expr' is null directly to the value of 'rule->arg.gpt.value'.
2430 *
2431 * This function always returns ACT_RET_CONT and parameter flags is unused.
2432 */
2433static enum act_return action_set_gpt(struct act_rule *rule, struct proxy *px,
2434 struct session *sess, struct stream *s, int flags)
2435{
2436 void *ptr;
2437 struct stksess *ts;
2438 struct stkctr *stkctr;
2439 unsigned int value = 0;
2440 struct sample *smp;
2441 int smp_opt_dir;
2442
2443 /* Extract the stksess, return OK if no stksess available. */
2444 if (s)
2445 stkctr = &s->stkctr[rule->arg.gpt.sc];
2446 else
2447 stkctr = &sess->stkctr[rule->arg.gpt.sc];
2448
2449 ts = stkctr_entry(stkctr);
2450 if (!ts)
2451 return ACT_RET_CONT;
2452
2453 /* Store the sample in the required sc, and ignore errors. */
2454 ptr = stktable_data_ptr_idx(stkctr->table, ts, STKTABLE_DT_GPT, rule->arg.gpt.idx);
2455 if (ptr) {
2456
2457 if (!rule->arg.gpt.expr)
2458 value = (unsigned int)(rule->arg.gpt.value);
2459 else {
2460 switch (rule->from) {
2461 case ACT_F_TCP_REQ_SES: smp_opt_dir = SMP_OPT_DIR_REQ; break;
2462 case ACT_F_TCP_REQ_CNT: smp_opt_dir = SMP_OPT_DIR_REQ; break;
2463 case ACT_F_TCP_RES_CNT: smp_opt_dir = SMP_OPT_DIR_RES; break;
2464 case ACT_F_HTTP_REQ: smp_opt_dir = SMP_OPT_DIR_REQ; break;
2465 case ACT_F_HTTP_RES: smp_opt_dir = SMP_OPT_DIR_RES; break;
2466 default:
2467 send_log(px, LOG_ERR, "stick table: internal error while setting gpt%u.", rule->arg.gpt.idx);
2468 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))
2469 ha_alert("stick table: internal error while executing setting gpt%u.\n", rule->arg.gpt.idx);
2470 return ACT_RET_CONT;
2471 }
2472
2473 /* Fetch and cast the expression. */
2474 smp = sample_fetch_as_type(px, sess, s, smp_opt_dir|SMP_OPT_FINAL, rule->arg.gpt.expr, SMP_T_SINT);
2475 if (!smp) {
2476 send_log(px, LOG_WARNING, "stick table: invalid expression or data type while setting gpt%u.", rule->arg.gpt.idx);
2477 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))
2478 ha_alert("stick table: invalid expression or data type while setting gpt%u.\n", rule->arg.gpt.idx);
2479 return ACT_RET_CONT;
2480 }
2481 value = (unsigned int)(smp->data.u.sint);
2482 }
2483
2484 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
2485
2486 stktable_data_cast(ptr, std_t_uint) = value;
2487
2488 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
2489
2490 stktable_touch_local(stkctr->table, ts, 0);
2491 }
2492
2493 return ACT_RET_CONT;
2494}
2495
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002496/* Always returns 1. */
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002497static enum act_return action_set_gpt0(struct act_rule *rule, struct proxy *px,
Willy Tarreau658b85b2015-09-27 10:00:49 +02002498 struct session *sess, struct stream *s, int flags)
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002499{
2500 void *ptr;
2501 struct stksess *ts;
2502 struct stkctr *stkctr;
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002503 unsigned int value = 0;
2504 struct sample *smp;
2505 int smp_opt_dir;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002506
2507 /* Extract the stksess, return OK if no stksess available. */
2508 if (s)
2509 stkctr = &s->stkctr[rule->arg.gpt.sc];
2510 else
2511 stkctr = &sess->stkctr[rule->arg.gpt.sc];
Willy Tarreau79c1e912016-01-25 14:54:45 +01002512
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002513 ts = stkctr_entry(stkctr);
2514 if (!ts)
2515 return ACT_RET_CONT;
2516
2517 /* Store the sample in the required sc, and ignore errors. */
2518 ptr = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPT0);
Emeric Brunf7ab0bf2021-06-30 18:58:22 +02002519 if (!ptr)
2520 ptr = stktable_data_ptr_idx(stkctr->table, ts, STKTABLE_DT_GPT, 0);
2521
Willy Tarreau79c1e912016-01-25 14:54:45 +01002522 if (ptr) {
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002523 if (!rule->arg.gpt.expr)
2524 value = (unsigned int)(rule->arg.gpt.value);
2525 else {
2526 switch (rule->from) {
2527 case ACT_F_TCP_REQ_SES: smp_opt_dir = SMP_OPT_DIR_REQ; break;
2528 case ACT_F_TCP_REQ_CNT: smp_opt_dir = SMP_OPT_DIR_REQ; break;
2529 case ACT_F_TCP_RES_CNT: smp_opt_dir = SMP_OPT_DIR_RES; break;
2530 case ACT_F_HTTP_REQ: smp_opt_dir = SMP_OPT_DIR_REQ; break;
2531 case ACT_F_HTTP_RES: smp_opt_dir = SMP_OPT_DIR_RES; break;
2532 default:
2533 send_log(px, LOG_ERR, "stick table: internal error while setting gpt0.");
2534 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))
2535 ha_alert("stick table: internal error while executing setting gpt0.\n");
2536 return ACT_RET_CONT;
2537 }
2538
2539 /* Fetch and cast the expression. */
2540 smp = sample_fetch_as_type(px, sess, s, smp_opt_dir|SMP_OPT_FINAL, rule->arg.gpt.expr, SMP_T_SINT);
2541 if (!smp) {
2542 send_log(px, LOG_WARNING, "stick table: invalid expression or data type while setting gpt0.");
2543 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))
2544 ha_alert("stick table: invalid expression or data type while setting gpt0.\n");
2545 return ACT_RET_CONT;
2546 }
2547 value = (unsigned int)(smp->data.u.sint);
2548 }
2549
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002550 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002551
Emeric Brun0e3457b2021-06-30 17:18:28 +02002552 stktable_data_cast(ptr, std_t_uint) = value;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002553
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002554 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002555
2556 stktable_touch_local(stkctr->table, ts, 0);
Willy Tarreau79c1e912016-01-25 14:54:45 +01002557 }
2558
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002559 return ACT_RET_CONT;
2560}
2561
Emeric Brun877b0b52021-06-30 18:57:49 +02002562/* This function is a parser for the "sc-set-gpt" and "sc-set-gpt0" actions.
2563 * It understands the formats:
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002564 *
Emeric Brun877b0b52021-06-30 18:57:49 +02002565 * sc-set-gpt(<gpt IDX>,<track ID>) <expression>
2566 * sc-set-gpt0(<track ID>) <expression>
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002567 *
Emeric Brun877b0b52021-06-30 18:57:49 +02002568 * It returns ACT_RET_PRS_ERR if fails and <err> is filled with an error message.
2569 * Otherwise, it returns ACT_RET_PRS_OK and the variable 'rule->arg.gpt.expr'
2570 * is filled with the pointer to the expression to execute or NULL if the arg
2571 * is directly an integer stored into 'rule->arg.gpt.value'.
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002572 */
Emeric Brun877b0b52021-06-30 18:57:49 +02002573static enum act_parse_ret parse_set_gpt(const char **args, int *arg, struct proxy *px,
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002574 struct act_rule *rule, char **err)
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002575{
2576 const char *cmd_name = args[*arg-1];
2577 char *error;
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002578 int smp_val;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002579
Emeric Brun877b0b52021-06-30 18:57:49 +02002580 cmd_name += strlen("sc-set-gpt");
2581 if (*cmd_name == '(') {
2582 cmd_name++; /* skip the '(' */
2583 rule->arg.gpt.idx = strtoul(cmd_name, &error, 10); /* Convert stick table id. */
2584 if (*error != ',') {
2585 memprintf(err, "Missing gpt ID '%s'. Expects sc-set-gpt(<GPT ID>,<Track ID>)", args[*arg-1]);
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002586 return ACT_RET_PRS_ERR;
2587 }
Emeric Brun877b0b52021-06-30 18:57:49 +02002588 else {
2589 cmd_name = error + 1; /* skip the ',' */
2590 rule->arg.gpt.sc = strtol(cmd_name, &error, 10); /* Convert stick table id. */
2591 if (*error != ')') {
2592 memprintf(err, "invalid stick table track ID '%s'. Expects sc-set-gpt(<GPT ID>,<Track ID>)", args[*arg-1]);
2593 return ACT_RET_PRS_ERR;
2594 }
2595
2596 if (rule->arg.gpt.sc >= MAX_SESS_STKCTR) {
2597 memprintf(err, "invalid stick table track ID '%s'. The max allowed ID is %d",
2598 args[*arg-1], MAX_SESS_STKCTR-1);
2599 return ACT_RET_PRS_ERR;
2600 }
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002601 }
Emeric Brun877b0b52021-06-30 18:57:49 +02002602 rule->action_ptr = action_set_gpt;
2603 }
2604 else if (*cmd_name == '0') {
2605 cmd_name++;
2606 if (*cmd_name == '\0') {
2607 /* default stick table id. */
2608 rule->arg.gpt.sc = 0;
2609 } else {
2610 /* parse the stick table id. */
2611 if (*cmd_name != '(') {
2612 memprintf(err, "invalid stick table track ID '%s'. Expects sc-set-gpt0(<Track ID>)", args[*arg-1]);
2613 return ACT_RET_PRS_ERR;
2614 }
2615 cmd_name++; /* jump the '(' */
2616 rule->arg.gpt.sc = strtol(cmd_name, &error, 10); /* Convert stick table id. */
2617 if (*error != ')') {
2618 memprintf(err, "invalid stick table track ID '%s'. Expects sc-set-gpt0(<Track ID>)", args[*arg-1]);
2619 return ACT_RET_PRS_ERR;
2620 }
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002621
Emeric Brun877b0b52021-06-30 18:57:49 +02002622 if (rule->arg.gpt.sc >= MAX_SESS_STKCTR) {
2623 memprintf(err, "invalid stick table track ID '%s'. The max allowed ID is %d",
2624 args[*arg-1], MAX_SESS_STKCTR-1);
2625 return ACT_RET_PRS_ERR;
2626 }
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002627 }
Emeric Brun877b0b52021-06-30 18:57:49 +02002628 rule->action_ptr = action_set_gpt0;
2629 }
2630 else {
2631 /* default stick table id. */
2632 memprintf(err, "invalid gpt ID '%s'. Expects sc-set-gpt(<GPT ID>,<Track ID>)", args[*arg-1]);
2633 return ACT_RET_PRS_ERR;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002634 }
2635
Willy Tarreauece4c4a2021-08-24 14:57:28 +02002636 /* value may be either an integer or an expression */
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002637 rule->arg.gpt.expr = NULL;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002638 rule->arg.gpt.value = strtol(args[*arg], &error, 10);
Willy Tarreauece4c4a2021-08-24 14:57:28 +02002639 if (*error == '\0') {
2640 /* valid integer, skip it */
2641 (*arg)++;
2642 } else {
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002643 rule->arg.gpt.expr = sample_parse_expr((char **)args, arg, px->conf.args.file,
Willy Tarreaue3b57bf2020-02-14 16:50:14 +01002644 px->conf.args.line, err, &px->conf.args, NULL);
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002645 if (!rule->arg.gpt.expr)
2646 return ACT_RET_PRS_ERR;
2647
2648 switch (rule->from) {
2649 case ACT_F_TCP_REQ_SES: smp_val = SMP_VAL_FE_SES_ACC; break;
2650 case ACT_F_TCP_REQ_CNT: smp_val = SMP_VAL_FE_REQ_CNT; break;
2651 case ACT_F_TCP_RES_CNT: smp_val = SMP_VAL_BE_RES_CNT; break;
2652 case ACT_F_HTTP_REQ: smp_val = SMP_VAL_FE_HRQ_HDR; break;
2653 case ACT_F_HTTP_RES: smp_val = SMP_VAL_BE_HRS_HDR; break;
2654 default:
2655 memprintf(err, "internal error, unexpected rule->from=%d, please report this bug!", rule->from);
2656 return ACT_RET_PRS_ERR;
2657 }
2658 if (!(rule->arg.gpt.expr->fetch->val & smp_val)) {
2659 memprintf(err, "fetch method '%s' extracts information from '%s', none of which is available here", args[*arg-1],
2660 sample_src_names(rule->arg.gpt.expr->fetch->use));
2661 free(rule->arg.gpt.expr);
2662 return ACT_RET_PRS_ERR;
2663 }
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002664 }
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002665
Thierry FOURNIER42148732015-09-02 17:17:33 +02002666 rule->action = ACT_CUSTOM;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002667
2668 return ACT_RET_PRS_OK;
2669}
2670
Willy Tarreau7d562212016-11-25 16:10:05 +01002671/* set temp integer to the number of used entries in the table pointed to by expr.
2672 * Accepts exactly 1 argument of type table.
2673 */
2674static int
2675smp_fetch_table_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
2676{
2677 smp->flags = SMP_F_VOL_TEST;
2678 smp->data.type = SMP_T_SINT;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002679 smp->data.u.sint = args->data.t->current;
Willy Tarreau7d562212016-11-25 16:10:05 +01002680 return 1;
2681}
2682
2683/* set temp integer to the number of free entries in the table pointed to by expr.
2684 * Accepts exactly 1 argument of type table.
2685 */
2686static int
2687smp_fetch_table_avl(const struct arg *args, struct sample *smp, const char *kw, void *private)
2688{
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002689 struct stktable *t;
Willy Tarreau7d562212016-11-25 16:10:05 +01002690
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002691 t = args->data.t;
Willy Tarreau7d562212016-11-25 16:10:05 +01002692 smp->flags = SMP_F_VOL_TEST;
2693 smp->data.type = SMP_T_SINT;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002694 smp->data.u.sint = t->size - t->current;
Willy Tarreau7d562212016-11-25 16:10:05 +01002695 return 1;
2696}
2697
2698/* Returns a pointer to a stkctr depending on the fetch keyword name.
2699 * It is designed to be called as sc[0-9]_* sc_* or src_* exclusively.
2700 * sc[0-9]_* will return a pointer to the respective field in the
2701 * stream <l4>. sc_* requires an UINT argument specifying the stick
2702 * counter number. src_* will fill a locally allocated structure with
2703 * the table and entry corresponding to what is specified with src_*.
2704 * NULL may be returned if the designated stkctr is not tracked. For
2705 * the sc_* and sc[0-9]_* forms, an optional table argument may be
2706 * passed. When present, the currently tracked key is then looked up
2707 * in the specified table instead of the current table. The purpose is
Ilya Shipitsin47d17182020-06-21 21:42:57 +05002708 * to be able to convert multiple values per key (eg: have gpc0 from
Willy Tarreau7d562212016-11-25 16:10:05 +01002709 * multiple tables). <strm> is allowed to be NULL, in which case only
2710 * the session will be consulted.
2711 */
2712struct stkctr *
Emeric Brun819fc6f2017-06-13 19:37:32 +02002713smp_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 +01002714{
Willy Tarreau7d562212016-11-25 16:10:05 +01002715 struct stkctr *stkptr;
2716 struct stksess *stksess;
2717 unsigned int num = kw[2] - '0';
2718 int arg = 0;
2719
2720 if (num == '_' - '0') {
2721 /* sc_* variant, args[0] = ctr# (mandatory) */
2722 num = args[arg++].data.sint;
Willy Tarreau7d562212016-11-25 16:10:05 +01002723 }
2724 else if (num > 9) { /* src_* variant, args[0] = table */
2725 struct stktable_key *key;
2726 struct connection *conn = objt_conn(sess->origin);
2727 struct sample smp;
2728
2729 if (!conn)
2730 return NULL;
2731
Joseph Herlant5662fa42018-11-15 13:43:28 -08002732 /* Fetch source address in a sample. */
Willy Tarreau7d562212016-11-25 16:10:05 +01002733 smp.px = NULL;
2734 smp.sess = sess;
2735 smp.strm = strm;
Amaury Denoyellec460c702021-05-12 10:17:47 +02002736 if (!smp_fetch_src || !smp_fetch_src(empty_arg_list, &smp, "src", NULL))
Willy Tarreau7d562212016-11-25 16:10:05 +01002737 return NULL;
2738
2739 /* Converts into key. */
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002740 key = smp_to_stkey(&smp, args->data.t);
Willy Tarreau7d562212016-11-25 16:10:05 +01002741 if (!key)
2742 return NULL;
2743
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002744 stkctr->table = args->data.t;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002745 stkctr_set_entry(stkctr, stktable_lookup_key(stkctr->table, key));
2746 return stkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002747 }
2748
2749 /* Here, <num> contains the counter number from 0 to 9 for
2750 * the sc[0-9]_ form, or even higher using sc_(num) if needed.
2751 * args[arg] is the first optional argument. We first lookup the
2752 * ctr form the stream, then from the session if it was not there.
Christopher Fauleta9fa88a2019-10-21 10:53:34 +02002753 * But we must be sure the counter does not exceed MAX_SESS_STKCTR.
Willy Tarreau7d562212016-11-25 16:10:05 +01002754 */
Christopher Fauleta9fa88a2019-10-21 10:53:34 +02002755 if (num >= MAX_SESS_STKCTR)
2756 return NULL;
Willy Tarreau7d562212016-11-25 16:10:05 +01002757
2758 if (strm)
2759 stkptr = &strm->stkctr[num];
2760 if (!strm || !stkctr_entry(stkptr)) {
2761 stkptr = &sess->stkctr[num];
2762 if (!stkctr_entry(stkptr))
2763 return NULL;
2764 }
2765
2766 stksess = stkctr_entry(stkptr);
2767 if (!stksess)
2768 return NULL;
2769
2770 if (unlikely(args[arg].type == ARGT_TAB)) {
2771 /* an alternate table was specified, let's look up the same key there */
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002772 stkctr->table = args[arg].data.t;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002773 stkctr_set_entry(stkctr, stktable_lookup(stkctr->table, stksess));
2774 return stkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002775 }
2776 return stkptr;
2777}
2778
2779/* same as smp_fetch_sc_stkctr() but dedicated to src_* and can create
2780 * the entry if it doesn't exist yet. This is needed for a few fetch
2781 * functions which need to create an entry, such as src_inc_gpc* and
2782 * src_clr_gpc*.
2783 */
2784struct stkctr *
Emeric Brun819fc6f2017-06-13 19:37:32 +02002785smp_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 +01002786{
Willy Tarreau7d562212016-11-25 16:10:05 +01002787 struct stktable_key *key;
2788 struct connection *conn = objt_conn(sess->origin);
2789 struct sample smp;
2790
2791 if (strncmp(kw, "src_", 4) != 0)
2792 return NULL;
2793
2794 if (!conn)
2795 return NULL;
2796
Joseph Herlant5662fa42018-11-15 13:43:28 -08002797 /* Fetch source address in a sample. */
Willy Tarreau7d562212016-11-25 16:10:05 +01002798 smp.px = NULL;
2799 smp.sess = sess;
2800 smp.strm = strm;
Amaury Denoyellec460c702021-05-12 10:17:47 +02002801 if (!smp_fetch_src || !smp_fetch_src(empty_arg_list, &smp, "src", NULL))
Willy Tarreau7d562212016-11-25 16:10:05 +01002802 return NULL;
2803
2804 /* Converts into key. */
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002805 key = smp_to_stkey(&smp, args->data.t);
Willy Tarreau7d562212016-11-25 16:10:05 +01002806 if (!key)
2807 return NULL;
2808
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002809 stkctr->table = args->data.t;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002810 stkctr_set_entry(stkctr, stktable_get_entry(stkctr->table, key));
2811 return stkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002812}
2813
2814/* set return a boolean indicating if the requested stream counter is
2815 * currently being tracked or not.
2816 * Supports being called as "sc[0-9]_tracked" only.
2817 */
2818static int
2819smp_fetch_sc_tracked(const struct arg *args, struct sample *smp, const char *kw, void *private)
2820{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002821 struct stkctr tmpstkctr;
2822 struct stkctr *stkctr;
2823
Willy Tarreau7d562212016-11-25 16:10:05 +01002824 smp->flags = SMP_F_VOL_TEST;
2825 smp->data.type = SMP_T_BOOL;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002826 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2827 smp->data.u.sint = !!stkctr;
2828
2829 /* release the ref count */
Dirkjan Bussinkff57f1b2018-09-14 14:31:22 +02002830 if (stkctr == &tmpstkctr)
Emeric Brun819fc6f2017-06-13 19:37:32 +02002831 stktable_release(stkctr->table, stkctr_entry(stkctr));
2832
Emeric Brun877b0b52021-06-30 18:57:49 +02002833 return 1;
2834}
2835
2836/* set <smp> to the General Purpose Tag of index set as first arg
2837 * to value from the stream's tracked frontend counters or from the src.
2838 * Supports being called as "sc_get_gpt(<gpt-idx>,<sc-idx>[,<table>])" or
2839 * "src_get_gpt(<gpt-idx>[,<table>])" only. Value zero is returned if
2840 * the key is new or gpt is not stored.
2841 */
2842static int
2843smp_fetch_sc_get_gpt(const struct arg *args, struct sample *smp, const char *kw, void *private)
2844{
2845 struct stkctr tmpstkctr;
2846 struct stkctr *stkctr;
2847 unsigned int idx;
2848
2849 idx = args[0].data.sint;
2850
2851 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args + 1, kw, &tmpstkctr);
2852 if (!stkctr)
2853 return 0;
2854
2855 smp->flags = SMP_F_VOL_TEST;
2856 smp->data.type = SMP_T_SINT;
2857 smp->data.u.sint = 0;
2858
2859 if (stkctr_entry(stkctr)) {
2860 void *ptr;
2861
2862 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPT, idx);
2863 if (!ptr) {
2864 if (stkctr == &tmpstkctr)
2865 stktable_release(stkctr->table, stkctr_entry(stkctr));
2866 return 0; /* parameter not stored */
2867 }
2868
2869 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2870
2871 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
2872
2873 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2874
2875 if (stkctr == &tmpstkctr)
2876 stktable_release(stkctr->table, stkctr_entry(stkctr));
2877 }
Willy Tarreau7d562212016-11-25 16:10:05 +01002878 return 1;
2879}
2880
2881/* set <smp> to the General Purpose Flag 0 value from the stream's tracked
2882 * frontend counters or from the src.
2883 * Supports being called as "sc[0-9]_get_gpc0" or "src_get_gpt0" only. Value
2884 * zero is returned if the key is new.
2885 */
2886static int
2887smp_fetch_sc_get_gpt0(const struct arg *args, struct sample *smp, const char *kw, void *private)
2888{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002889 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002890 struct stkctr *stkctr;
2891
Emeric Brun819fc6f2017-06-13 19:37:32 +02002892 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002893 if (!stkctr)
2894 return 0;
2895
2896 smp->flags = SMP_F_VOL_TEST;
2897 smp->data.type = SMP_T_SINT;
2898 smp->data.u.sint = 0;
2899
Emeric Brun819fc6f2017-06-13 19:37:32 +02002900 if (stkctr_entry(stkctr)) {
2901 void *ptr;
2902
2903 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPT0);
Emeric Brunf7ab0bf2021-06-30 18:58:22 +02002904 if (!ptr)
2905 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPT, 0);
2906
Emeric Brun4d7ada82021-06-30 19:04:16 +02002907 if (!ptr) {
2908 if (stkctr == &tmpstkctr)
2909 stktable_release(stkctr->table, stkctr_entry(stkctr));
2910 return 0; /* parameter not stored */
2911 }
2912
2913 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2914
2915 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
2916
2917 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2918
2919 if (stkctr == &tmpstkctr)
2920 stktable_release(stkctr->table, stkctr_entry(stkctr));
2921 }
2922 return 1;
2923}
2924
2925/* set <smp> to the GPC[args(0)]'s value from the stream's tracked
2926 * frontend counters or from the src.
2927 * Supports being called as "sc_get_gpc(<gpc-idx>,<sc-idx>[,<table>])" or
2928 * "src_get_gpc(<gpc-idx>[,<table>])" only. Value
2929 * Value zero is returned if the key is new or gpc is not stored.
2930 */
2931static int
2932smp_fetch_sc_get_gpc(const struct arg *args, struct sample *smp, const char *kw, void *private)
2933{
2934 struct stkctr tmpstkctr;
2935 struct stkctr *stkctr;
2936 unsigned int idx;
2937
2938 idx = args[0].data.sint;
2939
2940 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args + 1, kw, &tmpstkctr);
2941 if (!stkctr)
2942 return 0;
2943
2944 smp->flags = SMP_F_VOL_TEST;
2945 smp->data.type = SMP_T_SINT;
2946 smp->data.u.sint = 0;
2947
2948 if (stkctr_entry(stkctr) != NULL) {
2949 void *ptr;
2950
2951 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC, idx);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002952 if (!ptr) {
2953 if (stkctr == &tmpstkctr)
2954 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002955 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002956 }
2957
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002958 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002959
Emeric Brun0e3457b2021-06-30 17:18:28 +02002960 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002961
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002962 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002963
2964 if (stkctr == &tmpstkctr)
2965 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002966 }
2967 return 1;
2968}
2969
2970/* set <smp> to the General Purpose Counter 0 value from the stream's tracked
2971 * frontend counters or from the src.
2972 * Supports being called as "sc[0-9]_get_gpc0" or "src_get_gpc0" only. Value
2973 * zero is returned if the key is new.
2974 */
2975static int
2976smp_fetch_sc_get_gpc0(const struct arg *args, struct sample *smp, const char *kw, void *private)
2977{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002978 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002979 struct stkctr *stkctr;
2980
Emeric Brun819fc6f2017-06-13 19:37:32 +02002981 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002982 if (!stkctr)
2983 return 0;
2984
2985 smp->flags = SMP_F_VOL_TEST;
2986 smp->data.type = SMP_T_SINT;
2987 smp->data.u.sint = 0;
2988
2989 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002990 void *ptr;
2991
2992 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0);
2993 if (!ptr) {
Emeric Brun726783d2021-06-30 19:06:43 +02002994 /* fallback on the gpc array */
2995 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC, 0);
2996 }
2997
2998 if (!ptr) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002999 if (stkctr == &tmpstkctr)
3000 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003001 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003002 }
3003
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003004 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003005
Emeric Brun0e3457b2021-06-30 17:18:28 +02003006 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003007
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003008 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003009
3010 if (stkctr == &tmpstkctr)
3011 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003012 }
3013 return 1;
3014}
3015
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003016/* set <smp> to the General Purpose Counter 1 value from the stream's tracked
3017 * frontend counters or from the src.
3018 * Supports being called as "sc[0-9]_get_gpc1" or "src_get_gpc1" only. Value
3019 * zero is returned if the key is new.
3020 */
3021static int
3022smp_fetch_sc_get_gpc1(const struct arg *args, struct sample *smp, const char *kw, void *private)
3023{
3024 struct stkctr tmpstkctr;
3025 struct stkctr *stkctr;
3026
3027 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
3028 if (!stkctr)
3029 return 0;
3030
3031 smp->flags = SMP_F_VOL_TEST;
3032 smp->data.type = SMP_T_SINT;
3033 smp->data.u.sint = 0;
3034
3035 if (stkctr_entry(stkctr) != NULL) {
3036 void *ptr;
3037
3038 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1);
3039 if (!ptr) {
Emeric Brun726783d2021-06-30 19:06:43 +02003040 /* fallback on the gpc array */
3041 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC, 1);
3042 }
3043
3044 if (!ptr) {
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003045 if (stkctr == &tmpstkctr)
3046 stktable_release(stkctr->table, stkctr_entry(stkctr));
3047 return 0; /* parameter not stored */
3048 }
3049
3050 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3051
Emeric Brun0e3457b2021-06-30 17:18:28 +02003052 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003053
3054 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3055
3056 if (stkctr == &tmpstkctr)
3057 stktable_release(stkctr->table, stkctr_entry(stkctr));
3058 }
3059 return 1;
3060}
3061
Emeric Brun4d7ada82021-06-30 19:04:16 +02003062/* set <smp> to the GPC[args(0)]'s event rate from the stream's
3063 * tracked frontend counters or from the src.
3064 * Supports being called as "sc_gpc_rate(<gpc-idx>,<sc-idx>[,<table])"
3065 * or "src_gpc_rate(<gpc-idx>[,<table>])" only.
3066 * Value zero is returned if the key is new or gpc_rate is not stored.
3067 */
3068static int
3069smp_fetch_sc_gpc_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3070{
3071 struct stkctr tmpstkctr;
3072 struct stkctr *stkctr;
3073 unsigned int idx;
3074
3075 idx = args[0].data.sint;
3076
3077 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args + 1, kw, &tmpstkctr);
3078 if (!stkctr)
3079 return 0;
3080
3081 smp->flags = SMP_F_VOL_TEST;
3082 smp->data.type = SMP_T_SINT;
3083 smp->data.u.sint = 0;
3084 if (stkctr_entry(stkctr) != NULL) {
3085 void *ptr;
3086
3087 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC_RATE, idx);
3088 if (!ptr) {
3089 if (stkctr == &tmpstkctr)
3090 stktable_release(stkctr->table, stkctr_entry(stkctr));
3091 return 0; /* parameter not stored */
3092 }
3093
3094 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3095
3096 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
3097 stkctr->table->data_arg[STKTABLE_DT_GPC_RATE].u);
3098
3099 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3100
3101 if (stkctr == &tmpstkctr)
3102 stktable_release(stkctr->table, stkctr_entry(stkctr));
3103 }
3104 return 1;
3105}
3106
Willy Tarreau7d562212016-11-25 16:10:05 +01003107/* set <smp> to the General Purpose Counter 0's event rate from the stream's
3108 * tracked frontend counters or from the src.
3109 * Supports being called as "sc[0-9]_gpc0_rate" or "src_gpc0_rate" only.
3110 * Value zero is returned if the key is new.
3111 */
3112static int
3113smp_fetch_sc_gpc0_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3114{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003115 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003116 struct stkctr *stkctr;
Emeric Brun726783d2021-06-30 19:06:43 +02003117 unsigned int period;
Willy Tarreau7d562212016-11-25 16:10:05 +01003118
Emeric Brun819fc6f2017-06-13 19:37:32 +02003119 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003120 if (!stkctr)
3121 return 0;
3122
3123 smp->flags = SMP_F_VOL_TEST;
3124 smp->data.type = SMP_T_SINT;
3125 smp->data.u.sint = 0;
3126 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003127 void *ptr;
3128
3129 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0_RATE);
Emeric Brun726783d2021-06-30 19:06:43 +02003130 if (ptr) {
3131 period = stkctr->table->data_arg[STKTABLE_DT_GPC0_RATE].u;
3132 }
3133 else {
3134 /* fallback on the gpc array */
3135 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC_RATE, 0);
3136 if (ptr)
3137 period = stkctr->table->data_arg[STKTABLE_DT_GPC_RATE].u;
3138 }
3139
Emeric Brun819fc6f2017-06-13 19:37:32 +02003140 if (!ptr) {
3141 if (stkctr == &tmpstkctr)
3142 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003143 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003144 }
3145
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003146 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003147
Emeric Brun726783d2021-06-30 19:06:43 +02003148 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp), period);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003149
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003150 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003151
3152 if (stkctr == &tmpstkctr)
3153 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003154 }
3155 return 1;
3156}
3157
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003158/* set <smp> to the General Purpose Counter 1's event rate from the stream's
3159 * tracked frontend counters or from the src.
3160 * Supports being called as "sc[0-9]_gpc1_rate" or "src_gpc1_rate" only.
3161 * Value zero is returned if the key is new.
3162 */
3163static int
3164smp_fetch_sc_gpc1_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3165{
3166 struct stkctr tmpstkctr;
3167 struct stkctr *stkctr;
Emeric Brun726783d2021-06-30 19:06:43 +02003168 unsigned int period;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003169
3170 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
3171 if (!stkctr)
3172 return 0;
3173
3174 smp->flags = SMP_F_VOL_TEST;
3175 smp->data.type = SMP_T_SINT;
3176 smp->data.u.sint = 0;
3177 if (stkctr_entry(stkctr) != NULL) {
3178 void *ptr;
3179
3180 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1_RATE);
Emeric Brun726783d2021-06-30 19:06:43 +02003181 if (ptr) {
3182 period = stkctr->table->data_arg[STKTABLE_DT_GPC1_RATE].u;
3183 }
3184 else {
3185 /* fallback on the gpc array */
3186 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC_RATE, 1);
3187 if (ptr)
3188 period = stkctr->table->data_arg[STKTABLE_DT_GPC_RATE].u;
3189 }
3190
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003191 if (!ptr) {
3192 if (stkctr == &tmpstkctr)
3193 stktable_release(stkctr->table, stkctr_entry(stkctr));
3194 return 0; /* parameter not stored */
3195 }
3196
3197 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3198
Emeric Brun726783d2021-06-30 19:06:43 +02003199 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp), period);
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003200
3201 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3202
3203 if (stkctr == &tmpstkctr)
3204 stktable_release(stkctr->table, stkctr_entry(stkctr));
3205 }
3206 return 1;
3207}
3208
Emeric Brun4d7ada82021-06-30 19:04:16 +02003209/* Increment the GPC[args(0)] value from the stream's tracked
3210 * frontend counters and return it into temp integer.
3211 * Supports being called as "sc_inc_gpc(<gpc-idx>,<sc-idx>[,<table>])"
3212 * or "src_inc_gpc(<gpc-idx>[,<table>])" only.
3213 */
3214static int
3215smp_fetch_sc_inc_gpc(const struct arg *args, struct sample *smp, const char *kw, void *private)
3216{
3217 struct stkctr tmpstkctr;
3218 struct stkctr *stkctr;
3219 unsigned int idx;
3220
3221 idx = args[0].data.sint;
3222
3223 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args + 1, kw, &tmpstkctr);
3224 if (!stkctr)
3225 return 0;
3226
3227 smp->flags = SMP_F_VOL_TEST;
3228 smp->data.type = SMP_T_SINT;
3229 smp->data.u.sint = 0;
3230
3231 if (!stkctr_entry(stkctr))
3232 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
3233
3234 if (stkctr && stkctr_entry(stkctr)) {
3235 void *ptr1,*ptr2;
3236
3237
3238 /* First, update gpc0_rate if it's tracked. Second, update its
3239 * gpc0 if tracked. Returns gpc0's value otherwise the curr_ctr.
3240 */
3241 ptr1 = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC_RATE, idx);
3242 ptr2 = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC, idx);
3243 if (ptr1 || ptr2) {
3244 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3245
3246 if (ptr1) {
3247 update_freq_ctr_period(&stktable_data_cast(ptr1, std_t_frqp),
3248 stkctr->table->data_arg[STKTABLE_DT_GPC_RATE].u, 1);
3249 smp->data.u.sint = (&stktable_data_cast(ptr1, std_t_frqp))->curr_ctr;
3250 }
3251
3252 if (ptr2)
3253 smp->data.u.sint = ++stktable_data_cast(ptr2, std_t_uint);
3254
3255 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3256
3257 /* If data was modified, we need to touch to re-schedule sync */
3258 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
3259 }
3260 else if (stkctr == &tmpstkctr)
3261 stktable_release(stkctr->table, stkctr_entry(stkctr));
3262 }
3263 return 1;
3264}
3265
Willy Tarreau7d562212016-11-25 16:10:05 +01003266/* Increment the General Purpose Counter 0 value from the stream's tracked
3267 * frontend counters and return it into temp integer.
3268 * Supports being called as "sc[0-9]_inc_gpc0" or "src_inc_gpc0" only.
3269 */
3270static int
3271smp_fetch_sc_inc_gpc0(const struct arg *args, struct sample *smp, const char *kw, void *private)
3272{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003273 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003274 struct stkctr *stkctr;
Willy Tarreau5b654ad2021-07-06 18:51:12 +02003275 unsigned int period = 0;
Willy Tarreau7d562212016-11-25 16:10:05 +01003276
Emeric Brun819fc6f2017-06-13 19:37:32 +02003277 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003278 if (!stkctr)
3279 return 0;
3280
3281 smp->flags = SMP_F_VOL_TEST;
3282 smp->data.type = SMP_T_SINT;
3283 smp->data.u.sint = 0;
3284
Emeric Brun819fc6f2017-06-13 19:37:32 +02003285 if (!stkctr_entry(stkctr))
3286 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003287
3288 if (stkctr && stkctr_entry(stkctr)) {
3289 void *ptr1,*ptr2;
3290
Emeric Brun819fc6f2017-06-13 19:37:32 +02003291
Willy Tarreau7d562212016-11-25 16:10:05 +01003292 /* First, update gpc0_rate if it's tracked. Second, update its
3293 * gpc0 if tracked. Returns gpc0's value otherwise the curr_ctr.
3294 */
3295 ptr1 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0_RATE);
Emeric Brun726783d2021-06-30 19:06:43 +02003296 if (ptr1) {
3297 period = stkctr->table->data_arg[STKTABLE_DT_GPC0_RATE].u;
3298 }
3299 else {
3300 /* fallback on the gpc array */
3301 ptr1 = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC_RATE, 0);
3302 if (ptr1)
3303 period = stkctr->table->data_arg[STKTABLE_DT_GPC_RATE].u;
3304 }
3305
Willy Tarreau7d562212016-11-25 16:10:05 +01003306 ptr2 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0);
Emeric Brun726783d2021-06-30 19:06:43 +02003307 if (!ptr2) {
3308 /* fallback on the gpc array */
3309 ptr2 = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC, 0);
3310 }
3311
Emeric Brun819fc6f2017-06-13 19:37:32 +02003312 if (ptr1 || ptr2) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003313 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Willy Tarreau7d562212016-11-25 16:10:05 +01003314
Emeric Brun819fc6f2017-06-13 19:37:32 +02003315 if (ptr1) {
Emeric Brun0e3457b2021-06-30 17:18:28 +02003316 update_freq_ctr_period(&stktable_data_cast(ptr1, std_t_frqp),
Emeric Brun726783d2021-06-30 19:06:43 +02003317 period, 1);
Emeric Brun0e3457b2021-06-30 17:18:28 +02003318 smp->data.u.sint = (&stktable_data_cast(ptr1, std_t_frqp))->curr_ctr;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003319 }
3320
3321 if (ptr2)
Emeric Brun0e3457b2021-06-30 17:18:28 +02003322 smp->data.u.sint = ++stktable_data_cast(ptr2, std_t_uint);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003323
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003324 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003325
3326 /* If data was modified, we need to touch to re-schedule sync */
3327 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
3328 }
3329 else if (stkctr == &tmpstkctr)
3330 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003331 }
3332 return 1;
3333}
3334
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003335/* Increment the General Purpose Counter 1 value from the stream's tracked
3336 * frontend counters and return it into temp integer.
3337 * Supports being called as "sc[0-9]_inc_gpc1" or "src_inc_gpc1" only.
3338 */
3339static int
3340smp_fetch_sc_inc_gpc1(const struct arg *args, struct sample *smp, const char *kw, void *private)
3341{
3342 struct stkctr tmpstkctr;
3343 struct stkctr *stkctr;
Willy Tarreau5b654ad2021-07-06 18:51:12 +02003344 unsigned int period = 0;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003345
3346 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
3347 if (!stkctr)
3348 return 0;
3349
3350 smp->flags = SMP_F_VOL_TEST;
3351 smp->data.type = SMP_T_SINT;
3352 smp->data.u.sint = 0;
3353
3354 if (!stkctr_entry(stkctr))
3355 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
3356
3357 if (stkctr && stkctr_entry(stkctr)) {
3358 void *ptr1,*ptr2;
3359
3360
3361 /* First, update gpc1_rate if it's tracked. Second, update its
3362 * gpc1 if tracked. Returns gpc1's value otherwise the curr_ctr.
3363 */
3364 ptr1 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1_RATE);
Emeric Brun726783d2021-06-30 19:06:43 +02003365 if (ptr1) {
3366 period = stkctr->table->data_arg[STKTABLE_DT_GPC1_RATE].u;
3367 }
3368 else {
3369 /* fallback on the gpc array */
3370 ptr1 = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC_RATE, 1);
3371 if (ptr1)
3372 period = stkctr->table->data_arg[STKTABLE_DT_GPC_RATE].u;
3373 }
3374
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003375 ptr2 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1);
Emeric Brun726783d2021-06-30 19:06:43 +02003376 if (!ptr2) {
3377 /* fallback on the gpc array */
3378 ptr2 = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC, 1);
3379 }
3380
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003381 if (ptr1 || ptr2) {
3382 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3383
3384 if (ptr1) {
Emeric Brun0e3457b2021-06-30 17:18:28 +02003385 update_freq_ctr_period(&stktable_data_cast(ptr1, std_t_frqp),
Emeric Brun726783d2021-06-30 19:06:43 +02003386 period, 1);
Emeric Brun0e3457b2021-06-30 17:18:28 +02003387 smp->data.u.sint = (&stktable_data_cast(ptr1, std_t_frqp))->curr_ctr;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003388 }
3389
3390 if (ptr2)
Emeric Brun0e3457b2021-06-30 17:18:28 +02003391 smp->data.u.sint = ++stktable_data_cast(ptr2, std_t_uint);
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003392
3393 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3394
3395 /* If data was modified, we need to touch to re-schedule sync */
3396 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
3397 }
3398 else if (stkctr == &tmpstkctr)
3399 stktable_release(stkctr->table, stkctr_entry(stkctr));
3400 }
3401 return 1;
3402}
3403
Emeric Brun4d7ada82021-06-30 19:04:16 +02003404/* Clear the GPC[args(0)] value from the stream's tracked
3405 * frontend counters and return its previous value into temp integer.
3406 * Supports being called as "sc_clr_gpc(<gpc-idx>,<sc-idx>[,<table>])"
3407 * or "src_clr_gpc(<gpc-idx>[,<table>])" only.
3408 */
3409static int
3410smp_fetch_sc_clr_gpc(const struct arg *args, struct sample *smp, const char *kw, void *private)
3411{
3412 struct stkctr tmpstkctr;
3413 struct stkctr *stkctr;
3414 unsigned int idx;
3415
3416 idx = args[0].data.sint;
3417
3418 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args + 1, kw, &tmpstkctr);
3419 if (!stkctr)
3420 return 0;
3421
3422 smp->flags = SMP_F_VOL_TEST;
3423 smp->data.type = SMP_T_SINT;
3424 smp->data.u.sint = 0;
3425
3426 if (!stkctr_entry(stkctr))
3427 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
3428
3429 if (stkctr && stkctr_entry(stkctr)) {
3430 void *ptr;
3431
3432 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC, idx);
3433 if (!ptr) {
3434 if (stkctr == &tmpstkctr)
3435 stktable_release(stkctr->table, stkctr_entry(stkctr));
3436 return 0; /* parameter not stored */
3437 }
3438
3439 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3440
3441 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
3442 stktable_data_cast(ptr, std_t_uint) = 0;
3443
3444 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3445
3446 /* If data was modified, we need to touch to re-schedule sync */
3447 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
3448 }
3449 return 1;
3450}
3451
Willy Tarreau7d562212016-11-25 16:10:05 +01003452/* Clear the General Purpose Counter 0 value from the stream's tracked
3453 * frontend counters and return its previous value into temp integer.
3454 * Supports being called as "sc[0-9]_clr_gpc0" or "src_clr_gpc0" only.
3455 */
3456static int
3457smp_fetch_sc_clr_gpc0(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
Emeric Brun819fc6f2017-06-13 19:37:32 +02003470 if (!stkctr_entry(stkctr))
3471 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003472
Emeric Brun819fc6f2017-06-13 19:37:32 +02003473 if (stkctr && stkctr_entry(stkctr)) {
3474 void *ptr;
3475
3476 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0);
3477 if (!ptr) {
Emeric Brun726783d2021-06-30 19:06:43 +02003478 /* fallback on the gpc array */
3479 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC, 0);
3480 }
3481
3482 if (!ptr) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003483 if (stkctr == &tmpstkctr)
3484 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003485 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003486 }
3487
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003488 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003489
Emeric Brun0e3457b2021-06-30 17:18:28 +02003490 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
3491 stktable_data_cast(ptr, std_t_uint) = 0;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003492
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003493 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003494
Willy Tarreau7d562212016-11-25 16:10:05 +01003495 /* If data was modified, we need to touch to re-schedule sync */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003496 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
Willy Tarreau7d562212016-11-25 16:10:05 +01003497 }
3498 return 1;
3499}
3500
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003501/* Clear the General Purpose Counter 1 value from the stream's tracked
3502 * frontend counters and return its previous value into temp integer.
3503 * Supports being called as "sc[0-9]_clr_gpc1" or "src_clr_gpc1" only.
3504 */
3505static int
3506smp_fetch_sc_clr_gpc1(const struct arg *args, struct sample *smp, const char *kw, void *private)
3507{
3508 struct stkctr tmpstkctr;
3509 struct stkctr *stkctr;
3510
3511 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
3512 if (!stkctr)
3513 return 0;
3514
3515 smp->flags = SMP_F_VOL_TEST;
3516 smp->data.type = SMP_T_SINT;
3517 smp->data.u.sint = 0;
3518
3519 if (!stkctr_entry(stkctr))
3520 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
3521
3522 if (stkctr && stkctr_entry(stkctr)) {
3523 void *ptr;
3524
3525 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1);
3526 if (!ptr) {
Emeric Brun726783d2021-06-30 19:06:43 +02003527 /* fallback on the gpc array */
3528 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC, 1);
3529 }
3530
3531 if (!ptr) {
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003532 if (stkctr == &tmpstkctr)
3533 stktable_release(stkctr->table, stkctr_entry(stkctr));
3534 return 0; /* parameter not stored */
3535 }
3536
3537 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3538
Emeric Brun0e3457b2021-06-30 17:18:28 +02003539 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
3540 stktable_data_cast(ptr, std_t_uint) = 0;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003541
3542 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3543
3544 /* If data was modified, we need to touch to re-schedule sync */
3545 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
3546 }
3547 return 1;
3548}
3549
Willy Tarreau7d562212016-11-25 16:10:05 +01003550/* set <smp> to the cumulated number of connections from the stream's tracked
3551 * frontend counters. Supports being called as "sc[0-9]_conn_cnt" or
3552 * "src_conn_cnt" only.
3553 */
3554static int
3555smp_fetch_sc_conn_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
3556{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003557 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003558 struct stkctr *stkctr;
3559
Emeric Brun819fc6f2017-06-13 19:37:32 +02003560 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003561 if (!stkctr)
3562 return 0;
3563
3564 smp->flags = SMP_F_VOL_TEST;
3565 smp->data.type = SMP_T_SINT;
3566 smp->data.u.sint = 0;
3567 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003568 void *ptr;
3569
3570 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_CONN_CNT);
3571 if (!ptr) {
3572 if (stkctr == &tmpstkctr)
3573 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003574 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003575 }
3576
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003577 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003578
Emeric Brun0e3457b2021-06-30 17:18:28 +02003579 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003580
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003581 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003582
3583 if (stkctr == &tmpstkctr)
3584 stktable_release(stkctr->table, stkctr_entry(stkctr));
3585
3586
Willy Tarreau7d562212016-11-25 16:10:05 +01003587 }
3588 return 1;
3589}
3590
3591/* set <smp> to the connection rate from the stream's tracked frontend
3592 * counters. Supports being called as "sc[0-9]_conn_rate" or "src_conn_rate"
3593 * only.
3594 */
3595static int
3596smp_fetch_sc_conn_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3597{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003598 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003599 struct stkctr *stkctr;
3600
Emeric Brun819fc6f2017-06-13 19:37:32 +02003601 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003602 if (!stkctr)
3603 return 0;
3604
3605 smp->flags = SMP_F_VOL_TEST;
3606 smp->data.type = SMP_T_SINT;
3607 smp->data.u.sint = 0;
3608 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003609 void *ptr;
3610
3611 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_CONN_RATE);
3612 if (!ptr) {
3613 if (stkctr == &tmpstkctr)
3614 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003615 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003616 }
3617
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003618 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003619
Emeric Brun0e3457b2021-06-30 17:18:28 +02003620 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Willy Tarreau7d562212016-11-25 16:10:05 +01003621 stkctr->table->data_arg[STKTABLE_DT_CONN_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003622
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003623 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003624
3625 if (stkctr == &tmpstkctr)
3626 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003627 }
3628 return 1;
3629}
3630
3631/* set temp integer to the number of connections from the stream's source address
3632 * in the table pointed to by expr, after updating it.
3633 * Accepts exactly 1 argument of type table.
3634 */
3635static int
3636smp_fetch_src_updt_conn_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
3637{
3638 struct connection *conn = objt_conn(smp->sess->origin);
3639 struct stksess *ts;
3640 struct stktable_key *key;
3641 void *ptr;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003642 struct stktable *t;
Willy Tarreau7d562212016-11-25 16:10:05 +01003643
3644 if (!conn)
3645 return 0;
3646
Joseph Herlant5662fa42018-11-15 13:43:28 -08003647 /* Fetch source address in a sample. */
Amaury Denoyellec460c702021-05-12 10:17:47 +02003648 if (!smp_fetch_src || !smp_fetch_src(empty_arg_list, smp, "src", NULL))
Willy Tarreau7d562212016-11-25 16:10:05 +01003649 return 0;
3650
3651 /* Converts into key. */
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003652 key = smp_to_stkey(smp, args->data.t);
Willy Tarreau7d562212016-11-25 16:10:05 +01003653 if (!key)
3654 return 0;
3655
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003656 t = args->data.t;
Willy Tarreau7d562212016-11-25 16:10:05 +01003657
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003658 if ((ts = stktable_get_entry(t, key)) == NULL)
Willy Tarreau7d562212016-11-25 16:10:05 +01003659 /* entry does not exist and could not be created */
3660 return 0;
3661
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003662 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_CONN_CNT);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003663 if (!ptr) {
Willy Tarreau7d562212016-11-25 16:10:05 +01003664 return 0; /* parameter not stored in this table */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003665 }
Willy Tarreau7d562212016-11-25 16:10:05 +01003666
3667 smp->data.type = SMP_T_SINT;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003668
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003669 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003670
Emeric Brun0e3457b2021-06-30 17:18:28 +02003671 smp->data.u.sint = ++stktable_data_cast(ptr, std_t_uint);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003672
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003673 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003674
Willy Tarreau7d562212016-11-25 16:10:05 +01003675 smp->flags = SMP_F_VOL_TEST;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003676
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003677 stktable_touch_local(t, ts, 1);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003678
3679 /* Touch was previously performed by stktable_update_key */
Willy Tarreau7d562212016-11-25 16:10:05 +01003680 return 1;
3681}
3682
3683/* set <smp> to the number of concurrent connections from the stream's tracked
3684 * frontend counters. Supports being called as "sc[0-9]_conn_cur" or
3685 * "src_conn_cur" only.
3686 */
3687static int
3688smp_fetch_sc_conn_cur(const struct arg *args, struct sample *smp, const char *kw, void *private)
3689{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003690 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003691 struct stkctr *stkctr;
3692
Emeric Brun819fc6f2017-06-13 19:37:32 +02003693 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003694 if (!stkctr)
3695 return 0;
3696
3697 smp->flags = SMP_F_VOL_TEST;
3698 smp->data.type = SMP_T_SINT;
3699 smp->data.u.sint = 0;
3700 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003701 void *ptr;
3702
3703 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_CONN_CUR);
3704 if (!ptr) {
3705 if (stkctr == &tmpstkctr)
3706 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003707 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003708 }
3709
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003710 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003711
Emeric Brun0e3457b2021-06-30 17:18:28 +02003712 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003713
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003714 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003715
3716 if (stkctr == &tmpstkctr)
3717 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003718 }
3719 return 1;
3720}
3721
3722/* set <smp> to the cumulated number of streams from the stream's tracked
3723 * frontend counters. Supports being called as "sc[0-9]_sess_cnt" or
3724 * "src_sess_cnt" only.
3725 */
3726static int
3727smp_fetch_sc_sess_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
3728{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003729 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003730 struct stkctr *stkctr;
3731
Emeric Brun819fc6f2017-06-13 19:37:32 +02003732 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003733 if (!stkctr)
3734 return 0;
3735
3736 smp->flags = SMP_F_VOL_TEST;
3737 smp->data.type = SMP_T_SINT;
3738 smp->data.u.sint = 0;
3739 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003740 void *ptr;
3741
3742 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_SESS_CNT);
3743 if (!ptr) {
3744 if (stkctr == &tmpstkctr)
3745 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003746 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003747 }
3748
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003749 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003750
Emeric Brun0e3457b2021-06-30 17:18:28 +02003751 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003752
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003753 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003754
3755 if (stkctr == &tmpstkctr)
3756 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003757 }
3758 return 1;
3759}
3760
3761/* set <smp> to the stream rate from the stream's tracked frontend counters.
3762 * Supports being called as "sc[0-9]_sess_rate" or "src_sess_rate" only.
3763 */
3764static int
3765smp_fetch_sc_sess_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3766{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003767 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003768 struct stkctr *stkctr;
3769
Emeric Brun819fc6f2017-06-13 19:37:32 +02003770 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003771 if (!stkctr)
3772 return 0;
3773
3774 smp->flags = SMP_F_VOL_TEST;
3775 smp->data.type = SMP_T_SINT;
3776 smp->data.u.sint = 0;
3777 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003778 void *ptr;
3779
3780 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_SESS_RATE);
3781 if (!ptr) {
3782 if (stkctr == &tmpstkctr)
3783 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003784 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003785 }
3786
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003787 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003788
Emeric Brun0e3457b2021-06-30 17:18:28 +02003789 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Willy Tarreau7d562212016-11-25 16:10:05 +01003790 stkctr->table->data_arg[STKTABLE_DT_SESS_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003791
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003792 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003793
3794 if (stkctr == &tmpstkctr)
3795 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003796 }
3797 return 1;
3798}
3799
3800/* set <smp> to the cumulated number of HTTP requests from the stream's tracked
3801 * frontend counters. Supports being called as "sc[0-9]_http_req_cnt" or
3802 * "src_http_req_cnt" only.
3803 */
3804static int
3805smp_fetch_sc_http_req_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
3806{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003807 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003808 struct stkctr *stkctr;
3809
Emeric Brun819fc6f2017-06-13 19:37:32 +02003810 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003811 if (!stkctr)
3812 return 0;
3813
3814 smp->flags = SMP_F_VOL_TEST;
3815 smp->data.type = SMP_T_SINT;
3816 smp->data.u.sint = 0;
3817 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003818 void *ptr;
3819
3820 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_REQ_CNT);
3821 if (!ptr) {
3822 if (stkctr == &tmpstkctr)
3823 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003824 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003825 }
3826
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003827 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003828
Emeric Brun0e3457b2021-06-30 17:18:28 +02003829 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003830
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003831 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003832
3833 if (stkctr == &tmpstkctr)
3834 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003835 }
3836 return 1;
3837}
3838
3839/* set <smp> to the HTTP request rate from the stream's tracked frontend
3840 * counters. Supports being called as "sc[0-9]_http_req_rate" or
3841 * "src_http_req_rate" only.
3842 */
3843static int
3844smp_fetch_sc_http_req_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3845{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003846 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003847 struct stkctr *stkctr;
3848
Emeric Brun819fc6f2017-06-13 19:37:32 +02003849 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003850 if (!stkctr)
3851 return 0;
3852
3853 smp->flags = SMP_F_VOL_TEST;
3854 smp->data.type = SMP_T_SINT;
3855 smp->data.u.sint = 0;
3856 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003857 void *ptr;
3858
3859 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_REQ_RATE);
3860 if (!ptr) {
3861 if (stkctr == &tmpstkctr)
3862 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003863 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003864 }
3865
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003866 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003867
Emeric Brun0e3457b2021-06-30 17:18:28 +02003868 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Willy Tarreau7d562212016-11-25 16:10:05 +01003869 stkctr->table->data_arg[STKTABLE_DT_HTTP_REQ_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003870
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003871 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003872
3873 if (stkctr == &tmpstkctr)
3874 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003875 }
3876 return 1;
3877}
3878
3879/* set <smp> to the cumulated number of HTTP requests errors from the stream's
3880 * tracked frontend counters. Supports being called as "sc[0-9]_http_err_cnt" or
3881 * "src_http_err_cnt" only.
3882 */
3883static int
3884smp_fetch_sc_http_err_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
3885{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003886 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003887 struct stkctr *stkctr;
3888
Emeric Brun819fc6f2017-06-13 19:37:32 +02003889 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003890 if (!stkctr)
3891 return 0;
3892
3893 smp->flags = SMP_F_VOL_TEST;
3894 smp->data.type = SMP_T_SINT;
3895 smp->data.u.sint = 0;
3896 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003897 void *ptr;
3898
3899 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_ERR_CNT);
3900 if (!ptr) {
3901 if (stkctr == &tmpstkctr)
3902 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003903 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003904 }
3905
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003906 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003907
Emeric Brun0e3457b2021-06-30 17:18:28 +02003908 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003909
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003910 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003911
3912 if (stkctr == &tmpstkctr)
3913 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003914 }
3915 return 1;
3916}
3917
3918/* set <smp> to the HTTP request error rate from the stream's tracked frontend
3919 * counters. Supports being called as "sc[0-9]_http_err_rate" or
3920 * "src_http_err_rate" only.
3921 */
3922static int
3923smp_fetch_sc_http_err_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3924{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003925 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003926 struct stkctr *stkctr;
3927
Emeric Brun819fc6f2017-06-13 19:37:32 +02003928 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003929 if (!stkctr)
3930 return 0;
3931
3932 smp->flags = SMP_F_VOL_TEST;
3933 smp->data.type = SMP_T_SINT;
3934 smp->data.u.sint = 0;
3935 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003936 void *ptr;
3937
3938 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_ERR_RATE);
3939 if (!ptr) {
3940 if (stkctr == &tmpstkctr)
3941 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003942 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003943 }
3944
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003945 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003946
Emeric Brun0e3457b2021-06-30 17:18:28 +02003947 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Willy Tarreau7d562212016-11-25 16:10:05 +01003948 stkctr->table->data_arg[STKTABLE_DT_HTTP_ERR_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003949
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003950 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003951
3952 if (stkctr == &tmpstkctr)
3953 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003954 }
3955 return 1;
3956}
3957
Willy Tarreau826f3ab2021-02-10 12:07:15 +01003958/* set <smp> to the cumulated number of HTTP response failures from the stream's
3959 * tracked frontend counters. Supports being called as "sc[0-9]_http_fail_cnt" or
3960 * "src_http_fail_cnt" only.
3961 */
3962static int
3963smp_fetch_sc_http_fail_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
3964{
3965 struct stkctr tmpstkctr;
3966 struct stkctr *stkctr;
3967
3968 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
3969 if (!stkctr)
3970 return 0;
3971
3972 smp->flags = SMP_F_VOL_TEST;
3973 smp->data.type = SMP_T_SINT;
3974 smp->data.u.sint = 0;
3975 if (stkctr_entry(stkctr) != NULL) {
3976 void *ptr;
3977
3978 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_FAIL_CNT);
3979 if (!ptr) {
3980 if (stkctr == &tmpstkctr)
3981 stktable_release(stkctr->table, stkctr_entry(stkctr));
3982 return 0; /* parameter not stored */
3983 }
3984
3985 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3986
Emeric Brun0e3457b2021-06-30 17:18:28 +02003987 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Willy Tarreau826f3ab2021-02-10 12:07:15 +01003988
3989 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3990
3991 if (stkctr == &tmpstkctr)
3992 stktable_release(stkctr->table, stkctr_entry(stkctr));
3993 }
3994 return 1;
3995}
3996
3997/* set <smp> to the HTTP response failure rate from the stream's tracked frontend
3998 * counters. Supports being called as "sc[0-9]_http_fail_rate" or
3999 * "src_http_fail_rate" only.
4000 */
4001static int
4002smp_fetch_sc_http_fail_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
4003{
4004 struct stkctr tmpstkctr;
4005 struct stkctr *stkctr;
4006
4007 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
4008 if (!stkctr)
4009 return 0;
4010
4011 smp->flags = SMP_F_VOL_TEST;
4012 smp->data.type = SMP_T_SINT;
4013 smp->data.u.sint = 0;
4014 if (stkctr_entry(stkctr) != NULL) {
4015 void *ptr;
4016
4017 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_FAIL_RATE);
4018 if (!ptr) {
4019 if (stkctr == &tmpstkctr)
4020 stktable_release(stkctr->table, stkctr_entry(stkctr));
4021 return 0; /* parameter not stored */
4022 }
4023
4024 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
4025
Emeric Brun0e3457b2021-06-30 17:18:28 +02004026 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Willy Tarreau826f3ab2021-02-10 12:07:15 +01004027 stkctr->table->data_arg[STKTABLE_DT_HTTP_FAIL_RATE].u);
4028
4029 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
4030
4031 if (stkctr == &tmpstkctr)
4032 stktable_release(stkctr->table, stkctr_entry(stkctr));
4033 }
4034 return 1;
4035}
4036
Willy Tarreau7d562212016-11-25 16:10:05 +01004037/* set <smp> to the number of kbytes received from clients, as found in the
4038 * stream's tracked frontend counters. Supports being called as
4039 * "sc[0-9]_kbytes_in" or "src_kbytes_in" only.
4040 */
4041static int
4042smp_fetch_sc_kbytes_in(const struct arg *args, struct sample *smp, const char *kw, void *private)
4043{
Emeric Brun819fc6f2017-06-13 19:37:32 +02004044 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01004045 struct stkctr *stkctr;
4046
Emeric Brun819fc6f2017-06-13 19:37:32 +02004047 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01004048 if (!stkctr)
4049 return 0;
4050
4051 smp->flags = SMP_F_VOL_TEST;
4052 smp->data.type = SMP_T_SINT;
4053 smp->data.u.sint = 0;
4054 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02004055 void *ptr;
4056
4057 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_IN_CNT);
4058 if (!ptr) {
4059 if (stkctr == &tmpstkctr)
4060 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004061 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02004062 }
4063
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004064 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004065
Emeric Brun0e3457b2021-06-30 17:18:28 +02004066 smp->data.u.sint = stktable_data_cast(ptr, std_t_ull) >> 10;
Emeric Brun819fc6f2017-06-13 19:37:32 +02004067
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004068 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004069
4070 if (stkctr == &tmpstkctr)
4071 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004072 }
4073 return 1;
4074}
4075
4076/* set <smp> to the data rate received from clients in bytes/s, as found
4077 * in the stream's tracked frontend counters. Supports being called as
4078 * "sc[0-9]_bytes_in_rate" or "src_bytes_in_rate" only.
4079 */
4080static int
4081smp_fetch_sc_bytes_in_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
4082{
Emeric Brun819fc6f2017-06-13 19:37:32 +02004083 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01004084 struct stkctr *stkctr;
4085
Emeric Brun819fc6f2017-06-13 19:37:32 +02004086 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01004087 if (!stkctr)
4088 return 0;
4089
4090 smp->flags = SMP_F_VOL_TEST;
4091 smp->data.type = SMP_T_SINT;
4092 smp->data.u.sint = 0;
4093 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02004094 void *ptr;
4095
4096 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_IN_RATE);
4097 if (!ptr) {
4098 if (stkctr == &tmpstkctr)
4099 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004100 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02004101 }
4102
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004103 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004104
Emeric Brun0e3457b2021-06-30 17:18:28 +02004105 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Willy Tarreau7d562212016-11-25 16:10:05 +01004106 stkctr->table->data_arg[STKTABLE_DT_BYTES_IN_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004107
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004108 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004109
4110 if (stkctr == &tmpstkctr)
4111 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004112 }
4113 return 1;
4114}
4115
4116/* set <smp> to the number of kbytes sent to clients, as found in the
4117 * stream's tracked frontend counters. Supports being called as
4118 * "sc[0-9]_kbytes_out" or "src_kbytes_out" only.
4119 */
4120static int
4121smp_fetch_sc_kbytes_out(const struct arg *args, struct sample *smp, const char *kw, void *private)
4122{
Emeric Brun819fc6f2017-06-13 19:37:32 +02004123 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01004124 struct stkctr *stkctr;
4125
Emeric Brun819fc6f2017-06-13 19:37:32 +02004126 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01004127 if (!stkctr)
4128 return 0;
4129
4130 smp->flags = SMP_F_VOL_TEST;
4131 smp->data.type = SMP_T_SINT;
4132 smp->data.u.sint = 0;
4133 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02004134 void *ptr;
4135
4136 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_OUT_CNT);
4137 if (!ptr) {
4138 if (stkctr == &tmpstkctr)
4139 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004140 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02004141 }
4142
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004143 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004144
Emeric Brun0e3457b2021-06-30 17:18:28 +02004145 smp->data.u.sint = stktable_data_cast(ptr, std_t_ull) >> 10;
Emeric Brun819fc6f2017-06-13 19:37:32 +02004146
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004147 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004148
4149 if (stkctr == &tmpstkctr)
4150 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004151 }
4152 return 1;
4153}
4154
4155/* set <smp> to the data rate sent to clients in bytes/s, as found in the
4156 * stream's tracked frontend counters. Supports being called as
4157 * "sc[0-9]_bytes_out_rate" or "src_bytes_out_rate" only.
4158 */
4159static int
4160smp_fetch_sc_bytes_out_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
4161{
Emeric Brun819fc6f2017-06-13 19:37:32 +02004162 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01004163 struct stkctr *stkctr;
4164
Emeric Brun819fc6f2017-06-13 19:37:32 +02004165 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01004166 if (!stkctr)
4167 return 0;
4168
4169 smp->flags = SMP_F_VOL_TEST;
4170 smp->data.type = SMP_T_SINT;
4171 smp->data.u.sint = 0;
4172 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02004173 void *ptr;
4174
4175 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_OUT_RATE);
4176 if (!ptr) {
4177 if (stkctr == &tmpstkctr)
4178 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004179 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02004180 }
4181
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004182 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004183
Emeric Brun0e3457b2021-06-30 17:18:28 +02004184 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Willy Tarreau7d562212016-11-25 16:10:05 +01004185 stkctr->table->data_arg[STKTABLE_DT_BYTES_OUT_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004186
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004187 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004188
4189 if (stkctr == &tmpstkctr)
4190 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004191 }
4192 return 1;
4193}
4194
4195/* set <smp> to the number of active trackers on the SC entry in the stream's
4196 * tracked frontend counters. Supports being called as "sc[0-9]_trackers" only.
4197 */
4198static int
4199smp_fetch_sc_trackers(const struct arg *args, struct sample *smp, const char *kw, void *private)
4200{
Emeric Brun819fc6f2017-06-13 19:37:32 +02004201 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01004202 struct stkctr *stkctr;
4203
Emeric Brun819fc6f2017-06-13 19:37:32 +02004204 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01004205 if (!stkctr)
4206 return 0;
4207
4208 smp->flags = SMP_F_VOL_TEST;
4209 smp->data.type = SMP_T_SINT;
Emeric Brun819fc6f2017-06-13 19:37:32 +02004210 if (stkctr == &tmpstkctr) {
4211 smp->data.u.sint = stkctr_entry(stkctr) ? (stkctr_entry(stkctr)->ref_cnt-1) : 0;
4212 stktable_release(stkctr->table, stkctr_entry(stkctr));
4213 }
4214 else {
4215 smp->data.u.sint = stkctr_entry(stkctr) ? stkctr_entry(stkctr)->ref_cnt : 0;
4216 }
4217
Willy Tarreau7d562212016-11-25 16:10:05 +01004218 return 1;
4219}
4220
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004221
4222/* The functions below are used to manipulate table contents from the CLI.
4223 * There are 3 main actions, "clear", "set" and "show". The code is shared
4224 * between all actions, and the action is encoded in the void *private in
4225 * the appctx as well as in the keyword registration, among one of the
4226 * following values.
4227 */
4228
4229enum {
4230 STK_CLI_ACT_CLR,
4231 STK_CLI_ACT_SET,
4232 STK_CLI_ACT_SHOW,
4233};
4234
4235/* Dump the status of a table to a stream interface's
4236 * read buffer. It returns 0 if the output buffer is full
4237 * and needs to be called again, otherwise non-zero.
4238 */
Willy Tarreau83061a82018-07-13 11:56:34 +02004239static int table_dump_head_to_buffer(struct buffer *msg,
4240 struct stream_interface *si,
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004241 struct stktable *t, struct stktable *target)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004242{
4243 struct stream *s = si_strm(si);
4244
4245 chunk_appendf(msg, "# table: %s, type: %s, size:%d, used:%d\n",
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004246 t->id, stktable_types[t->type].kw, t->size, t->current);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004247
4248 /* any other information should be dumped here */
4249
William Lallemand07a62f72017-05-24 00:57:40 +02004250 if (target && (strm_li(s)->bind_conf->level & ACCESS_LVL_MASK) < ACCESS_LVL_OPER)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004251 chunk_appendf(msg, "# contents not dumped due to insufficient privileges\n");
4252
Willy Tarreau06d80a92017-10-19 14:32:15 +02004253 if (ci_putchk(si_ic(si), msg) == -1) {
Willy Tarreaudb398432018-11-15 11:08:52 +01004254 si_rx_room_blk(si);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004255 return 0;
4256 }
4257
4258 return 1;
4259}
4260
4261/* Dump a table entry to a stream interface's
4262 * read buffer. It returns 0 if the output buffer is full
4263 * and needs to be called again, otherwise non-zero.
4264 */
Willy Tarreau83061a82018-07-13 11:56:34 +02004265static int table_dump_entry_to_buffer(struct buffer *msg,
4266 struct stream_interface *si,
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004267 struct stktable *t, struct stksess *entry)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004268{
4269 int dt;
4270
4271 chunk_appendf(msg, "%p:", entry);
4272
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004273 if (t->type == SMP_T_IPV4) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004274 char addr[INET_ADDRSTRLEN];
4275 inet_ntop(AF_INET, (const void *)&entry->key.key, addr, sizeof(addr));
4276 chunk_appendf(msg, " key=%s", addr);
4277 }
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004278 else if (t->type == SMP_T_IPV6) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004279 char addr[INET6_ADDRSTRLEN];
4280 inet_ntop(AF_INET6, (const void *)&entry->key.key, addr, sizeof(addr));
4281 chunk_appendf(msg, " key=%s", addr);
4282 }
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004283 else if (t->type == SMP_T_SINT) {
Willy Tarreau6cde5d82020-02-25 09:41:22 +01004284 chunk_appendf(msg, " key=%u", read_u32(entry->key.key));
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004285 }
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004286 else if (t->type == SMP_T_STR) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004287 chunk_appendf(msg, " key=");
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004288 dump_text(msg, (const char *)entry->key.key, t->key_size);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004289 }
4290 else {
4291 chunk_appendf(msg, " key=");
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004292 dump_binary(msg, (const char *)entry->key.key, t->key_size);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004293 }
4294
4295 chunk_appendf(msg, " use=%d exp=%d", entry->ref_cnt - 1, tick_remain(now_ms, entry->expire));
4296
4297 for (dt = 0; dt < STKTABLE_DATA_TYPES; dt++) {
4298 void *ptr;
4299
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004300 if (t->data_ofs[dt] == 0)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004301 continue;
Emeric Brunc64a2a32021-06-30 18:01:02 +02004302 if (stktable_data_types[dt].is_array) {
4303 char tmp[16] = {};
4304 const char *name_pfx = stktable_data_types[dt].name;
4305 const char *name_sfx = NULL;
4306 unsigned int idx = 0;
4307 int i = 0;
4308
4309 /* split name to show index before first _ of the name
4310 * for example: 'gpc3_rate' if array name is 'gpc_rate'.
4311 */
4312 for (i = 0 ; i < (sizeof(tmp) - 1); i++) {
4313 if (!name_pfx[i])
4314 break;
4315 if (name_pfx[i] == '_') {
4316 name_pfx = &tmp[0];
4317 name_sfx = &stktable_data_types[dt].name[i];
4318 break;
4319 }
4320 tmp[i] = name_pfx[i];
4321 }
4322
4323 ptr = stktable_data_ptr_idx(t, entry, dt, idx);
4324 while (ptr) {
4325 if (stktable_data_types[dt].arg_type == ARG_T_DELAY)
4326 chunk_appendf(msg, " %s%u%s(%u)=", name_pfx, idx, name_sfx ? name_sfx : "", t->data_arg[dt].u);
4327 else
4328 chunk_appendf(msg, " %s%u%s=", name_pfx, idx, name_sfx ? name_sfx : "");
4329 switch (stktable_data_types[dt].std_type) {
4330 case STD_T_SINT:
4331 chunk_appendf(msg, "%d", stktable_data_cast(ptr, std_t_sint));
4332 break;
4333 case STD_T_UINT:
4334 chunk_appendf(msg, "%u", stktable_data_cast(ptr, std_t_uint));
4335 break;
4336 case STD_T_ULL:
4337 chunk_appendf(msg, "%llu", stktable_data_cast(ptr, std_t_ull));
4338 break;
4339 case STD_T_FRQP:
4340 chunk_appendf(msg, "%u",
4341 read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
4342 t->data_arg[dt].u));
4343 break;
4344 }
4345 ptr = stktable_data_ptr_idx(t, entry, dt, ++idx);
4346 }
4347 continue;
4348 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004349 if (stktable_data_types[dt].arg_type == ARG_T_DELAY)
Emeric Brun01928ae2021-06-30 16:24:04 +02004350 chunk_appendf(msg, " %s(%u)=", stktable_data_types[dt].name, t->data_arg[dt].u);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004351 else
4352 chunk_appendf(msg, " %s=", stktable_data_types[dt].name);
4353
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004354 ptr = stktable_data_ptr(t, entry, dt);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004355 switch (stktable_data_types[dt].std_type) {
4356 case STD_T_SINT:
4357 chunk_appendf(msg, "%d", stktable_data_cast(ptr, std_t_sint));
4358 break;
4359 case STD_T_UINT:
4360 chunk_appendf(msg, "%u", stktable_data_cast(ptr, std_t_uint));
4361 break;
4362 case STD_T_ULL:
Emeric Brun01928ae2021-06-30 16:24:04 +02004363 chunk_appendf(msg, "%llu", stktable_data_cast(ptr, std_t_ull));
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004364 break;
4365 case STD_T_FRQP:
Emeric Brun01928ae2021-06-30 16:24:04 +02004366 chunk_appendf(msg, "%u",
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004367 read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004368 t->data_arg[dt].u));
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004369 break;
Frédéric Lécaille16b4f542019-05-23 12:15:04 +02004370 case STD_T_DICT: {
4371 struct dict_entry *de;
4372 de = stktable_data_cast(ptr, std_t_dict);
4373 chunk_appendf(msg, "%s", de ? (char *)de->value.key : "-");
4374 break;
4375 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004376 }
4377 }
4378 chunk_appendf(msg, "\n");
4379
Willy Tarreau06d80a92017-10-19 14:32:15 +02004380 if (ci_putchk(si_ic(si), msg) == -1) {
Willy Tarreaudb398432018-11-15 11:08:52 +01004381 si_rx_room_blk(si);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004382 return 0;
4383 }
4384
4385 return 1;
4386}
4387
4388
4389/* Processes a single table entry matching a specific key passed in argument.
4390 * returns 0 if wants to be called again, 1 if has ended processing.
4391 */
4392static int table_process_entry_per_key(struct appctx *appctx, char **args)
4393{
4394 struct stream_interface *si = appctx->owner;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004395 struct stktable *t = appctx->ctx.table.target;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004396 struct stksess *ts;
4397 uint32_t uint32_key;
4398 unsigned char ip6_key[sizeof(struct in6_addr)];
4399 long long value;
4400 int data_type;
4401 int cur_arg;
4402 void *ptr;
Willy Tarreaufa1258f2021-04-10 23:00:53 +02004403 struct freq_ctr *frqp;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004404
Willy Tarreau9d008692019-08-09 11:21:01 +02004405 if (!*args[4])
4406 return cli_err(appctx, "Key value expected\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004407
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004408 switch (t->type) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004409 case SMP_T_IPV4:
4410 uint32_key = htonl(inetaddr_host(args[4]));
Christopher Fauletca20d022017-08-29 15:30:31 +02004411 static_table_key.key = &uint32_key;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004412 break;
4413 case SMP_T_IPV6:
4414 inet_pton(AF_INET6, args[4], ip6_key);
Christopher Fauletca20d022017-08-29 15:30:31 +02004415 static_table_key.key = &ip6_key;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004416 break;
4417 case SMP_T_SINT:
4418 {
4419 char *endptr;
4420 unsigned long val;
4421 errno = 0;
4422 val = strtoul(args[4], &endptr, 10);
4423 if ((errno == ERANGE && val == ULONG_MAX) ||
4424 (errno != 0 && val == 0) || endptr == args[4] ||
Willy Tarreau9d008692019-08-09 11:21:01 +02004425 val > 0xffffffff)
4426 return cli_err(appctx, "Invalid key\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004427 uint32_key = (uint32_t) val;
Christopher Fauletca20d022017-08-29 15:30:31 +02004428 static_table_key.key = &uint32_key;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004429 break;
4430 }
4431 break;
4432 case SMP_T_STR:
Christopher Fauletca20d022017-08-29 15:30:31 +02004433 static_table_key.key = args[4];
4434 static_table_key.key_len = strlen(args[4]);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004435 break;
4436 default:
Willy Tarreaua24bc782016-12-14 15:50:35 +01004437 switch (appctx->ctx.table.action) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004438 case STK_CLI_ACT_SHOW:
Willy Tarreau9d008692019-08-09 11:21:01 +02004439 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 +01004440 case STK_CLI_ACT_CLR:
Willy Tarreau9d008692019-08-09 11:21:01 +02004441 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 +01004442 case STK_CLI_ACT_SET:
Willy Tarreau9d008692019-08-09 11:21:01 +02004443 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 +01004444 default:
Willy Tarreau9d008692019-08-09 11:21:01 +02004445 return cli_err(appctx, "Unknown action\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004446 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004447 }
4448
4449 /* check permissions */
4450 if (!cli_has_level(appctx, ACCESS_LVL_OPER))
4451 return 1;
4452
Willy Tarreaua24bc782016-12-14 15:50:35 +01004453 switch (appctx->ctx.table.action) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004454 case STK_CLI_ACT_SHOW:
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004455 ts = stktable_lookup_key(t, &static_table_key);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004456 if (!ts)
4457 return 1;
4458 chunk_reset(&trash);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004459 if (!table_dump_head_to_buffer(&trash, si, t, t)) {
4460 stktable_release(t, ts);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004461 return 0;
Emeric Brun819fc6f2017-06-13 19:37:32 +02004462 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004463 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004464 if (!table_dump_entry_to_buffer(&trash, si, t, ts)) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004465 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004466 stktable_release(t, ts);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004467 return 0;
Emeric Brun819fc6f2017-06-13 19:37:32 +02004468 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004469 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004470 stktable_release(t, ts);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004471 break;
4472
4473 case STK_CLI_ACT_CLR:
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004474 ts = stktable_lookup_key(t, &static_table_key);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004475 if (!ts)
4476 return 1;
Emeric Brun819fc6f2017-06-13 19:37:32 +02004477
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004478 if (!stksess_kill(t, ts, 1)) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004479 /* don't delete an entry which is currently referenced */
Willy Tarreau9d008692019-08-09 11:21:01 +02004480 return cli_err(appctx, "Entry currently in use, cannot remove\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004481 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004482 break;
4483
4484 case STK_CLI_ACT_SET:
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004485 ts = stktable_get_entry(t, &static_table_key);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004486 if (!ts) {
4487 /* don't delete an entry which is currently referenced */
Willy Tarreau9d008692019-08-09 11:21:01 +02004488 return cli_err(appctx, "Unable to allocate a new entry\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004489 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004490 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004491 for (cur_arg = 5; *args[cur_arg]; cur_arg += 2) {
4492 if (strncmp(args[cur_arg], "data.", 5) != 0) {
Willy Tarreau9d008692019-08-09 11:21:01 +02004493 cli_err(appctx, "\"data.<type>\" followed by a value expected\n");
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004494 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004495 stktable_touch_local(t, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004496 return 1;
4497 }
4498
4499 data_type = stktable_get_data_type(args[cur_arg] + 5);
4500 if (data_type < 0) {
Willy Tarreau9d008692019-08-09 11:21:01 +02004501 cli_err(appctx, "Unknown data type\n");
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004502 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004503 stktable_touch_local(t, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004504 return 1;
4505 }
4506
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004507 if (!t->data_ofs[data_type]) {
Willy Tarreau9d008692019-08-09 11:21:01 +02004508 cli_err(appctx, "Data type not stored in this table\n");
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004509 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004510 stktable_touch_local(t, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004511 return 1;
4512 }
4513
4514 if (!*args[cur_arg+1] || strl2llrc(args[cur_arg+1], strlen(args[cur_arg+1]), &value) != 0) {
Willy Tarreau9d008692019-08-09 11:21:01 +02004515 cli_err(appctx, "Require a valid integer value to store\n");
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004516 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004517 stktable_touch_local(t, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004518 return 1;
4519 }
4520
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004521 ptr = stktable_data_ptr(t, ts, data_type);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004522
4523 switch (stktable_data_types[data_type].std_type) {
4524 case STD_T_SINT:
4525 stktable_data_cast(ptr, std_t_sint) = value;
4526 break;
4527 case STD_T_UINT:
4528 stktable_data_cast(ptr, std_t_uint) = value;
4529 break;
4530 case STD_T_ULL:
4531 stktable_data_cast(ptr, std_t_ull) = value;
4532 break;
4533 case STD_T_FRQP:
4534 /* We set both the current and previous values. That way
4535 * the reported frequency is stable during all the period
4536 * then slowly fades out. This allows external tools to
4537 * push measures without having to update them too often.
4538 */
4539 frqp = &stktable_data_cast(ptr, std_t_frqp);
Willy Tarreaufa1258f2021-04-10 23:00:53 +02004540 /* First bit is reserved for the freq_ctr lock
Emeric Brunf2fc1fd2017-11-02 17:32:43 +01004541 Note: here we're still protected by the stksess lock
Willy Tarreaufa1258f2021-04-10 23:00:53 +02004542 so we don't need to update the update the freq_ctr
Emeric Brunf2fc1fd2017-11-02 17:32:43 +01004543 using its internal lock */
4544 frqp->curr_tick = now_ms & ~0x1;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004545 frqp->prev_ctr = 0;
4546 frqp->curr_ctr = value;
4547 break;
4548 }
4549 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004550 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004551 stktable_touch_local(t, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004552 break;
4553
4554 default:
Willy Tarreau9d008692019-08-09 11:21:01 +02004555 return cli_err(appctx, "Unknown action\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004556 }
4557 return 1;
4558}
4559
4560/* Prepares the appctx fields with the data-based filters from the command line.
4561 * Returns 0 if the dump can proceed, 1 if has ended processing.
4562 */
4563static int table_prepare_data_request(struct appctx *appctx, char **args)
4564{
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004565 int i;
Adis Nezirovicd0142e72020-01-22 16:50:27 +01004566 char *err = NULL;
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004567
Willy Tarreau9d008692019-08-09 11:21:01 +02004568 if (appctx->ctx.table.action != STK_CLI_ACT_SHOW && appctx->ctx.table.action != STK_CLI_ACT_CLR)
4569 return cli_err(appctx, "content-based lookup is only supported with the \"show\" and \"clear\" actions\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004570
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004571 for (i = 0; i < STKTABLE_FILTER_LEN; i++) {
4572 if (i > 0 && !*args[3+3*i]) // number of filter entries can be less than STKTABLE_FILTER_LEN
4573 break;
4574 /* condition on stored data value */
4575 appctx->ctx.table.data_type[i] = stktable_get_data_type(args[3+3*i] + 5);
4576 if (appctx->ctx.table.data_type[i] < 0)
Adis Nezirovicd0142e72020-01-22 16:50:27 +01004577 return cli_dynerr(appctx, memprintf(&err, "Filter entry #%i: Unknown data type\n", i + 1));
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004578
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004579 if (!((struct stktable *)appctx->ctx.table.target)->data_ofs[appctx->ctx.table.data_type[i]])
Adis Nezirovicd0142e72020-01-22 16:50:27 +01004580 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 +01004581
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004582 appctx->ctx.table.data_op[i] = get_std_op(args[4+3*i]);
Willy Tarreau2b64a352020-01-22 17:09:47 +01004583 if (appctx->ctx.table.data_op[i] < 0)
Adis Nezirovicd0142e72020-01-22 16:50:27 +01004584 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 +01004585
Adis Nezirovic56dd3542020-01-22 16:16:48 +01004586 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 +01004587 return cli_dynerr(appctx, memprintf(&err, "Filter entry #%i: Require a valid integer value to compare against\n", i + 1));
4588 }
4589
4590 if (*args[3+3*i]) {
4591 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 +01004592 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004593
4594 /* OK we're done, all the fields are set */
4595 return 0;
4596}
4597
4598/* returns 0 if wants to be called, 1 if has ended processing */
Aurélien Nephtaliabbf6072018-04-18 13:26:46 +02004599static int cli_parse_table_req(char **args, char *payload, struct appctx *appctx, void *private)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004600{
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004601 int i;
4602
4603 for (i = 0; i < STKTABLE_FILTER_LEN; i++)
4604 appctx->ctx.table.data_type[i] = -1;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004605 appctx->ctx.table.target = NULL;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004606 appctx->ctx.table.entry = NULL;
Willy Tarreaua24bc782016-12-14 15:50:35 +01004607 appctx->ctx.table.action = (long)private; // keyword argument, one of STK_CLI_ACT_*
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004608
4609 if (*args[2]) {
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004610 appctx->ctx.table.target = stktable_find_by_name(args[2]);
Willy Tarreau9d008692019-08-09 11:21:01 +02004611 if (!appctx->ctx.table.target)
4612 return cli_err(appctx, "No such table\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004613 }
4614 else {
Willy Tarreaua24bc782016-12-14 15:50:35 +01004615 if (appctx->ctx.table.action != STK_CLI_ACT_SHOW)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004616 goto err_args;
4617 return 0;
4618 }
4619
4620 if (strcmp(args[3], "key") == 0)
4621 return table_process_entry_per_key(appctx, args);
4622 else if (strncmp(args[3], "data.", 5) == 0)
4623 return table_prepare_data_request(appctx, args);
4624 else if (*args[3])
4625 goto err_args;
4626
4627 return 0;
4628
4629err_args:
Willy Tarreaua24bc782016-12-14 15:50:35 +01004630 switch (appctx->ctx.table.action) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004631 case STK_CLI_ACT_SHOW:
Willy Tarreau9d008692019-08-09 11:21:01 +02004632 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 +01004633 case STK_CLI_ACT_CLR:
Willy Tarreau9d008692019-08-09 11:21:01 +02004634 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 +01004635 case STK_CLI_ACT_SET:
Willy Tarreau9d008692019-08-09 11:21:01 +02004636 return cli_err(appctx, "Required arguments: <table> key <key> [data.<store_data_type> <value>]*\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004637 default:
Willy Tarreau9d008692019-08-09 11:21:01 +02004638 return cli_err(appctx, "Unknown action\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004639 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004640}
4641
4642/* This function is used to deal with table operations (dump or clear depending
4643 * on the action stored in appctx->private). It returns 0 if the output buffer is
4644 * full and it needs to be called again, otherwise non-zero.
4645 */
4646static int cli_io_handler_table(struct appctx *appctx)
4647{
4648 struct stream_interface *si = appctx->owner;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004649 struct stream *s = si_strm(si);
4650 struct ebmb_node *eb;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004651 int skip_entry;
Willy Tarreaua24bc782016-12-14 15:50:35 +01004652 int show = appctx->ctx.table.action == STK_CLI_ACT_SHOW;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004653
4654 /*
4655 * We have 3 possible states in appctx->st2 :
4656 * - STAT_ST_INIT : the first call
4657 * - STAT_ST_INFO : the proxy pointer points to the next table to
4658 * dump, the entry pointer is NULL ;
4659 * - STAT_ST_LIST : the proxy pointer points to the current table
4660 * and the entry pointer points to the next entry to be dumped,
4661 * and the refcount on the next entry is held ;
4662 * - STAT_ST_END : nothing left to dump, the buffer may contain some
4663 * data though.
4664 */
4665
4666 if (unlikely(si_ic(si)->flags & (CF_WRITE_ERROR|CF_SHUTW))) {
4667 /* in case of abort, remove any refcount we might have set on an entry */
4668 if (appctx->st2 == STAT_ST_LIST) {
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004669 stksess_kill_if_expired(appctx->ctx.table.t, appctx->ctx.table.entry, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004670 }
4671 return 1;
4672 }
4673
4674 chunk_reset(&trash);
4675
4676 while (appctx->st2 != STAT_ST_FIN) {
4677 switch (appctx->st2) {
4678 case STAT_ST_INIT:
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004679 appctx->ctx.table.t = appctx->ctx.table.target;
4680 if (!appctx->ctx.table.t)
4681 appctx->ctx.table.t = stktables_list;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004682
4683 appctx->ctx.table.entry = NULL;
4684 appctx->st2 = STAT_ST_INFO;
4685 break;
4686
4687 case STAT_ST_INFO:
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004688 if (!appctx->ctx.table.t ||
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004689 (appctx->ctx.table.target &&
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004690 appctx->ctx.table.t != appctx->ctx.table.target)) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004691 appctx->st2 = STAT_ST_END;
4692 break;
4693 }
4694
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004695 if (appctx->ctx.table.t->size) {
4696 if (show && !table_dump_head_to_buffer(&trash, si, appctx->ctx.table.t, appctx->ctx.table.target))
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004697 return 0;
4698
4699 if (appctx->ctx.table.target &&
William Lallemand07a62f72017-05-24 00:57:40 +02004700 (strm_li(s)->bind_conf->level & ACCESS_LVL_MASK) >= ACCESS_LVL_OPER) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004701 /* dump entries only if table explicitly requested */
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004702 HA_SPIN_LOCK(STK_TABLE_LOCK, &appctx->ctx.table.t->lock);
4703 eb = ebmb_first(&appctx->ctx.table.t->keys);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004704 if (eb) {
4705 appctx->ctx.table.entry = ebmb_entry(eb, struct stksess, key);
4706 appctx->ctx.table.entry->ref_cnt++;
4707 appctx->st2 = STAT_ST_LIST;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004708 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &appctx->ctx.table.t->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004709 break;
4710 }
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004711 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &appctx->ctx.table.t->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004712 }
4713 }
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004714 appctx->ctx.table.t = appctx->ctx.table.t->next;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004715 break;
4716
4717 case STAT_ST_LIST:
4718 skip_entry = 0;
4719
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004720 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &appctx->ctx.table.entry->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004721
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004722 if (appctx->ctx.table.data_type[0] >= 0) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004723 /* we're filtering on some data contents */
4724 void *ptr;
Willy Tarreau2b64a352020-01-22 17:09:47 +01004725 int dt, i;
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004726 signed char op;
4727 long long data, value;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004728
Emeric Brun819fc6f2017-06-13 19:37:32 +02004729
Willy Tarreau2b64a352020-01-22 17:09:47 +01004730 for (i = 0; i < STKTABLE_FILTER_LEN; i++) {
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004731 if (appctx->ctx.table.data_type[i] == -1)
4732 break;
4733 dt = appctx->ctx.table.data_type[i];
4734 ptr = stktable_data_ptr(appctx->ctx.table.t,
4735 appctx->ctx.table.entry,
4736 dt);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004737
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004738 data = 0;
4739 switch (stktable_data_types[dt].std_type) {
4740 case STD_T_SINT:
4741 data = stktable_data_cast(ptr, std_t_sint);
4742 break;
4743 case STD_T_UINT:
4744 data = stktable_data_cast(ptr, std_t_uint);
4745 break;
4746 case STD_T_ULL:
4747 data = stktable_data_cast(ptr, std_t_ull);
4748 break;
4749 case STD_T_FRQP:
4750 data = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
4751 appctx->ctx.table.t->data_arg[dt].u);
4752 break;
4753 }
4754
4755 op = appctx->ctx.table.data_op[i];
4756 value = appctx->ctx.table.value[i];
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004757
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004758 /* skip the entry if the data does not match the test and the value */
4759 if ((data < value &&
4760 (op == STD_OP_EQ || op == STD_OP_GT || op == STD_OP_GE)) ||
4761 (data == value &&
4762 (op == STD_OP_NE || op == STD_OP_GT || op == STD_OP_LT)) ||
4763 (data > value &&
4764 (op == STD_OP_EQ || op == STD_OP_LT || op == STD_OP_LE))) {
4765 skip_entry = 1;
4766 break;
4767 }
4768 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004769 }
4770
4771 if (show && !skip_entry &&
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004772 !table_dump_entry_to_buffer(&trash, si, appctx->ctx.table.t, appctx->ctx.table.entry)) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004773 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &appctx->ctx.table.entry->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004774 return 0;
4775 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004776
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004777 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &appctx->ctx.table.entry->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004778
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004779 HA_SPIN_LOCK(STK_TABLE_LOCK, &appctx->ctx.table.t->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004780 appctx->ctx.table.entry->ref_cnt--;
4781
4782 eb = ebmb_next(&appctx->ctx.table.entry->key);
4783 if (eb) {
4784 struct stksess *old = appctx->ctx.table.entry;
4785 appctx->ctx.table.entry = ebmb_entry(eb, struct stksess, key);
4786 if (show)
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004787 __stksess_kill_if_expired(appctx->ctx.table.t, old);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004788 else if (!skip_entry && !appctx->ctx.table.entry->ref_cnt)
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004789 __stksess_kill(appctx->ctx.table.t, old);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004790 appctx->ctx.table.entry->ref_cnt++;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004791 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &appctx->ctx.table.t->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004792 break;
4793 }
4794
4795
4796 if (show)
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004797 __stksess_kill_if_expired(appctx->ctx.table.t, appctx->ctx.table.entry);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004798 else if (!skip_entry && !appctx->ctx.table.entry->ref_cnt)
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004799 __stksess_kill(appctx->ctx.table.t, appctx->ctx.table.entry);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004800
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004801 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &appctx->ctx.table.t->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004802
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004803 appctx->ctx.table.t = appctx->ctx.table.t->next;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004804 appctx->st2 = STAT_ST_INFO;
4805 break;
4806
4807 case STAT_ST_END:
4808 appctx->st2 = STAT_ST_FIN;
4809 break;
4810 }
4811 }
4812 return 1;
4813}
4814
4815static void cli_release_show_table(struct appctx *appctx)
4816{
4817 if (appctx->st2 == STAT_ST_LIST) {
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004818 stksess_kill_if_expired(appctx->ctx.table.t, appctx->ctx.table.entry, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004819 }
4820}
4821
Willy Tarreau478331d2020-08-28 11:31:31 +02004822static void stkt_late_init(void)
4823{
4824 struct sample_fetch *f;
4825
4826 f = find_sample_fetch("src", strlen("src"));
4827 if (f)
4828 smp_fetch_src = f->process;
4829}
4830
4831INITCALL0(STG_INIT, stkt_late_init);
4832
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004833/* register cli keywords */
4834static struct cli_kw_list cli_kws = {{ },{
Willy Tarreaub205bfd2021-05-07 11:38:37 +02004835 { { "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 },
4836 { { "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 },
4837 { { "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 +01004838 {{},}
4839}};
4840
Willy Tarreau0108d902018-11-25 19:14:37 +01004841INITCALL1(STG_REGISTER, cli_register_kw, &cli_kws);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004842
Thierry FOURNIER236657b2015-08-19 08:25:14 +02004843static struct action_kw_list tcp_conn_kws = { { }, {
Emeric Brun4d7ada82021-06-30 19:04:16 +02004844 { "sc-inc-gpc", parse_inc_gpc, KWF_MATCH_PREFIX },
4845 { "sc-inc-gpc0", parse_inc_gpc, KWF_MATCH_PREFIX },
4846 { "sc-inc-gpc1", parse_inc_gpc, KWF_MATCH_PREFIX },
Emeric Brun877b0b52021-06-30 18:57:49 +02004847 { "sc-set-gpt", parse_set_gpt, KWF_MATCH_PREFIX },
4848 { "sc-set-gpt0", parse_set_gpt, KWF_MATCH_PREFIX },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02004849 { /* END */ }
4850}};
4851
Willy Tarreau0108d902018-11-25 19:14:37 +01004852INITCALL1(STG_REGISTER, tcp_req_conn_keywords_register, &tcp_conn_kws);
4853
Willy Tarreau620408f2016-10-21 16:37:51 +02004854static struct action_kw_list tcp_sess_kws = { { }, {
Emeric Brun4d7ada82021-06-30 19:04:16 +02004855 { "sc-inc-gpc", parse_inc_gpc, KWF_MATCH_PREFIX },
4856 { "sc-inc-gpc0", parse_inc_gpc, KWF_MATCH_PREFIX },
4857 { "sc-inc-gpc1", parse_inc_gpc, KWF_MATCH_PREFIX },
Emeric Brun877b0b52021-06-30 18:57:49 +02004858 { "sc-set-gpt", parse_set_gpt, KWF_MATCH_PREFIX },
4859 { "sc-set-gpt0", parse_set_gpt, KWF_MATCH_PREFIX },
Willy Tarreau620408f2016-10-21 16:37:51 +02004860 { /* END */ }
4861}};
4862
Willy Tarreau0108d902018-11-25 19:14:37 +01004863INITCALL1(STG_REGISTER, tcp_req_sess_keywords_register, &tcp_sess_kws);
4864
Thierry FOURNIER236657b2015-08-19 08:25:14 +02004865static struct action_kw_list tcp_req_kws = { { }, {
Emeric Brun4d7ada82021-06-30 19:04:16 +02004866 { "sc-inc-gpc", parse_inc_gpc, KWF_MATCH_PREFIX },
4867 { "sc-inc-gpc0", parse_inc_gpc, KWF_MATCH_PREFIX },
4868 { "sc-inc-gpc1", parse_inc_gpc, KWF_MATCH_PREFIX },
Emeric Brun877b0b52021-06-30 18:57:49 +02004869 { "sc-set-gpt", parse_set_gpt, KWF_MATCH_PREFIX },
4870 { "sc-set-gpt0", parse_set_gpt, KWF_MATCH_PREFIX },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02004871 { /* END */ }
4872}};
4873
Willy Tarreau0108d902018-11-25 19:14:37 +01004874INITCALL1(STG_REGISTER, tcp_req_cont_keywords_register, &tcp_req_kws);
4875
Thierry FOURNIER236657b2015-08-19 08:25:14 +02004876static struct action_kw_list tcp_res_kws = { { }, {
Emeric Brun4d7ada82021-06-30 19:04:16 +02004877 { "sc-inc-gpc", parse_inc_gpc, KWF_MATCH_PREFIX },
4878 { "sc-inc-gpc0", parse_inc_gpc, KWF_MATCH_PREFIX },
4879 { "sc-inc-gpc1", parse_inc_gpc, KWF_MATCH_PREFIX },
Emeric Brun877b0b52021-06-30 18:57:49 +02004880 { "sc-set-gpt", parse_set_gpt, KWF_MATCH_PREFIX },
4881 { "sc-set-gpt0", parse_set_gpt, KWF_MATCH_PREFIX },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02004882 { /* END */ }
4883}};
4884
Willy Tarreau0108d902018-11-25 19:14:37 +01004885INITCALL1(STG_REGISTER, tcp_res_cont_keywords_register, &tcp_res_kws);
4886
Thierry FOURNIER236657b2015-08-19 08:25:14 +02004887static struct action_kw_list http_req_kws = { { }, {
Emeric Brun4d7ada82021-06-30 19:04:16 +02004888 { "sc-inc-gpc", parse_inc_gpc, KWF_MATCH_PREFIX },
4889 { "sc-inc-gpc0", parse_inc_gpc, KWF_MATCH_PREFIX },
4890 { "sc-inc-gpc1", parse_inc_gpc, KWF_MATCH_PREFIX },
Emeric Brun877b0b52021-06-30 18:57:49 +02004891 { "sc-set-gpt", parse_set_gpt, KWF_MATCH_PREFIX },
4892 { "sc-set-gpt0", parse_set_gpt, KWF_MATCH_PREFIX },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02004893 { /* END */ }
4894}};
4895
Willy Tarreau0108d902018-11-25 19:14:37 +01004896INITCALL1(STG_REGISTER, http_req_keywords_register, &http_req_kws);
4897
Thierry FOURNIER236657b2015-08-19 08:25:14 +02004898static struct action_kw_list http_res_kws = { { }, {
Emeric Brun4d7ada82021-06-30 19:04:16 +02004899 { "sc-inc-gpc", parse_inc_gpc, KWF_MATCH_PREFIX },
4900 { "sc-inc-gpc0", parse_inc_gpc, KWF_MATCH_PREFIX },
4901 { "sc-inc-gpc1", parse_inc_gpc, KWF_MATCH_PREFIX },
Emeric Brun877b0b52021-06-30 18:57:49 +02004902 { "sc-set-gpt", parse_set_gpt, KWF_MATCH_PREFIX },
4903 { "sc-set-gpt0", parse_set_gpt, KWF_MATCH_PREFIX },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02004904 { /* END */ }
4905}};
4906
Willy Tarreau0108d902018-11-25 19:14:37 +01004907INITCALL1(STG_REGISTER, http_res_keywords_register, &http_res_kws);
4908
Willy Tarreau7d562212016-11-25 16:10:05 +01004909/* Note: must not be declared <const> as its list will be overwritten.
4910 * Please take care of keeping this list alphabetically sorted.
4911 */
4912static struct sample_fetch_kw_list smp_fetch_keywords = {ILH, {
4913 { "sc_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4914 { "sc_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
Emeric Brun4d7ada82021-06-30 19:04:16 +02004915 { "sc_clr_gpc", smp_fetch_sc_clr_gpc, ARG3(2,SINT,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
Willy Tarreau7d562212016-11-25 16:10:05 +01004916 { "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 +01004917 { "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 +01004918 { "sc_conn_cnt", smp_fetch_sc_conn_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4919 { "sc_conn_cur", smp_fetch_sc_conn_cur, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4920 { "sc_conn_rate", smp_fetch_sc_conn_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
Emeric Brun877b0b52021-06-30 18:57:49 +02004921 { "sc_get_gpt", smp_fetch_sc_get_gpt, ARG3(2,SINT,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
Thierry FOURNIER401c64b2017-01-05 11:44:09 +01004922 { "sc_get_gpt0", smp_fetch_sc_get_gpt0, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
Emeric Brun4d7ada82021-06-30 19:04:16 +02004923 { "sc_get_gpc", smp_fetch_sc_get_gpc, ARG3(2,SINT,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
Willy Tarreau7d562212016-11-25 16:10:05 +01004924 { "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 +01004925 { "sc_get_gpc1", smp_fetch_sc_get_gpc1, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN },
Emeric Brun4d7ada82021-06-30 19:04:16 +02004926 { "sc_gpc_rate", smp_fetch_sc_gpc_rate, ARG3(2,SINT,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
Willy Tarreau7d562212016-11-25 16:10:05 +01004927 { "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 +01004928 { "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 +01004929 { "sc_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4930 { "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 +01004931 { "sc_http_fail_cnt", smp_fetch_sc_http_fail_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4932 { "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 +01004933 { "sc_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4934 { "sc_http_req_rate", smp_fetch_sc_http_req_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
Emeric Brun4d7ada82021-06-30 19:04:16 +02004935 { "sc_inc_gpc", smp_fetch_sc_inc_gpc, ARG3(2,SINT,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
Willy Tarreau7d562212016-11-25 16:10:05 +01004936 { "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 +01004937 { "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 +01004938 { "sc_kbytes_in", smp_fetch_sc_kbytes_in, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4939 { "sc_kbytes_out", smp_fetch_sc_kbytes_out, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4940 { "sc_sess_cnt", smp_fetch_sc_sess_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4941 { "sc_sess_rate", smp_fetch_sc_sess_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4942 { "sc_tracked", smp_fetch_sc_tracked, ARG2(1,SINT,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
4943 { "sc_trackers", smp_fetch_sc_trackers, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4944 { "sc0_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4945 { "sc0_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4946 { "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 +01004947 { "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 +01004948 { "sc0_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4949 { "sc0_conn_cur", smp_fetch_sc_conn_cur, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4950 { "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 +01004951 { "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 +01004952 { "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 +01004953 { "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 +01004954 { "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 +01004955 { "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 +01004956 { "sc0_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4957 { "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 +01004958 { "sc0_http_fail_cnt", smp_fetch_sc_http_fail_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4959 { "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 +01004960 { "sc0_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4961 { "sc0_http_req_rate", smp_fetch_sc_http_req_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4962 { "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 +01004963 { "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 +01004964 { "sc0_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4965 { "sc0_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4966 { "sc0_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4967 { "sc0_sess_rate", smp_fetch_sc_sess_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4968 { "sc0_tracked", smp_fetch_sc_tracked, ARG1(0,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
4969 { "sc0_trackers", smp_fetch_sc_trackers, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4970 { "sc1_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4971 { "sc1_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
Emeric Brun4d7ada82021-06-30 19:04:16 +02004972 { "sc1_clr_gpc", smp_fetch_sc_clr_gpc, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
Willy Tarreau7d562212016-11-25 16:10:05 +01004973 { "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 +01004974 { "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 +01004975 { "sc1_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4976 { "sc1_conn_cur", smp_fetch_sc_conn_cur, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4977 { "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 +01004978 { "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 +01004979 { "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 +01004980 { "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 +01004981 { "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 +01004982 { "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 +01004983 { "sc1_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4984 { "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 +01004985 { "sc1_http_fail_cnt", smp_fetch_sc_http_fail_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4986 { "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 +01004987 { "sc1_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4988 { "sc1_http_req_rate", smp_fetch_sc_http_req_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4989 { "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 +01004990 { "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 +01004991 { "sc1_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4992 { "sc1_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4993 { "sc1_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4994 { "sc1_sess_rate", smp_fetch_sc_sess_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4995 { "sc1_tracked", smp_fetch_sc_tracked, ARG1(0,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
4996 { "sc1_trackers", smp_fetch_sc_trackers, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4997 { "sc2_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4998 { "sc2_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4999 { "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 +01005000 { "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 +01005001 { "sc2_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5002 { "sc2_conn_cur", smp_fetch_sc_conn_cur, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5003 { "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 +01005004 { "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 +01005005 { "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 +01005006 { "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 +01005007 { "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 +01005008 { "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 +01005009 { "sc2_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5010 { "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 +01005011 { "sc2_http_fail_cnt", smp_fetch_sc_http_fail_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5012 { "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 +01005013 { "sc2_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5014 { "sc2_http_req_rate", smp_fetch_sc_http_req_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5015 { "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 +01005016 { "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 +01005017 { "sc2_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5018 { "sc2_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5019 { "sc2_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5020 { "sc2_sess_rate", smp_fetch_sc_sess_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5021 { "sc2_tracked", smp_fetch_sc_tracked, ARG1(0,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
5022 { "sc2_trackers", smp_fetch_sc_trackers, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5023 { "src_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5024 { "src_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
Emeric Brun4d7ada82021-06-30 19:04:16 +02005025 { "src_clr_gpc", smp_fetch_sc_clr_gpc, ARG2(2,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
Willy Tarreau7d562212016-11-25 16:10:05 +01005026 { "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 +01005027 { "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 +01005028 { "src_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5029 { "src_conn_cur", smp_fetch_sc_conn_cur, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5030 { "src_conn_rate", smp_fetch_sc_conn_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
Emeric Brun877b0b52021-06-30 18:57:49 +02005031 { "src_get_gpt" , smp_fetch_sc_get_gpt, ARG2(2,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
Thierry FOURNIER401c64b2017-01-05 11:44:09 +01005032 { "src_get_gpt0", smp_fetch_sc_get_gpt0, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
Emeric Brun4d7ada82021-06-30 19:04:16 +02005033 { "src_get_gpc", smp_fetch_sc_get_gpc, ARG2(2,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
Willy Tarreau7d562212016-11-25 16:10:05 +01005034 { "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 +01005035 { "src_get_gpc1", smp_fetch_sc_get_gpc1, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
Emeric Brun4d7ada82021-06-30 19:04:16 +02005036 { "src_gpc_rate", smp_fetch_sc_gpc_rate, ARG2(2,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
Willy Tarreau7d562212016-11-25 16:10:05 +01005037 { "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 +01005038 { "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 +01005039 { "src_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5040 { "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 +01005041 { "src_http_fail_cnt", smp_fetch_sc_http_fail_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5042 { "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 +01005043 { "src_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5044 { "src_http_req_rate", smp_fetch_sc_http_req_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
Emeric Brun4d7ada82021-06-30 19:04:16 +02005045 { "src_inc_gpc", smp_fetch_sc_inc_gpc, ARG2(2,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
Willy Tarreau7d562212016-11-25 16:10:05 +01005046 { "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 +01005047 { "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 +01005048 { "src_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5049 { "src_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5050 { "src_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5051 { "src_sess_rate", smp_fetch_sc_sess_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5052 { "src_updt_conn_cnt", smp_fetch_src_updt_conn_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5053 { "table_avl", smp_fetch_table_avl, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5054 { "table_cnt", smp_fetch_table_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5055 { /* END */ },
5056}};
5057
Willy Tarreau0108d902018-11-25 19:14:37 +01005058INITCALL1(STG_REGISTER, sample_register_fetches, &smp_fetch_keywords);
Willy Tarreau7d562212016-11-25 16:10:05 +01005059
Willy Tarreaud9f316a2014-07-10 14:03:38 +02005060/* Note: must not be declared <const> as its list will be overwritten */
5061static struct sample_conv_kw_list sample_conv_kws = {ILH, {
Willy Tarreau2d17db52016-05-25 17:16:38 +02005062 { "in_table", sample_conv_in_table, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_BOOL },
5063 { "table_bytes_in_rate", sample_conv_table_bytes_in_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5064 { "table_bytes_out_rate", sample_conv_table_bytes_out_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5065 { "table_conn_cnt", sample_conv_table_conn_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5066 { "table_conn_cur", sample_conv_table_conn_cur, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5067 { "table_conn_rate", sample_conv_table_conn_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
Emeric Brun877b0b52021-06-30 18:57:49 +02005068 { "table_gpt", sample_conv_table_gpt, ARG2(2,SINT,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
Willy Tarreau2d17db52016-05-25 17:16:38 +02005069 { "table_gpt0", sample_conv_table_gpt0, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
Emeric Brun4d7ada82021-06-30 19:04:16 +02005070 { "table_gpc", sample_conv_table_gpc, ARG2(2,SINT,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
Willy Tarreau2d17db52016-05-25 17:16:38 +02005071 { "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 +01005072 { "table_gpc1", sample_conv_table_gpc1, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
Emeric Brun4d7ada82021-06-30 19:04:16 +02005073 { "table_gpc_rate", sample_conv_table_gpc_rate, ARG2(2,SINT,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
Willy Tarreau2d17db52016-05-25 17:16:38 +02005074 { "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 +01005075 { "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 +02005076 { "table_http_err_cnt", sample_conv_table_http_err_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5077 { "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 +01005078 { "table_http_fail_cnt", sample_conv_table_http_fail_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5079 { "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 +02005080 { "table_http_req_cnt", sample_conv_table_http_req_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5081 { "table_http_req_rate", sample_conv_table_http_req_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5082 { "table_kbytes_in", sample_conv_table_kbytes_in, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5083 { "table_kbytes_out", sample_conv_table_kbytes_out, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5084 { "table_server_id", sample_conv_table_server_id, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5085 { "table_sess_cnt", sample_conv_table_sess_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5086 { "table_sess_rate", sample_conv_table_sess_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5087 { "table_trackers", sample_conv_table_trackers, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
Willy Tarreaud9f316a2014-07-10 14:03:38 +02005088 { /* END */ },
5089}};
5090
Willy Tarreau0108d902018-11-25 19:14:37 +01005091INITCALL1(STG_REGISTER, sample_register_convs, &sample_conv_kws);