blob: 664de044ee2fff6e691c24b7f19fbd78bb95a439 [file] [log] [blame]
Emeric Brun3bd697e2010-01-04 15:23:48 +01001/*
2 * Stick tables management functions.
3 *
4 * Copyright 2009-2010 EXCELIANCE, Emeric Brun <ebrun@exceliance.fr>
Willy Tarreau08d5f982010-06-06 13:34:54 +02005 * Copyright (C) 2010 Willy Tarreau <w@1wt.eu>
Emeric Brun3bd697e2010-01-04 15:23:48 +01006 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version
10 * 2 of the License, or (at your option) any later version.
11 *
12 */
13
14#include <string.h>
Willy Tarreauf13ebdf2016-11-22 18:00:53 +010015#include <errno.h>
Emeric Brun3bd697e2010-01-04 15:23:48 +010016
Willy Tarreaub2551052020-06-09 09:07:15 +020017#include <import/ebmbtree.h>
18#include <import/ebsttree.h>
19#include <import/ebistree.h>
20
Willy Tarreau4c7e4b72020-05-27 12:58:42 +020021#include <haproxy/api.h>
Willy Tarreaub2551052020-06-09 09:07:15 +020022#include <haproxy/arg.h>
Willy Tarreau6be78492020-06-05 00:00:29 +020023#include <haproxy/cfgparse.h>
Willy Tarreau83487a82020-06-04 20:19:54 +020024#include <haproxy/cli.h>
Christopher Faulet908628c2022-03-25 16:43:49 +010025#include <haproxy/conn_stream.h>
26#include <haproxy/cs_utils.h>
Thayne McCombs92149f92020-11-20 01:28:26 -070027#include <haproxy/dict.h>
Willy Tarreau36979d92020-06-05 17:27:29 +020028#include <haproxy/errors.h>
Willy Tarreauf268ee82020-06-04 17:05:57 +020029#include <haproxy/global.h>
Willy Tarreauc761f842020-06-04 11:40:28 +020030#include <haproxy/http_rules.h>
Willy Tarreau853b2972020-05-27 18:01:47 +020031#include <haproxy/list.h>
Willy Tarreauaeed4a82020-06-04 22:01:04 +020032#include <haproxy/log.h>
Willy Tarreau6131d6a2020-06-02 16:48:09 +020033#include <haproxy/net_helper.h>
Willy Tarreau3c2a7c22020-06-04 18:38:21 +020034#include <haproxy/peers.h>
Willy Tarreaub2551052020-06-09 09:07:15 +020035#include <haproxy/pool.h>
36#include <haproxy/proto_tcp.h>
Willy Tarreaua264d962020-06-04 22:29:18 +020037#include <haproxy/proxy.h>
Willy Tarreaub2551052020-06-09 09:07:15 +020038#include <haproxy/sample.h>
Willy Tarreau2eec9b52020-06-04 19:58:55 +020039#include <haproxy/stats-t.h>
Willy Tarreaub2551052020-06-09 09:07:15 +020040#include <haproxy/stick_table.h>
Willy Tarreaudfd3de82020-06-04 23:46:14 +020041#include <haproxy/stream.h>
Willy Tarreau5e539c92020-06-04 20:45:39 +020042#include <haproxy/stream_interface.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
1396 * it up into this table. Returns the data rate sent to clients in bytes/s
1397 * if the key is present in the table, otherwise zero, so that comparisons can
1398 * be easily performed. If the inspected parameter is not stored in the table,
1399 * <not found> is returned.
1400 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001401static int sample_conv_table_bytes_out_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001402{
1403 struct stktable *t;
1404 struct stktable_key *key;
1405 struct stksess *ts;
1406 void *ptr;
1407
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001408 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001409
1410 key = smp_to_stkey(smp, t);
1411 if (!key)
1412 return 0;
1413
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001414 ts = stktable_lookup_key(t, key);
1415
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001416 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001417 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001418 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001419
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001420 if (!ts) /* key not present */
1421 return 1;
1422
1423 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_OUT_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001424 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001425 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Daniel Corbett3e60b112018-05-27 09:47:12 -04001426 t->data_arg[STKTABLE_DT_BYTES_OUT_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001427
Daniel Corbett3e60b112018-05-27 09:47:12 -04001428 stktable_release(t, ts);
1429 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001430}
1431
Emeric Brun877b0b52021-06-30 18:57:49 +02001432/* Casts sample <smp> to the type of the table specified in arg_p(1), and looks
1433 * it up into this table. Returns the value of the GPT[arg_p(0)] tag for the key
1434 * if the key is present in the table, otherwise false, so that comparisons can
1435 * be easily performed. If the inspected parameter is not stored in the table,
1436 * <not found> is returned.
1437 */
1438static int sample_conv_table_gpt(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 void *ptr;
1444 unsigned int idx;
1445
1446 idx = arg_p[0].data.sint;
1447
1448 t = arg_p[1].data.t;
1449
1450 key = smp_to_stkey(smp, t);
1451 if (!key)
1452 return 0;
1453
1454 ts = stktable_lookup_key(t, key);
1455
1456 smp->flags = SMP_F_VOL_TEST;
1457 smp->data.type = SMP_T_SINT;
1458 smp->data.u.sint = 0;
1459
1460 if (!ts) /* key not present */
1461 return 1;
1462
1463 ptr = stktable_data_ptr_idx(t, ts, STKTABLE_DT_GPT, idx);
1464 if (ptr)
1465 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
1466
1467 stktable_release(t, ts);
1468 return !!ptr;
1469}
1470
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001471/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001472 * it up into this table. Returns the value of the GPT0 tag for the key
1473 * if the key is present in the table, otherwise false, so that comparisons can
1474 * be easily performed. If the inspected parameter is not stored in the table,
1475 * <not found> is returned.
1476 */
1477static int sample_conv_table_gpt0(const struct arg *arg_p, struct sample *smp, void *private)
1478{
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;
Thierry FOURNIER236657b2015-08-19 08:25:14 +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
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001492 smp->flags = SMP_F_VOL_TEST;
1493 smp->data.type = SMP_T_SINT;
1494 smp->data.u.sint = 0;
1495
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001496 if (!ts) /* key not present */
1497 return 1;
1498
1499 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPT0);
Emeric Brunf7ab0bf2021-06-30 18:58:22 +02001500 if (!ptr)
1501 ptr = stktable_data_ptr_idx(t, ts, STKTABLE_DT_GPT, 0);
1502
Daniel Corbett3e60b112018-05-27 09:47:12 -04001503 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001504 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001505
Daniel Corbett3e60b112018-05-27 09:47:12 -04001506 stktable_release(t, ts);
1507 return !!ptr;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001508}
1509
Emeric Brun4d7ada82021-06-30 19:04:16 +02001510/* Casts sample <smp> to the type of the table specified in arg_p(1), and looks
1511 * it up into this table. Returns the value of the GPC[arg_p(0)] counter for the key
1512 * if the key is present in the table, otherwise zero, so that comparisons can
1513 * be easily performed. If the inspected parameter is not stored in the table,
1514 * <not found> is returned.
1515 */
1516static int sample_conv_table_gpc(const struct arg *arg_p, struct sample *smp, void *private)
1517{
1518 struct stktable *t;
1519 struct stktable_key *key;
1520 struct stksess *ts;
1521 void *ptr;
1522 unsigned int idx;
1523
1524 idx = arg_p[0].data.sint;
1525
1526 t = arg_p[1].data.t;
1527
1528 key = smp_to_stkey(smp, t);
1529 if (!key)
1530 return 0;
1531
1532 ts = stktable_lookup_key(t, key);
1533
1534 smp->flags = SMP_F_VOL_TEST;
1535 smp->data.type = SMP_T_SINT;
1536 smp->data.u.sint = 0;
1537
1538 if (!ts) /* key not present */
1539 return 1;
1540
1541 ptr = stktable_data_ptr_idx(t, ts, STKTABLE_DT_GPC, idx);
1542 if (ptr)
1543 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
1544
1545 stktable_release(t, ts);
1546 return !!ptr;
1547}
1548
1549/* Casts sample <smp> to the type of the table specified in arg_p(1), and looks
1550 * it up into this table. Returns the event rate of the GPC[arg_p(0)] counter
1551 * for the key if the key is present in the table, otherwise zero, so that
1552 * comparisons can be easily performed. If the inspected parameter is not
1553 * stored in the table, <not found> is returned.
1554 */
1555static int sample_conv_table_gpc_rate(const struct arg *arg_p, struct sample *smp, void *private)
1556{
1557 struct stktable *t;
1558 struct stktable_key *key;
1559 struct stksess *ts;
1560 void *ptr;
1561 unsigned int idx;
1562
1563 idx = arg_p[0].data.sint;
1564
1565 t = arg_p[1].data.t;
1566
1567 key = smp_to_stkey(smp, t);
1568 if (!key)
1569 return 0;
1570
1571 ts = stktable_lookup_key(t, key);
1572
1573 smp->flags = SMP_F_VOL_TEST;
1574 smp->data.type = SMP_T_SINT;
1575 smp->data.u.sint = 0;
1576
1577 if (!ts) /* key not present */
1578 return 1;
1579
1580 ptr = stktable_data_ptr_idx(t, ts, STKTABLE_DT_GPC_RATE, idx);
1581 if (ptr)
1582 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
1583 t->data_arg[STKTABLE_DT_GPC_RATE].u);
1584
1585 stktable_release(t, ts);
1586 return !!ptr;
1587}
1588
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001589/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001590 * it up into this table. Returns the value of the GPC0 counter for the key
1591 * if the key is present in the table, otherwise zero, so that comparisons can
1592 * be easily performed. If the inspected parameter is not stored in the table,
1593 * <not found> is returned.
1594 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001595static int sample_conv_table_gpc0(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001596{
1597 struct stktable *t;
1598 struct stktable_key *key;
1599 struct stksess *ts;
1600 void *ptr;
1601
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001602 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001603
1604 key = smp_to_stkey(smp, t);
1605 if (!key)
1606 return 0;
1607
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001608 ts = stktable_lookup_key(t, key);
1609
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001610 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001611 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001612 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001613
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001614 if (!ts) /* key not present */
1615 return 1;
1616
1617 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPC0);
Emeric Brun726783d2021-06-30 19:06:43 +02001618 if (!ptr) {
1619 /* fallback on the gpc array */
1620 ptr = stktable_data_ptr_idx(t, ts, STKTABLE_DT_GPC, 0);
1621 }
1622
Daniel Corbett3e60b112018-05-27 09:47:12 -04001623 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001624 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001625
Daniel Corbett3e60b112018-05-27 09:47:12 -04001626 stktable_release(t, ts);
1627 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001628}
1629
1630/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1631 * it up into this table. Returns the event rate of the GPC0 counter for the key
1632 * if the key is present in the table, otherwise zero, so that comparisons can
1633 * be easily performed. If the inspected parameter is not stored in the table,
1634 * <not found> is returned.
1635 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001636static int sample_conv_table_gpc0_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001637{
1638 struct stktable *t;
1639 struct stktable_key *key;
1640 struct stksess *ts;
1641 void *ptr;
1642
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001643 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001644
1645 key = smp_to_stkey(smp, t);
1646 if (!key)
1647 return 0;
1648
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001649 ts = stktable_lookup_key(t, key);
1650
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001651 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001652 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001653 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001654
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001655 if (!ts) /* key not present */
1656 return 1;
1657
1658 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPC0_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001659 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001660 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Daniel Corbett3e60b112018-05-27 09:47:12 -04001661 t->data_arg[STKTABLE_DT_GPC0_RATE].u);
Emeric Brun726783d2021-06-30 19:06:43 +02001662 else {
1663 /* fallback on the gpc array */
1664 ptr = stktable_data_ptr_idx(t, ts, STKTABLE_DT_GPC_RATE, 0);
1665 if (ptr)
1666 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
1667 t->data_arg[STKTABLE_DT_GPC_RATE].u);
1668 }
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001669
Daniel Corbett3e60b112018-05-27 09:47:12 -04001670 stktable_release(t, ts);
1671 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001672}
1673
1674/* 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 +01001675 * it up into this table. Returns the value of the GPC1 counter for the key
1676 * if the key is present in the table, otherwise zero, so that comparisons can
1677 * be easily performed. If the inspected parameter is not stored in the table,
1678 * <not found> is returned.
1679 */
1680static int sample_conv_table_gpc1(const struct arg *arg_p, struct sample *smp, void *private)
1681{
1682 struct stktable *t;
1683 struct stktable_key *key;
1684 struct stksess *ts;
1685 void *ptr;
1686
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001687 t = arg_p[0].data.t;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001688
1689 key = smp_to_stkey(smp, t);
1690 if (!key)
1691 return 0;
1692
1693 ts = stktable_lookup_key(t, key);
1694
1695 smp->flags = SMP_F_VOL_TEST;
1696 smp->data.type = SMP_T_SINT;
1697 smp->data.u.sint = 0;
1698
1699 if (!ts) /* key not present */
1700 return 1;
1701
1702 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPC1);
Emeric Brun726783d2021-06-30 19:06:43 +02001703 if (!ptr) {
1704 /* fallback on the gpc array */
1705 ptr = stktable_data_ptr_idx(t, ts, STKTABLE_DT_GPC, 1);
1706 }
1707
Daniel Corbett3e60b112018-05-27 09:47:12 -04001708 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001709 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001710
Daniel Corbett3e60b112018-05-27 09:47:12 -04001711 stktable_release(t, ts);
1712 return !!ptr;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001713}
1714
1715/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1716 * it up into this table. Returns the event rate of the GPC1 counter for the key
1717 * if the key is present in the table, otherwise zero, so that comparisons can
1718 * be easily performed. If the inspected parameter is not stored in the table,
1719 * <not found> is returned.
1720 */
1721static int sample_conv_table_gpc1_rate(const struct arg *arg_p, struct sample *smp, void *private)
1722{
1723 struct stktable *t;
1724 struct stktable_key *key;
1725 struct stksess *ts;
1726 void *ptr;
1727
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001728 t = arg_p[0].data.t;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001729
1730 key = smp_to_stkey(smp, t);
1731 if (!key)
1732 return 0;
1733
1734 ts = stktable_lookup_key(t, key);
1735
1736 smp->flags = SMP_F_VOL_TEST;
1737 smp->data.type = SMP_T_SINT;
1738 smp->data.u.sint = 0;
1739
1740 if (!ts) /* key not present */
1741 return 1;
1742
1743 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPC1_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001744 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001745 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Daniel Corbett3e60b112018-05-27 09:47:12 -04001746 t->data_arg[STKTABLE_DT_GPC1_RATE].u);
Emeric Brun726783d2021-06-30 19:06:43 +02001747 else {
1748 /* fallback on the gpc array */
1749 ptr = stktable_data_ptr_idx(t, ts, STKTABLE_DT_GPC_RATE, 1);
1750 if (ptr)
1751 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
1752 t->data_arg[STKTABLE_DT_GPC_RATE].u);
1753 }
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001754
Daniel Corbett3e60b112018-05-27 09:47:12 -04001755 stktable_release(t, ts);
1756 return !!ptr;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001757}
1758
1759/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001760 * it up into this table. Returns the cumulated number of HTTP request errors
1761 * for the key if the key is present in the table, otherwise zero, so that
1762 * comparisons can be easily performed. If the inspected parameter is not stored
1763 * in the table, <not found> is returned.
1764 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001765static int sample_conv_table_http_err_cnt(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001766{
1767 struct stktable *t;
1768 struct stktable_key *key;
1769 struct stksess *ts;
1770 void *ptr;
1771
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001772 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001773
1774 key = smp_to_stkey(smp, t);
1775 if (!key)
1776 return 0;
1777
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001778 ts = stktable_lookup_key(t, key);
1779
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001780 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001781 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001782 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001783
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001784 if (!ts) /* key not present */
1785 return 1;
1786
1787 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_ERR_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001788 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001789 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001790
Daniel Corbett3e60b112018-05-27 09:47:12 -04001791 stktable_release(t, ts);
1792 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001793}
1794
1795/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1796 * it up into this table. Returns the HTTP request error rate the key
1797 * if the key is present in the table, otherwise zero, so that comparisons can
1798 * be easily performed. If the inspected parameter is not stored in the table,
1799 * <not found> is returned.
1800 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001801static int sample_conv_table_http_err_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001802{
1803 struct stktable *t;
1804 struct stktable_key *key;
1805 struct stksess *ts;
1806 void *ptr;
1807
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001808 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001809
1810 key = smp_to_stkey(smp, t);
1811 if (!key)
1812 return 0;
1813
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001814 ts = stktable_lookup_key(t, key);
1815
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001816 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001817 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001818 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001819
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001820 if (!ts) /* key not present */
1821 return 1;
1822
1823 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_ERR_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001824 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001825 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Daniel Corbett3e60b112018-05-27 09:47:12 -04001826 t->data_arg[STKTABLE_DT_HTTP_ERR_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001827
Daniel Corbett3e60b112018-05-27 09:47:12 -04001828 stktable_release(t, ts);
1829 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001830}
1831
1832/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Willy Tarreau826f3ab2021-02-10 12:07:15 +01001833 * it up into this table. Returns the cumulated number of HTTP response failures
1834 * for the key if the key is present in the table, otherwise zero, so that
1835 * comparisons can be easily performed. If the inspected parameter is not stored
1836 * in the table, <not found> is returned.
1837 */
1838static int sample_conv_table_http_fail_cnt(const struct arg *arg_p, struct sample *smp, void *private)
1839{
1840 struct stktable *t;
1841 struct stktable_key *key;
1842 struct stksess *ts;
1843 void *ptr;
1844
1845 t = arg_p[0].data.t;
1846
1847 key = smp_to_stkey(smp, t);
1848 if (!key)
1849 return 0;
1850
1851 ts = stktable_lookup_key(t, key);
1852
1853 smp->flags = SMP_F_VOL_TEST;
1854 smp->data.type = SMP_T_SINT;
1855 smp->data.u.sint = 0;
1856
1857 if (!ts) /* key not present */
1858 return 1;
1859
1860 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_FAIL_CNT);
1861 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001862 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Willy Tarreau826f3ab2021-02-10 12:07:15 +01001863
1864 stktable_release(t, ts);
1865 return !!ptr;
1866}
1867
1868/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1869 * it up into this table. Returns the HTTP response failure rate for the key
1870 * if the key is present in the table, otherwise zero, so that comparisons can
1871 * be easily performed. If the inspected parameter is not stored in the table,
1872 * <not found> is returned.
1873 */
1874static int sample_conv_table_http_fail_rate(const struct arg *arg_p, struct sample *smp, void *private)
1875{
1876 struct stktable *t;
1877 struct stktable_key *key;
1878 struct stksess *ts;
1879 void *ptr;
1880
1881 t = arg_p[0].data.t;
1882
1883 key = smp_to_stkey(smp, t);
1884 if (!key)
1885 return 0;
1886
1887 ts = stktable_lookup_key(t, key);
1888
1889 smp->flags = SMP_F_VOL_TEST;
1890 smp->data.type = SMP_T_SINT;
1891 smp->data.u.sint = 0;
1892
1893 if (!ts) /* key not present */
1894 return 1;
1895
1896 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_FAIL_RATE);
1897 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001898 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Willy Tarreau826f3ab2021-02-10 12:07:15 +01001899 t->data_arg[STKTABLE_DT_HTTP_FAIL_RATE].u);
1900
1901 stktable_release(t, ts);
1902 return !!ptr;
1903}
1904
1905/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001906 * it up into this table. Returns the cumulated number of HTTP request for the
1907 * key if the key is present in the table, otherwise zero, so that comparisons
1908 * can be easily performed. If the inspected parameter is not stored in the
1909 * table, <not found> is returned.
1910 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001911static int sample_conv_table_http_req_cnt(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001912{
1913 struct stktable *t;
1914 struct stktable_key *key;
1915 struct stksess *ts;
1916 void *ptr;
1917
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001918 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001919
1920 key = smp_to_stkey(smp, t);
1921 if (!key)
1922 return 0;
1923
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001924 ts = stktable_lookup_key(t, key);
1925
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001926 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001927 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001928 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001929
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001930 if (!ts) /* key not present */
1931 return 1;
1932
1933 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_REQ_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001934 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001935 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001936
Daniel Corbett3e60b112018-05-27 09:47:12 -04001937 stktable_release(t, ts);
1938 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001939}
1940
1941/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1942 * it up into this table. Returns the HTTP request rate the key if the key is
1943 * present in the table, otherwise zero, so that comparisons can be easily
1944 * performed. If the inspected parameter is not stored in the table, <not found>
1945 * is returned.
1946 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001947static int sample_conv_table_http_req_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001948{
1949 struct stktable *t;
1950 struct stktable_key *key;
1951 struct stksess *ts;
1952 void *ptr;
1953
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001954 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001955
1956 key = smp_to_stkey(smp, t);
1957 if (!key)
1958 return 0;
1959
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001960 ts = stktable_lookup_key(t, key);
1961
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001962 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001963 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001964 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001965
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001966 if (!ts) /* key not present */
1967 return 1;
1968
1969 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_REQ_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001970 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001971 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Daniel Corbett3e60b112018-05-27 09:47:12 -04001972 t->data_arg[STKTABLE_DT_HTTP_REQ_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001973
Daniel Corbett3e60b112018-05-27 09:47:12 -04001974 stktable_release(t, ts);
1975 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001976}
1977
1978/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1979 * it up into this table. Returns the volume of datareceived from clients in kbytes
1980 * if the key is present in the table, otherwise zero, so that comparisons can
1981 * be easily performed. If the inspected parameter is not stored in the table,
1982 * <not found> is returned.
1983 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001984static int sample_conv_table_kbytes_in(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001985{
1986 struct stktable *t;
1987 struct stktable_key *key;
1988 struct stksess *ts;
1989 void *ptr;
1990
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001991 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001992
1993 key = smp_to_stkey(smp, t);
1994 if (!key)
1995 return 0;
1996
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001997 ts = stktable_lookup_key(t, key);
1998
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001999 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02002000 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02002001 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002002
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002003 if (!ts) /* key not present */
2004 return 1;
2005
2006 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_IN_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04002007 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002008 smp->data.u.sint = stktable_data_cast(ptr, std_t_ull) >> 10;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002009
Daniel Corbett3e60b112018-05-27 09:47:12 -04002010 stktable_release(t, ts);
2011 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002012}
2013
2014/* Casts sample <smp> to the type of the table specified in arg(0), and looks
2015 * it up into this table. Returns the volume of data sent to clients in kbytes
2016 * if the key is present in the table, otherwise zero, so that comparisons can
2017 * be easily performed. If the inspected parameter is not stored in the table,
2018 * <not found> is returned.
2019 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02002020static int sample_conv_table_kbytes_out(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002021{
2022 struct stktable *t;
2023 struct stktable_key *key;
2024 struct stksess *ts;
2025 void *ptr;
2026
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002027 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002028
2029 key = smp_to_stkey(smp, t);
2030 if (!key)
2031 return 0;
2032
Willy Tarreauf0c730a2016-05-25 17:07:56 +02002033 ts = stktable_lookup_key(t, key);
2034
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002035 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02002036 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02002037 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002038
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002039 if (!ts) /* key not present */
2040 return 1;
2041
2042 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_OUT_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04002043 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002044 smp->data.u.sint = stktable_data_cast(ptr, std_t_ull) >> 10;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002045
Daniel Corbett3e60b112018-05-27 09:47:12 -04002046 stktable_release(t, ts);
2047 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002048}
2049
2050/* Casts sample <smp> to the type of the table specified in arg(0), and looks
2051 * it up into this table. Returns the server ID associated with the key if the
2052 * key is present in the table, otherwise zero, so that comparisons can be
2053 * easily performed. If the inspected parameter is not stored in the table,
2054 * <not found> is returned.
2055 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02002056static int sample_conv_table_server_id(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002057{
2058 struct stktable *t;
2059 struct stktable_key *key;
2060 struct stksess *ts;
2061 void *ptr;
2062
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002063 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002064
2065 key = smp_to_stkey(smp, t);
2066 if (!key)
2067 return 0;
2068
Willy Tarreauf0c730a2016-05-25 17:07:56 +02002069 ts = stktable_lookup_key(t, key);
2070
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002071 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02002072 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02002073 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002074
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002075 if (!ts) /* key not present */
2076 return 1;
2077
2078 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_SERVER_ID);
Daniel Corbett3e60b112018-05-27 09:47:12 -04002079 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002080 smp->data.u.sint = stktable_data_cast(ptr, std_t_sint);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002081
Daniel Corbett3e60b112018-05-27 09:47:12 -04002082 stktable_release(t, ts);
2083 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002084}
2085
2086/* Casts sample <smp> to the type of the table specified in arg(0), and looks
2087 * it up into this table. Returns the cumulated number of sessions for the
2088 * key if the key is present in the table, otherwise zero, so that comparisons
2089 * can be easily performed. If the inspected parameter is not stored in the
2090 * table, <not found> is returned.
2091 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02002092static int sample_conv_table_sess_cnt(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002093{
2094 struct stktable *t;
2095 struct stktable_key *key;
2096 struct stksess *ts;
2097 void *ptr;
2098
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002099 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002100
2101 key = smp_to_stkey(smp, t);
2102 if (!key)
2103 return 0;
2104
Willy Tarreauf0c730a2016-05-25 17:07:56 +02002105 ts = stktable_lookup_key(t, key);
2106
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002107 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02002108 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02002109 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002110
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002111 if (!ts) /* key not present */
2112 return 1;
2113
2114 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_SESS_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04002115 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002116 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002117
Daniel Corbett3e60b112018-05-27 09:47:12 -04002118 stktable_release(t, ts);
2119 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002120}
2121
2122/* Casts sample <smp> to the type of the table specified in arg(0), and looks
2123 * it up into this table. Returns the session rate the key if the key is
2124 * present in the table, otherwise zero, so that comparisons can be easily
2125 * performed. If the inspected parameter is not stored in the table, <not found>
2126 * is returned.
2127 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02002128static int sample_conv_table_sess_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002129{
2130 struct stktable *t;
2131 struct stktable_key *key;
2132 struct stksess *ts;
2133 void *ptr;
2134
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002135 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002136
2137 key = smp_to_stkey(smp, t);
2138 if (!key)
2139 return 0;
2140
Willy Tarreauf0c730a2016-05-25 17:07:56 +02002141 ts = stktable_lookup_key(t, key);
2142
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002143 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02002144 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02002145 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002146
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002147 if (!ts) /* key not present */
2148 return 1;
2149
2150 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_SESS_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04002151 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002152 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Daniel Corbett3e60b112018-05-27 09:47:12 -04002153 t->data_arg[STKTABLE_DT_SESS_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002154
Daniel Corbett3e60b112018-05-27 09:47:12 -04002155 stktable_release(t, ts);
2156 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002157}
2158
2159/* Casts sample <smp> to the type of the table specified in arg(0), and looks
2160 * it up into this table. Returns the amount of concurrent connections tracking
2161 * the same key if the key is present in the table, otherwise zero, so that
2162 * comparisons can be easily performed. If the inspected parameter is not
2163 * stored in the table, <not found> is returned.
2164 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02002165static int sample_conv_table_trackers(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002166{
2167 struct stktable *t;
2168 struct stktable_key *key;
2169 struct stksess *ts;
2170
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002171 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002172
2173 key = smp_to_stkey(smp, t);
2174 if (!key)
2175 return 0;
2176
Willy Tarreauf0c730a2016-05-25 17:07:56 +02002177 ts = stktable_lookup_key(t, key);
2178
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002179 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02002180 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02002181 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002182
Tim Duesterhus65189c12018-06-26 15:57:29 +02002183 if (!ts)
2184 return 1;
2185
2186 smp->data.u.sint = ts->ref_cnt;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002187
Daniel Corbett3e60b112018-05-27 09:47:12 -04002188 stktable_release(t, ts);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002189 return 1;
2190}
2191
Emeric Brun4d7ada82021-06-30 19:04:16 +02002192/* This function increments the gpc counter at index 'rule->arg.gpc.idx' of the
2193 * array on the tracksc counter of index 'rule->arg.gpc.sc' stored into the
2194 * <stream> or directly in the session <sess> if <stream> is set to NULL
2195 *
2196 * This function always returns ACT_RET_CONT and parameter flags is unused.
2197 */
2198static enum act_return action_inc_gpc(struct act_rule *rule, struct proxy *px,
2199 struct session *sess, struct stream *s, int flags)
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002200{
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002201 struct stksess *ts;
2202 struct stkctr *stkctr;
2203
2204 /* Extract the stksess, return OK if no stksess available. */
2205 if (s)
2206 stkctr = &s->stkctr[rule->arg.gpc.sc];
2207 else
2208 stkctr = &sess->stkctr[rule->arg.gpc.sc];
Willy Tarreau79c1e912016-01-25 14:54:45 +01002209
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002210 ts = stkctr_entry(stkctr);
Willy Tarreau79c1e912016-01-25 14:54:45 +01002211 if (ts) {
2212 void *ptr1, *ptr2;
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002213
Emeric Brun4d7ada82021-06-30 19:04:16 +02002214 /* First, update gpc_rate if it's tracked. Second, update its gpc if tracked. */
2215 ptr1 = stktable_data_ptr_idx(stkctr->table, ts, STKTABLE_DT_GPC_RATE, rule->arg.gpc.idx);
2216 ptr2 = stktable_data_ptr_idx(stkctr->table, ts, STKTABLE_DT_GPC, rule->arg.gpc.idx);
2217
Emeric Brun819fc6f2017-06-13 19:37:32 +02002218 if (ptr1 || ptr2) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002219 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002220
2221 if (ptr1)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002222 update_freq_ctr_period(&stktable_data_cast(ptr1, std_t_frqp),
Emeric Brun4d7ada82021-06-30 19:04:16 +02002223 stkctr->table->data_arg[STKTABLE_DT_GPC_RATE].u, 1);
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002224
Emeric Brun819fc6f2017-06-13 19:37:32 +02002225 if (ptr2)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002226 stktable_data_cast(ptr2, std_t_uint)++;
Willy Tarreau79c1e912016-01-25 14:54:45 +01002227
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002228 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002229
2230 /* If data was modified, we need to touch to re-schedule sync */
2231 stktable_touch_local(stkctr->table, ts, 0);
2232 }
Willy Tarreau79c1e912016-01-25 14:54:45 +01002233 }
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002234 return ACT_RET_CONT;
2235}
2236
Emeric Brun4d7ada82021-06-30 19:04:16 +02002237/* Same as action_inc_gpc() but for gpc0 only */
2238static enum act_return action_inc_gpc0(struct act_rule *rule, struct proxy *px,
2239 struct session *sess, struct stream *s, int flags)
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002240{
Emeric Brun4d7ada82021-06-30 19:04:16 +02002241 struct stksess *ts;
2242 struct stkctr *stkctr;
Willy Tarreau5b654ad2021-07-06 18:51:12 +02002243 unsigned int period = 0;
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002244
Emeric Brun4d7ada82021-06-30 19:04:16 +02002245 /* Extract the stksess, return OK if no stksess available. */
2246 if (s)
2247 stkctr = &s->stkctr[rule->arg.gpc.sc];
2248 else
2249 stkctr = &sess->stkctr[rule->arg.gpc.sc];
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002250
Emeric Brun4d7ada82021-06-30 19:04:16 +02002251 ts = stkctr_entry(stkctr);
2252 if (ts) {
2253 void *ptr1, *ptr2;
2254
2255 /* First, update gpc0_rate if it's tracked. Second, update its gpc0 if tracked. */
2256 ptr1 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC0_RATE);
Emeric Brun726783d2021-06-30 19:06:43 +02002257 if (ptr1) {
2258 period = stkctr->table->data_arg[STKTABLE_DT_GPC0_RATE].u;
2259 }
2260 else {
2261 /* fallback on the gpc array */
2262 ptr1 = stktable_data_ptr_idx(stkctr->table, ts, STKTABLE_DT_GPC_RATE, 0);
2263 if (ptr1)
2264 period = stkctr->table->data_arg[STKTABLE_DT_GPC_RATE].u;
2265 }
2266
Emeric Brun4d7ada82021-06-30 19:04:16 +02002267 ptr2 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC0);
Emeric Brun726783d2021-06-30 19:06:43 +02002268 if (!ptr2) {
2269 /* fallback on the gpc array */
2270 ptr2 = stktable_data_ptr_idx(stkctr->table, ts, STKTABLE_DT_GPC, 0);
2271 }
2272
Emeric Brun4d7ada82021-06-30 19:04:16 +02002273 if (ptr1 || ptr2) {
2274 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
2275
2276 if (ptr1)
2277 update_freq_ctr_period(&stktable_data_cast(ptr1, std_t_frqp),
Emeric Brun726783d2021-06-30 19:06:43 +02002278 period, 1);
Emeric Brun4d7ada82021-06-30 19:04:16 +02002279
2280 if (ptr2)
2281 stktable_data_cast(ptr2, std_t_uint)++;
2282
2283 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
2284
2285 /* If data was modified, we need to touch to re-schedule sync */
2286 stktable_touch_local(stkctr->table, ts, 0);
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002287 }
2288 }
Emeric Brun4d7ada82021-06-30 19:04:16 +02002289 return ACT_RET_CONT;
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002290}
2291
Emeric Brun4d7ada82021-06-30 19:04:16 +02002292/* Same as action_inc_gpc() but for gpc1 only */
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002293static enum act_return action_inc_gpc1(struct act_rule *rule, struct proxy *px,
2294 struct session *sess, struct stream *s, int flags)
2295{
2296 struct stksess *ts;
2297 struct stkctr *stkctr;
Willy Tarreau5b654ad2021-07-06 18:51:12 +02002298 unsigned int period = 0;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002299
2300 /* Extract the stksess, return OK if no stksess available. */
2301 if (s)
2302 stkctr = &s->stkctr[rule->arg.gpc.sc];
2303 else
2304 stkctr = &sess->stkctr[rule->arg.gpc.sc];
2305
2306 ts = stkctr_entry(stkctr);
2307 if (ts) {
2308 void *ptr1, *ptr2;
2309
2310 /* First, update gpc1_rate if it's tracked. Second, update its gpc1 if tracked. */
2311 ptr1 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC1_RATE);
Emeric Brun726783d2021-06-30 19:06:43 +02002312 if (ptr1) {
2313 period = stkctr->table->data_arg[STKTABLE_DT_GPC1_RATE].u;
2314 }
2315 else {
2316 /* fallback on the gpc array */
2317 ptr1 = stktable_data_ptr_idx(stkctr->table, ts, STKTABLE_DT_GPC_RATE, 1);
2318 if (ptr1)
2319 period = stkctr->table->data_arg[STKTABLE_DT_GPC_RATE].u;
2320 }
2321
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002322 ptr2 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC1);
Emeric Brun726783d2021-06-30 19:06:43 +02002323 if (!ptr2) {
2324 /* fallback on the gpc array */
2325 ptr2 = stktable_data_ptr_idx(stkctr->table, ts, STKTABLE_DT_GPC, 1);
2326 }
2327
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002328 if (ptr1 || ptr2) {
2329 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
2330
2331 if (ptr1)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002332 update_freq_ctr_period(&stktable_data_cast(ptr1, std_t_frqp),
Emeric Brun726783d2021-06-30 19:06:43 +02002333 period, 1);
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002334
2335 if (ptr2)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002336 stktable_data_cast(ptr2, std_t_uint)++;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002337
2338 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
2339
2340 /* If data was modified, we need to touch to re-schedule sync */
2341 stktable_touch_local(stkctr->table, ts, 0);
2342 }
2343 }
2344 return ACT_RET_CONT;
2345}
2346
Emeric Brun4d7ada82021-06-30 19:04:16 +02002347/* This function is a common parser for actions incrementing the GPC
2348 * (General Purpose Counters). It understands the formats:
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002349 *
Emeric Brun4d7ada82021-06-30 19:04:16 +02002350 * sc-inc-gpc(<gpc IDX>,<track ID>)
2351 * sc-inc-gpc0([<track ID>])
2352 * sc-inc-gpc1([<track ID>])
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002353 *
Emeric Brun4d7ada82021-06-30 19:04:16 +02002354 * It returns ACT_RET_PRS_ERR if fails and <err> is filled with an error
2355 * message. Otherwise it returns ACT_RET_PRS_OK.
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002356 */
Emeric Brun4d7ada82021-06-30 19:04:16 +02002357static enum act_parse_ret parse_inc_gpc(const char **args, int *arg, struct proxy *px,
2358 struct act_rule *rule, char **err)
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002359{
2360 const char *cmd_name = args[*arg-1];
2361 char *error;
2362
Emeric Brun4d7ada82021-06-30 19:04:16 +02002363 cmd_name += strlen("sc-inc-gpc");
2364 if (*cmd_name == '(') {
2365 cmd_name++; /* skip the '(' */
2366 rule->arg.gpc.idx = strtoul(cmd_name, &error, 10); /* Convert stick table id. */
2367 if (*error != ',') {
2368 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 +01002369 return ACT_RET_PRS_ERR;
2370 }
Emeric Brun4d7ada82021-06-30 19:04:16 +02002371 else {
2372 cmd_name = error + 1; /* skip the ',' */
2373 rule->arg.gpc.sc = strtol(cmd_name, &error, 10); /* Convert stick table id. */
2374 if (*error != ')') {
2375 memprintf(err, "invalid stick table track ID '%s'. Expects sc-inc-gpc(<GPC ID>,<Track ID>)", args[*arg-1]);
2376 return ACT_RET_PRS_ERR;
2377 }
2378
2379 if (rule->arg.gpc.sc >= MAX_SESS_STKCTR) {
2380 memprintf(err, "invalid stick table track ID '%s'. The max allowed ID is %d",
2381 args[*arg-1], MAX_SESS_STKCTR-1);
2382 return ACT_RET_PRS_ERR;
2383 }
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002384 }
Emeric Brun4d7ada82021-06-30 19:04:16 +02002385 rule->action_ptr = action_inc_gpc;
2386 }
2387 else if (*cmd_name == '0' ||*cmd_name == '1') {
2388 char c = *cmd_name;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002389
Emeric Brun4d7ada82021-06-30 19:04:16 +02002390 cmd_name++;
2391 if (*cmd_name == '\0') {
2392 /* default stick table id. */
2393 rule->arg.gpc.sc = 0;
2394 } else {
2395 /* parse the stick table id. */
2396 if (*cmd_name != '(') {
2397 memprintf(err, "invalid stick table track ID. Expects %s(<Track ID>)", args[*arg-1]);
2398 return ACT_RET_PRS_ERR;
2399 }
2400 cmd_name++; /* jump the '(' */
2401 rule->arg.gpc.sc = strtol(cmd_name, &error, 10); /* Convert stick table id. */
2402 if (*error != ')') {
2403 memprintf(err, "invalid stick table track ID. Expects %s(<Track ID>)", args[*arg-1]);
2404 return ACT_RET_PRS_ERR;
2405 }
2406
2407 if (rule->arg.gpc.sc >= MAX_SESS_STKCTR) {
2408 memprintf(err, "invalid stick table track ID. The max allowed ID is %d",
2409 MAX_SESS_STKCTR-1);
2410 return ACT_RET_PRS_ERR;
2411 }
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002412 }
Emeric Brun4d7ada82021-06-30 19:04:16 +02002413 if (c == '1')
2414 rule->action_ptr = action_inc_gpc1;
2415 else
2416 rule->action_ptr = action_inc_gpc0;
2417 }
2418 else {
2419 /* default stick table id. */
2420 memprintf(err, "invalid gpc ID '%s'. Expects sc-set-gpc(<GPC ID>,<Track ID>)", args[*arg-1]);
2421 return ACT_RET_PRS_ERR;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002422 }
2423 rule->action = ACT_CUSTOM;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002424 return ACT_RET_PRS_OK;
2425}
2426
Emeric Brun877b0b52021-06-30 18:57:49 +02002427/* This function sets the gpt at index 'rule->arg.gpt.idx' of the array on the
2428 * tracksc counter of index 'rule->arg.gpt.sc' stored into the <stream> or
2429 * directly in the session <sess> if <stream> is set to NULL. This gpt is
2430 * set to the value computed by the expression 'rule->arg.gpt.expr' or if
2431 * 'rule->arg.gpt.expr' is null directly to the value of 'rule->arg.gpt.value'.
2432 *
2433 * This function always returns ACT_RET_CONT and parameter flags is unused.
2434 */
2435static enum act_return action_set_gpt(struct act_rule *rule, struct proxy *px,
2436 struct session *sess, struct stream *s, int flags)
2437{
2438 void *ptr;
2439 struct stksess *ts;
2440 struct stkctr *stkctr;
2441 unsigned int value = 0;
2442 struct sample *smp;
2443 int smp_opt_dir;
2444
2445 /* Extract the stksess, return OK if no stksess available. */
2446 if (s)
2447 stkctr = &s->stkctr[rule->arg.gpt.sc];
2448 else
2449 stkctr = &sess->stkctr[rule->arg.gpt.sc];
2450
2451 ts = stkctr_entry(stkctr);
2452 if (!ts)
2453 return ACT_RET_CONT;
2454
2455 /* Store the sample in the required sc, and ignore errors. */
2456 ptr = stktable_data_ptr_idx(stkctr->table, ts, STKTABLE_DT_GPT, rule->arg.gpt.idx);
2457 if (ptr) {
2458
2459 if (!rule->arg.gpt.expr)
2460 value = (unsigned int)(rule->arg.gpt.value);
2461 else {
2462 switch (rule->from) {
2463 case ACT_F_TCP_REQ_SES: smp_opt_dir = SMP_OPT_DIR_REQ; break;
2464 case ACT_F_TCP_REQ_CNT: smp_opt_dir = SMP_OPT_DIR_REQ; break;
2465 case ACT_F_TCP_RES_CNT: smp_opt_dir = SMP_OPT_DIR_RES; break;
2466 case ACT_F_HTTP_REQ: smp_opt_dir = SMP_OPT_DIR_REQ; break;
2467 case ACT_F_HTTP_RES: smp_opt_dir = SMP_OPT_DIR_RES; break;
2468 default:
2469 send_log(px, LOG_ERR, "stick table: internal error while setting gpt%u.", rule->arg.gpt.idx);
2470 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))
2471 ha_alert("stick table: internal error while executing setting gpt%u.\n", rule->arg.gpt.idx);
2472 return ACT_RET_CONT;
2473 }
2474
2475 /* Fetch and cast the expression. */
2476 smp = sample_fetch_as_type(px, sess, s, smp_opt_dir|SMP_OPT_FINAL, rule->arg.gpt.expr, SMP_T_SINT);
2477 if (!smp) {
2478 send_log(px, LOG_WARNING, "stick table: invalid expression or data type while setting gpt%u.", rule->arg.gpt.idx);
2479 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))
2480 ha_alert("stick table: invalid expression or data type while setting gpt%u.\n", rule->arg.gpt.idx);
2481 return ACT_RET_CONT;
2482 }
2483 value = (unsigned int)(smp->data.u.sint);
2484 }
2485
2486 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
2487
2488 stktable_data_cast(ptr, std_t_uint) = value;
2489
2490 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
2491
2492 stktable_touch_local(stkctr->table, ts, 0);
2493 }
2494
2495 return ACT_RET_CONT;
2496}
2497
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002498/* Always returns 1. */
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002499static enum act_return action_set_gpt0(struct act_rule *rule, struct proxy *px,
Willy Tarreau658b85b2015-09-27 10:00:49 +02002500 struct session *sess, struct stream *s, int flags)
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002501{
2502 void *ptr;
2503 struct stksess *ts;
2504 struct stkctr *stkctr;
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002505 unsigned int value = 0;
2506 struct sample *smp;
2507 int smp_opt_dir;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002508
2509 /* Extract the stksess, return OK if no stksess available. */
2510 if (s)
2511 stkctr = &s->stkctr[rule->arg.gpt.sc];
2512 else
2513 stkctr = &sess->stkctr[rule->arg.gpt.sc];
Willy Tarreau79c1e912016-01-25 14:54:45 +01002514
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002515 ts = stkctr_entry(stkctr);
2516 if (!ts)
2517 return ACT_RET_CONT;
2518
2519 /* Store the sample in the required sc, and ignore errors. */
2520 ptr = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPT0);
Emeric Brunf7ab0bf2021-06-30 18:58:22 +02002521 if (!ptr)
2522 ptr = stktable_data_ptr_idx(stkctr->table, ts, STKTABLE_DT_GPT, 0);
2523
Willy Tarreau79c1e912016-01-25 14:54:45 +01002524 if (ptr) {
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002525 if (!rule->arg.gpt.expr)
2526 value = (unsigned int)(rule->arg.gpt.value);
2527 else {
2528 switch (rule->from) {
2529 case ACT_F_TCP_REQ_SES: smp_opt_dir = SMP_OPT_DIR_REQ; break;
2530 case ACT_F_TCP_REQ_CNT: smp_opt_dir = SMP_OPT_DIR_REQ; break;
2531 case ACT_F_TCP_RES_CNT: smp_opt_dir = SMP_OPT_DIR_RES; break;
2532 case ACT_F_HTTP_REQ: smp_opt_dir = SMP_OPT_DIR_REQ; break;
2533 case ACT_F_HTTP_RES: smp_opt_dir = SMP_OPT_DIR_RES; break;
2534 default:
2535 send_log(px, LOG_ERR, "stick table: internal error while setting gpt0.");
2536 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))
2537 ha_alert("stick table: internal error while executing setting gpt0.\n");
2538 return ACT_RET_CONT;
2539 }
2540
2541 /* Fetch and cast the expression. */
2542 smp = sample_fetch_as_type(px, sess, s, smp_opt_dir|SMP_OPT_FINAL, rule->arg.gpt.expr, SMP_T_SINT);
2543 if (!smp) {
2544 send_log(px, LOG_WARNING, "stick table: invalid expression or data type while setting gpt0.");
2545 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))
2546 ha_alert("stick table: invalid expression or data type while setting gpt0.\n");
2547 return ACT_RET_CONT;
2548 }
2549 value = (unsigned int)(smp->data.u.sint);
2550 }
2551
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002552 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002553
Emeric Brun0e3457b2021-06-30 17:18:28 +02002554 stktable_data_cast(ptr, std_t_uint) = value;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002555
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002556 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002557
2558 stktable_touch_local(stkctr->table, ts, 0);
Willy Tarreau79c1e912016-01-25 14:54:45 +01002559 }
2560
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002561 return ACT_RET_CONT;
2562}
2563
Emeric Brun877b0b52021-06-30 18:57:49 +02002564/* This function is a parser for the "sc-set-gpt" and "sc-set-gpt0" actions.
2565 * It understands the formats:
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002566 *
Emeric Brun877b0b52021-06-30 18:57:49 +02002567 * sc-set-gpt(<gpt IDX>,<track ID>) <expression>
2568 * sc-set-gpt0(<track ID>) <expression>
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002569 *
Emeric Brun877b0b52021-06-30 18:57:49 +02002570 * It returns ACT_RET_PRS_ERR if fails and <err> is filled with an error message.
2571 * Otherwise, it returns ACT_RET_PRS_OK and the variable 'rule->arg.gpt.expr'
2572 * is filled with the pointer to the expression to execute or NULL if the arg
2573 * is directly an integer stored into 'rule->arg.gpt.value'.
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002574 */
Emeric Brun877b0b52021-06-30 18:57:49 +02002575static enum act_parse_ret parse_set_gpt(const char **args, int *arg, struct proxy *px,
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002576 struct act_rule *rule, char **err)
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002577{
2578 const char *cmd_name = args[*arg-1];
2579 char *error;
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002580 int smp_val;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002581
Emeric Brun877b0b52021-06-30 18:57:49 +02002582 cmd_name += strlen("sc-set-gpt");
2583 if (*cmd_name == '(') {
2584 cmd_name++; /* skip the '(' */
2585 rule->arg.gpt.idx = strtoul(cmd_name, &error, 10); /* Convert stick table id. */
2586 if (*error != ',') {
2587 memprintf(err, "Missing gpt ID '%s'. Expects sc-set-gpt(<GPT ID>,<Track ID>)", args[*arg-1]);
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002588 return ACT_RET_PRS_ERR;
2589 }
Emeric Brun877b0b52021-06-30 18:57:49 +02002590 else {
2591 cmd_name = error + 1; /* skip the ',' */
2592 rule->arg.gpt.sc = strtol(cmd_name, &error, 10); /* Convert stick table id. */
2593 if (*error != ')') {
2594 memprintf(err, "invalid stick table track ID '%s'. Expects sc-set-gpt(<GPT ID>,<Track ID>)", args[*arg-1]);
2595 return ACT_RET_PRS_ERR;
2596 }
2597
2598 if (rule->arg.gpt.sc >= MAX_SESS_STKCTR) {
2599 memprintf(err, "invalid stick table track ID '%s'. The max allowed ID is %d",
2600 args[*arg-1], MAX_SESS_STKCTR-1);
2601 return ACT_RET_PRS_ERR;
2602 }
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002603 }
Emeric Brun877b0b52021-06-30 18:57:49 +02002604 rule->action_ptr = action_set_gpt;
2605 }
2606 else if (*cmd_name == '0') {
2607 cmd_name++;
2608 if (*cmd_name == '\0') {
2609 /* default stick table id. */
2610 rule->arg.gpt.sc = 0;
2611 } else {
2612 /* parse the stick table id. */
2613 if (*cmd_name != '(') {
2614 memprintf(err, "invalid stick table track ID '%s'. Expects sc-set-gpt0(<Track ID>)", args[*arg-1]);
2615 return ACT_RET_PRS_ERR;
2616 }
2617 cmd_name++; /* jump the '(' */
2618 rule->arg.gpt.sc = strtol(cmd_name, &error, 10); /* Convert stick table id. */
2619 if (*error != ')') {
2620 memprintf(err, "invalid stick table track ID '%s'. Expects sc-set-gpt0(<Track ID>)", args[*arg-1]);
2621 return ACT_RET_PRS_ERR;
2622 }
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002623
Emeric Brun877b0b52021-06-30 18:57:49 +02002624 if (rule->arg.gpt.sc >= MAX_SESS_STKCTR) {
2625 memprintf(err, "invalid stick table track ID '%s'. The max allowed ID is %d",
2626 args[*arg-1], MAX_SESS_STKCTR-1);
2627 return ACT_RET_PRS_ERR;
2628 }
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002629 }
Emeric Brun877b0b52021-06-30 18:57:49 +02002630 rule->action_ptr = action_set_gpt0;
2631 }
2632 else {
2633 /* default stick table id. */
2634 memprintf(err, "invalid gpt ID '%s'. Expects sc-set-gpt(<GPT ID>,<Track ID>)", args[*arg-1]);
2635 return ACT_RET_PRS_ERR;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002636 }
2637
Willy Tarreauece4c4a2021-08-24 14:57:28 +02002638 /* value may be either an integer or an expression */
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002639 rule->arg.gpt.expr = NULL;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002640 rule->arg.gpt.value = strtol(args[*arg], &error, 10);
Willy Tarreauece4c4a2021-08-24 14:57:28 +02002641 if (*error == '\0') {
2642 /* valid integer, skip it */
2643 (*arg)++;
2644 } else {
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002645 rule->arg.gpt.expr = sample_parse_expr((char **)args, arg, px->conf.args.file,
Willy Tarreaue3b57bf2020-02-14 16:50:14 +01002646 px->conf.args.line, err, &px->conf.args, NULL);
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002647 if (!rule->arg.gpt.expr)
2648 return ACT_RET_PRS_ERR;
2649
2650 switch (rule->from) {
2651 case ACT_F_TCP_REQ_SES: smp_val = SMP_VAL_FE_SES_ACC; break;
2652 case ACT_F_TCP_REQ_CNT: smp_val = SMP_VAL_FE_REQ_CNT; break;
2653 case ACT_F_TCP_RES_CNT: smp_val = SMP_VAL_BE_RES_CNT; break;
2654 case ACT_F_HTTP_REQ: smp_val = SMP_VAL_FE_HRQ_HDR; break;
2655 case ACT_F_HTTP_RES: smp_val = SMP_VAL_BE_HRS_HDR; break;
2656 default:
2657 memprintf(err, "internal error, unexpected rule->from=%d, please report this bug!", rule->from);
2658 return ACT_RET_PRS_ERR;
2659 }
2660 if (!(rule->arg.gpt.expr->fetch->val & smp_val)) {
2661 memprintf(err, "fetch method '%s' extracts information from '%s', none of which is available here", args[*arg-1],
2662 sample_src_names(rule->arg.gpt.expr->fetch->use));
2663 free(rule->arg.gpt.expr);
2664 return ACT_RET_PRS_ERR;
2665 }
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002666 }
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002667
Thierry FOURNIER42148732015-09-02 17:17:33 +02002668 rule->action = ACT_CUSTOM;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002669
2670 return ACT_RET_PRS_OK;
2671}
2672
Willy Tarreau7d562212016-11-25 16:10:05 +01002673/* set temp integer to the number of used entries in the table pointed to by expr.
2674 * Accepts exactly 1 argument of type table.
2675 */
2676static int
2677smp_fetch_table_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
2678{
2679 smp->flags = SMP_F_VOL_TEST;
2680 smp->data.type = SMP_T_SINT;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002681 smp->data.u.sint = args->data.t->current;
Willy Tarreau7d562212016-11-25 16:10:05 +01002682 return 1;
2683}
2684
2685/* set temp integer to the number of free entries in the table pointed to by expr.
2686 * Accepts exactly 1 argument of type table.
2687 */
2688static int
2689smp_fetch_table_avl(const struct arg *args, struct sample *smp, const char *kw, void *private)
2690{
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002691 struct stktable *t;
Willy Tarreau7d562212016-11-25 16:10:05 +01002692
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002693 t = args->data.t;
Willy Tarreau7d562212016-11-25 16:10:05 +01002694 smp->flags = SMP_F_VOL_TEST;
2695 smp->data.type = SMP_T_SINT;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002696 smp->data.u.sint = t->size - t->current;
Willy Tarreau7d562212016-11-25 16:10:05 +01002697 return 1;
2698}
2699
2700/* Returns a pointer to a stkctr depending on the fetch keyword name.
2701 * It is designed to be called as sc[0-9]_* sc_* or src_* exclusively.
2702 * sc[0-9]_* will return a pointer to the respective field in the
2703 * stream <l4>. sc_* requires an UINT argument specifying the stick
2704 * counter number. src_* will fill a locally allocated structure with
2705 * the table and entry corresponding to what is specified with src_*.
2706 * NULL may be returned if the designated stkctr is not tracked. For
2707 * the sc_* and sc[0-9]_* forms, an optional table argument may be
2708 * passed. When present, the currently tracked key is then looked up
2709 * in the specified table instead of the current table. The purpose is
Ilya Shipitsin47d17182020-06-21 21:42:57 +05002710 * to be able to convert multiple values per key (eg: have gpc0 from
Willy Tarreau7d562212016-11-25 16:10:05 +01002711 * multiple tables). <strm> is allowed to be NULL, in which case only
2712 * the session will be consulted.
2713 */
2714struct stkctr *
Emeric Brun819fc6f2017-06-13 19:37:32 +02002715smp_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 +01002716{
Willy Tarreau7d562212016-11-25 16:10:05 +01002717 struct stkctr *stkptr;
2718 struct stksess *stksess;
2719 unsigned int num = kw[2] - '0';
2720 int arg = 0;
2721
2722 if (num == '_' - '0') {
2723 /* sc_* variant, args[0] = ctr# (mandatory) */
2724 num = args[arg++].data.sint;
Willy Tarreau7d562212016-11-25 16:10:05 +01002725 }
2726 else if (num > 9) { /* src_* variant, args[0] = table */
2727 struct stktable_key *key;
2728 struct connection *conn = objt_conn(sess->origin);
2729 struct sample smp;
2730
2731 if (!conn)
2732 return NULL;
2733
Joseph Herlant5662fa42018-11-15 13:43:28 -08002734 /* Fetch source address in a sample. */
Willy Tarreau7d562212016-11-25 16:10:05 +01002735 smp.px = NULL;
2736 smp.sess = sess;
2737 smp.strm = strm;
Amaury Denoyellec460c702021-05-12 10:17:47 +02002738 if (!smp_fetch_src || !smp_fetch_src(empty_arg_list, &smp, "src", NULL))
Willy Tarreau7d562212016-11-25 16:10:05 +01002739 return NULL;
2740
2741 /* Converts into key. */
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002742 key = smp_to_stkey(&smp, args->data.t);
Willy Tarreau7d562212016-11-25 16:10:05 +01002743 if (!key)
2744 return NULL;
2745
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002746 stkctr->table = args->data.t;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002747 stkctr_set_entry(stkctr, stktable_lookup_key(stkctr->table, key));
2748 return stkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002749 }
2750
2751 /* Here, <num> contains the counter number from 0 to 9 for
2752 * the sc[0-9]_ form, or even higher using sc_(num) if needed.
2753 * args[arg] is the first optional argument. We first lookup the
2754 * ctr form the stream, then from the session if it was not there.
Christopher Fauleta9fa88a2019-10-21 10:53:34 +02002755 * But we must be sure the counter does not exceed MAX_SESS_STKCTR.
Willy Tarreau7d562212016-11-25 16:10:05 +01002756 */
Christopher Fauleta9fa88a2019-10-21 10:53:34 +02002757 if (num >= MAX_SESS_STKCTR)
2758 return NULL;
Willy Tarreau7d562212016-11-25 16:10:05 +01002759
2760 if (strm)
2761 stkptr = &strm->stkctr[num];
2762 if (!strm || !stkctr_entry(stkptr)) {
2763 stkptr = &sess->stkctr[num];
2764 if (!stkctr_entry(stkptr))
2765 return NULL;
2766 }
2767
2768 stksess = stkctr_entry(stkptr);
2769 if (!stksess)
2770 return NULL;
2771
2772 if (unlikely(args[arg].type == ARGT_TAB)) {
2773 /* an alternate table was specified, let's look up the same key there */
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002774 stkctr->table = args[arg].data.t;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002775 stkctr_set_entry(stkctr, stktable_lookup(stkctr->table, stksess));
2776 return stkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002777 }
2778 return stkptr;
2779}
2780
2781/* same as smp_fetch_sc_stkctr() but dedicated to src_* and can create
2782 * the entry if it doesn't exist yet. This is needed for a few fetch
2783 * functions which need to create an entry, such as src_inc_gpc* and
2784 * src_clr_gpc*.
2785 */
2786struct stkctr *
Emeric Brun819fc6f2017-06-13 19:37:32 +02002787smp_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 +01002788{
Willy Tarreau7d562212016-11-25 16:10:05 +01002789 struct stktable_key *key;
2790 struct connection *conn = objt_conn(sess->origin);
2791 struct sample smp;
2792
2793 if (strncmp(kw, "src_", 4) != 0)
2794 return NULL;
2795
2796 if (!conn)
2797 return NULL;
2798
Joseph Herlant5662fa42018-11-15 13:43:28 -08002799 /* Fetch source address in a sample. */
Willy Tarreau7d562212016-11-25 16:10:05 +01002800 smp.px = NULL;
2801 smp.sess = sess;
2802 smp.strm = strm;
Amaury Denoyellec460c702021-05-12 10:17:47 +02002803 if (!smp_fetch_src || !smp_fetch_src(empty_arg_list, &smp, "src", NULL))
Willy Tarreau7d562212016-11-25 16:10:05 +01002804 return NULL;
2805
2806 /* Converts into key. */
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002807 key = smp_to_stkey(&smp, args->data.t);
Willy Tarreau7d562212016-11-25 16:10:05 +01002808 if (!key)
2809 return NULL;
2810
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002811 stkctr->table = args->data.t;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002812 stkctr_set_entry(stkctr, stktable_get_entry(stkctr->table, key));
2813 return stkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002814}
2815
2816/* set return a boolean indicating if the requested stream counter is
2817 * currently being tracked or not.
2818 * Supports being called as "sc[0-9]_tracked" only.
2819 */
2820static int
2821smp_fetch_sc_tracked(const struct arg *args, struct sample *smp, const char *kw, void *private)
2822{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002823 struct stkctr tmpstkctr;
2824 struct stkctr *stkctr;
2825
Willy Tarreau7d562212016-11-25 16:10:05 +01002826 smp->flags = SMP_F_VOL_TEST;
2827 smp->data.type = SMP_T_BOOL;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002828 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2829 smp->data.u.sint = !!stkctr;
2830
2831 /* release the ref count */
Dirkjan Bussinkff57f1b2018-09-14 14:31:22 +02002832 if (stkctr == &tmpstkctr)
Emeric Brun819fc6f2017-06-13 19:37:32 +02002833 stktable_release(stkctr->table, stkctr_entry(stkctr));
2834
Emeric Brun877b0b52021-06-30 18:57:49 +02002835 return 1;
2836}
2837
2838/* set <smp> to the General Purpose Tag of index set as first arg
2839 * to value from the stream's tracked frontend counters or from the src.
2840 * Supports being called as "sc_get_gpt(<gpt-idx>,<sc-idx>[,<table>])" or
2841 * "src_get_gpt(<gpt-idx>[,<table>])" only. Value zero is returned if
2842 * the key is new or gpt is not stored.
2843 */
2844static int
2845smp_fetch_sc_get_gpt(const struct arg *args, struct sample *smp, const char *kw, void *private)
2846{
2847 struct stkctr tmpstkctr;
2848 struct stkctr *stkctr;
2849 unsigned int idx;
2850
2851 idx = args[0].data.sint;
2852
2853 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args + 1, kw, &tmpstkctr);
2854 if (!stkctr)
2855 return 0;
2856
2857 smp->flags = SMP_F_VOL_TEST;
2858 smp->data.type = SMP_T_SINT;
2859 smp->data.u.sint = 0;
2860
2861 if (stkctr_entry(stkctr)) {
2862 void *ptr;
2863
2864 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPT, idx);
2865 if (!ptr) {
2866 if (stkctr == &tmpstkctr)
2867 stktable_release(stkctr->table, stkctr_entry(stkctr));
2868 return 0; /* parameter not stored */
2869 }
2870
2871 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2872
2873 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
2874
2875 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2876
2877 if (stkctr == &tmpstkctr)
2878 stktable_release(stkctr->table, stkctr_entry(stkctr));
2879 }
Willy Tarreau7d562212016-11-25 16:10:05 +01002880 return 1;
2881}
2882
2883/* set <smp> to the General Purpose Flag 0 value from the stream's tracked
2884 * frontend counters or from the src.
2885 * Supports being called as "sc[0-9]_get_gpc0" or "src_get_gpt0" only. Value
2886 * zero is returned if the key is new.
2887 */
2888static int
2889smp_fetch_sc_get_gpt0(const struct arg *args, struct sample *smp, const char *kw, void *private)
2890{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002891 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002892 struct stkctr *stkctr;
2893
Emeric Brun819fc6f2017-06-13 19:37:32 +02002894 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002895 if (!stkctr)
2896 return 0;
2897
2898 smp->flags = SMP_F_VOL_TEST;
2899 smp->data.type = SMP_T_SINT;
2900 smp->data.u.sint = 0;
2901
Emeric Brun819fc6f2017-06-13 19:37:32 +02002902 if (stkctr_entry(stkctr)) {
2903 void *ptr;
2904
2905 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPT0);
Emeric Brunf7ab0bf2021-06-30 18:58:22 +02002906 if (!ptr)
2907 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPT, 0);
2908
Emeric Brun4d7ada82021-06-30 19:04:16 +02002909 if (!ptr) {
2910 if (stkctr == &tmpstkctr)
2911 stktable_release(stkctr->table, stkctr_entry(stkctr));
2912 return 0; /* parameter not stored */
2913 }
2914
2915 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2916
2917 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
2918
2919 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2920
2921 if (stkctr == &tmpstkctr)
2922 stktable_release(stkctr->table, stkctr_entry(stkctr));
2923 }
2924 return 1;
2925}
2926
2927/* set <smp> to the GPC[args(0)]'s value from the stream's tracked
2928 * frontend counters or from the src.
2929 * Supports being called as "sc_get_gpc(<gpc-idx>,<sc-idx>[,<table>])" or
2930 * "src_get_gpc(<gpc-idx>[,<table>])" only. Value
2931 * Value zero is returned if the key is new or gpc is not stored.
2932 */
2933static int
2934smp_fetch_sc_get_gpc(const struct arg *args, struct sample *smp, const char *kw, void *private)
2935{
2936 struct stkctr tmpstkctr;
2937 struct stkctr *stkctr;
2938 unsigned int idx;
2939
2940 idx = args[0].data.sint;
2941
2942 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args + 1, kw, &tmpstkctr);
2943 if (!stkctr)
2944 return 0;
2945
2946 smp->flags = SMP_F_VOL_TEST;
2947 smp->data.type = SMP_T_SINT;
2948 smp->data.u.sint = 0;
2949
2950 if (stkctr_entry(stkctr) != NULL) {
2951 void *ptr;
2952
2953 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC, idx);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002954 if (!ptr) {
2955 if (stkctr == &tmpstkctr)
2956 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002957 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002958 }
2959
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002960 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002961
Emeric Brun0e3457b2021-06-30 17:18:28 +02002962 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002963
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002964 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002965
2966 if (stkctr == &tmpstkctr)
2967 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002968 }
2969 return 1;
2970}
2971
2972/* set <smp> to the General Purpose Counter 0 value from the stream's tracked
2973 * frontend counters or from the src.
2974 * Supports being called as "sc[0-9]_get_gpc0" or "src_get_gpc0" only. Value
2975 * zero is returned if the key is new.
2976 */
2977static int
2978smp_fetch_sc_get_gpc0(const struct arg *args, struct sample *smp, const char *kw, void *private)
2979{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002980 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002981 struct stkctr *stkctr;
2982
Emeric Brun819fc6f2017-06-13 19:37:32 +02002983 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002984 if (!stkctr)
2985 return 0;
2986
2987 smp->flags = SMP_F_VOL_TEST;
2988 smp->data.type = SMP_T_SINT;
2989 smp->data.u.sint = 0;
2990
2991 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002992 void *ptr;
2993
2994 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0);
2995 if (!ptr) {
Emeric Brun726783d2021-06-30 19:06:43 +02002996 /* fallback on the gpc array */
2997 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC, 0);
2998 }
2999
3000 if (!ptr) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003001 if (stkctr == &tmpstkctr)
3002 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003003 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003004 }
3005
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003006 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003007
Emeric Brun0e3457b2021-06-30 17:18:28 +02003008 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003009
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003010 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003011
3012 if (stkctr == &tmpstkctr)
3013 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003014 }
3015 return 1;
3016}
3017
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003018/* set <smp> to the General Purpose Counter 1 value from the stream's tracked
3019 * frontend counters or from the src.
3020 * Supports being called as "sc[0-9]_get_gpc1" or "src_get_gpc1" only. Value
3021 * zero is returned if the key is new.
3022 */
3023static int
3024smp_fetch_sc_get_gpc1(const struct arg *args, struct sample *smp, const char *kw, void *private)
3025{
3026 struct stkctr tmpstkctr;
3027 struct stkctr *stkctr;
3028
3029 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
3030 if (!stkctr)
3031 return 0;
3032
3033 smp->flags = SMP_F_VOL_TEST;
3034 smp->data.type = SMP_T_SINT;
3035 smp->data.u.sint = 0;
3036
3037 if (stkctr_entry(stkctr) != NULL) {
3038 void *ptr;
3039
3040 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1);
3041 if (!ptr) {
Emeric Brun726783d2021-06-30 19:06:43 +02003042 /* fallback on the gpc array */
3043 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC, 1);
3044 }
3045
3046 if (!ptr) {
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003047 if (stkctr == &tmpstkctr)
3048 stktable_release(stkctr->table, stkctr_entry(stkctr));
3049 return 0; /* parameter not stored */
3050 }
3051
3052 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3053
Emeric Brun0e3457b2021-06-30 17:18:28 +02003054 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003055
3056 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3057
3058 if (stkctr == &tmpstkctr)
3059 stktable_release(stkctr->table, stkctr_entry(stkctr));
3060 }
3061 return 1;
3062}
3063
Emeric Brun4d7ada82021-06-30 19:04:16 +02003064/* set <smp> to the GPC[args(0)]'s event rate from the stream's
3065 * tracked frontend counters or from the src.
3066 * Supports being called as "sc_gpc_rate(<gpc-idx>,<sc-idx>[,<table])"
3067 * or "src_gpc_rate(<gpc-idx>[,<table>])" only.
3068 * Value zero is returned if the key is new or gpc_rate is not stored.
3069 */
3070static int
3071smp_fetch_sc_gpc_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3072{
3073 struct stkctr tmpstkctr;
3074 struct stkctr *stkctr;
3075 unsigned int idx;
3076
3077 idx = args[0].data.sint;
3078
3079 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args + 1, kw, &tmpstkctr);
3080 if (!stkctr)
3081 return 0;
3082
3083 smp->flags = SMP_F_VOL_TEST;
3084 smp->data.type = SMP_T_SINT;
3085 smp->data.u.sint = 0;
3086 if (stkctr_entry(stkctr) != NULL) {
3087 void *ptr;
3088
3089 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC_RATE, idx);
3090 if (!ptr) {
3091 if (stkctr == &tmpstkctr)
3092 stktable_release(stkctr->table, stkctr_entry(stkctr));
3093 return 0; /* parameter not stored */
3094 }
3095
3096 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3097
3098 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
3099 stkctr->table->data_arg[STKTABLE_DT_GPC_RATE].u);
3100
3101 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3102
3103 if (stkctr == &tmpstkctr)
3104 stktable_release(stkctr->table, stkctr_entry(stkctr));
3105 }
3106 return 1;
3107}
3108
Willy Tarreau7d562212016-11-25 16:10:05 +01003109/* set <smp> to the General Purpose Counter 0's event rate from the stream's
3110 * tracked frontend counters or from the src.
3111 * Supports being called as "sc[0-9]_gpc0_rate" or "src_gpc0_rate" only.
3112 * Value zero is returned if the key is new.
3113 */
3114static int
3115smp_fetch_sc_gpc0_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3116{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003117 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003118 struct stkctr *stkctr;
Emeric Brun726783d2021-06-30 19:06:43 +02003119 unsigned int period;
Willy Tarreau7d562212016-11-25 16:10:05 +01003120
Emeric Brun819fc6f2017-06-13 19:37:32 +02003121 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003122 if (!stkctr)
3123 return 0;
3124
3125 smp->flags = SMP_F_VOL_TEST;
3126 smp->data.type = SMP_T_SINT;
3127 smp->data.u.sint = 0;
3128 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003129 void *ptr;
3130
3131 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0_RATE);
Emeric Brun726783d2021-06-30 19:06:43 +02003132 if (ptr) {
3133 period = stkctr->table->data_arg[STKTABLE_DT_GPC0_RATE].u;
3134 }
3135 else {
3136 /* fallback on the gpc array */
3137 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC_RATE, 0);
3138 if (ptr)
3139 period = stkctr->table->data_arg[STKTABLE_DT_GPC_RATE].u;
3140 }
3141
Emeric Brun819fc6f2017-06-13 19:37:32 +02003142 if (!ptr) {
3143 if (stkctr == &tmpstkctr)
3144 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003145 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003146 }
3147
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003148 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003149
Emeric Brun726783d2021-06-30 19:06:43 +02003150 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp), period);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003151
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003152 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003153
3154 if (stkctr == &tmpstkctr)
3155 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003156 }
3157 return 1;
3158}
3159
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003160/* set <smp> to the General Purpose Counter 1's event rate from the stream's
3161 * tracked frontend counters or from the src.
3162 * Supports being called as "sc[0-9]_gpc1_rate" or "src_gpc1_rate" only.
3163 * Value zero is returned if the key is new.
3164 */
3165static int
3166smp_fetch_sc_gpc1_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3167{
3168 struct stkctr tmpstkctr;
3169 struct stkctr *stkctr;
Emeric Brun726783d2021-06-30 19:06:43 +02003170 unsigned int period;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003171
3172 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
3173 if (!stkctr)
3174 return 0;
3175
3176 smp->flags = SMP_F_VOL_TEST;
3177 smp->data.type = SMP_T_SINT;
3178 smp->data.u.sint = 0;
3179 if (stkctr_entry(stkctr) != NULL) {
3180 void *ptr;
3181
3182 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1_RATE);
Emeric Brun726783d2021-06-30 19:06:43 +02003183 if (ptr) {
3184 period = stkctr->table->data_arg[STKTABLE_DT_GPC1_RATE].u;
3185 }
3186 else {
3187 /* fallback on the gpc array */
3188 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC_RATE, 1);
3189 if (ptr)
3190 period = stkctr->table->data_arg[STKTABLE_DT_GPC_RATE].u;
3191 }
3192
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003193 if (!ptr) {
3194 if (stkctr == &tmpstkctr)
3195 stktable_release(stkctr->table, stkctr_entry(stkctr));
3196 return 0; /* parameter not stored */
3197 }
3198
3199 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3200
Emeric Brun726783d2021-06-30 19:06:43 +02003201 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 +01003202
3203 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3204
3205 if (stkctr == &tmpstkctr)
3206 stktable_release(stkctr->table, stkctr_entry(stkctr));
3207 }
3208 return 1;
3209}
3210
Emeric Brun4d7ada82021-06-30 19:04:16 +02003211/* Increment the GPC[args(0)] value from the stream's tracked
3212 * frontend counters and return it into temp integer.
3213 * Supports being called as "sc_inc_gpc(<gpc-idx>,<sc-idx>[,<table>])"
3214 * or "src_inc_gpc(<gpc-idx>[,<table>])" only.
3215 */
3216static int
3217smp_fetch_sc_inc_gpc(const struct arg *args, struct sample *smp, const char *kw, void *private)
3218{
3219 struct stkctr tmpstkctr;
3220 struct stkctr *stkctr;
3221 unsigned int idx;
3222
3223 idx = args[0].data.sint;
3224
3225 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args + 1, kw, &tmpstkctr);
3226 if (!stkctr)
3227 return 0;
3228
3229 smp->flags = SMP_F_VOL_TEST;
3230 smp->data.type = SMP_T_SINT;
3231 smp->data.u.sint = 0;
3232
3233 if (!stkctr_entry(stkctr))
3234 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
3235
3236 if (stkctr && stkctr_entry(stkctr)) {
3237 void *ptr1,*ptr2;
3238
3239
3240 /* First, update gpc0_rate if it's tracked. Second, update its
3241 * gpc0 if tracked. Returns gpc0's value otherwise the curr_ctr.
3242 */
3243 ptr1 = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC_RATE, idx);
3244 ptr2 = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC, idx);
3245 if (ptr1 || ptr2) {
3246 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3247
3248 if (ptr1) {
3249 update_freq_ctr_period(&stktable_data_cast(ptr1, std_t_frqp),
3250 stkctr->table->data_arg[STKTABLE_DT_GPC_RATE].u, 1);
3251 smp->data.u.sint = (&stktable_data_cast(ptr1, std_t_frqp))->curr_ctr;
3252 }
3253
3254 if (ptr2)
3255 smp->data.u.sint = ++stktable_data_cast(ptr2, std_t_uint);
3256
3257 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3258
3259 /* If data was modified, we need to touch to re-schedule sync */
3260 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
3261 }
3262 else if (stkctr == &tmpstkctr)
3263 stktable_release(stkctr->table, stkctr_entry(stkctr));
3264 }
3265 return 1;
3266}
3267
Willy Tarreau7d562212016-11-25 16:10:05 +01003268/* Increment the General Purpose Counter 0 value from the stream's tracked
3269 * frontend counters and return it into temp integer.
3270 * Supports being called as "sc[0-9]_inc_gpc0" or "src_inc_gpc0" only.
3271 */
3272static int
3273smp_fetch_sc_inc_gpc0(const struct arg *args, struct sample *smp, const char *kw, void *private)
3274{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003275 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003276 struct stkctr *stkctr;
Willy Tarreau5b654ad2021-07-06 18:51:12 +02003277 unsigned int period = 0;
Willy Tarreau7d562212016-11-25 16:10:05 +01003278
Emeric Brun819fc6f2017-06-13 19:37:32 +02003279 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003280 if (!stkctr)
3281 return 0;
3282
3283 smp->flags = SMP_F_VOL_TEST;
3284 smp->data.type = SMP_T_SINT;
3285 smp->data.u.sint = 0;
3286
Emeric Brun819fc6f2017-06-13 19:37:32 +02003287 if (!stkctr_entry(stkctr))
3288 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003289
3290 if (stkctr && stkctr_entry(stkctr)) {
3291 void *ptr1,*ptr2;
3292
Emeric Brun819fc6f2017-06-13 19:37:32 +02003293
Willy Tarreau7d562212016-11-25 16:10:05 +01003294 /* First, update gpc0_rate if it's tracked. Second, update its
3295 * gpc0 if tracked. Returns gpc0's value otherwise the curr_ctr.
3296 */
3297 ptr1 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0_RATE);
Emeric Brun726783d2021-06-30 19:06:43 +02003298 if (ptr1) {
3299 period = stkctr->table->data_arg[STKTABLE_DT_GPC0_RATE].u;
3300 }
3301 else {
3302 /* fallback on the gpc array */
3303 ptr1 = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC_RATE, 0);
3304 if (ptr1)
3305 period = stkctr->table->data_arg[STKTABLE_DT_GPC_RATE].u;
3306 }
3307
Willy Tarreau7d562212016-11-25 16:10:05 +01003308 ptr2 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0);
Emeric Brun726783d2021-06-30 19:06:43 +02003309 if (!ptr2) {
3310 /* fallback on the gpc array */
3311 ptr2 = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC, 0);
3312 }
3313
Emeric Brun819fc6f2017-06-13 19:37:32 +02003314 if (ptr1 || ptr2) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003315 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Willy Tarreau7d562212016-11-25 16:10:05 +01003316
Emeric Brun819fc6f2017-06-13 19:37:32 +02003317 if (ptr1) {
Emeric Brun0e3457b2021-06-30 17:18:28 +02003318 update_freq_ctr_period(&stktable_data_cast(ptr1, std_t_frqp),
Emeric Brun726783d2021-06-30 19:06:43 +02003319 period, 1);
Emeric Brun0e3457b2021-06-30 17:18:28 +02003320 smp->data.u.sint = (&stktable_data_cast(ptr1, std_t_frqp))->curr_ctr;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003321 }
3322
3323 if (ptr2)
Emeric Brun0e3457b2021-06-30 17:18:28 +02003324 smp->data.u.sint = ++stktable_data_cast(ptr2, std_t_uint);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003325
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003326 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003327
3328 /* If data was modified, we need to touch to re-schedule sync */
3329 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
3330 }
3331 else if (stkctr == &tmpstkctr)
3332 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003333 }
3334 return 1;
3335}
3336
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003337/* Increment the General Purpose Counter 1 value from the stream's tracked
3338 * frontend counters and return it into temp integer.
3339 * Supports being called as "sc[0-9]_inc_gpc1" or "src_inc_gpc1" only.
3340 */
3341static int
3342smp_fetch_sc_inc_gpc1(const struct arg *args, struct sample *smp, const char *kw, void *private)
3343{
3344 struct stkctr tmpstkctr;
3345 struct stkctr *stkctr;
Willy Tarreau5b654ad2021-07-06 18:51:12 +02003346 unsigned int period = 0;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003347
3348 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
3349 if (!stkctr)
3350 return 0;
3351
3352 smp->flags = SMP_F_VOL_TEST;
3353 smp->data.type = SMP_T_SINT;
3354 smp->data.u.sint = 0;
3355
3356 if (!stkctr_entry(stkctr))
3357 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
3358
3359 if (stkctr && stkctr_entry(stkctr)) {
3360 void *ptr1,*ptr2;
3361
3362
3363 /* First, update gpc1_rate if it's tracked. Second, update its
3364 * gpc1 if tracked. Returns gpc1's value otherwise the curr_ctr.
3365 */
3366 ptr1 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1_RATE);
Emeric Brun726783d2021-06-30 19:06:43 +02003367 if (ptr1) {
3368 period = stkctr->table->data_arg[STKTABLE_DT_GPC1_RATE].u;
3369 }
3370 else {
3371 /* fallback on the gpc array */
3372 ptr1 = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC_RATE, 1);
3373 if (ptr1)
3374 period = stkctr->table->data_arg[STKTABLE_DT_GPC_RATE].u;
3375 }
3376
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003377 ptr2 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1);
Emeric Brun726783d2021-06-30 19:06:43 +02003378 if (!ptr2) {
3379 /* fallback on the gpc array */
3380 ptr2 = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC, 1);
3381 }
3382
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003383 if (ptr1 || ptr2) {
3384 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3385
3386 if (ptr1) {
Emeric Brun0e3457b2021-06-30 17:18:28 +02003387 update_freq_ctr_period(&stktable_data_cast(ptr1, std_t_frqp),
Emeric Brun726783d2021-06-30 19:06:43 +02003388 period, 1);
Emeric Brun0e3457b2021-06-30 17:18:28 +02003389 smp->data.u.sint = (&stktable_data_cast(ptr1, std_t_frqp))->curr_ctr;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003390 }
3391
3392 if (ptr2)
Emeric Brun0e3457b2021-06-30 17:18:28 +02003393 smp->data.u.sint = ++stktable_data_cast(ptr2, std_t_uint);
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003394
3395 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3396
3397 /* If data was modified, we need to touch to re-schedule sync */
3398 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
3399 }
3400 else if (stkctr == &tmpstkctr)
3401 stktable_release(stkctr->table, stkctr_entry(stkctr));
3402 }
3403 return 1;
3404}
3405
Emeric Brun4d7ada82021-06-30 19:04:16 +02003406/* Clear the GPC[args(0)] value from the stream's tracked
3407 * frontend counters and return its previous value into temp integer.
3408 * Supports being called as "sc_clr_gpc(<gpc-idx>,<sc-idx>[,<table>])"
3409 * or "src_clr_gpc(<gpc-idx>[,<table>])" only.
3410 */
3411static int
3412smp_fetch_sc_clr_gpc(const struct arg *args, struct sample *smp, const char *kw, void *private)
3413{
3414 struct stkctr tmpstkctr;
3415 struct stkctr *stkctr;
3416 unsigned int idx;
3417
3418 idx = args[0].data.sint;
3419
3420 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args + 1, kw, &tmpstkctr);
3421 if (!stkctr)
3422 return 0;
3423
3424 smp->flags = SMP_F_VOL_TEST;
3425 smp->data.type = SMP_T_SINT;
3426 smp->data.u.sint = 0;
3427
3428 if (!stkctr_entry(stkctr))
3429 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
3430
3431 if (stkctr && stkctr_entry(stkctr)) {
3432 void *ptr;
3433
3434 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC, idx);
3435 if (!ptr) {
3436 if (stkctr == &tmpstkctr)
3437 stktable_release(stkctr->table, stkctr_entry(stkctr));
3438 return 0; /* parameter not stored */
3439 }
3440
3441 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3442
3443 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
3444 stktable_data_cast(ptr, std_t_uint) = 0;
3445
3446 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3447
3448 /* If data was modified, we need to touch to re-schedule sync */
3449 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
3450 }
3451 return 1;
3452}
3453
Willy Tarreau7d562212016-11-25 16:10:05 +01003454/* Clear the General Purpose Counter 0 value from the stream's tracked
3455 * frontend counters and return its previous value into temp integer.
3456 * Supports being called as "sc[0-9]_clr_gpc0" or "src_clr_gpc0" only.
3457 */
3458static int
3459smp_fetch_sc_clr_gpc0(const struct arg *args, struct sample *smp, const char *kw, void *private)
3460{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003461 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003462 struct stkctr *stkctr;
3463
Emeric Brun819fc6f2017-06-13 19:37:32 +02003464 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003465 if (!stkctr)
3466 return 0;
3467
3468 smp->flags = SMP_F_VOL_TEST;
3469 smp->data.type = SMP_T_SINT;
3470 smp->data.u.sint = 0;
3471
Emeric Brun819fc6f2017-06-13 19:37:32 +02003472 if (!stkctr_entry(stkctr))
3473 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003474
Emeric Brun819fc6f2017-06-13 19:37:32 +02003475 if (stkctr && stkctr_entry(stkctr)) {
3476 void *ptr;
3477
3478 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0);
3479 if (!ptr) {
Emeric Brun726783d2021-06-30 19:06:43 +02003480 /* fallback on the gpc array */
3481 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC, 0);
3482 }
3483
3484 if (!ptr) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003485 if (stkctr == &tmpstkctr)
3486 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003487 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003488 }
3489
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003490 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003491
Emeric Brun0e3457b2021-06-30 17:18:28 +02003492 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
3493 stktable_data_cast(ptr, std_t_uint) = 0;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003494
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003495 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003496
Willy Tarreau7d562212016-11-25 16:10:05 +01003497 /* If data was modified, we need to touch to re-schedule sync */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003498 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
Willy Tarreau7d562212016-11-25 16:10:05 +01003499 }
3500 return 1;
3501}
3502
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003503/* Clear the General Purpose Counter 1 value from the stream's tracked
3504 * frontend counters and return its previous value into temp integer.
3505 * Supports being called as "sc[0-9]_clr_gpc1" or "src_clr_gpc1" only.
3506 */
3507static int
3508smp_fetch_sc_clr_gpc1(const struct arg *args, struct sample *smp, const char *kw, void *private)
3509{
3510 struct stkctr tmpstkctr;
3511 struct stkctr *stkctr;
3512
3513 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
3514 if (!stkctr)
3515 return 0;
3516
3517 smp->flags = SMP_F_VOL_TEST;
3518 smp->data.type = SMP_T_SINT;
3519 smp->data.u.sint = 0;
3520
3521 if (!stkctr_entry(stkctr))
3522 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
3523
3524 if (stkctr && stkctr_entry(stkctr)) {
3525 void *ptr;
3526
3527 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1);
3528 if (!ptr) {
Emeric Brun726783d2021-06-30 19:06:43 +02003529 /* fallback on the gpc array */
3530 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC, 1);
3531 }
3532
3533 if (!ptr) {
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003534 if (stkctr == &tmpstkctr)
3535 stktable_release(stkctr->table, stkctr_entry(stkctr));
3536 return 0; /* parameter not stored */
3537 }
3538
3539 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3540
Emeric Brun0e3457b2021-06-30 17:18:28 +02003541 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
3542 stktable_data_cast(ptr, std_t_uint) = 0;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003543
3544 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3545
3546 /* If data was modified, we need to touch to re-schedule sync */
3547 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
3548 }
3549 return 1;
3550}
3551
Willy Tarreau7d562212016-11-25 16:10:05 +01003552/* set <smp> to the cumulated number of connections from the stream's tracked
3553 * frontend counters. Supports being called as "sc[0-9]_conn_cnt" or
3554 * "src_conn_cnt" only.
3555 */
3556static int
3557smp_fetch_sc_conn_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
3558{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003559 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003560 struct stkctr *stkctr;
3561
Emeric Brun819fc6f2017-06-13 19:37:32 +02003562 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003563 if (!stkctr)
3564 return 0;
3565
3566 smp->flags = SMP_F_VOL_TEST;
3567 smp->data.type = SMP_T_SINT;
3568 smp->data.u.sint = 0;
3569 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003570 void *ptr;
3571
3572 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_CONN_CNT);
3573 if (!ptr) {
3574 if (stkctr == &tmpstkctr)
3575 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003576 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003577 }
3578
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003579 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003580
Emeric Brun0e3457b2021-06-30 17:18:28 +02003581 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003582
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003583 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003584
3585 if (stkctr == &tmpstkctr)
3586 stktable_release(stkctr->table, stkctr_entry(stkctr));
3587
3588
Willy Tarreau7d562212016-11-25 16:10:05 +01003589 }
3590 return 1;
3591}
3592
3593/* set <smp> to the connection rate from the stream's tracked frontend
3594 * counters. Supports being called as "sc[0-9]_conn_rate" or "src_conn_rate"
3595 * only.
3596 */
3597static int
3598smp_fetch_sc_conn_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3599{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003600 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003601 struct stkctr *stkctr;
3602
Emeric Brun819fc6f2017-06-13 19:37:32 +02003603 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003604 if (!stkctr)
3605 return 0;
3606
3607 smp->flags = SMP_F_VOL_TEST;
3608 smp->data.type = SMP_T_SINT;
3609 smp->data.u.sint = 0;
3610 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003611 void *ptr;
3612
3613 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_CONN_RATE);
3614 if (!ptr) {
3615 if (stkctr == &tmpstkctr)
3616 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003617 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003618 }
3619
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003620 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003621
Emeric Brun0e3457b2021-06-30 17:18:28 +02003622 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Willy Tarreau7d562212016-11-25 16:10:05 +01003623 stkctr->table->data_arg[STKTABLE_DT_CONN_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003624
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003625 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003626
3627 if (stkctr == &tmpstkctr)
3628 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003629 }
3630 return 1;
3631}
3632
3633/* set temp integer to the number of connections from the stream's source address
3634 * in the table pointed to by expr, after updating it.
3635 * Accepts exactly 1 argument of type table.
3636 */
3637static int
3638smp_fetch_src_updt_conn_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
3639{
3640 struct connection *conn = objt_conn(smp->sess->origin);
3641 struct stksess *ts;
3642 struct stktable_key *key;
3643 void *ptr;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003644 struct stktable *t;
Willy Tarreau7d562212016-11-25 16:10:05 +01003645
3646 if (!conn)
3647 return 0;
3648
Joseph Herlant5662fa42018-11-15 13:43:28 -08003649 /* Fetch source address in a sample. */
Amaury Denoyellec460c702021-05-12 10:17:47 +02003650 if (!smp_fetch_src || !smp_fetch_src(empty_arg_list, smp, "src", NULL))
Willy Tarreau7d562212016-11-25 16:10:05 +01003651 return 0;
3652
3653 /* Converts into key. */
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003654 key = smp_to_stkey(smp, args->data.t);
Willy Tarreau7d562212016-11-25 16:10:05 +01003655 if (!key)
3656 return 0;
3657
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003658 t = args->data.t;
Willy Tarreau7d562212016-11-25 16:10:05 +01003659
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003660 if ((ts = stktable_get_entry(t, key)) == NULL)
Willy Tarreau7d562212016-11-25 16:10:05 +01003661 /* entry does not exist and could not be created */
3662 return 0;
3663
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003664 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_CONN_CNT);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003665 if (!ptr) {
Willy Tarreau7d562212016-11-25 16:10:05 +01003666 return 0; /* parameter not stored in this table */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003667 }
Willy Tarreau7d562212016-11-25 16:10:05 +01003668
3669 smp->data.type = SMP_T_SINT;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003670
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003671 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003672
Emeric Brun0e3457b2021-06-30 17:18:28 +02003673 smp->data.u.sint = ++stktable_data_cast(ptr, std_t_uint);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003674
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003675 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003676
Willy Tarreau7d562212016-11-25 16:10:05 +01003677 smp->flags = SMP_F_VOL_TEST;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003678
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003679 stktable_touch_local(t, ts, 1);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003680
3681 /* Touch was previously performed by stktable_update_key */
Willy Tarreau7d562212016-11-25 16:10:05 +01003682 return 1;
3683}
3684
3685/* set <smp> to the number of concurrent connections from the stream's tracked
3686 * frontend counters. Supports being called as "sc[0-9]_conn_cur" or
3687 * "src_conn_cur" only.
3688 */
3689static int
3690smp_fetch_sc_conn_cur(const struct arg *args, struct sample *smp, const char *kw, void *private)
3691{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003692 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003693 struct stkctr *stkctr;
3694
Emeric Brun819fc6f2017-06-13 19:37:32 +02003695 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003696 if (!stkctr)
3697 return 0;
3698
3699 smp->flags = SMP_F_VOL_TEST;
3700 smp->data.type = SMP_T_SINT;
3701 smp->data.u.sint = 0;
3702 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003703 void *ptr;
3704
3705 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_CONN_CUR);
3706 if (!ptr) {
3707 if (stkctr == &tmpstkctr)
3708 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003709 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003710 }
3711
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003712 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003713
Emeric Brun0e3457b2021-06-30 17:18:28 +02003714 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003715
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003716 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003717
3718 if (stkctr == &tmpstkctr)
3719 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003720 }
3721 return 1;
3722}
3723
3724/* set <smp> to the cumulated number of streams from the stream's tracked
3725 * frontend counters. Supports being called as "sc[0-9]_sess_cnt" or
3726 * "src_sess_cnt" only.
3727 */
3728static int
3729smp_fetch_sc_sess_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
3730{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003731 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003732 struct stkctr *stkctr;
3733
Emeric Brun819fc6f2017-06-13 19:37:32 +02003734 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003735 if (!stkctr)
3736 return 0;
3737
3738 smp->flags = SMP_F_VOL_TEST;
3739 smp->data.type = SMP_T_SINT;
3740 smp->data.u.sint = 0;
3741 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003742 void *ptr;
3743
3744 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_SESS_CNT);
3745 if (!ptr) {
3746 if (stkctr == &tmpstkctr)
3747 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003748 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003749 }
3750
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003751 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003752
Emeric Brun0e3457b2021-06-30 17:18:28 +02003753 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003754
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003755 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003756
3757 if (stkctr == &tmpstkctr)
3758 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003759 }
3760 return 1;
3761}
3762
3763/* set <smp> to the stream rate from the stream's tracked frontend counters.
3764 * Supports being called as "sc[0-9]_sess_rate" or "src_sess_rate" only.
3765 */
3766static int
3767smp_fetch_sc_sess_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3768{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003769 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003770 struct stkctr *stkctr;
3771
Emeric Brun819fc6f2017-06-13 19:37:32 +02003772 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003773 if (!stkctr)
3774 return 0;
3775
3776 smp->flags = SMP_F_VOL_TEST;
3777 smp->data.type = SMP_T_SINT;
3778 smp->data.u.sint = 0;
3779 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003780 void *ptr;
3781
3782 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_SESS_RATE);
3783 if (!ptr) {
3784 if (stkctr == &tmpstkctr)
3785 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003786 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003787 }
3788
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003789 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003790
Emeric Brun0e3457b2021-06-30 17:18:28 +02003791 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Willy Tarreau7d562212016-11-25 16:10:05 +01003792 stkctr->table->data_arg[STKTABLE_DT_SESS_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003793
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003794 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003795
3796 if (stkctr == &tmpstkctr)
3797 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003798 }
3799 return 1;
3800}
3801
3802/* set <smp> to the cumulated number of HTTP requests from the stream's tracked
3803 * frontend counters. Supports being called as "sc[0-9]_http_req_cnt" or
3804 * "src_http_req_cnt" only.
3805 */
3806static int
3807smp_fetch_sc_http_req_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
3808{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003809 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003810 struct stkctr *stkctr;
3811
Emeric Brun819fc6f2017-06-13 19:37:32 +02003812 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003813 if (!stkctr)
3814 return 0;
3815
3816 smp->flags = SMP_F_VOL_TEST;
3817 smp->data.type = SMP_T_SINT;
3818 smp->data.u.sint = 0;
3819 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003820 void *ptr;
3821
3822 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_REQ_CNT);
3823 if (!ptr) {
3824 if (stkctr == &tmpstkctr)
3825 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003826 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003827 }
3828
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003829 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003830
Emeric Brun0e3457b2021-06-30 17:18:28 +02003831 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003832
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003833 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003834
3835 if (stkctr == &tmpstkctr)
3836 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003837 }
3838 return 1;
3839}
3840
3841/* set <smp> to the HTTP request rate from the stream's tracked frontend
3842 * counters. Supports being called as "sc[0-9]_http_req_rate" or
3843 * "src_http_req_rate" only.
3844 */
3845static int
3846smp_fetch_sc_http_req_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3847{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003848 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003849 struct stkctr *stkctr;
3850
Emeric Brun819fc6f2017-06-13 19:37:32 +02003851 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003852 if (!stkctr)
3853 return 0;
3854
3855 smp->flags = SMP_F_VOL_TEST;
3856 smp->data.type = SMP_T_SINT;
3857 smp->data.u.sint = 0;
3858 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003859 void *ptr;
3860
3861 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_REQ_RATE);
3862 if (!ptr) {
3863 if (stkctr == &tmpstkctr)
3864 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003865 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003866 }
3867
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003868 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003869
Emeric Brun0e3457b2021-06-30 17:18:28 +02003870 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Willy Tarreau7d562212016-11-25 16:10:05 +01003871 stkctr->table->data_arg[STKTABLE_DT_HTTP_REQ_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003872
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003873 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003874
3875 if (stkctr == &tmpstkctr)
3876 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003877 }
3878 return 1;
3879}
3880
3881/* set <smp> to the cumulated number of HTTP requests errors from the stream's
3882 * tracked frontend counters. Supports being called as "sc[0-9]_http_err_cnt" or
3883 * "src_http_err_cnt" only.
3884 */
3885static int
3886smp_fetch_sc_http_err_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
3887{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003888 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003889 struct stkctr *stkctr;
3890
Emeric Brun819fc6f2017-06-13 19:37:32 +02003891 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003892 if (!stkctr)
3893 return 0;
3894
3895 smp->flags = SMP_F_VOL_TEST;
3896 smp->data.type = SMP_T_SINT;
3897 smp->data.u.sint = 0;
3898 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003899 void *ptr;
3900
3901 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_ERR_CNT);
3902 if (!ptr) {
3903 if (stkctr == &tmpstkctr)
3904 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003905 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003906 }
3907
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003908 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003909
Emeric Brun0e3457b2021-06-30 17:18:28 +02003910 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003911
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003912 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003913
3914 if (stkctr == &tmpstkctr)
3915 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003916 }
3917 return 1;
3918}
3919
3920/* set <smp> to the HTTP request error rate from the stream's tracked frontend
3921 * counters. Supports being called as "sc[0-9]_http_err_rate" or
3922 * "src_http_err_rate" only.
3923 */
3924static int
3925smp_fetch_sc_http_err_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3926{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003927 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003928 struct stkctr *stkctr;
3929
Emeric Brun819fc6f2017-06-13 19:37:32 +02003930 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003931 if (!stkctr)
3932 return 0;
3933
3934 smp->flags = SMP_F_VOL_TEST;
3935 smp->data.type = SMP_T_SINT;
3936 smp->data.u.sint = 0;
3937 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003938 void *ptr;
3939
3940 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_ERR_RATE);
3941 if (!ptr) {
3942 if (stkctr == &tmpstkctr)
3943 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003944 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003945 }
3946
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003947 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003948
Emeric Brun0e3457b2021-06-30 17:18:28 +02003949 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Willy Tarreau7d562212016-11-25 16:10:05 +01003950 stkctr->table->data_arg[STKTABLE_DT_HTTP_ERR_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003951
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003952 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003953
3954 if (stkctr == &tmpstkctr)
3955 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003956 }
3957 return 1;
3958}
3959
Willy Tarreau826f3ab2021-02-10 12:07:15 +01003960/* set <smp> to the cumulated number of HTTP response failures from the stream's
3961 * tracked frontend counters. Supports being called as "sc[0-9]_http_fail_cnt" or
3962 * "src_http_fail_cnt" only.
3963 */
3964static int
3965smp_fetch_sc_http_fail_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
3966{
3967 struct stkctr tmpstkctr;
3968 struct stkctr *stkctr;
3969
3970 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
3971 if (!stkctr)
3972 return 0;
3973
3974 smp->flags = SMP_F_VOL_TEST;
3975 smp->data.type = SMP_T_SINT;
3976 smp->data.u.sint = 0;
3977 if (stkctr_entry(stkctr) != NULL) {
3978 void *ptr;
3979
3980 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_FAIL_CNT);
3981 if (!ptr) {
3982 if (stkctr == &tmpstkctr)
3983 stktable_release(stkctr->table, stkctr_entry(stkctr));
3984 return 0; /* parameter not stored */
3985 }
3986
3987 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3988
Emeric Brun0e3457b2021-06-30 17:18:28 +02003989 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Willy Tarreau826f3ab2021-02-10 12:07:15 +01003990
3991 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3992
3993 if (stkctr == &tmpstkctr)
3994 stktable_release(stkctr->table, stkctr_entry(stkctr));
3995 }
3996 return 1;
3997}
3998
3999/* set <smp> to the HTTP response failure rate from the stream's tracked frontend
4000 * counters. Supports being called as "sc[0-9]_http_fail_rate" or
4001 * "src_http_fail_rate" only.
4002 */
4003static int
4004smp_fetch_sc_http_fail_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
4005{
4006 struct stkctr tmpstkctr;
4007 struct stkctr *stkctr;
4008
4009 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
4010 if (!stkctr)
4011 return 0;
4012
4013 smp->flags = SMP_F_VOL_TEST;
4014 smp->data.type = SMP_T_SINT;
4015 smp->data.u.sint = 0;
4016 if (stkctr_entry(stkctr) != NULL) {
4017 void *ptr;
4018
4019 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_FAIL_RATE);
4020 if (!ptr) {
4021 if (stkctr == &tmpstkctr)
4022 stktable_release(stkctr->table, stkctr_entry(stkctr));
4023 return 0; /* parameter not stored */
4024 }
4025
4026 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
4027
Emeric Brun0e3457b2021-06-30 17:18:28 +02004028 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Willy Tarreau826f3ab2021-02-10 12:07:15 +01004029 stkctr->table->data_arg[STKTABLE_DT_HTTP_FAIL_RATE].u);
4030
4031 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
4032
4033 if (stkctr == &tmpstkctr)
4034 stktable_release(stkctr->table, stkctr_entry(stkctr));
4035 }
4036 return 1;
4037}
4038
Willy Tarreau7d562212016-11-25 16:10:05 +01004039/* set <smp> to the number of kbytes received from clients, as found in the
4040 * stream's tracked frontend counters. Supports being called as
4041 * "sc[0-9]_kbytes_in" or "src_kbytes_in" only.
4042 */
4043static int
4044smp_fetch_sc_kbytes_in(const struct arg *args, struct sample *smp, const char *kw, void *private)
4045{
Emeric Brun819fc6f2017-06-13 19:37:32 +02004046 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01004047 struct stkctr *stkctr;
4048
Emeric Brun819fc6f2017-06-13 19:37:32 +02004049 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01004050 if (!stkctr)
4051 return 0;
4052
4053 smp->flags = SMP_F_VOL_TEST;
4054 smp->data.type = SMP_T_SINT;
4055 smp->data.u.sint = 0;
4056 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02004057 void *ptr;
4058
4059 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_IN_CNT);
4060 if (!ptr) {
4061 if (stkctr == &tmpstkctr)
4062 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004063 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02004064 }
4065
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004066 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004067
Emeric Brun0e3457b2021-06-30 17:18:28 +02004068 smp->data.u.sint = stktable_data_cast(ptr, std_t_ull) >> 10;
Emeric Brun819fc6f2017-06-13 19:37:32 +02004069
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004070 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004071
4072 if (stkctr == &tmpstkctr)
4073 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004074 }
4075 return 1;
4076}
4077
4078/* set <smp> to the data rate received from clients in bytes/s, as found
4079 * in the stream's tracked frontend counters. Supports being called as
4080 * "sc[0-9]_bytes_in_rate" or "src_bytes_in_rate" only.
4081 */
4082static int
4083smp_fetch_sc_bytes_in_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
4084{
Emeric Brun819fc6f2017-06-13 19:37:32 +02004085 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01004086 struct stkctr *stkctr;
4087
Emeric Brun819fc6f2017-06-13 19:37:32 +02004088 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01004089 if (!stkctr)
4090 return 0;
4091
4092 smp->flags = SMP_F_VOL_TEST;
4093 smp->data.type = SMP_T_SINT;
4094 smp->data.u.sint = 0;
4095 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02004096 void *ptr;
4097
4098 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_IN_RATE);
4099 if (!ptr) {
4100 if (stkctr == &tmpstkctr)
4101 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004102 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02004103 }
4104
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004105 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004106
Emeric Brun0e3457b2021-06-30 17:18:28 +02004107 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Willy Tarreau7d562212016-11-25 16:10:05 +01004108 stkctr->table->data_arg[STKTABLE_DT_BYTES_IN_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004109
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004110 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004111
4112 if (stkctr == &tmpstkctr)
4113 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004114 }
4115 return 1;
4116}
4117
4118/* set <smp> to the number of kbytes sent to clients, as found in the
4119 * stream's tracked frontend counters. Supports being called as
4120 * "sc[0-9]_kbytes_out" or "src_kbytes_out" only.
4121 */
4122static int
4123smp_fetch_sc_kbytes_out(const struct arg *args, struct sample *smp, const char *kw, void *private)
4124{
Emeric Brun819fc6f2017-06-13 19:37:32 +02004125 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01004126 struct stkctr *stkctr;
4127
Emeric Brun819fc6f2017-06-13 19:37:32 +02004128 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01004129 if (!stkctr)
4130 return 0;
4131
4132 smp->flags = SMP_F_VOL_TEST;
4133 smp->data.type = SMP_T_SINT;
4134 smp->data.u.sint = 0;
4135 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02004136 void *ptr;
4137
4138 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_OUT_CNT);
4139 if (!ptr) {
4140 if (stkctr == &tmpstkctr)
4141 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004142 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02004143 }
4144
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004145 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004146
Emeric Brun0e3457b2021-06-30 17:18:28 +02004147 smp->data.u.sint = stktable_data_cast(ptr, std_t_ull) >> 10;
Emeric Brun819fc6f2017-06-13 19:37:32 +02004148
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004149 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004150
4151 if (stkctr == &tmpstkctr)
4152 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004153 }
4154 return 1;
4155}
4156
4157/* set <smp> to the data rate sent to clients in bytes/s, as found in the
4158 * stream's tracked frontend counters. Supports being called as
4159 * "sc[0-9]_bytes_out_rate" or "src_bytes_out_rate" only.
4160 */
4161static int
4162smp_fetch_sc_bytes_out_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
4163{
Emeric Brun819fc6f2017-06-13 19:37:32 +02004164 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01004165 struct stkctr *stkctr;
4166
Emeric Brun819fc6f2017-06-13 19:37:32 +02004167 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01004168 if (!stkctr)
4169 return 0;
4170
4171 smp->flags = SMP_F_VOL_TEST;
4172 smp->data.type = SMP_T_SINT;
4173 smp->data.u.sint = 0;
4174 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02004175 void *ptr;
4176
4177 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_OUT_RATE);
4178 if (!ptr) {
4179 if (stkctr == &tmpstkctr)
4180 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004181 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02004182 }
4183
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004184 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004185
Emeric Brun0e3457b2021-06-30 17:18:28 +02004186 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Willy Tarreau7d562212016-11-25 16:10:05 +01004187 stkctr->table->data_arg[STKTABLE_DT_BYTES_OUT_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004188
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004189 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004190
4191 if (stkctr == &tmpstkctr)
4192 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004193 }
4194 return 1;
4195}
4196
4197/* set <smp> to the number of active trackers on the SC entry in the stream's
4198 * tracked frontend counters. Supports being called as "sc[0-9]_trackers" only.
4199 */
4200static int
4201smp_fetch_sc_trackers(const struct arg *args, struct sample *smp, const char *kw, void *private)
4202{
Emeric Brun819fc6f2017-06-13 19:37:32 +02004203 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01004204 struct stkctr *stkctr;
4205
Emeric Brun819fc6f2017-06-13 19:37:32 +02004206 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01004207 if (!stkctr)
4208 return 0;
4209
4210 smp->flags = SMP_F_VOL_TEST;
4211 smp->data.type = SMP_T_SINT;
Emeric Brun819fc6f2017-06-13 19:37:32 +02004212 if (stkctr == &tmpstkctr) {
4213 smp->data.u.sint = stkctr_entry(stkctr) ? (stkctr_entry(stkctr)->ref_cnt-1) : 0;
4214 stktable_release(stkctr->table, stkctr_entry(stkctr));
4215 }
4216 else {
4217 smp->data.u.sint = stkctr_entry(stkctr) ? stkctr_entry(stkctr)->ref_cnt : 0;
4218 }
4219
Willy Tarreau7d562212016-11-25 16:10:05 +01004220 return 1;
4221}
4222
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004223
4224/* The functions below are used to manipulate table contents from the CLI.
4225 * There are 3 main actions, "clear", "set" and "show". The code is shared
4226 * between all actions, and the action is encoded in the void *private in
4227 * the appctx as well as in the keyword registration, among one of the
4228 * following values.
4229 */
4230
4231enum {
4232 STK_CLI_ACT_CLR,
4233 STK_CLI_ACT_SET,
4234 STK_CLI_ACT_SHOW,
4235};
4236
4237/* Dump the status of a table to a stream interface's
4238 * read buffer. It returns 0 if the output buffer is full
4239 * and needs to be called again, otherwise non-zero.
4240 */
Willy Tarreau83061a82018-07-13 11:56:34 +02004241static int table_dump_head_to_buffer(struct buffer *msg,
Christopher Faulet908628c2022-03-25 16:43:49 +01004242 struct conn_stream *cs,
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004243 struct stktable *t, struct stktable *target)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004244{
Christopher Faulet908628c2022-03-25 16:43:49 +01004245 struct stream *s = __cs_strm(cs);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004246
4247 chunk_appendf(msg, "# table: %s, type: %s, size:%d, used:%d\n",
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004248 t->id, stktable_types[t->type].kw, t->size, t->current);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004249
4250 /* any other information should be dumped here */
4251
William Lallemand07a62f72017-05-24 00:57:40 +02004252 if (target && (strm_li(s)->bind_conf->level & ACCESS_LVL_MASK) < ACCESS_LVL_OPER)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004253 chunk_appendf(msg, "# contents not dumped due to insufficient privileges\n");
4254
Christopher Faulet908628c2022-03-25 16:43:49 +01004255 if (ci_putchk(cs_ic(cs), msg) == -1) {
4256 si_rx_room_blk(cs->si);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004257 return 0;
4258 }
4259
4260 return 1;
4261}
4262
4263/* Dump a table entry to a stream interface's
4264 * read buffer. It returns 0 if the output buffer is full
4265 * and needs to be called again, otherwise non-zero.
4266 */
Willy Tarreau83061a82018-07-13 11:56:34 +02004267static int table_dump_entry_to_buffer(struct buffer *msg,
Christopher Faulet908628c2022-03-25 16:43:49 +01004268 struct conn_stream *cs,
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004269 struct stktable *t, struct stksess *entry)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004270{
4271 int dt;
4272
4273 chunk_appendf(msg, "%p:", entry);
4274
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004275 if (t->type == SMP_T_IPV4) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004276 char addr[INET_ADDRSTRLEN];
4277 inet_ntop(AF_INET, (const void *)&entry->key.key, addr, sizeof(addr));
4278 chunk_appendf(msg, " key=%s", addr);
4279 }
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004280 else if (t->type == SMP_T_IPV6) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004281 char addr[INET6_ADDRSTRLEN];
4282 inet_ntop(AF_INET6, (const void *)&entry->key.key, addr, sizeof(addr));
4283 chunk_appendf(msg, " key=%s", addr);
4284 }
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004285 else if (t->type == SMP_T_SINT) {
Willy Tarreau6cde5d82020-02-25 09:41:22 +01004286 chunk_appendf(msg, " key=%u", read_u32(entry->key.key));
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004287 }
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004288 else if (t->type == SMP_T_STR) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004289 chunk_appendf(msg, " key=");
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004290 dump_text(msg, (const char *)entry->key.key, t->key_size);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004291 }
4292 else {
4293 chunk_appendf(msg, " key=");
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004294 dump_binary(msg, (const char *)entry->key.key, t->key_size);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004295 }
4296
4297 chunk_appendf(msg, " use=%d exp=%d", entry->ref_cnt - 1, tick_remain(now_ms, entry->expire));
4298
4299 for (dt = 0; dt < STKTABLE_DATA_TYPES; dt++) {
4300 void *ptr;
4301
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004302 if (t->data_ofs[dt] == 0)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004303 continue;
Emeric Brunc64a2a32021-06-30 18:01:02 +02004304 if (stktable_data_types[dt].is_array) {
4305 char tmp[16] = {};
4306 const char *name_pfx = stktable_data_types[dt].name;
4307 const char *name_sfx = NULL;
4308 unsigned int idx = 0;
4309 int i = 0;
4310
4311 /* split name to show index before first _ of the name
4312 * for example: 'gpc3_rate' if array name is 'gpc_rate'.
4313 */
4314 for (i = 0 ; i < (sizeof(tmp) - 1); i++) {
4315 if (!name_pfx[i])
4316 break;
4317 if (name_pfx[i] == '_') {
4318 name_pfx = &tmp[0];
4319 name_sfx = &stktable_data_types[dt].name[i];
4320 break;
4321 }
4322 tmp[i] = name_pfx[i];
4323 }
4324
4325 ptr = stktable_data_ptr_idx(t, entry, dt, idx);
4326 while (ptr) {
4327 if (stktable_data_types[dt].arg_type == ARG_T_DELAY)
4328 chunk_appendf(msg, " %s%u%s(%u)=", name_pfx, idx, name_sfx ? name_sfx : "", t->data_arg[dt].u);
4329 else
4330 chunk_appendf(msg, " %s%u%s=", name_pfx, idx, name_sfx ? name_sfx : "");
4331 switch (stktable_data_types[dt].std_type) {
4332 case STD_T_SINT:
4333 chunk_appendf(msg, "%d", stktable_data_cast(ptr, std_t_sint));
4334 break;
4335 case STD_T_UINT:
4336 chunk_appendf(msg, "%u", stktable_data_cast(ptr, std_t_uint));
4337 break;
4338 case STD_T_ULL:
4339 chunk_appendf(msg, "%llu", stktable_data_cast(ptr, std_t_ull));
4340 break;
4341 case STD_T_FRQP:
4342 chunk_appendf(msg, "%u",
4343 read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
4344 t->data_arg[dt].u));
4345 break;
4346 }
4347 ptr = stktable_data_ptr_idx(t, entry, dt, ++idx);
4348 }
4349 continue;
4350 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004351 if (stktable_data_types[dt].arg_type == ARG_T_DELAY)
Emeric Brun01928ae2021-06-30 16:24:04 +02004352 chunk_appendf(msg, " %s(%u)=", stktable_data_types[dt].name, t->data_arg[dt].u);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004353 else
4354 chunk_appendf(msg, " %s=", stktable_data_types[dt].name);
4355
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004356 ptr = stktable_data_ptr(t, entry, dt);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004357 switch (stktable_data_types[dt].std_type) {
4358 case STD_T_SINT:
4359 chunk_appendf(msg, "%d", stktable_data_cast(ptr, std_t_sint));
4360 break;
4361 case STD_T_UINT:
4362 chunk_appendf(msg, "%u", stktable_data_cast(ptr, std_t_uint));
4363 break;
4364 case STD_T_ULL:
Emeric Brun01928ae2021-06-30 16:24:04 +02004365 chunk_appendf(msg, "%llu", stktable_data_cast(ptr, std_t_ull));
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004366 break;
4367 case STD_T_FRQP:
Emeric Brun01928ae2021-06-30 16:24:04 +02004368 chunk_appendf(msg, "%u",
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004369 read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004370 t->data_arg[dt].u));
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004371 break;
Frédéric Lécaille16b4f542019-05-23 12:15:04 +02004372 case STD_T_DICT: {
4373 struct dict_entry *de;
4374 de = stktable_data_cast(ptr, std_t_dict);
4375 chunk_appendf(msg, "%s", de ? (char *)de->value.key : "-");
4376 break;
4377 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004378 }
4379 }
4380 chunk_appendf(msg, "\n");
4381
Christopher Faulet908628c2022-03-25 16:43:49 +01004382 if (ci_putchk(cs_ic(cs), msg) == -1) {
4383 si_rx_room_blk(cs->si);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004384 return 0;
4385 }
4386
4387 return 1;
4388}
4389
4390
4391/* Processes a single table entry matching a specific key passed in argument.
4392 * returns 0 if wants to be called again, 1 if has ended processing.
4393 */
4394static int table_process_entry_per_key(struct appctx *appctx, char **args)
4395{
Christopher Faulet908628c2022-03-25 16:43:49 +01004396 struct conn_stream *cs = appctx->owner;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004397 struct stktable *t = appctx->ctx.table.target;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004398 struct stksess *ts;
4399 uint32_t uint32_key;
4400 unsigned char ip6_key[sizeof(struct in6_addr)];
4401 long long value;
4402 int data_type;
4403 int cur_arg;
4404 void *ptr;
Willy Tarreaufa1258f2021-04-10 23:00:53 +02004405 struct freq_ctr *frqp;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004406
Willy Tarreau9d008692019-08-09 11:21:01 +02004407 if (!*args[4])
4408 return cli_err(appctx, "Key value expected\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004409
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004410 switch (t->type) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004411 case SMP_T_IPV4:
4412 uint32_key = htonl(inetaddr_host(args[4]));
Christopher Fauletca20d022017-08-29 15:30:31 +02004413 static_table_key.key = &uint32_key;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004414 break;
4415 case SMP_T_IPV6:
Christopher Fauletb7c962b2021-11-15 09:17:25 +01004416 if (inet_pton(AF_INET6, args[4], ip6_key) <= 0)
4417 return cli_err(appctx, "Invalid key\n");
Christopher Fauletca20d022017-08-29 15:30:31 +02004418 static_table_key.key = &ip6_key;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004419 break;
4420 case SMP_T_SINT:
4421 {
4422 char *endptr;
4423 unsigned long val;
4424 errno = 0;
4425 val = strtoul(args[4], &endptr, 10);
4426 if ((errno == ERANGE && val == ULONG_MAX) ||
4427 (errno != 0 && val == 0) || endptr == args[4] ||
Willy Tarreau9d008692019-08-09 11:21:01 +02004428 val > 0xffffffff)
4429 return cli_err(appctx, "Invalid key\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004430 uint32_key = (uint32_t) val;
Christopher Fauletca20d022017-08-29 15:30:31 +02004431 static_table_key.key = &uint32_key;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004432 break;
4433 }
4434 break;
4435 case SMP_T_STR:
Christopher Fauletca20d022017-08-29 15:30:31 +02004436 static_table_key.key = args[4];
4437 static_table_key.key_len = strlen(args[4]);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004438 break;
4439 default:
Willy Tarreaua24bc782016-12-14 15:50:35 +01004440 switch (appctx->ctx.table.action) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004441 case STK_CLI_ACT_SHOW:
Willy Tarreau9d008692019-08-09 11:21:01 +02004442 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 +01004443 case STK_CLI_ACT_CLR:
Willy Tarreau9d008692019-08-09 11:21:01 +02004444 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 +01004445 case STK_CLI_ACT_SET:
Willy Tarreau9d008692019-08-09 11:21:01 +02004446 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 +01004447 default:
Willy Tarreau9d008692019-08-09 11:21:01 +02004448 return cli_err(appctx, "Unknown action\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004449 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004450 }
4451
4452 /* check permissions */
4453 if (!cli_has_level(appctx, ACCESS_LVL_OPER))
4454 return 1;
4455
Willy Tarreaua24bc782016-12-14 15:50:35 +01004456 switch (appctx->ctx.table.action) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004457 case STK_CLI_ACT_SHOW:
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004458 ts = stktable_lookup_key(t, &static_table_key);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004459 if (!ts)
4460 return 1;
4461 chunk_reset(&trash);
Christopher Faulet908628c2022-03-25 16:43:49 +01004462 if (!table_dump_head_to_buffer(&trash, cs, t, t)) {
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004463 stktable_release(t, ts);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004464 return 0;
Emeric Brun819fc6f2017-06-13 19:37:32 +02004465 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004466 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &ts->lock);
Christopher Faulet908628c2022-03-25 16:43:49 +01004467 if (!table_dump_entry_to_buffer(&trash, cs, t, ts)) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004468 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004469 stktable_release(t, ts);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004470 return 0;
Emeric Brun819fc6f2017-06-13 19:37:32 +02004471 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004472 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004473 stktable_release(t, ts);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004474 break;
4475
4476 case STK_CLI_ACT_CLR:
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004477 ts = stktable_lookup_key(t, &static_table_key);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004478 if (!ts)
4479 return 1;
Emeric Brun819fc6f2017-06-13 19:37:32 +02004480
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004481 if (!stksess_kill(t, ts, 1)) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004482 /* don't delete an entry which is currently referenced */
Willy Tarreau9d008692019-08-09 11:21:01 +02004483 return cli_err(appctx, "Entry currently in use, cannot remove\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004484 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004485 break;
4486
4487 case STK_CLI_ACT_SET:
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004488 ts = stktable_get_entry(t, &static_table_key);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004489 if (!ts) {
4490 /* don't delete an entry which is currently referenced */
Willy Tarreau9d008692019-08-09 11:21:01 +02004491 return cli_err(appctx, "Unable to allocate a new entry\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004492 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004493 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004494 for (cur_arg = 5; *args[cur_arg]; cur_arg += 2) {
4495 if (strncmp(args[cur_arg], "data.", 5) != 0) {
Willy Tarreau9d008692019-08-09 11:21:01 +02004496 cli_err(appctx, "\"data.<type>\" followed by a value expected\n");
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004497 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004498 stktable_touch_local(t, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004499 return 1;
4500 }
4501
4502 data_type = stktable_get_data_type(args[cur_arg] + 5);
4503 if (data_type < 0) {
Willy Tarreau9d008692019-08-09 11:21:01 +02004504 cli_err(appctx, "Unknown data type\n");
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004505 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004506 stktable_touch_local(t, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004507 return 1;
4508 }
4509
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004510 if (!t->data_ofs[data_type]) {
Willy Tarreau9d008692019-08-09 11:21:01 +02004511 cli_err(appctx, "Data type not stored in this table\n");
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004512 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004513 stktable_touch_local(t, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004514 return 1;
4515 }
4516
4517 if (!*args[cur_arg+1] || strl2llrc(args[cur_arg+1], strlen(args[cur_arg+1]), &value) != 0) {
Willy Tarreau9d008692019-08-09 11:21:01 +02004518 cli_err(appctx, "Require a valid integer value to store\n");
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004519 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004520 stktable_touch_local(t, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004521 return 1;
4522 }
4523
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004524 ptr = stktable_data_ptr(t, ts, data_type);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004525
4526 switch (stktable_data_types[data_type].std_type) {
4527 case STD_T_SINT:
4528 stktable_data_cast(ptr, std_t_sint) = value;
4529 break;
4530 case STD_T_UINT:
4531 stktable_data_cast(ptr, std_t_uint) = value;
4532 break;
4533 case STD_T_ULL:
4534 stktable_data_cast(ptr, std_t_ull) = value;
4535 break;
4536 case STD_T_FRQP:
4537 /* We set both the current and previous values. That way
4538 * the reported frequency is stable during all the period
4539 * then slowly fades out. This allows external tools to
4540 * push measures without having to update them too often.
4541 */
4542 frqp = &stktable_data_cast(ptr, std_t_frqp);
Willy Tarreaufa1258f2021-04-10 23:00:53 +02004543 /* First bit is reserved for the freq_ctr lock
Emeric Brunf2fc1fd2017-11-02 17:32:43 +01004544 Note: here we're still protected by the stksess lock
Willy Tarreaufa1258f2021-04-10 23:00:53 +02004545 so we don't need to update the update the freq_ctr
Emeric Brunf2fc1fd2017-11-02 17:32:43 +01004546 using its internal lock */
4547 frqp->curr_tick = now_ms & ~0x1;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004548 frqp->prev_ctr = 0;
4549 frqp->curr_ctr = value;
4550 break;
4551 }
4552 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004553 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004554 stktable_touch_local(t, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004555 break;
4556
4557 default:
Willy Tarreau9d008692019-08-09 11:21:01 +02004558 return cli_err(appctx, "Unknown action\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004559 }
4560 return 1;
4561}
4562
4563/* Prepares the appctx fields with the data-based filters from the command line.
4564 * Returns 0 if the dump can proceed, 1 if has ended processing.
4565 */
4566static int table_prepare_data_request(struct appctx *appctx, char **args)
4567{
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004568 int i;
Adis Nezirovicd0142e72020-01-22 16:50:27 +01004569 char *err = NULL;
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004570
Willy Tarreau9d008692019-08-09 11:21:01 +02004571 if (appctx->ctx.table.action != STK_CLI_ACT_SHOW && appctx->ctx.table.action != STK_CLI_ACT_CLR)
4572 return cli_err(appctx, "content-based lookup is only supported with the \"show\" and \"clear\" actions\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004573
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004574 for (i = 0; i < STKTABLE_FILTER_LEN; i++) {
4575 if (i > 0 && !*args[3+3*i]) // number of filter entries can be less than STKTABLE_FILTER_LEN
4576 break;
4577 /* condition on stored data value */
4578 appctx->ctx.table.data_type[i] = stktable_get_data_type(args[3+3*i] + 5);
4579 if (appctx->ctx.table.data_type[i] < 0)
Adis Nezirovicd0142e72020-01-22 16:50:27 +01004580 return cli_dynerr(appctx, memprintf(&err, "Filter entry #%i: Unknown data type\n", i + 1));
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004581
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004582 if (!((struct stktable *)appctx->ctx.table.target)->data_ofs[appctx->ctx.table.data_type[i]])
Adis Nezirovicd0142e72020-01-22 16:50:27 +01004583 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 +01004584
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004585 appctx->ctx.table.data_op[i] = get_std_op(args[4+3*i]);
Willy Tarreau2b64a352020-01-22 17:09:47 +01004586 if (appctx->ctx.table.data_op[i] < 0)
Adis Nezirovicd0142e72020-01-22 16:50:27 +01004587 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 +01004588
Adis Nezirovic56dd3542020-01-22 16:16:48 +01004589 if (!*args[5+3*i] || strl2llrc(args[5+3*i], strlen(args[5+3*i]), &appctx->ctx.table.value[i]) != 0)
Adis Nezirovicd0142e72020-01-22 16:50:27 +01004590 return cli_dynerr(appctx, memprintf(&err, "Filter entry #%i: Require a valid integer value to compare against\n", i + 1));
4591 }
4592
4593 if (*args[3+3*i]) {
4594 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 +01004595 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004596
4597 /* OK we're done, all the fields are set */
4598 return 0;
4599}
4600
4601/* returns 0 if wants to be called, 1 if has ended processing */
Aurélien Nephtaliabbf6072018-04-18 13:26:46 +02004602static int cli_parse_table_req(char **args, char *payload, struct appctx *appctx, void *private)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004603{
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004604 int i;
4605
4606 for (i = 0; i < STKTABLE_FILTER_LEN; i++)
4607 appctx->ctx.table.data_type[i] = -1;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004608 appctx->ctx.table.target = NULL;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004609 appctx->ctx.table.entry = NULL;
Willy Tarreaua24bc782016-12-14 15:50:35 +01004610 appctx->ctx.table.action = (long)private; // keyword argument, one of STK_CLI_ACT_*
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004611
4612 if (*args[2]) {
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004613 appctx->ctx.table.target = stktable_find_by_name(args[2]);
Willy Tarreau9d008692019-08-09 11:21:01 +02004614 if (!appctx->ctx.table.target)
4615 return cli_err(appctx, "No such table\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004616 }
4617 else {
Willy Tarreaua24bc782016-12-14 15:50:35 +01004618 if (appctx->ctx.table.action != STK_CLI_ACT_SHOW)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004619 goto err_args;
4620 return 0;
4621 }
4622
4623 if (strcmp(args[3], "key") == 0)
4624 return table_process_entry_per_key(appctx, args);
4625 else if (strncmp(args[3], "data.", 5) == 0)
4626 return table_prepare_data_request(appctx, args);
4627 else if (*args[3])
4628 goto err_args;
4629
4630 return 0;
4631
4632err_args:
Willy Tarreaua24bc782016-12-14 15:50:35 +01004633 switch (appctx->ctx.table.action) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004634 case STK_CLI_ACT_SHOW:
Willy Tarreau9d008692019-08-09 11:21:01 +02004635 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 +01004636 case STK_CLI_ACT_CLR:
Willy Tarreau9d008692019-08-09 11:21:01 +02004637 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 +01004638 case STK_CLI_ACT_SET:
Willy Tarreau9d008692019-08-09 11:21:01 +02004639 return cli_err(appctx, "Required arguments: <table> key <key> [data.<store_data_type> <value>]*\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004640 default:
Willy Tarreau9d008692019-08-09 11:21:01 +02004641 return cli_err(appctx, "Unknown action\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004642 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004643}
4644
4645/* This function is used to deal with table operations (dump or clear depending
4646 * on the action stored in appctx->private). It returns 0 if the output buffer is
4647 * full and it needs to be called again, otherwise non-zero.
4648 */
4649static int cli_io_handler_table(struct appctx *appctx)
4650{
Christopher Faulet908628c2022-03-25 16:43:49 +01004651 struct conn_stream *cs = appctx->owner;
4652 struct stream *s = __cs_strm(cs);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004653 struct ebmb_node *eb;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004654 int skip_entry;
Willy Tarreaua24bc782016-12-14 15:50:35 +01004655 int show = appctx->ctx.table.action == STK_CLI_ACT_SHOW;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004656
4657 /*
4658 * We have 3 possible states in appctx->st2 :
4659 * - STAT_ST_INIT : the first call
4660 * - STAT_ST_INFO : the proxy pointer points to the next table to
4661 * dump, the entry pointer is NULL ;
4662 * - STAT_ST_LIST : the proxy pointer points to the current table
4663 * and the entry pointer points to the next entry to be dumped,
4664 * and the refcount on the next entry is held ;
4665 * - STAT_ST_END : nothing left to dump, the buffer may contain some
4666 * data though.
4667 */
4668
Christopher Faulet908628c2022-03-25 16:43:49 +01004669 if (unlikely(cs_ic(cs)->flags & (CF_WRITE_ERROR|CF_SHUTW))) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004670 /* in case of abort, remove any refcount we might have set on an entry */
4671 if (appctx->st2 == STAT_ST_LIST) {
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004672 stksess_kill_if_expired(appctx->ctx.table.t, appctx->ctx.table.entry, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004673 }
4674 return 1;
4675 }
4676
4677 chunk_reset(&trash);
4678
4679 while (appctx->st2 != STAT_ST_FIN) {
4680 switch (appctx->st2) {
4681 case STAT_ST_INIT:
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004682 appctx->ctx.table.t = appctx->ctx.table.target;
4683 if (!appctx->ctx.table.t)
4684 appctx->ctx.table.t = stktables_list;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004685
4686 appctx->ctx.table.entry = NULL;
4687 appctx->st2 = STAT_ST_INFO;
4688 break;
4689
4690 case STAT_ST_INFO:
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004691 if (!appctx->ctx.table.t ||
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004692 (appctx->ctx.table.target &&
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004693 appctx->ctx.table.t != appctx->ctx.table.target)) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004694 appctx->st2 = STAT_ST_END;
4695 break;
4696 }
4697
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004698 if (appctx->ctx.table.t->size) {
Christopher Faulet908628c2022-03-25 16:43:49 +01004699 if (show && !table_dump_head_to_buffer(&trash, cs, appctx->ctx.table.t, appctx->ctx.table.target))
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004700 return 0;
4701
4702 if (appctx->ctx.table.target &&
William Lallemand07a62f72017-05-24 00:57:40 +02004703 (strm_li(s)->bind_conf->level & ACCESS_LVL_MASK) >= ACCESS_LVL_OPER) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004704 /* dump entries only if table explicitly requested */
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004705 HA_SPIN_LOCK(STK_TABLE_LOCK, &appctx->ctx.table.t->lock);
4706 eb = ebmb_first(&appctx->ctx.table.t->keys);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004707 if (eb) {
4708 appctx->ctx.table.entry = ebmb_entry(eb, struct stksess, key);
4709 appctx->ctx.table.entry->ref_cnt++;
4710 appctx->st2 = STAT_ST_LIST;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004711 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &appctx->ctx.table.t->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004712 break;
4713 }
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004714 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &appctx->ctx.table.t->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004715 }
4716 }
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004717 appctx->ctx.table.t = appctx->ctx.table.t->next;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004718 break;
4719
4720 case STAT_ST_LIST:
4721 skip_entry = 0;
4722
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004723 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &appctx->ctx.table.entry->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004724
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004725 if (appctx->ctx.table.data_type[0] >= 0) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004726 /* we're filtering on some data contents */
4727 void *ptr;
Willy Tarreau2b64a352020-01-22 17:09:47 +01004728 int dt, i;
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004729 signed char op;
4730 long long data, value;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004731
Emeric Brun819fc6f2017-06-13 19:37:32 +02004732
Willy Tarreau2b64a352020-01-22 17:09:47 +01004733 for (i = 0; i < STKTABLE_FILTER_LEN; i++) {
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004734 if (appctx->ctx.table.data_type[i] == -1)
4735 break;
4736 dt = appctx->ctx.table.data_type[i];
4737 ptr = stktable_data_ptr(appctx->ctx.table.t,
4738 appctx->ctx.table.entry,
4739 dt);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004740
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004741 data = 0;
4742 switch (stktable_data_types[dt].std_type) {
4743 case STD_T_SINT:
4744 data = stktable_data_cast(ptr, std_t_sint);
4745 break;
4746 case STD_T_UINT:
4747 data = stktable_data_cast(ptr, std_t_uint);
4748 break;
4749 case STD_T_ULL:
4750 data = stktable_data_cast(ptr, std_t_ull);
4751 break;
4752 case STD_T_FRQP:
4753 data = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
4754 appctx->ctx.table.t->data_arg[dt].u);
4755 break;
4756 }
4757
4758 op = appctx->ctx.table.data_op[i];
4759 value = appctx->ctx.table.value[i];
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004760
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004761 /* skip the entry if the data does not match the test and the value */
4762 if ((data < value &&
4763 (op == STD_OP_EQ || op == STD_OP_GT || op == STD_OP_GE)) ||
4764 (data == value &&
4765 (op == STD_OP_NE || op == STD_OP_GT || op == STD_OP_LT)) ||
4766 (data > value &&
4767 (op == STD_OP_EQ || op == STD_OP_LT || op == STD_OP_LE))) {
4768 skip_entry = 1;
4769 break;
4770 }
4771 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004772 }
4773
4774 if (show && !skip_entry &&
Christopher Faulet908628c2022-03-25 16:43:49 +01004775 !table_dump_entry_to_buffer(&trash, cs, appctx->ctx.table.t, appctx->ctx.table.entry)) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004776 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &appctx->ctx.table.entry->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004777 return 0;
4778 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004779
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004780 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &appctx->ctx.table.entry->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004781
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004782 HA_SPIN_LOCK(STK_TABLE_LOCK, &appctx->ctx.table.t->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004783 appctx->ctx.table.entry->ref_cnt--;
4784
4785 eb = ebmb_next(&appctx->ctx.table.entry->key);
4786 if (eb) {
4787 struct stksess *old = appctx->ctx.table.entry;
4788 appctx->ctx.table.entry = ebmb_entry(eb, struct stksess, key);
4789 if (show)
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004790 __stksess_kill_if_expired(appctx->ctx.table.t, old);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004791 else if (!skip_entry && !appctx->ctx.table.entry->ref_cnt)
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004792 __stksess_kill(appctx->ctx.table.t, old);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004793 appctx->ctx.table.entry->ref_cnt++;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004794 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &appctx->ctx.table.t->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004795 break;
4796 }
4797
4798
4799 if (show)
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004800 __stksess_kill_if_expired(appctx->ctx.table.t, appctx->ctx.table.entry);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004801 else if (!skip_entry && !appctx->ctx.table.entry->ref_cnt)
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004802 __stksess_kill(appctx->ctx.table.t, appctx->ctx.table.entry);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004803
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004804 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &appctx->ctx.table.t->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004805
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004806 appctx->ctx.table.t = appctx->ctx.table.t->next;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004807 appctx->st2 = STAT_ST_INFO;
4808 break;
4809
4810 case STAT_ST_END:
4811 appctx->st2 = STAT_ST_FIN;
4812 break;
4813 }
4814 }
4815 return 1;
4816}
4817
4818static void cli_release_show_table(struct appctx *appctx)
4819{
4820 if (appctx->st2 == STAT_ST_LIST) {
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004821 stksess_kill_if_expired(appctx->ctx.table.t, appctx->ctx.table.entry, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004822 }
4823}
4824
Willy Tarreau478331d2020-08-28 11:31:31 +02004825static void stkt_late_init(void)
4826{
4827 struct sample_fetch *f;
4828
4829 f = find_sample_fetch("src", strlen("src"));
4830 if (f)
4831 smp_fetch_src = f->process;
4832}
4833
4834INITCALL0(STG_INIT, stkt_late_init);
4835
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004836/* register cli keywords */
4837static struct cli_kw_list cli_kws = {{ },{
Willy Tarreaub205bfd2021-05-07 11:38:37 +02004838 { { "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 },
4839 { { "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 },
4840 { { "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 +01004841 {{},}
4842}};
4843
Willy Tarreau0108d902018-11-25 19:14:37 +01004844INITCALL1(STG_REGISTER, cli_register_kw, &cli_kws);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004845
Thierry FOURNIER236657b2015-08-19 08:25:14 +02004846static struct action_kw_list tcp_conn_kws = { { }, {
Emeric Brun4d7ada82021-06-30 19:04:16 +02004847 { "sc-inc-gpc", parse_inc_gpc, KWF_MATCH_PREFIX },
4848 { "sc-inc-gpc0", parse_inc_gpc, KWF_MATCH_PREFIX },
4849 { "sc-inc-gpc1", parse_inc_gpc, KWF_MATCH_PREFIX },
Emeric Brun877b0b52021-06-30 18:57:49 +02004850 { "sc-set-gpt", parse_set_gpt, KWF_MATCH_PREFIX },
4851 { "sc-set-gpt0", parse_set_gpt, KWF_MATCH_PREFIX },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02004852 { /* END */ }
4853}};
4854
Willy Tarreau0108d902018-11-25 19:14:37 +01004855INITCALL1(STG_REGISTER, tcp_req_conn_keywords_register, &tcp_conn_kws);
4856
Willy Tarreau620408f2016-10-21 16:37:51 +02004857static struct action_kw_list tcp_sess_kws = { { }, {
Emeric Brun4d7ada82021-06-30 19:04:16 +02004858 { "sc-inc-gpc", parse_inc_gpc, KWF_MATCH_PREFIX },
4859 { "sc-inc-gpc0", parse_inc_gpc, KWF_MATCH_PREFIX },
4860 { "sc-inc-gpc1", parse_inc_gpc, KWF_MATCH_PREFIX },
Emeric Brun877b0b52021-06-30 18:57:49 +02004861 { "sc-set-gpt", parse_set_gpt, KWF_MATCH_PREFIX },
4862 { "sc-set-gpt0", parse_set_gpt, KWF_MATCH_PREFIX },
Willy Tarreau620408f2016-10-21 16:37:51 +02004863 { /* END */ }
4864}};
4865
Willy Tarreau0108d902018-11-25 19:14:37 +01004866INITCALL1(STG_REGISTER, tcp_req_sess_keywords_register, &tcp_sess_kws);
4867
Thierry FOURNIER236657b2015-08-19 08:25:14 +02004868static struct action_kw_list tcp_req_kws = { { }, {
Emeric Brun4d7ada82021-06-30 19:04:16 +02004869 { "sc-inc-gpc", parse_inc_gpc, KWF_MATCH_PREFIX },
4870 { "sc-inc-gpc0", parse_inc_gpc, KWF_MATCH_PREFIX },
4871 { "sc-inc-gpc1", parse_inc_gpc, KWF_MATCH_PREFIX },
Emeric Brun877b0b52021-06-30 18:57:49 +02004872 { "sc-set-gpt", parse_set_gpt, KWF_MATCH_PREFIX },
4873 { "sc-set-gpt0", parse_set_gpt, KWF_MATCH_PREFIX },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02004874 { /* END */ }
4875}};
4876
Willy Tarreau0108d902018-11-25 19:14:37 +01004877INITCALL1(STG_REGISTER, tcp_req_cont_keywords_register, &tcp_req_kws);
4878
Thierry FOURNIER236657b2015-08-19 08:25:14 +02004879static struct action_kw_list tcp_res_kws = { { }, {
Emeric Brun4d7ada82021-06-30 19:04:16 +02004880 { "sc-inc-gpc", parse_inc_gpc, KWF_MATCH_PREFIX },
4881 { "sc-inc-gpc0", parse_inc_gpc, KWF_MATCH_PREFIX },
4882 { "sc-inc-gpc1", parse_inc_gpc, KWF_MATCH_PREFIX },
Emeric Brun877b0b52021-06-30 18:57:49 +02004883 { "sc-set-gpt", parse_set_gpt, KWF_MATCH_PREFIX },
4884 { "sc-set-gpt0", parse_set_gpt, KWF_MATCH_PREFIX },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02004885 { /* END */ }
4886}};
4887
Willy Tarreau0108d902018-11-25 19:14:37 +01004888INITCALL1(STG_REGISTER, tcp_res_cont_keywords_register, &tcp_res_kws);
4889
Thierry FOURNIER236657b2015-08-19 08:25:14 +02004890static struct action_kw_list http_req_kws = { { }, {
Emeric Brun4d7ada82021-06-30 19:04:16 +02004891 { "sc-inc-gpc", parse_inc_gpc, KWF_MATCH_PREFIX },
4892 { "sc-inc-gpc0", parse_inc_gpc, KWF_MATCH_PREFIX },
4893 { "sc-inc-gpc1", parse_inc_gpc, KWF_MATCH_PREFIX },
Emeric Brun877b0b52021-06-30 18:57:49 +02004894 { "sc-set-gpt", parse_set_gpt, KWF_MATCH_PREFIX },
4895 { "sc-set-gpt0", parse_set_gpt, KWF_MATCH_PREFIX },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02004896 { /* END */ }
4897}};
4898
Willy Tarreau0108d902018-11-25 19:14:37 +01004899INITCALL1(STG_REGISTER, http_req_keywords_register, &http_req_kws);
4900
Thierry FOURNIER236657b2015-08-19 08:25:14 +02004901static struct action_kw_list http_res_kws = { { }, {
Emeric Brun4d7ada82021-06-30 19:04:16 +02004902 { "sc-inc-gpc", parse_inc_gpc, KWF_MATCH_PREFIX },
4903 { "sc-inc-gpc0", parse_inc_gpc, KWF_MATCH_PREFIX },
4904 { "sc-inc-gpc1", parse_inc_gpc, KWF_MATCH_PREFIX },
Emeric Brun877b0b52021-06-30 18:57:49 +02004905 { "sc-set-gpt", parse_set_gpt, KWF_MATCH_PREFIX },
4906 { "sc-set-gpt0", parse_set_gpt, KWF_MATCH_PREFIX },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02004907 { /* END */ }
4908}};
4909
Willy Tarreau0108d902018-11-25 19:14:37 +01004910INITCALL1(STG_REGISTER, http_res_keywords_register, &http_res_kws);
4911
Willy Tarreau7d562212016-11-25 16:10:05 +01004912/* Note: must not be declared <const> as its list will be overwritten.
4913 * Please take care of keeping this list alphabetically sorted.
4914 */
4915static struct sample_fetch_kw_list smp_fetch_keywords = {ILH, {
4916 { "sc_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4917 { "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 +02004918 { "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 +01004919 { "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 +01004920 { "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 +01004921 { "sc_conn_cnt", smp_fetch_sc_conn_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4922 { "sc_conn_cur", smp_fetch_sc_conn_cur, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4923 { "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 +02004924 { "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 +01004925 { "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 +02004926 { "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 +01004927 { "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 +01004928 { "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 +02004929 { "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 +01004930 { "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 +01004931 { "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 +01004932 { "sc_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4933 { "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 +01004934 { "sc_http_fail_cnt", smp_fetch_sc_http_fail_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4935 { "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 +01004936 { "sc_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4937 { "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 +02004938 { "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 +01004939 { "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 +01004940 { "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 +01004941 { "sc_kbytes_in", smp_fetch_sc_kbytes_in, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4942 { "sc_kbytes_out", smp_fetch_sc_kbytes_out, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4943 { "sc_sess_cnt", smp_fetch_sc_sess_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4944 { "sc_sess_rate", smp_fetch_sc_sess_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4945 { "sc_tracked", smp_fetch_sc_tracked, ARG2(1,SINT,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
4946 { "sc_trackers", smp_fetch_sc_trackers, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4947 { "sc0_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4948 { "sc0_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4949 { "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 +01004950 { "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 +01004951 { "sc0_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4952 { "sc0_conn_cur", smp_fetch_sc_conn_cur, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4953 { "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 +01004954 { "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 +01004955 { "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 +01004956 { "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 +01004957 { "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 +01004958 { "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 +01004959 { "sc0_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4960 { "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 +01004961 { "sc0_http_fail_cnt", smp_fetch_sc_http_fail_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4962 { "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 +01004963 { "sc0_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4964 { "sc0_http_req_rate", smp_fetch_sc_http_req_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4965 { "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 +01004966 { "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 +01004967 { "sc0_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4968 { "sc0_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4969 { "sc0_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4970 { "sc0_sess_rate", smp_fetch_sc_sess_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4971 { "sc0_tracked", smp_fetch_sc_tracked, ARG1(0,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
4972 { "sc0_trackers", smp_fetch_sc_trackers, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4973 { "sc1_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4974 { "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 +02004975 { "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 +01004976 { "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 +01004977 { "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 +01004978 { "sc1_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4979 { "sc1_conn_cur", smp_fetch_sc_conn_cur, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4980 { "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 +01004981 { "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 +01004982 { "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 +01004983 { "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 +01004984 { "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 +01004985 { "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 +01004986 { "sc1_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4987 { "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 +01004988 { "sc1_http_fail_cnt", smp_fetch_sc_http_fail_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4989 { "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 +01004990 { "sc1_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4991 { "sc1_http_req_rate", smp_fetch_sc_http_req_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4992 { "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 +01004993 { "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 +01004994 { "sc1_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4995 { "sc1_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4996 { "sc1_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4997 { "sc1_sess_rate", smp_fetch_sc_sess_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4998 { "sc1_tracked", smp_fetch_sc_tracked, ARG1(0,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
4999 { "sc1_trackers", smp_fetch_sc_trackers, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5000 { "sc2_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5001 { "sc2_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5002 { "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 +01005003 { "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 +01005004 { "sc2_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5005 { "sc2_conn_cur", smp_fetch_sc_conn_cur, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5006 { "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 +01005007 { "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 +01005008 { "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 +01005009 { "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 +01005010 { "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 +01005011 { "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 +01005012 { "sc2_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5013 { "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 +01005014 { "sc2_http_fail_cnt", smp_fetch_sc_http_fail_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5015 { "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 +01005016 { "sc2_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5017 { "sc2_http_req_rate", smp_fetch_sc_http_req_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5018 { "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 +01005019 { "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 +01005020 { "sc2_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5021 { "sc2_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5022 { "sc2_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5023 { "sc2_sess_rate", smp_fetch_sc_sess_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5024 { "sc2_tracked", smp_fetch_sc_tracked, ARG1(0,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
5025 { "sc2_trackers", smp_fetch_sc_trackers, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5026 { "src_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5027 { "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 +02005028 { "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 +01005029 { "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 +01005030 { "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 +01005031 { "src_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5032 { "src_conn_cur", smp_fetch_sc_conn_cur, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5033 { "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 +02005034 { "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 +01005035 { "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 +02005036 { "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 +01005037 { "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 +01005038 { "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 +02005039 { "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 +01005040 { "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 +01005041 { "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 +01005042 { "src_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5043 { "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 +01005044 { "src_http_fail_cnt", smp_fetch_sc_http_fail_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5045 { "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 +01005046 { "src_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5047 { "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 +02005048 { "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 +01005049 { "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 +01005050 { "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 +01005051 { "src_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5052 { "src_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5053 { "src_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5054 { "src_sess_rate", smp_fetch_sc_sess_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5055 { "src_updt_conn_cnt", smp_fetch_src_updt_conn_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5056 { "table_avl", smp_fetch_table_avl, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5057 { "table_cnt", smp_fetch_table_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5058 { /* END */ },
5059}};
5060
Willy Tarreau0108d902018-11-25 19:14:37 +01005061INITCALL1(STG_REGISTER, sample_register_fetches, &smp_fetch_keywords);
Willy Tarreau7d562212016-11-25 16:10:05 +01005062
Willy Tarreaud9f316a2014-07-10 14:03:38 +02005063/* Note: must not be declared <const> as its list will be overwritten */
5064static struct sample_conv_kw_list sample_conv_kws = {ILH, {
Willy Tarreau2d17db52016-05-25 17:16:38 +02005065 { "in_table", sample_conv_in_table, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_BOOL },
5066 { "table_bytes_in_rate", sample_conv_table_bytes_in_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5067 { "table_bytes_out_rate", sample_conv_table_bytes_out_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5068 { "table_conn_cnt", sample_conv_table_conn_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5069 { "table_conn_cur", sample_conv_table_conn_cur, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5070 { "table_conn_rate", sample_conv_table_conn_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
Emeric Brun877b0b52021-06-30 18:57:49 +02005071 { "table_gpt", sample_conv_table_gpt, ARG2(2,SINT,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
Willy Tarreau2d17db52016-05-25 17:16:38 +02005072 { "table_gpt0", sample_conv_table_gpt0, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
Emeric Brun4d7ada82021-06-30 19:04:16 +02005073 { "table_gpc", sample_conv_table_gpc, ARG2(2,SINT,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
Willy Tarreau2d17db52016-05-25 17:16:38 +02005074 { "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 +01005075 { "table_gpc1", sample_conv_table_gpc1, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
Emeric Brun4d7ada82021-06-30 19:04:16 +02005076 { "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 +02005077 { "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 +01005078 { "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 +02005079 { "table_http_err_cnt", sample_conv_table_http_err_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5080 { "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 +01005081 { "table_http_fail_cnt", sample_conv_table_http_fail_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5082 { "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 +02005083 { "table_http_req_cnt", sample_conv_table_http_req_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5084 { "table_http_req_rate", sample_conv_table_http_req_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5085 { "table_kbytes_in", sample_conv_table_kbytes_in, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5086 { "table_kbytes_out", sample_conv_table_kbytes_out, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5087 { "table_server_id", sample_conv_table_server_id, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5088 { "table_sess_cnt", sample_conv_table_sess_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5089 { "table_sess_rate", sample_conv_table_sess_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5090 { "table_trackers", sample_conv_table_trackers, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
Willy Tarreaud9f316a2014-07-10 14:03:38 +02005091 { /* END */ },
5092}};
5093
Willy Tarreau0108d902018-11-25 19:14:37 +01005094INITCALL1(STG_REGISTER, sample_register_convs, &sample_conv_kws);