blob: b1e7b59a5ef2623224a71b2e8ee21c256775cbb0 [file] [log] [blame]
Emeric Brun3bd697e2010-01-04 15:23:48 +01001/*
2 * Stick tables management functions.
3 *
4 * Copyright 2009-2010 EXCELIANCE, Emeric Brun <ebrun@exceliance.fr>
Willy Tarreau08d5f982010-06-06 13:34:54 +02005 * Copyright (C) 2010 Willy Tarreau <w@1wt.eu>
Emeric Brun3bd697e2010-01-04 15:23:48 +01006 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version
10 * 2 of the License, or (at your option) any later version.
11 *
12 */
13
14#include <string.h>
Willy Tarreauf13ebdf2016-11-22 18:00:53 +010015#include <errno.h>
Emeric Brun3bd697e2010-01-04 15:23:48 +010016
Willy Tarreaub2551052020-06-09 09:07:15 +020017#include <import/ebmbtree.h>
18#include <import/ebsttree.h>
19#include <import/ebistree.h>
20
Willy Tarreau4c7e4b72020-05-27 12:58:42 +020021#include <haproxy/api.h>
Willy Tarreau3c69e082022-05-03 11:35:07 +020022#include <haproxy/applet.h>
Willy Tarreaub2551052020-06-09 09:07:15 +020023#include <haproxy/arg.h>
Willy Tarreau6be78492020-06-05 00:00:29 +020024#include <haproxy/cfgparse.h>
Willy Tarreau83487a82020-06-04 20:19:54 +020025#include <haproxy/cli.h>
Thayne McCombs92149f92020-11-20 01:28:26 -070026#include <haproxy/dict.h>
Willy Tarreau36979d92020-06-05 17:27:29 +020027#include <haproxy/errors.h>
Willy Tarreauf268ee82020-06-04 17:05:57 +020028#include <haproxy/global.h>
Willy Tarreauc761f842020-06-04 11:40:28 +020029#include <haproxy/http_rules.h>
Willy Tarreau853b2972020-05-27 18:01:47 +020030#include <haproxy/list.h>
Willy Tarreauaeed4a82020-06-04 22:01:04 +020031#include <haproxy/log.h>
Willy Tarreau6131d6a2020-06-02 16:48:09 +020032#include <haproxy/net_helper.h>
Willy Tarreau3c2a7c22020-06-04 18:38:21 +020033#include <haproxy/peers.h>
Willy Tarreaub2551052020-06-09 09:07:15 +020034#include <haproxy/pool.h>
35#include <haproxy/proto_tcp.h>
Willy Tarreaua264d962020-06-04 22:29:18 +020036#include <haproxy/proxy.h>
Willy Tarreaub2551052020-06-09 09:07:15 +020037#include <haproxy/sample.h>
Willy Tarreau5edca2f2022-05-27 09:25:10 +020038#include <haproxy/sc_strm.h>
Willy Tarreau2eec9b52020-06-04 19:58:55 +020039#include <haproxy/stats-t.h>
Willy Tarreaucb086c62022-05-27 09:47:12 +020040#include <haproxy/stconn.h>
Willy Tarreaub2551052020-06-09 09:07:15 +020041#include <haproxy/stick_table.h>
Willy Tarreaudfd3de82020-06-04 23:46:14 +020042#include <haproxy/stream.h>
Willy Tarreaucea0e1b2020-06-04 17:25:40 +020043#include <haproxy/task.h>
Willy Tarreau8b550af2020-06-04 17:42:48 +020044#include <haproxy/tcp_rules.h>
Willy Tarreau9310f482021-10-06 16:18:40 +020045#include <haproxy/ticks.h>
Willy Tarreaub2551052020-06-09 09:07:15 +020046#include <haproxy/tools.h>
Emeric Brun3bd697e2010-01-04 15:23:48 +010047
Emeric Brun3bd697e2010-01-04 15:23:48 +010048
Willy Tarreau12785782012-04-27 21:37:17 +020049/* structure used to return a table key built from a sample */
Emeric Brun819fc6f2017-06-13 19:37:32 +020050static THREAD_LOCAL struct stktable_key static_table_key;
Willy Tarreau478331d2020-08-28 11:31:31 +020051static int (*smp_fetch_src)(const struct arg *, struct sample *, const char *, void *);
Willy Tarreauf0b38bf2010-06-06 13:22:23 +020052
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +010053struct stktable *stktables_list;
54struct eb_root stktable_by_name = EB_ROOT;
55
Olivier Houchard52dabbc2018-11-14 17:54:36 +010056#define round_ptr_size(i) (((i) + (sizeof(void *) - 1)) &~ (sizeof(void *) - 1))
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +010057
58/* This function inserts stktable <t> into the tree of known stick-table.
59 * The stick-table ID is used as the storing key so it must already have
60 * been initialized.
61 */
62void stktable_store_name(struct stktable *t)
63{
64 t->name.key = t->id;
65 ebis_insert(&stktable_by_name, &t->name);
66}
67
68struct stktable *stktable_find_by_name(const char *name)
69{
70 struct ebpt_node *node;
71 struct stktable *t;
72
73 node = ebis_lookup(&stktable_by_name, name);
74 if (node) {
75 t = container_of(node, struct stktable, name);
Tim Duesterhuse5ff1412021-01-02 22:31:53 +010076 if (strcmp(t->id, name) == 0)
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +010077 return t;
78 }
79
80 return NULL;
81}
82
Emeric Brun3bd697e2010-01-04 15:23:48 +010083/*
Willy Tarreauaea940e2010-06-06 11:56:36 +020084 * Free an allocated sticky session <ts>, and decrease sticky sessions counter
85 * in table <t>.
Emeric Brun3bd697e2010-01-04 15:23:48 +010086 */
Emeric Brun819fc6f2017-06-13 19:37:32 +020087void __stksess_free(struct stktable *t, struct stksess *ts)
Emeric Brun3bd697e2010-01-04 15:23:48 +010088{
89 t->current--;
Olivier Houchard52dabbc2018-11-14 17:54:36 +010090 pool_free(t->pool, (void *)ts - round_ptr_size(t->data_size));
Emeric Brun3bd697e2010-01-04 15:23:48 +010091}
92
93/*
Emeric Brun819fc6f2017-06-13 19:37:32 +020094 * Free an allocated sticky session <ts>, and decrease sticky sessions counter
95 * in table <t>.
96 * This function locks the table
97 */
98void stksess_free(struct stktable *t, struct stksess *ts)
99{
Thayne McCombs92149f92020-11-20 01:28:26 -0700100 void *data;
101 data = stktable_data_ptr(t, ts, STKTABLE_DT_SERVER_KEY);
102 if (data) {
Emeric Brun0e3457b2021-06-30 17:18:28 +0200103 dict_entry_unref(&server_key_dict, stktable_data_cast(data, std_t_dict));
104 stktable_data_cast(data, std_t_dict) = NULL;
Thayne McCombs92149f92020-11-20 01:28:26 -0700105 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100106 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200107 __stksess_free(t, ts);
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100108 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200109}
110
111/*
Willy Tarreauf6efda12010-08-03 20:34:06 +0200112 * Kill an stksess (only if its ref_cnt is zero).
113 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200114int __stksess_kill(struct stktable *t, struct stksess *ts)
Willy Tarreauf6efda12010-08-03 20:34:06 +0200115{
116 if (ts->ref_cnt)
Emeric Brun819fc6f2017-06-13 19:37:32 +0200117 return 0;
Willy Tarreauf6efda12010-08-03 20:34:06 +0200118
119 eb32_delete(&ts->exp);
Emeric Brun85e77c72010-09-23 18:16:52 +0200120 eb32_delete(&ts->upd);
Willy Tarreauf6efda12010-08-03 20:34:06 +0200121 ebmb_delete(&ts->key);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200122 __stksess_free(t, ts);
123 return 1;
Willy Tarreauf6efda12010-08-03 20:34:06 +0200124}
125
126/*
Emeric Brun819fc6f2017-06-13 19:37:32 +0200127 * Decrease the refcount if decrefcnt is not 0.
128 * and try to kill the stksess
129 * This function locks the table
130 */
131int stksess_kill(struct stktable *t, struct stksess *ts, int decrefcnt)
132{
133 int ret;
134
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100135 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200136 if (decrefcnt)
137 ts->ref_cnt--;
138 ret = __stksess_kill(t, ts);
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100139 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200140
141 return ret;
142}
143
144/*
Willy Tarreauaea940e2010-06-06 11:56:36 +0200145 * Initialize or update the key in the sticky session <ts> present in table <t>
146 * from the value present in <key>.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100147 */
Willy Tarreau393379c2010-06-06 12:11:37 +0200148void stksess_setkey(struct stktable *t, struct stksess *ts, struct stktable_key *key)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100149{
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200150 if (t->type != SMP_T_STR)
Willy Tarreau86257dc2010-06-06 12:57:10 +0200151 memcpy(ts->key.key, key->key, t->key_size);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100152 else {
Willy Tarreau86257dc2010-06-06 12:57:10 +0200153 memcpy(ts->key.key, key->key, MIN(t->key_size - 1, key->key_len));
154 ts->key.key[MIN(t->key_size - 1, key->key_len)] = 0;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100155 }
156}
157
158
159/*
Willy Tarreau393379c2010-06-06 12:11:37 +0200160 * Init sticky session <ts> of table <t>. The data parts are cleared and <ts>
161 * is returned.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100162 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200163static struct stksess *__stksess_init(struct stktable *t, struct stksess * ts)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100164{
Willy Tarreau393379c2010-06-06 12:11:37 +0200165 memset((void *)ts - t->data_size, 0, t->data_size);
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200166 ts->ref_cnt = 0;
Willy Tarreau86257dc2010-06-06 12:57:10 +0200167 ts->key.node.leaf_p = NULL;
168 ts->exp.node.leaf_p = NULL;
Emeric Brun85e77c72010-09-23 18:16:52 +0200169 ts->upd.node.leaf_p = NULL;
Emeric Brun819fc6f2017-06-13 19:37:32 +0200170 ts->expire = tick_add(now_ms, MS_TO_TICKS(t->expire));
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100171 HA_RWLOCK_INIT(&ts->lock);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100172 return ts;
173}
174
175/*
Willy Tarreauaea940e2010-06-06 11:56:36 +0200176 * Trash oldest <to_batch> sticky sessions from table <t>
Willy Tarreaudfe79252020-11-03 17:47:41 +0100177 * Returns number of trashed sticky sessions. It may actually trash less
178 * than expected if finding these requires too long a search time (e.g.
179 * most of them have ts->ref_cnt>0).
Emeric Brun3bd697e2010-01-04 15:23:48 +0100180 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200181int __stktable_trash_oldest(struct stktable *t, int to_batch)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100182{
183 struct stksess *ts;
184 struct eb32_node *eb;
Willy Tarreaudfe79252020-11-03 17:47:41 +0100185 int max_search = to_batch * 2; // no more than 50% misses
Emeric Brun3bd697e2010-01-04 15:23:48 +0100186 int batched = 0;
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200187 int looped = 0;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100188
189 eb = eb32_lookup_ge(&t->exps, now_ms - TIMER_LOOK_BACK);
190
191 while (batched < to_batch) {
192
193 if (unlikely(!eb)) {
194 /* we might have reached the end of the tree, typically because
195 * <now_ms> is in the first half and we're first scanning the last
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200196 * half. Let's loop back to the beginning of the tree now if we
197 * have not yet visited it.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100198 */
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200199 if (looped)
200 break;
201 looped = 1;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100202 eb = eb32_first(&t->exps);
203 if (likely(!eb))
204 break;
205 }
206
Willy Tarreaudfe79252020-11-03 17:47:41 +0100207 if (--max_search < 0)
208 break;
209
Emeric Brun3bd697e2010-01-04 15:23:48 +0100210 /* timer looks expired, detach it from the queue */
Willy Tarreau86257dc2010-06-06 12:57:10 +0200211 ts = eb32_entry(eb, struct stksess, exp);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100212 eb = eb32_next(eb);
213
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200214 /* don't delete an entry which is currently referenced */
215 if (ts->ref_cnt)
216 continue;
217
Willy Tarreau86257dc2010-06-06 12:57:10 +0200218 eb32_delete(&ts->exp);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100219
Willy Tarreau86257dc2010-06-06 12:57:10 +0200220 if (ts->expire != ts->exp.key) {
Emeric Brun3bd697e2010-01-04 15:23:48 +0100221 if (!tick_isset(ts->expire))
222 continue;
223
Willy Tarreau86257dc2010-06-06 12:57:10 +0200224 ts->exp.key = ts->expire;
225 eb32_insert(&t->exps, &ts->exp);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100226
Willy Tarreau86257dc2010-06-06 12:57:10 +0200227 if (!eb || eb->key > ts->exp.key)
228 eb = &ts->exp;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100229
230 continue;
231 }
Emeric Brun3bd697e2010-01-04 15:23:48 +0100232
Willy Tarreauaea940e2010-06-06 11:56:36 +0200233 /* session expired, trash it */
Willy Tarreau86257dc2010-06-06 12:57:10 +0200234 ebmb_delete(&ts->key);
Emeric Brun85e77c72010-09-23 18:16:52 +0200235 eb32_delete(&ts->upd);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200236 __stksess_free(t, ts);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100237 batched++;
238 }
239
240 return batched;
241}
242
243/*
Emeric Brun819fc6f2017-06-13 19:37:32 +0200244 * Trash oldest <to_batch> sticky sessions from table <t>
245 * Returns number of trashed sticky sessions.
246 * This function locks the table
247 */
248int stktable_trash_oldest(struct stktable *t, int to_batch)
249{
250 int ret;
251
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100252 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200253 ret = __stktable_trash_oldest(t, to_batch);
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100254 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200255
256 return ret;
257}
258/*
Willy Tarreauaea940e2010-06-06 11:56:36 +0200259 * Allocate and initialise a new sticky session.
260 * The new sticky session is returned or NULL in case of lack of memory.
261 * Sticky sessions should only be allocated this way, and must be freed using
Willy Tarreaua7b46b52013-04-11 16:55:37 +0200262 * stksess_free(). Table <t>'s sticky session counter is increased. If <key>
263 * is not NULL, it is assigned to the new session.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100264 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200265struct stksess *__stksess_new(struct stktable *t, struct stktable_key *key)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100266{
267 struct stksess *ts;
268
269 if (unlikely(t->current == t->size)) {
270 if ( t->nopurge )
271 return NULL;
272
Emeric Brun819fc6f2017-06-13 19:37:32 +0200273 if (!__stktable_trash_oldest(t, (t->size >> 8) + 1))
Emeric Brun3bd697e2010-01-04 15:23:48 +0100274 return NULL;
275 }
276
Willy Tarreaubafbe012017-11-24 17:34:44 +0100277 ts = pool_alloc(t->pool);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100278 if (ts) {
279 t->current++;
Olivier Houchard52dabbc2018-11-14 17:54:36 +0100280 ts = (void *)ts + round_ptr_size(t->data_size);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200281 __stksess_init(t, ts);
Willy Tarreaua7b46b52013-04-11 16:55:37 +0200282 if (key)
283 stksess_setkey(t, ts, key);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100284 }
285
286 return ts;
287}
Emeric Brun819fc6f2017-06-13 19:37:32 +0200288/*
289 * Allocate and initialise a new sticky session.
290 * The new sticky session is returned or NULL in case of lack of memory.
291 * Sticky sessions should only be allocated this way, and must be freed using
292 * stksess_free(). Table <t>'s sticky session counter is increased. If <key>
293 * is not NULL, it is assigned to the new session.
294 * This function locks the table
295 */
296struct stksess *stksess_new(struct stktable *t, struct stktable_key *key)
297{
298 struct stksess *ts;
299
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100300 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200301 ts = __stksess_new(t, key);
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100302 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200303
304 return ts;
305}
Emeric Brun3bd697e2010-01-04 15:23:48 +0100306
307/*
Willy Tarreauf16d2b82010-06-06 15:38:59 +0200308 * Looks in table <t> for a sticky session matching key <key>.
Willy Tarreauaea940e2010-06-06 11:56:36 +0200309 * Returns pointer on requested sticky session or NULL if none was found.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100310 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200311struct stksess *__stktable_lookup_key(struct stktable *t, struct stktable_key *key)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100312{
313 struct ebmb_node *eb;
314
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200315 if (t->type == SMP_T_STR)
Emeric Brun485479d2010-09-23 18:02:19 +0200316 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 +0100317 else
318 eb = ebmb_lookup(&t->keys, key->key, t->key_size);
319
320 if (unlikely(!eb)) {
321 /* no session found */
322 return NULL;
323 }
324
Willy Tarreau86257dc2010-06-06 12:57:10 +0200325 return ebmb_entry(eb, struct stksess, key);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100326}
327
Emeric Brun819fc6f2017-06-13 19:37:32 +0200328/*
329 * Looks in table <t> for a sticky session matching key <key>.
330 * Returns pointer on requested sticky session or NULL if none was found.
331 * The refcount of the found entry is increased and this function
332 * is protected using the table lock
Willy Tarreau1f7e9252010-06-20 12:27:21 +0200333 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200334struct stksess *stktable_lookup_key(struct stktable *t, struct stktable_key *key)
Willy Tarreau1f7e9252010-06-20 12:27:21 +0200335{
336 struct stksess *ts;
337
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100338 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200339 ts = __stktable_lookup_key(t, key);
340 if (ts)
341 ts->ref_cnt++;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100342 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Willy Tarreau1f7e9252010-06-20 12:27:21 +0200343
Willy Tarreau1f7e9252010-06-20 12:27:21 +0200344 return ts;
345}
346
Willy Tarreauf16d2b82010-06-06 15:38:59 +0200347/*
348 * Looks in table <t> for a sticky session with same key as <ts>.
349 * Returns pointer on requested sticky session or NULL if none was found.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100350 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200351struct stksess *__stktable_lookup(struct stktable *t, struct stksess *ts)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100352{
Emeric Brun3bd697e2010-01-04 15:23:48 +0100353 struct ebmb_node *eb;
354
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200355 if (t->type == SMP_T_STR)
Willy Tarreau86257dc2010-06-06 12:57:10 +0200356 eb = ebst_lookup(&(t->keys), (char *)ts->key.key);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100357 else
Willy Tarreau86257dc2010-06-06 12:57:10 +0200358 eb = ebmb_lookup(&(t->keys), ts->key.key, t->key_size);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100359
Willy Tarreauf16d2b82010-06-06 15:38:59 +0200360 if (unlikely(!eb))
361 return NULL;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100362
Willy Tarreauf16d2b82010-06-06 15:38:59 +0200363 return ebmb_entry(eb, struct stksess, key);
364}
Emeric Brun3bd697e2010-01-04 15:23:48 +0100365
Emeric Brun819fc6f2017-06-13 19:37:32 +0200366/*
367 * Looks in table <t> for a sticky session with same key as <ts>.
368 * Returns pointer on requested sticky session or NULL if none was found.
369 * The refcount of the found entry is increased and this function
370 * is protected using the table lock
371 */
372struct stksess *stktable_lookup(struct stktable *t, struct stksess *ts)
373{
374 struct stksess *lts;
375
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100376 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200377 lts = __stktable_lookup(t, ts);
378 if (lts)
379 lts->ref_cnt++;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100380 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200381
382 return lts;
383}
384
Willy Tarreaucb183642010-06-06 17:58:34 +0200385/* Update the expiration timer for <ts> but do not touch its expiration node.
386 * The table's expiration timer is updated if set.
Emeric Brun819fc6f2017-06-13 19:37:32 +0200387 * The node will be also inserted into the update tree if needed, at a position
388 * depending if the update is a local or coming from a remote node
Willy Tarreaucb183642010-06-06 17:58:34 +0200389 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200390void __stktable_touch_with_exp(struct stktable *t, struct stksess *ts, int local, int expire)
Willy Tarreaucb183642010-06-06 17:58:34 +0200391{
Emeric Brun85e77c72010-09-23 18:16:52 +0200392 struct eb32_node * eb;
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200393 ts->expire = expire;
Willy Tarreaucb183642010-06-06 17:58:34 +0200394 if (t->expire) {
395 t->exp_task->expire = t->exp_next = tick_first(ts->expire, t->exp_next);
396 task_queue(t->exp_task);
397 }
Emeric Brun85e77c72010-09-23 18:16:52 +0200398
Emeric Brun819fc6f2017-06-13 19:37:32 +0200399 /* If sync is enabled */
400 if (t->sync_task) {
401 if (local) {
402 /* If this entry is not in the tree
403 or not scheduled for at least one peer */
404 if (!ts->upd.node.leaf_p
405 || (int)(t->commitupdate - ts->upd.key) >= 0
406 || (int)(ts->upd.key - t->localupdate) >= 0) {
407 ts->upd.key = ++t->update;
408 t->localupdate = t->update;
409 eb32_delete(&ts->upd);
410 eb = eb32_insert(&t->updates, &ts->upd);
411 if (eb != &ts->upd) {
412 eb32_delete(eb);
413 eb32_insert(&t->updates, &ts->upd);
414 }
Emeric Brunaaf58602015-06-15 17:23:30 +0200415 }
Emeric Brun819fc6f2017-06-13 19:37:32 +0200416 task_wakeup(t->sync_task, TASK_WOKEN_MSG);
Emeric Brun85e77c72010-09-23 18:16:52 +0200417 }
Emeric Brun819fc6f2017-06-13 19:37:32 +0200418 else {
419 /* If this entry is not in the tree */
420 if (!ts->upd.node.leaf_p) {
421 ts->upd.key= (++t->update)+(2147483648U);
422 eb = eb32_insert(&t->updates, &ts->upd);
423 if (eb != &ts->upd) {
424 eb32_delete(eb);
425 eb32_insert(&t->updates, &ts->upd);
426 }
427 }
428 }
Emeric Brun85e77c72010-09-23 18:16:52 +0200429 }
Willy Tarreaucb183642010-06-06 17:58:34 +0200430}
431
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200432/* Update the expiration timer for <ts> but do not touch its expiration node.
Emeric Brun819fc6f2017-06-13 19:37:32 +0200433 * The table's expiration timer is updated using the date of expiration coming from
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200434 * <t> stick-table configuration.
Emeric Brun819fc6f2017-06-13 19:37:32 +0200435 * The node will be also inserted into the update tree if needed, at a position
436 * considering the update is coming from a remote node
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200437 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200438void stktable_touch_remote(struct stktable *t, struct stksess *ts, int decrefcnt)
439{
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100440 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200441 __stktable_touch_with_exp(t, ts, 0, ts->expire);
442 if (decrefcnt)
443 ts->ref_cnt--;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100444 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200445}
446
447/* Update the expiration timer for <ts> but do not touch its expiration node.
448 * The table's expiration timer is updated using the date of expiration coming from
449 * <t> stick-table configuration.
450 * The node will be also inserted into the update tree if needed, at a position
451 * considering the update was made locally
452 */
453void stktable_touch_local(struct stktable *t, struct stksess *ts, int decrefcnt)
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200454{
455 int expire = tick_add(now_ms, MS_TO_TICKS(t->expire));
456
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100457 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200458 __stktable_touch_with_exp(t, ts, 1, expire);
459 if (decrefcnt)
460 ts->ref_cnt--;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100461 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200462}
Willy Tarreau43e90352018-06-27 06:25:57 +0200463/* Just decrease the ref_cnt of the current session. Does nothing if <ts> is NULL */
464static void stktable_release(struct stktable *t, struct stksess *ts)
Emeric Brun819fc6f2017-06-13 19:37:32 +0200465{
Willy Tarreau43e90352018-06-27 06:25:57 +0200466 if (!ts)
467 return;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100468 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200469 ts->ref_cnt--;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100470 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200471}
472
Willy Tarreauf16d2b82010-06-06 15:38:59 +0200473/* Insert new sticky session <ts> in the table. It is assumed that it does not
474 * yet exist (the caller must check this). The table's timeout is updated if it
475 * is set. <ts> is returned.
476 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200477void __stktable_store(struct stktable *t, struct stksess *ts)
Willy Tarreauf16d2b82010-06-06 15:38:59 +0200478{
Emeric Brun3bd697e2010-01-04 15:23:48 +0100479
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200480 ebmb_insert(&t->keys, &ts->key, t->key_size);
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200481 ts->exp.key = ts->expire;
482 eb32_insert(&t->exps, &ts->exp);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200483 if (t->expire) {
484 t->exp_task->expire = t->exp_next = tick_first(ts->expire, t->exp_next);
485 task_queue(t->exp_task);
486 }
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200487}
488
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200489/* Returns a valid or initialized stksess for the specified stktable_key in the
490 * specified table, or NULL if the key was NULL, or if no entry was found nor
491 * could be created. The entry's expiration is updated.
492 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200493struct stksess *__stktable_get_entry(struct stktable *table, struct stktable_key *key)
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200494{
495 struct stksess *ts;
496
497 if (!key)
498 return NULL;
499
Emeric Brun819fc6f2017-06-13 19:37:32 +0200500 ts = __stktable_lookup_key(table, key);
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200501 if (ts == NULL) {
502 /* entry does not exist, initialize a new one */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200503 ts = __stksess_new(table, key);
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200504 if (!ts)
505 return NULL;
Emeric Brun819fc6f2017-06-13 19:37:32 +0200506 __stktable_store(table, ts);
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200507 }
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200508 return ts;
509}
Emeric Brun819fc6f2017-06-13 19:37:32 +0200510/* Returns a valid or initialized stksess for the specified stktable_key in the
511 * specified table, or NULL if the key was NULL, or if no entry was found nor
512 * could be created. The entry's expiration is updated.
513 * This function locks the table, and the refcount of the entry is increased.
514 */
515struct stksess *stktable_get_entry(struct stktable *table, struct stktable_key *key)
516{
517 struct stksess *ts;
518
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100519 HA_SPIN_LOCK(STK_TABLE_LOCK, &table->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200520 ts = __stktable_get_entry(table, key);
521 if (ts)
522 ts->ref_cnt++;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100523 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &table->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200524
525 return ts;
526}
527
528/* Lookup for an entry with the same key and store the submitted
529 * stksess if not found.
530 */
531struct stksess *__stktable_set_entry(struct stktable *table, struct stksess *nts)
532{
533 struct stksess *ts;
534
535 ts = __stktable_lookup(table, nts);
536 if (ts == NULL) {
537 ts = nts;
538 __stktable_store(table, ts);
539 }
540 return ts;
541}
542
543/* Lookup for an entry with the same key and store the submitted
544 * stksess if not found.
545 * This function locks the table, and the refcount of the entry is increased.
546 */
547struct stksess *stktable_set_entry(struct stktable *table, struct stksess *nts)
548{
549 struct stksess *ts;
550
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100551 HA_SPIN_LOCK(STK_TABLE_LOCK, &table->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200552 ts = __stktable_set_entry(table, nts);
553 ts->ref_cnt++;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100554 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &table->lock);
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200555
Emeric Brun819fc6f2017-06-13 19:37:32 +0200556 return ts;
557}
Emeric Brun3bd697e2010-01-04 15:23:48 +0100558/*
Willy Tarreauaea940e2010-06-06 11:56:36 +0200559 * Trash expired sticky sessions from table <t>. The next expiration date is
560 * returned.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100561 */
562static int stktable_trash_expired(struct stktable *t)
563{
564 struct stksess *ts;
565 struct eb32_node *eb;
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200566 int looped = 0;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100567
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100568 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100569 eb = eb32_lookup_ge(&t->exps, now_ms - TIMER_LOOK_BACK);
570
571 while (1) {
572 if (unlikely(!eb)) {
573 /* we might have reached the end of the tree, typically because
574 * <now_ms> is in the first half and we're first scanning the last
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200575 * half. Let's loop back to the beginning of the tree now if we
576 * have not yet visited it.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100577 */
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200578 if (looped)
579 break;
580 looped = 1;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100581 eb = eb32_first(&t->exps);
582 if (likely(!eb))
583 break;
584 }
585
586 if (likely(tick_is_lt(now_ms, eb->key))) {
587 /* timer not expired yet, revisit it later */
588 t->exp_next = eb->key;
Willy Tarreau4d5f13c2017-11-05 11:04:47 +0100589 goto out_unlock;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100590 }
591
592 /* timer looks expired, detach it from the queue */
Willy Tarreau86257dc2010-06-06 12:57:10 +0200593 ts = eb32_entry(eb, struct stksess, exp);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100594 eb = eb32_next(eb);
595
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200596 /* don't delete an entry which is currently referenced */
597 if (ts->ref_cnt)
598 continue;
599
Willy Tarreau86257dc2010-06-06 12:57:10 +0200600 eb32_delete(&ts->exp);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100601
602 if (!tick_is_expired(ts->expire, now_ms)) {
603 if (!tick_isset(ts->expire))
604 continue;
605
Willy Tarreau86257dc2010-06-06 12:57:10 +0200606 ts->exp.key = ts->expire;
607 eb32_insert(&t->exps, &ts->exp);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100608
Willy Tarreau86257dc2010-06-06 12:57:10 +0200609 if (!eb || eb->key > ts->exp.key)
610 eb = &ts->exp;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100611 continue;
612 }
613
614 /* session expired, trash it */
Willy Tarreau86257dc2010-06-06 12:57:10 +0200615 ebmb_delete(&ts->key);
Emeric Brun85e77c72010-09-23 18:16:52 +0200616 eb32_delete(&ts->upd);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200617 __stksess_free(t, ts);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100618 }
619
620 /* We have found no task to expire in any tree */
621 t->exp_next = TICK_ETERNITY;
Willy Tarreau4d5f13c2017-11-05 11:04:47 +0100622out_unlock:
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100623 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100624 return t->exp_next;
625}
626
627/*
Willy Tarreauaea940e2010-06-06 11:56:36 +0200628 * Task processing function to trash expired sticky sessions. A pointer to the
629 * task itself is returned since it never dies.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100630 */
Willy Tarreau144f84a2021-03-02 16:09:26 +0100631struct task *process_table_expire(struct task *task, void *context, unsigned int state)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100632{
Olivier Houchard9f6af332018-05-25 14:04:04 +0200633 struct stktable *t = context;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100634
635 task->expire = stktable_trash_expired(t);
636 return task;
637}
638
Willy Tarreauaea940e2010-06-06 11:56:36 +0200639/* Perform minimal stick table intializations, report 0 in case of error, 1 if OK. */
Emeric Brun3bd697e2010-01-04 15:23:48 +0100640int stktable_init(struct stktable *t)
641{
Remi Tricot-Le Breton208ff012021-05-12 17:39:04 +0200642 int peers_retval = 0;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100643 if (t->size) {
Emeric Brun819fc6f2017-06-13 19:37:32 +0200644 t->keys = EB_ROOT_UNIQUE;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100645 memset(&t->exps, 0, sizeof(t->exps));
Emeric Brun1c6235d2015-12-16 15:28:12 +0100646 t->updates = EB_ROOT_UNIQUE;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100647 HA_SPIN_INIT(&t->lock);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100648
Olivier Houchard52dabbc2018-11-14 17:54:36 +0100649 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 +0100650
651 t->exp_next = TICK_ETERNITY;
652 if ( t->expire ) {
Willy Tarreaubeeabf52021-10-01 18:23:30 +0200653 t->exp_task = task_new_anywhere();
Willy Tarreau848522f2018-10-15 11:12:15 +0200654 if (!t->exp_task)
655 return 0;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100656 t->exp_task->process = process_table_expire;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100657 t->exp_task->context = (void *)t;
658 }
Christopher Fauletdfd10ab2021-10-06 14:24:19 +0200659 if (t->peers.p && t->peers.p->peers_fe && !(t->peers.p->peers_fe->flags & (PR_FL_DISABLED|PR_FL_STOPPED))) {
Remi Tricot-Le Breton208ff012021-05-12 17:39:04 +0200660 peers_retval = peers_register_table(t->peers.p, t);
Emeric Brun32da3c42010-09-23 18:39:19 +0200661 }
662
Remi Tricot-Le Breton208ff012021-05-12 17:39:04 +0200663 return (t->pool != NULL) && !peers_retval;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100664 }
665 return 1;
666}
667
668/*
669 * Configuration keywords of known table types
670 */
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200671struct stktable_type stktable_types[SMP_TYPES] = {
672 [SMP_T_SINT] = { "integer", 0, 4 },
673 [SMP_T_IPV4] = { "ip", 0, 4 },
674 [SMP_T_IPV6] = { "ipv6", 0, 16 },
675 [SMP_T_STR] = { "string", STK_F_CUSTOM_KEYSIZE, 32 },
676 [SMP_T_BIN] = { "binary", STK_F_CUSTOM_KEYSIZE, 32 }
677};
Emeric Brun3bd697e2010-01-04 15:23:48 +0100678
679/*
680 * Parse table type configuration.
681 * Returns 0 on successful parsing, else 1.
682 * <myidx> is set at next configuration <args> index.
683 */
684int stktable_parse_type(char **args, int *myidx, unsigned long *type, size_t *key_size)
685{
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200686 for (*type = 0; *type < SMP_TYPES; (*type)++) {
687 if (!stktable_types[*type].kw)
688 continue;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100689 if (strcmp(args[*myidx], stktable_types[*type].kw) != 0)
690 continue;
691
692 *key_size = stktable_types[*type].default_size;
693 (*myidx)++;
694
Willy Tarreauaea940e2010-06-06 11:56:36 +0200695 if (stktable_types[*type].flags & STK_F_CUSTOM_KEYSIZE) {
Emeric Brun3bd697e2010-01-04 15:23:48 +0100696 if (strcmp("len", args[*myidx]) == 0) {
697 (*myidx)++;
698 *key_size = atol(args[*myidx]);
Emeric Brun485479d2010-09-23 18:02:19 +0200699 if (!*key_size)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100700 break;
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200701 if (*type == SMP_T_STR) {
Emeric Brun485479d2010-09-23 18:02:19 +0200702 /* null terminated string needs +1 for '\0'. */
703 (*key_size)++;
704 }
Emeric Brun3bd697e2010-01-04 15:23:48 +0100705 (*myidx)++;
706 }
707 }
708 return 0;
709 }
710 return 1;
711}
712
Emeric Brunc64a2a32021-06-30 18:01:02 +0200713/* reserve some space for data type <type>, there is 2 optionnals
714 * argument at <sa> and <sa2> to configure this data type and
715 * they can be NULL if unused for a given type.
716 * Returns PE_NONE (0) if OK or an error code among :
Willy Tarreau3b63ca22021-05-08 14:10:42 +0200717 * - PE_ENUM_OOR if <type> does not exist
718 * - PE_EXIST if <type> is already registered
Emeric Brunc64a2a32021-06-30 18:01:02 +0200719 * - PE_ARG_NOT_USE if <sa>/<sa2> was provided but not expected
720 * - PE_ARG_MISSING if <sa>/<sa2> was expected but not provided
721 * - PE_ARG_VALUE_OOR if type is an array and <sa> it out of array size range.
Willy Tarreau3b63ca22021-05-08 14:10:42 +0200722 */
Emeric Brunc64a2a32021-06-30 18:01:02 +0200723int stktable_alloc_data_type(struct stktable *t, int type, const char *sa, const char *sa2)
724
Willy Tarreau3b63ca22021-05-08 14:10:42 +0200725{
726 if (type >= STKTABLE_DATA_TYPES)
727 return PE_ENUM_OOR;
728
729 if (t->data_ofs[type])
730 /* already allocated */
731 return PE_EXIST;
732
Emeric Brunc64a2a32021-06-30 18:01:02 +0200733 t->data_nbelem[type] = 1;
734 if (stktable_data_types[type].is_array) {
735 /* arrays take their element count on first argument */
736 if (!sa)
737 return PE_ARG_MISSING;
738 t->data_nbelem[type] = atoi(sa);
739 if (!t->data_nbelem[type] || (t->data_nbelem[type] > STKTABLE_MAX_DT_ARRAY_SIZE))
740 return PE_ARG_VALUE_OOR;
741 sa = sa2;
742 }
743
Willy Tarreau3b63ca22021-05-08 14:10:42 +0200744 switch (stktable_data_types[type].arg_type) {
745 case ARG_T_NONE:
746 if (sa)
747 return PE_ARG_NOT_USED;
748 break;
749 case ARG_T_INT:
750 if (!sa)
751 return PE_ARG_MISSING;
752 t->data_arg[type].i = atoi(sa);
753 break;
754 case ARG_T_DELAY:
755 if (!sa)
756 return PE_ARG_MISSING;
757 sa = parse_time_err(sa, &t->data_arg[type].u, TIME_UNIT_MS);
758 if (sa)
759 return PE_ARG_INVC; /* invalid char */
760 break;
761 }
762
Emeric Brunc64a2a32021-06-30 18:01:02 +0200763 t->data_size += t->data_nbelem[type] * stktable_type_size(stktable_data_types[type].std_type);
Willy Tarreau3b63ca22021-05-08 14:10:42 +0200764 t->data_ofs[type] = -t->data_size;
765 return PE_NONE;
766}
767
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100768/*
Frédéric Lécaillec02766a2019-03-20 15:06:55 +0100769 * Parse a line with <linenum> as number in <file> configuration file to configure
770 * the stick-table with <t> as address and <id> as ID.
771 * <peers> provides the "peers" section pointer only if this function is called
772 * from a "peers" section.
773 * <nid> is the stick-table name which is sent over the network. It must be equal
774 * to <id> if this stick-table is parsed from a proxy section, and prefixed by <peers>
775 * "peers" section name followed by a '/' character if parsed from a "peers" section.
Ilya Shipitsind4259502020-04-08 01:07:56 +0500776 * This is the responsibility of the caller to check this.
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100777 * Return an error status with ERR_* flags set if required, 0 if no error was encountered.
778 */
779int parse_stick_table(const char *file, int linenum, char **args,
Frédéric Lécaillec02766a2019-03-20 15:06:55 +0100780 struct stktable *t, char *id, char *nid, struct peers *peers)
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100781{
782 int err_code = 0;
783 int idx = 1;
784 unsigned int val;
785
786 if (!id || !*id) {
787 ha_alert("parsing [%s:%d] : %s: ID not provided.\n", file, linenum, args[0]);
788 err_code |= ERR_ALERT | ERR_ABORT;
789 goto out;
790 }
791
792 /* Store the "peers" section if this function is called from a "peers" section. */
793 if (peers) {
794 t->peers.p = peers;
795 idx++;
796 }
797
798 t->id = id;
Frédéric Lécaillec02766a2019-03-20 15:06:55 +0100799 t->nid = nid;
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100800 t->type = (unsigned int)-1;
801 t->conf.file = file;
802 t->conf.line = linenum;
803
804 while (*args[idx]) {
805 const char *err;
806
807 if (strcmp(args[idx], "size") == 0) {
808 idx++;
809 if (!*(args[idx])) {
810 ha_alert("parsing [%s:%d] : %s: missing argument after '%s'.\n",
811 file, linenum, args[0], args[idx-1]);
812 err_code |= ERR_ALERT | ERR_FATAL;
813 goto out;
814 }
815 if ((err = parse_size_err(args[idx], &t->size))) {
816 ha_alert("parsing [%s:%d] : %s: unexpected character '%c' in argument of '%s'.\n",
817 file, linenum, args[0], *err, args[idx-1]);
818 err_code |= ERR_ALERT | ERR_FATAL;
819 goto out;
820 }
821 idx++;
822 }
823 /* This argument does not exit in "peers" section. */
824 else if (!peers && strcmp(args[idx], "peers") == 0) {
825 idx++;
826 if (!*(args[idx])) {
827 ha_alert("parsing [%s:%d] : %s: missing argument after '%s'.\n",
828 file, linenum, args[0], args[idx-1]);
829 err_code |= ERR_ALERT | ERR_FATAL;
830 goto out;
831 }
832 t->peers.name = strdup(args[idx++]);
833 }
834 else if (strcmp(args[idx], "expire") == 0) {
835 idx++;
836 if (!*(args[idx])) {
837 ha_alert("parsing [%s:%d] : %s: missing argument after '%s'.\n",
838 file, linenum, args[0], args[idx-1]);
839 err_code |= ERR_ALERT | ERR_FATAL;
840 goto out;
841 }
842 err = parse_time_err(args[idx], &val, TIME_UNIT_MS);
Willy Tarreau9faebe32019-06-07 19:00:37 +0200843 if (err == PARSE_TIME_OVER) {
844 ha_alert("parsing [%s:%d]: %s: timer overflow in argument <%s> to <%s>, maximum value is 2147483647 ms (~24.8 days).\n",
845 file, linenum, args[0], args[idx], args[idx-1]);
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100846 err_code |= ERR_ALERT | ERR_FATAL;
847 goto out;
848 }
Willy Tarreau9faebe32019-06-07 19:00:37 +0200849 else if (err == PARSE_TIME_UNDER) {
850 ha_alert("parsing [%s:%d]: %s: timer underflow in argument <%s> to <%s>, minimum non-null value is 1 ms.\n",
851 file, linenum, args[0], args[idx], args[idx-1]);
852 err_code |= ERR_ALERT | ERR_FATAL;
853 goto out;
854 }
855 else if (err) {
856 ha_alert("parsing [%s:%d] : %s: unexpected character '%c' in argument of '%s'.\n",
857 file, linenum, args[0], *err, args[idx-1]);
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100858 err_code |= ERR_ALERT | ERR_FATAL;
859 goto out;
860 }
861 t->expire = val;
862 idx++;
863 }
864 else if (strcmp(args[idx], "nopurge") == 0) {
865 t->nopurge = 1;
866 idx++;
867 }
868 else if (strcmp(args[idx], "type") == 0) {
869 idx++;
870 if (stktable_parse_type(args, &idx, &t->type, &t->key_size) != 0) {
871 ha_alert("parsing [%s:%d] : %s: unknown type '%s'.\n",
872 file, linenum, args[0], args[idx]);
873 err_code |= ERR_ALERT | ERR_FATAL;
874 goto out;
875 }
876 /* idx already points to next arg */
877 }
878 else if (strcmp(args[idx], "store") == 0) {
879 int type, err;
Emeric Brunc64a2a32021-06-30 18:01:02 +0200880 char *cw, *nw, *sa, *sa2;
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100881
882 idx++;
883 nw = args[idx];
884 while (*nw) {
885 /* the "store" keyword supports a comma-separated list */
886 cw = nw;
887 sa = NULL; /* store arg */
Emeric Brunc64a2a32021-06-30 18:01:02 +0200888 sa2 = NULL;
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100889 while (*nw && *nw != ',') {
890 if (*nw == '(') {
891 *nw = 0;
892 sa = ++nw;
893 while (*nw != ')') {
894 if (!*nw) {
895 ha_alert("parsing [%s:%d] : %s: missing closing parenthesis after store option '%s'.\n",
896 file, linenum, args[0], cw);
897 err_code |= ERR_ALERT | ERR_FATAL;
898 goto out;
899 }
Emeric Brunc64a2a32021-06-30 18:01:02 +0200900 if (*nw == ',') {
901 *nw = '\0';
902 sa2 = nw + 1;
903 }
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100904 nw++;
905 }
906 *nw = '\0';
907 }
908 nw++;
909 }
910 if (*nw)
911 *nw++ = '\0';
912 type = stktable_get_data_type(cw);
913 if (type < 0) {
914 ha_alert("parsing [%s:%d] : %s: unknown store option '%s'.\n",
915 file, linenum, args[0], cw);
916 err_code |= ERR_ALERT | ERR_FATAL;
917 goto out;
918 }
919
Emeric Brunc64a2a32021-06-30 18:01:02 +0200920 err = stktable_alloc_data_type(t, type, sa, sa2);
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100921 switch (err) {
922 case PE_NONE: break;
923 case PE_EXIST:
924 ha_warning("parsing [%s:%d]: %s: store option '%s' already enabled, ignored.\n",
925 file, linenum, args[0], cw);
926 err_code |= ERR_WARN;
927 break;
928
929 case PE_ARG_MISSING:
930 ha_alert("parsing [%s:%d] : %s: missing argument to store option '%s'.\n",
931 file, linenum, args[0], cw);
932 err_code |= ERR_ALERT | ERR_FATAL;
933 goto out;
934
935 case PE_ARG_NOT_USED:
936 ha_alert("parsing [%s:%d] : %s: unexpected argument to store option '%s'.\n",
937 file, linenum, args[0], cw);
938 err_code |= ERR_ALERT | ERR_FATAL;
939 goto out;
Emeric Brunc64a2a32021-06-30 18:01:02 +0200940 case PE_ARG_VALUE_OOR:
941 ha_alert("parsing [%s:%d] : %s: array size is out of allowed range (1-%d) for store option '%s'.\n",
942 file, linenum, args[0], STKTABLE_MAX_DT_ARRAY_SIZE, cw);
943 err_code |= ERR_ALERT | ERR_FATAL;
944 goto out;
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100945
946 default:
947 ha_alert("parsing [%s:%d] : %s: error when processing store option '%s'.\n",
948 file, linenum, args[0], cw);
949 err_code |= ERR_ALERT | ERR_FATAL;
950 goto out;
951 }
952 }
953 idx++;
Emeric Brunf7ab0bf2021-06-30 18:58:22 +0200954 if (t->data_ofs[STKTABLE_DT_GPT] && t->data_ofs[STKTABLE_DT_GPT0]) {
955 ha_alert("parsing [%s:%d] : %s: simultaneous usage of 'gpt' and 'gpt0' in a same table is not permitted as 'gpt' overrides 'gpt0'.\n",
956 file, linenum, args[0]);
957 err_code |= ERR_ALERT | ERR_FATAL;
958 goto out;
959 }
Emeric Brun726783d2021-06-30 19:06:43 +0200960 else if (t->data_ofs[STKTABLE_DT_GPC] && (t->data_ofs[STKTABLE_DT_GPC0] || t->data_ofs[STKTABLE_DT_GPC1])) {
961 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",
962 file, linenum, args[0]);
963 err_code |= ERR_ALERT | ERR_FATAL;
964 goto out;
965 }
966 else if (t->data_ofs[STKTABLE_DT_GPC_RATE] && (t->data_ofs[STKTABLE_DT_GPC0_RATE] || t->data_ofs[STKTABLE_DT_GPC1_RATE])) {
967 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",
968 file, linenum, args[0]);
969 err_code |= ERR_ALERT | ERR_FATAL;
970 goto out;
971 }
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100972 }
Thayne McCombs92149f92020-11-20 01:28:26 -0700973 else if (strcmp(args[idx], "srvkey") == 0) {
974 char *keytype;
975 idx++;
976 keytype = args[idx];
977 if (strcmp(keytype, "name") == 0) {
978 t->server_key_type = STKTABLE_SRV_NAME;
979 }
980 else if (strcmp(keytype, "addr") == 0) {
981 t->server_key_type = STKTABLE_SRV_ADDR;
982 }
983 else {
984 ha_alert("parsing [%s:%d] : %s : unknown server key type '%s'.\n",
985 file, linenum, args[0], keytype);
986 err_code |= ERR_ALERT | ERR_FATAL;
987 goto out;
988
989 }
990 idx++;
991 }
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100992 else {
993 ha_alert("parsing [%s:%d] : %s: unknown argument '%s'.\n",
994 file, linenum, args[0], args[idx]);
995 err_code |= ERR_ALERT | ERR_FATAL;
996 goto out;
997 }
998 }
999
1000 if (!t->size) {
1001 ha_alert("parsing [%s:%d] : %s: missing size.\n",
1002 file, linenum, args[0]);
1003 err_code |= ERR_ALERT | ERR_FATAL;
1004 goto out;
1005 }
1006
1007 if (t->type == (unsigned int)-1) {
1008 ha_alert("parsing [%s:%d] : %s: missing type.\n",
1009 file, linenum, args[0]);
1010 err_code |= ERR_ALERT | ERR_FATAL;
1011 goto out;
1012 }
1013
1014 out:
1015 return err_code;
1016}
1017
Willy Tarreau8fed9032014-07-03 17:02:46 +02001018/* Prepares a stktable_key from a sample <smp> to search into table <t>.
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001019 * Note that the sample *is* modified and that the returned key may point
1020 * to it, so the sample must not be modified afterwards before the lookup.
Willy Tarreau8fed9032014-07-03 17:02:46 +02001021 * Returns NULL if the sample could not be converted (eg: no matching type),
1022 * otherwise a pointer to the static stktable_key filled with what is needed
1023 * for the lookup.
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001024 */
Willy Tarreau8fed9032014-07-03 17:02:46 +02001025struct stktable_key *smp_to_stkey(struct sample *smp, struct stktable *t)
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001026{
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001027 /* Convert sample. */
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +02001028 if (!sample_convert(smp, t->type))
Willy Tarreau7fc1c6e2012-04-26 11:03:17 +02001029 return NULL;
1030
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001031 /* Fill static_table_key. */
1032 switch (t->type) {
Emeric Brun485479d2010-09-23 18:02:19 +02001033
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +02001034 case SMP_T_IPV4:
Christopher Fauletca20d022017-08-29 15:30:31 +02001035 static_table_key.key = &smp->data.u.ipv4;
1036 static_table_key.key_len = 4;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001037 break;
Emeric Brun485479d2010-09-23 18:02:19 +02001038
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +02001039 case SMP_T_IPV6:
Christopher Fauletca20d022017-08-29 15:30:31 +02001040 static_table_key.key = &smp->data.u.ipv6;
1041 static_table_key.key_len = 16;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001042 break;
Emeric Brun485479d2010-09-23 18:02:19 +02001043
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +02001044 case SMP_T_SINT:
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001045 /* The stick table require a 32bit unsigned int, "sint" is a
1046 * signed 64 it, so we can convert it inplace.
1047 */
Willy Tarreau28c63c12019-10-23 06:21:05 +02001048 smp->data.u.sint = (unsigned int)smp->data.u.sint;
Christopher Fauletca20d022017-08-29 15:30:31 +02001049 static_table_key.key = &smp->data.u.sint;
1050 static_table_key.key_len = 4;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001051 break;
1052
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +02001053 case SMP_T_STR:
Willy Tarreauce6955e2016-08-09 11:59:12 +02001054 if (!smp_make_safe(smp))
1055 return NULL;
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001056 static_table_key.key = smp->data.u.str.area;
1057 static_table_key.key_len = smp->data.u.str.data;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001058 break;
Emeric Brun485479d2010-09-23 18:02:19 +02001059
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +02001060 case SMP_T_BIN:
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001061 if (smp->data.u.str.data < t->key_size) {
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001062 /* This type needs padding with 0. */
Willy Tarreauf65c6c02016-08-09 12:08:41 +02001063 if (!smp_make_rw(smp))
1064 return NULL;
1065
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001066 if (smp->data.u.str.size < t->key_size)
1067 if (!smp_dup(smp))
1068 return NULL;
1069 if (smp->data.u.str.size < t->key_size)
1070 return NULL;
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001071 memset(smp->data.u.str.area + smp->data.u.str.data, 0,
1072 t->key_size - smp->data.u.str.data);
1073 smp->data.u.str.data = t->key_size;
Emeric Brun485479d2010-09-23 18:02:19 +02001074 }
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001075 static_table_key.key = smp->data.u.str.area;
1076 static_table_key.key_len = smp->data.u.str.data;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001077 break;
Emeric Brun485479d2010-09-23 18:02:19 +02001078
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001079 default: /* impossible case. */
1080 return NULL;
Emeric Brun485479d2010-09-23 18:02:19 +02001081 }
1082
Christopher Fauletca20d022017-08-29 15:30:31 +02001083 return &static_table_key;
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001084}
1085
1086/*
Willy Tarreau8fed9032014-07-03 17:02:46 +02001087 * Process a fetch + format conversion as defined by the sample expression <expr>
1088 * on request or response considering the <opt> parameter. Returns either NULL if
1089 * no key could be extracted, or a pointer to the converted result stored in
1090 * static_table_key in format <table_type>. If <smp> is not NULL, it will be reset
1091 * and its flags will be initialized so that the caller gets a copy of the input
Willy Tarreau6bcb0a82014-07-30 08:56:35 +02001092 * sample, and knows why it was not accepted (eg: SMP_F_MAY_CHANGE is present
1093 * without SMP_OPT_FINAL). The output will be usable like this :
1094 *
1095 * return MAY_CHANGE FINAL Meaning for the sample
1096 * NULL 0 * Not present and will never be (eg: header)
1097 * NULL 1 0 Not present or unstable, could change (eg: req_len)
1098 * NULL 1 1 Not present, will not change anymore
1099 * smp 0 * Present and will not change (eg: header)
1100 * smp 1 0 not possible
1101 * smp 1 1 Present, last known value (eg: request length)
Willy Tarreau8fed9032014-07-03 17:02:46 +02001102 */
Willy Tarreau192252e2015-04-04 01:47:55 +02001103struct stktable_key *stktable_fetch_key(struct stktable *t, struct proxy *px, struct session *sess, struct stream *strm,
Willy Tarreau8fed9032014-07-03 17:02:46 +02001104 unsigned int opt, struct sample_expr *expr, struct sample *smp)
1105{
1106 if (smp)
1107 memset(smp, 0, sizeof(*smp));
1108
Willy Tarreau192252e2015-04-04 01:47:55 +02001109 smp = sample_process(px, sess, strm, opt, expr, smp);
Willy Tarreau8fed9032014-07-03 17:02:46 +02001110 if (!smp)
1111 return NULL;
1112
1113 if ((smp->flags & SMP_F_MAY_CHANGE) && !(opt & SMP_OPT_FINAL))
1114 return NULL; /* we can only use stable samples */
1115
1116 return smp_to_stkey(smp, t);
1117}
1118
1119/*
Willy Tarreau12785782012-04-27 21:37:17 +02001120 * Returns 1 if sample expression <expr> result can be converted to table key of
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001121 * type <table_type>, otherwise zero. Used in configuration check.
1122 */
Willy Tarreau12785782012-04-27 21:37:17 +02001123int stktable_compatible_sample(struct sample_expr *expr, unsigned long table_type)
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001124{
Thierry FOURNIERf73eb8f2013-11-27 15:30:55 +01001125 int out_type;
1126
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +02001127 if (table_type >= SMP_TYPES || !stktable_types[table_type].kw)
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001128 return 0;
1129
Thierry FOURNIERf73eb8f2013-11-27 15:30:55 +01001130 out_type = smp_expr_output_type(expr);
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001131
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001132 /* Convert sample. */
1133 if (!sample_casts[out_type][table_type])
Thierry FOURNIERf73eb8f2013-11-27 15:30:55 +01001134 return 0;
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001135
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001136 return 1;
1137}
Emeric Brun3bd697e2010-01-04 15:23:48 +01001138
Willy Tarreauedee1d62014-07-15 16:44:27 +02001139/* Extra data types processing : after the last one, some room may remain
1140 * before STKTABLE_DATA_TYPES that may be used to register extra data types
1141 * at run time.
1142 */
Willy Tarreau08d5f982010-06-06 13:34:54 +02001143struct stktable_data_type stktable_data_types[STKTABLE_DATA_TYPES] = {
Willy Tarreau3b9c6e02010-07-18 08:04:30 +02001144 [STKTABLE_DT_SERVER_ID] = { .name = "server_id", .std_type = STD_T_SINT },
Thierry FOURNIER3cf11112015-07-28 08:57:05 +02001145 [STKTABLE_DT_GPT0] = { .name = "gpt0", .std_type = STD_T_UINT },
Willy Tarreau3b9c6e02010-07-18 08:04:30 +02001146 [STKTABLE_DT_GPC0] = { .name = "gpc0", .std_type = STD_T_UINT },
Willy Tarreauba2ffd12013-05-29 15:54:14 +02001147 [STKTABLE_DT_GPC0_RATE] = { .name = "gpc0_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
Willy Tarreau3b9c6e02010-07-18 08:04:30 +02001148 [STKTABLE_DT_CONN_CNT] = { .name = "conn_cnt", .std_type = STD_T_UINT },
1149 [STKTABLE_DT_CONN_RATE] = { .name = "conn_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
Willy Tarreaudb2ab822021-10-08 17:53:12 +02001150 [STKTABLE_DT_CONN_CUR] = { .name = "conn_cur", .std_type = STD_T_UINT, .is_local = 1 },
Willy Tarreau3b9c6e02010-07-18 08:04:30 +02001151 [STKTABLE_DT_SESS_CNT] = { .name = "sess_cnt", .std_type = STD_T_UINT },
1152 [STKTABLE_DT_SESS_RATE] = { .name = "sess_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
1153 [STKTABLE_DT_HTTP_REQ_CNT] = { .name = "http_req_cnt", .std_type = STD_T_UINT },
1154 [STKTABLE_DT_HTTP_REQ_RATE] = { .name = "http_req_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
1155 [STKTABLE_DT_HTTP_ERR_CNT] = { .name = "http_err_cnt", .std_type = STD_T_UINT },
1156 [STKTABLE_DT_HTTP_ERR_RATE] = { .name = "http_err_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
1157 [STKTABLE_DT_BYTES_IN_CNT] = { .name = "bytes_in_cnt", .std_type = STD_T_ULL },
1158 [STKTABLE_DT_BYTES_IN_RATE] = { .name = "bytes_in_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
1159 [STKTABLE_DT_BYTES_OUT_CNT] = { .name = "bytes_out_cnt", .std_type = STD_T_ULL },
1160 [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 +01001161 [STKTABLE_DT_GPC1] = { .name = "gpc1", .std_type = STD_T_UINT },
1162 [STKTABLE_DT_GPC1_RATE] = { .name = "gpc1_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
Thayne McCombs92149f92020-11-20 01:28:26 -07001163 [STKTABLE_DT_SERVER_KEY] = { .name = "server_key", .std_type = STD_T_DICT },
Willy Tarreau826f3ab2021-02-10 12:07:15 +01001164 [STKTABLE_DT_HTTP_FAIL_CNT] = { .name = "http_fail_cnt", .std_type = STD_T_UINT },
1165 [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 +02001166 [STKTABLE_DT_GPT] = { .name = "gpt", .std_type = STD_T_UINT, .is_array = 1 },
Emeric Brun4d7ada82021-06-30 19:04:16 +02001167 [STKTABLE_DT_GPC] = { .name = "gpc", .std_type = STD_T_UINT, .is_array = 1 },
1168 [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 +02001169};
1170
Willy Tarreauedee1d62014-07-15 16:44:27 +02001171/* Registers stick-table extra data type with index <idx>, name <name>, type
1172 * <std_type> and arg type <arg_type>. If the index is negative, the next free
1173 * index is automatically allocated. The allocated index is returned, or -1 if
1174 * no free index was found or <name> was already registered. The <name> is used
1175 * directly as a pointer, so if it's not stable, the caller must allocate it.
1176 */
1177int stktable_register_data_store(int idx, const char *name, int std_type, int arg_type)
1178{
1179 if (idx < 0) {
1180 for (idx = 0; idx < STKTABLE_DATA_TYPES; idx++) {
1181 if (!stktable_data_types[idx].name)
1182 break;
1183
1184 if (strcmp(stktable_data_types[idx].name, name) == 0)
1185 return -1;
1186 }
1187 }
1188
1189 if (idx >= STKTABLE_DATA_TYPES)
1190 return -1;
1191
1192 if (stktable_data_types[idx].name != NULL)
1193 return -1;
1194
1195 stktable_data_types[idx].name = name;
1196 stktable_data_types[idx].std_type = std_type;
1197 stktable_data_types[idx].arg_type = arg_type;
1198 return idx;
1199}
1200
Willy Tarreau08d5f982010-06-06 13:34:54 +02001201/*
1202 * Returns the data type number for the stktable_data_type whose name is <name>,
1203 * or <0 if not found.
1204 */
1205int stktable_get_data_type(char *name)
1206{
1207 int type;
1208
1209 for (type = 0; type < STKTABLE_DATA_TYPES; type++) {
Willy Tarreauedee1d62014-07-15 16:44:27 +02001210 if (!stktable_data_types[type].name)
1211 continue;
Willy Tarreau08d5f982010-06-06 13:34:54 +02001212 if (strcmp(name, stktable_data_types[type].name) == 0)
1213 return type;
1214 }
Thayne McCombs92149f92020-11-20 01:28:26 -07001215 /* For backwards compatibility */
1216 if (strcmp(name, "server_name") == 0)
1217 return STKTABLE_DT_SERVER_KEY;
Willy Tarreau08d5f982010-06-06 13:34:54 +02001218 return -1;
1219}
1220
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001221/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1222 * it up into this table. Returns true if found, false otherwise. The input
1223 * type is STR so that input samples are converted to string (since all types
1224 * can be converted to strings), then the function casts the string again into
1225 * the table's type. This is a double conversion, but in the future we might
1226 * support automatic input types to perform the cast on the fly.
1227 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001228static int sample_conv_in_table(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001229{
1230 struct stktable *t;
1231 struct stktable_key *key;
1232 struct stksess *ts;
1233
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001234 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001235
1236 key = smp_to_stkey(smp, t);
1237 if (!key)
1238 return 0;
1239
1240 ts = stktable_lookup_key(t, key);
1241
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001242 smp->data.type = SMP_T_BOOL;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001243 smp->data.u.sint = !!ts;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001244 smp->flags = SMP_F_VOL_TEST;
Willy Tarreau43e90352018-06-27 06:25:57 +02001245 stktable_release(t, ts);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001246 return 1;
1247}
1248
1249/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1250 * it up into this table. Returns the data rate received from clients in bytes/s
1251 * if the key is present in the table, otherwise zero, so that comparisons can
1252 * be easily performed. If the inspected parameter is not stored in the table,
1253 * <not found> is returned.
1254 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001255static int sample_conv_table_bytes_in_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001256{
1257 struct stktable *t;
1258 struct stktable_key *key;
1259 struct stksess *ts;
1260 void *ptr;
1261
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001262 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001263
1264 key = smp_to_stkey(smp, t);
1265 if (!key)
1266 return 0;
1267
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001268 ts = stktable_lookup_key(t, key);
1269
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001270 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001271 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001272 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001273
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001274 if (!ts) /* key not present */
1275 return 1;
1276
1277 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_IN_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001278 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001279 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Daniel Corbett3e60b112018-05-27 09:47:12 -04001280 t->data_arg[STKTABLE_DT_BYTES_IN_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001281
Daniel Corbett3e60b112018-05-27 09:47:12 -04001282 stktable_release(t, ts);
1283 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001284}
1285
1286/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1287 * it up into this table. Returns the cumulated number of connections for the key
1288 * if the key is present in the table, otherwise zero, so that comparisons can
1289 * be easily performed. If the inspected parameter is not stored in the table,
1290 * <not found> is returned.
1291 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001292static int sample_conv_table_conn_cnt(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001293{
1294 struct stktable *t;
1295 struct stktable_key *key;
1296 struct stksess *ts;
1297 void *ptr;
1298
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001299 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001300
1301 key = smp_to_stkey(smp, t);
1302 if (!key)
1303 return 0;
1304
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001305 ts = stktable_lookup_key(t, key);
1306
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001307 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001308 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001309 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001310
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001311 if (!ts) /* key not present */
1312 return 1;
1313
1314 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_CONN_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001315 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001316 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001317
Daniel Corbett3e60b112018-05-27 09:47:12 -04001318 stktable_release(t, ts);
1319 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001320}
1321
1322/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1323 * it up into this table. Returns the number of concurrent connections for the
1324 * key if the key is present in the table, otherwise zero, so that comparisons
1325 * can be easily performed. If the inspected parameter is not stored in the
1326 * table, <not found> is returned.
1327 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001328static int sample_conv_table_conn_cur(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001329{
1330 struct stktable *t;
1331 struct stktable_key *key;
1332 struct stksess *ts;
1333 void *ptr;
1334
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001335 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001336
1337 key = smp_to_stkey(smp, t);
1338 if (!key)
1339 return 0;
1340
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001341 ts = stktable_lookup_key(t, key);
1342
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001343 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001344 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001345 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001346
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001347 if (!ts) /* key not present */
1348 return 1;
1349
1350 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_CONN_CUR);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001351 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001352 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001353
Daniel Corbett3e60b112018-05-27 09:47:12 -04001354 stktable_release(t, ts);
1355 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001356}
1357
1358/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1359 * it up into this table. Returns the rate of incoming connections from the key
1360 * if the key is present in the table, otherwise zero, so that comparisons can
1361 * be easily performed. If the inspected parameter is not stored in the table,
1362 * <not found> is returned.
1363 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001364static int sample_conv_table_conn_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001365{
1366 struct stktable *t;
1367 struct stktable_key *key;
1368 struct stksess *ts;
1369 void *ptr;
1370
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001371 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001372
1373 key = smp_to_stkey(smp, t);
1374 if (!key)
1375 return 0;
1376
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001377 ts = stktable_lookup_key(t, key);
1378
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001379 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001380 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001381 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001382
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001383 if (!ts) /* key not present */
1384 return 1;
1385
1386 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_CONN_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001387 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001388 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Daniel Corbett3e60b112018-05-27 09:47:12 -04001389 t->data_arg[STKTABLE_DT_CONN_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001390
Daniel Corbett3e60b112018-05-27 09:47:12 -04001391 stktable_release(t, ts);
1392 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001393}
1394
1395/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Frédéric Lécaillebbeec372022-08-16 18:11:25 +02001396 * it up into this table. Returns the expiration delay for the key if the key is
1397 * present in the table, otherwise the default value provided as second argument
1398 * if any, if not (no default value), <not found> is returned.
1399 */
1400static int sample_conv_table_expire(const struct arg *arg_p, struct sample *smp, void *private)
1401{
1402 struct stktable *t;
1403 struct stktable_key *key;
1404 struct stksess *ts;
1405
1406 t = arg_p[0].data.t;
1407
1408 key = smp_to_stkey(smp, t);
1409 if (!key)
1410 return 0;
1411
1412 ts = stktable_lookup_key(t, key);
1413
1414 smp->flags = SMP_F_VOL_TEST;
1415 smp->data.type = SMP_T_SINT;
1416 smp->data.u.sint = 0;
1417
1418 if (!ts) { /* key not present */
1419 if (arg_p[1].type == ARGT_STOP)
1420 return 0;
1421
1422 /* default value */
1423 smp->data.u.sint = arg_p[1].data.sint;
1424 return 1;
1425 }
1426
1427 smp->data.u.sint = tick_remain(now_ms, ts->expire);
1428
1429 stktable_release(t, ts);
1430 return 1;
1431}
1432
1433/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1434 * it up into this table. Returns the time the key remains unused if the key is
1435 * present in the table, otherwise the default value provided as second argument
1436 * if any, if not (no default value), <not found> is returned.
1437 */
1438static int sample_conv_table_idle(const struct arg *arg_p, struct sample *smp, void *private)
1439{
1440 struct stktable *t;
1441 struct stktable_key *key;
1442 struct stksess *ts;
1443
1444 t = arg_p[0].data.t;
1445
1446 key = smp_to_stkey(smp, t);
1447 if (!key)
1448 return 0;
1449
1450 ts = stktable_lookup_key(t, key);
1451
1452 smp->flags = SMP_F_VOL_TEST;
1453 smp->data.type = SMP_T_SINT;
1454 smp->data.u.sint = 0;
1455
1456 if (!ts) { /* key not present */
1457 if (arg_p[1].type == ARGT_STOP)
1458 return 0;
1459
1460 /* default value */
1461 smp->data.u.sint = arg_p[1].data.sint;
1462 return 1;
1463 }
1464
1465 smp->data.u.sint = tick_remain(tick_remain(now_ms, ts->expire), t->expire);
1466
1467 stktable_release(t, ts);
1468 return 1;
1469}
1470
1471/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001472 * it up into this table. Returns the data rate sent to clients in bytes/s
1473 * if the key is present in the table, otherwise zero, so that comparisons can
1474 * be easily performed. If the inspected parameter is not stored in the table,
1475 * <not found> is returned.
1476 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001477static int sample_conv_table_bytes_out_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001478{
1479 struct stktable *t;
1480 struct stktable_key *key;
1481 struct stksess *ts;
1482 void *ptr;
1483
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001484 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001485
1486 key = smp_to_stkey(smp, t);
1487 if (!key)
1488 return 0;
1489
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001490 ts = stktable_lookup_key(t, key);
1491
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001492 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001493 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001494 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001495
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001496 if (!ts) /* key not present */
1497 return 1;
1498
1499 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_OUT_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001500 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001501 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Daniel Corbett3e60b112018-05-27 09:47:12 -04001502 t->data_arg[STKTABLE_DT_BYTES_OUT_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001503
Daniel Corbett3e60b112018-05-27 09:47:12 -04001504 stktable_release(t, ts);
1505 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001506}
1507
Emeric Brun877b0b52021-06-30 18:57:49 +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 GPT[arg_p(0)] tag for the key
1510 * if the key is present in the table, otherwise false, 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_gpt(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_GPT, 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
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001547/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001548 * it up into this table. Returns the value of the GPT0 tag for the key
1549 * if the key is present in the table, otherwise false, so that comparisons can
1550 * be easily performed. If the inspected parameter is not stored in the table,
1551 * <not found> is returned.
1552 */
1553static int sample_conv_table_gpt0(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
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001560 t = arg_p[0].data.t;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001561
1562 key = smp_to_stkey(smp, t);
1563 if (!key)
1564 return 0;
1565
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001566 ts = stktable_lookup_key(t, key);
1567
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001568 smp->flags = SMP_F_VOL_TEST;
1569 smp->data.type = SMP_T_SINT;
1570 smp->data.u.sint = 0;
1571
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001572 if (!ts) /* key not present */
1573 return 1;
1574
1575 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPT0);
Emeric Brunf7ab0bf2021-06-30 18:58:22 +02001576 if (!ptr)
1577 ptr = stktable_data_ptr_idx(t, ts, STKTABLE_DT_GPT, 0);
1578
Daniel Corbett3e60b112018-05-27 09:47:12 -04001579 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001580 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001581
Daniel Corbett3e60b112018-05-27 09:47:12 -04001582 stktable_release(t, ts);
1583 return !!ptr;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001584}
1585
Emeric Brun4d7ada82021-06-30 19:04:16 +02001586/* Casts sample <smp> to the type of the table specified in arg_p(1), and looks
1587 * it up into this table. Returns the value of the GPC[arg_p(0)] counter for the key
1588 * if the key is present in the table, otherwise zero, so that comparisons can
1589 * be easily performed. If the inspected parameter is not stored in the table,
1590 * <not found> is returned.
1591 */
1592static int sample_conv_table_gpc(const struct arg *arg_p, struct sample *smp, void *private)
1593{
1594 struct stktable *t;
1595 struct stktable_key *key;
1596 struct stksess *ts;
1597 void *ptr;
1598 unsigned int idx;
1599
1600 idx = arg_p[0].data.sint;
1601
1602 t = arg_p[1].data.t;
1603
1604 key = smp_to_stkey(smp, t);
1605 if (!key)
1606 return 0;
1607
1608 ts = stktable_lookup_key(t, key);
1609
1610 smp->flags = SMP_F_VOL_TEST;
1611 smp->data.type = SMP_T_SINT;
1612 smp->data.u.sint = 0;
1613
1614 if (!ts) /* key not present */
1615 return 1;
1616
1617 ptr = stktable_data_ptr_idx(t, ts, STKTABLE_DT_GPC, idx);
1618 if (ptr)
1619 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
1620
1621 stktable_release(t, ts);
1622 return !!ptr;
1623}
1624
1625/* Casts sample <smp> to the type of the table specified in arg_p(1), and looks
1626 * it up into this table. Returns the event rate of the GPC[arg_p(0)] counter
1627 * for the key if the key is present in the table, otherwise zero, so that
1628 * comparisons can be easily performed. If the inspected parameter is not
1629 * stored in the table, <not found> is returned.
1630 */
1631static int sample_conv_table_gpc_rate(const struct arg *arg_p, struct sample *smp, void *private)
1632{
1633 struct stktable *t;
1634 struct stktable_key *key;
1635 struct stksess *ts;
1636 void *ptr;
1637 unsigned int idx;
1638
1639 idx = arg_p[0].data.sint;
1640
1641 t = arg_p[1].data.t;
1642
1643 key = smp_to_stkey(smp, t);
1644 if (!key)
1645 return 0;
1646
1647 ts = stktable_lookup_key(t, key);
1648
1649 smp->flags = SMP_F_VOL_TEST;
1650 smp->data.type = SMP_T_SINT;
1651 smp->data.u.sint = 0;
1652
1653 if (!ts) /* key not present */
1654 return 1;
1655
1656 ptr = stktable_data_ptr_idx(t, ts, STKTABLE_DT_GPC_RATE, idx);
1657 if (ptr)
1658 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
1659 t->data_arg[STKTABLE_DT_GPC_RATE].u);
1660
1661 stktable_release(t, ts);
1662 return !!ptr;
1663}
1664
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001665/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001666 * it up into this table. Returns the value of the GPC0 counter for the key
1667 * if the key is present in the table, otherwise zero, so that comparisons can
1668 * be easily performed. If the inspected parameter is not stored in the table,
1669 * <not found> is returned.
1670 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001671static int sample_conv_table_gpc0(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001672{
1673 struct stktable *t;
1674 struct stktable_key *key;
1675 struct stksess *ts;
1676 void *ptr;
1677
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001678 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001679
1680 key = smp_to_stkey(smp, t);
1681 if (!key)
1682 return 0;
1683
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001684 ts = stktable_lookup_key(t, key);
1685
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001686 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001687 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001688 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001689
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001690 if (!ts) /* key not present */
1691 return 1;
1692
1693 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPC0);
Emeric Brun726783d2021-06-30 19:06:43 +02001694 if (!ptr) {
1695 /* fallback on the gpc array */
1696 ptr = stktable_data_ptr_idx(t, ts, STKTABLE_DT_GPC, 0);
1697 }
1698
Daniel Corbett3e60b112018-05-27 09:47:12 -04001699 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001700 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001701
Daniel Corbett3e60b112018-05-27 09:47:12 -04001702 stktable_release(t, ts);
1703 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001704}
1705
1706/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1707 * it up into this table. Returns the event rate of the GPC0 counter for the key
1708 * if the key is present in the table, otherwise zero, so that comparisons can
1709 * be easily performed. If the inspected parameter is not stored in the table,
1710 * <not found> is returned.
1711 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001712static int sample_conv_table_gpc0_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001713{
1714 struct stktable *t;
1715 struct stktable_key *key;
1716 struct stksess *ts;
1717 void *ptr;
1718
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001719 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001720
1721 key = smp_to_stkey(smp, t);
1722 if (!key)
1723 return 0;
1724
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001725 ts = stktable_lookup_key(t, key);
1726
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001727 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001728 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001729 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001730
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001731 if (!ts) /* key not present */
1732 return 1;
1733
1734 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPC0_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001735 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001736 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Daniel Corbett3e60b112018-05-27 09:47:12 -04001737 t->data_arg[STKTABLE_DT_GPC0_RATE].u);
Emeric Brun726783d2021-06-30 19:06:43 +02001738 else {
1739 /* fallback on the gpc array */
1740 ptr = stktable_data_ptr_idx(t, ts, STKTABLE_DT_GPC_RATE, 0);
1741 if (ptr)
1742 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
1743 t->data_arg[STKTABLE_DT_GPC_RATE].u);
1744 }
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001745
Daniel Corbett3e60b112018-05-27 09:47:12 -04001746 stktable_release(t, ts);
1747 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001748}
1749
1750/* 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 +01001751 * it up into this table. Returns the value of the GPC1 counter for the key
1752 * if the key is present in the table, otherwise zero, so that comparisons can
1753 * be easily performed. If the inspected parameter is not stored in the table,
1754 * <not found> is returned.
1755 */
1756static int sample_conv_table_gpc1(const struct arg *arg_p, struct sample *smp, void *private)
1757{
1758 struct stktable *t;
1759 struct stktable_key *key;
1760 struct stksess *ts;
1761 void *ptr;
1762
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001763 t = arg_p[0].data.t;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001764
1765 key = smp_to_stkey(smp, t);
1766 if (!key)
1767 return 0;
1768
1769 ts = stktable_lookup_key(t, key);
1770
1771 smp->flags = SMP_F_VOL_TEST;
1772 smp->data.type = SMP_T_SINT;
1773 smp->data.u.sint = 0;
1774
1775 if (!ts) /* key not present */
1776 return 1;
1777
1778 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPC1);
Emeric Brun726783d2021-06-30 19:06:43 +02001779 if (!ptr) {
1780 /* fallback on the gpc array */
1781 ptr = stktable_data_ptr_idx(t, ts, STKTABLE_DT_GPC, 1);
1782 }
1783
Daniel Corbett3e60b112018-05-27 09:47:12 -04001784 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001785 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001786
Daniel Corbett3e60b112018-05-27 09:47:12 -04001787 stktable_release(t, ts);
1788 return !!ptr;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001789}
1790
1791/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1792 * it up into this table. Returns the event rate of the GPC1 counter for the key
1793 * if the key is present in the table, otherwise zero, so that comparisons can
1794 * be easily performed. If the inspected parameter is not stored in the table,
1795 * <not found> is returned.
1796 */
1797static int sample_conv_table_gpc1_rate(const struct arg *arg_p, struct sample *smp, void *private)
1798{
1799 struct stktable *t;
1800 struct stktable_key *key;
1801 struct stksess *ts;
1802 void *ptr;
1803
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001804 t = arg_p[0].data.t;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001805
1806 key = smp_to_stkey(smp, t);
1807 if (!key)
1808 return 0;
1809
1810 ts = stktable_lookup_key(t, key);
1811
1812 smp->flags = SMP_F_VOL_TEST;
1813 smp->data.type = SMP_T_SINT;
1814 smp->data.u.sint = 0;
1815
1816 if (!ts) /* key not present */
1817 return 1;
1818
1819 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPC1_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001820 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001821 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Daniel Corbett3e60b112018-05-27 09:47:12 -04001822 t->data_arg[STKTABLE_DT_GPC1_RATE].u);
Emeric Brun726783d2021-06-30 19:06:43 +02001823 else {
1824 /* fallback on the gpc array */
1825 ptr = stktable_data_ptr_idx(t, ts, STKTABLE_DT_GPC_RATE, 1);
1826 if (ptr)
1827 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
1828 t->data_arg[STKTABLE_DT_GPC_RATE].u);
1829 }
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001830
Daniel Corbett3e60b112018-05-27 09:47:12 -04001831 stktable_release(t, ts);
1832 return !!ptr;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001833}
1834
1835/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001836 * it up into this table. Returns the cumulated number of HTTP request errors
1837 * for the key if the key is present in the table, otherwise zero, so that
1838 * comparisons can be easily performed. If the inspected parameter is not stored
1839 * in the table, <not found> is returned.
1840 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001841static int sample_conv_table_http_err_cnt(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001842{
1843 struct stktable *t;
1844 struct stktable_key *key;
1845 struct stksess *ts;
1846 void *ptr;
1847
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001848 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001849
1850 key = smp_to_stkey(smp, t);
1851 if (!key)
1852 return 0;
1853
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001854 ts = stktable_lookup_key(t, key);
1855
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001856 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001857 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001858 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001859
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001860 if (!ts) /* key not present */
1861 return 1;
1862
1863 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_ERR_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001864 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001865 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001866
Daniel Corbett3e60b112018-05-27 09:47:12 -04001867 stktable_release(t, ts);
1868 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001869}
1870
1871/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1872 * it up into this table. Returns the HTTP request error rate the key
1873 * if the key is present in the table, otherwise zero, so that comparisons can
1874 * be easily performed. If the inspected parameter is not stored in the table,
1875 * <not found> is returned.
1876 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001877static int sample_conv_table_http_err_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001878{
1879 struct stktable *t;
1880 struct stktable_key *key;
1881 struct stksess *ts;
1882 void *ptr;
1883
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001884 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001885
1886 key = smp_to_stkey(smp, t);
1887 if (!key)
1888 return 0;
1889
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001890 ts = stktable_lookup_key(t, key);
1891
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001892 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001893 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001894 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001895
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001896 if (!ts) /* key not present */
1897 return 1;
1898
1899 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_ERR_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001900 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001901 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Daniel Corbett3e60b112018-05-27 09:47:12 -04001902 t->data_arg[STKTABLE_DT_HTTP_ERR_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001903
Daniel Corbett3e60b112018-05-27 09:47:12 -04001904 stktable_release(t, ts);
1905 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001906}
1907
1908/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Willy Tarreau826f3ab2021-02-10 12:07:15 +01001909 * it up into this table. Returns the cumulated number of HTTP response failures
1910 * for the key if the key is present in the table, otherwise zero, so that
1911 * comparisons can be easily performed. If the inspected parameter is not stored
1912 * in the table, <not found> is returned.
1913 */
1914static int sample_conv_table_http_fail_cnt(const struct arg *arg_p, struct sample *smp, void *private)
1915{
1916 struct stktable *t;
1917 struct stktable_key *key;
1918 struct stksess *ts;
1919 void *ptr;
1920
1921 t = arg_p[0].data.t;
1922
1923 key = smp_to_stkey(smp, t);
1924 if (!key)
1925 return 0;
1926
1927 ts = stktable_lookup_key(t, key);
1928
1929 smp->flags = SMP_F_VOL_TEST;
1930 smp->data.type = SMP_T_SINT;
1931 smp->data.u.sint = 0;
1932
1933 if (!ts) /* key not present */
1934 return 1;
1935
1936 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_FAIL_CNT);
1937 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001938 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Willy Tarreau826f3ab2021-02-10 12:07:15 +01001939
1940 stktable_release(t, ts);
1941 return !!ptr;
1942}
1943
1944/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1945 * it up into this table. Returns the HTTP response failure rate for the key
1946 * if the key is present in the table, otherwise zero, so that comparisons can
1947 * be easily performed. If the inspected parameter is not stored in the table,
1948 * <not found> is returned.
1949 */
1950static int sample_conv_table_http_fail_rate(const struct arg *arg_p, struct sample *smp, void *private)
1951{
1952 struct stktable *t;
1953 struct stktable_key *key;
1954 struct stksess *ts;
1955 void *ptr;
1956
1957 t = arg_p[0].data.t;
1958
1959 key = smp_to_stkey(smp, t);
1960 if (!key)
1961 return 0;
1962
1963 ts = stktable_lookup_key(t, key);
1964
1965 smp->flags = SMP_F_VOL_TEST;
1966 smp->data.type = SMP_T_SINT;
1967 smp->data.u.sint = 0;
1968
1969 if (!ts) /* key not present */
1970 return 1;
1971
1972 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_FAIL_RATE);
1973 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001974 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Willy Tarreau826f3ab2021-02-10 12:07:15 +01001975 t->data_arg[STKTABLE_DT_HTTP_FAIL_RATE].u);
1976
1977 stktable_release(t, ts);
1978 return !!ptr;
1979}
1980
1981/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001982 * it up into this table. Returns the cumulated number of HTTP request for the
1983 * key if the key is present in the table, otherwise zero, so that comparisons
1984 * can be easily performed. If the inspected parameter is not stored in the
1985 * table, <not found> is returned.
1986 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001987static int sample_conv_table_http_req_cnt(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001988{
1989 struct stktable *t;
1990 struct stktable_key *key;
1991 struct stksess *ts;
1992 void *ptr;
1993
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001994 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001995
1996 key = smp_to_stkey(smp, t);
1997 if (!key)
1998 return 0;
1999
Willy Tarreauf0c730a2016-05-25 17:07:56 +02002000 ts = stktable_lookup_key(t, key);
2001
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002002 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02002003 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02002004 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002005
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002006 if (!ts) /* key not present */
2007 return 1;
2008
2009 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_REQ_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04002010 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002011 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002012
Daniel Corbett3e60b112018-05-27 09:47:12 -04002013 stktable_release(t, ts);
2014 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002015}
2016
2017/* Casts sample <smp> to the type of the table specified in arg(0), and looks
2018 * it up into this table. Returns the HTTP request rate the key if the key is
2019 * present in the table, otherwise zero, so that comparisons can be easily
2020 * performed. If the inspected parameter is not stored in the table, <not found>
2021 * is returned.
2022 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02002023static int sample_conv_table_http_req_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002024{
2025 struct stktable *t;
2026 struct stktable_key *key;
2027 struct stksess *ts;
2028 void *ptr;
2029
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002030 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002031
2032 key = smp_to_stkey(smp, t);
2033 if (!key)
2034 return 0;
2035
Willy Tarreauf0c730a2016-05-25 17:07:56 +02002036 ts = stktable_lookup_key(t, key);
2037
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002038 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02002039 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02002040 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002041
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002042 if (!ts) /* key not present */
2043 return 1;
2044
2045 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_REQ_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04002046 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002047 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Daniel Corbett3e60b112018-05-27 09:47:12 -04002048 t->data_arg[STKTABLE_DT_HTTP_REQ_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002049
Daniel Corbett3e60b112018-05-27 09:47:12 -04002050 stktable_release(t, ts);
2051 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002052}
2053
2054/* Casts sample <smp> to the type of the table specified in arg(0), and looks
2055 * it up into this table. Returns the volume of datareceived from clients in kbytes
2056 * if the key is present in the table, otherwise zero, so that comparisons can
2057 * be easily performed. If the inspected parameter is not stored in the table,
2058 * <not found> is returned.
2059 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02002060static int sample_conv_table_kbytes_in(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002061{
2062 struct stktable *t;
2063 struct stktable_key *key;
2064 struct stksess *ts;
2065 void *ptr;
2066
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002067 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002068
2069 key = smp_to_stkey(smp, t);
2070 if (!key)
2071 return 0;
2072
Willy Tarreauf0c730a2016-05-25 17:07:56 +02002073 ts = stktable_lookup_key(t, key);
2074
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002075 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02002076 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02002077 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002078
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002079 if (!ts) /* key not present */
2080 return 1;
2081
2082 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_IN_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04002083 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002084 smp->data.u.sint = stktable_data_cast(ptr, std_t_ull) >> 10;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002085
Daniel Corbett3e60b112018-05-27 09:47:12 -04002086 stktable_release(t, ts);
2087 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002088}
2089
2090/* Casts sample <smp> to the type of the table specified in arg(0), and looks
2091 * it up into this table. Returns the volume of data sent to clients in kbytes
2092 * if the key is present in the table, otherwise zero, so that comparisons can
2093 * be easily performed. If the inspected parameter is not stored in the table,
2094 * <not found> is returned.
2095 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02002096static int sample_conv_table_kbytes_out(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002097{
2098 struct stktable *t;
2099 struct stktable_key *key;
2100 struct stksess *ts;
2101 void *ptr;
2102
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002103 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002104
2105 key = smp_to_stkey(smp, t);
2106 if (!key)
2107 return 0;
2108
Willy Tarreauf0c730a2016-05-25 17:07:56 +02002109 ts = stktable_lookup_key(t, key);
2110
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002111 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02002112 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02002113 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002114
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002115 if (!ts) /* key not present */
2116 return 1;
2117
2118 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_OUT_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04002119 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002120 smp->data.u.sint = stktable_data_cast(ptr, std_t_ull) >> 10;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002121
Daniel Corbett3e60b112018-05-27 09:47:12 -04002122 stktable_release(t, ts);
2123 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002124}
2125
2126/* Casts sample <smp> to the type of the table specified in arg(0), and looks
2127 * it up into this table. Returns the server ID associated with the key if the
2128 * key is present in the table, otherwise zero, so that comparisons can be
2129 * easily performed. If the inspected parameter is not stored in the table,
2130 * <not found> is returned.
2131 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02002132static int sample_conv_table_server_id(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002133{
2134 struct stktable *t;
2135 struct stktable_key *key;
2136 struct stksess *ts;
2137 void *ptr;
2138
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002139 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002140
2141 key = smp_to_stkey(smp, t);
2142 if (!key)
2143 return 0;
2144
Willy Tarreauf0c730a2016-05-25 17:07:56 +02002145 ts = stktable_lookup_key(t, key);
2146
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002147 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02002148 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02002149 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002150
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002151 if (!ts) /* key not present */
2152 return 1;
2153
2154 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_SERVER_ID);
Daniel Corbett3e60b112018-05-27 09:47:12 -04002155 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002156 smp->data.u.sint = stktable_data_cast(ptr, std_t_sint);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002157
Daniel Corbett3e60b112018-05-27 09:47:12 -04002158 stktable_release(t, ts);
2159 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002160}
2161
2162/* Casts sample <smp> to the type of the table specified in arg(0), and looks
2163 * it up into this table. Returns the cumulated number of sessions for the
2164 * key if the key is present in the table, otherwise zero, so that comparisons
2165 * can be easily performed. If the inspected parameter is not stored in the
2166 * table, <not found> is returned.
2167 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02002168static int sample_conv_table_sess_cnt(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002169{
2170 struct stktable *t;
2171 struct stktable_key *key;
2172 struct stksess *ts;
2173 void *ptr;
2174
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002175 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002176
2177 key = smp_to_stkey(smp, t);
2178 if (!key)
2179 return 0;
2180
Willy Tarreauf0c730a2016-05-25 17:07:56 +02002181 ts = stktable_lookup_key(t, key);
2182
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002183 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02002184 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02002185 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002186
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002187 if (!ts) /* key not present */
2188 return 1;
2189
2190 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_SESS_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04002191 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002192 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002193
Daniel Corbett3e60b112018-05-27 09:47:12 -04002194 stktable_release(t, ts);
2195 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002196}
2197
2198/* Casts sample <smp> to the type of the table specified in arg(0), and looks
2199 * it up into this table. Returns the session rate the key if the key is
2200 * present in the table, otherwise zero, so that comparisons can be easily
2201 * performed. If the inspected parameter is not stored in the table, <not found>
2202 * is returned.
2203 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02002204static int sample_conv_table_sess_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002205{
2206 struct stktable *t;
2207 struct stktable_key *key;
2208 struct stksess *ts;
2209 void *ptr;
2210
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002211 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002212
2213 key = smp_to_stkey(smp, t);
2214 if (!key)
2215 return 0;
2216
Willy Tarreauf0c730a2016-05-25 17:07:56 +02002217 ts = stktable_lookup_key(t, key);
2218
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002219 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02002220 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02002221 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002222
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002223 if (!ts) /* key not present */
2224 return 1;
2225
2226 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_SESS_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04002227 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002228 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Daniel Corbett3e60b112018-05-27 09:47:12 -04002229 t->data_arg[STKTABLE_DT_SESS_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002230
Daniel Corbett3e60b112018-05-27 09:47:12 -04002231 stktable_release(t, ts);
2232 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002233}
2234
2235/* Casts sample <smp> to the type of the table specified in arg(0), and looks
2236 * it up into this table. Returns the amount of concurrent connections tracking
2237 * the same key if the key is present in the table, otherwise zero, so that
2238 * comparisons can be easily performed. If the inspected parameter is not
2239 * stored in the table, <not found> is returned.
2240 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02002241static int sample_conv_table_trackers(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002242{
2243 struct stktable *t;
2244 struct stktable_key *key;
2245 struct stksess *ts;
2246
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002247 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002248
2249 key = smp_to_stkey(smp, t);
2250 if (!key)
2251 return 0;
2252
Willy Tarreauf0c730a2016-05-25 17:07:56 +02002253 ts = stktable_lookup_key(t, key);
2254
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002255 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02002256 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02002257 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002258
Tim Duesterhus65189c12018-06-26 15:57:29 +02002259 if (!ts)
2260 return 1;
2261
2262 smp->data.u.sint = ts->ref_cnt;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002263
Daniel Corbett3e60b112018-05-27 09:47:12 -04002264 stktable_release(t, ts);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002265 return 1;
2266}
2267
Emeric Brun4d7ada82021-06-30 19:04:16 +02002268/* This function increments the gpc counter at index 'rule->arg.gpc.idx' of the
2269 * array on the tracksc counter of index 'rule->arg.gpc.sc' stored into the
2270 * <stream> or directly in the session <sess> if <stream> is set to NULL
2271 *
2272 * This function always returns ACT_RET_CONT and parameter flags is unused.
2273 */
2274static enum act_return action_inc_gpc(struct act_rule *rule, struct proxy *px,
2275 struct session *sess, struct stream *s, int flags)
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002276{
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002277 struct stksess *ts;
2278 struct stkctr *stkctr;
2279
2280 /* Extract the stksess, return OK if no stksess available. */
2281 if (s)
2282 stkctr = &s->stkctr[rule->arg.gpc.sc];
2283 else
2284 stkctr = &sess->stkctr[rule->arg.gpc.sc];
Willy Tarreau79c1e912016-01-25 14:54:45 +01002285
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002286 ts = stkctr_entry(stkctr);
Willy Tarreau79c1e912016-01-25 14:54:45 +01002287 if (ts) {
2288 void *ptr1, *ptr2;
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002289
Emeric Brun4d7ada82021-06-30 19:04:16 +02002290 /* First, update gpc_rate if it's tracked. Second, update its gpc if tracked. */
2291 ptr1 = stktable_data_ptr_idx(stkctr->table, ts, STKTABLE_DT_GPC_RATE, rule->arg.gpc.idx);
2292 ptr2 = stktable_data_ptr_idx(stkctr->table, ts, STKTABLE_DT_GPC, rule->arg.gpc.idx);
2293
Emeric Brun819fc6f2017-06-13 19:37:32 +02002294 if (ptr1 || ptr2) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002295 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002296
2297 if (ptr1)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002298 update_freq_ctr_period(&stktable_data_cast(ptr1, std_t_frqp),
Emeric Brun4d7ada82021-06-30 19:04:16 +02002299 stkctr->table->data_arg[STKTABLE_DT_GPC_RATE].u, 1);
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002300
Emeric Brun819fc6f2017-06-13 19:37:32 +02002301 if (ptr2)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002302 stktable_data_cast(ptr2, std_t_uint)++;
Willy Tarreau79c1e912016-01-25 14:54:45 +01002303
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002304 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002305
2306 /* If data was modified, we need to touch to re-schedule sync */
2307 stktable_touch_local(stkctr->table, ts, 0);
2308 }
Willy Tarreau79c1e912016-01-25 14:54:45 +01002309 }
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002310 return ACT_RET_CONT;
2311}
2312
Emeric Brun4d7ada82021-06-30 19:04:16 +02002313/* Same as action_inc_gpc() but for gpc0 only */
2314static enum act_return action_inc_gpc0(struct act_rule *rule, struct proxy *px,
2315 struct session *sess, struct stream *s, int flags)
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002316{
Emeric Brun4d7ada82021-06-30 19:04:16 +02002317 struct stksess *ts;
2318 struct stkctr *stkctr;
Willy Tarreau5b654ad2021-07-06 18:51:12 +02002319 unsigned int period = 0;
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002320
Emeric Brun4d7ada82021-06-30 19:04:16 +02002321 /* Extract the stksess, return OK if no stksess available. */
2322 if (s)
2323 stkctr = &s->stkctr[rule->arg.gpc.sc];
2324 else
2325 stkctr = &sess->stkctr[rule->arg.gpc.sc];
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002326
Emeric Brun4d7ada82021-06-30 19:04:16 +02002327 ts = stkctr_entry(stkctr);
2328 if (ts) {
2329 void *ptr1, *ptr2;
2330
2331 /* First, update gpc0_rate if it's tracked. Second, update its gpc0 if tracked. */
2332 ptr1 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC0_RATE);
Emeric Brun726783d2021-06-30 19:06:43 +02002333 if (ptr1) {
2334 period = stkctr->table->data_arg[STKTABLE_DT_GPC0_RATE].u;
2335 }
2336 else {
2337 /* fallback on the gpc array */
2338 ptr1 = stktable_data_ptr_idx(stkctr->table, ts, STKTABLE_DT_GPC_RATE, 0);
2339 if (ptr1)
2340 period = stkctr->table->data_arg[STKTABLE_DT_GPC_RATE].u;
2341 }
2342
Emeric Brun4d7ada82021-06-30 19:04:16 +02002343 ptr2 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC0);
Emeric Brun726783d2021-06-30 19:06:43 +02002344 if (!ptr2) {
2345 /* fallback on the gpc array */
2346 ptr2 = stktable_data_ptr_idx(stkctr->table, ts, STKTABLE_DT_GPC, 0);
2347 }
2348
Emeric Brun4d7ada82021-06-30 19:04:16 +02002349 if (ptr1 || ptr2) {
2350 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
2351
2352 if (ptr1)
2353 update_freq_ctr_period(&stktable_data_cast(ptr1, std_t_frqp),
Emeric Brun726783d2021-06-30 19:06:43 +02002354 period, 1);
Emeric Brun4d7ada82021-06-30 19:04:16 +02002355
2356 if (ptr2)
2357 stktable_data_cast(ptr2, std_t_uint)++;
2358
2359 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
2360
2361 /* If data was modified, we need to touch to re-schedule sync */
2362 stktable_touch_local(stkctr->table, ts, 0);
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002363 }
2364 }
Emeric Brun4d7ada82021-06-30 19:04:16 +02002365 return ACT_RET_CONT;
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002366}
2367
Emeric Brun4d7ada82021-06-30 19:04:16 +02002368/* Same as action_inc_gpc() but for gpc1 only */
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002369static enum act_return action_inc_gpc1(struct act_rule *rule, struct proxy *px,
2370 struct session *sess, struct stream *s, int flags)
2371{
2372 struct stksess *ts;
2373 struct stkctr *stkctr;
Willy Tarreau5b654ad2021-07-06 18:51:12 +02002374 unsigned int period = 0;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002375
2376 /* Extract the stksess, return OK if no stksess available. */
2377 if (s)
2378 stkctr = &s->stkctr[rule->arg.gpc.sc];
2379 else
2380 stkctr = &sess->stkctr[rule->arg.gpc.sc];
2381
2382 ts = stkctr_entry(stkctr);
2383 if (ts) {
2384 void *ptr1, *ptr2;
2385
2386 /* First, update gpc1_rate if it's tracked. Second, update its gpc1 if tracked. */
2387 ptr1 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC1_RATE);
Emeric Brun726783d2021-06-30 19:06:43 +02002388 if (ptr1) {
2389 period = stkctr->table->data_arg[STKTABLE_DT_GPC1_RATE].u;
2390 }
2391 else {
2392 /* fallback on the gpc array */
2393 ptr1 = stktable_data_ptr_idx(stkctr->table, ts, STKTABLE_DT_GPC_RATE, 1);
2394 if (ptr1)
2395 period = stkctr->table->data_arg[STKTABLE_DT_GPC_RATE].u;
2396 }
2397
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002398 ptr2 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC1);
Emeric Brun726783d2021-06-30 19:06:43 +02002399 if (!ptr2) {
2400 /* fallback on the gpc array */
2401 ptr2 = stktable_data_ptr_idx(stkctr->table, ts, STKTABLE_DT_GPC, 1);
2402 }
2403
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002404 if (ptr1 || ptr2) {
2405 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
2406
2407 if (ptr1)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002408 update_freq_ctr_period(&stktable_data_cast(ptr1, std_t_frqp),
Emeric Brun726783d2021-06-30 19:06:43 +02002409 period, 1);
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002410
2411 if (ptr2)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002412 stktable_data_cast(ptr2, std_t_uint)++;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002413
2414 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
2415
2416 /* If data was modified, we need to touch to re-schedule sync */
2417 stktable_touch_local(stkctr->table, ts, 0);
2418 }
2419 }
2420 return ACT_RET_CONT;
2421}
2422
Emeric Brun4d7ada82021-06-30 19:04:16 +02002423/* This function is a common parser for actions incrementing the GPC
2424 * (General Purpose Counters). It understands the formats:
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002425 *
Emeric Brun4d7ada82021-06-30 19:04:16 +02002426 * sc-inc-gpc(<gpc IDX>,<track ID>)
2427 * sc-inc-gpc0([<track ID>])
2428 * sc-inc-gpc1([<track ID>])
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002429 *
Emeric Brun4d7ada82021-06-30 19:04:16 +02002430 * It returns ACT_RET_PRS_ERR if fails and <err> is filled with an error
2431 * message. Otherwise it returns ACT_RET_PRS_OK.
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002432 */
Emeric Brun4d7ada82021-06-30 19:04:16 +02002433static enum act_parse_ret parse_inc_gpc(const char **args, int *arg, struct proxy *px,
2434 struct act_rule *rule, char **err)
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002435{
2436 const char *cmd_name = args[*arg-1];
2437 char *error;
2438
Emeric Brun4d7ada82021-06-30 19:04:16 +02002439 cmd_name += strlen("sc-inc-gpc");
2440 if (*cmd_name == '(') {
2441 cmd_name++; /* skip the '(' */
2442 rule->arg.gpc.idx = strtoul(cmd_name, &error, 10); /* Convert stick table id. */
2443 if (*error != ',') {
2444 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 +01002445 return ACT_RET_PRS_ERR;
2446 }
Emeric Brun4d7ada82021-06-30 19:04:16 +02002447 else {
2448 cmd_name = error + 1; /* skip the ',' */
2449 rule->arg.gpc.sc = strtol(cmd_name, &error, 10); /* Convert stick table id. */
2450 if (*error != ')') {
2451 memprintf(err, "invalid stick table track ID '%s'. Expects sc-inc-gpc(<GPC ID>,<Track ID>)", args[*arg-1]);
2452 return ACT_RET_PRS_ERR;
2453 }
2454
2455 if (rule->arg.gpc.sc >= MAX_SESS_STKCTR) {
2456 memprintf(err, "invalid stick table track ID '%s'. The max allowed ID is %d",
2457 args[*arg-1], MAX_SESS_STKCTR-1);
2458 return ACT_RET_PRS_ERR;
2459 }
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002460 }
Emeric Brun4d7ada82021-06-30 19:04:16 +02002461 rule->action_ptr = action_inc_gpc;
2462 }
2463 else if (*cmd_name == '0' ||*cmd_name == '1') {
2464 char c = *cmd_name;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002465
Emeric Brun4d7ada82021-06-30 19:04:16 +02002466 cmd_name++;
2467 if (*cmd_name == '\0') {
2468 /* default stick table id. */
2469 rule->arg.gpc.sc = 0;
2470 } else {
2471 /* parse the stick table id. */
2472 if (*cmd_name != '(') {
2473 memprintf(err, "invalid stick table track ID. Expects %s(<Track ID>)", args[*arg-1]);
2474 return ACT_RET_PRS_ERR;
2475 }
2476 cmd_name++; /* jump the '(' */
2477 rule->arg.gpc.sc = strtol(cmd_name, &error, 10); /* Convert stick table id. */
2478 if (*error != ')') {
2479 memprintf(err, "invalid stick table track ID. Expects %s(<Track ID>)", args[*arg-1]);
2480 return ACT_RET_PRS_ERR;
2481 }
2482
2483 if (rule->arg.gpc.sc >= MAX_SESS_STKCTR) {
2484 memprintf(err, "invalid stick table track ID. The max allowed ID is %d",
2485 MAX_SESS_STKCTR-1);
2486 return ACT_RET_PRS_ERR;
2487 }
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002488 }
Emeric Brun4d7ada82021-06-30 19:04:16 +02002489 if (c == '1')
2490 rule->action_ptr = action_inc_gpc1;
2491 else
2492 rule->action_ptr = action_inc_gpc0;
2493 }
2494 else {
2495 /* default stick table id. */
2496 memprintf(err, "invalid gpc ID '%s'. Expects sc-set-gpc(<GPC ID>,<Track ID>)", args[*arg-1]);
2497 return ACT_RET_PRS_ERR;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002498 }
2499 rule->action = ACT_CUSTOM;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002500 return ACT_RET_PRS_OK;
2501}
2502
Emeric Brun877b0b52021-06-30 18:57:49 +02002503/* This function sets the gpt at index 'rule->arg.gpt.idx' of the array on the
2504 * tracksc counter of index 'rule->arg.gpt.sc' stored into the <stream> or
2505 * directly in the session <sess> if <stream> is set to NULL. This gpt is
2506 * set to the value computed by the expression 'rule->arg.gpt.expr' or if
2507 * 'rule->arg.gpt.expr' is null directly to the value of 'rule->arg.gpt.value'.
2508 *
2509 * This function always returns ACT_RET_CONT and parameter flags is unused.
2510 */
2511static enum act_return action_set_gpt(struct act_rule *rule, struct proxy *px,
2512 struct session *sess, struct stream *s, int flags)
2513{
2514 void *ptr;
2515 struct stksess *ts;
2516 struct stkctr *stkctr;
2517 unsigned int value = 0;
2518 struct sample *smp;
2519 int smp_opt_dir;
2520
2521 /* Extract the stksess, return OK if no stksess available. */
2522 if (s)
2523 stkctr = &s->stkctr[rule->arg.gpt.sc];
2524 else
2525 stkctr = &sess->stkctr[rule->arg.gpt.sc];
2526
2527 ts = stkctr_entry(stkctr);
2528 if (!ts)
2529 return ACT_RET_CONT;
2530
2531 /* Store the sample in the required sc, and ignore errors. */
2532 ptr = stktable_data_ptr_idx(stkctr->table, ts, STKTABLE_DT_GPT, rule->arg.gpt.idx);
2533 if (ptr) {
2534
2535 if (!rule->arg.gpt.expr)
2536 value = (unsigned int)(rule->arg.gpt.value);
2537 else {
2538 switch (rule->from) {
2539 case ACT_F_TCP_REQ_SES: smp_opt_dir = SMP_OPT_DIR_REQ; break;
2540 case ACT_F_TCP_REQ_CNT: smp_opt_dir = SMP_OPT_DIR_REQ; break;
2541 case ACT_F_TCP_RES_CNT: smp_opt_dir = SMP_OPT_DIR_RES; break;
2542 case ACT_F_HTTP_REQ: smp_opt_dir = SMP_OPT_DIR_REQ; break;
2543 case ACT_F_HTTP_RES: smp_opt_dir = SMP_OPT_DIR_RES; break;
2544 default:
2545 send_log(px, LOG_ERR, "stick table: internal error while setting gpt%u.", rule->arg.gpt.idx);
2546 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))
2547 ha_alert("stick table: internal error while executing setting gpt%u.\n", rule->arg.gpt.idx);
2548 return ACT_RET_CONT;
2549 }
2550
2551 /* Fetch and cast the expression. */
2552 smp = sample_fetch_as_type(px, sess, s, smp_opt_dir|SMP_OPT_FINAL, rule->arg.gpt.expr, SMP_T_SINT);
2553 if (!smp) {
2554 send_log(px, LOG_WARNING, "stick table: invalid expression or data type while setting gpt%u.", rule->arg.gpt.idx);
2555 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))
2556 ha_alert("stick table: invalid expression or data type while setting gpt%u.\n", rule->arg.gpt.idx);
2557 return ACT_RET_CONT;
2558 }
2559 value = (unsigned int)(smp->data.u.sint);
2560 }
2561
2562 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
2563
2564 stktable_data_cast(ptr, std_t_uint) = value;
2565
2566 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
2567
2568 stktable_touch_local(stkctr->table, ts, 0);
2569 }
2570
2571 return ACT_RET_CONT;
2572}
2573
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002574/* Always returns 1. */
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002575static enum act_return action_set_gpt0(struct act_rule *rule, struct proxy *px,
Willy Tarreau658b85b2015-09-27 10:00:49 +02002576 struct session *sess, struct stream *s, int flags)
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002577{
2578 void *ptr;
2579 struct stksess *ts;
2580 struct stkctr *stkctr;
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002581 unsigned int value = 0;
2582 struct sample *smp;
2583 int smp_opt_dir;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002584
2585 /* Extract the stksess, return OK if no stksess available. */
2586 if (s)
2587 stkctr = &s->stkctr[rule->arg.gpt.sc];
2588 else
2589 stkctr = &sess->stkctr[rule->arg.gpt.sc];
Willy Tarreau79c1e912016-01-25 14:54:45 +01002590
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002591 ts = stkctr_entry(stkctr);
2592 if (!ts)
2593 return ACT_RET_CONT;
2594
2595 /* Store the sample in the required sc, and ignore errors. */
2596 ptr = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPT0);
Emeric Brunf7ab0bf2021-06-30 18:58:22 +02002597 if (!ptr)
2598 ptr = stktable_data_ptr_idx(stkctr->table, ts, STKTABLE_DT_GPT, 0);
2599
Willy Tarreau79c1e912016-01-25 14:54:45 +01002600 if (ptr) {
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002601 if (!rule->arg.gpt.expr)
2602 value = (unsigned int)(rule->arg.gpt.value);
2603 else {
2604 switch (rule->from) {
2605 case ACT_F_TCP_REQ_SES: smp_opt_dir = SMP_OPT_DIR_REQ; break;
2606 case ACT_F_TCP_REQ_CNT: smp_opt_dir = SMP_OPT_DIR_REQ; break;
2607 case ACT_F_TCP_RES_CNT: smp_opt_dir = SMP_OPT_DIR_RES; break;
2608 case ACT_F_HTTP_REQ: smp_opt_dir = SMP_OPT_DIR_REQ; break;
2609 case ACT_F_HTTP_RES: smp_opt_dir = SMP_OPT_DIR_RES; break;
2610 default:
2611 send_log(px, LOG_ERR, "stick table: internal error while setting gpt0.");
2612 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))
2613 ha_alert("stick table: internal error while executing setting gpt0.\n");
2614 return ACT_RET_CONT;
2615 }
2616
2617 /* Fetch and cast the expression. */
2618 smp = sample_fetch_as_type(px, sess, s, smp_opt_dir|SMP_OPT_FINAL, rule->arg.gpt.expr, SMP_T_SINT);
2619 if (!smp) {
2620 send_log(px, LOG_WARNING, "stick table: invalid expression or data type while setting gpt0.");
2621 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))
2622 ha_alert("stick table: invalid expression or data type while setting gpt0.\n");
2623 return ACT_RET_CONT;
2624 }
2625 value = (unsigned int)(smp->data.u.sint);
2626 }
2627
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002628 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002629
Emeric Brun0e3457b2021-06-30 17:18:28 +02002630 stktable_data_cast(ptr, std_t_uint) = value;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002631
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002632 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002633
2634 stktable_touch_local(stkctr->table, ts, 0);
Willy Tarreau79c1e912016-01-25 14:54:45 +01002635 }
2636
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002637 return ACT_RET_CONT;
2638}
2639
Emeric Brun877b0b52021-06-30 18:57:49 +02002640/* This function is a parser for the "sc-set-gpt" and "sc-set-gpt0" actions.
2641 * It understands the formats:
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002642 *
Emeric Brun877b0b52021-06-30 18:57:49 +02002643 * sc-set-gpt(<gpt IDX>,<track ID>) <expression>
2644 * sc-set-gpt0(<track ID>) <expression>
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002645 *
Emeric Brun877b0b52021-06-30 18:57:49 +02002646 * It returns ACT_RET_PRS_ERR if fails and <err> is filled with an error message.
2647 * Otherwise, it returns ACT_RET_PRS_OK and the variable 'rule->arg.gpt.expr'
2648 * is filled with the pointer to the expression to execute or NULL if the arg
2649 * is directly an integer stored into 'rule->arg.gpt.value'.
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002650 */
Emeric Brun877b0b52021-06-30 18:57:49 +02002651static enum act_parse_ret parse_set_gpt(const char **args, int *arg, struct proxy *px,
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002652 struct act_rule *rule, char **err)
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002653{
2654 const char *cmd_name = args[*arg-1];
2655 char *error;
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002656 int smp_val;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002657
Emeric Brun877b0b52021-06-30 18:57:49 +02002658 cmd_name += strlen("sc-set-gpt");
2659 if (*cmd_name == '(') {
2660 cmd_name++; /* skip the '(' */
2661 rule->arg.gpt.idx = strtoul(cmd_name, &error, 10); /* Convert stick table id. */
2662 if (*error != ',') {
2663 memprintf(err, "Missing gpt ID '%s'. Expects sc-set-gpt(<GPT ID>,<Track ID>)", args[*arg-1]);
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002664 return ACT_RET_PRS_ERR;
2665 }
Emeric Brun877b0b52021-06-30 18:57:49 +02002666 else {
2667 cmd_name = error + 1; /* skip the ',' */
2668 rule->arg.gpt.sc = strtol(cmd_name, &error, 10); /* Convert stick table id. */
2669 if (*error != ')') {
2670 memprintf(err, "invalid stick table track ID '%s'. Expects sc-set-gpt(<GPT ID>,<Track ID>)", args[*arg-1]);
2671 return ACT_RET_PRS_ERR;
2672 }
2673
2674 if (rule->arg.gpt.sc >= MAX_SESS_STKCTR) {
2675 memprintf(err, "invalid stick table track ID '%s'. The max allowed ID is %d",
2676 args[*arg-1], MAX_SESS_STKCTR-1);
2677 return ACT_RET_PRS_ERR;
2678 }
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002679 }
Emeric Brun877b0b52021-06-30 18:57:49 +02002680 rule->action_ptr = action_set_gpt;
2681 }
2682 else if (*cmd_name == '0') {
2683 cmd_name++;
2684 if (*cmd_name == '\0') {
2685 /* default stick table id. */
2686 rule->arg.gpt.sc = 0;
2687 } else {
2688 /* parse the stick table id. */
2689 if (*cmd_name != '(') {
2690 memprintf(err, "invalid stick table track ID '%s'. Expects sc-set-gpt0(<Track ID>)", args[*arg-1]);
2691 return ACT_RET_PRS_ERR;
2692 }
2693 cmd_name++; /* jump the '(' */
2694 rule->arg.gpt.sc = strtol(cmd_name, &error, 10); /* Convert stick table id. */
2695 if (*error != ')') {
2696 memprintf(err, "invalid stick table track ID '%s'. Expects sc-set-gpt0(<Track ID>)", args[*arg-1]);
2697 return ACT_RET_PRS_ERR;
2698 }
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002699
Emeric Brun877b0b52021-06-30 18:57:49 +02002700 if (rule->arg.gpt.sc >= MAX_SESS_STKCTR) {
2701 memprintf(err, "invalid stick table track ID '%s'. The max allowed ID is %d",
2702 args[*arg-1], MAX_SESS_STKCTR-1);
2703 return ACT_RET_PRS_ERR;
2704 }
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002705 }
Emeric Brun877b0b52021-06-30 18:57:49 +02002706 rule->action_ptr = action_set_gpt0;
2707 }
2708 else {
2709 /* default stick table id. */
2710 memprintf(err, "invalid gpt ID '%s'. Expects sc-set-gpt(<GPT ID>,<Track ID>)", args[*arg-1]);
2711 return ACT_RET_PRS_ERR;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002712 }
2713
Willy Tarreauece4c4a2021-08-24 14:57:28 +02002714 /* value may be either an integer or an expression */
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002715 rule->arg.gpt.expr = NULL;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002716 rule->arg.gpt.value = strtol(args[*arg], &error, 10);
Willy Tarreauece4c4a2021-08-24 14:57:28 +02002717 if (*error == '\0') {
2718 /* valid integer, skip it */
2719 (*arg)++;
2720 } else {
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002721 rule->arg.gpt.expr = sample_parse_expr((char **)args, arg, px->conf.args.file,
Willy Tarreaue3b57bf2020-02-14 16:50:14 +01002722 px->conf.args.line, err, &px->conf.args, NULL);
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002723 if (!rule->arg.gpt.expr)
2724 return ACT_RET_PRS_ERR;
2725
2726 switch (rule->from) {
2727 case ACT_F_TCP_REQ_SES: smp_val = SMP_VAL_FE_SES_ACC; break;
2728 case ACT_F_TCP_REQ_CNT: smp_val = SMP_VAL_FE_REQ_CNT; break;
2729 case ACT_F_TCP_RES_CNT: smp_val = SMP_VAL_BE_RES_CNT; break;
2730 case ACT_F_HTTP_REQ: smp_val = SMP_VAL_FE_HRQ_HDR; break;
2731 case ACT_F_HTTP_RES: smp_val = SMP_VAL_BE_HRS_HDR; break;
2732 default:
2733 memprintf(err, "internal error, unexpected rule->from=%d, please report this bug!", rule->from);
2734 return ACT_RET_PRS_ERR;
2735 }
2736 if (!(rule->arg.gpt.expr->fetch->val & smp_val)) {
2737 memprintf(err, "fetch method '%s' extracts information from '%s', none of which is available here", args[*arg-1],
2738 sample_src_names(rule->arg.gpt.expr->fetch->use));
2739 free(rule->arg.gpt.expr);
2740 return ACT_RET_PRS_ERR;
2741 }
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002742 }
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002743
Thierry FOURNIER42148732015-09-02 17:17:33 +02002744 rule->action = ACT_CUSTOM;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002745
2746 return ACT_RET_PRS_OK;
2747}
2748
Willy Tarreau7d562212016-11-25 16:10:05 +01002749/* set temp integer to the number of used entries in the table pointed to by expr.
2750 * Accepts exactly 1 argument of type table.
2751 */
2752static int
2753smp_fetch_table_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
2754{
2755 smp->flags = SMP_F_VOL_TEST;
2756 smp->data.type = SMP_T_SINT;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002757 smp->data.u.sint = args->data.t->current;
Willy Tarreau7d562212016-11-25 16:10:05 +01002758 return 1;
2759}
2760
2761/* set temp integer to the number of free entries in the table pointed to by expr.
2762 * Accepts exactly 1 argument of type table.
2763 */
2764static int
2765smp_fetch_table_avl(const struct arg *args, struct sample *smp, const char *kw, void *private)
2766{
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002767 struct stktable *t;
Willy Tarreau7d562212016-11-25 16:10:05 +01002768
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002769 t = args->data.t;
Willy Tarreau7d562212016-11-25 16:10:05 +01002770 smp->flags = SMP_F_VOL_TEST;
2771 smp->data.type = SMP_T_SINT;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002772 smp->data.u.sint = t->size - t->current;
Willy Tarreau7d562212016-11-25 16:10:05 +01002773 return 1;
2774}
2775
2776/* Returns a pointer to a stkctr depending on the fetch keyword name.
2777 * It is designed to be called as sc[0-9]_* sc_* or src_* exclusively.
2778 * sc[0-9]_* will return a pointer to the respective field in the
2779 * stream <l4>. sc_* requires an UINT argument specifying the stick
2780 * counter number. src_* will fill a locally allocated structure with
2781 * the table and entry corresponding to what is specified with src_*.
2782 * NULL may be returned if the designated stkctr is not tracked. For
2783 * the sc_* and sc[0-9]_* forms, an optional table argument may be
2784 * passed. When present, the currently tracked key is then looked up
2785 * in the specified table instead of the current table. The purpose is
Ilya Shipitsin47d17182020-06-21 21:42:57 +05002786 * to be able to convert multiple values per key (eg: have gpc0 from
Willy Tarreau7d562212016-11-25 16:10:05 +01002787 * multiple tables). <strm> is allowed to be NULL, in which case only
2788 * the session will be consulted.
2789 */
2790struct stkctr *
Emeric Brun819fc6f2017-06-13 19:37:32 +02002791smp_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 +01002792{
Willy Tarreau7d562212016-11-25 16:10:05 +01002793 struct stkctr *stkptr;
2794 struct stksess *stksess;
2795 unsigned int num = kw[2] - '0';
2796 int arg = 0;
2797
2798 if (num == '_' - '0') {
2799 /* sc_* variant, args[0] = ctr# (mandatory) */
2800 num = args[arg++].data.sint;
Willy Tarreau7d562212016-11-25 16:10:05 +01002801 }
2802 else if (num > 9) { /* src_* variant, args[0] = table */
2803 struct stktable_key *key;
2804 struct connection *conn = objt_conn(sess->origin);
2805 struct sample smp;
2806
2807 if (!conn)
2808 return NULL;
2809
Joseph Herlant5662fa42018-11-15 13:43:28 -08002810 /* Fetch source address in a sample. */
Willy Tarreau7d562212016-11-25 16:10:05 +01002811 smp.px = NULL;
2812 smp.sess = sess;
2813 smp.strm = strm;
Amaury Denoyellec460c702021-05-12 10:17:47 +02002814 if (!smp_fetch_src || !smp_fetch_src(empty_arg_list, &smp, "src", NULL))
Willy Tarreau7d562212016-11-25 16:10:05 +01002815 return NULL;
2816
2817 /* Converts into key. */
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002818 key = smp_to_stkey(&smp, args->data.t);
Willy Tarreau7d562212016-11-25 16:10:05 +01002819 if (!key)
2820 return NULL;
2821
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002822 stkctr->table = args->data.t;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002823 stkctr_set_entry(stkctr, stktable_lookup_key(stkctr->table, key));
2824 return stkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002825 }
2826
2827 /* Here, <num> contains the counter number from 0 to 9 for
2828 * the sc[0-9]_ form, or even higher using sc_(num) if needed.
2829 * args[arg] is the first optional argument. We first lookup the
2830 * ctr form the stream, then from the session if it was not there.
Christopher Fauleta9fa88a2019-10-21 10:53:34 +02002831 * But we must be sure the counter does not exceed MAX_SESS_STKCTR.
Willy Tarreau7d562212016-11-25 16:10:05 +01002832 */
Christopher Fauleta9fa88a2019-10-21 10:53:34 +02002833 if (num >= MAX_SESS_STKCTR)
2834 return NULL;
Willy Tarreau7d562212016-11-25 16:10:05 +01002835
2836 if (strm)
2837 stkptr = &strm->stkctr[num];
2838 if (!strm || !stkctr_entry(stkptr)) {
2839 stkptr = &sess->stkctr[num];
2840 if (!stkctr_entry(stkptr))
2841 return NULL;
2842 }
2843
2844 stksess = stkctr_entry(stkptr);
2845 if (!stksess)
2846 return NULL;
2847
2848 if (unlikely(args[arg].type == ARGT_TAB)) {
2849 /* an alternate table was specified, let's look up the same key there */
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002850 stkctr->table = args[arg].data.t;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002851 stkctr_set_entry(stkctr, stktable_lookup(stkctr->table, stksess));
2852 return stkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002853 }
2854 return stkptr;
2855}
2856
2857/* same as smp_fetch_sc_stkctr() but dedicated to src_* and can create
2858 * the entry if it doesn't exist yet. This is needed for a few fetch
2859 * functions which need to create an entry, such as src_inc_gpc* and
2860 * src_clr_gpc*.
2861 */
2862struct stkctr *
Emeric Brun819fc6f2017-06-13 19:37:32 +02002863smp_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 +01002864{
Willy Tarreau7d562212016-11-25 16:10:05 +01002865 struct stktable_key *key;
2866 struct connection *conn = objt_conn(sess->origin);
2867 struct sample smp;
2868
2869 if (strncmp(kw, "src_", 4) != 0)
2870 return NULL;
2871
2872 if (!conn)
2873 return NULL;
2874
Joseph Herlant5662fa42018-11-15 13:43:28 -08002875 /* Fetch source address in a sample. */
Willy Tarreau7d562212016-11-25 16:10:05 +01002876 smp.px = NULL;
2877 smp.sess = sess;
2878 smp.strm = strm;
Amaury Denoyellec460c702021-05-12 10:17:47 +02002879 if (!smp_fetch_src || !smp_fetch_src(empty_arg_list, &smp, "src", NULL))
Willy Tarreau7d562212016-11-25 16:10:05 +01002880 return NULL;
2881
2882 /* Converts into key. */
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002883 key = smp_to_stkey(&smp, args->data.t);
Willy Tarreau7d562212016-11-25 16:10:05 +01002884 if (!key)
2885 return NULL;
2886
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002887 stkctr->table = args->data.t;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002888 stkctr_set_entry(stkctr, stktable_get_entry(stkctr->table, key));
2889 return stkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002890}
2891
2892/* set return a boolean indicating if the requested stream counter is
2893 * currently being tracked or not.
2894 * Supports being called as "sc[0-9]_tracked" only.
2895 */
2896static int
2897smp_fetch_sc_tracked(const struct arg *args, struct sample *smp, const char *kw, void *private)
2898{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002899 struct stkctr tmpstkctr;
2900 struct stkctr *stkctr;
2901
Willy Tarreau7d562212016-11-25 16:10:05 +01002902 smp->flags = SMP_F_VOL_TEST;
2903 smp->data.type = SMP_T_BOOL;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002904 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2905 smp->data.u.sint = !!stkctr;
2906
2907 /* release the ref count */
Dirkjan Bussinkff57f1b2018-09-14 14:31:22 +02002908 if (stkctr == &tmpstkctr)
Emeric Brun819fc6f2017-06-13 19:37:32 +02002909 stktable_release(stkctr->table, stkctr_entry(stkctr));
2910
Emeric Brun877b0b52021-06-30 18:57:49 +02002911 return 1;
2912}
2913
2914/* set <smp> to the General Purpose Tag of index set as first arg
2915 * to value from the stream's tracked frontend counters or from the src.
2916 * Supports being called as "sc_get_gpt(<gpt-idx>,<sc-idx>[,<table>])" or
2917 * "src_get_gpt(<gpt-idx>[,<table>])" only. Value zero is returned if
2918 * the key is new or gpt is not stored.
2919 */
2920static int
2921smp_fetch_sc_get_gpt(const struct arg *args, struct sample *smp, const char *kw, void *private)
2922{
2923 struct stkctr tmpstkctr;
2924 struct stkctr *stkctr;
2925 unsigned int idx;
2926
2927 idx = args[0].data.sint;
2928
2929 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args + 1, kw, &tmpstkctr);
2930 if (!stkctr)
2931 return 0;
2932
2933 smp->flags = SMP_F_VOL_TEST;
2934 smp->data.type = SMP_T_SINT;
2935 smp->data.u.sint = 0;
2936
2937 if (stkctr_entry(stkctr)) {
2938 void *ptr;
2939
2940 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPT, idx);
2941 if (!ptr) {
2942 if (stkctr == &tmpstkctr)
2943 stktable_release(stkctr->table, stkctr_entry(stkctr));
2944 return 0; /* parameter not stored */
2945 }
2946
2947 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2948
2949 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
2950
2951 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2952
2953 if (stkctr == &tmpstkctr)
2954 stktable_release(stkctr->table, stkctr_entry(stkctr));
2955 }
Willy Tarreau7d562212016-11-25 16:10:05 +01002956 return 1;
2957}
2958
2959/* set <smp> to the General Purpose Flag 0 value from the stream's tracked
2960 * frontend counters or from the src.
2961 * Supports being called as "sc[0-9]_get_gpc0" or "src_get_gpt0" only. Value
2962 * zero is returned if the key is new.
2963 */
2964static int
2965smp_fetch_sc_get_gpt0(const struct arg *args, struct sample *smp, const char *kw, void *private)
2966{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002967 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002968 struct stkctr *stkctr;
2969
Emeric Brun819fc6f2017-06-13 19:37:32 +02002970 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002971 if (!stkctr)
2972 return 0;
2973
2974 smp->flags = SMP_F_VOL_TEST;
2975 smp->data.type = SMP_T_SINT;
2976 smp->data.u.sint = 0;
2977
Emeric Brun819fc6f2017-06-13 19:37:32 +02002978 if (stkctr_entry(stkctr)) {
2979 void *ptr;
2980
2981 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPT0);
Emeric Brunf7ab0bf2021-06-30 18:58:22 +02002982 if (!ptr)
2983 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPT, 0);
2984
Emeric Brun4d7ada82021-06-30 19:04:16 +02002985 if (!ptr) {
2986 if (stkctr == &tmpstkctr)
2987 stktable_release(stkctr->table, stkctr_entry(stkctr));
2988 return 0; /* parameter not stored */
2989 }
2990
2991 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2992
2993 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
2994
2995 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2996
2997 if (stkctr == &tmpstkctr)
2998 stktable_release(stkctr->table, stkctr_entry(stkctr));
2999 }
3000 return 1;
3001}
3002
3003/* set <smp> to the GPC[args(0)]'s value from the stream's tracked
3004 * frontend counters or from the src.
3005 * Supports being called as "sc_get_gpc(<gpc-idx>,<sc-idx>[,<table>])" or
3006 * "src_get_gpc(<gpc-idx>[,<table>])" only. Value
3007 * Value zero is returned if the key is new or gpc is not stored.
3008 */
3009static int
3010smp_fetch_sc_get_gpc(const struct arg *args, struct sample *smp, const char *kw, void *private)
3011{
3012 struct stkctr tmpstkctr;
3013 struct stkctr *stkctr;
3014 unsigned int idx;
3015
3016 idx = args[0].data.sint;
3017
3018 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args + 1, kw, &tmpstkctr);
3019 if (!stkctr)
3020 return 0;
3021
3022 smp->flags = SMP_F_VOL_TEST;
3023 smp->data.type = SMP_T_SINT;
3024 smp->data.u.sint = 0;
3025
3026 if (stkctr_entry(stkctr) != NULL) {
3027 void *ptr;
3028
3029 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC, idx);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003030 if (!ptr) {
3031 if (stkctr == &tmpstkctr)
3032 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003033 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003034 }
3035
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003036 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003037
Emeric Brun0e3457b2021-06-30 17:18:28 +02003038 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003039
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003040 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003041
3042 if (stkctr == &tmpstkctr)
3043 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003044 }
3045 return 1;
3046}
3047
3048/* set <smp> to the General Purpose Counter 0 value from the stream's tracked
3049 * frontend counters or from the src.
3050 * Supports being called as "sc[0-9]_get_gpc0" or "src_get_gpc0" only. Value
3051 * zero is returned if the key is new.
3052 */
3053static int
3054smp_fetch_sc_get_gpc0(const struct arg *args, struct sample *smp, const char *kw, void *private)
3055{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003056 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003057 struct stkctr *stkctr;
3058
Emeric Brun819fc6f2017-06-13 19:37:32 +02003059 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003060 if (!stkctr)
3061 return 0;
3062
3063 smp->flags = SMP_F_VOL_TEST;
3064 smp->data.type = SMP_T_SINT;
3065 smp->data.u.sint = 0;
3066
3067 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003068 void *ptr;
3069
3070 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0);
3071 if (!ptr) {
Emeric Brun726783d2021-06-30 19:06:43 +02003072 /* fallback on the gpc array */
3073 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC, 0);
3074 }
3075
3076 if (!ptr) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003077 if (stkctr == &tmpstkctr)
3078 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003079 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003080 }
3081
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003082 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003083
Emeric Brun0e3457b2021-06-30 17:18:28 +02003084 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003085
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003086 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003087
3088 if (stkctr == &tmpstkctr)
3089 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003090 }
3091 return 1;
3092}
3093
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003094/* set <smp> to the General Purpose Counter 1 value from the stream's tracked
3095 * frontend counters or from the src.
3096 * Supports being called as "sc[0-9]_get_gpc1" or "src_get_gpc1" only. Value
3097 * zero is returned if the key is new.
3098 */
3099static int
3100smp_fetch_sc_get_gpc1(const struct arg *args, struct sample *smp, const char *kw, void *private)
3101{
3102 struct stkctr tmpstkctr;
3103 struct stkctr *stkctr;
3104
3105 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
3106 if (!stkctr)
3107 return 0;
3108
3109 smp->flags = SMP_F_VOL_TEST;
3110 smp->data.type = SMP_T_SINT;
3111 smp->data.u.sint = 0;
3112
3113 if (stkctr_entry(stkctr) != NULL) {
3114 void *ptr;
3115
3116 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1);
3117 if (!ptr) {
Emeric Brun726783d2021-06-30 19:06:43 +02003118 /* fallback on the gpc array */
3119 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC, 1);
3120 }
3121
3122 if (!ptr) {
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003123 if (stkctr == &tmpstkctr)
3124 stktable_release(stkctr->table, stkctr_entry(stkctr));
3125 return 0; /* parameter not stored */
3126 }
3127
3128 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3129
Emeric Brun0e3457b2021-06-30 17:18:28 +02003130 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003131
3132 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3133
3134 if (stkctr == &tmpstkctr)
3135 stktable_release(stkctr->table, stkctr_entry(stkctr));
3136 }
3137 return 1;
3138}
3139
Emeric Brun4d7ada82021-06-30 19:04:16 +02003140/* set <smp> to the GPC[args(0)]'s event rate from the stream's
3141 * tracked frontend counters or from the src.
3142 * Supports being called as "sc_gpc_rate(<gpc-idx>,<sc-idx>[,<table])"
3143 * or "src_gpc_rate(<gpc-idx>[,<table>])" only.
3144 * Value zero is returned if the key is new or gpc_rate is not stored.
3145 */
3146static int
3147smp_fetch_sc_gpc_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3148{
3149 struct stkctr tmpstkctr;
3150 struct stkctr *stkctr;
3151 unsigned int idx;
3152
3153 idx = args[0].data.sint;
3154
3155 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args + 1, kw, &tmpstkctr);
3156 if (!stkctr)
3157 return 0;
3158
3159 smp->flags = SMP_F_VOL_TEST;
3160 smp->data.type = SMP_T_SINT;
3161 smp->data.u.sint = 0;
3162 if (stkctr_entry(stkctr) != NULL) {
3163 void *ptr;
3164
3165 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC_RATE, idx);
3166 if (!ptr) {
3167 if (stkctr == &tmpstkctr)
3168 stktable_release(stkctr->table, stkctr_entry(stkctr));
3169 return 0; /* parameter not stored */
3170 }
3171
3172 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3173
3174 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
3175 stkctr->table->data_arg[STKTABLE_DT_GPC_RATE].u);
3176
3177 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3178
3179 if (stkctr == &tmpstkctr)
3180 stktable_release(stkctr->table, stkctr_entry(stkctr));
3181 }
3182 return 1;
3183}
3184
Willy Tarreau7d562212016-11-25 16:10:05 +01003185/* set <smp> to the General Purpose Counter 0's event rate from the stream's
3186 * tracked frontend counters or from the src.
3187 * Supports being called as "sc[0-9]_gpc0_rate" or "src_gpc0_rate" only.
3188 * Value zero is returned if the key is new.
3189 */
3190static int
3191smp_fetch_sc_gpc0_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3192{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003193 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003194 struct stkctr *stkctr;
Emeric Brun726783d2021-06-30 19:06:43 +02003195 unsigned int period;
Willy Tarreau7d562212016-11-25 16:10:05 +01003196
Emeric Brun819fc6f2017-06-13 19:37:32 +02003197 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003198 if (!stkctr)
3199 return 0;
3200
3201 smp->flags = SMP_F_VOL_TEST;
3202 smp->data.type = SMP_T_SINT;
3203 smp->data.u.sint = 0;
3204 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003205 void *ptr;
3206
3207 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0_RATE);
Emeric Brun726783d2021-06-30 19:06:43 +02003208 if (ptr) {
3209 period = stkctr->table->data_arg[STKTABLE_DT_GPC0_RATE].u;
3210 }
3211 else {
3212 /* fallback on the gpc array */
3213 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC_RATE, 0);
3214 if (ptr)
3215 period = stkctr->table->data_arg[STKTABLE_DT_GPC_RATE].u;
3216 }
3217
Emeric Brun819fc6f2017-06-13 19:37:32 +02003218 if (!ptr) {
3219 if (stkctr == &tmpstkctr)
3220 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003221 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003222 }
3223
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003224 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003225
Emeric Brun726783d2021-06-30 19:06:43 +02003226 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp), period);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003227
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003228 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003229
3230 if (stkctr == &tmpstkctr)
3231 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003232 }
3233 return 1;
3234}
3235
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003236/* set <smp> to the General Purpose Counter 1's event rate from the stream's
3237 * tracked frontend counters or from the src.
3238 * Supports being called as "sc[0-9]_gpc1_rate" or "src_gpc1_rate" only.
3239 * Value zero is returned if the key is new.
3240 */
3241static int
3242smp_fetch_sc_gpc1_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3243{
3244 struct stkctr tmpstkctr;
3245 struct stkctr *stkctr;
Emeric Brun726783d2021-06-30 19:06:43 +02003246 unsigned int period;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003247
3248 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
3249 if (!stkctr)
3250 return 0;
3251
3252 smp->flags = SMP_F_VOL_TEST;
3253 smp->data.type = SMP_T_SINT;
3254 smp->data.u.sint = 0;
3255 if (stkctr_entry(stkctr) != NULL) {
3256 void *ptr;
3257
3258 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1_RATE);
Emeric Brun726783d2021-06-30 19:06:43 +02003259 if (ptr) {
3260 period = stkctr->table->data_arg[STKTABLE_DT_GPC1_RATE].u;
3261 }
3262 else {
3263 /* fallback on the gpc array */
3264 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC_RATE, 1);
3265 if (ptr)
3266 period = stkctr->table->data_arg[STKTABLE_DT_GPC_RATE].u;
3267 }
3268
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003269 if (!ptr) {
3270 if (stkctr == &tmpstkctr)
3271 stktable_release(stkctr->table, stkctr_entry(stkctr));
3272 return 0; /* parameter not stored */
3273 }
3274
3275 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3276
Emeric Brun726783d2021-06-30 19:06:43 +02003277 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 +01003278
3279 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3280
3281 if (stkctr == &tmpstkctr)
3282 stktable_release(stkctr->table, stkctr_entry(stkctr));
3283 }
3284 return 1;
3285}
3286
Emeric Brun4d7ada82021-06-30 19:04:16 +02003287/* Increment the GPC[args(0)] value from the stream's tracked
3288 * frontend counters and return it into temp integer.
3289 * Supports being called as "sc_inc_gpc(<gpc-idx>,<sc-idx>[,<table>])"
3290 * or "src_inc_gpc(<gpc-idx>[,<table>])" only.
3291 */
3292static int
3293smp_fetch_sc_inc_gpc(const struct arg *args, struct sample *smp, const char *kw, void *private)
3294{
3295 struct stkctr tmpstkctr;
3296 struct stkctr *stkctr;
3297 unsigned int idx;
3298
3299 idx = args[0].data.sint;
3300
3301 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args + 1, kw, &tmpstkctr);
3302 if (!stkctr)
3303 return 0;
3304
3305 smp->flags = SMP_F_VOL_TEST;
3306 smp->data.type = SMP_T_SINT;
3307 smp->data.u.sint = 0;
3308
3309 if (!stkctr_entry(stkctr))
3310 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
3311
3312 if (stkctr && stkctr_entry(stkctr)) {
3313 void *ptr1,*ptr2;
3314
3315
3316 /* First, update gpc0_rate if it's tracked. Second, update its
3317 * gpc0 if tracked. Returns gpc0's value otherwise the curr_ctr.
3318 */
3319 ptr1 = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC_RATE, idx);
3320 ptr2 = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC, idx);
3321 if (ptr1 || ptr2) {
3322 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3323
3324 if (ptr1) {
3325 update_freq_ctr_period(&stktable_data_cast(ptr1, std_t_frqp),
3326 stkctr->table->data_arg[STKTABLE_DT_GPC_RATE].u, 1);
3327 smp->data.u.sint = (&stktable_data_cast(ptr1, std_t_frqp))->curr_ctr;
3328 }
3329
3330 if (ptr2)
3331 smp->data.u.sint = ++stktable_data_cast(ptr2, std_t_uint);
3332
3333 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3334
3335 /* If data was modified, we need to touch to re-schedule sync */
3336 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
3337 }
3338 else if (stkctr == &tmpstkctr)
3339 stktable_release(stkctr->table, stkctr_entry(stkctr));
3340 }
3341 return 1;
3342}
3343
Willy Tarreau7d562212016-11-25 16:10:05 +01003344/* Increment the General Purpose Counter 0 value from the stream's tracked
3345 * frontend counters and return it into temp integer.
3346 * Supports being called as "sc[0-9]_inc_gpc0" or "src_inc_gpc0" only.
3347 */
3348static int
3349smp_fetch_sc_inc_gpc0(const struct arg *args, struct sample *smp, const char *kw, void *private)
3350{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003351 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003352 struct stkctr *stkctr;
Willy Tarreau5b654ad2021-07-06 18:51:12 +02003353 unsigned int period = 0;
Willy Tarreau7d562212016-11-25 16:10:05 +01003354
Emeric Brun819fc6f2017-06-13 19:37:32 +02003355 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003356 if (!stkctr)
3357 return 0;
3358
3359 smp->flags = SMP_F_VOL_TEST;
3360 smp->data.type = SMP_T_SINT;
3361 smp->data.u.sint = 0;
3362
Emeric Brun819fc6f2017-06-13 19:37:32 +02003363 if (!stkctr_entry(stkctr))
3364 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003365
3366 if (stkctr && stkctr_entry(stkctr)) {
3367 void *ptr1,*ptr2;
3368
Emeric Brun819fc6f2017-06-13 19:37:32 +02003369
Willy Tarreau7d562212016-11-25 16:10:05 +01003370 /* First, update gpc0_rate if it's tracked. Second, update its
3371 * gpc0 if tracked. Returns gpc0's value otherwise the curr_ctr.
3372 */
3373 ptr1 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0_RATE);
Emeric Brun726783d2021-06-30 19:06:43 +02003374 if (ptr1) {
3375 period = stkctr->table->data_arg[STKTABLE_DT_GPC0_RATE].u;
3376 }
3377 else {
3378 /* fallback on the gpc array */
3379 ptr1 = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC_RATE, 0);
3380 if (ptr1)
3381 period = stkctr->table->data_arg[STKTABLE_DT_GPC_RATE].u;
3382 }
3383
Willy Tarreau7d562212016-11-25 16:10:05 +01003384 ptr2 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0);
Emeric Brun726783d2021-06-30 19:06:43 +02003385 if (!ptr2) {
3386 /* fallback on the gpc array */
3387 ptr2 = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC, 0);
3388 }
3389
Emeric Brun819fc6f2017-06-13 19:37:32 +02003390 if (ptr1 || ptr2) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003391 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Willy Tarreau7d562212016-11-25 16:10:05 +01003392
Emeric Brun819fc6f2017-06-13 19:37:32 +02003393 if (ptr1) {
Emeric Brun0e3457b2021-06-30 17:18:28 +02003394 update_freq_ctr_period(&stktable_data_cast(ptr1, std_t_frqp),
Emeric Brun726783d2021-06-30 19:06:43 +02003395 period, 1);
Emeric Brun0e3457b2021-06-30 17:18:28 +02003396 smp->data.u.sint = (&stktable_data_cast(ptr1, std_t_frqp))->curr_ctr;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003397 }
3398
3399 if (ptr2)
Emeric Brun0e3457b2021-06-30 17:18:28 +02003400 smp->data.u.sint = ++stktable_data_cast(ptr2, std_t_uint);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003401
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003402 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003403
3404 /* If data was modified, we need to touch to re-schedule sync */
3405 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
3406 }
3407 else if (stkctr == &tmpstkctr)
3408 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003409 }
3410 return 1;
3411}
3412
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003413/* Increment the General Purpose Counter 1 value from the stream's tracked
3414 * frontend counters and return it into temp integer.
3415 * Supports being called as "sc[0-9]_inc_gpc1" or "src_inc_gpc1" only.
3416 */
3417static int
3418smp_fetch_sc_inc_gpc1(const struct arg *args, struct sample *smp, const char *kw, void *private)
3419{
3420 struct stkctr tmpstkctr;
3421 struct stkctr *stkctr;
Willy Tarreau5b654ad2021-07-06 18:51:12 +02003422 unsigned int period = 0;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003423
3424 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
3425 if (!stkctr)
3426 return 0;
3427
3428 smp->flags = SMP_F_VOL_TEST;
3429 smp->data.type = SMP_T_SINT;
3430 smp->data.u.sint = 0;
3431
3432 if (!stkctr_entry(stkctr))
3433 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
3434
3435 if (stkctr && stkctr_entry(stkctr)) {
3436 void *ptr1,*ptr2;
3437
3438
3439 /* First, update gpc1_rate if it's tracked. Second, update its
3440 * gpc1 if tracked. Returns gpc1's value otherwise the curr_ctr.
3441 */
3442 ptr1 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1_RATE);
Emeric Brun726783d2021-06-30 19:06:43 +02003443 if (ptr1) {
3444 period = stkctr->table->data_arg[STKTABLE_DT_GPC1_RATE].u;
3445 }
3446 else {
3447 /* fallback on the gpc array */
3448 ptr1 = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC_RATE, 1);
3449 if (ptr1)
3450 period = stkctr->table->data_arg[STKTABLE_DT_GPC_RATE].u;
3451 }
3452
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003453 ptr2 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1);
Emeric Brun726783d2021-06-30 19:06:43 +02003454 if (!ptr2) {
3455 /* fallback on the gpc array */
3456 ptr2 = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC, 1);
3457 }
3458
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003459 if (ptr1 || ptr2) {
3460 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3461
3462 if (ptr1) {
Emeric Brun0e3457b2021-06-30 17:18:28 +02003463 update_freq_ctr_period(&stktable_data_cast(ptr1, std_t_frqp),
Emeric Brun726783d2021-06-30 19:06:43 +02003464 period, 1);
Emeric Brun0e3457b2021-06-30 17:18:28 +02003465 smp->data.u.sint = (&stktable_data_cast(ptr1, std_t_frqp))->curr_ctr;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003466 }
3467
3468 if (ptr2)
Emeric Brun0e3457b2021-06-30 17:18:28 +02003469 smp->data.u.sint = ++stktable_data_cast(ptr2, std_t_uint);
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003470
3471 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3472
3473 /* If data was modified, we need to touch to re-schedule sync */
3474 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
3475 }
3476 else if (stkctr == &tmpstkctr)
3477 stktable_release(stkctr->table, stkctr_entry(stkctr));
3478 }
3479 return 1;
3480}
3481
Emeric Brun4d7ada82021-06-30 19:04:16 +02003482/* Clear the GPC[args(0)] value from the stream's tracked
3483 * frontend counters and return its previous value into temp integer.
3484 * Supports being called as "sc_clr_gpc(<gpc-idx>,<sc-idx>[,<table>])"
3485 * or "src_clr_gpc(<gpc-idx>[,<table>])" only.
3486 */
3487static int
3488smp_fetch_sc_clr_gpc(const struct arg *args, struct sample *smp, const char *kw, void *private)
3489{
3490 struct stkctr tmpstkctr;
3491 struct stkctr *stkctr;
3492 unsigned int idx;
3493
3494 idx = args[0].data.sint;
3495
3496 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args + 1, kw, &tmpstkctr);
3497 if (!stkctr)
3498 return 0;
3499
3500 smp->flags = SMP_F_VOL_TEST;
3501 smp->data.type = SMP_T_SINT;
3502 smp->data.u.sint = 0;
3503
3504 if (!stkctr_entry(stkctr))
3505 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
3506
3507 if (stkctr && stkctr_entry(stkctr)) {
3508 void *ptr;
3509
3510 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC, idx);
3511 if (!ptr) {
3512 if (stkctr == &tmpstkctr)
3513 stktable_release(stkctr->table, stkctr_entry(stkctr));
3514 return 0; /* parameter not stored */
3515 }
3516
3517 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3518
3519 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
3520 stktable_data_cast(ptr, std_t_uint) = 0;
3521
3522 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3523
3524 /* If data was modified, we need to touch to re-schedule sync */
3525 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
3526 }
3527 return 1;
3528}
3529
Willy Tarreau7d562212016-11-25 16:10:05 +01003530/* Clear the General Purpose Counter 0 value from the stream's tracked
3531 * frontend counters and return its previous value into temp integer.
3532 * Supports being called as "sc[0-9]_clr_gpc0" or "src_clr_gpc0" only.
3533 */
3534static int
3535smp_fetch_sc_clr_gpc0(const struct arg *args, struct sample *smp, const char *kw, void *private)
3536{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003537 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003538 struct stkctr *stkctr;
3539
Emeric Brun819fc6f2017-06-13 19:37:32 +02003540 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003541 if (!stkctr)
3542 return 0;
3543
3544 smp->flags = SMP_F_VOL_TEST;
3545 smp->data.type = SMP_T_SINT;
3546 smp->data.u.sint = 0;
3547
Emeric Brun819fc6f2017-06-13 19:37:32 +02003548 if (!stkctr_entry(stkctr))
3549 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003550
Emeric Brun819fc6f2017-06-13 19:37:32 +02003551 if (stkctr && stkctr_entry(stkctr)) {
3552 void *ptr;
3553
3554 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0);
3555 if (!ptr) {
Emeric Brun726783d2021-06-30 19:06:43 +02003556 /* fallback on the gpc array */
3557 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC, 0);
3558 }
3559
3560 if (!ptr) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003561 if (stkctr == &tmpstkctr)
3562 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003563 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003564 }
3565
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003566 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003567
Emeric Brun0e3457b2021-06-30 17:18:28 +02003568 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
3569 stktable_data_cast(ptr, std_t_uint) = 0;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003570
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003571 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003572
Willy Tarreau7d562212016-11-25 16:10:05 +01003573 /* If data was modified, we need to touch to re-schedule sync */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003574 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
Willy Tarreau7d562212016-11-25 16:10:05 +01003575 }
3576 return 1;
3577}
3578
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003579/* Clear the General Purpose Counter 1 value from the stream's tracked
3580 * frontend counters and return its previous value into temp integer.
3581 * Supports being called as "sc[0-9]_clr_gpc1" or "src_clr_gpc1" only.
3582 */
3583static int
3584smp_fetch_sc_clr_gpc1(const struct arg *args, struct sample *smp, const char *kw, void *private)
3585{
3586 struct stkctr tmpstkctr;
3587 struct stkctr *stkctr;
3588
3589 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
3590 if (!stkctr)
3591 return 0;
3592
3593 smp->flags = SMP_F_VOL_TEST;
3594 smp->data.type = SMP_T_SINT;
3595 smp->data.u.sint = 0;
3596
3597 if (!stkctr_entry(stkctr))
3598 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
3599
3600 if (stkctr && stkctr_entry(stkctr)) {
3601 void *ptr;
3602
3603 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1);
3604 if (!ptr) {
Emeric Brun726783d2021-06-30 19:06:43 +02003605 /* fallback on the gpc array */
3606 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC, 1);
3607 }
3608
3609 if (!ptr) {
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003610 if (stkctr == &tmpstkctr)
3611 stktable_release(stkctr->table, stkctr_entry(stkctr));
3612 return 0; /* parameter not stored */
3613 }
3614
3615 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3616
Emeric Brun0e3457b2021-06-30 17:18:28 +02003617 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
3618 stktable_data_cast(ptr, std_t_uint) = 0;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003619
3620 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3621
3622 /* If data was modified, we need to touch to re-schedule sync */
3623 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
3624 }
3625 return 1;
3626}
3627
Willy Tarreau7d562212016-11-25 16:10:05 +01003628/* set <smp> to the cumulated number of connections from the stream's tracked
3629 * frontend counters. Supports being called as "sc[0-9]_conn_cnt" or
3630 * "src_conn_cnt" only.
3631 */
3632static int
3633smp_fetch_sc_conn_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
3634{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003635 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003636 struct stkctr *stkctr;
3637
Emeric Brun819fc6f2017-06-13 19:37:32 +02003638 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003639 if (!stkctr)
3640 return 0;
3641
3642 smp->flags = SMP_F_VOL_TEST;
3643 smp->data.type = SMP_T_SINT;
3644 smp->data.u.sint = 0;
3645 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003646 void *ptr;
3647
3648 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_CONN_CNT);
3649 if (!ptr) {
3650 if (stkctr == &tmpstkctr)
3651 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003652 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003653 }
3654
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003655 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003656
Emeric Brun0e3457b2021-06-30 17:18:28 +02003657 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003658
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003659 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003660
3661 if (stkctr == &tmpstkctr)
3662 stktable_release(stkctr->table, stkctr_entry(stkctr));
3663
3664
Willy Tarreau7d562212016-11-25 16:10:05 +01003665 }
3666 return 1;
3667}
3668
3669/* set <smp> to the connection rate from the stream's tracked frontend
3670 * counters. Supports being called as "sc[0-9]_conn_rate" or "src_conn_rate"
3671 * only.
3672 */
3673static int
3674smp_fetch_sc_conn_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3675{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003676 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003677 struct stkctr *stkctr;
3678
Emeric Brun819fc6f2017-06-13 19:37:32 +02003679 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003680 if (!stkctr)
3681 return 0;
3682
3683 smp->flags = SMP_F_VOL_TEST;
3684 smp->data.type = SMP_T_SINT;
3685 smp->data.u.sint = 0;
3686 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003687 void *ptr;
3688
3689 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_CONN_RATE);
3690 if (!ptr) {
3691 if (stkctr == &tmpstkctr)
3692 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003693 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003694 }
3695
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003696 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003697
Emeric Brun0e3457b2021-06-30 17:18:28 +02003698 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Willy Tarreau7d562212016-11-25 16:10:05 +01003699 stkctr->table->data_arg[STKTABLE_DT_CONN_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003700
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003701 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003702
3703 if (stkctr == &tmpstkctr)
3704 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003705 }
3706 return 1;
3707}
3708
3709/* set temp integer to the number of connections from the stream's source address
3710 * in the table pointed to by expr, after updating it.
3711 * Accepts exactly 1 argument of type table.
3712 */
3713static int
3714smp_fetch_src_updt_conn_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
3715{
3716 struct connection *conn = objt_conn(smp->sess->origin);
3717 struct stksess *ts;
3718 struct stktable_key *key;
3719 void *ptr;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003720 struct stktable *t;
Willy Tarreau7d562212016-11-25 16:10:05 +01003721
3722 if (!conn)
3723 return 0;
3724
Joseph Herlant5662fa42018-11-15 13:43:28 -08003725 /* Fetch source address in a sample. */
Amaury Denoyellec460c702021-05-12 10:17:47 +02003726 if (!smp_fetch_src || !smp_fetch_src(empty_arg_list, smp, "src", NULL))
Willy Tarreau7d562212016-11-25 16:10:05 +01003727 return 0;
3728
3729 /* Converts into key. */
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003730 key = smp_to_stkey(smp, args->data.t);
Willy Tarreau7d562212016-11-25 16:10:05 +01003731 if (!key)
3732 return 0;
3733
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003734 t = args->data.t;
Willy Tarreau7d562212016-11-25 16:10:05 +01003735
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003736 if ((ts = stktable_get_entry(t, key)) == NULL)
Willy Tarreau7d562212016-11-25 16:10:05 +01003737 /* entry does not exist and could not be created */
3738 return 0;
3739
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003740 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_CONN_CNT);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003741 if (!ptr) {
Willy Tarreau7d562212016-11-25 16:10:05 +01003742 return 0; /* parameter not stored in this table */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003743 }
Willy Tarreau7d562212016-11-25 16:10:05 +01003744
3745 smp->data.type = SMP_T_SINT;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003746
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003747 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003748
Emeric Brun0e3457b2021-06-30 17:18:28 +02003749 smp->data.u.sint = ++stktable_data_cast(ptr, std_t_uint);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003750
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003751 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003752
Willy Tarreau7d562212016-11-25 16:10:05 +01003753 smp->flags = SMP_F_VOL_TEST;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003754
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003755 stktable_touch_local(t, ts, 1);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003756
3757 /* Touch was previously performed by stktable_update_key */
Willy Tarreau7d562212016-11-25 16:10:05 +01003758 return 1;
3759}
3760
3761/* set <smp> to the number of concurrent connections from the stream's tracked
3762 * frontend counters. Supports being called as "sc[0-9]_conn_cur" or
3763 * "src_conn_cur" only.
3764 */
3765static int
3766smp_fetch_sc_conn_cur(const struct arg *args, struct sample *smp, const char *kw, void *private)
3767{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003768 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003769 struct stkctr *stkctr;
3770
Emeric Brun819fc6f2017-06-13 19:37:32 +02003771 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003772 if (!stkctr)
3773 return 0;
3774
3775 smp->flags = SMP_F_VOL_TEST;
3776 smp->data.type = SMP_T_SINT;
3777 smp->data.u.sint = 0;
3778 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003779 void *ptr;
3780
3781 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_CONN_CUR);
3782 if (!ptr) {
3783 if (stkctr == &tmpstkctr)
3784 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003785 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003786 }
3787
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003788 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003789
Emeric Brun0e3457b2021-06-30 17:18:28 +02003790 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
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 streams from the stream's tracked
3801 * frontend counters. Supports being called as "sc[0-9]_sess_cnt" or
3802 * "src_sess_cnt" only.
3803 */
3804static int
3805smp_fetch_sc_sess_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_SESS_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 stream rate from the stream's tracked frontend counters.
3840 * Supports being called as "sc[0-9]_sess_rate" or "src_sess_rate" only.
3841 */
3842static int
3843smp_fetch_sc_sess_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3844{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003845 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003846 struct stkctr *stkctr;
3847
Emeric Brun819fc6f2017-06-13 19:37:32 +02003848 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003849 if (!stkctr)
3850 return 0;
3851
3852 smp->flags = SMP_F_VOL_TEST;
3853 smp->data.type = SMP_T_SINT;
3854 smp->data.u.sint = 0;
3855 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003856 void *ptr;
3857
3858 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_SESS_RATE);
3859 if (!ptr) {
3860 if (stkctr == &tmpstkctr)
3861 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003862 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003863 }
3864
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003865 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003866
Emeric Brun0e3457b2021-06-30 17:18:28 +02003867 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Willy Tarreau7d562212016-11-25 16:10:05 +01003868 stkctr->table->data_arg[STKTABLE_DT_SESS_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003869
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003870 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003871
3872 if (stkctr == &tmpstkctr)
3873 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003874 }
3875 return 1;
3876}
3877
3878/* set <smp> to the cumulated number of HTTP requests from the stream's tracked
3879 * frontend counters. Supports being called as "sc[0-9]_http_req_cnt" or
3880 * "src_http_req_cnt" only.
3881 */
3882static int
3883smp_fetch_sc_http_req_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
3884{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003885 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003886 struct stkctr *stkctr;
3887
Emeric Brun819fc6f2017-06-13 19:37:32 +02003888 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003889 if (!stkctr)
3890 return 0;
3891
3892 smp->flags = SMP_F_VOL_TEST;
3893 smp->data.type = SMP_T_SINT;
3894 smp->data.u.sint = 0;
3895 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003896 void *ptr;
3897
3898 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_REQ_CNT);
3899 if (!ptr) {
3900 if (stkctr == &tmpstkctr)
3901 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003902 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003903 }
3904
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003905 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003906
Emeric Brun0e3457b2021-06-30 17:18:28 +02003907 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003908
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003909 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003910
3911 if (stkctr == &tmpstkctr)
3912 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003913 }
3914 return 1;
3915}
3916
3917/* set <smp> to the HTTP request rate from the stream's tracked frontend
3918 * counters. Supports being called as "sc[0-9]_http_req_rate" or
3919 * "src_http_req_rate" only.
3920 */
3921static int
3922smp_fetch_sc_http_req_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3923{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003924 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003925 struct stkctr *stkctr;
3926
Emeric Brun819fc6f2017-06-13 19:37:32 +02003927 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003928 if (!stkctr)
3929 return 0;
3930
3931 smp->flags = SMP_F_VOL_TEST;
3932 smp->data.type = SMP_T_SINT;
3933 smp->data.u.sint = 0;
3934 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003935 void *ptr;
3936
3937 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_REQ_RATE);
3938 if (!ptr) {
3939 if (stkctr == &tmpstkctr)
3940 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003941 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003942 }
3943
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003944 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003945
Emeric Brun0e3457b2021-06-30 17:18:28 +02003946 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Willy Tarreau7d562212016-11-25 16:10:05 +01003947 stkctr->table->data_arg[STKTABLE_DT_HTTP_REQ_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003948
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003949 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003950
3951 if (stkctr == &tmpstkctr)
3952 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003953 }
3954 return 1;
3955}
3956
3957/* set <smp> to the cumulated number of HTTP requests errors from the stream's
3958 * tracked frontend counters. Supports being called as "sc[0-9]_http_err_cnt" or
3959 * "src_http_err_cnt" only.
3960 */
3961static int
3962smp_fetch_sc_http_err_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
3963{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003964 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003965 struct stkctr *stkctr;
3966
Emeric Brun819fc6f2017-06-13 19:37:32 +02003967 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003968 if (!stkctr)
3969 return 0;
3970
3971 smp->flags = SMP_F_VOL_TEST;
3972 smp->data.type = SMP_T_SINT;
3973 smp->data.u.sint = 0;
3974 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003975 void *ptr;
3976
3977 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_ERR_CNT);
3978 if (!ptr) {
3979 if (stkctr == &tmpstkctr)
3980 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003981 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003982 }
3983
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003984 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003985
Emeric Brun0e3457b2021-06-30 17:18:28 +02003986 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003987
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003988 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003989
3990 if (stkctr == &tmpstkctr)
3991 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003992 }
3993 return 1;
3994}
3995
3996/* set <smp> to the HTTP request error rate from the stream's tracked frontend
3997 * counters. Supports being called as "sc[0-9]_http_err_rate" or
3998 * "src_http_err_rate" only.
3999 */
4000static int
4001smp_fetch_sc_http_err_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
4002{
Emeric Brun819fc6f2017-06-13 19:37:32 +02004003 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01004004 struct stkctr *stkctr;
4005
Emeric Brun819fc6f2017-06-13 19:37:32 +02004006 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01004007 if (!stkctr)
4008 return 0;
4009
4010 smp->flags = SMP_F_VOL_TEST;
4011 smp->data.type = SMP_T_SINT;
4012 smp->data.u.sint = 0;
4013 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02004014 void *ptr;
4015
4016 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_ERR_RATE);
4017 if (!ptr) {
4018 if (stkctr == &tmpstkctr)
4019 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004020 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02004021 }
4022
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004023 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004024
Emeric Brun0e3457b2021-06-30 17:18:28 +02004025 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Willy Tarreau7d562212016-11-25 16:10:05 +01004026 stkctr->table->data_arg[STKTABLE_DT_HTTP_ERR_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004027
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004028 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004029
4030 if (stkctr == &tmpstkctr)
4031 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004032 }
4033 return 1;
4034}
4035
Willy Tarreau826f3ab2021-02-10 12:07:15 +01004036/* set <smp> to the cumulated number of HTTP response failures from the stream's
4037 * tracked frontend counters. Supports being called as "sc[0-9]_http_fail_cnt" or
4038 * "src_http_fail_cnt" only.
4039 */
4040static int
4041smp_fetch_sc_http_fail_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
4042{
4043 struct stkctr tmpstkctr;
4044 struct stkctr *stkctr;
4045
4046 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
4047 if (!stkctr)
4048 return 0;
4049
4050 smp->flags = SMP_F_VOL_TEST;
4051 smp->data.type = SMP_T_SINT;
4052 smp->data.u.sint = 0;
4053 if (stkctr_entry(stkctr) != NULL) {
4054 void *ptr;
4055
4056 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_FAIL_CNT);
4057 if (!ptr) {
4058 if (stkctr == &tmpstkctr)
4059 stktable_release(stkctr->table, stkctr_entry(stkctr));
4060 return 0; /* parameter not stored */
4061 }
4062
4063 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
4064
Emeric Brun0e3457b2021-06-30 17:18:28 +02004065 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Willy Tarreau826f3ab2021-02-10 12:07:15 +01004066
4067 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
4068
4069 if (stkctr == &tmpstkctr)
4070 stktable_release(stkctr->table, stkctr_entry(stkctr));
4071 }
4072 return 1;
4073}
4074
4075/* set <smp> to the HTTP response failure rate from the stream's tracked frontend
4076 * counters. Supports being called as "sc[0-9]_http_fail_rate" or
4077 * "src_http_fail_rate" only.
4078 */
4079static int
4080smp_fetch_sc_http_fail_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
4081{
4082 struct stkctr tmpstkctr;
4083 struct stkctr *stkctr;
4084
4085 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
4086 if (!stkctr)
4087 return 0;
4088
4089 smp->flags = SMP_F_VOL_TEST;
4090 smp->data.type = SMP_T_SINT;
4091 smp->data.u.sint = 0;
4092 if (stkctr_entry(stkctr) != NULL) {
4093 void *ptr;
4094
4095 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_FAIL_RATE);
4096 if (!ptr) {
4097 if (stkctr == &tmpstkctr)
4098 stktable_release(stkctr->table, stkctr_entry(stkctr));
4099 return 0; /* parameter not stored */
4100 }
4101
4102 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
4103
Emeric Brun0e3457b2021-06-30 17:18:28 +02004104 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Willy Tarreau826f3ab2021-02-10 12:07:15 +01004105 stkctr->table->data_arg[STKTABLE_DT_HTTP_FAIL_RATE].u);
4106
4107 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
4108
4109 if (stkctr == &tmpstkctr)
4110 stktable_release(stkctr->table, stkctr_entry(stkctr));
4111 }
4112 return 1;
4113}
4114
Willy Tarreau7d562212016-11-25 16:10:05 +01004115/* set <smp> to the number of kbytes received from clients, as found in the
4116 * stream's tracked frontend counters. Supports being called as
4117 * "sc[0-9]_kbytes_in" or "src_kbytes_in" only.
4118 */
4119static int
4120smp_fetch_sc_kbytes_in(const struct arg *args, struct sample *smp, const char *kw, void *private)
4121{
Emeric Brun819fc6f2017-06-13 19:37:32 +02004122 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01004123 struct stkctr *stkctr;
4124
Emeric Brun819fc6f2017-06-13 19:37:32 +02004125 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01004126 if (!stkctr)
4127 return 0;
4128
4129 smp->flags = SMP_F_VOL_TEST;
4130 smp->data.type = SMP_T_SINT;
4131 smp->data.u.sint = 0;
4132 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02004133 void *ptr;
4134
4135 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_IN_CNT);
4136 if (!ptr) {
4137 if (stkctr == &tmpstkctr)
4138 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004139 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02004140 }
4141
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004142 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004143
Emeric Brun0e3457b2021-06-30 17:18:28 +02004144 smp->data.u.sint = stktable_data_cast(ptr, std_t_ull) >> 10;
Emeric Brun819fc6f2017-06-13 19:37:32 +02004145
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004146 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004147
4148 if (stkctr == &tmpstkctr)
4149 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004150 }
4151 return 1;
4152}
4153
4154/* set <smp> to the data rate received from clients in bytes/s, as found
4155 * in the stream's tracked frontend counters. Supports being called as
4156 * "sc[0-9]_bytes_in_rate" or "src_bytes_in_rate" only.
4157 */
4158static int
4159smp_fetch_sc_bytes_in_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
4160{
Emeric Brun819fc6f2017-06-13 19:37:32 +02004161 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01004162 struct stkctr *stkctr;
4163
Emeric Brun819fc6f2017-06-13 19:37:32 +02004164 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01004165 if (!stkctr)
4166 return 0;
4167
4168 smp->flags = SMP_F_VOL_TEST;
4169 smp->data.type = SMP_T_SINT;
4170 smp->data.u.sint = 0;
4171 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02004172 void *ptr;
4173
4174 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_IN_RATE);
4175 if (!ptr) {
4176 if (stkctr == &tmpstkctr)
4177 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004178 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02004179 }
4180
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004181 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004182
Emeric Brun0e3457b2021-06-30 17:18:28 +02004183 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Willy Tarreau7d562212016-11-25 16:10:05 +01004184 stkctr->table->data_arg[STKTABLE_DT_BYTES_IN_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004185
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004186 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004187
4188 if (stkctr == &tmpstkctr)
4189 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004190 }
4191 return 1;
4192}
4193
4194/* set <smp> to the number of kbytes sent to clients, as found in the
4195 * stream's tracked frontend counters. Supports being called as
4196 * "sc[0-9]_kbytes_out" or "src_kbytes_out" only.
4197 */
4198static int
4199smp_fetch_sc_kbytes_out(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;
4210 smp->data.u.sint = 0;
4211 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02004212 void *ptr;
4213
4214 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_OUT_CNT);
4215 if (!ptr) {
4216 if (stkctr == &tmpstkctr)
4217 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004218 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02004219 }
4220
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004221 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004222
Emeric Brun0e3457b2021-06-30 17:18:28 +02004223 smp->data.u.sint = stktable_data_cast(ptr, std_t_ull) >> 10;
Emeric Brun819fc6f2017-06-13 19:37:32 +02004224
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004225 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004226
4227 if (stkctr == &tmpstkctr)
4228 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004229 }
4230 return 1;
4231}
4232
4233/* set <smp> to the data rate sent to clients in bytes/s, as found in the
4234 * stream's tracked frontend counters. Supports being called as
4235 * "sc[0-9]_bytes_out_rate" or "src_bytes_out_rate" only.
4236 */
4237static int
4238smp_fetch_sc_bytes_out_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
4239{
Emeric Brun819fc6f2017-06-13 19:37:32 +02004240 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01004241 struct stkctr *stkctr;
4242
Emeric Brun819fc6f2017-06-13 19:37:32 +02004243 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01004244 if (!stkctr)
4245 return 0;
4246
4247 smp->flags = SMP_F_VOL_TEST;
4248 smp->data.type = SMP_T_SINT;
4249 smp->data.u.sint = 0;
4250 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02004251 void *ptr;
4252
4253 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_OUT_RATE);
4254 if (!ptr) {
4255 if (stkctr == &tmpstkctr)
4256 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004257 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02004258 }
4259
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004260 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004261
Emeric Brun0e3457b2021-06-30 17:18:28 +02004262 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Willy Tarreau7d562212016-11-25 16:10:05 +01004263 stkctr->table->data_arg[STKTABLE_DT_BYTES_OUT_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004264
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004265 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004266
4267 if (stkctr == &tmpstkctr)
4268 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004269 }
4270 return 1;
4271}
4272
4273/* set <smp> to the number of active trackers on the SC entry in the stream's
4274 * tracked frontend counters. Supports being called as "sc[0-9]_trackers" only.
4275 */
4276static int
4277smp_fetch_sc_trackers(const struct arg *args, struct sample *smp, const char *kw, void *private)
4278{
Emeric Brun819fc6f2017-06-13 19:37:32 +02004279 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01004280 struct stkctr *stkctr;
4281
Emeric Brun819fc6f2017-06-13 19:37:32 +02004282 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01004283 if (!stkctr)
4284 return 0;
4285
4286 smp->flags = SMP_F_VOL_TEST;
4287 smp->data.type = SMP_T_SINT;
Emeric Brun819fc6f2017-06-13 19:37:32 +02004288 if (stkctr == &tmpstkctr) {
4289 smp->data.u.sint = stkctr_entry(stkctr) ? (stkctr_entry(stkctr)->ref_cnt-1) : 0;
4290 stktable_release(stkctr->table, stkctr_entry(stkctr));
4291 }
4292 else {
4293 smp->data.u.sint = stkctr_entry(stkctr) ? stkctr_entry(stkctr)->ref_cnt : 0;
4294 }
4295
Willy Tarreau7d562212016-11-25 16:10:05 +01004296 return 1;
4297}
4298
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004299
4300/* The functions below are used to manipulate table contents from the CLI.
4301 * There are 3 main actions, "clear", "set" and "show". The code is shared
4302 * between all actions, and the action is encoded in the void *private in
4303 * the appctx as well as in the keyword registration, among one of the
4304 * following values.
4305 */
4306
4307enum {
4308 STK_CLI_ACT_CLR,
4309 STK_CLI_ACT_SET,
4310 STK_CLI_ACT_SHOW,
4311};
4312
Willy Tarreau4596fe22022-05-17 19:07:51 +02004313/* Dump the status of a table to a stream connector's
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004314 * read buffer. It returns 0 if the output buffer is full
4315 * and needs to be called again, otherwise non-zero.
4316 */
Willy Tarreau83061a82018-07-13 11:56:34 +02004317static int table_dump_head_to_buffer(struct buffer *msg,
Willy Tarreaud0a06d52022-05-18 15:07:19 +02004318 struct appctx *appctx,
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004319 struct stktable *t, struct stktable *target)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004320{
Willy Tarreauc12b3212022-05-27 11:08:15 +02004321 struct stream *s = __sc_strm(appctx_sc(appctx));
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004322
4323 chunk_appendf(msg, "# table: %s, type: %s, size:%d, used:%d\n",
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004324 t->id, stktable_types[t->type].kw, t->size, t->current);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004325
4326 /* any other information should be dumped here */
4327
William Lallemand07a62f72017-05-24 00:57:40 +02004328 if (target && (strm_li(s)->bind_conf->level & ACCESS_LVL_MASK) < ACCESS_LVL_OPER)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004329 chunk_appendf(msg, "# contents not dumped due to insufficient privileges\n");
4330
Willy Tarreaud0a06d52022-05-18 15:07:19 +02004331 if (applet_putchk(appctx, msg) == -1)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004332 return 0;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004333
4334 return 1;
4335}
4336
Willy Tarreau4596fe22022-05-17 19:07:51 +02004337/* Dump a table entry to a stream connector's
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004338 * read buffer. It returns 0 if the output buffer is full
4339 * and needs to be called again, otherwise non-zero.
4340 */
Willy Tarreau83061a82018-07-13 11:56:34 +02004341static int table_dump_entry_to_buffer(struct buffer *msg,
Willy Tarreaud0a06d52022-05-18 15:07:19 +02004342 struct appctx *appctx,
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004343 struct stktable *t, struct stksess *entry)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004344{
4345 int dt;
4346
4347 chunk_appendf(msg, "%p:", entry);
4348
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004349 if (t->type == SMP_T_IPV4) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004350 char addr[INET_ADDRSTRLEN];
4351 inet_ntop(AF_INET, (const void *)&entry->key.key, addr, sizeof(addr));
4352 chunk_appendf(msg, " key=%s", addr);
4353 }
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004354 else if (t->type == SMP_T_IPV6) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004355 char addr[INET6_ADDRSTRLEN];
4356 inet_ntop(AF_INET6, (const void *)&entry->key.key, addr, sizeof(addr));
4357 chunk_appendf(msg, " key=%s", addr);
4358 }
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004359 else if (t->type == SMP_T_SINT) {
Willy Tarreau6cde5d82020-02-25 09:41:22 +01004360 chunk_appendf(msg, " key=%u", read_u32(entry->key.key));
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004361 }
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004362 else if (t->type == SMP_T_STR) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004363 chunk_appendf(msg, " key=");
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004364 dump_text(msg, (const char *)entry->key.key, t->key_size);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004365 }
4366 else {
4367 chunk_appendf(msg, " key=");
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004368 dump_binary(msg, (const char *)entry->key.key, t->key_size);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004369 }
4370
4371 chunk_appendf(msg, " use=%d exp=%d", entry->ref_cnt - 1, tick_remain(now_ms, entry->expire));
4372
4373 for (dt = 0; dt < STKTABLE_DATA_TYPES; dt++) {
4374 void *ptr;
4375
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004376 if (t->data_ofs[dt] == 0)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004377 continue;
Emeric Brunc64a2a32021-06-30 18:01:02 +02004378 if (stktable_data_types[dt].is_array) {
4379 char tmp[16] = {};
4380 const char *name_pfx = stktable_data_types[dt].name;
4381 const char *name_sfx = NULL;
4382 unsigned int idx = 0;
4383 int i = 0;
4384
4385 /* split name to show index before first _ of the name
4386 * for example: 'gpc3_rate' if array name is 'gpc_rate'.
4387 */
4388 for (i = 0 ; i < (sizeof(tmp) - 1); i++) {
4389 if (!name_pfx[i])
4390 break;
4391 if (name_pfx[i] == '_') {
4392 name_pfx = &tmp[0];
4393 name_sfx = &stktable_data_types[dt].name[i];
4394 break;
4395 }
4396 tmp[i] = name_pfx[i];
4397 }
4398
4399 ptr = stktable_data_ptr_idx(t, entry, dt, idx);
4400 while (ptr) {
4401 if (stktable_data_types[dt].arg_type == ARG_T_DELAY)
4402 chunk_appendf(msg, " %s%u%s(%u)=", name_pfx, idx, name_sfx ? name_sfx : "", t->data_arg[dt].u);
4403 else
4404 chunk_appendf(msg, " %s%u%s=", name_pfx, idx, name_sfx ? name_sfx : "");
4405 switch (stktable_data_types[dt].std_type) {
4406 case STD_T_SINT:
4407 chunk_appendf(msg, "%d", stktable_data_cast(ptr, std_t_sint));
4408 break;
4409 case STD_T_UINT:
4410 chunk_appendf(msg, "%u", stktable_data_cast(ptr, std_t_uint));
4411 break;
4412 case STD_T_ULL:
4413 chunk_appendf(msg, "%llu", stktable_data_cast(ptr, std_t_ull));
4414 break;
4415 case STD_T_FRQP:
4416 chunk_appendf(msg, "%u",
4417 read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
4418 t->data_arg[dt].u));
4419 break;
4420 }
4421 ptr = stktable_data_ptr_idx(t, entry, dt, ++idx);
4422 }
4423 continue;
4424 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004425 if (stktable_data_types[dt].arg_type == ARG_T_DELAY)
Emeric Brun01928ae2021-06-30 16:24:04 +02004426 chunk_appendf(msg, " %s(%u)=", stktable_data_types[dt].name, t->data_arg[dt].u);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004427 else
4428 chunk_appendf(msg, " %s=", stktable_data_types[dt].name);
4429
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004430 ptr = stktable_data_ptr(t, entry, dt);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004431 switch (stktable_data_types[dt].std_type) {
4432 case STD_T_SINT:
4433 chunk_appendf(msg, "%d", stktable_data_cast(ptr, std_t_sint));
4434 break;
4435 case STD_T_UINT:
4436 chunk_appendf(msg, "%u", stktable_data_cast(ptr, std_t_uint));
4437 break;
4438 case STD_T_ULL:
Emeric Brun01928ae2021-06-30 16:24:04 +02004439 chunk_appendf(msg, "%llu", stktable_data_cast(ptr, std_t_ull));
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004440 break;
4441 case STD_T_FRQP:
Emeric Brun01928ae2021-06-30 16:24:04 +02004442 chunk_appendf(msg, "%u",
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004443 read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004444 t->data_arg[dt].u));
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004445 break;
Frédéric Lécaille16b4f542019-05-23 12:15:04 +02004446 case STD_T_DICT: {
4447 struct dict_entry *de;
4448 de = stktable_data_cast(ptr, std_t_dict);
4449 chunk_appendf(msg, "%s", de ? (char *)de->value.key : "-");
4450 break;
4451 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004452 }
4453 }
4454 chunk_appendf(msg, "\n");
4455
Willy Tarreaud0a06d52022-05-18 15:07:19 +02004456 if (applet_putchk(appctx, msg) == -1)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004457 return 0;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004458
4459 return 1;
4460}
4461
Willy Tarreau3c69e082022-05-03 11:35:07 +02004462/* appctx context used by the "show table" command */
4463struct show_table_ctx {
4464 void *target; /* table we want to dump, or NULL for all */
4465 struct stktable *t; /* table being currently dumped (first if NULL) */
4466 struct stksess *entry; /* last entry we were trying to dump (or first if NULL) */
4467 long long value[STKTABLE_FILTER_LEN]; /* value to compare against */
4468 signed char data_type[STKTABLE_FILTER_LEN]; /* type of data to compare, or -1 if none */
4469 signed char data_op[STKTABLE_FILTER_LEN]; /* operator (STD_OP_*) when data_type set */
Willy Tarreau7849d4c2022-05-03 11:45:02 +02004470 enum {
Willy Tarreau0f154ed2022-05-03 12:02:36 +02004471 STATE_NEXT = 0, /* px points to next table, entry=NULL */
Willy Tarreau7849d4c2022-05-03 11:45:02 +02004472 STATE_DUMP, /* px points to curr table, entry is valid, refcount held */
4473 STATE_DONE, /* done dumping */
4474 } state;
Willy Tarreau3c69e082022-05-03 11:35:07 +02004475 char action; /* action on the table : one of STK_CLI_ACT_* */
4476};
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004477
4478/* Processes a single table entry matching a specific key passed in argument.
4479 * returns 0 if wants to be called again, 1 if has ended processing.
4480 */
4481static int table_process_entry_per_key(struct appctx *appctx, char **args)
4482{
Willy Tarreau3c69e082022-05-03 11:35:07 +02004483 struct show_table_ctx *ctx = appctx->svcctx;
4484 struct stktable *t = ctx->target;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004485 struct stksess *ts;
4486 uint32_t uint32_key;
4487 unsigned char ip6_key[sizeof(struct in6_addr)];
4488 long long value;
4489 int data_type;
4490 int cur_arg;
4491 void *ptr;
Willy Tarreaufa1258f2021-04-10 23:00:53 +02004492 struct freq_ctr *frqp;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004493
Willy Tarreau9d008692019-08-09 11:21:01 +02004494 if (!*args[4])
4495 return cli_err(appctx, "Key value expected\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004496
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004497 switch (t->type) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004498 case SMP_T_IPV4:
4499 uint32_key = htonl(inetaddr_host(args[4]));
Christopher Fauletca20d022017-08-29 15:30:31 +02004500 static_table_key.key = &uint32_key;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004501 break;
4502 case SMP_T_IPV6:
Christopher Fauletb7c962b2021-11-15 09:17:25 +01004503 if (inet_pton(AF_INET6, args[4], ip6_key) <= 0)
4504 return cli_err(appctx, "Invalid key\n");
Christopher Fauletca20d022017-08-29 15:30:31 +02004505 static_table_key.key = &ip6_key;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004506 break;
4507 case SMP_T_SINT:
4508 {
4509 char *endptr;
4510 unsigned long val;
4511 errno = 0;
4512 val = strtoul(args[4], &endptr, 10);
4513 if ((errno == ERANGE && val == ULONG_MAX) ||
4514 (errno != 0 && val == 0) || endptr == args[4] ||
Willy Tarreau9d008692019-08-09 11:21:01 +02004515 val > 0xffffffff)
4516 return cli_err(appctx, "Invalid key\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004517 uint32_key = (uint32_t) val;
Christopher Fauletca20d022017-08-29 15:30:31 +02004518 static_table_key.key = &uint32_key;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004519 break;
4520 }
4521 break;
4522 case SMP_T_STR:
Christopher Fauletca20d022017-08-29 15:30:31 +02004523 static_table_key.key = args[4];
4524 static_table_key.key_len = strlen(args[4]);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004525 break;
4526 default:
Willy Tarreau3c69e082022-05-03 11:35:07 +02004527 switch (ctx->action) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004528 case STK_CLI_ACT_SHOW:
Willy Tarreau9d008692019-08-09 11:21:01 +02004529 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 +01004530 case STK_CLI_ACT_CLR:
Willy Tarreau9d008692019-08-09 11:21:01 +02004531 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 +01004532 case STK_CLI_ACT_SET:
Willy Tarreau9d008692019-08-09 11:21:01 +02004533 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 +01004534 default:
Willy Tarreau9d008692019-08-09 11:21:01 +02004535 return cli_err(appctx, "Unknown action\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004536 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004537 }
4538
4539 /* check permissions */
4540 if (!cli_has_level(appctx, ACCESS_LVL_OPER))
4541 return 1;
4542
Willy Tarreau3c69e082022-05-03 11:35:07 +02004543 switch (ctx->action) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004544 case STK_CLI_ACT_SHOW:
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004545 ts = stktable_lookup_key(t, &static_table_key);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004546 if (!ts)
4547 return 1;
4548 chunk_reset(&trash);
Willy Tarreaud0a06d52022-05-18 15:07:19 +02004549 if (!table_dump_head_to_buffer(&trash, appctx, t, t)) {
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004550 stktable_release(t, ts);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004551 return 0;
Emeric Brun819fc6f2017-06-13 19:37:32 +02004552 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004553 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &ts->lock);
Willy Tarreaud0a06d52022-05-18 15:07:19 +02004554 if (!table_dump_entry_to_buffer(&trash, appctx, t, ts)) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004555 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004556 stktable_release(t, ts);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004557 return 0;
Emeric Brun819fc6f2017-06-13 19:37:32 +02004558 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004559 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004560 stktable_release(t, ts);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004561 break;
4562
4563 case STK_CLI_ACT_CLR:
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004564 ts = stktable_lookup_key(t, &static_table_key);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004565 if (!ts)
4566 return 1;
Emeric Brun819fc6f2017-06-13 19:37:32 +02004567
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004568 if (!stksess_kill(t, ts, 1)) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004569 /* don't delete an entry which is currently referenced */
Willy Tarreau9d008692019-08-09 11:21:01 +02004570 return cli_err(appctx, "Entry currently in use, cannot remove\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004571 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004572 break;
4573
4574 case STK_CLI_ACT_SET:
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004575 ts = stktable_get_entry(t, &static_table_key);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004576 if (!ts) {
4577 /* don't delete an entry which is currently referenced */
Willy Tarreau9d008692019-08-09 11:21:01 +02004578 return cli_err(appctx, "Unable to allocate a new entry\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004579 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004580 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004581 for (cur_arg = 5; *args[cur_arg]; cur_arg += 2) {
4582 if (strncmp(args[cur_arg], "data.", 5) != 0) {
Willy Tarreau9d008692019-08-09 11:21:01 +02004583 cli_err(appctx, "\"data.<type>\" followed by a value expected\n");
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004584 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004585 stktable_touch_local(t, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004586 return 1;
4587 }
4588
4589 data_type = stktable_get_data_type(args[cur_arg] + 5);
4590 if (data_type < 0) {
Willy Tarreau9d008692019-08-09 11:21:01 +02004591 cli_err(appctx, "Unknown data type\n");
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004592 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004593 stktable_touch_local(t, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004594 return 1;
4595 }
4596
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004597 if (!t->data_ofs[data_type]) {
Willy Tarreau9d008692019-08-09 11:21:01 +02004598 cli_err(appctx, "Data type not stored in this table\n");
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004599 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004600 stktable_touch_local(t, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004601 return 1;
4602 }
4603
4604 if (!*args[cur_arg+1] || strl2llrc(args[cur_arg+1], strlen(args[cur_arg+1]), &value) != 0) {
Willy Tarreau9d008692019-08-09 11:21:01 +02004605 cli_err(appctx, "Require a valid integer value to store\n");
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004606 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004607 stktable_touch_local(t, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004608 return 1;
4609 }
4610
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004611 ptr = stktable_data_ptr(t, ts, data_type);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004612
4613 switch (stktable_data_types[data_type].std_type) {
4614 case STD_T_SINT:
4615 stktable_data_cast(ptr, std_t_sint) = value;
4616 break;
4617 case STD_T_UINT:
4618 stktable_data_cast(ptr, std_t_uint) = value;
4619 break;
4620 case STD_T_ULL:
4621 stktable_data_cast(ptr, std_t_ull) = value;
4622 break;
4623 case STD_T_FRQP:
4624 /* We set both the current and previous values. That way
4625 * the reported frequency is stable during all the period
4626 * then slowly fades out. This allows external tools to
4627 * push measures without having to update them too often.
4628 */
4629 frqp = &stktable_data_cast(ptr, std_t_frqp);
Willy Tarreaufa1258f2021-04-10 23:00:53 +02004630 /* First bit is reserved for the freq_ctr lock
Emeric Brunf2fc1fd2017-11-02 17:32:43 +01004631 Note: here we're still protected by the stksess lock
Willy Tarreaufa1258f2021-04-10 23:00:53 +02004632 so we don't need to update the update the freq_ctr
Emeric Brunf2fc1fd2017-11-02 17:32:43 +01004633 using its internal lock */
4634 frqp->curr_tick = now_ms & ~0x1;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004635 frqp->prev_ctr = 0;
4636 frqp->curr_ctr = value;
4637 break;
4638 }
4639 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004640 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004641 stktable_touch_local(t, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004642 break;
4643
4644 default:
Willy Tarreau9d008692019-08-09 11:21:01 +02004645 return cli_err(appctx, "Unknown action\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004646 }
4647 return 1;
4648}
4649
4650/* Prepares the appctx fields with the data-based filters from the command line.
4651 * Returns 0 if the dump can proceed, 1 if has ended processing.
4652 */
4653static int table_prepare_data_request(struct appctx *appctx, char **args)
4654{
Willy Tarreau3c69e082022-05-03 11:35:07 +02004655 struct show_table_ctx *ctx = appctx->svcctx;
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004656 int i;
Adis Nezirovicd0142e72020-01-22 16:50:27 +01004657 char *err = NULL;
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004658
Willy Tarreau3c69e082022-05-03 11:35:07 +02004659 if (ctx->action != STK_CLI_ACT_SHOW && ctx->action != STK_CLI_ACT_CLR)
Willy Tarreau9d008692019-08-09 11:21:01 +02004660 return cli_err(appctx, "content-based lookup is only supported with the \"show\" and \"clear\" actions\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004661
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004662 for (i = 0; i < STKTABLE_FILTER_LEN; i++) {
4663 if (i > 0 && !*args[3+3*i]) // number of filter entries can be less than STKTABLE_FILTER_LEN
4664 break;
4665 /* condition on stored data value */
Willy Tarreau3c69e082022-05-03 11:35:07 +02004666 ctx->data_type[i] = stktable_get_data_type(args[3+3*i] + 5);
4667 if (ctx->data_type[i] < 0)
Adis Nezirovicd0142e72020-01-22 16:50:27 +01004668 return cli_dynerr(appctx, memprintf(&err, "Filter entry #%i: Unknown data type\n", i + 1));
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004669
Willy Tarreau3c69e082022-05-03 11:35:07 +02004670 if (!((struct stktable *)ctx->target)->data_ofs[ctx->data_type[i]])
Adis Nezirovicd0142e72020-01-22 16:50:27 +01004671 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 +01004672
Willy Tarreau3c69e082022-05-03 11:35:07 +02004673 ctx->data_op[i] = get_std_op(args[4+3*i]);
4674 if (ctx->data_op[i] < 0)
Adis Nezirovicd0142e72020-01-22 16:50:27 +01004675 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 +01004676
Willy Tarreau3c69e082022-05-03 11:35:07 +02004677 if (!*args[5+3*i] || strl2llrc(args[5+3*i], strlen(args[5+3*i]), &ctx->value[i]) != 0)
Adis Nezirovicd0142e72020-01-22 16:50:27 +01004678 return cli_dynerr(appctx, memprintf(&err, "Filter entry #%i: Require a valid integer value to compare against\n", i + 1));
4679 }
4680
4681 if (*args[3+3*i]) {
4682 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 +01004683 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004684
4685 /* OK we're done, all the fields are set */
4686 return 0;
4687}
4688
4689/* returns 0 if wants to be called, 1 if has ended processing */
Aurélien Nephtaliabbf6072018-04-18 13:26:46 +02004690static int cli_parse_table_req(char **args, char *payload, struct appctx *appctx, void *private)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004691{
Willy Tarreau3c69e082022-05-03 11:35:07 +02004692 struct show_table_ctx *ctx = applet_reserve_svcctx(appctx, sizeof(*ctx));
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004693 int i;
4694
4695 for (i = 0; i < STKTABLE_FILTER_LEN; i++)
Willy Tarreau3c69e082022-05-03 11:35:07 +02004696 ctx->data_type[i] = -1;
4697 ctx->target = NULL;
4698 ctx->entry = NULL;
4699 ctx->action = (long)private; // keyword argument, one of STK_CLI_ACT_*
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004700
4701 if (*args[2]) {
Willy Tarreau0f154ed2022-05-03 12:02:36 +02004702 ctx->t = ctx->target = stktable_find_by_name(args[2]);
Willy Tarreau3c69e082022-05-03 11:35:07 +02004703 if (!ctx->target)
Willy Tarreau9d008692019-08-09 11:21:01 +02004704 return cli_err(appctx, "No such table\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004705 }
4706 else {
Willy Tarreau0f154ed2022-05-03 12:02:36 +02004707 ctx->t = stktables_list;
Willy Tarreau3c69e082022-05-03 11:35:07 +02004708 if (ctx->action != STK_CLI_ACT_SHOW)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004709 goto err_args;
4710 return 0;
4711 }
4712
4713 if (strcmp(args[3], "key") == 0)
4714 return table_process_entry_per_key(appctx, args);
4715 else if (strncmp(args[3], "data.", 5) == 0)
4716 return table_prepare_data_request(appctx, args);
4717 else if (*args[3])
4718 goto err_args;
4719
4720 return 0;
4721
4722err_args:
Willy Tarreau3c69e082022-05-03 11:35:07 +02004723 switch (ctx->action) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004724 case STK_CLI_ACT_SHOW:
Willy Tarreau9d008692019-08-09 11:21:01 +02004725 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 +01004726 case STK_CLI_ACT_CLR:
Willy Tarreau9d008692019-08-09 11:21:01 +02004727 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 +01004728 case STK_CLI_ACT_SET:
Willy Tarreau9d008692019-08-09 11:21:01 +02004729 return cli_err(appctx, "Required arguments: <table> key <key> [data.<store_data_type> <value>]*\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004730 default:
Willy Tarreau9d008692019-08-09 11:21:01 +02004731 return cli_err(appctx, "Unknown action\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004732 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004733}
4734
4735/* This function is used to deal with table operations (dump or clear depending
4736 * on the action stored in appctx->private). It returns 0 if the output buffer is
4737 * full and it needs to be called again, otherwise non-zero.
4738 */
4739static int cli_io_handler_table(struct appctx *appctx)
4740{
Willy Tarreau3c69e082022-05-03 11:35:07 +02004741 struct show_table_ctx *ctx = appctx->svcctx;
Willy Tarreauc12b3212022-05-27 11:08:15 +02004742 struct stconn *sc = appctx_sc(appctx);
Willy Tarreau475e4632022-05-27 10:26:46 +02004743 struct stream *s = __sc_strm(sc);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004744 struct ebmb_node *eb;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004745 int skip_entry;
Willy Tarreau3c69e082022-05-03 11:35:07 +02004746 int show = ctx->action == STK_CLI_ACT_SHOW;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004747
4748 /*
Willy Tarreau0f154ed2022-05-03 12:02:36 +02004749 * We have 3 possible states in ctx->state :
Willy Tarreau7849d4c2022-05-03 11:45:02 +02004750 * - STATE_NEXT : the proxy pointer points to the next table to
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004751 * dump, the entry pointer is NULL ;
Willy Tarreau7849d4c2022-05-03 11:45:02 +02004752 * - STATE_DUMP : the proxy pointer points to the current table
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004753 * and the entry pointer points to the next entry to be dumped,
4754 * and the refcount on the next entry is held ;
Willy Tarreau7849d4c2022-05-03 11:45:02 +02004755 * - STATE_DONE : nothing left to dump, the buffer may contain some
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004756 * data though.
4757 */
4758
Willy Tarreau475e4632022-05-27 10:26:46 +02004759 if (unlikely(sc_ic(sc)->flags & (CF_WRITE_ERROR|CF_SHUTW))) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004760 /* in case of abort, remove any refcount we might have set on an entry */
Willy Tarreau7849d4c2022-05-03 11:45:02 +02004761 if (ctx->state == STATE_DUMP) {
Willy Tarreau3c69e082022-05-03 11:35:07 +02004762 stksess_kill_if_expired(ctx->t, ctx->entry, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004763 }
4764 return 1;
4765 }
4766
4767 chunk_reset(&trash);
4768
Willy Tarreau7849d4c2022-05-03 11:45:02 +02004769 while (ctx->state != STATE_DONE) {
4770 switch (ctx->state) {
Willy Tarreau7849d4c2022-05-03 11:45:02 +02004771 case STATE_NEXT:
Willy Tarreau3c69e082022-05-03 11:35:07 +02004772 if (!ctx->t ||
4773 (ctx->target &&
4774 ctx->t != ctx->target)) {
Willy Tarreau7849d4c2022-05-03 11:45:02 +02004775 ctx->state = STATE_DONE;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004776 break;
4777 }
4778
Willy Tarreau3c69e082022-05-03 11:35:07 +02004779 if (ctx->t->size) {
Willy Tarreaud0a06d52022-05-18 15:07:19 +02004780 if (show && !table_dump_head_to_buffer(&trash, appctx, ctx->t, ctx->target))
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004781 return 0;
4782
Willy Tarreau3c69e082022-05-03 11:35:07 +02004783 if (ctx->target &&
William Lallemand07a62f72017-05-24 00:57:40 +02004784 (strm_li(s)->bind_conf->level & ACCESS_LVL_MASK) >= ACCESS_LVL_OPER) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004785 /* dump entries only if table explicitly requested */
Willy Tarreau3c69e082022-05-03 11:35:07 +02004786 HA_SPIN_LOCK(STK_TABLE_LOCK, &ctx->t->lock);
4787 eb = ebmb_first(&ctx->t->keys);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004788 if (eb) {
Willy Tarreau3c69e082022-05-03 11:35:07 +02004789 ctx->entry = ebmb_entry(eb, struct stksess, key);
4790 ctx->entry->ref_cnt++;
Willy Tarreau7849d4c2022-05-03 11:45:02 +02004791 ctx->state = STATE_DUMP;
Willy Tarreau3c69e082022-05-03 11:35:07 +02004792 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &ctx->t->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004793 break;
4794 }
Willy Tarreau3c69e082022-05-03 11:35:07 +02004795 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &ctx->t->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004796 }
4797 }
Willy Tarreau3c69e082022-05-03 11:35:07 +02004798 ctx->t = ctx->t->next;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004799 break;
4800
Willy Tarreau7849d4c2022-05-03 11:45:02 +02004801 case STATE_DUMP:
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004802 skip_entry = 0;
4803
Willy Tarreau3c69e082022-05-03 11:35:07 +02004804 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &ctx->entry->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004805
Willy Tarreau3c69e082022-05-03 11:35:07 +02004806 if (ctx->data_type[0] >= 0) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004807 /* we're filtering on some data contents */
4808 void *ptr;
Willy Tarreau2b64a352020-01-22 17:09:47 +01004809 int dt, i;
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004810 signed char op;
4811 long long data, value;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004812
Emeric Brun819fc6f2017-06-13 19:37:32 +02004813
Willy Tarreau2b64a352020-01-22 17:09:47 +01004814 for (i = 0; i < STKTABLE_FILTER_LEN; i++) {
Willy Tarreau3c69e082022-05-03 11:35:07 +02004815 if (ctx->data_type[i] == -1)
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004816 break;
Willy Tarreau3c69e082022-05-03 11:35:07 +02004817 dt = ctx->data_type[i];
4818 ptr = stktable_data_ptr(ctx->t,
4819 ctx->entry,
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004820 dt);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004821
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004822 data = 0;
4823 switch (stktable_data_types[dt].std_type) {
4824 case STD_T_SINT:
4825 data = stktable_data_cast(ptr, std_t_sint);
4826 break;
4827 case STD_T_UINT:
4828 data = stktable_data_cast(ptr, std_t_uint);
4829 break;
4830 case STD_T_ULL:
4831 data = stktable_data_cast(ptr, std_t_ull);
4832 break;
4833 case STD_T_FRQP:
4834 data = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Willy Tarreau3c69e082022-05-03 11:35:07 +02004835 ctx->t->data_arg[dt].u);
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004836 break;
4837 }
4838
Willy Tarreau3c69e082022-05-03 11:35:07 +02004839 op = ctx->data_op[i];
4840 value = ctx->value[i];
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004841
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004842 /* skip the entry if the data does not match the test and the value */
4843 if ((data < value &&
4844 (op == STD_OP_EQ || op == STD_OP_GT || op == STD_OP_GE)) ||
4845 (data == value &&
4846 (op == STD_OP_NE || op == STD_OP_GT || op == STD_OP_LT)) ||
4847 (data > value &&
4848 (op == STD_OP_EQ || op == STD_OP_LT || op == STD_OP_LE))) {
4849 skip_entry = 1;
4850 break;
4851 }
4852 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004853 }
4854
4855 if (show && !skip_entry &&
Willy Tarreaud0a06d52022-05-18 15:07:19 +02004856 !table_dump_entry_to_buffer(&trash, appctx, ctx->t, ctx->entry)) {
Willy Tarreau3c69e082022-05-03 11:35:07 +02004857 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &ctx->entry->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004858 return 0;
4859 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004860
Willy Tarreau3c69e082022-05-03 11:35:07 +02004861 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &ctx->entry->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004862
Willy Tarreau3c69e082022-05-03 11:35:07 +02004863 HA_SPIN_LOCK(STK_TABLE_LOCK, &ctx->t->lock);
4864 ctx->entry->ref_cnt--;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004865
Willy Tarreau3c69e082022-05-03 11:35:07 +02004866 eb = ebmb_next(&ctx->entry->key);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004867 if (eb) {
Willy Tarreau3c69e082022-05-03 11:35:07 +02004868 struct stksess *old = ctx->entry;
4869 ctx->entry = ebmb_entry(eb, struct stksess, key);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004870 if (show)
Willy Tarreau3c69e082022-05-03 11:35:07 +02004871 __stksess_kill_if_expired(ctx->t, old);
4872 else if (!skip_entry && !ctx->entry->ref_cnt)
4873 __stksess_kill(ctx->t, old);
4874 ctx->entry->ref_cnt++;
4875 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &ctx->t->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004876 break;
4877 }
4878
4879
4880 if (show)
Willy Tarreau3c69e082022-05-03 11:35:07 +02004881 __stksess_kill_if_expired(ctx->t, ctx->entry);
4882 else if (!skip_entry && !ctx->entry->ref_cnt)
4883 __stksess_kill(ctx->t, ctx->entry);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004884
Willy Tarreau3c69e082022-05-03 11:35:07 +02004885 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &ctx->t->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004886
Willy Tarreau3c69e082022-05-03 11:35:07 +02004887 ctx->t = ctx->t->next;
Willy Tarreau7849d4c2022-05-03 11:45:02 +02004888 ctx->state = STATE_NEXT;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004889 break;
4890
Willy Tarreau7849d4c2022-05-03 11:45:02 +02004891 default:
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004892 break;
4893 }
4894 }
4895 return 1;
4896}
4897
4898static void cli_release_show_table(struct appctx *appctx)
4899{
Willy Tarreau3c69e082022-05-03 11:35:07 +02004900 struct show_table_ctx *ctx = appctx->svcctx;
4901
Willy Tarreau7849d4c2022-05-03 11:45:02 +02004902 if (ctx->state == STATE_DUMP) {
Willy Tarreau3c69e082022-05-03 11:35:07 +02004903 stksess_kill_if_expired(ctx->t, ctx->entry, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004904 }
4905}
4906
Willy Tarreau478331d2020-08-28 11:31:31 +02004907static void stkt_late_init(void)
4908{
4909 struct sample_fetch *f;
4910
4911 f = find_sample_fetch("src", strlen("src"));
4912 if (f)
4913 smp_fetch_src = f->process;
4914}
4915
4916INITCALL0(STG_INIT, stkt_late_init);
4917
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004918/* register cli keywords */
4919static struct cli_kw_list cli_kws = {{ },{
Willy Tarreaub205bfd2021-05-07 11:38:37 +02004920 { { "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 },
4921 { { "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 },
4922 { { "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 +01004923 {{},}
4924}};
4925
Willy Tarreau0108d902018-11-25 19:14:37 +01004926INITCALL1(STG_REGISTER, cli_register_kw, &cli_kws);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004927
Thierry FOURNIER236657b2015-08-19 08:25:14 +02004928static struct action_kw_list tcp_conn_kws = { { }, {
Emeric Brun4d7ada82021-06-30 19:04:16 +02004929 { "sc-inc-gpc", parse_inc_gpc, KWF_MATCH_PREFIX },
4930 { "sc-inc-gpc0", parse_inc_gpc, KWF_MATCH_PREFIX },
4931 { "sc-inc-gpc1", parse_inc_gpc, KWF_MATCH_PREFIX },
Emeric Brun877b0b52021-06-30 18:57:49 +02004932 { "sc-set-gpt", parse_set_gpt, KWF_MATCH_PREFIX },
4933 { "sc-set-gpt0", parse_set_gpt, KWF_MATCH_PREFIX },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02004934 { /* END */ }
4935}};
4936
Willy Tarreau0108d902018-11-25 19:14:37 +01004937INITCALL1(STG_REGISTER, tcp_req_conn_keywords_register, &tcp_conn_kws);
4938
Willy Tarreau620408f2016-10-21 16:37:51 +02004939static struct action_kw_list tcp_sess_kws = { { }, {
Emeric Brun4d7ada82021-06-30 19:04:16 +02004940 { "sc-inc-gpc", parse_inc_gpc, KWF_MATCH_PREFIX },
4941 { "sc-inc-gpc0", parse_inc_gpc, KWF_MATCH_PREFIX },
4942 { "sc-inc-gpc1", parse_inc_gpc, KWF_MATCH_PREFIX },
Emeric Brun877b0b52021-06-30 18:57:49 +02004943 { "sc-set-gpt", parse_set_gpt, KWF_MATCH_PREFIX },
4944 { "sc-set-gpt0", parse_set_gpt, KWF_MATCH_PREFIX },
Willy Tarreau620408f2016-10-21 16:37:51 +02004945 { /* END */ }
4946}};
4947
Willy Tarreau0108d902018-11-25 19:14:37 +01004948INITCALL1(STG_REGISTER, tcp_req_sess_keywords_register, &tcp_sess_kws);
4949
Thierry FOURNIER236657b2015-08-19 08:25:14 +02004950static struct action_kw_list tcp_req_kws = { { }, {
Emeric Brun4d7ada82021-06-30 19:04:16 +02004951 { "sc-inc-gpc", parse_inc_gpc, KWF_MATCH_PREFIX },
4952 { "sc-inc-gpc0", parse_inc_gpc, KWF_MATCH_PREFIX },
4953 { "sc-inc-gpc1", parse_inc_gpc, KWF_MATCH_PREFIX },
Emeric Brun877b0b52021-06-30 18:57:49 +02004954 { "sc-set-gpt", parse_set_gpt, KWF_MATCH_PREFIX },
4955 { "sc-set-gpt0", parse_set_gpt, KWF_MATCH_PREFIX },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02004956 { /* END */ }
4957}};
4958
Willy Tarreau0108d902018-11-25 19:14:37 +01004959INITCALL1(STG_REGISTER, tcp_req_cont_keywords_register, &tcp_req_kws);
4960
Thierry FOURNIER236657b2015-08-19 08:25:14 +02004961static struct action_kw_list tcp_res_kws = { { }, {
Emeric Brun4d7ada82021-06-30 19:04:16 +02004962 { "sc-inc-gpc", parse_inc_gpc, KWF_MATCH_PREFIX },
4963 { "sc-inc-gpc0", parse_inc_gpc, KWF_MATCH_PREFIX },
4964 { "sc-inc-gpc1", parse_inc_gpc, KWF_MATCH_PREFIX },
Emeric Brun877b0b52021-06-30 18:57:49 +02004965 { "sc-set-gpt", parse_set_gpt, KWF_MATCH_PREFIX },
4966 { "sc-set-gpt0", parse_set_gpt, KWF_MATCH_PREFIX },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02004967 { /* END */ }
4968}};
4969
Willy Tarreau0108d902018-11-25 19:14:37 +01004970INITCALL1(STG_REGISTER, tcp_res_cont_keywords_register, &tcp_res_kws);
4971
Thierry FOURNIER236657b2015-08-19 08:25:14 +02004972static struct action_kw_list http_req_kws = { { }, {
Emeric Brun4d7ada82021-06-30 19:04:16 +02004973 { "sc-inc-gpc", parse_inc_gpc, KWF_MATCH_PREFIX },
4974 { "sc-inc-gpc0", parse_inc_gpc, KWF_MATCH_PREFIX },
4975 { "sc-inc-gpc1", parse_inc_gpc, KWF_MATCH_PREFIX },
Emeric Brun877b0b52021-06-30 18:57:49 +02004976 { "sc-set-gpt", parse_set_gpt, KWF_MATCH_PREFIX },
4977 { "sc-set-gpt0", parse_set_gpt, KWF_MATCH_PREFIX },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02004978 { /* END */ }
4979}};
4980
Willy Tarreau0108d902018-11-25 19:14:37 +01004981INITCALL1(STG_REGISTER, http_req_keywords_register, &http_req_kws);
4982
Thierry FOURNIER236657b2015-08-19 08:25:14 +02004983static struct action_kw_list http_res_kws = { { }, {
Emeric Brun4d7ada82021-06-30 19:04:16 +02004984 { "sc-inc-gpc", parse_inc_gpc, KWF_MATCH_PREFIX },
4985 { "sc-inc-gpc0", parse_inc_gpc, KWF_MATCH_PREFIX },
4986 { "sc-inc-gpc1", parse_inc_gpc, KWF_MATCH_PREFIX },
Emeric Brun877b0b52021-06-30 18:57:49 +02004987 { "sc-set-gpt", parse_set_gpt, KWF_MATCH_PREFIX },
4988 { "sc-set-gpt0", parse_set_gpt, KWF_MATCH_PREFIX },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02004989 { /* END */ }
4990}};
4991
Willy Tarreau0108d902018-11-25 19:14:37 +01004992INITCALL1(STG_REGISTER, http_res_keywords_register, &http_res_kws);
4993
Willy Tarreau7d562212016-11-25 16:10:05 +01004994/* Note: must not be declared <const> as its list will be overwritten.
4995 * Please take care of keeping this list alphabetically sorted.
4996 */
4997static struct sample_fetch_kw_list smp_fetch_keywords = {ILH, {
4998 { "sc_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4999 { "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 +02005000 { "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 +01005001 { "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 +01005002 { "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 +01005003 { "sc_conn_cnt", smp_fetch_sc_conn_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5004 { "sc_conn_cur", smp_fetch_sc_conn_cur, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5005 { "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 +02005006 { "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 +01005007 { "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 +02005008 { "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 +01005009 { "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 +01005010 { "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 +02005011 { "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 +01005012 { "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 +01005013 { "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 +01005014 { "sc_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5015 { "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 +01005016 { "sc_http_fail_cnt", smp_fetch_sc_http_fail_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5017 { "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 +01005018 { "sc_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5019 { "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 +02005020 { "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 +01005021 { "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 +01005022 { "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 +01005023 { "sc_kbytes_in", smp_fetch_sc_kbytes_in, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5024 { "sc_kbytes_out", smp_fetch_sc_kbytes_out, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5025 { "sc_sess_cnt", smp_fetch_sc_sess_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5026 { "sc_sess_rate", smp_fetch_sc_sess_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5027 { "sc_tracked", smp_fetch_sc_tracked, ARG2(1,SINT,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
5028 { "sc_trackers", smp_fetch_sc_trackers, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5029 { "sc0_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5030 { "sc0_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5031 { "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 +01005032 { "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 +01005033 { "sc0_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5034 { "sc0_conn_cur", smp_fetch_sc_conn_cur, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5035 { "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 +01005036 { "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 +01005037 { "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 +01005038 { "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 +01005039 { "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 +01005040 { "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 +01005041 { "sc0_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5042 { "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 +01005043 { "sc0_http_fail_cnt", smp_fetch_sc_http_fail_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5044 { "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 +01005045 { "sc0_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5046 { "sc0_http_req_rate", smp_fetch_sc_http_req_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5047 { "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 +01005048 { "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 +01005049 { "sc0_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5050 { "sc0_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5051 { "sc0_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5052 { "sc0_sess_rate", smp_fetch_sc_sess_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5053 { "sc0_tracked", smp_fetch_sc_tracked, ARG1(0,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
5054 { "sc0_trackers", smp_fetch_sc_trackers, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5055 { "sc1_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5056 { "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 +02005057 { "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 +01005058 { "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 +01005059 { "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 +01005060 { "sc1_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5061 { "sc1_conn_cur", smp_fetch_sc_conn_cur, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5062 { "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 +01005063 { "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 +01005064 { "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 +01005065 { "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 +01005066 { "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 +01005067 { "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 +01005068 { "sc1_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5069 { "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 +01005070 { "sc1_http_fail_cnt", smp_fetch_sc_http_fail_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5071 { "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 +01005072 { "sc1_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5073 { "sc1_http_req_rate", smp_fetch_sc_http_req_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5074 { "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 +01005075 { "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 +01005076 { "sc1_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5077 { "sc1_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5078 { "sc1_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5079 { "sc1_sess_rate", smp_fetch_sc_sess_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5080 { "sc1_tracked", smp_fetch_sc_tracked, ARG1(0,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
5081 { "sc1_trackers", smp_fetch_sc_trackers, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5082 { "sc2_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5083 { "sc2_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5084 { "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 +01005085 { "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 +01005086 { "sc2_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5087 { "sc2_conn_cur", smp_fetch_sc_conn_cur, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5088 { "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 +01005089 { "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 +01005090 { "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 +01005091 { "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 +01005092 { "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 +01005093 { "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 +01005094 { "sc2_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5095 { "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 +01005096 { "sc2_http_fail_cnt", smp_fetch_sc_http_fail_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5097 { "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 +01005098 { "sc2_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5099 { "sc2_http_req_rate", smp_fetch_sc_http_req_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5100 { "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 +01005101 { "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 +01005102 { "sc2_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5103 { "sc2_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5104 { "sc2_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5105 { "sc2_sess_rate", smp_fetch_sc_sess_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5106 { "sc2_tracked", smp_fetch_sc_tracked, ARG1(0,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
5107 { "sc2_trackers", smp_fetch_sc_trackers, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5108 { "src_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5109 { "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 +02005110 { "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 +01005111 { "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 +01005112 { "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 +01005113 { "src_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5114 { "src_conn_cur", smp_fetch_sc_conn_cur, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5115 { "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 +02005116 { "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 +01005117 { "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 +02005118 { "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 +01005119 { "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 +01005120 { "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 +02005121 { "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 +01005122 { "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 +01005123 { "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 +01005124 { "src_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5125 { "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 +01005126 { "src_http_fail_cnt", smp_fetch_sc_http_fail_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5127 { "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 +01005128 { "src_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5129 { "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 +02005130 { "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 +01005131 { "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 +01005132 { "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 +01005133 { "src_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5134 { "src_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5135 { "src_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5136 { "src_sess_rate", smp_fetch_sc_sess_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5137 { "src_updt_conn_cnt", smp_fetch_src_updt_conn_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5138 { "table_avl", smp_fetch_table_avl, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5139 { "table_cnt", smp_fetch_table_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5140 { /* END */ },
5141}};
5142
Willy Tarreau0108d902018-11-25 19:14:37 +01005143INITCALL1(STG_REGISTER, sample_register_fetches, &smp_fetch_keywords);
Willy Tarreau7d562212016-11-25 16:10:05 +01005144
Willy Tarreaud9f316a2014-07-10 14:03:38 +02005145/* Note: must not be declared <const> as its list will be overwritten */
5146static struct sample_conv_kw_list sample_conv_kws = {ILH, {
Willy Tarreau2d17db52016-05-25 17:16:38 +02005147 { "in_table", sample_conv_in_table, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_BOOL },
5148 { "table_bytes_in_rate", sample_conv_table_bytes_in_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5149 { "table_bytes_out_rate", sample_conv_table_bytes_out_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5150 { "table_conn_cnt", sample_conv_table_conn_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5151 { "table_conn_cur", sample_conv_table_conn_cur, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5152 { "table_conn_rate", sample_conv_table_conn_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
Frédéric Lécaillebbeec372022-08-16 18:11:25 +02005153 { "table_expire", sample_conv_table_expire, ARG2(1,TAB,SINT), NULL, SMP_T_ANY, SMP_T_SINT },
Emeric Brun877b0b52021-06-30 18:57:49 +02005154 { "table_gpt", sample_conv_table_gpt, ARG2(2,SINT,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
Willy Tarreau2d17db52016-05-25 17:16:38 +02005155 { "table_gpt0", sample_conv_table_gpt0, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
Emeric Brun4d7ada82021-06-30 19:04:16 +02005156 { "table_gpc", sample_conv_table_gpc, ARG2(2,SINT,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
Willy Tarreau2d17db52016-05-25 17:16:38 +02005157 { "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 +01005158 { "table_gpc1", sample_conv_table_gpc1, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
Emeric Brun4d7ada82021-06-30 19:04:16 +02005159 { "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 +02005160 { "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 +01005161 { "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 +02005162 { "table_http_err_cnt", sample_conv_table_http_err_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5163 { "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 +01005164 { "table_http_fail_cnt", sample_conv_table_http_fail_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5165 { "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 +02005166 { "table_http_req_cnt", sample_conv_table_http_req_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5167 { "table_http_req_rate", sample_conv_table_http_req_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
Frédéric Lécaillebbeec372022-08-16 18:11:25 +02005168 { "table_idle", sample_conv_table_idle, ARG2(1,TAB,SINT), NULL, SMP_T_ANY, SMP_T_SINT },
Willy Tarreau2d17db52016-05-25 17:16:38 +02005169 { "table_kbytes_in", sample_conv_table_kbytes_in, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5170 { "table_kbytes_out", sample_conv_table_kbytes_out, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5171 { "table_server_id", sample_conv_table_server_id, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5172 { "table_sess_cnt", sample_conv_table_sess_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5173 { "table_sess_rate", sample_conv_table_sess_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5174 { "table_trackers", sample_conv_table_trackers, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
Willy Tarreaud9f316a2014-07-10 14:03:38 +02005175 { /* END */ },
5176}};
5177
Willy Tarreau0108d902018-11-25 19:14:37 +01005178INITCALL1(STG_REGISTER, sample_register_convs, &sample_conv_kws);