blob: c6fe243e8bb7e169ef4d1b7307b664052c83948f [file] [log] [blame]
Emeric Brun3bd697e2010-01-04 15:23:48 +01001/*
2 * Stick tables management functions.
3 *
4 * Copyright 2009-2010 EXCELIANCE, Emeric Brun <ebrun@exceliance.fr>
Willy Tarreau08d5f982010-06-06 13:34:54 +02005 * Copyright (C) 2010 Willy Tarreau <w@1wt.eu>
Emeric Brun3bd697e2010-01-04 15:23:48 +01006 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version
10 * 2 of the License, or (at your option) any later version.
11 *
12 */
13
14#include <string.h>
Willy Tarreauf13ebdf2016-11-22 18:00:53 +010015#include <errno.h>
Emeric Brun3bd697e2010-01-04 15:23:48 +010016
Willy Tarreaub2551052020-06-09 09:07:15 +020017#include <import/ebmbtree.h>
18#include <import/ebsttree.h>
19#include <import/ebistree.h>
20
Willy Tarreau4c7e4b72020-05-27 12:58:42 +020021#include <haproxy/api.h>
Willy Tarreau3c69e082022-05-03 11:35:07 +020022#include <haproxy/applet.h>
Willy Tarreaub2551052020-06-09 09:07:15 +020023#include <haproxy/arg.h>
Willy Tarreau6be78492020-06-05 00:00:29 +020024#include <haproxy/cfgparse.h>
Willy Tarreau83487a82020-06-04 20:19:54 +020025#include <haproxy/cli.h>
Thayne McCombs92149f92020-11-20 01:28:26 -070026#include <haproxy/dict.h>
Willy Tarreau36979d92020-06-05 17:27:29 +020027#include <haproxy/errors.h>
Willy Tarreauf268ee82020-06-04 17:05:57 +020028#include <haproxy/global.h>
Willy Tarreauc761f842020-06-04 11:40:28 +020029#include <haproxy/http_rules.h>
Willy Tarreau853b2972020-05-27 18:01:47 +020030#include <haproxy/list.h>
Willy Tarreauaeed4a82020-06-04 22:01:04 +020031#include <haproxy/log.h>
Willy Tarreau6131d6a2020-06-02 16:48:09 +020032#include <haproxy/net_helper.h>
Willy Tarreau3c2a7c22020-06-04 18:38:21 +020033#include <haproxy/peers.h>
Willy Tarreaub2551052020-06-09 09:07:15 +020034#include <haproxy/pool.h>
35#include <haproxy/proto_tcp.h>
Willy Tarreaua264d962020-06-04 22:29:18 +020036#include <haproxy/proxy.h>
Willy Tarreaub2551052020-06-09 09:07:15 +020037#include <haproxy/sample.h>
Willy Tarreau5edca2f2022-05-27 09:25:10 +020038#include <haproxy/sc_strm.h>
Willy Tarreau2eec9b52020-06-04 19:58:55 +020039#include <haproxy/stats-t.h>
Willy Tarreaucb086c62022-05-27 09:47:12 +020040#include <haproxy/stconn.h>
Willy Tarreaub2551052020-06-09 09:07:15 +020041#include <haproxy/stick_table.h>
Willy Tarreaudfd3de82020-06-04 23:46:14 +020042#include <haproxy/stream.h>
Willy Tarreaucea0e1b2020-06-04 17:25:40 +020043#include <haproxy/task.h>
Willy Tarreau8b550af2020-06-04 17:42:48 +020044#include <haproxy/tcp_rules.h>
Willy Tarreau9310f482021-10-06 16:18:40 +020045#include <haproxy/ticks.h>
Willy Tarreaub2551052020-06-09 09:07:15 +020046#include <haproxy/tools.h>
Emeric Brun3bd697e2010-01-04 15:23:48 +010047
Emeric Brun3bd697e2010-01-04 15:23:48 +010048
Willy Tarreau12785782012-04-27 21:37:17 +020049/* structure used to return a table key built from a sample */
Emeric Brun819fc6f2017-06-13 19:37:32 +020050static THREAD_LOCAL struct stktable_key static_table_key;
Willy Tarreau478331d2020-08-28 11:31:31 +020051static int (*smp_fetch_src)(const struct arg *, struct sample *, const char *, void *);
Willy Tarreauf0b38bf2010-06-06 13:22:23 +020052
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +010053struct stktable *stktables_list;
54struct eb_root stktable_by_name = EB_ROOT;
55
Olivier Houchard52dabbc2018-11-14 17:54:36 +010056#define round_ptr_size(i) (((i) + (sizeof(void *) - 1)) &~ (sizeof(void *) - 1))
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +010057
58/* This function inserts stktable <t> into the tree of known stick-table.
59 * The stick-table ID is used as the storing key so it must already have
60 * been initialized.
61 */
62void stktable_store_name(struct stktable *t)
63{
64 t->name.key = t->id;
65 ebis_insert(&stktable_by_name, &t->name);
66}
67
68struct stktable *stktable_find_by_name(const char *name)
69{
70 struct ebpt_node *node;
71 struct stktable *t;
72
73 node = ebis_lookup(&stktable_by_name, name);
74 if (node) {
75 t = container_of(node, struct stktable, name);
Tim Duesterhuse5ff1412021-01-02 22:31:53 +010076 if (strcmp(t->id, name) == 0)
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +010077 return t;
78 }
79
80 return NULL;
81}
82
Emeric Brun3bd697e2010-01-04 15:23:48 +010083/*
Willy Tarreauaea940e2010-06-06 11:56:36 +020084 * Free an allocated sticky session <ts>, and decrease sticky sessions counter
Willy Tarreau996f1a52022-10-11 16:19:35 +020085 * in table <t>. It's safe to call it under or out of a lock.
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{
Willy Tarreau996f1a52022-10-11 16:19:35 +020089 HA_ATOMIC_DEC(&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 }
Willy Tarreau8d3c3332022-10-11 18:50:22 +0000106 HA_RWLOCK_RDLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200107 __stksess_free(t, ts);
Willy Tarreau8d3c3332022-10-11 18:50:22 +0000108 HA_RWLOCK_RDUNLOCK(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
Willy Tarreau76642222022-10-11 12:02:50 +0200135 HA_RWLOCK_WRLOCK(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);
Willy Tarreau76642222022-10-11 12:02:50 +0200139 HA_RWLOCK_WRUNLOCK(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
Willy Tarreau76642222022-10-11 12:02:50 +0200252 HA_RWLOCK_WRLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200253 ret = __stktable_trash_oldest(t, to_batch);
Willy Tarreau76642222022-10-11 12:02:50 +0200254 HA_RWLOCK_WRUNLOCK(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>
Willy Tarreau996f1a52022-10-11 16:19:35 +0200263 * is not NULL, it is assigned to the new session. It must be called unlocked
264 * as it may rely on a lock to trash older entries.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100265 */
Willy Tarreau996f1a52022-10-11 16:19:35 +0200266struct stksess *stksess_new(struct stktable *t, struct stktable_key *key)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100267{
268 struct stksess *ts;
Willy Tarreau996f1a52022-10-11 16:19:35 +0200269 unsigned int current;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100270
Willy Tarreau996f1a52022-10-11 16:19:35 +0200271 current = HA_ATOMIC_FETCH_ADD(&t->current, 1);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100272
Willy Tarreau996f1a52022-10-11 16:19:35 +0200273 if (unlikely(current >= t->size)) {
274 /* the table was already full, we may have to purge entries */
275 if (t->nopurge || !stktable_trash_oldest(t, (t->size >> 8) + 1)) {
276 HA_ATOMIC_DEC(&t->current);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100277 return NULL;
Willy Tarreau996f1a52022-10-11 16:19:35 +0200278 }
Emeric Brun3bd697e2010-01-04 15:23:48 +0100279 }
280
Willy Tarreaubafbe012017-11-24 17:34:44 +0100281 ts = pool_alloc(t->pool);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100282 if (ts) {
Olivier Houchard52dabbc2018-11-14 17:54:36 +0100283 ts = (void *)ts + round_ptr_size(t->data_size);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200284 __stksess_init(t, ts);
Willy Tarreaua7b46b52013-04-11 16:55:37 +0200285 if (key)
286 stksess_setkey(t, ts, key);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100287 }
288
289 return ts;
290}
291
292/*
Willy Tarreauf16d2b82010-06-06 15:38:59 +0200293 * Looks in table <t> for a sticky session matching key <key>.
Willy Tarreauaea940e2010-06-06 11:56:36 +0200294 * Returns pointer on requested sticky session or NULL if none was found.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100295 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200296struct stksess *__stktable_lookup_key(struct stktable *t, struct stktable_key *key)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100297{
298 struct ebmb_node *eb;
299
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200300 if (t->type == SMP_T_STR)
Emeric Brun485479d2010-09-23 18:02:19 +0200301 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 +0100302 else
303 eb = ebmb_lookup(&t->keys, key->key, t->key_size);
304
305 if (unlikely(!eb)) {
306 /* no session found */
307 return NULL;
308 }
309
Willy Tarreau86257dc2010-06-06 12:57:10 +0200310 return ebmb_entry(eb, struct stksess, key);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100311}
312
Emeric Brun819fc6f2017-06-13 19:37:32 +0200313/*
314 * Looks in table <t> for a sticky session matching key <key>.
315 * Returns pointer on requested sticky session or NULL if none was found.
316 * The refcount of the found entry is increased and this function
317 * is protected using the table lock
Willy Tarreau1f7e9252010-06-20 12:27:21 +0200318 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200319struct stksess *stktable_lookup_key(struct stktable *t, struct stktable_key *key)
Willy Tarreau1f7e9252010-06-20 12:27:21 +0200320{
321 struct stksess *ts;
322
Willy Tarreaua7d6a132022-10-11 15:42:54 +0200323 HA_RWLOCK_RDLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200324 ts = __stktable_lookup_key(t, key);
325 if (ts)
Willy Tarreaua7d6a132022-10-11 15:42:54 +0200326 HA_ATOMIC_INC(&ts->ref_cnt);
327 HA_RWLOCK_RDUNLOCK(STK_TABLE_LOCK, &t->lock);
Willy Tarreau1f7e9252010-06-20 12:27:21 +0200328
Willy Tarreau1f7e9252010-06-20 12:27:21 +0200329 return ts;
330}
331
Willy Tarreauf16d2b82010-06-06 15:38:59 +0200332/*
333 * Looks in table <t> for a sticky session with same key as <ts>.
334 * Returns pointer on requested sticky session or NULL if none was found.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100335 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200336struct stksess *__stktable_lookup(struct stktable *t, struct stksess *ts)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100337{
Emeric Brun3bd697e2010-01-04 15:23:48 +0100338 struct ebmb_node *eb;
339
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200340 if (t->type == SMP_T_STR)
Willy Tarreau86257dc2010-06-06 12:57:10 +0200341 eb = ebst_lookup(&(t->keys), (char *)ts->key.key);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100342 else
Willy Tarreau86257dc2010-06-06 12:57:10 +0200343 eb = ebmb_lookup(&(t->keys), ts->key.key, t->key_size);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100344
Willy Tarreauf16d2b82010-06-06 15:38:59 +0200345 if (unlikely(!eb))
346 return NULL;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100347
Willy Tarreauf16d2b82010-06-06 15:38:59 +0200348 return ebmb_entry(eb, struct stksess, key);
349}
Emeric Brun3bd697e2010-01-04 15:23:48 +0100350
Emeric Brun819fc6f2017-06-13 19:37:32 +0200351/*
352 * Looks in table <t> for a sticky session with same key as <ts>.
353 * Returns pointer on requested sticky session or NULL if none was found.
354 * The refcount of the found entry is increased and this function
355 * is protected using the table lock
356 */
357struct stksess *stktable_lookup(struct stktable *t, struct stksess *ts)
358{
359 struct stksess *lts;
360
Willy Tarreaua7d6a132022-10-11 15:42:54 +0200361 HA_RWLOCK_RDLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200362 lts = __stktable_lookup(t, ts);
363 if (lts)
Willy Tarreaua7d6a132022-10-11 15:42:54 +0200364 HA_ATOMIC_INC(&lts->ref_cnt);
365 HA_RWLOCK_RDUNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200366
367 return lts;
368}
369
Willy Tarreaucb183642010-06-06 17:58:34 +0200370/* Update the expiration timer for <ts> but do not touch its expiration node.
371 * The table's expiration timer is updated if set.
Emeric Brun819fc6f2017-06-13 19:37:32 +0200372 * The node will be also inserted into the update tree if needed, at a position
Willy Tarreau9f5cb432022-10-11 18:17:58 +0000373 * depending if the update is a local or coming from a remote node.
374 * If <decrefcnt> is set, the ts entry's ref_cnt will be decremented. The table's
375 * write lock may be taken.
Willy Tarreaucb183642010-06-06 17:58:34 +0200376 */
Willy Tarreau9f5cb432022-10-11 18:17:58 +0000377void stktable_touch_with_exp(struct stktable *t, struct stksess *ts, int local, int expire, int decrefcnt)
Willy Tarreaucb183642010-06-06 17:58:34 +0200378{
Emeric Brun85e77c72010-09-23 18:16:52 +0200379 struct eb32_node * eb;
Willy Tarreaua7536ef2022-10-11 18:31:04 +0000380 int locked = 0;
Willy Tarreau9f5cb432022-10-11 18:17:58 +0000381
Willy Tarreaua7536ef2022-10-11 18:31:04 +0000382 if (expire != HA_ATOMIC_LOAD(&ts->expire)) {
383 /* we'll need to set the expiration and to wake up the expiration timer .*/
384 HA_ATOMIC_STORE(&ts->expire, expire);
Willy Tarreaudbae89e2022-10-12 10:00:50 +0000385 stktable_requeue_exp(t, ts);
Willy Tarreaucb183642010-06-06 17:58:34 +0200386 }
Emeric Brun85e77c72010-09-23 18:16:52 +0200387
Emeric Brun819fc6f2017-06-13 19:37:32 +0200388 /* If sync is enabled */
389 if (t->sync_task) {
390 if (local) {
391 /* If this entry is not in the tree
Willy Tarreaua7536ef2022-10-11 18:31:04 +0000392 * or not scheduled for at least one peer.
393 */
394 if (!locked++)
395 HA_RWLOCK_WRLOCK(STK_TABLE_LOCK, &t->lock);
396
Emeric Brun819fc6f2017-06-13 19:37:32 +0200397 if (!ts->upd.node.leaf_p
398 || (int)(t->commitupdate - ts->upd.key) >= 0
399 || (int)(ts->upd.key - t->localupdate) >= 0) {
400 ts->upd.key = ++t->update;
401 t->localupdate = t->update;
402 eb32_delete(&ts->upd);
403 eb = eb32_insert(&t->updates, &ts->upd);
404 if (eb != &ts->upd) {
405 eb32_delete(eb);
406 eb32_insert(&t->updates, &ts->upd);
407 }
Emeric Brunaaf58602015-06-15 17:23:30 +0200408 }
Emeric Brun819fc6f2017-06-13 19:37:32 +0200409 task_wakeup(t->sync_task, TASK_WOKEN_MSG);
Emeric Brun85e77c72010-09-23 18:16:52 +0200410 }
Emeric Brun819fc6f2017-06-13 19:37:32 +0200411 else {
412 /* If this entry is not in the tree */
Willy Tarreaua7536ef2022-10-11 18:31:04 +0000413 if (!locked++)
414 HA_RWLOCK_WRLOCK(STK_TABLE_LOCK, &t->lock);
415
Emeric Brun819fc6f2017-06-13 19:37:32 +0200416 if (!ts->upd.node.leaf_p) {
417 ts->upd.key= (++t->update)+(2147483648U);
418 eb = eb32_insert(&t->updates, &ts->upd);
419 if (eb != &ts->upd) {
420 eb32_delete(eb);
421 eb32_insert(&t->updates, &ts->upd);
422 }
423 }
424 }
Emeric Brun85e77c72010-09-23 18:16:52 +0200425 }
Willy Tarreau9f5cb432022-10-11 18:17:58 +0000426
Willy Tarreaua7536ef2022-10-11 18:31:04 +0000427 if (decrefcnt) {
428 if (locked)
429 ts->ref_cnt--;
430 else {
431 HA_RWLOCK_RDLOCK(STK_TABLE_LOCK, &t->lock);
432 HA_ATOMIC_DEC(&ts->ref_cnt);
433 HA_RWLOCK_RDUNLOCK(STK_TABLE_LOCK, &t->lock);
434 }
435 }
436
437 if (locked)
438 HA_RWLOCK_WRUNLOCK(STK_TABLE_LOCK, &t->lock);
Willy Tarreaucb183642010-06-06 17:58:34 +0200439}
440
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200441/* Update the expiration timer for <ts> but do not touch its expiration node.
Emeric Brun819fc6f2017-06-13 19:37:32 +0200442 * The table's expiration timer is updated using the date of expiration coming from
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200443 * <t> stick-table configuration.
Emeric Brun819fc6f2017-06-13 19:37:32 +0200444 * The node will be also inserted into the update tree if needed, at a position
445 * considering the update is coming from a remote node
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200446 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200447void stktable_touch_remote(struct stktable *t, struct stksess *ts, int decrefcnt)
448{
Willy Tarreau9f5cb432022-10-11 18:17:58 +0000449 stktable_touch_with_exp(t, ts, 0, ts->expire, decrefcnt);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200450}
451
452/* Update the expiration timer for <ts> but do not touch its expiration node.
453 * The table's expiration timer is updated using the date of expiration coming from
454 * <t> stick-table configuration.
455 * The node will be also inserted into the update tree if needed, at a position
456 * considering the update was made locally
457 */
458void stktable_touch_local(struct stktable *t, struct stksess *ts, int decrefcnt)
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200459{
460 int expire = tick_add(now_ms, MS_TO_TICKS(t->expire));
461
Willy Tarreau9f5cb432022-10-11 18:17:58 +0000462 stktable_touch_with_exp(t, ts, 1, expire, decrefcnt);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200463}
Willy Tarreau4be073b2022-10-11 18:10:27 +0000464/* Just decrease the ref_cnt of the current session. Does nothing if <ts> is NULL.
465 * Note that we still need to take the read lock because a number of other places
466 * (including in Lua and peers) update the ref_cnt non-atomically under the write
467 * lock.
468 */
Willy Tarreau43e90352018-06-27 06:25:57 +0200469static void stktable_release(struct stktable *t, struct stksess *ts)
Emeric Brun819fc6f2017-06-13 19:37:32 +0200470{
Willy Tarreau43e90352018-06-27 06:25:57 +0200471 if (!ts)
472 return;
Willy Tarreau4be073b2022-10-11 18:10:27 +0000473 HA_RWLOCK_RDLOCK(STK_TABLE_LOCK, &t->lock);
474 HA_ATOMIC_DEC(&ts->ref_cnt);
475 HA_RWLOCK_RDUNLOCK(STK_TABLE_LOCK, &t->lock);
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200476}
477
Willy Tarreauf16d2b82010-06-06 15:38:59 +0200478/* Insert new sticky session <ts> in the table. It is assumed that it does not
479 * yet exist (the caller must check this). The table's timeout is updated if it
Willy Tarreaud2d3fd92022-10-11 15:09:46 +0200480 * is set. <ts> is returned if properly inserted, otherwise the one already
481 * present if any.
Willy Tarreauf16d2b82010-06-06 15:38:59 +0200482 */
Willy Tarreaud2d3fd92022-10-11 15:09:46 +0200483struct stksess *__stktable_store(struct stktable *t, struct stksess *ts)
Willy Tarreauf16d2b82010-06-06 15:38:59 +0200484{
Willy Tarreaud2d3fd92022-10-11 15:09:46 +0200485 struct ebmb_node *eb;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100486
Willy Tarreaud2d3fd92022-10-11 15:09:46 +0200487 eb = ebmb_insert(&t->keys, &ts->key, t->key_size);
488 if (likely(eb == &ts->key)) {
489 ts->exp.key = ts->expire;
490 eb32_insert(&t->exps, &ts->exp);
491 }
Willy Tarreaud2d3fd92022-10-11 15:09:46 +0200492 return ebmb_entry(eb, struct stksess, key); // most commonly this is <ts>
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200493}
494
Willy Tarreaueb23e3e2022-10-12 09:56:08 +0000495/* requeues the table's expiration task to take the recently added <ts> into
496 * account. This is performed atomically and doesn't require any lock.
497 */
Willy Tarreaudbae89e2022-10-12 10:00:50 +0000498void stktable_requeue_exp(struct stktable *t, const struct stksess *ts)
Willy Tarreaueb23e3e2022-10-12 09:56:08 +0000499{
Willy Tarreaudbae89e2022-10-12 10:00:50 +0000500 int old_exp, new_exp;
501 int expire = ts->expire;
502
Willy Tarreaueb23e3e2022-10-12 09:56:08 +0000503 if (!t->expire)
504 return;
Willy Tarreaudbae89e2022-10-12 10:00:50 +0000505
506 /* set both t->exp_next and the task's expire to the newest
507 * expiration date.
508 */
509 old_exp = HA_ATOMIC_LOAD(&t->exp_next);
510 do {
511 new_exp = tick_first(expire, old_exp);
512 } while (new_exp != old_exp &&
513 !HA_ATOMIC_CAS(&t->exp_next, &old_exp, new_exp) &&
514 __ha_cpu_relax());
515
516 old_exp = HA_ATOMIC_LOAD(&t->exp_task->expire);
517 do {
518 new_exp = HA_ATOMIC_LOAD(&t->exp_next);
519 } while (new_exp != old_exp &&
520 !HA_ATOMIC_CAS(&t->exp_task->expire, &old_exp, new_exp) &&
521 __ha_cpu_relax());
522
Willy Tarreaueb23e3e2022-10-12 09:56:08 +0000523 task_queue(t->exp_task);
524}
525
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200526/* Returns a valid or initialized stksess for the specified stktable_key in the
527 * specified table, or NULL if the key was NULL, or if no entry was found nor
Willy Tarreau47f22972022-10-11 15:22:42 +0200528 * could be created. The entry's expiration is updated. This function locks the
529 * table, and the refcount of the entry is increased.
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200530 */
Willy Tarreau47f22972022-10-11 15:22:42 +0200531struct stksess *stktable_get_entry(struct stktable *table, struct stktable_key *key)
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200532{
Willy Tarreau175aa062022-10-11 15:13:46 +0200533 struct stksess *ts, *ts2;
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200534
535 if (!key)
536 return NULL;
537
Willy Tarreau47f22972022-10-11 15:22:42 +0200538 ts = stktable_lookup_key(table, key);
539 if (ts)
540 return ts;
Emeric Brun819fc6f2017-06-13 19:37:32 +0200541
Willy Tarreau996f1a52022-10-11 16:19:35 +0200542 /* No such entry exists, let's try to create a new one. this doesn't
543 * require locking yet.
544 */
545
546 ts = stksess_new(table, key);
547 if (!ts)
548 return NULL;
549
550 /* Now we're certain to have a ts. We need to store it. For this we'll
Willy Tarreau47f22972022-10-11 15:22:42 +0200551 * need an exclusive access. We don't need an atomic upgrade, this is
552 * rare and an unlock+lock sequence will do the job fine. Given that
553 * this will not be atomic, the missing entry might appear in the mean
554 * tome so we have to be careful that the one we try to insert is the
555 * one we find.
556 */
Willy Tarreau47f22972022-10-11 15:22:42 +0200557
Willy Tarreau996f1a52022-10-11 16:19:35 +0200558 HA_RWLOCK_WRLOCK(STK_TABLE_LOCK, &table->lock);
Willy Tarreau47f22972022-10-11 15:22:42 +0200559
560 ts2 = __stktable_store(table, ts);
561 if (unlikely(ts2 != ts)) {
562 /* another entry was added in the mean time, let's
563 * switch to it.
564 */
565 __stksess_free(table, ts);
566 ts = ts2;
567 }
568
569 HA_ATOMIC_INC(&ts->ref_cnt);
Willy Tarreau76642222022-10-11 12:02:50 +0200570 HA_RWLOCK_WRUNLOCK(STK_TABLE_LOCK, &table->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200571
Willy Tarreaucbdb5282022-10-12 10:04:01 +0000572 stktable_requeue_exp(table, ts);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200573 return ts;
574}
575
576/* Lookup for an entry with the same key and store the submitted
Willy Tarreaue6288522022-10-12 09:13:14 +0000577 * stksess if not found. This function locks the table either shared or
578 * exclusively, and the refcount of the entry is increased.
Emeric Brun819fc6f2017-06-13 19:37:32 +0200579 */
Willy Tarreaue6288522022-10-12 09:13:14 +0000580struct stksess *stktable_set_entry(struct stktable *table, struct stksess *nts)
Emeric Brun819fc6f2017-06-13 19:37:32 +0200581{
582 struct stksess *ts;
583
Willy Tarreaue6288522022-10-12 09:13:14 +0000584 HA_RWLOCK_RDLOCK(STK_TABLE_LOCK, &table->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200585 ts = __stktable_lookup(table, nts);
Willy Tarreaue6288522022-10-12 09:13:14 +0000586 if (ts) {
587 HA_ATOMIC_INC(&ts->ref_cnt);
588 HA_RWLOCK_RDUNLOCK(STK_TABLE_LOCK, &table->lock);
589 return ts;
Emeric Brun819fc6f2017-06-13 19:37:32 +0200590 }
Willy Tarreaue6288522022-10-12 09:13:14 +0000591 ts = nts;
Emeric Brun819fc6f2017-06-13 19:37:32 +0200592
Willy Tarreaue6288522022-10-12 09:13:14 +0000593 /* let's increment it before switching to exclusive */
594 HA_ATOMIC_INC(&ts->ref_cnt);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200595
Willy Tarreaue6288522022-10-12 09:13:14 +0000596 if (HA_RWLOCK_TRYRDTOSK(STK_TABLE_LOCK, &table->lock) != 0) {
597 /* upgrade to seek lock failed, let's drop and take */
598 HA_RWLOCK_RDUNLOCK(STK_TABLE_LOCK, &table->lock);
599 HA_RWLOCK_WRLOCK(STK_TABLE_LOCK, &table->lock);
600 }
601 else
602 HA_RWLOCK_SKTOWR(STK_TABLE_LOCK, &table->lock);
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200603
Willy Tarreaue6288522022-10-12 09:13:14 +0000604 /* now we're write-locked */
605
606 __stktable_store(table, ts);
607 HA_RWLOCK_WRUNLOCK(STK_TABLE_LOCK, &table->lock);
Willy Tarreaucbdb5282022-10-12 10:04:01 +0000608
609 stktable_requeue_exp(table, ts);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200610 return ts;
611}
Willy Tarreaue6288522022-10-12 09:13:14 +0000612
Emeric Brun3bd697e2010-01-04 15:23:48 +0100613/*
Willy Tarreauaea940e2010-06-06 11:56:36 +0200614 * Trash expired sticky sessions from table <t>. The next expiration date is
615 * returned.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100616 */
617static int stktable_trash_expired(struct stktable *t)
618{
619 struct stksess *ts;
620 struct eb32_node *eb;
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200621 int looped = 0;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100622
Willy Tarreau76642222022-10-11 12:02:50 +0200623 HA_RWLOCK_WRLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100624 eb = eb32_lookup_ge(&t->exps, now_ms - TIMER_LOOK_BACK);
625
626 while (1) {
627 if (unlikely(!eb)) {
628 /* we might have reached the end of the tree, typically because
629 * <now_ms> is in the first half and we're first scanning the last
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200630 * half. Let's loop back to the beginning of the tree now if we
631 * have not yet visited it.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100632 */
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200633 if (looped)
634 break;
635 looped = 1;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100636 eb = eb32_first(&t->exps);
637 if (likely(!eb))
638 break;
639 }
640
641 if (likely(tick_is_lt(now_ms, eb->key))) {
642 /* timer not expired yet, revisit it later */
643 t->exp_next = eb->key;
Willy Tarreau4d5f13c2017-11-05 11:04:47 +0100644 goto out_unlock;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100645 }
646
647 /* timer looks expired, detach it from the queue */
Willy Tarreau86257dc2010-06-06 12:57:10 +0200648 ts = eb32_entry(eb, struct stksess, exp);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100649 eb = eb32_next(eb);
650
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200651 /* don't delete an entry which is currently referenced */
652 if (ts->ref_cnt)
653 continue;
654
Willy Tarreau86257dc2010-06-06 12:57:10 +0200655 eb32_delete(&ts->exp);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100656
657 if (!tick_is_expired(ts->expire, now_ms)) {
658 if (!tick_isset(ts->expire))
659 continue;
660
Willy Tarreau86257dc2010-06-06 12:57:10 +0200661 ts->exp.key = ts->expire;
662 eb32_insert(&t->exps, &ts->exp);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100663
Willy Tarreau86257dc2010-06-06 12:57:10 +0200664 if (!eb || eb->key > ts->exp.key)
665 eb = &ts->exp;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100666 continue;
667 }
668
669 /* session expired, trash it */
Willy Tarreau86257dc2010-06-06 12:57:10 +0200670 ebmb_delete(&ts->key);
Emeric Brun85e77c72010-09-23 18:16:52 +0200671 eb32_delete(&ts->upd);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200672 __stksess_free(t, ts);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100673 }
674
675 /* We have found no task to expire in any tree */
676 t->exp_next = TICK_ETERNITY;
Willy Tarreau4d5f13c2017-11-05 11:04:47 +0100677out_unlock:
Willy Tarreau76642222022-10-11 12:02:50 +0200678 HA_RWLOCK_WRUNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100679 return t->exp_next;
680}
681
682/*
Willy Tarreauaea940e2010-06-06 11:56:36 +0200683 * Task processing function to trash expired sticky sessions. A pointer to the
684 * task itself is returned since it never dies.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100685 */
Willy Tarreau144f84a2021-03-02 16:09:26 +0100686struct task *process_table_expire(struct task *task, void *context, unsigned int state)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100687{
Olivier Houchard9f6af332018-05-25 14:04:04 +0200688 struct stktable *t = context;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100689
690 task->expire = stktable_trash_expired(t);
691 return task;
692}
693
Willy Tarreauaea940e2010-06-06 11:56:36 +0200694/* Perform minimal stick table intializations, report 0 in case of error, 1 if OK. */
Emeric Brun3bd697e2010-01-04 15:23:48 +0100695int stktable_init(struct stktable *t)
696{
Remi Tricot-Le Breton208ff012021-05-12 17:39:04 +0200697 int peers_retval = 0;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100698 if (t->size) {
Emeric Brun819fc6f2017-06-13 19:37:32 +0200699 t->keys = EB_ROOT_UNIQUE;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100700 memset(&t->exps, 0, sizeof(t->exps));
Emeric Brun1c6235d2015-12-16 15:28:12 +0100701 t->updates = EB_ROOT_UNIQUE;
Amaury Denoyelle3e064882022-10-12 16:47:59 +0200702 HA_RWLOCK_INIT(&t->lock);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100703
Olivier Houchard52dabbc2018-11-14 17:54:36 +0100704 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 +0100705
706 t->exp_next = TICK_ETERNITY;
707 if ( t->expire ) {
Willy Tarreaubeeabf52021-10-01 18:23:30 +0200708 t->exp_task = task_new_anywhere();
Willy Tarreau848522f2018-10-15 11:12:15 +0200709 if (!t->exp_task)
710 return 0;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100711 t->exp_task->process = process_table_expire;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100712 t->exp_task->context = (void *)t;
713 }
Christopher Fauletdfd10ab2021-10-06 14:24:19 +0200714 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 +0200715 peers_retval = peers_register_table(t->peers.p, t);
Emeric Brun32da3c42010-09-23 18:39:19 +0200716 }
717
Remi Tricot-Le Breton208ff012021-05-12 17:39:04 +0200718 return (t->pool != NULL) && !peers_retval;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100719 }
720 return 1;
721}
722
723/*
724 * Configuration keywords of known table types
725 */
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200726struct stktable_type stktable_types[SMP_TYPES] = {
727 [SMP_T_SINT] = { "integer", 0, 4 },
728 [SMP_T_IPV4] = { "ip", 0, 4 },
729 [SMP_T_IPV6] = { "ipv6", 0, 16 },
730 [SMP_T_STR] = { "string", STK_F_CUSTOM_KEYSIZE, 32 },
731 [SMP_T_BIN] = { "binary", STK_F_CUSTOM_KEYSIZE, 32 }
732};
Emeric Brun3bd697e2010-01-04 15:23:48 +0100733
734/*
735 * Parse table type configuration.
736 * Returns 0 on successful parsing, else 1.
737 * <myidx> is set at next configuration <args> index.
738 */
739int stktable_parse_type(char **args, int *myidx, unsigned long *type, size_t *key_size)
740{
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200741 for (*type = 0; *type < SMP_TYPES; (*type)++) {
742 if (!stktable_types[*type].kw)
743 continue;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100744 if (strcmp(args[*myidx], stktable_types[*type].kw) != 0)
745 continue;
746
747 *key_size = stktable_types[*type].default_size;
748 (*myidx)++;
749
Willy Tarreauaea940e2010-06-06 11:56:36 +0200750 if (stktable_types[*type].flags & STK_F_CUSTOM_KEYSIZE) {
Emeric Brun3bd697e2010-01-04 15:23:48 +0100751 if (strcmp("len", args[*myidx]) == 0) {
752 (*myidx)++;
753 *key_size = atol(args[*myidx]);
Emeric Brun485479d2010-09-23 18:02:19 +0200754 if (!*key_size)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100755 break;
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200756 if (*type == SMP_T_STR) {
Emeric Brun485479d2010-09-23 18:02:19 +0200757 /* null terminated string needs +1 for '\0'. */
758 (*key_size)++;
759 }
Emeric Brun3bd697e2010-01-04 15:23:48 +0100760 (*myidx)++;
761 }
762 }
763 return 0;
764 }
765 return 1;
766}
767
Emeric Brunc64a2a32021-06-30 18:01:02 +0200768/* reserve some space for data type <type>, there is 2 optionnals
769 * argument at <sa> and <sa2> to configure this data type and
770 * they can be NULL if unused for a given type.
771 * Returns PE_NONE (0) if OK or an error code among :
Willy Tarreau3b63ca22021-05-08 14:10:42 +0200772 * - PE_ENUM_OOR if <type> does not exist
773 * - PE_EXIST if <type> is already registered
Emeric Brunc64a2a32021-06-30 18:01:02 +0200774 * - PE_ARG_NOT_USE if <sa>/<sa2> was provided but not expected
775 * - PE_ARG_MISSING if <sa>/<sa2> was expected but not provided
776 * - PE_ARG_VALUE_OOR if type is an array and <sa> it out of array size range.
Willy Tarreau3b63ca22021-05-08 14:10:42 +0200777 */
Emeric Brunc64a2a32021-06-30 18:01:02 +0200778int stktable_alloc_data_type(struct stktable *t, int type, const char *sa, const char *sa2)
779
Willy Tarreau3b63ca22021-05-08 14:10:42 +0200780{
781 if (type >= STKTABLE_DATA_TYPES)
782 return PE_ENUM_OOR;
783
784 if (t->data_ofs[type])
785 /* already allocated */
786 return PE_EXIST;
787
Emeric Brunc64a2a32021-06-30 18:01:02 +0200788 t->data_nbelem[type] = 1;
789 if (stktable_data_types[type].is_array) {
790 /* arrays take their element count on first argument */
791 if (!sa)
792 return PE_ARG_MISSING;
793 t->data_nbelem[type] = atoi(sa);
794 if (!t->data_nbelem[type] || (t->data_nbelem[type] > STKTABLE_MAX_DT_ARRAY_SIZE))
795 return PE_ARG_VALUE_OOR;
796 sa = sa2;
797 }
798
Willy Tarreau3b63ca22021-05-08 14:10:42 +0200799 switch (stktable_data_types[type].arg_type) {
800 case ARG_T_NONE:
801 if (sa)
802 return PE_ARG_NOT_USED;
803 break;
804 case ARG_T_INT:
805 if (!sa)
806 return PE_ARG_MISSING;
807 t->data_arg[type].i = atoi(sa);
808 break;
809 case ARG_T_DELAY:
810 if (!sa)
811 return PE_ARG_MISSING;
812 sa = parse_time_err(sa, &t->data_arg[type].u, TIME_UNIT_MS);
813 if (sa)
814 return PE_ARG_INVC; /* invalid char */
815 break;
816 }
817
Emeric Brunc64a2a32021-06-30 18:01:02 +0200818 t->data_size += t->data_nbelem[type] * stktable_type_size(stktable_data_types[type].std_type);
Willy Tarreau3b63ca22021-05-08 14:10:42 +0200819 t->data_ofs[type] = -t->data_size;
820 return PE_NONE;
821}
822
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100823/*
Frédéric Lécaillec02766a2019-03-20 15:06:55 +0100824 * Parse a line with <linenum> as number in <file> configuration file to configure
825 * the stick-table with <t> as address and <id> as ID.
826 * <peers> provides the "peers" section pointer only if this function is called
827 * from a "peers" section.
828 * <nid> is the stick-table name which is sent over the network. It must be equal
829 * to <id> if this stick-table is parsed from a proxy section, and prefixed by <peers>
830 * "peers" section name followed by a '/' character if parsed from a "peers" section.
Ilya Shipitsind4259502020-04-08 01:07:56 +0500831 * This is the responsibility of the caller to check this.
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100832 * Return an error status with ERR_* flags set if required, 0 if no error was encountered.
833 */
834int parse_stick_table(const char *file, int linenum, char **args,
Frédéric Lécaillec02766a2019-03-20 15:06:55 +0100835 struct stktable *t, char *id, char *nid, struct peers *peers)
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100836{
837 int err_code = 0;
838 int idx = 1;
839 unsigned int val;
840
841 if (!id || !*id) {
842 ha_alert("parsing [%s:%d] : %s: ID not provided.\n", file, linenum, args[0]);
843 err_code |= ERR_ALERT | ERR_ABORT;
844 goto out;
845 }
846
847 /* Store the "peers" section if this function is called from a "peers" section. */
848 if (peers) {
849 t->peers.p = peers;
850 idx++;
851 }
852
853 t->id = id;
Frédéric Lécaillec02766a2019-03-20 15:06:55 +0100854 t->nid = nid;
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100855 t->type = (unsigned int)-1;
856 t->conf.file = file;
857 t->conf.line = linenum;
858
859 while (*args[idx]) {
860 const char *err;
861
862 if (strcmp(args[idx], "size") == 0) {
863 idx++;
864 if (!*(args[idx])) {
865 ha_alert("parsing [%s:%d] : %s: missing argument after '%s'.\n",
866 file, linenum, args[0], args[idx-1]);
867 err_code |= ERR_ALERT | ERR_FATAL;
868 goto out;
869 }
870 if ((err = parse_size_err(args[idx], &t->size))) {
871 ha_alert("parsing [%s:%d] : %s: unexpected character '%c' in argument of '%s'.\n",
872 file, linenum, args[0], *err, args[idx-1]);
873 err_code |= ERR_ALERT | ERR_FATAL;
874 goto out;
875 }
876 idx++;
877 }
878 /* This argument does not exit in "peers" section. */
879 else if (!peers && strcmp(args[idx], "peers") == 0) {
880 idx++;
881 if (!*(args[idx])) {
882 ha_alert("parsing [%s:%d] : %s: missing argument after '%s'.\n",
883 file, linenum, args[0], args[idx-1]);
884 err_code |= ERR_ALERT | ERR_FATAL;
885 goto out;
886 }
887 t->peers.name = strdup(args[idx++]);
888 }
889 else if (strcmp(args[idx], "expire") == 0) {
890 idx++;
891 if (!*(args[idx])) {
892 ha_alert("parsing [%s:%d] : %s: missing argument after '%s'.\n",
893 file, linenum, args[0], args[idx-1]);
894 err_code |= ERR_ALERT | ERR_FATAL;
895 goto out;
896 }
897 err = parse_time_err(args[idx], &val, TIME_UNIT_MS);
Willy Tarreau9faebe32019-06-07 19:00:37 +0200898 if (err == PARSE_TIME_OVER) {
899 ha_alert("parsing [%s:%d]: %s: timer overflow in argument <%s> to <%s>, maximum value is 2147483647 ms (~24.8 days).\n",
900 file, linenum, args[0], args[idx], args[idx-1]);
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100901 err_code |= ERR_ALERT | ERR_FATAL;
902 goto out;
903 }
Willy Tarreau9faebe32019-06-07 19:00:37 +0200904 else if (err == PARSE_TIME_UNDER) {
905 ha_alert("parsing [%s:%d]: %s: timer underflow in argument <%s> to <%s>, minimum non-null value is 1 ms.\n",
906 file, linenum, args[0], args[idx], args[idx-1]);
907 err_code |= ERR_ALERT | ERR_FATAL;
908 goto out;
909 }
910 else if (err) {
911 ha_alert("parsing [%s:%d] : %s: unexpected character '%c' in argument of '%s'.\n",
912 file, linenum, args[0], *err, args[idx-1]);
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100913 err_code |= ERR_ALERT | ERR_FATAL;
914 goto out;
915 }
916 t->expire = val;
917 idx++;
918 }
919 else if (strcmp(args[idx], "nopurge") == 0) {
920 t->nopurge = 1;
921 idx++;
922 }
923 else if (strcmp(args[idx], "type") == 0) {
924 idx++;
925 if (stktable_parse_type(args, &idx, &t->type, &t->key_size) != 0) {
926 ha_alert("parsing [%s:%d] : %s: unknown type '%s'.\n",
927 file, linenum, args[0], args[idx]);
928 err_code |= ERR_ALERT | ERR_FATAL;
929 goto out;
930 }
931 /* idx already points to next arg */
932 }
933 else if (strcmp(args[idx], "store") == 0) {
934 int type, err;
Emeric Brunc64a2a32021-06-30 18:01:02 +0200935 char *cw, *nw, *sa, *sa2;
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100936
937 idx++;
938 nw = args[idx];
939 while (*nw) {
940 /* the "store" keyword supports a comma-separated list */
941 cw = nw;
942 sa = NULL; /* store arg */
Emeric Brunc64a2a32021-06-30 18:01:02 +0200943 sa2 = NULL;
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100944 while (*nw && *nw != ',') {
945 if (*nw == '(') {
946 *nw = 0;
947 sa = ++nw;
948 while (*nw != ')') {
949 if (!*nw) {
950 ha_alert("parsing [%s:%d] : %s: missing closing parenthesis after store option '%s'.\n",
951 file, linenum, args[0], cw);
952 err_code |= ERR_ALERT | ERR_FATAL;
953 goto out;
954 }
Emeric Brunc64a2a32021-06-30 18:01:02 +0200955 if (*nw == ',') {
956 *nw = '\0';
957 sa2 = nw + 1;
958 }
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100959 nw++;
960 }
961 *nw = '\0';
962 }
963 nw++;
964 }
965 if (*nw)
966 *nw++ = '\0';
967 type = stktable_get_data_type(cw);
968 if (type < 0) {
969 ha_alert("parsing [%s:%d] : %s: unknown store option '%s'.\n",
970 file, linenum, args[0], cw);
971 err_code |= ERR_ALERT | ERR_FATAL;
972 goto out;
973 }
974
Emeric Brunc64a2a32021-06-30 18:01:02 +0200975 err = stktable_alloc_data_type(t, type, sa, sa2);
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100976 switch (err) {
977 case PE_NONE: break;
978 case PE_EXIST:
979 ha_warning("parsing [%s:%d]: %s: store option '%s' already enabled, ignored.\n",
980 file, linenum, args[0], cw);
981 err_code |= ERR_WARN;
982 break;
983
984 case PE_ARG_MISSING:
985 ha_alert("parsing [%s:%d] : %s: missing argument to store option '%s'.\n",
986 file, linenum, args[0], cw);
987 err_code |= ERR_ALERT | ERR_FATAL;
988 goto out;
989
990 case PE_ARG_NOT_USED:
991 ha_alert("parsing [%s:%d] : %s: unexpected argument to store option '%s'.\n",
992 file, linenum, args[0], cw);
993 err_code |= ERR_ALERT | ERR_FATAL;
994 goto out;
Emeric Brunc64a2a32021-06-30 18:01:02 +0200995 case PE_ARG_VALUE_OOR:
996 ha_alert("parsing [%s:%d] : %s: array size is out of allowed range (1-%d) for store option '%s'.\n",
997 file, linenum, args[0], STKTABLE_MAX_DT_ARRAY_SIZE, cw);
998 err_code |= ERR_ALERT | ERR_FATAL;
999 goto out;
Frédéric Lécailled456aa42019-03-08 14:47:00 +01001000
1001 default:
1002 ha_alert("parsing [%s:%d] : %s: error when processing store option '%s'.\n",
1003 file, linenum, args[0], cw);
1004 err_code |= ERR_ALERT | ERR_FATAL;
1005 goto out;
1006 }
1007 }
1008 idx++;
Emeric Brunf7ab0bf2021-06-30 18:58:22 +02001009 if (t->data_ofs[STKTABLE_DT_GPT] && t->data_ofs[STKTABLE_DT_GPT0]) {
1010 ha_alert("parsing [%s:%d] : %s: simultaneous usage of 'gpt' and 'gpt0' in a same table is not permitted as 'gpt' overrides 'gpt0'.\n",
1011 file, linenum, args[0]);
1012 err_code |= ERR_ALERT | ERR_FATAL;
1013 goto out;
1014 }
Emeric Brun726783d2021-06-30 19:06:43 +02001015 else if (t->data_ofs[STKTABLE_DT_GPC] && (t->data_ofs[STKTABLE_DT_GPC0] || t->data_ofs[STKTABLE_DT_GPC1])) {
1016 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",
1017 file, linenum, args[0]);
1018 err_code |= ERR_ALERT | ERR_FATAL;
1019 goto out;
1020 }
1021 else if (t->data_ofs[STKTABLE_DT_GPC_RATE] && (t->data_ofs[STKTABLE_DT_GPC0_RATE] || t->data_ofs[STKTABLE_DT_GPC1_RATE])) {
1022 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",
1023 file, linenum, args[0]);
1024 err_code |= ERR_ALERT | ERR_FATAL;
1025 goto out;
1026 }
Frédéric Lécailled456aa42019-03-08 14:47:00 +01001027 }
Thayne McCombs92149f92020-11-20 01:28:26 -07001028 else if (strcmp(args[idx], "srvkey") == 0) {
1029 char *keytype;
1030 idx++;
1031 keytype = args[idx];
1032 if (strcmp(keytype, "name") == 0) {
1033 t->server_key_type = STKTABLE_SRV_NAME;
1034 }
1035 else if (strcmp(keytype, "addr") == 0) {
1036 t->server_key_type = STKTABLE_SRV_ADDR;
1037 }
1038 else {
1039 ha_alert("parsing [%s:%d] : %s : unknown server key type '%s'.\n",
1040 file, linenum, args[0], keytype);
1041 err_code |= ERR_ALERT | ERR_FATAL;
1042 goto out;
1043
1044 }
1045 idx++;
1046 }
Frédéric Lécailled456aa42019-03-08 14:47:00 +01001047 else {
1048 ha_alert("parsing [%s:%d] : %s: unknown argument '%s'.\n",
1049 file, linenum, args[0], args[idx]);
1050 err_code |= ERR_ALERT | ERR_FATAL;
1051 goto out;
1052 }
1053 }
1054
1055 if (!t->size) {
1056 ha_alert("parsing [%s:%d] : %s: missing size.\n",
1057 file, linenum, args[0]);
1058 err_code |= ERR_ALERT | ERR_FATAL;
1059 goto out;
1060 }
1061
1062 if (t->type == (unsigned int)-1) {
1063 ha_alert("parsing [%s:%d] : %s: missing type.\n",
1064 file, linenum, args[0]);
1065 err_code |= ERR_ALERT | ERR_FATAL;
1066 goto out;
1067 }
1068
1069 out:
1070 return err_code;
1071}
1072
Willy Tarreau8fed9032014-07-03 17:02:46 +02001073/* Prepares a stktable_key from a sample <smp> to search into table <t>.
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001074 * Note that the sample *is* modified and that the returned key may point
1075 * to it, so the sample must not be modified afterwards before the lookup.
Willy Tarreau8fed9032014-07-03 17:02:46 +02001076 * Returns NULL if the sample could not be converted (eg: no matching type),
1077 * otherwise a pointer to the static stktable_key filled with what is needed
1078 * for the lookup.
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001079 */
Willy Tarreau8fed9032014-07-03 17:02:46 +02001080struct stktable_key *smp_to_stkey(struct sample *smp, struct stktable *t)
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001081{
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001082 /* Convert sample. */
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +02001083 if (!sample_convert(smp, t->type))
Willy Tarreau7fc1c6e2012-04-26 11:03:17 +02001084 return NULL;
1085
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001086 /* Fill static_table_key. */
1087 switch (t->type) {
Emeric Brun485479d2010-09-23 18:02:19 +02001088
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +02001089 case SMP_T_IPV4:
Christopher Fauletca20d022017-08-29 15:30:31 +02001090 static_table_key.key = &smp->data.u.ipv4;
1091 static_table_key.key_len = 4;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001092 break;
Emeric Brun485479d2010-09-23 18:02:19 +02001093
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +02001094 case SMP_T_IPV6:
Christopher Fauletca20d022017-08-29 15:30:31 +02001095 static_table_key.key = &smp->data.u.ipv6;
1096 static_table_key.key_len = 16;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001097 break;
Emeric Brun485479d2010-09-23 18:02:19 +02001098
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +02001099 case SMP_T_SINT:
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001100 /* The stick table require a 32bit unsigned int, "sint" is a
1101 * signed 64 it, so we can convert it inplace.
1102 */
Willy Tarreau28c63c12019-10-23 06:21:05 +02001103 smp->data.u.sint = (unsigned int)smp->data.u.sint;
Christopher Fauletca20d022017-08-29 15:30:31 +02001104 static_table_key.key = &smp->data.u.sint;
1105 static_table_key.key_len = 4;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001106 break;
1107
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +02001108 case SMP_T_STR:
Willy Tarreauce6955e2016-08-09 11:59:12 +02001109 if (!smp_make_safe(smp))
1110 return NULL;
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001111 static_table_key.key = smp->data.u.str.area;
1112 static_table_key.key_len = smp->data.u.str.data;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001113 break;
Emeric Brun485479d2010-09-23 18:02:19 +02001114
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +02001115 case SMP_T_BIN:
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001116 if (smp->data.u.str.data < t->key_size) {
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001117 /* This type needs padding with 0. */
Willy Tarreauf65c6c02016-08-09 12:08:41 +02001118 if (!smp_make_rw(smp))
1119 return NULL;
1120
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001121 if (smp->data.u.str.size < t->key_size)
1122 if (!smp_dup(smp))
1123 return NULL;
1124 if (smp->data.u.str.size < t->key_size)
1125 return NULL;
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001126 memset(smp->data.u.str.area + smp->data.u.str.data, 0,
1127 t->key_size - smp->data.u.str.data);
1128 smp->data.u.str.data = t->key_size;
Emeric Brun485479d2010-09-23 18:02:19 +02001129 }
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001130 static_table_key.key = smp->data.u.str.area;
1131 static_table_key.key_len = smp->data.u.str.data;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001132 break;
Emeric Brun485479d2010-09-23 18:02:19 +02001133
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001134 default: /* impossible case. */
1135 return NULL;
Emeric Brun485479d2010-09-23 18:02:19 +02001136 }
1137
Christopher Fauletca20d022017-08-29 15:30:31 +02001138 return &static_table_key;
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001139}
1140
1141/*
Willy Tarreau8fed9032014-07-03 17:02:46 +02001142 * Process a fetch + format conversion as defined by the sample expression <expr>
1143 * on request or response considering the <opt> parameter. Returns either NULL if
1144 * no key could be extracted, or a pointer to the converted result stored in
1145 * static_table_key in format <table_type>. If <smp> is not NULL, it will be reset
1146 * and its flags will be initialized so that the caller gets a copy of the input
Willy Tarreau6bcb0a82014-07-30 08:56:35 +02001147 * sample, and knows why it was not accepted (eg: SMP_F_MAY_CHANGE is present
1148 * without SMP_OPT_FINAL). The output will be usable like this :
1149 *
1150 * return MAY_CHANGE FINAL Meaning for the sample
1151 * NULL 0 * Not present and will never be (eg: header)
1152 * NULL 1 0 Not present or unstable, could change (eg: req_len)
1153 * NULL 1 1 Not present, will not change anymore
1154 * smp 0 * Present and will not change (eg: header)
1155 * smp 1 0 not possible
1156 * smp 1 1 Present, last known value (eg: request length)
Willy Tarreau8fed9032014-07-03 17:02:46 +02001157 */
Willy Tarreau192252e2015-04-04 01:47:55 +02001158struct stktable_key *stktable_fetch_key(struct stktable *t, struct proxy *px, struct session *sess, struct stream *strm,
Willy Tarreau8fed9032014-07-03 17:02:46 +02001159 unsigned int opt, struct sample_expr *expr, struct sample *smp)
1160{
1161 if (smp)
1162 memset(smp, 0, sizeof(*smp));
1163
Willy Tarreau192252e2015-04-04 01:47:55 +02001164 smp = sample_process(px, sess, strm, opt, expr, smp);
Willy Tarreau8fed9032014-07-03 17:02:46 +02001165 if (!smp)
1166 return NULL;
1167
1168 if ((smp->flags & SMP_F_MAY_CHANGE) && !(opt & SMP_OPT_FINAL))
1169 return NULL; /* we can only use stable samples */
1170
1171 return smp_to_stkey(smp, t);
1172}
1173
1174/*
Willy Tarreau12785782012-04-27 21:37:17 +02001175 * Returns 1 if sample expression <expr> result can be converted to table key of
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001176 * type <table_type>, otherwise zero. Used in configuration check.
1177 */
Willy Tarreau12785782012-04-27 21:37:17 +02001178int stktable_compatible_sample(struct sample_expr *expr, unsigned long table_type)
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001179{
Thierry FOURNIERf73eb8f2013-11-27 15:30:55 +01001180 int out_type;
1181
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +02001182 if (table_type >= SMP_TYPES || !stktable_types[table_type].kw)
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001183 return 0;
1184
Thierry FOURNIERf73eb8f2013-11-27 15:30:55 +01001185 out_type = smp_expr_output_type(expr);
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001186
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001187 /* Convert sample. */
1188 if (!sample_casts[out_type][table_type])
Thierry FOURNIERf73eb8f2013-11-27 15:30:55 +01001189 return 0;
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001190
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001191 return 1;
1192}
Emeric Brun3bd697e2010-01-04 15:23:48 +01001193
Willy Tarreauedee1d62014-07-15 16:44:27 +02001194/* Extra data types processing : after the last one, some room may remain
1195 * before STKTABLE_DATA_TYPES that may be used to register extra data types
1196 * at run time.
1197 */
Willy Tarreau08d5f982010-06-06 13:34:54 +02001198struct stktable_data_type stktable_data_types[STKTABLE_DATA_TYPES] = {
Willy Tarreau3b9c6e02010-07-18 08:04:30 +02001199 [STKTABLE_DT_SERVER_ID] = { .name = "server_id", .std_type = STD_T_SINT },
Thierry FOURNIER3cf11112015-07-28 08:57:05 +02001200 [STKTABLE_DT_GPT0] = { .name = "gpt0", .std_type = STD_T_UINT },
Willy Tarreau3b9c6e02010-07-18 08:04:30 +02001201 [STKTABLE_DT_GPC0] = { .name = "gpc0", .std_type = STD_T_UINT },
Willy Tarreauba2ffd12013-05-29 15:54:14 +02001202 [STKTABLE_DT_GPC0_RATE] = { .name = "gpc0_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
Willy Tarreau3b9c6e02010-07-18 08:04:30 +02001203 [STKTABLE_DT_CONN_CNT] = { .name = "conn_cnt", .std_type = STD_T_UINT },
1204 [STKTABLE_DT_CONN_RATE] = { .name = "conn_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
Willy Tarreaudb2ab822021-10-08 17:53:12 +02001205 [STKTABLE_DT_CONN_CUR] = { .name = "conn_cur", .std_type = STD_T_UINT, .is_local = 1 },
Willy Tarreau3b9c6e02010-07-18 08:04:30 +02001206 [STKTABLE_DT_SESS_CNT] = { .name = "sess_cnt", .std_type = STD_T_UINT },
1207 [STKTABLE_DT_SESS_RATE] = { .name = "sess_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
1208 [STKTABLE_DT_HTTP_REQ_CNT] = { .name = "http_req_cnt", .std_type = STD_T_UINT },
1209 [STKTABLE_DT_HTTP_REQ_RATE] = { .name = "http_req_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
1210 [STKTABLE_DT_HTTP_ERR_CNT] = { .name = "http_err_cnt", .std_type = STD_T_UINT },
1211 [STKTABLE_DT_HTTP_ERR_RATE] = { .name = "http_err_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
1212 [STKTABLE_DT_BYTES_IN_CNT] = { .name = "bytes_in_cnt", .std_type = STD_T_ULL },
1213 [STKTABLE_DT_BYTES_IN_RATE] = { .name = "bytes_in_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
1214 [STKTABLE_DT_BYTES_OUT_CNT] = { .name = "bytes_out_cnt", .std_type = STD_T_ULL },
1215 [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 +01001216 [STKTABLE_DT_GPC1] = { .name = "gpc1", .std_type = STD_T_UINT },
1217 [STKTABLE_DT_GPC1_RATE] = { .name = "gpc1_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
Thayne McCombs92149f92020-11-20 01:28:26 -07001218 [STKTABLE_DT_SERVER_KEY] = { .name = "server_key", .std_type = STD_T_DICT },
Willy Tarreau826f3ab2021-02-10 12:07:15 +01001219 [STKTABLE_DT_HTTP_FAIL_CNT] = { .name = "http_fail_cnt", .std_type = STD_T_UINT },
1220 [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 +02001221 [STKTABLE_DT_GPT] = { .name = "gpt", .std_type = STD_T_UINT, .is_array = 1 },
Emeric Brun4d7ada82021-06-30 19:04:16 +02001222 [STKTABLE_DT_GPC] = { .name = "gpc", .std_type = STD_T_UINT, .is_array = 1 },
1223 [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 +02001224};
1225
Willy Tarreauedee1d62014-07-15 16:44:27 +02001226/* Registers stick-table extra data type with index <idx>, name <name>, type
1227 * <std_type> and arg type <arg_type>. If the index is negative, the next free
1228 * index is automatically allocated. The allocated index is returned, or -1 if
1229 * no free index was found or <name> was already registered. The <name> is used
1230 * directly as a pointer, so if it's not stable, the caller must allocate it.
1231 */
1232int stktable_register_data_store(int idx, const char *name, int std_type, int arg_type)
1233{
1234 if (idx < 0) {
1235 for (idx = 0; idx < STKTABLE_DATA_TYPES; idx++) {
1236 if (!stktable_data_types[idx].name)
1237 break;
1238
1239 if (strcmp(stktable_data_types[idx].name, name) == 0)
1240 return -1;
1241 }
1242 }
1243
1244 if (idx >= STKTABLE_DATA_TYPES)
1245 return -1;
1246
1247 if (stktable_data_types[idx].name != NULL)
1248 return -1;
1249
1250 stktable_data_types[idx].name = name;
1251 stktable_data_types[idx].std_type = std_type;
1252 stktable_data_types[idx].arg_type = arg_type;
1253 return idx;
1254}
1255
Willy Tarreau08d5f982010-06-06 13:34:54 +02001256/*
1257 * Returns the data type number for the stktable_data_type whose name is <name>,
1258 * or <0 if not found.
1259 */
1260int stktable_get_data_type(char *name)
1261{
1262 int type;
1263
1264 for (type = 0; type < STKTABLE_DATA_TYPES; type++) {
Willy Tarreauedee1d62014-07-15 16:44:27 +02001265 if (!stktable_data_types[type].name)
1266 continue;
Willy Tarreau08d5f982010-06-06 13:34:54 +02001267 if (strcmp(name, stktable_data_types[type].name) == 0)
1268 return type;
1269 }
Thayne McCombs92149f92020-11-20 01:28:26 -07001270 /* For backwards compatibility */
1271 if (strcmp(name, "server_name") == 0)
1272 return STKTABLE_DT_SERVER_KEY;
Willy Tarreau08d5f982010-06-06 13:34:54 +02001273 return -1;
1274}
1275
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001276/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1277 * it up into this table. Returns true if found, false otherwise. The input
1278 * type is STR so that input samples are converted to string (since all types
1279 * can be converted to strings), then the function casts the string again into
1280 * the table's type. This is a double conversion, but in the future we might
1281 * support automatic input types to perform the cast on the fly.
1282 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001283static int sample_conv_in_table(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001284{
1285 struct stktable *t;
1286 struct stktable_key *key;
1287 struct stksess *ts;
1288
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001289 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001290
1291 key = smp_to_stkey(smp, t);
1292 if (!key)
1293 return 0;
1294
1295 ts = stktable_lookup_key(t, key);
1296
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001297 smp->data.type = SMP_T_BOOL;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001298 smp->data.u.sint = !!ts;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001299 smp->flags = SMP_F_VOL_TEST;
Willy Tarreau43e90352018-06-27 06:25:57 +02001300 stktable_release(t, ts);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001301 return 1;
1302}
1303
1304/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1305 * it up into this table. Returns the data rate received from clients in bytes/s
1306 * if the key is present in the table, otherwise zero, so that comparisons can
1307 * be easily performed. If the inspected parameter is not stored in the table,
1308 * <not found> is returned.
1309 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001310static int sample_conv_table_bytes_in_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001311{
1312 struct stktable *t;
1313 struct stktable_key *key;
1314 struct stksess *ts;
1315 void *ptr;
1316
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001317 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001318
1319 key = smp_to_stkey(smp, t);
1320 if (!key)
1321 return 0;
1322
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001323 ts = stktable_lookup_key(t, key);
1324
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001325 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001326 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001327 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001328
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001329 if (!ts) /* key not present */
1330 return 1;
1331
1332 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_IN_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001333 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001334 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Daniel Corbett3e60b112018-05-27 09:47:12 -04001335 t->data_arg[STKTABLE_DT_BYTES_IN_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001336
Daniel Corbett3e60b112018-05-27 09:47:12 -04001337 stktable_release(t, ts);
1338 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001339}
1340
1341/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1342 * it up into this table. Returns the cumulated number of connections for the key
1343 * if the key is present in the table, otherwise zero, so that comparisons can
1344 * be easily performed. If the inspected parameter is not stored in the table,
1345 * <not found> is returned.
1346 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001347static int sample_conv_table_conn_cnt(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001348{
1349 struct stktable *t;
1350 struct stktable_key *key;
1351 struct stksess *ts;
1352 void *ptr;
1353
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001354 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001355
1356 key = smp_to_stkey(smp, t);
1357 if (!key)
1358 return 0;
1359
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001360 ts = stktable_lookup_key(t, key);
1361
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001362 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001363 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001364 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001365
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001366 if (!ts) /* key not present */
1367 return 1;
1368
1369 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_CONN_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001370 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001371 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001372
Daniel Corbett3e60b112018-05-27 09:47:12 -04001373 stktable_release(t, ts);
1374 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001375}
1376
1377/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1378 * it up into this table. Returns the number of concurrent connections for the
1379 * key if the key is present in the table, otherwise zero, so that comparisons
1380 * can be easily performed. If the inspected parameter is not stored in the
1381 * table, <not found> is returned.
1382 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001383static int sample_conv_table_conn_cur(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001384{
1385 struct stktable *t;
1386 struct stktable_key *key;
1387 struct stksess *ts;
1388 void *ptr;
1389
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001390 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001391
1392 key = smp_to_stkey(smp, t);
1393 if (!key)
1394 return 0;
1395
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001396 ts = stktable_lookup_key(t, key);
1397
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001398 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001399 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001400 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001401
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001402 if (!ts) /* key not present */
1403 return 1;
1404
1405 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_CONN_CUR);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001406 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001407 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001408
Daniel Corbett3e60b112018-05-27 09:47:12 -04001409 stktable_release(t, ts);
1410 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001411}
1412
1413/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1414 * it up into this table. Returns the rate of incoming connections from the key
1415 * if the key is present in the table, otherwise zero, so that comparisons can
1416 * be easily performed. If the inspected parameter is not stored in the table,
1417 * <not found> is returned.
1418 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001419static int sample_conv_table_conn_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001420{
1421 struct stktable *t;
1422 struct stktable_key *key;
1423 struct stksess *ts;
1424 void *ptr;
1425
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001426 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001427
1428 key = smp_to_stkey(smp, t);
1429 if (!key)
1430 return 0;
1431
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001432 ts = stktable_lookup_key(t, key);
1433
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001434 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001435 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001436 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001437
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001438 if (!ts) /* key not present */
1439 return 1;
1440
1441 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_CONN_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001442 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001443 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Daniel Corbett3e60b112018-05-27 09:47:12 -04001444 t->data_arg[STKTABLE_DT_CONN_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001445
Daniel Corbett3e60b112018-05-27 09:47:12 -04001446 stktable_release(t, ts);
1447 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001448}
1449
1450/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Frédéric Lécaillebbeec372022-08-16 18:11:25 +02001451 * it up into this table. Returns the expiration delay for the key if the key is
1452 * present in the table, otherwise the default value provided as second argument
1453 * if any, if not (no default value), <not found> is returned.
1454 */
1455static int sample_conv_table_expire(const struct arg *arg_p, struct sample *smp, void *private)
1456{
1457 struct stktable *t;
1458 struct stktable_key *key;
1459 struct stksess *ts;
1460
1461 t = arg_p[0].data.t;
1462
1463 key = smp_to_stkey(smp, t);
1464 if (!key)
1465 return 0;
1466
1467 ts = stktable_lookup_key(t, key);
1468
1469 smp->flags = SMP_F_VOL_TEST;
1470 smp->data.type = SMP_T_SINT;
1471 smp->data.u.sint = 0;
1472
1473 if (!ts) { /* key not present */
1474 if (arg_p[1].type == ARGT_STOP)
1475 return 0;
1476
1477 /* default value */
1478 smp->data.u.sint = arg_p[1].data.sint;
1479 return 1;
1480 }
1481
1482 smp->data.u.sint = tick_remain(now_ms, ts->expire);
1483
1484 stktable_release(t, ts);
1485 return 1;
1486}
1487
1488/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1489 * it up into this table. Returns the time the key remains unused if the key is
1490 * present in the table, otherwise the default value provided as second argument
1491 * if any, if not (no default value), <not found> is returned.
1492 */
1493static int sample_conv_table_idle(const struct arg *arg_p, struct sample *smp, void *private)
1494{
1495 struct stktable *t;
1496 struct stktable_key *key;
1497 struct stksess *ts;
1498
1499 t = arg_p[0].data.t;
1500
1501 key = smp_to_stkey(smp, t);
1502 if (!key)
1503 return 0;
1504
1505 ts = stktable_lookup_key(t, key);
1506
1507 smp->flags = SMP_F_VOL_TEST;
1508 smp->data.type = SMP_T_SINT;
1509 smp->data.u.sint = 0;
1510
1511 if (!ts) { /* key not present */
1512 if (arg_p[1].type == ARGT_STOP)
1513 return 0;
1514
1515 /* default value */
1516 smp->data.u.sint = arg_p[1].data.sint;
1517 return 1;
1518 }
1519
1520 smp->data.u.sint = tick_remain(tick_remain(now_ms, ts->expire), t->expire);
1521
1522 stktable_release(t, ts);
1523 return 1;
1524}
1525
1526/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001527 * it up into this table. Returns the data rate sent to clients in bytes/s
1528 * if the key is present in the table, otherwise zero, so that comparisons can
1529 * be easily performed. If the inspected parameter is not stored in the table,
1530 * <not found> is returned.
1531 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001532static int sample_conv_table_bytes_out_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001533{
1534 struct stktable *t;
1535 struct stktable_key *key;
1536 struct stksess *ts;
1537 void *ptr;
1538
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001539 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001540
1541 key = smp_to_stkey(smp, t);
1542 if (!key)
1543 return 0;
1544
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001545 ts = stktable_lookup_key(t, key);
1546
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001547 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001548 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001549 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001550
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001551 if (!ts) /* key not present */
1552 return 1;
1553
1554 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_OUT_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001555 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001556 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Daniel Corbett3e60b112018-05-27 09:47:12 -04001557 t->data_arg[STKTABLE_DT_BYTES_OUT_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001558
Daniel Corbett3e60b112018-05-27 09:47:12 -04001559 stktable_release(t, ts);
1560 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001561}
1562
Emeric Brun877b0b52021-06-30 18:57:49 +02001563/* Casts sample <smp> to the type of the table specified in arg_p(1), and looks
1564 * it up into this table. Returns the value of the GPT[arg_p(0)] tag for the key
1565 * if the key is present in the table, otherwise false, so that comparisons can
1566 * be easily performed. If the inspected parameter is not stored in the table,
1567 * <not found> is returned.
1568 */
1569static int sample_conv_table_gpt(const struct arg *arg_p, struct sample *smp, void *private)
1570{
1571 struct stktable *t;
1572 struct stktable_key *key;
1573 struct stksess *ts;
1574 void *ptr;
1575 unsigned int idx;
1576
1577 idx = arg_p[0].data.sint;
1578
1579 t = arg_p[1].data.t;
1580
1581 key = smp_to_stkey(smp, t);
1582 if (!key)
1583 return 0;
1584
1585 ts = stktable_lookup_key(t, key);
1586
1587 smp->flags = SMP_F_VOL_TEST;
1588 smp->data.type = SMP_T_SINT;
1589 smp->data.u.sint = 0;
1590
1591 if (!ts) /* key not present */
1592 return 1;
1593
1594 ptr = stktable_data_ptr_idx(t, ts, STKTABLE_DT_GPT, idx);
1595 if (ptr)
1596 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
1597
1598 stktable_release(t, ts);
1599 return !!ptr;
1600}
1601
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001602/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001603 * it up into this table. Returns the value of the GPT0 tag for the key
1604 * if the key is present in the table, otherwise false, so that comparisons can
1605 * be easily performed. If the inspected parameter is not stored in the table,
1606 * <not found> is returned.
1607 */
1608static int sample_conv_table_gpt0(const struct arg *arg_p, struct sample *smp, void *private)
1609{
1610 struct stktable *t;
1611 struct stktable_key *key;
1612 struct stksess *ts;
1613 void *ptr;
1614
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001615 t = arg_p[0].data.t;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001616
1617 key = smp_to_stkey(smp, t);
1618 if (!key)
1619 return 0;
1620
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001621 ts = stktable_lookup_key(t, key);
1622
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001623 smp->flags = SMP_F_VOL_TEST;
1624 smp->data.type = SMP_T_SINT;
1625 smp->data.u.sint = 0;
1626
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001627 if (!ts) /* key not present */
1628 return 1;
1629
1630 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPT0);
Emeric Brunf7ab0bf2021-06-30 18:58:22 +02001631 if (!ptr)
1632 ptr = stktable_data_ptr_idx(t, ts, STKTABLE_DT_GPT, 0);
1633
Daniel Corbett3e60b112018-05-27 09:47:12 -04001634 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001635 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001636
Daniel Corbett3e60b112018-05-27 09:47:12 -04001637 stktable_release(t, ts);
1638 return !!ptr;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001639}
1640
Emeric Brun4d7ada82021-06-30 19:04:16 +02001641/* Casts sample <smp> to the type of the table specified in arg_p(1), and looks
1642 * it up into this table. Returns the value of the GPC[arg_p(0)] counter for the key
1643 * if the key is present in the table, otherwise zero, so that comparisons can
1644 * be easily performed. If the inspected parameter is not stored in the table,
1645 * <not found> is returned.
1646 */
1647static int sample_conv_table_gpc(const struct arg *arg_p, struct sample *smp, void *private)
1648{
1649 struct stktable *t;
1650 struct stktable_key *key;
1651 struct stksess *ts;
1652 void *ptr;
1653 unsigned int idx;
1654
1655 idx = arg_p[0].data.sint;
1656
1657 t = arg_p[1].data.t;
1658
1659 key = smp_to_stkey(smp, t);
1660 if (!key)
1661 return 0;
1662
1663 ts = stktable_lookup_key(t, key);
1664
1665 smp->flags = SMP_F_VOL_TEST;
1666 smp->data.type = SMP_T_SINT;
1667 smp->data.u.sint = 0;
1668
1669 if (!ts) /* key not present */
1670 return 1;
1671
1672 ptr = stktable_data_ptr_idx(t, ts, STKTABLE_DT_GPC, idx);
1673 if (ptr)
1674 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
1675
1676 stktable_release(t, ts);
1677 return !!ptr;
1678}
1679
1680/* Casts sample <smp> to the type of the table specified in arg_p(1), and looks
1681 * it up into this table. Returns the event rate of the GPC[arg_p(0)] counter
1682 * for the key if the key is present in the table, otherwise zero, so that
1683 * comparisons can be easily performed. If the inspected parameter is not
1684 * stored in the table, <not found> is returned.
1685 */
1686static int sample_conv_table_gpc_rate(const struct arg *arg_p, struct sample *smp, void *private)
1687{
1688 struct stktable *t;
1689 struct stktable_key *key;
1690 struct stksess *ts;
1691 void *ptr;
1692 unsigned int idx;
1693
1694 idx = arg_p[0].data.sint;
1695
1696 t = arg_p[1].data.t;
1697
1698 key = smp_to_stkey(smp, t);
1699 if (!key)
1700 return 0;
1701
1702 ts = stktable_lookup_key(t, key);
1703
1704 smp->flags = SMP_F_VOL_TEST;
1705 smp->data.type = SMP_T_SINT;
1706 smp->data.u.sint = 0;
1707
1708 if (!ts) /* key not present */
1709 return 1;
1710
1711 ptr = stktable_data_ptr_idx(t, ts, STKTABLE_DT_GPC_RATE, idx);
1712 if (ptr)
1713 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
1714 t->data_arg[STKTABLE_DT_GPC_RATE].u);
1715
1716 stktable_release(t, ts);
1717 return !!ptr;
1718}
1719
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001720/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001721 * it up into this table. Returns the value of the GPC0 counter for the key
1722 * if the key is present in the table, otherwise zero, so that comparisons can
1723 * be easily performed. If the inspected parameter is not stored in the table,
1724 * <not found> is returned.
1725 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001726static int sample_conv_table_gpc0(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001727{
1728 struct stktable *t;
1729 struct stktable_key *key;
1730 struct stksess *ts;
1731 void *ptr;
1732
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001733 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001734
1735 key = smp_to_stkey(smp, t);
1736 if (!key)
1737 return 0;
1738
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001739 ts = stktable_lookup_key(t, key);
1740
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001741 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001742 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001743 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001744
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001745 if (!ts) /* key not present */
1746 return 1;
1747
1748 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPC0);
Emeric Brun726783d2021-06-30 19:06:43 +02001749 if (!ptr) {
1750 /* fallback on the gpc array */
1751 ptr = stktable_data_ptr_idx(t, ts, STKTABLE_DT_GPC, 0);
1752 }
1753
Daniel Corbett3e60b112018-05-27 09:47:12 -04001754 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001755 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001756
Daniel Corbett3e60b112018-05-27 09:47:12 -04001757 stktable_release(t, ts);
1758 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001759}
1760
1761/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1762 * it up into this table. Returns the event rate of the GPC0 counter for the key
1763 * if the key is present in the table, otherwise zero, so that comparisons can
1764 * be easily performed. If the inspected parameter is not stored in the table,
1765 * <not found> is returned.
1766 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001767static int sample_conv_table_gpc0_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001768{
1769 struct stktable *t;
1770 struct stktable_key *key;
1771 struct stksess *ts;
1772 void *ptr;
1773
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001774 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001775
1776 key = smp_to_stkey(smp, t);
1777 if (!key)
1778 return 0;
1779
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001780 ts = stktable_lookup_key(t, key);
1781
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001782 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001783 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001784 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001785
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001786 if (!ts) /* key not present */
1787 return 1;
1788
1789 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPC0_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001790 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001791 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Daniel Corbett3e60b112018-05-27 09:47:12 -04001792 t->data_arg[STKTABLE_DT_GPC0_RATE].u);
Emeric Brun726783d2021-06-30 19:06:43 +02001793 else {
1794 /* fallback on the gpc array */
1795 ptr = stktable_data_ptr_idx(t, ts, STKTABLE_DT_GPC_RATE, 0);
1796 if (ptr)
1797 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
1798 t->data_arg[STKTABLE_DT_GPC_RATE].u);
1799 }
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001800
Daniel Corbett3e60b112018-05-27 09:47:12 -04001801 stktable_release(t, ts);
1802 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001803}
1804
1805/* 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 +01001806 * it up into this table. Returns the value of the GPC1 counter for the key
1807 * if the key is present in the table, otherwise zero, so that comparisons can
1808 * be easily performed. If the inspected parameter is not stored in the table,
1809 * <not found> is returned.
1810 */
1811static int sample_conv_table_gpc1(const struct arg *arg_p, struct sample *smp, void *private)
1812{
1813 struct stktable *t;
1814 struct stktable_key *key;
1815 struct stksess *ts;
1816 void *ptr;
1817
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001818 t = arg_p[0].data.t;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001819
1820 key = smp_to_stkey(smp, t);
1821 if (!key)
1822 return 0;
1823
1824 ts = stktable_lookup_key(t, key);
1825
1826 smp->flags = SMP_F_VOL_TEST;
1827 smp->data.type = SMP_T_SINT;
1828 smp->data.u.sint = 0;
1829
1830 if (!ts) /* key not present */
1831 return 1;
1832
1833 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPC1);
Emeric Brun726783d2021-06-30 19:06:43 +02001834 if (!ptr) {
1835 /* fallback on the gpc array */
1836 ptr = stktable_data_ptr_idx(t, ts, STKTABLE_DT_GPC, 1);
1837 }
1838
Daniel Corbett3e60b112018-05-27 09:47:12 -04001839 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001840 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001841
Daniel Corbett3e60b112018-05-27 09:47:12 -04001842 stktable_release(t, ts);
1843 return !!ptr;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001844}
1845
1846/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1847 * it up into this table. Returns the event rate of the GPC1 counter for the key
1848 * if the key is present in the table, otherwise zero, so that comparisons can
1849 * be easily performed. If the inspected parameter is not stored in the table,
1850 * <not found> is returned.
1851 */
1852static int sample_conv_table_gpc1_rate(const struct arg *arg_p, struct sample *smp, void *private)
1853{
1854 struct stktable *t;
1855 struct stktable_key *key;
1856 struct stksess *ts;
1857 void *ptr;
1858
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001859 t = arg_p[0].data.t;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001860
1861 key = smp_to_stkey(smp, t);
1862 if (!key)
1863 return 0;
1864
1865 ts = stktable_lookup_key(t, key);
1866
1867 smp->flags = SMP_F_VOL_TEST;
1868 smp->data.type = SMP_T_SINT;
1869 smp->data.u.sint = 0;
1870
1871 if (!ts) /* key not present */
1872 return 1;
1873
1874 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPC1_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001875 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001876 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Daniel Corbett3e60b112018-05-27 09:47:12 -04001877 t->data_arg[STKTABLE_DT_GPC1_RATE].u);
Emeric Brun726783d2021-06-30 19:06:43 +02001878 else {
1879 /* fallback on the gpc array */
1880 ptr = stktable_data_ptr_idx(t, ts, STKTABLE_DT_GPC_RATE, 1);
1881 if (ptr)
1882 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
1883 t->data_arg[STKTABLE_DT_GPC_RATE].u);
1884 }
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001885
Daniel Corbett3e60b112018-05-27 09:47:12 -04001886 stktable_release(t, ts);
1887 return !!ptr;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001888}
1889
1890/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001891 * it up into this table. Returns the cumulated number of HTTP request errors
1892 * for the key if the key is present in the table, otherwise zero, so that
1893 * comparisons can be easily performed. If the inspected parameter is not stored
1894 * in the table, <not found> is returned.
1895 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001896static int sample_conv_table_http_err_cnt(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001897{
1898 struct stktable *t;
1899 struct stktable_key *key;
1900 struct stksess *ts;
1901 void *ptr;
1902
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001903 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001904
1905 key = smp_to_stkey(smp, t);
1906 if (!key)
1907 return 0;
1908
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001909 ts = stktable_lookup_key(t, key);
1910
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001911 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001912 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001913 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001914
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001915 if (!ts) /* key not present */
1916 return 1;
1917
1918 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_ERR_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001919 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001920 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001921
Daniel Corbett3e60b112018-05-27 09:47:12 -04001922 stktable_release(t, ts);
1923 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001924}
1925
1926/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1927 * it up into this table. Returns the HTTP request error rate the key
1928 * if the key is present in the table, otherwise zero, so that comparisons can
1929 * be easily performed. If the inspected parameter is not stored in the table,
1930 * <not found> is returned.
1931 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001932static int sample_conv_table_http_err_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001933{
1934 struct stktable *t;
1935 struct stktable_key *key;
1936 struct stksess *ts;
1937 void *ptr;
1938
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001939 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001940
1941 key = smp_to_stkey(smp, t);
1942 if (!key)
1943 return 0;
1944
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001945 ts = stktable_lookup_key(t, key);
1946
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001947 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001948 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001949 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001950
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001951 if (!ts) /* key not present */
1952 return 1;
1953
1954 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_ERR_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001955 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001956 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Daniel Corbett3e60b112018-05-27 09:47:12 -04001957 t->data_arg[STKTABLE_DT_HTTP_ERR_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001958
Daniel Corbett3e60b112018-05-27 09:47:12 -04001959 stktable_release(t, ts);
1960 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001961}
1962
1963/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Willy Tarreau826f3ab2021-02-10 12:07:15 +01001964 * it up into this table. Returns the cumulated number of HTTP response failures
1965 * for the key if the key is present in the table, otherwise zero, so that
1966 * comparisons can be easily performed. If the inspected parameter is not stored
1967 * in the table, <not found> is returned.
1968 */
1969static int sample_conv_table_http_fail_cnt(const struct arg *arg_p, struct sample *smp, void *private)
1970{
1971 struct stktable *t;
1972 struct stktable_key *key;
1973 struct stksess *ts;
1974 void *ptr;
1975
1976 t = arg_p[0].data.t;
1977
1978 key = smp_to_stkey(smp, t);
1979 if (!key)
1980 return 0;
1981
1982 ts = stktable_lookup_key(t, key);
1983
1984 smp->flags = SMP_F_VOL_TEST;
1985 smp->data.type = SMP_T_SINT;
1986 smp->data.u.sint = 0;
1987
1988 if (!ts) /* key not present */
1989 return 1;
1990
1991 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_FAIL_CNT);
1992 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001993 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Willy Tarreau826f3ab2021-02-10 12:07:15 +01001994
1995 stktable_release(t, ts);
1996 return !!ptr;
1997}
1998
1999/* Casts sample <smp> to the type of the table specified in arg(0), and looks
2000 * it up into this table. Returns the HTTP response failure rate for the key
2001 * if the key is present in the table, otherwise zero, so that comparisons can
2002 * be easily performed. If the inspected parameter is not stored in the table,
2003 * <not found> is returned.
2004 */
2005static int sample_conv_table_http_fail_rate(const struct arg *arg_p, struct sample *smp, void *private)
2006{
2007 struct stktable *t;
2008 struct stktable_key *key;
2009 struct stksess *ts;
2010 void *ptr;
2011
2012 t = arg_p[0].data.t;
2013
2014 key = smp_to_stkey(smp, t);
2015 if (!key)
2016 return 0;
2017
2018 ts = stktable_lookup_key(t, key);
2019
2020 smp->flags = SMP_F_VOL_TEST;
2021 smp->data.type = SMP_T_SINT;
2022 smp->data.u.sint = 0;
2023
2024 if (!ts) /* key not present */
2025 return 1;
2026
2027 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_FAIL_RATE);
2028 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002029 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Willy Tarreau826f3ab2021-02-10 12:07:15 +01002030 t->data_arg[STKTABLE_DT_HTTP_FAIL_RATE].u);
2031
2032 stktable_release(t, ts);
2033 return !!ptr;
2034}
2035
2036/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002037 * it up into this table. Returns the cumulated number of HTTP request for the
2038 * key if the key is present in the table, otherwise zero, so that comparisons
2039 * can be easily performed. If the inspected parameter is not stored in the
2040 * table, <not found> is returned.
2041 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02002042static int sample_conv_table_http_req_cnt(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002043{
2044 struct stktable *t;
2045 struct stktable_key *key;
2046 struct stksess *ts;
2047 void *ptr;
2048
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002049 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002050
2051 key = smp_to_stkey(smp, t);
2052 if (!key)
2053 return 0;
2054
Willy Tarreauf0c730a2016-05-25 17:07:56 +02002055 ts = stktable_lookup_key(t, key);
2056
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002057 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02002058 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02002059 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002060
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002061 if (!ts) /* key not present */
2062 return 1;
2063
2064 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_REQ_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04002065 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002066 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002067
Daniel Corbett3e60b112018-05-27 09:47:12 -04002068 stktable_release(t, ts);
2069 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002070}
2071
2072/* Casts sample <smp> to the type of the table specified in arg(0), and looks
2073 * it up into this table. Returns the HTTP request rate the key if the key is
2074 * present in the table, otherwise zero, so that comparisons can be easily
2075 * performed. If the inspected parameter is not stored in the table, <not found>
2076 * is returned.
2077 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02002078static int sample_conv_table_http_req_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002079{
2080 struct stktable *t;
2081 struct stktable_key *key;
2082 struct stksess *ts;
2083 void *ptr;
2084
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002085 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002086
2087 key = smp_to_stkey(smp, t);
2088 if (!key)
2089 return 0;
2090
Willy Tarreauf0c730a2016-05-25 17:07:56 +02002091 ts = stktable_lookup_key(t, key);
2092
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002093 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02002094 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02002095 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002096
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002097 if (!ts) /* key not present */
2098 return 1;
2099
2100 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_REQ_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04002101 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002102 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Daniel Corbett3e60b112018-05-27 09:47:12 -04002103 t->data_arg[STKTABLE_DT_HTTP_REQ_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002104
Daniel Corbett3e60b112018-05-27 09:47:12 -04002105 stktable_release(t, ts);
2106 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002107}
2108
2109/* Casts sample <smp> to the type of the table specified in arg(0), and looks
2110 * it up into this table. Returns the volume of datareceived from clients in kbytes
2111 * if the key is present in the table, otherwise zero, so that comparisons can
2112 * be easily performed. If the inspected parameter is not stored in the table,
2113 * <not found> is returned.
2114 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02002115static int sample_conv_table_kbytes_in(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002116{
2117 struct stktable *t;
2118 struct stktable_key *key;
2119 struct stksess *ts;
2120 void *ptr;
2121
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002122 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002123
2124 key = smp_to_stkey(smp, t);
2125 if (!key)
2126 return 0;
2127
Willy Tarreauf0c730a2016-05-25 17:07:56 +02002128 ts = stktable_lookup_key(t, key);
2129
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002130 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02002131 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02002132 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002133
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002134 if (!ts) /* key not present */
2135 return 1;
2136
2137 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_IN_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04002138 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002139 smp->data.u.sint = stktable_data_cast(ptr, std_t_ull) >> 10;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002140
Daniel Corbett3e60b112018-05-27 09:47:12 -04002141 stktable_release(t, ts);
2142 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002143}
2144
2145/* Casts sample <smp> to the type of the table specified in arg(0), and looks
2146 * it up into this table. Returns the volume of data sent to clients in kbytes
2147 * if the key is present in the table, otherwise zero, so that comparisons can
2148 * be easily performed. If the inspected parameter is not stored in the table,
2149 * <not found> is returned.
2150 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02002151static int sample_conv_table_kbytes_out(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002152{
2153 struct stktable *t;
2154 struct stktable_key *key;
2155 struct stksess *ts;
2156 void *ptr;
2157
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002158 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002159
2160 key = smp_to_stkey(smp, t);
2161 if (!key)
2162 return 0;
2163
Willy Tarreauf0c730a2016-05-25 17:07:56 +02002164 ts = stktable_lookup_key(t, key);
2165
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002166 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02002167 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02002168 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002169
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002170 if (!ts) /* key not present */
2171 return 1;
2172
2173 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_OUT_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04002174 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002175 smp->data.u.sint = stktable_data_cast(ptr, std_t_ull) >> 10;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002176
Daniel Corbett3e60b112018-05-27 09:47:12 -04002177 stktable_release(t, ts);
2178 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002179}
2180
2181/* Casts sample <smp> to the type of the table specified in arg(0), and looks
2182 * it up into this table. Returns the server ID associated with the key if the
2183 * key is present in the table, otherwise zero, so that comparisons can be
2184 * easily performed. If the inspected parameter is not stored in the table,
2185 * <not found> is returned.
2186 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02002187static int sample_conv_table_server_id(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002188{
2189 struct stktable *t;
2190 struct stktable_key *key;
2191 struct stksess *ts;
2192 void *ptr;
2193
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002194 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002195
2196 key = smp_to_stkey(smp, t);
2197 if (!key)
2198 return 0;
2199
Willy Tarreauf0c730a2016-05-25 17:07:56 +02002200 ts = stktable_lookup_key(t, key);
2201
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002202 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02002203 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02002204 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002205
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002206 if (!ts) /* key not present */
2207 return 1;
2208
2209 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_SERVER_ID);
Daniel Corbett3e60b112018-05-27 09:47:12 -04002210 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002211 smp->data.u.sint = stktable_data_cast(ptr, std_t_sint);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002212
Daniel Corbett3e60b112018-05-27 09:47:12 -04002213 stktable_release(t, ts);
2214 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002215}
2216
2217/* Casts sample <smp> to the type of the table specified in arg(0), and looks
2218 * it up into this table. Returns the cumulated number of sessions for the
2219 * key if the key is present in the table, otherwise zero, so that comparisons
2220 * can be easily performed. If the inspected parameter is not stored in the
2221 * table, <not found> is returned.
2222 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02002223static int sample_conv_table_sess_cnt(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002224{
2225 struct stktable *t;
2226 struct stktable_key *key;
2227 struct stksess *ts;
2228 void *ptr;
2229
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002230 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002231
2232 key = smp_to_stkey(smp, t);
2233 if (!key)
2234 return 0;
2235
Willy Tarreauf0c730a2016-05-25 17:07:56 +02002236 ts = stktable_lookup_key(t, key);
2237
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002238 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02002239 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02002240 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002241
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002242 if (!ts) /* key not present */
2243 return 1;
2244
2245 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_SESS_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04002246 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002247 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002248
Daniel Corbett3e60b112018-05-27 09:47:12 -04002249 stktable_release(t, ts);
2250 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002251}
2252
2253/* Casts sample <smp> to the type of the table specified in arg(0), and looks
2254 * it up into this table. Returns the session rate the key if the key is
2255 * present in the table, otherwise zero, so that comparisons can be easily
2256 * performed. If the inspected parameter is not stored in the table, <not found>
2257 * is returned.
2258 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02002259static int sample_conv_table_sess_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002260{
2261 struct stktable *t;
2262 struct stktable_key *key;
2263 struct stksess *ts;
2264 void *ptr;
2265
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002266 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002267
2268 key = smp_to_stkey(smp, t);
2269 if (!key)
2270 return 0;
2271
Willy Tarreauf0c730a2016-05-25 17:07:56 +02002272 ts = stktable_lookup_key(t, key);
2273
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002274 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02002275 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02002276 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002277
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002278 if (!ts) /* key not present */
2279 return 1;
2280
2281 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_SESS_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04002282 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002283 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Daniel Corbett3e60b112018-05-27 09:47:12 -04002284 t->data_arg[STKTABLE_DT_SESS_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002285
Daniel Corbett3e60b112018-05-27 09:47:12 -04002286 stktable_release(t, ts);
2287 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002288}
2289
2290/* Casts sample <smp> to the type of the table specified in arg(0), and looks
2291 * it up into this table. Returns the amount of concurrent connections tracking
2292 * the same key if the key is present in the table, otherwise zero, so that
2293 * comparisons can be easily performed. If the inspected parameter is not
2294 * stored in the table, <not found> is returned.
2295 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02002296static int sample_conv_table_trackers(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002297{
2298 struct stktable *t;
2299 struct stktable_key *key;
2300 struct stksess *ts;
2301
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002302 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002303
2304 key = smp_to_stkey(smp, t);
2305 if (!key)
2306 return 0;
2307
Willy Tarreauf0c730a2016-05-25 17:07:56 +02002308 ts = stktable_lookup_key(t, key);
2309
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002310 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02002311 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02002312 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002313
Tim Duesterhus65189c12018-06-26 15:57:29 +02002314 if (!ts)
2315 return 1;
2316
2317 smp->data.u.sint = ts->ref_cnt;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002318
Daniel Corbett3e60b112018-05-27 09:47:12 -04002319 stktable_release(t, ts);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002320 return 1;
2321}
2322
Emeric Brun4d7ada82021-06-30 19:04:16 +02002323/* This function increments the gpc counter at index 'rule->arg.gpc.idx' of the
2324 * array on the tracksc counter of index 'rule->arg.gpc.sc' stored into the
2325 * <stream> or directly in the session <sess> if <stream> is set to NULL
2326 *
2327 * This function always returns ACT_RET_CONT and parameter flags is unused.
2328 */
2329static enum act_return action_inc_gpc(struct act_rule *rule, struct proxy *px,
2330 struct session *sess, struct stream *s, int flags)
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002331{
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002332 struct stksess *ts;
2333 struct stkctr *stkctr;
2334
2335 /* Extract the stksess, return OK if no stksess available. */
2336 if (s)
2337 stkctr = &s->stkctr[rule->arg.gpc.sc];
2338 else
2339 stkctr = &sess->stkctr[rule->arg.gpc.sc];
Willy Tarreau79c1e912016-01-25 14:54:45 +01002340
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002341 ts = stkctr_entry(stkctr);
Willy Tarreau79c1e912016-01-25 14:54:45 +01002342 if (ts) {
2343 void *ptr1, *ptr2;
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002344
Emeric Brun4d7ada82021-06-30 19:04:16 +02002345 /* First, update gpc_rate if it's tracked. Second, update its gpc if tracked. */
2346 ptr1 = stktable_data_ptr_idx(stkctr->table, ts, STKTABLE_DT_GPC_RATE, rule->arg.gpc.idx);
2347 ptr2 = stktable_data_ptr_idx(stkctr->table, ts, STKTABLE_DT_GPC, rule->arg.gpc.idx);
2348
Emeric Brun819fc6f2017-06-13 19:37:32 +02002349 if (ptr1 || ptr2) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002350 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002351
2352 if (ptr1)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002353 update_freq_ctr_period(&stktable_data_cast(ptr1, std_t_frqp),
Emeric Brun4d7ada82021-06-30 19:04:16 +02002354 stkctr->table->data_arg[STKTABLE_DT_GPC_RATE].u, 1);
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002355
Emeric Brun819fc6f2017-06-13 19:37:32 +02002356 if (ptr2)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002357 stktable_data_cast(ptr2, std_t_uint)++;
Willy Tarreau79c1e912016-01-25 14:54:45 +01002358
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002359 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002360
2361 /* If data was modified, we need to touch to re-schedule sync */
2362 stktable_touch_local(stkctr->table, ts, 0);
2363 }
Willy Tarreau79c1e912016-01-25 14:54:45 +01002364 }
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002365 return ACT_RET_CONT;
2366}
2367
Emeric Brun4d7ada82021-06-30 19:04:16 +02002368/* Same as action_inc_gpc() but for gpc0 only */
2369static enum act_return action_inc_gpc0(struct act_rule *rule, struct proxy *px,
2370 struct session *sess, struct stream *s, int flags)
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002371{
Emeric Brun4d7ada82021-06-30 19:04:16 +02002372 struct stksess *ts;
2373 struct stkctr *stkctr;
Willy Tarreau5b654ad2021-07-06 18:51:12 +02002374 unsigned int period = 0;
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002375
Emeric Brun4d7ada82021-06-30 19:04:16 +02002376 /* Extract the stksess, return OK if no stksess available. */
2377 if (s)
2378 stkctr = &s->stkctr[rule->arg.gpc.sc];
2379 else
2380 stkctr = &sess->stkctr[rule->arg.gpc.sc];
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002381
Emeric Brun4d7ada82021-06-30 19:04:16 +02002382 ts = stkctr_entry(stkctr);
2383 if (ts) {
2384 void *ptr1, *ptr2;
2385
2386 /* First, update gpc0_rate if it's tracked. Second, update its gpc0 if tracked. */
2387 ptr1 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC0_RATE);
Emeric Brun726783d2021-06-30 19:06:43 +02002388 if (ptr1) {
2389 period = stkctr->table->data_arg[STKTABLE_DT_GPC0_RATE].u;
2390 }
2391 else {
2392 /* fallback on the gpc array */
2393 ptr1 = stktable_data_ptr_idx(stkctr->table, ts, STKTABLE_DT_GPC_RATE, 0);
2394 if (ptr1)
2395 period = stkctr->table->data_arg[STKTABLE_DT_GPC_RATE].u;
2396 }
2397
Emeric Brun4d7ada82021-06-30 19:04:16 +02002398 ptr2 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC0);
Emeric Brun726783d2021-06-30 19:06:43 +02002399 if (!ptr2) {
2400 /* fallback on the gpc array */
2401 ptr2 = stktable_data_ptr_idx(stkctr->table, ts, STKTABLE_DT_GPC, 0);
2402 }
2403
Emeric Brun4d7ada82021-06-30 19:04:16 +02002404 if (ptr1 || ptr2) {
2405 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
2406
2407 if (ptr1)
2408 update_freq_ctr_period(&stktable_data_cast(ptr1, std_t_frqp),
Emeric Brun726783d2021-06-30 19:06:43 +02002409 period, 1);
Emeric Brun4d7ada82021-06-30 19:04:16 +02002410
2411 if (ptr2)
2412 stktable_data_cast(ptr2, std_t_uint)++;
2413
2414 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
2415
2416 /* If data was modified, we need to touch to re-schedule sync */
2417 stktable_touch_local(stkctr->table, ts, 0);
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002418 }
2419 }
Emeric Brun4d7ada82021-06-30 19:04:16 +02002420 return ACT_RET_CONT;
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002421}
2422
Emeric Brun4d7ada82021-06-30 19:04:16 +02002423/* Same as action_inc_gpc() but for gpc1 only */
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002424static enum act_return action_inc_gpc1(struct act_rule *rule, struct proxy *px,
2425 struct session *sess, struct stream *s, int flags)
2426{
2427 struct stksess *ts;
2428 struct stkctr *stkctr;
Willy Tarreau5b654ad2021-07-06 18:51:12 +02002429 unsigned int period = 0;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002430
2431 /* Extract the stksess, return OK if no stksess available. */
2432 if (s)
2433 stkctr = &s->stkctr[rule->arg.gpc.sc];
2434 else
2435 stkctr = &sess->stkctr[rule->arg.gpc.sc];
2436
2437 ts = stkctr_entry(stkctr);
2438 if (ts) {
2439 void *ptr1, *ptr2;
2440
2441 /* First, update gpc1_rate if it's tracked. Second, update its gpc1 if tracked. */
2442 ptr1 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC1_RATE);
Emeric Brun726783d2021-06-30 19:06:43 +02002443 if (ptr1) {
2444 period = stkctr->table->data_arg[STKTABLE_DT_GPC1_RATE].u;
2445 }
2446 else {
2447 /* fallback on the gpc array */
2448 ptr1 = stktable_data_ptr_idx(stkctr->table, ts, STKTABLE_DT_GPC_RATE, 1);
2449 if (ptr1)
2450 period = stkctr->table->data_arg[STKTABLE_DT_GPC_RATE].u;
2451 }
2452
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002453 ptr2 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC1);
Emeric Brun726783d2021-06-30 19:06:43 +02002454 if (!ptr2) {
2455 /* fallback on the gpc array */
2456 ptr2 = stktable_data_ptr_idx(stkctr->table, ts, STKTABLE_DT_GPC, 1);
2457 }
2458
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002459 if (ptr1 || ptr2) {
2460 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
2461
2462 if (ptr1)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002463 update_freq_ctr_period(&stktable_data_cast(ptr1, std_t_frqp),
Emeric Brun726783d2021-06-30 19:06:43 +02002464 period, 1);
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002465
2466 if (ptr2)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002467 stktable_data_cast(ptr2, std_t_uint)++;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002468
2469 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
2470
2471 /* If data was modified, we need to touch to re-schedule sync */
2472 stktable_touch_local(stkctr->table, ts, 0);
2473 }
2474 }
2475 return ACT_RET_CONT;
2476}
2477
Emeric Brun4d7ada82021-06-30 19:04:16 +02002478/* This function is a common parser for actions incrementing the GPC
2479 * (General Purpose Counters). It understands the formats:
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002480 *
Emeric Brun4d7ada82021-06-30 19:04:16 +02002481 * sc-inc-gpc(<gpc IDX>,<track ID>)
2482 * sc-inc-gpc0([<track ID>])
2483 * sc-inc-gpc1([<track ID>])
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002484 *
Emeric Brun4d7ada82021-06-30 19:04:16 +02002485 * It returns ACT_RET_PRS_ERR if fails and <err> is filled with an error
2486 * message. Otherwise it returns ACT_RET_PRS_OK.
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002487 */
Emeric Brun4d7ada82021-06-30 19:04:16 +02002488static enum act_parse_ret parse_inc_gpc(const char **args, int *arg, struct proxy *px,
2489 struct act_rule *rule, char **err)
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002490{
2491 const char *cmd_name = args[*arg-1];
2492 char *error;
2493
Emeric Brun4d7ada82021-06-30 19:04:16 +02002494 cmd_name += strlen("sc-inc-gpc");
2495 if (*cmd_name == '(') {
2496 cmd_name++; /* skip the '(' */
2497 rule->arg.gpc.idx = strtoul(cmd_name, &error, 10); /* Convert stick table id. */
2498 if (*error != ',') {
2499 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 +01002500 return ACT_RET_PRS_ERR;
2501 }
Emeric Brun4d7ada82021-06-30 19:04:16 +02002502 else {
2503 cmd_name = error + 1; /* skip the ',' */
2504 rule->arg.gpc.sc = strtol(cmd_name, &error, 10); /* Convert stick table id. */
2505 if (*error != ')') {
2506 memprintf(err, "invalid stick table track ID '%s'. Expects sc-inc-gpc(<GPC ID>,<Track ID>)", args[*arg-1]);
2507 return ACT_RET_PRS_ERR;
2508 }
2509
2510 if (rule->arg.gpc.sc >= MAX_SESS_STKCTR) {
2511 memprintf(err, "invalid stick table track ID '%s'. The max allowed ID is %d",
2512 args[*arg-1], MAX_SESS_STKCTR-1);
2513 return ACT_RET_PRS_ERR;
2514 }
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002515 }
Emeric Brun4d7ada82021-06-30 19:04:16 +02002516 rule->action_ptr = action_inc_gpc;
2517 }
2518 else if (*cmd_name == '0' ||*cmd_name == '1') {
2519 char c = *cmd_name;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002520
Emeric Brun4d7ada82021-06-30 19:04:16 +02002521 cmd_name++;
2522 if (*cmd_name == '\0') {
2523 /* default stick table id. */
2524 rule->arg.gpc.sc = 0;
2525 } else {
2526 /* parse the stick table id. */
2527 if (*cmd_name != '(') {
2528 memprintf(err, "invalid stick table track ID. Expects %s(<Track ID>)", args[*arg-1]);
2529 return ACT_RET_PRS_ERR;
2530 }
2531 cmd_name++; /* jump the '(' */
2532 rule->arg.gpc.sc = strtol(cmd_name, &error, 10); /* Convert stick table id. */
2533 if (*error != ')') {
2534 memprintf(err, "invalid stick table track ID. Expects %s(<Track ID>)", args[*arg-1]);
2535 return ACT_RET_PRS_ERR;
2536 }
2537
2538 if (rule->arg.gpc.sc >= MAX_SESS_STKCTR) {
2539 memprintf(err, "invalid stick table track ID. The max allowed ID is %d",
2540 MAX_SESS_STKCTR-1);
2541 return ACT_RET_PRS_ERR;
2542 }
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002543 }
Emeric Brun4d7ada82021-06-30 19:04:16 +02002544 if (c == '1')
2545 rule->action_ptr = action_inc_gpc1;
2546 else
2547 rule->action_ptr = action_inc_gpc0;
2548 }
2549 else {
2550 /* default stick table id. */
2551 memprintf(err, "invalid gpc ID '%s'. Expects sc-set-gpc(<GPC ID>,<Track ID>)", args[*arg-1]);
2552 return ACT_RET_PRS_ERR;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002553 }
2554 rule->action = ACT_CUSTOM;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002555 return ACT_RET_PRS_OK;
2556}
2557
Emeric Brun877b0b52021-06-30 18:57:49 +02002558/* This function sets the gpt at index 'rule->arg.gpt.idx' of the array on the
2559 * tracksc counter of index 'rule->arg.gpt.sc' stored into the <stream> or
2560 * directly in the session <sess> if <stream> is set to NULL. This gpt is
2561 * set to the value computed by the expression 'rule->arg.gpt.expr' or if
2562 * 'rule->arg.gpt.expr' is null directly to the value of 'rule->arg.gpt.value'.
2563 *
2564 * This function always returns ACT_RET_CONT and parameter flags is unused.
2565 */
2566static enum act_return action_set_gpt(struct act_rule *rule, struct proxy *px,
2567 struct session *sess, struct stream *s, int flags)
2568{
2569 void *ptr;
2570 struct stksess *ts;
2571 struct stkctr *stkctr;
2572 unsigned int value = 0;
2573 struct sample *smp;
2574 int smp_opt_dir;
2575
2576 /* Extract the stksess, return OK if no stksess available. */
2577 if (s)
2578 stkctr = &s->stkctr[rule->arg.gpt.sc];
2579 else
2580 stkctr = &sess->stkctr[rule->arg.gpt.sc];
2581
2582 ts = stkctr_entry(stkctr);
2583 if (!ts)
2584 return ACT_RET_CONT;
2585
2586 /* Store the sample in the required sc, and ignore errors. */
2587 ptr = stktable_data_ptr_idx(stkctr->table, ts, STKTABLE_DT_GPT, rule->arg.gpt.idx);
2588 if (ptr) {
2589
2590 if (!rule->arg.gpt.expr)
2591 value = (unsigned int)(rule->arg.gpt.value);
2592 else {
2593 switch (rule->from) {
2594 case ACT_F_TCP_REQ_SES: smp_opt_dir = SMP_OPT_DIR_REQ; break;
2595 case ACT_F_TCP_REQ_CNT: smp_opt_dir = SMP_OPT_DIR_REQ; break;
2596 case ACT_F_TCP_RES_CNT: smp_opt_dir = SMP_OPT_DIR_RES; break;
2597 case ACT_F_HTTP_REQ: smp_opt_dir = SMP_OPT_DIR_REQ; break;
2598 case ACT_F_HTTP_RES: smp_opt_dir = SMP_OPT_DIR_RES; break;
2599 default:
2600 send_log(px, LOG_ERR, "stick table: internal error while setting gpt%u.", rule->arg.gpt.idx);
2601 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))
2602 ha_alert("stick table: internal error while executing setting gpt%u.\n", rule->arg.gpt.idx);
2603 return ACT_RET_CONT;
2604 }
2605
2606 /* Fetch and cast the expression. */
2607 smp = sample_fetch_as_type(px, sess, s, smp_opt_dir|SMP_OPT_FINAL, rule->arg.gpt.expr, SMP_T_SINT);
2608 if (!smp) {
2609 send_log(px, LOG_WARNING, "stick table: invalid expression or data type while setting gpt%u.", rule->arg.gpt.idx);
2610 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))
2611 ha_alert("stick table: invalid expression or data type while setting gpt%u.\n", rule->arg.gpt.idx);
2612 return ACT_RET_CONT;
2613 }
2614 value = (unsigned int)(smp->data.u.sint);
2615 }
2616
2617 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
2618
2619 stktable_data_cast(ptr, std_t_uint) = value;
2620
2621 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
2622
2623 stktable_touch_local(stkctr->table, ts, 0);
2624 }
2625
2626 return ACT_RET_CONT;
2627}
2628
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002629/* Always returns 1. */
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002630static enum act_return action_set_gpt0(struct act_rule *rule, struct proxy *px,
Willy Tarreau658b85b2015-09-27 10:00:49 +02002631 struct session *sess, struct stream *s, int flags)
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002632{
2633 void *ptr;
2634 struct stksess *ts;
2635 struct stkctr *stkctr;
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002636 unsigned int value = 0;
2637 struct sample *smp;
2638 int smp_opt_dir;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002639
2640 /* Extract the stksess, return OK if no stksess available. */
2641 if (s)
2642 stkctr = &s->stkctr[rule->arg.gpt.sc];
2643 else
2644 stkctr = &sess->stkctr[rule->arg.gpt.sc];
Willy Tarreau79c1e912016-01-25 14:54:45 +01002645
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002646 ts = stkctr_entry(stkctr);
2647 if (!ts)
2648 return ACT_RET_CONT;
2649
2650 /* Store the sample in the required sc, and ignore errors. */
2651 ptr = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPT0);
Emeric Brunf7ab0bf2021-06-30 18:58:22 +02002652 if (!ptr)
2653 ptr = stktable_data_ptr_idx(stkctr->table, ts, STKTABLE_DT_GPT, 0);
2654
Willy Tarreau79c1e912016-01-25 14:54:45 +01002655 if (ptr) {
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002656 if (!rule->arg.gpt.expr)
2657 value = (unsigned int)(rule->arg.gpt.value);
2658 else {
2659 switch (rule->from) {
2660 case ACT_F_TCP_REQ_SES: smp_opt_dir = SMP_OPT_DIR_REQ; break;
2661 case ACT_F_TCP_REQ_CNT: smp_opt_dir = SMP_OPT_DIR_REQ; break;
2662 case ACT_F_TCP_RES_CNT: smp_opt_dir = SMP_OPT_DIR_RES; break;
2663 case ACT_F_HTTP_REQ: smp_opt_dir = SMP_OPT_DIR_REQ; break;
2664 case ACT_F_HTTP_RES: smp_opt_dir = SMP_OPT_DIR_RES; break;
2665 default:
2666 send_log(px, LOG_ERR, "stick table: internal error while setting gpt0.");
2667 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))
2668 ha_alert("stick table: internal error while executing setting gpt0.\n");
2669 return ACT_RET_CONT;
2670 }
2671
2672 /* Fetch and cast the expression. */
2673 smp = sample_fetch_as_type(px, sess, s, smp_opt_dir|SMP_OPT_FINAL, rule->arg.gpt.expr, SMP_T_SINT);
2674 if (!smp) {
2675 send_log(px, LOG_WARNING, "stick table: invalid expression or data type while setting gpt0.");
2676 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))
2677 ha_alert("stick table: invalid expression or data type while setting gpt0.\n");
2678 return ACT_RET_CONT;
2679 }
2680 value = (unsigned int)(smp->data.u.sint);
2681 }
2682
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002683 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002684
Emeric Brun0e3457b2021-06-30 17:18:28 +02002685 stktable_data_cast(ptr, std_t_uint) = value;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002686
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002687 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002688
2689 stktable_touch_local(stkctr->table, ts, 0);
Willy Tarreau79c1e912016-01-25 14:54:45 +01002690 }
2691
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002692 return ACT_RET_CONT;
2693}
2694
Emeric Brun877b0b52021-06-30 18:57:49 +02002695/* This function is a parser for the "sc-set-gpt" and "sc-set-gpt0" actions.
2696 * It understands the formats:
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002697 *
Emeric Brun877b0b52021-06-30 18:57:49 +02002698 * sc-set-gpt(<gpt IDX>,<track ID>) <expression>
2699 * sc-set-gpt0(<track ID>) <expression>
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002700 *
Emeric Brun877b0b52021-06-30 18:57:49 +02002701 * It returns ACT_RET_PRS_ERR if fails and <err> is filled with an error message.
2702 * Otherwise, it returns ACT_RET_PRS_OK and the variable 'rule->arg.gpt.expr'
2703 * is filled with the pointer to the expression to execute or NULL if the arg
2704 * is directly an integer stored into 'rule->arg.gpt.value'.
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002705 */
Emeric Brun877b0b52021-06-30 18:57:49 +02002706static enum act_parse_ret parse_set_gpt(const char **args, int *arg, struct proxy *px,
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002707 struct act_rule *rule, char **err)
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002708{
2709 const char *cmd_name = args[*arg-1];
2710 char *error;
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002711 int smp_val;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002712
Emeric Brun877b0b52021-06-30 18:57:49 +02002713 cmd_name += strlen("sc-set-gpt");
2714 if (*cmd_name == '(') {
2715 cmd_name++; /* skip the '(' */
2716 rule->arg.gpt.idx = strtoul(cmd_name, &error, 10); /* Convert stick table id. */
2717 if (*error != ',') {
2718 memprintf(err, "Missing gpt ID '%s'. Expects sc-set-gpt(<GPT ID>,<Track ID>)", args[*arg-1]);
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002719 return ACT_RET_PRS_ERR;
2720 }
Emeric Brun877b0b52021-06-30 18:57:49 +02002721 else {
2722 cmd_name = error + 1; /* skip the ',' */
2723 rule->arg.gpt.sc = strtol(cmd_name, &error, 10); /* Convert stick table id. */
2724 if (*error != ')') {
2725 memprintf(err, "invalid stick table track ID '%s'. Expects sc-set-gpt(<GPT ID>,<Track ID>)", args[*arg-1]);
2726 return ACT_RET_PRS_ERR;
2727 }
2728
2729 if (rule->arg.gpt.sc >= MAX_SESS_STKCTR) {
2730 memprintf(err, "invalid stick table track ID '%s'. The max allowed ID is %d",
2731 args[*arg-1], MAX_SESS_STKCTR-1);
2732 return ACT_RET_PRS_ERR;
2733 }
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002734 }
Emeric Brun877b0b52021-06-30 18:57:49 +02002735 rule->action_ptr = action_set_gpt;
2736 }
2737 else if (*cmd_name == '0') {
2738 cmd_name++;
2739 if (*cmd_name == '\0') {
2740 /* default stick table id. */
2741 rule->arg.gpt.sc = 0;
2742 } else {
2743 /* parse the stick table id. */
2744 if (*cmd_name != '(') {
2745 memprintf(err, "invalid stick table track ID '%s'. Expects sc-set-gpt0(<Track ID>)", args[*arg-1]);
2746 return ACT_RET_PRS_ERR;
2747 }
2748 cmd_name++; /* jump the '(' */
2749 rule->arg.gpt.sc = strtol(cmd_name, &error, 10); /* Convert stick table id. */
2750 if (*error != ')') {
2751 memprintf(err, "invalid stick table track ID '%s'. Expects sc-set-gpt0(<Track ID>)", args[*arg-1]);
2752 return ACT_RET_PRS_ERR;
2753 }
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002754
Emeric Brun877b0b52021-06-30 18:57:49 +02002755 if (rule->arg.gpt.sc >= MAX_SESS_STKCTR) {
2756 memprintf(err, "invalid stick table track ID '%s'. The max allowed ID is %d",
2757 args[*arg-1], MAX_SESS_STKCTR-1);
2758 return ACT_RET_PRS_ERR;
2759 }
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002760 }
Emeric Brun877b0b52021-06-30 18:57:49 +02002761 rule->action_ptr = action_set_gpt0;
2762 }
2763 else {
2764 /* default stick table id. */
2765 memprintf(err, "invalid gpt ID '%s'. Expects sc-set-gpt(<GPT ID>,<Track ID>)", args[*arg-1]);
2766 return ACT_RET_PRS_ERR;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002767 }
2768
Willy Tarreauece4c4a2021-08-24 14:57:28 +02002769 /* value may be either an integer or an expression */
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002770 rule->arg.gpt.expr = NULL;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002771 rule->arg.gpt.value = strtol(args[*arg], &error, 10);
Willy Tarreauece4c4a2021-08-24 14:57:28 +02002772 if (*error == '\0') {
2773 /* valid integer, skip it */
2774 (*arg)++;
2775 } else {
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002776 rule->arg.gpt.expr = sample_parse_expr((char **)args, arg, px->conf.args.file,
Willy Tarreaue3b57bf2020-02-14 16:50:14 +01002777 px->conf.args.line, err, &px->conf.args, NULL);
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002778 if (!rule->arg.gpt.expr)
2779 return ACT_RET_PRS_ERR;
2780
2781 switch (rule->from) {
2782 case ACT_F_TCP_REQ_SES: smp_val = SMP_VAL_FE_SES_ACC; break;
2783 case ACT_F_TCP_REQ_CNT: smp_val = SMP_VAL_FE_REQ_CNT; break;
2784 case ACT_F_TCP_RES_CNT: smp_val = SMP_VAL_BE_RES_CNT; break;
2785 case ACT_F_HTTP_REQ: smp_val = SMP_VAL_FE_HRQ_HDR; break;
2786 case ACT_F_HTTP_RES: smp_val = SMP_VAL_BE_HRS_HDR; break;
2787 default:
2788 memprintf(err, "internal error, unexpected rule->from=%d, please report this bug!", rule->from);
2789 return ACT_RET_PRS_ERR;
2790 }
2791 if (!(rule->arg.gpt.expr->fetch->val & smp_val)) {
2792 memprintf(err, "fetch method '%s' extracts information from '%s', none of which is available here", args[*arg-1],
2793 sample_src_names(rule->arg.gpt.expr->fetch->use));
2794 free(rule->arg.gpt.expr);
2795 return ACT_RET_PRS_ERR;
2796 }
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002797 }
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002798
Thierry FOURNIER42148732015-09-02 17:17:33 +02002799 rule->action = ACT_CUSTOM;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002800
2801 return ACT_RET_PRS_OK;
2802}
2803
Willy Tarreau7d562212016-11-25 16:10:05 +01002804/* set temp integer to the number of used entries in the table pointed to by expr.
2805 * Accepts exactly 1 argument of type table.
2806 */
2807static int
2808smp_fetch_table_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
2809{
2810 smp->flags = SMP_F_VOL_TEST;
2811 smp->data.type = SMP_T_SINT;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002812 smp->data.u.sint = args->data.t->current;
Willy Tarreau7d562212016-11-25 16:10:05 +01002813 return 1;
2814}
2815
2816/* set temp integer to the number of free entries in the table pointed to by expr.
2817 * Accepts exactly 1 argument of type table.
2818 */
2819static int
2820smp_fetch_table_avl(const struct arg *args, struct sample *smp, const char *kw, void *private)
2821{
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002822 struct stktable *t;
Willy Tarreau7d562212016-11-25 16:10:05 +01002823
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002824 t = args->data.t;
Willy Tarreau7d562212016-11-25 16:10:05 +01002825 smp->flags = SMP_F_VOL_TEST;
2826 smp->data.type = SMP_T_SINT;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002827 smp->data.u.sint = t->size - t->current;
Willy Tarreau7d562212016-11-25 16:10:05 +01002828 return 1;
2829}
2830
2831/* Returns a pointer to a stkctr depending on the fetch keyword name.
2832 * It is designed to be called as sc[0-9]_* sc_* or src_* exclusively.
2833 * sc[0-9]_* will return a pointer to the respective field in the
2834 * stream <l4>. sc_* requires an UINT argument specifying the stick
2835 * counter number. src_* will fill a locally allocated structure with
2836 * the table and entry corresponding to what is specified with src_*.
2837 * NULL may be returned if the designated stkctr is not tracked. For
2838 * the sc_* and sc[0-9]_* forms, an optional table argument may be
2839 * passed. When present, the currently tracked key is then looked up
2840 * in the specified table instead of the current table. The purpose is
Ilya Shipitsin47d17182020-06-21 21:42:57 +05002841 * to be able to convert multiple values per key (eg: have gpc0 from
Willy Tarreau7d562212016-11-25 16:10:05 +01002842 * multiple tables). <strm> is allowed to be NULL, in which case only
2843 * the session will be consulted.
2844 */
2845struct stkctr *
Emeric Brun819fc6f2017-06-13 19:37:32 +02002846smp_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 +01002847{
Willy Tarreau7d562212016-11-25 16:10:05 +01002848 struct stkctr *stkptr;
2849 struct stksess *stksess;
2850 unsigned int num = kw[2] - '0';
2851 int arg = 0;
2852
2853 if (num == '_' - '0') {
2854 /* sc_* variant, args[0] = ctr# (mandatory) */
2855 num = args[arg++].data.sint;
Willy Tarreau7d562212016-11-25 16:10:05 +01002856 }
2857 else if (num > 9) { /* src_* variant, args[0] = table */
2858 struct stktable_key *key;
2859 struct connection *conn = objt_conn(sess->origin);
2860 struct sample smp;
2861
2862 if (!conn)
2863 return NULL;
2864
Joseph Herlant5662fa42018-11-15 13:43:28 -08002865 /* Fetch source address in a sample. */
Willy Tarreau7d562212016-11-25 16:10:05 +01002866 smp.px = NULL;
2867 smp.sess = sess;
2868 smp.strm = strm;
Amaury Denoyellec460c702021-05-12 10:17:47 +02002869 if (!smp_fetch_src || !smp_fetch_src(empty_arg_list, &smp, "src", NULL))
Willy Tarreau7d562212016-11-25 16:10:05 +01002870 return NULL;
2871
2872 /* Converts into key. */
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002873 key = smp_to_stkey(&smp, args->data.t);
Willy Tarreau7d562212016-11-25 16:10:05 +01002874 if (!key)
2875 return NULL;
2876
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002877 stkctr->table = args->data.t;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002878 stkctr_set_entry(stkctr, stktable_lookup_key(stkctr->table, key));
2879 return stkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002880 }
2881
2882 /* Here, <num> contains the counter number from 0 to 9 for
2883 * the sc[0-9]_ form, or even higher using sc_(num) if needed.
2884 * args[arg] is the first optional argument. We first lookup the
2885 * ctr form the stream, then from the session if it was not there.
Christopher Fauleta9fa88a2019-10-21 10:53:34 +02002886 * But we must be sure the counter does not exceed MAX_SESS_STKCTR.
Willy Tarreau7d562212016-11-25 16:10:05 +01002887 */
Christopher Fauleta9fa88a2019-10-21 10:53:34 +02002888 if (num >= MAX_SESS_STKCTR)
2889 return NULL;
Willy Tarreau7d562212016-11-25 16:10:05 +01002890
2891 if (strm)
2892 stkptr = &strm->stkctr[num];
2893 if (!strm || !stkctr_entry(stkptr)) {
2894 stkptr = &sess->stkctr[num];
2895 if (!stkctr_entry(stkptr))
2896 return NULL;
2897 }
2898
2899 stksess = stkctr_entry(stkptr);
2900 if (!stksess)
2901 return NULL;
2902
2903 if (unlikely(args[arg].type == ARGT_TAB)) {
2904 /* an alternate table was specified, let's look up the same key there */
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002905 stkctr->table = args[arg].data.t;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002906 stkctr_set_entry(stkctr, stktable_lookup(stkctr->table, stksess));
2907 return stkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002908 }
2909 return stkptr;
2910}
2911
2912/* same as smp_fetch_sc_stkctr() but dedicated to src_* and can create
2913 * the entry if it doesn't exist yet. This is needed for a few fetch
2914 * functions which need to create an entry, such as src_inc_gpc* and
2915 * src_clr_gpc*.
2916 */
2917struct stkctr *
Emeric Brun819fc6f2017-06-13 19:37:32 +02002918smp_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 +01002919{
Willy Tarreau7d562212016-11-25 16:10:05 +01002920 struct stktable_key *key;
2921 struct connection *conn = objt_conn(sess->origin);
2922 struct sample smp;
2923
2924 if (strncmp(kw, "src_", 4) != 0)
2925 return NULL;
2926
2927 if (!conn)
2928 return NULL;
2929
Joseph Herlant5662fa42018-11-15 13:43:28 -08002930 /* Fetch source address in a sample. */
Willy Tarreau7d562212016-11-25 16:10:05 +01002931 smp.px = NULL;
2932 smp.sess = sess;
2933 smp.strm = strm;
Amaury Denoyellec460c702021-05-12 10:17:47 +02002934 if (!smp_fetch_src || !smp_fetch_src(empty_arg_list, &smp, "src", NULL))
Willy Tarreau7d562212016-11-25 16:10:05 +01002935 return NULL;
2936
2937 /* Converts into key. */
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002938 key = smp_to_stkey(&smp, args->data.t);
Willy Tarreau7d562212016-11-25 16:10:05 +01002939 if (!key)
2940 return NULL;
2941
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002942 stkctr->table = args->data.t;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002943 stkctr_set_entry(stkctr, stktable_get_entry(stkctr->table, key));
2944 return stkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002945}
2946
2947/* set return a boolean indicating if the requested stream counter is
2948 * currently being tracked or not.
2949 * Supports being called as "sc[0-9]_tracked" only.
2950 */
2951static int
2952smp_fetch_sc_tracked(const struct arg *args, struct sample *smp, const char *kw, void *private)
2953{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002954 struct stkctr tmpstkctr;
2955 struct stkctr *stkctr;
2956
Willy Tarreau7d562212016-11-25 16:10:05 +01002957 smp->flags = SMP_F_VOL_TEST;
2958 smp->data.type = SMP_T_BOOL;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002959 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2960 smp->data.u.sint = !!stkctr;
2961
2962 /* release the ref count */
Dirkjan Bussinkff57f1b2018-09-14 14:31:22 +02002963 if (stkctr == &tmpstkctr)
Emeric Brun819fc6f2017-06-13 19:37:32 +02002964 stktable_release(stkctr->table, stkctr_entry(stkctr));
2965
Emeric Brun877b0b52021-06-30 18:57:49 +02002966 return 1;
2967}
2968
2969/* set <smp> to the General Purpose Tag of index set as first arg
2970 * to value from the stream's tracked frontend counters or from the src.
2971 * Supports being called as "sc_get_gpt(<gpt-idx>,<sc-idx>[,<table>])" or
2972 * "src_get_gpt(<gpt-idx>[,<table>])" only. Value zero is returned if
2973 * the key is new or gpt is not stored.
2974 */
2975static int
2976smp_fetch_sc_get_gpt(const struct arg *args, struct sample *smp, const char *kw, void *private)
2977{
2978 struct stkctr tmpstkctr;
2979 struct stkctr *stkctr;
2980 unsigned int idx;
2981
2982 idx = args[0].data.sint;
2983
2984 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args + 1, kw, &tmpstkctr);
2985 if (!stkctr)
2986 return 0;
2987
2988 smp->flags = SMP_F_VOL_TEST;
2989 smp->data.type = SMP_T_SINT;
2990 smp->data.u.sint = 0;
2991
2992 if (stkctr_entry(stkctr)) {
2993 void *ptr;
2994
2995 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPT, idx);
2996 if (!ptr) {
2997 if (stkctr == &tmpstkctr)
2998 stktable_release(stkctr->table, stkctr_entry(stkctr));
2999 return 0; /* parameter not stored */
3000 }
3001
3002 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3003
3004 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
3005
3006 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3007
3008 if (stkctr == &tmpstkctr)
3009 stktable_release(stkctr->table, stkctr_entry(stkctr));
3010 }
Willy Tarreau7d562212016-11-25 16:10:05 +01003011 return 1;
3012}
3013
3014/* set <smp> to the General Purpose Flag 0 value from the stream's tracked
3015 * frontend counters or from the src.
3016 * Supports being called as "sc[0-9]_get_gpc0" or "src_get_gpt0" only. Value
3017 * zero is returned if the key is new.
3018 */
3019static int
3020smp_fetch_sc_get_gpt0(const struct arg *args, struct sample *smp, const char *kw, void *private)
3021{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003022 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003023 struct stkctr *stkctr;
3024
Emeric Brun819fc6f2017-06-13 19:37:32 +02003025 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003026 if (!stkctr)
3027 return 0;
3028
3029 smp->flags = SMP_F_VOL_TEST;
3030 smp->data.type = SMP_T_SINT;
3031 smp->data.u.sint = 0;
3032
Emeric Brun819fc6f2017-06-13 19:37:32 +02003033 if (stkctr_entry(stkctr)) {
3034 void *ptr;
3035
3036 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPT0);
Emeric Brunf7ab0bf2021-06-30 18:58:22 +02003037 if (!ptr)
3038 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPT, 0);
3039
Emeric Brun4d7ada82021-06-30 19:04:16 +02003040 if (!ptr) {
3041 if (stkctr == &tmpstkctr)
3042 stktable_release(stkctr->table, stkctr_entry(stkctr));
3043 return 0; /* parameter not stored */
3044 }
3045
3046 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3047
3048 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
3049
3050 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3051
3052 if (stkctr == &tmpstkctr)
3053 stktable_release(stkctr->table, stkctr_entry(stkctr));
3054 }
3055 return 1;
3056}
3057
3058/* set <smp> to the GPC[args(0)]'s value from the stream's tracked
3059 * frontend counters or from the src.
3060 * Supports being called as "sc_get_gpc(<gpc-idx>,<sc-idx>[,<table>])" or
3061 * "src_get_gpc(<gpc-idx>[,<table>])" only. Value
3062 * Value zero is returned if the key is new or gpc is not stored.
3063 */
3064static int
3065smp_fetch_sc_get_gpc(const struct arg *args, struct sample *smp, const char *kw, void *private)
3066{
3067 struct stkctr tmpstkctr;
3068 struct stkctr *stkctr;
3069 unsigned int idx;
3070
3071 idx = args[0].data.sint;
3072
3073 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args + 1, kw, &tmpstkctr);
3074 if (!stkctr)
3075 return 0;
3076
3077 smp->flags = SMP_F_VOL_TEST;
3078 smp->data.type = SMP_T_SINT;
3079 smp->data.u.sint = 0;
3080
3081 if (stkctr_entry(stkctr) != NULL) {
3082 void *ptr;
3083
3084 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC, idx);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003085 if (!ptr) {
3086 if (stkctr == &tmpstkctr)
3087 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003088 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003089 }
3090
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003091 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003092
Emeric Brun0e3457b2021-06-30 17:18:28 +02003093 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003094
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003095 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003096
3097 if (stkctr == &tmpstkctr)
3098 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003099 }
3100 return 1;
3101}
3102
3103/* set <smp> to the General Purpose Counter 0 value from the stream's tracked
3104 * frontend counters or from the src.
3105 * Supports being called as "sc[0-9]_get_gpc0" or "src_get_gpc0" only. Value
3106 * zero is returned if the key is new.
3107 */
3108static int
3109smp_fetch_sc_get_gpc0(const struct arg *args, struct sample *smp, const char *kw, void *private)
3110{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003111 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003112 struct stkctr *stkctr;
3113
Emeric Brun819fc6f2017-06-13 19:37:32 +02003114 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003115 if (!stkctr)
3116 return 0;
3117
3118 smp->flags = SMP_F_VOL_TEST;
3119 smp->data.type = SMP_T_SINT;
3120 smp->data.u.sint = 0;
3121
3122 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003123 void *ptr;
3124
3125 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0);
3126 if (!ptr) {
Emeric Brun726783d2021-06-30 19:06:43 +02003127 /* fallback on the gpc array */
3128 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC, 0);
3129 }
3130
3131 if (!ptr) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003132 if (stkctr == &tmpstkctr)
3133 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003134 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003135 }
3136
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003137 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003138
Emeric Brun0e3457b2021-06-30 17:18:28 +02003139 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003140
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003141 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003142
3143 if (stkctr == &tmpstkctr)
3144 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003145 }
3146 return 1;
3147}
3148
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003149/* set <smp> to the General Purpose Counter 1 value from the stream's tracked
3150 * frontend counters or from the src.
3151 * Supports being called as "sc[0-9]_get_gpc1" or "src_get_gpc1" only. Value
3152 * zero is returned if the key is new.
3153 */
3154static int
3155smp_fetch_sc_get_gpc1(const struct arg *args, struct sample *smp, const char *kw, void *private)
3156{
3157 struct stkctr tmpstkctr;
3158 struct stkctr *stkctr;
3159
3160 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
3161 if (!stkctr)
3162 return 0;
3163
3164 smp->flags = SMP_F_VOL_TEST;
3165 smp->data.type = SMP_T_SINT;
3166 smp->data.u.sint = 0;
3167
3168 if (stkctr_entry(stkctr) != NULL) {
3169 void *ptr;
3170
3171 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1);
3172 if (!ptr) {
Emeric Brun726783d2021-06-30 19:06:43 +02003173 /* fallback on the gpc array */
3174 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC, 1);
3175 }
3176
3177 if (!ptr) {
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003178 if (stkctr == &tmpstkctr)
3179 stktable_release(stkctr->table, stkctr_entry(stkctr));
3180 return 0; /* parameter not stored */
3181 }
3182
3183 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3184
Emeric Brun0e3457b2021-06-30 17:18:28 +02003185 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003186
3187 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3188
3189 if (stkctr == &tmpstkctr)
3190 stktable_release(stkctr->table, stkctr_entry(stkctr));
3191 }
3192 return 1;
3193}
3194
Emeric Brun4d7ada82021-06-30 19:04:16 +02003195/* set <smp> to the GPC[args(0)]'s event rate from the stream's
3196 * tracked frontend counters or from the src.
3197 * Supports being called as "sc_gpc_rate(<gpc-idx>,<sc-idx>[,<table])"
3198 * or "src_gpc_rate(<gpc-idx>[,<table>])" only.
3199 * Value zero is returned if the key is new or gpc_rate is not stored.
3200 */
3201static int
3202smp_fetch_sc_gpc_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3203{
3204 struct stkctr tmpstkctr;
3205 struct stkctr *stkctr;
3206 unsigned int idx;
3207
3208 idx = args[0].data.sint;
3209
3210 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args + 1, kw, &tmpstkctr);
3211 if (!stkctr)
3212 return 0;
3213
3214 smp->flags = SMP_F_VOL_TEST;
3215 smp->data.type = SMP_T_SINT;
3216 smp->data.u.sint = 0;
3217 if (stkctr_entry(stkctr) != NULL) {
3218 void *ptr;
3219
3220 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC_RATE, idx);
3221 if (!ptr) {
3222 if (stkctr == &tmpstkctr)
3223 stktable_release(stkctr->table, stkctr_entry(stkctr));
3224 return 0; /* parameter not stored */
3225 }
3226
3227 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3228
3229 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
3230 stkctr->table->data_arg[STKTABLE_DT_GPC_RATE].u);
3231
3232 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3233
3234 if (stkctr == &tmpstkctr)
3235 stktable_release(stkctr->table, stkctr_entry(stkctr));
3236 }
3237 return 1;
3238}
3239
Willy Tarreau7d562212016-11-25 16:10:05 +01003240/* set <smp> to the General Purpose Counter 0's event rate from the stream's
3241 * tracked frontend counters or from the src.
3242 * Supports being called as "sc[0-9]_gpc0_rate" or "src_gpc0_rate" only.
3243 * Value zero is returned if the key is new.
3244 */
3245static int
3246smp_fetch_sc_gpc0_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3247{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003248 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003249 struct stkctr *stkctr;
Emeric Brun726783d2021-06-30 19:06:43 +02003250 unsigned int period;
Willy Tarreau7d562212016-11-25 16:10:05 +01003251
Emeric Brun819fc6f2017-06-13 19:37:32 +02003252 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003253 if (!stkctr)
3254 return 0;
3255
3256 smp->flags = SMP_F_VOL_TEST;
3257 smp->data.type = SMP_T_SINT;
3258 smp->data.u.sint = 0;
3259 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003260 void *ptr;
3261
3262 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0_RATE);
Emeric Brun726783d2021-06-30 19:06:43 +02003263 if (ptr) {
3264 period = stkctr->table->data_arg[STKTABLE_DT_GPC0_RATE].u;
3265 }
3266 else {
3267 /* fallback on the gpc array */
3268 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC_RATE, 0);
3269 if (ptr)
3270 period = stkctr->table->data_arg[STKTABLE_DT_GPC_RATE].u;
3271 }
3272
Emeric Brun819fc6f2017-06-13 19:37:32 +02003273 if (!ptr) {
3274 if (stkctr == &tmpstkctr)
3275 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003276 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003277 }
3278
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003279 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003280
Emeric Brun726783d2021-06-30 19:06:43 +02003281 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp), period);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003282
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003283 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003284
3285 if (stkctr == &tmpstkctr)
3286 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003287 }
3288 return 1;
3289}
3290
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003291/* set <smp> to the General Purpose Counter 1's event rate from the stream's
3292 * tracked frontend counters or from the src.
3293 * Supports being called as "sc[0-9]_gpc1_rate" or "src_gpc1_rate" only.
3294 * Value zero is returned if the key is new.
3295 */
3296static int
3297smp_fetch_sc_gpc1_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3298{
3299 struct stkctr tmpstkctr;
3300 struct stkctr *stkctr;
Emeric Brun726783d2021-06-30 19:06:43 +02003301 unsigned int period;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003302
3303 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
3304 if (!stkctr)
3305 return 0;
3306
3307 smp->flags = SMP_F_VOL_TEST;
3308 smp->data.type = SMP_T_SINT;
3309 smp->data.u.sint = 0;
3310 if (stkctr_entry(stkctr) != NULL) {
3311 void *ptr;
3312
3313 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1_RATE);
Emeric Brun726783d2021-06-30 19:06:43 +02003314 if (ptr) {
3315 period = stkctr->table->data_arg[STKTABLE_DT_GPC1_RATE].u;
3316 }
3317 else {
3318 /* fallback on the gpc array */
3319 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC_RATE, 1);
3320 if (ptr)
3321 period = stkctr->table->data_arg[STKTABLE_DT_GPC_RATE].u;
3322 }
3323
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003324 if (!ptr) {
3325 if (stkctr == &tmpstkctr)
3326 stktable_release(stkctr->table, stkctr_entry(stkctr));
3327 return 0; /* parameter not stored */
3328 }
3329
3330 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3331
Emeric Brun726783d2021-06-30 19:06:43 +02003332 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 +01003333
3334 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3335
3336 if (stkctr == &tmpstkctr)
3337 stktable_release(stkctr->table, stkctr_entry(stkctr));
3338 }
3339 return 1;
3340}
3341
Emeric Brun4d7ada82021-06-30 19:04:16 +02003342/* Increment the GPC[args(0)] value from the stream's tracked
3343 * frontend counters and return it into temp integer.
3344 * Supports being called as "sc_inc_gpc(<gpc-idx>,<sc-idx>[,<table>])"
3345 * or "src_inc_gpc(<gpc-idx>[,<table>])" only.
3346 */
3347static int
3348smp_fetch_sc_inc_gpc(const struct arg *args, struct sample *smp, const char *kw, void *private)
3349{
3350 struct stkctr tmpstkctr;
3351 struct stkctr *stkctr;
3352 unsigned int idx;
3353
3354 idx = args[0].data.sint;
3355
3356 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args + 1, kw, &tmpstkctr);
3357 if (!stkctr)
3358 return 0;
3359
3360 smp->flags = SMP_F_VOL_TEST;
3361 smp->data.type = SMP_T_SINT;
3362 smp->data.u.sint = 0;
3363
3364 if (!stkctr_entry(stkctr))
3365 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
3366
3367 if (stkctr && stkctr_entry(stkctr)) {
3368 void *ptr1,*ptr2;
3369
3370
3371 /* First, update gpc0_rate if it's tracked. Second, update its
3372 * gpc0 if tracked. Returns gpc0's value otherwise the curr_ctr.
3373 */
3374 ptr1 = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC_RATE, idx);
3375 ptr2 = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC, idx);
3376 if (ptr1 || ptr2) {
3377 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3378
3379 if (ptr1) {
3380 update_freq_ctr_period(&stktable_data_cast(ptr1, std_t_frqp),
3381 stkctr->table->data_arg[STKTABLE_DT_GPC_RATE].u, 1);
3382 smp->data.u.sint = (&stktable_data_cast(ptr1, std_t_frqp))->curr_ctr;
3383 }
3384
3385 if (ptr2)
3386 smp->data.u.sint = ++stktable_data_cast(ptr2, std_t_uint);
3387
3388 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3389
3390 /* If data was modified, we need to touch to re-schedule sync */
3391 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
3392 }
3393 else if (stkctr == &tmpstkctr)
3394 stktable_release(stkctr->table, stkctr_entry(stkctr));
3395 }
3396 return 1;
3397}
3398
Willy Tarreau7d562212016-11-25 16:10:05 +01003399/* Increment the General Purpose Counter 0 value from the stream's tracked
3400 * frontend counters and return it into temp integer.
3401 * Supports being called as "sc[0-9]_inc_gpc0" or "src_inc_gpc0" only.
3402 */
3403static int
3404smp_fetch_sc_inc_gpc0(const struct arg *args, struct sample *smp, const char *kw, void *private)
3405{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003406 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003407 struct stkctr *stkctr;
Willy Tarreau5b654ad2021-07-06 18:51:12 +02003408 unsigned int period = 0;
Willy Tarreau7d562212016-11-25 16:10:05 +01003409
Emeric Brun819fc6f2017-06-13 19:37:32 +02003410 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003411 if (!stkctr)
3412 return 0;
3413
3414 smp->flags = SMP_F_VOL_TEST;
3415 smp->data.type = SMP_T_SINT;
3416 smp->data.u.sint = 0;
3417
Emeric Brun819fc6f2017-06-13 19:37:32 +02003418 if (!stkctr_entry(stkctr))
3419 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003420
3421 if (stkctr && stkctr_entry(stkctr)) {
3422 void *ptr1,*ptr2;
3423
Emeric Brun819fc6f2017-06-13 19:37:32 +02003424
Willy Tarreau7d562212016-11-25 16:10:05 +01003425 /* First, update gpc0_rate if it's tracked. Second, update its
3426 * gpc0 if tracked. Returns gpc0's value otherwise the curr_ctr.
3427 */
3428 ptr1 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0_RATE);
Emeric Brun726783d2021-06-30 19:06:43 +02003429 if (ptr1) {
3430 period = stkctr->table->data_arg[STKTABLE_DT_GPC0_RATE].u;
3431 }
3432 else {
3433 /* fallback on the gpc array */
3434 ptr1 = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC_RATE, 0);
3435 if (ptr1)
3436 period = stkctr->table->data_arg[STKTABLE_DT_GPC_RATE].u;
3437 }
3438
Willy Tarreau7d562212016-11-25 16:10:05 +01003439 ptr2 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0);
Emeric Brun726783d2021-06-30 19:06:43 +02003440 if (!ptr2) {
3441 /* fallback on the gpc array */
3442 ptr2 = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC, 0);
3443 }
3444
Emeric Brun819fc6f2017-06-13 19:37:32 +02003445 if (ptr1 || ptr2) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003446 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Willy Tarreau7d562212016-11-25 16:10:05 +01003447
Emeric Brun819fc6f2017-06-13 19:37:32 +02003448 if (ptr1) {
Emeric Brun0e3457b2021-06-30 17:18:28 +02003449 update_freq_ctr_period(&stktable_data_cast(ptr1, std_t_frqp),
Emeric Brun726783d2021-06-30 19:06:43 +02003450 period, 1);
Emeric Brun0e3457b2021-06-30 17:18:28 +02003451 smp->data.u.sint = (&stktable_data_cast(ptr1, std_t_frqp))->curr_ctr;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003452 }
3453
3454 if (ptr2)
Emeric Brun0e3457b2021-06-30 17:18:28 +02003455 smp->data.u.sint = ++stktable_data_cast(ptr2, std_t_uint);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003456
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003457 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003458
3459 /* If data was modified, we need to touch to re-schedule sync */
3460 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
3461 }
3462 else if (stkctr == &tmpstkctr)
3463 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003464 }
3465 return 1;
3466}
3467
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003468/* Increment the General Purpose Counter 1 value from the stream's tracked
3469 * frontend counters and return it into temp integer.
3470 * Supports being called as "sc[0-9]_inc_gpc1" or "src_inc_gpc1" only.
3471 */
3472static int
3473smp_fetch_sc_inc_gpc1(const struct arg *args, struct sample *smp, const char *kw, void *private)
3474{
3475 struct stkctr tmpstkctr;
3476 struct stkctr *stkctr;
Willy Tarreau5b654ad2021-07-06 18:51:12 +02003477 unsigned int period = 0;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003478
3479 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
3480 if (!stkctr)
3481 return 0;
3482
3483 smp->flags = SMP_F_VOL_TEST;
3484 smp->data.type = SMP_T_SINT;
3485 smp->data.u.sint = 0;
3486
3487 if (!stkctr_entry(stkctr))
3488 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
3489
3490 if (stkctr && stkctr_entry(stkctr)) {
3491 void *ptr1,*ptr2;
3492
3493
3494 /* First, update gpc1_rate if it's tracked. Second, update its
3495 * gpc1 if tracked. Returns gpc1's value otherwise the curr_ctr.
3496 */
3497 ptr1 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1_RATE);
Emeric Brun726783d2021-06-30 19:06:43 +02003498 if (ptr1) {
3499 period = stkctr->table->data_arg[STKTABLE_DT_GPC1_RATE].u;
3500 }
3501 else {
3502 /* fallback on the gpc array */
3503 ptr1 = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC_RATE, 1);
3504 if (ptr1)
3505 period = stkctr->table->data_arg[STKTABLE_DT_GPC_RATE].u;
3506 }
3507
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003508 ptr2 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1);
Emeric Brun726783d2021-06-30 19:06:43 +02003509 if (!ptr2) {
3510 /* fallback on the gpc array */
3511 ptr2 = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC, 1);
3512 }
3513
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003514 if (ptr1 || ptr2) {
3515 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3516
3517 if (ptr1) {
Emeric Brun0e3457b2021-06-30 17:18:28 +02003518 update_freq_ctr_period(&stktable_data_cast(ptr1, std_t_frqp),
Emeric Brun726783d2021-06-30 19:06:43 +02003519 period, 1);
Emeric Brun0e3457b2021-06-30 17:18:28 +02003520 smp->data.u.sint = (&stktable_data_cast(ptr1, std_t_frqp))->curr_ctr;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003521 }
3522
3523 if (ptr2)
Emeric Brun0e3457b2021-06-30 17:18:28 +02003524 smp->data.u.sint = ++stktable_data_cast(ptr2, std_t_uint);
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003525
3526 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3527
3528 /* If data was modified, we need to touch to re-schedule sync */
3529 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
3530 }
3531 else if (stkctr == &tmpstkctr)
3532 stktable_release(stkctr->table, stkctr_entry(stkctr));
3533 }
3534 return 1;
3535}
3536
Emeric Brun4d7ada82021-06-30 19:04:16 +02003537/* Clear the GPC[args(0)] value from the stream's tracked
3538 * frontend counters and return its previous value into temp integer.
3539 * Supports being called as "sc_clr_gpc(<gpc-idx>,<sc-idx>[,<table>])"
3540 * or "src_clr_gpc(<gpc-idx>[,<table>])" only.
3541 */
3542static int
3543smp_fetch_sc_clr_gpc(const struct arg *args, struct sample *smp, const char *kw, void *private)
3544{
3545 struct stkctr tmpstkctr;
3546 struct stkctr *stkctr;
3547 unsigned int idx;
3548
3549 idx = args[0].data.sint;
3550
3551 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args + 1, kw, &tmpstkctr);
3552 if (!stkctr)
3553 return 0;
3554
3555 smp->flags = SMP_F_VOL_TEST;
3556 smp->data.type = SMP_T_SINT;
3557 smp->data.u.sint = 0;
3558
3559 if (!stkctr_entry(stkctr))
3560 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
3561
3562 if (stkctr && stkctr_entry(stkctr)) {
3563 void *ptr;
3564
3565 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC, idx);
3566 if (!ptr) {
3567 if (stkctr == &tmpstkctr)
3568 stktable_release(stkctr->table, stkctr_entry(stkctr));
3569 return 0; /* parameter not stored */
3570 }
3571
3572 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3573
3574 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
3575 stktable_data_cast(ptr, std_t_uint) = 0;
3576
3577 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3578
3579 /* If data was modified, we need to touch to re-schedule sync */
3580 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
3581 }
3582 return 1;
3583}
3584
Willy Tarreau7d562212016-11-25 16:10:05 +01003585/* Clear the General Purpose Counter 0 value from the stream's tracked
3586 * frontend counters and return its previous value into temp integer.
3587 * Supports being called as "sc[0-9]_clr_gpc0" or "src_clr_gpc0" only.
3588 */
3589static int
3590smp_fetch_sc_clr_gpc0(const struct arg *args, struct sample *smp, const char *kw, void *private)
3591{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003592 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003593 struct stkctr *stkctr;
3594
Emeric Brun819fc6f2017-06-13 19:37:32 +02003595 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003596 if (!stkctr)
3597 return 0;
3598
3599 smp->flags = SMP_F_VOL_TEST;
3600 smp->data.type = SMP_T_SINT;
3601 smp->data.u.sint = 0;
3602
Emeric Brun819fc6f2017-06-13 19:37:32 +02003603 if (!stkctr_entry(stkctr))
3604 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003605
Emeric Brun819fc6f2017-06-13 19:37:32 +02003606 if (stkctr && stkctr_entry(stkctr)) {
3607 void *ptr;
3608
3609 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0);
3610 if (!ptr) {
Emeric Brun726783d2021-06-30 19:06:43 +02003611 /* fallback on the gpc array */
3612 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC, 0);
3613 }
3614
3615 if (!ptr) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003616 if (stkctr == &tmpstkctr)
3617 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003618 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003619 }
3620
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003621 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003622
Emeric Brun0e3457b2021-06-30 17:18:28 +02003623 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
3624 stktable_data_cast(ptr, std_t_uint) = 0;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003625
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003626 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003627
Willy Tarreau7d562212016-11-25 16:10:05 +01003628 /* If data was modified, we need to touch to re-schedule sync */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003629 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
Willy Tarreau7d562212016-11-25 16:10:05 +01003630 }
3631 return 1;
3632}
3633
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003634/* Clear the General Purpose Counter 1 value from the stream's tracked
3635 * frontend counters and return its previous value into temp integer.
3636 * Supports being called as "sc[0-9]_clr_gpc1" or "src_clr_gpc1" only.
3637 */
3638static int
3639smp_fetch_sc_clr_gpc1(const struct arg *args, struct sample *smp, const char *kw, void *private)
3640{
3641 struct stkctr tmpstkctr;
3642 struct stkctr *stkctr;
3643
3644 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
3645 if (!stkctr)
3646 return 0;
3647
3648 smp->flags = SMP_F_VOL_TEST;
3649 smp->data.type = SMP_T_SINT;
3650 smp->data.u.sint = 0;
3651
3652 if (!stkctr_entry(stkctr))
3653 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
3654
3655 if (stkctr && stkctr_entry(stkctr)) {
3656 void *ptr;
3657
3658 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1);
3659 if (!ptr) {
Emeric Brun726783d2021-06-30 19:06:43 +02003660 /* fallback on the gpc array */
3661 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC, 1);
3662 }
3663
3664 if (!ptr) {
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003665 if (stkctr == &tmpstkctr)
3666 stktable_release(stkctr->table, stkctr_entry(stkctr));
3667 return 0; /* parameter not stored */
3668 }
3669
3670 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3671
Emeric Brun0e3457b2021-06-30 17:18:28 +02003672 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
3673 stktable_data_cast(ptr, std_t_uint) = 0;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003674
3675 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3676
3677 /* If data was modified, we need to touch to re-schedule sync */
3678 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
3679 }
3680 return 1;
3681}
3682
Willy Tarreau7d562212016-11-25 16:10:05 +01003683/* set <smp> to the cumulated number of connections from the stream's tracked
3684 * frontend counters. Supports being called as "sc[0-9]_conn_cnt" or
3685 * "src_conn_cnt" only.
3686 */
3687static int
3688smp_fetch_sc_conn_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
3689{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003690 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003691 struct stkctr *stkctr;
3692
Emeric Brun819fc6f2017-06-13 19:37:32 +02003693 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003694 if (!stkctr)
3695 return 0;
3696
3697 smp->flags = SMP_F_VOL_TEST;
3698 smp->data.type = SMP_T_SINT;
3699 smp->data.u.sint = 0;
3700 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003701 void *ptr;
3702
3703 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_CONN_CNT);
3704 if (!ptr) {
3705 if (stkctr == &tmpstkctr)
3706 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003707 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003708 }
3709
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003710 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003711
Emeric Brun0e3457b2021-06-30 17:18:28 +02003712 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003713
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003714 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003715
3716 if (stkctr == &tmpstkctr)
3717 stktable_release(stkctr->table, stkctr_entry(stkctr));
3718
3719
Willy Tarreau7d562212016-11-25 16:10:05 +01003720 }
3721 return 1;
3722}
3723
3724/* set <smp> to the connection rate from the stream's tracked frontend
3725 * counters. Supports being called as "sc[0-9]_conn_rate" or "src_conn_rate"
3726 * only.
3727 */
3728static int
3729smp_fetch_sc_conn_rate(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_CONN_RATE);
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 = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Willy Tarreau7d562212016-11-25 16:10:05 +01003754 stkctr->table->data_arg[STKTABLE_DT_CONN_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003755
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003756 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003757
3758 if (stkctr == &tmpstkctr)
3759 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003760 }
3761 return 1;
3762}
3763
3764/* set temp integer to the number of connections from the stream's source address
3765 * in the table pointed to by expr, after updating it.
3766 * Accepts exactly 1 argument of type table.
3767 */
3768static int
3769smp_fetch_src_updt_conn_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
3770{
3771 struct connection *conn = objt_conn(smp->sess->origin);
3772 struct stksess *ts;
3773 struct stktable_key *key;
3774 void *ptr;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003775 struct stktable *t;
Willy Tarreau7d562212016-11-25 16:10:05 +01003776
3777 if (!conn)
3778 return 0;
3779
Joseph Herlant5662fa42018-11-15 13:43:28 -08003780 /* Fetch source address in a sample. */
Amaury Denoyellec460c702021-05-12 10:17:47 +02003781 if (!smp_fetch_src || !smp_fetch_src(empty_arg_list, smp, "src", NULL))
Willy Tarreau7d562212016-11-25 16:10:05 +01003782 return 0;
3783
3784 /* Converts into key. */
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003785 key = smp_to_stkey(smp, args->data.t);
Willy Tarreau7d562212016-11-25 16:10:05 +01003786 if (!key)
3787 return 0;
3788
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003789 t = args->data.t;
Willy Tarreau7d562212016-11-25 16:10:05 +01003790
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003791 if ((ts = stktable_get_entry(t, key)) == NULL)
Willy Tarreau7d562212016-11-25 16:10:05 +01003792 /* entry does not exist and could not be created */
3793 return 0;
3794
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003795 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_CONN_CNT);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003796 if (!ptr) {
Willy Tarreau7d562212016-11-25 16:10:05 +01003797 return 0; /* parameter not stored in this table */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003798 }
Willy Tarreau7d562212016-11-25 16:10:05 +01003799
3800 smp->data.type = SMP_T_SINT;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003801
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003802 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003803
Emeric Brun0e3457b2021-06-30 17:18:28 +02003804 smp->data.u.sint = ++stktable_data_cast(ptr, std_t_uint);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003805
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003806 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003807
Willy Tarreau7d562212016-11-25 16:10:05 +01003808 smp->flags = SMP_F_VOL_TEST;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003809
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003810 stktable_touch_local(t, ts, 1);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003811
3812 /* Touch was previously performed by stktable_update_key */
Willy Tarreau7d562212016-11-25 16:10:05 +01003813 return 1;
3814}
3815
3816/* set <smp> to the number of concurrent connections from the stream's tracked
3817 * frontend counters. Supports being called as "sc[0-9]_conn_cur" or
3818 * "src_conn_cur" only.
3819 */
3820static int
3821smp_fetch_sc_conn_cur(const struct arg *args, struct sample *smp, const char *kw, void *private)
3822{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003823 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003824 struct stkctr *stkctr;
3825
Emeric Brun819fc6f2017-06-13 19:37:32 +02003826 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003827 if (!stkctr)
3828 return 0;
3829
3830 smp->flags = SMP_F_VOL_TEST;
3831 smp->data.type = SMP_T_SINT;
3832 smp->data.u.sint = 0;
3833 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003834 void *ptr;
3835
3836 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_CONN_CUR);
3837 if (!ptr) {
3838 if (stkctr == &tmpstkctr)
3839 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003840 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003841 }
3842
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003843 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003844
Emeric Brun0e3457b2021-06-30 17:18:28 +02003845 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003846
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003847 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003848
3849 if (stkctr == &tmpstkctr)
3850 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003851 }
3852 return 1;
3853}
3854
3855/* set <smp> to the cumulated number of streams from the stream's tracked
3856 * frontend counters. Supports being called as "sc[0-9]_sess_cnt" or
3857 * "src_sess_cnt" only.
3858 */
3859static int
3860smp_fetch_sc_sess_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
3861{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003862 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003863 struct stkctr *stkctr;
3864
Emeric Brun819fc6f2017-06-13 19:37:32 +02003865 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003866 if (!stkctr)
3867 return 0;
3868
3869 smp->flags = SMP_F_VOL_TEST;
3870 smp->data.type = SMP_T_SINT;
3871 smp->data.u.sint = 0;
3872 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003873 void *ptr;
3874
3875 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_SESS_CNT);
3876 if (!ptr) {
3877 if (stkctr == &tmpstkctr)
3878 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003879 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003880 }
3881
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003882 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003883
Emeric Brun0e3457b2021-06-30 17:18:28 +02003884 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003885
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003886 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003887
3888 if (stkctr == &tmpstkctr)
3889 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003890 }
3891 return 1;
3892}
3893
3894/* set <smp> to the stream rate from the stream's tracked frontend counters.
3895 * Supports being called as "sc[0-9]_sess_rate" or "src_sess_rate" only.
3896 */
3897static int
3898smp_fetch_sc_sess_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3899{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003900 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003901 struct stkctr *stkctr;
3902
Emeric Brun819fc6f2017-06-13 19:37:32 +02003903 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003904 if (!stkctr)
3905 return 0;
3906
3907 smp->flags = SMP_F_VOL_TEST;
3908 smp->data.type = SMP_T_SINT;
3909 smp->data.u.sint = 0;
3910 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003911 void *ptr;
3912
3913 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_SESS_RATE);
3914 if (!ptr) {
3915 if (stkctr == &tmpstkctr)
3916 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003917 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003918 }
3919
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003920 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003921
Emeric Brun0e3457b2021-06-30 17:18:28 +02003922 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Willy Tarreau7d562212016-11-25 16:10:05 +01003923 stkctr->table->data_arg[STKTABLE_DT_SESS_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003924
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003925 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003926
3927 if (stkctr == &tmpstkctr)
3928 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003929 }
3930 return 1;
3931}
3932
3933/* set <smp> to the cumulated number of HTTP requests from the stream's tracked
3934 * frontend counters. Supports being called as "sc[0-9]_http_req_cnt" or
3935 * "src_http_req_cnt" only.
3936 */
3937static int
3938smp_fetch_sc_http_req_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
3939{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003940 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003941 struct stkctr *stkctr;
3942
Emeric Brun819fc6f2017-06-13 19:37:32 +02003943 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003944 if (!stkctr)
3945 return 0;
3946
3947 smp->flags = SMP_F_VOL_TEST;
3948 smp->data.type = SMP_T_SINT;
3949 smp->data.u.sint = 0;
3950 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003951 void *ptr;
3952
3953 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_REQ_CNT);
3954 if (!ptr) {
3955 if (stkctr == &tmpstkctr)
3956 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003957 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003958 }
3959
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003960 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003961
Emeric Brun0e3457b2021-06-30 17:18:28 +02003962 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003963
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003964 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003965
3966 if (stkctr == &tmpstkctr)
3967 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003968 }
3969 return 1;
3970}
3971
3972/* set <smp> to the HTTP request rate from the stream's tracked frontend
3973 * counters. Supports being called as "sc[0-9]_http_req_rate" or
3974 * "src_http_req_rate" only.
3975 */
3976static int
3977smp_fetch_sc_http_req_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3978{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003979 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003980 struct stkctr *stkctr;
3981
Emeric Brun819fc6f2017-06-13 19:37:32 +02003982 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003983 if (!stkctr)
3984 return 0;
3985
3986 smp->flags = SMP_F_VOL_TEST;
3987 smp->data.type = SMP_T_SINT;
3988 smp->data.u.sint = 0;
3989 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003990 void *ptr;
3991
3992 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_REQ_RATE);
3993 if (!ptr) {
3994 if (stkctr == &tmpstkctr)
3995 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003996 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003997 }
3998
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003999 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004000
Emeric Brun0e3457b2021-06-30 17:18:28 +02004001 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Willy Tarreau7d562212016-11-25 16:10:05 +01004002 stkctr->table->data_arg[STKTABLE_DT_HTTP_REQ_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004003
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004004 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004005
4006 if (stkctr == &tmpstkctr)
4007 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004008 }
4009 return 1;
4010}
4011
4012/* set <smp> to the cumulated number of HTTP requests errors from the stream's
4013 * tracked frontend counters. Supports being called as "sc[0-9]_http_err_cnt" or
4014 * "src_http_err_cnt" only.
4015 */
4016static int
4017smp_fetch_sc_http_err_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
4018{
Emeric Brun819fc6f2017-06-13 19:37:32 +02004019 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01004020 struct stkctr *stkctr;
4021
Emeric Brun819fc6f2017-06-13 19:37:32 +02004022 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01004023 if (!stkctr)
4024 return 0;
4025
4026 smp->flags = SMP_F_VOL_TEST;
4027 smp->data.type = SMP_T_SINT;
4028 smp->data.u.sint = 0;
4029 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02004030 void *ptr;
4031
4032 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_ERR_CNT);
4033 if (!ptr) {
4034 if (stkctr == &tmpstkctr)
4035 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004036 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02004037 }
4038
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004039 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004040
Emeric Brun0e3457b2021-06-30 17:18:28 +02004041 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004042
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004043 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004044
4045 if (stkctr == &tmpstkctr)
4046 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004047 }
4048 return 1;
4049}
4050
4051/* set <smp> to the HTTP request error rate from the stream's tracked frontend
4052 * counters. Supports being called as "sc[0-9]_http_err_rate" or
4053 * "src_http_err_rate" only.
4054 */
4055static int
4056smp_fetch_sc_http_err_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
4057{
Emeric Brun819fc6f2017-06-13 19:37:32 +02004058 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01004059 struct stkctr *stkctr;
4060
Emeric Brun819fc6f2017-06-13 19:37:32 +02004061 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01004062 if (!stkctr)
4063 return 0;
4064
4065 smp->flags = SMP_F_VOL_TEST;
4066 smp->data.type = SMP_T_SINT;
4067 smp->data.u.sint = 0;
4068 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02004069 void *ptr;
4070
4071 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_ERR_RATE);
4072 if (!ptr) {
4073 if (stkctr == &tmpstkctr)
4074 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004075 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02004076 }
4077
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004078 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004079
Emeric Brun0e3457b2021-06-30 17:18:28 +02004080 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Willy Tarreau7d562212016-11-25 16:10:05 +01004081 stkctr->table->data_arg[STKTABLE_DT_HTTP_ERR_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004082
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004083 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004084
4085 if (stkctr == &tmpstkctr)
4086 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004087 }
4088 return 1;
4089}
4090
Willy Tarreau826f3ab2021-02-10 12:07:15 +01004091/* set <smp> to the cumulated number of HTTP response failures from the stream's
4092 * tracked frontend counters. Supports being called as "sc[0-9]_http_fail_cnt" or
4093 * "src_http_fail_cnt" only.
4094 */
4095static int
4096smp_fetch_sc_http_fail_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
4097{
4098 struct stkctr tmpstkctr;
4099 struct stkctr *stkctr;
4100
4101 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
4102 if (!stkctr)
4103 return 0;
4104
4105 smp->flags = SMP_F_VOL_TEST;
4106 smp->data.type = SMP_T_SINT;
4107 smp->data.u.sint = 0;
4108 if (stkctr_entry(stkctr) != NULL) {
4109 void *ptr;
4110
4111 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_FAIL_CNT);
4112 if (!ptr) {
4113 if (stkctr == &tmpstkctr)
4114 stktable_release(stkctr->table, stkctr_entry(stkctr));
4115 return 0; /* parameter not stored */
4116 }
4117
4118 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
4119
Emeric Brun0e3457b2021-06-30 17:18:28 +02004120 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Willy Tarreau826f3ab2021-02-10 12:07:15 +01004121
4122 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
4123
4124 if (stkctr == &tmpstkctr)
4125 stktable_release(stkctr->table, stkctr_entry(stkctr));
4126 }
4127 return 1;
4128}
4129
4130/* set <smp> to the HTTP response failure rate from the stream's tracked frontend
4131 * counters. Supports being called as "sc[0-9]_http_fail_rate" or
4132 * "src_http_fail_rate" only.
4133 */
4134static int
4135smp_fetch_sc_http_fail_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
4136{
4137 struct stkctr tmpstkctr;
4138 struct stkctr *stkctr;
4139
4140 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
4141 if (!stkctr)
4142 return 0;
4143
4144 smp->flags = SMP_F_VOL_TEST;
4145 smp->data.type = SMP_T_SINT;
4146 smp->data.u.sint = 0;
4147 if (stkctr_entry(stkctr) != NULL) {
4148 void *ptr;
4149
4150 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_FAIL_RATE);
4151 if (!ptr) {
4152 if (stkctr == &tmpstkctr)
4153 stktable_release(stkctr->table, stkctr_entry(stkctr));
4154 return 0; /* parameter not stored */
4155 }
4156
4157 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
4158
Emeric Brun0e3457b2021-06-30 17:18:28 +02004159 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Willy Tarreau826f3ab2021-02-10 12:07:15 +01004160 stkctr->table->data_arg[STKTABLE_DT_HTTP_FAIL_RATE].u);
4161
4162 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
4163
4164 if (stkctr == &tmpstkctr)
4165 stktable_release(stkctr->table, stkctr_entry(stkctr));
4166 }
4167 return 1;
4168}
4169
Willy Tarreau7d562212016-11-25 16:10:05 +01004170/* set <smp> to the number of kbytes received from clients, as found in the
4171 * stream's tracked frontend counters. Supports being called as
4172 * "sc[0-9]_kbytes_in" or "src_kbytes_in" only.
4173 */
4174static int
4175smp_fetch_sc_kbytes_in(const struct arg *args, struct sample *smp, const char *kw, void *private)
4176{
Emeric Brun819fc6f2017-06-13 19:37:32 +02004177 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01004178 struct stkctr *stkctr;
4179
Emeric Brun819fc6f2017-06-13 19:37:32 +02004180 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01004181 if (!stkctr)
4182 return 0;
4183
4184 smp->flags = SMP_F_VOL_TEST;
4185 smp->data.type = SMP_T_SINT;
4186 smp->data.u.sint = 0;
4187 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02004188 void *ptr;
4189
4190 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_IN_CNT);
4191 if (!ptr) {
4192 if (stkctr == &tmpstkctr)
4193 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004194 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02004195 }
4196
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004197 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004198
Emeric Brun0e3457b2021-06-30 17:18:28 +02004199 smp->data.u.sint = stktable_data_cast(ptr, std_t_ull) >> 10;
Emeric Brun819fc6f2017-06-13 19:37:32 +02004200
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004201 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004202
4203 if (stkctr == &tmpstkctr)
4204 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004205 }
4206 return 1;
4207}
4208
4209/* set <smp> to the data rate received from clients in bytes/s, as found
4210 * in the stream's tracked frontend counters. Supports being called as
4211 * "sc[0-9]_bytes_in_rate" or "src_bytes_in_rate" only.
4212 */
4213static int
4214smp_fetch_sc_bytes_in_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
4215{
Emeric Brun819fc6f2017-06-13 19:37:32 +02004216 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01004217 struct stkctr *stkctr;
4218
Emeric Brun819fc6f2017-06-13 19:37:32 +02004219 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01004220 if (!stkctr)
4221 return 0;
4222
4223 smp->flags = SMP_F_VOL_TEST;
4224 smp->data.type = SMP_T_SINT;
4225 smp->data.u.sint = 0;
4226 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02004227 void *ptr;
4228
4229 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_IN_RATE);
4230 if (!ptr) {
4231 if (stkctr == &tmpstkctr)
4232 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004233 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02004234 }
4235
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004236 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004237
Emeric Brun0e3457b2021-06-30 17:18:28 +02004238 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Willy Tarreau7d562212016-11-25 16:10:05 +01004239 stkctr->table->data_arg[STKTABLE_DT_BYTES_IN_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004240
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004241 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004242
4243 if (stkctr == &tmpstkctr)
4244 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004245 }
4246 return 1;
4247}
4248
4249/* set <smp> to the number of kbytes sent to clients, as found in the
4250 * stream's tracked frontend counters. Supports being called as
4251 * "sc[0-9]_kbytes_out" or "src_kbytes_out" only.
4252 */
4253static int
4254smp_fetch_sc_kbytes_out(const struct arg *args, struct sample *smp, const char *kw, void *private)
4255{
Emeric Brun819fc6f2017-06-13 19:37:32 +02004256 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01004257 struct stkctr *stkctr;
4258
Emeric Brun819fc6f2017-06-13 19:37:32 +02004259 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01004260 if (!stkctr)
4261 return 0;
4262
4263 smp->flags = SMP_F_VOL_TEST;
4264 smp->data.type = SMP_T_SINT;
4265 smp->data.u.sint = 0;
4266 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02004267 void *ptr;
4268
4269 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_OUT_CNT);
4270 if (!ptr) {
4271 if (stkctr == &tmpstkctr)
4272 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004273 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02004274 }
4275
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004276 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004277
Emeric Brun0e3457b2021-06-30 17:18:28 +02004278 smp->data.u.sint = stktable_data_cast(ptr, std_t_ull) >> 10;
Emeric Brun819fc6f2017-06-13 19:37:32 +02004279
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004280 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004281
4282 if (stkctr == &tmpstkctr)
4283 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004284 }
4285 return 1;
4286}
4287
4288/* set <smp> to the data rate sent to clients in bytes/s, as found in the
4289 * stream's tracked frontend counters. Supports being called as
4290 * "sc[0-9]_bytes_out_rate" or "src_bytes_out_rate" only.
4291 */
4292static int
4293smp_fetch_sc_bytes_out_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
4294{
Emeric Brun819fc6f2017-06-13 19:37:32 +02004295 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01004296 struct stkctr *stkctr;
4297
Emeric Brun819fc6f2017-06-13 19:37:32 +02004298 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01004299 if (!stkctr)
4300 return 0;
4301
4302 smp->flags = SMP_F_VOL_TEST;
4303 smp->data.type = SMP_T_SINT;
4304 smp->data.u.sint = 0;
4305 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02004306 void *ptr;
4307
4308 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_OUT_RATE);
4309 if (!ptr) {
4310 if (stkctr == &tmpstkctr)
4311 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004312 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02004313 }
4314
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004315 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004316
Emeric Brun0e3457b2021-06-30 17:18:28 +02004317 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Willy Tarreau7d562212016-11-25 16:10:05 +01004318 stkctr->table->data_arg[STKTABLE_DT_BYTES_OUT_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004319
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004320 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004321
4322 if (stkctr == &tmpstkctr)
4323 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01004324 }
4325 return 1;
4326}
4327
4328/* set <smp> to the number of active trackers on the SC entry in the stream's
4329 * tracked frontend counters. Supports being called as "sc[0-9]_trackers" only.
4330 */
4331static int
4332smp_fetch_sc_trackers(const struct arg *args, struct sample *smp, const char *kw, void *private)
4333{
Emeric Brun819fc6f2017-06-13 19:37:32 +02004334 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01004335 struct stkctr *stkctr;
4336
Emeric Brun819fc6f2017-06-13 19:37:32 +02004337 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01004338 if (!stkctr)
4339 return 0;
4340
4341 smp->flags = SMP_F_VOL_TEST;
4342 smp->data.type = SMP_T_SINT;
Emeric Brun819fc6f2017-06-13 19:37:32 +02004343 if (stkctr == &tmpstkctr) {
4344 smp->data.u.sint = stkctr_entry(stkctr) ? (stkctr_entry(stkctr)->ref_cnt-1) : 0;
4345 stktable_release(stkctr->table, stkctr_entry(stkctr));
4346 }
4347 else {
4348 smp->data.u.sint = stkctr_entry(stkctr) ? stkctr_entry(stkctr)->ref_cnt : 0;
4349 }
4350
Willy Tarreau7d562212016-11-25 16:10:05 +01004351 return 1;
4352}
4353
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004354
4355/* The functions below are used to manipulate table contents from the CLI.
4356 * There are 3 main actions, "clear", "set" and "show". The code is shared
4357 * between all actions, and the action is encoded in the void *private in
4358 * the appctx as well as in the keyword registration, among one of the
4359 * following values.
4360 */
4361
4362enum {
4363 STK_CLI_ACT_CLR,
4364 STK_CLI_ACT_SET,
4365 STK_CLI_ACT_SHOW,
4366};
4367
Willy Tarreau4596fe22022-05-17 19:07:51 +02004368/* Dump the status of a table to a stream connector's
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004369 * read buffer. It returns 0 if the output buffer is full
4370 * and needs to be called again, otherwise non-zero.
4371 */
Willy Tarreau83061a82018-07-13 11:56:34 +02004372static int table_dump_head_to_buffer(struct buffer *msg,
Willy Tarreaud0a06d52022-05-18 15:07:19 +02004373 struct appctx *appctx,
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004374 struct stktable *t, struct stktable *target)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004375{
Willy Tarreauc12b3212022-05-27 11:08:15 +02004376 struct stream *s = __sc_strm(appctx_sc(appctx));
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004377
4378 chunk_appendf(msg, "# table: %s, type: %s, size:%d, used:%d\n",
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004379 t->id, stktable_types[t->type].kw, t->size, t->current);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004380
4381 /* any other information should be dumped here */
4382
William Lallemand07a62f72017-05-24 00:57:40 +02004383 if (target && (strm_li(s)->bind_conf->level & ACCESS_LVL_MASK) < ACCESS_LVL_OPER)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004384 chunk_appendf(msg, "# contents not dumped due to insufficient privileges\n");
4385
Willy Tarreaud0a06d52022-05-18 15:07:19 +02004386 if (applet_putchk(appctx, msg) == -1)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004387 return 0;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004388
4389 return 1;
4390}
4391
Willy Tarreau4596fe22022-05-17 19:07:51 +02004392/* Dump a table entry to a stream connector's
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004393 * read buffer. It returns 0 if the output buffer is full
4394 * and needs to be called again, otherwise non-zero.
4395 */
Willy Tarreau83061a82018-07-13 11:56:34 +02004396static int table_dump_entry_to_buffer(struct buffer *msg,
Willy Tarreaud0a06d52022-05-18 15:07:19 +02004397 struct appctx *appctx,
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004398 struct stktable *t, struct stksess *entry)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004399{
4400 int dt;
4401
4402 chunk_appendf(msg, "%p:", entry);
4403
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004404 if (t->type == SMP_T_IPV4) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004405 char addr[INET_ADDRSTRLEN];
4406 inet_ntop(AF_INET, (const void *)&entry->key.key, addr, sizeof(addr));
4407 chunk_appendf(msg, " key=%s", addr);
4408 }
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004409 else if (t->type == SMP_T_IPV6) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004410 char addr[INET6_ADDRSTRLEN];
4411 inet_ntop(AF_INET6, (const void *)&entry->key.key, addr, sizeof(addr));
4412 chunk_appendf(msg, " key=%s", addr);
4413 }
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004414 else if (t->type == SMP_T_SINT) {
Willy Tarreau6cde5d82020-02-25 09:41:22 +01004415 chunk_appendf(msg, " key=%u", read_u32(entry->key.key));
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004416 }
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004417 else if (t->type == SMP_T_STR) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004418 chunk_appendf(msg, " key=");
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004419 dump_text(msg, (const char *)entry->key.key, t->key_size);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004420 }
4421 else {
4422 chunk_appendf(msg, " key=");
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004423 dump_binary(msg, (const char *)entry->key.key, t->key_size);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004424 }
4425
4426 chunk_appendf(msg, " use=%d exp=%d", entry->ref_cnt - 1, tick_remain(now_ms, entry->expire));
4427
4428 for (dt = 0; dt < STKTABLE_DATA_TYPES; dt++) {
4429 void *ptr;
4430
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004431 if (t->data_ofs[dt] == 0)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004432 continue;
Emeric Brunc64a2a32021-06-30 18:01:02 +02004433 if (stktable_data_types[dt].is_array) {
4434 char tmp[16] = {};
4435 const char *name_pfx = stktable_data_types[dt].name;
4436 const char *name_sfx = NULL;
4437 unsigned int idx = 0;
4438 int i = 0;
4439
4440 /* split name to show index before first _ of the name
4441 * for example: 'gpc3_rate' if array name is 'gpc_rate'.
4442 */
4443 for (i = 0 ; i < (sizeof(tmp) - 1); i++) {
4444 if (!name_pfx[i])
4445 break;
4446 if (name_pfx[i] == '_') {
4447 name_pfx = &tmp[0];
4448 name_sfx = &stktable_data_types[dt].name[i];
4449 break;
4450 }
4451 tmp[i] = name_pfx[i];
4452 }
4453
4454 ptr = stktable_data_ptr_idx(t, entry, dt, idx);
4455 while (ptr) {
4456 if (stktable_data_types[dt].arg_type == ARG_T_DELAY)
4457 chunk_appendf(msg, " %s%u%s(%u)=", name_pfx, idx, name_sfx ? name_sfx : "", t->data_arg[dt].u);
4458 else
4459 chunk_appendf(msg, " %s%u%s=", name_pfx, idx, name_sfx ? name_sfx : "");
4460 switch (stktable_data_types[dt].std_type) {
4461 case STD_T_SINT:
4462 chunk_appendf(msg, "%d", stktable_data_cast(ptr, std_t_sint));
4463 break;
4464 case STD_T_UINT:
4465 chunk_appendf(msg, "%u", stktable_data_cast(ptr, std_t_uint));
4466 break;
4467 case STD_T_ULL:
4468 chunk_appendf(msg, "%llu", stktable_data_cast(ptr, std_t_ull));
4469 break;
4470 case STD_T_FRQP:
4471 chunk_appendf(msg, "%u",
4472 read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
4473 t->data_arg[dt].u));
4474 break;
4475 }
4476 ptr = stktable_data_ptr_idx(t, entry, dt, ++idx);
4477 }
4478 continue;
4479 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004480 if (stktable_data_types[dt].arg_type == ARG_T_DELAY)
Emeric Brun01928ae2021-06-30 16:24:04 +02004481 chunk_appendf(msg, " %s(%u)=", stktable_data_types[dt].name, t->data_arg[dt].u);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004482 else
4483 chunk_appendf(msg, " %s=", stktable_data_types[dt].name);
4484
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004485 ptr = stktable_data_ptr(t, entry, dt);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004486 switch (stktable_data_types[dt].std_type) {
4487 case STD_T_SINT:
4488 chunk_appendf(msg, "%d", stktable_data_cast(ptr, std_t_sint));
4489 break;
4490 case STD_T_UINT:
4491 chunk_appendf(msg, "%u", stktable_data_cast(ptr, std_t_uint));
4492 break;
4493 case STD_T_ULL:
Emeric Brun01928ae2021-06-30 16:24:04 +02004494 chunk_appendf(msg, "%llu", stktable_data_cast(ptr, std_t_ull));
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004495 break;
4496 case STD_T_FRQP:
Emeric Brun01928ae2021-06-30 16:24:04 +02004497 chunk_appendf(msg, "%u",
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004498 read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004499 t->data_arg[dt].u));
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004500 break;
Frédéric Lécaille16b4f542019-05-23 12:15:04 +02004501 case STD_T_DICT: {
4502 struct dict_entry *de;
4503 de = stktable_data_cast(ptr, std_t_dict);
4504 chunk_appendf(msg, "%s", de ? (char *)de->value.key : "-");
4505 break;
4506 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004507 }
4508 }
4509 chunk_appendf(msg, "\n");
4510
Willy Tarreaud0a06d52022-05-18 15:07:19 +02004511 if (applet_putchk(appctx, msg) == -1)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004512 return 0;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004513
4514 return 1;
4515}
4516
Willy Tarreau3c69e082022-05-03 11:35:07 +02004517/* appctx context used by the "show table" command */
4518struct show_table_ctx {
4519 void *target; /* table we want to dump, or NULL for all */
4520 struct stktable *t; /* table being currently dumped (first if NULL) */
4521 struct stksess *entry; /* last entry we were trying to dump (or first if NULL) */
4522 long long value[STKTABLE_FILTER_LEN]; /* value to compare against */
4523 signed char data_type[STKTABLE_FILTER_LEN]; /* type of data to compare, or -1 if none */
4524 signed char data_op[STKTABLE_FILTER_LEN]; /* operator (STD_OP_*) when data_type set */
Willy Tarreau7849d4c2022-05-03 11:45:02 +02004525 enum {
Willy Tarreau0f154ed2022-05-03 12:02:36 +02004526 STATE_NEXT = 0, /* px points to next table, entry=NULL */
Willy Tarreau7849d4c2022-05-03 11:45:02 +02004527 STATE_DUMP, /* px points to curr table, entry is valid, refcount held */
4528 STATE_DONE, /* done dumping */
4529 } state;
Willy Tarreau3c69e082022-05-03 11:35:07 +02004530 char action; /* action on the table : one of STK_CLI_ACT_* */
4531};
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004532
4533/* Processes a single table entry matching a specific key passed in argument.
4534 * returns 0 if wants to be called again, 1 if has ended processing.
4535 */
4536static int table_process_entry_per_key(struct appctx *appctx, char **args)
4537{
Willy Tarreau3c69e082022-05-03 11:35:07 +02004538 struct show_table_ctx *ctx = appctx->svcctx;
4539 struct stktable *t = ctx->target;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004540 struct stksess *ts;
4541 uint32_t uint32_key;
4542 unsigned char ip6_key[sizeof(struct in6_addr)];
4543 long long value;
4544 int data_type;
4545 int cur_arg;
4546 void *ptr;
Willy Tarreaufa1258f2021-04-10 23:00:53 +02004547 struct freq_ctr *frqp;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004548
Willy Tarreau9d008692019-08-09 11:21:01 +02004549 if (!*args[4])
4550 return cli_err(appctx, "Key value expected\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004551
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004552 switch (t->type) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004553 case SMP_T_IPV4:
4554 uint32_key = htonl(inetaddr_host(args[4]));
Christopher Fauletca20d022017-08-29 15:30:31 +02004555 static_table_key.key = &uint32_key;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004556 break;
4557 case SMP_T_IPV6:
Christopher Fauletb7c962b2021-11-15 09:17:25 +01004558 if (inet_pton(AF_INET6, args[4], ip6_key) <= 0)
4559 return cli_err(appctx, "Invalid key\n");
Christopher Fauletca20d022017-08-29 15:30:31 +02004560 static_table_key.key = &ip6_key;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004561 break;
4562 case SMP_T_SINT:
4563 {
4564 char *endptr;
4565 unsigned long val;
4566 errno = 0;
4567 val = strtoul(args[4], &endptr, 10);
4568 if ((errno == ERANGE && val == ULONG_MAX) ||
4569 (errno != 0 && val == 0) || endptr == args[4] ||
Willy Tarreau9d008692019-08-09 11:21:01 +02004570 val > 0xffffffff)
4571 return cli_err(appctx, "Invalid key\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004572 uint32_key = (uint32_t) val;
Christopher Fauletca20d022017-08-29 15:30:31 +02004573 static_table_key.key = &uint32_key;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004574 break;
4575 }
4576 break;
4577 case SMP_T_STR:
Christopher Fauletca20d022017-08-29 15:30:31 +02004578 static_table_key.key = args[4];
4579 static_table_key.key_len = strlen(args[4]);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004580 break;
4581 default:
Willy Tarreau3c69e082022-05-03 11:35:07 +02004582 switch (ctx->action) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004583 case STK_CLI_ACT_SHOW:
Willy Tarreau9d008692019-08-09 11:21:01 +02004584 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 +01004585 case STK_CLI_ACT_CLR:
Willy Tarreau9d008692019-08-09 11:21:01 +02004586 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 +01004587 case STK_CLI_ACT_SET:
Willy Tarreau9d008692019-08-09 11:21:01 +02004588 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 +01004589 default:
Willy Tarreau9d008692019-08-09 11:21:01 +02004590 return cli_err(appctx, "Unknown action\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004591 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004592 }
4593
4594 /* check permissions */
4595 if (!cli_has_level(appctx, ACCESS_LVL_OPER))
4596 return 1;
4597
Willy Tarreau3c69e082022-05-03 11:35:07 +02004598 switch (ctx->action) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004599 case STK_CLI_ACT_SHOW:
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004600 ts = stktable_lookup_key(t, &static_table_key);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004601 if (!ts)
4602 return 1;
4603 chunk_reset(&trash);
Willy Tarreaud0a06d52022-05-18 15:07:19 +02004604 if (!table_dump_head_to_buffer(&trash, appctx, t, t)) {
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004605 stktable_release(t, ts);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004606 return 0;
Emeric Brun819fc6f2017-06-13 19:37:32 +02004607 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004608 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &ts->lock);
Willy Tarreaud0a06d52022-05-18 15:07:19 +02004609 if (!table_dump_entry_to_buffer(&trash, appctx, t, ts)) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004610 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004611 stktable_release(t, ts);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004612 return 0;
Emeric Brun819fc6f2017-06-13 19:37:32 +02004613 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004614 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004615 stktable_release(t, ts);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004616 break;
4617
4618 case STK_CLI_ACT_CLR:
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004619 ts = stktable_lookup_key(t, &static_table_key);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004620 if (!ts)
4621 return 1;
Emeric Brun819fc6f2017-06-13 19:37:32 +02004622
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004623 if (!stksess_kill(t, ts, 1)) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004624 /* don't delete an entry which is currently referenced */
Willy Tarreau9d008692019-08-09 11:21:01 +02004625 return cli_err(appctx, "Entry currently in use, cannot remove\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004626 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004627 break;
4628
4629 case STK_CLI_ACT_SET:
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004630 ts = stktable_get_entry(t, &static_table_key);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004631 if (!ts) {
4632 /* don't delete an entry which is currently referenced */
Willy Tarreau9d008692019-08-09 11:21:01 +02004633 return cli_err(appctx, "Unable to allocate a new entry\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004634 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004635 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004636 for (cur_arg = 5; *args[cur_arg]; cur_arg += 2) {
4637 if (strncmp(args[cur_arg], "data.", 5) != 0) {
Willy Tarreau9d008692019-08-09 11:21:01 +02004638 cli_err(appctx, "\"data.<type>\" followed by a value expected\n");
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004639 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004640 stktable_touch_local(t, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004641 return 1;
4642 }
4643
4644 data_type = stktable_get_data_type(args[cur_arg] + 5);
4645 if (data_type < 0) {
Willy Tarreau9d008692019-08-09 11:21:01 +02004646 cli_err(appctx, "Unknown data type\n");
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004647 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004648 stktable_touch_local(t, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004649 return 1;
4650 }
4651
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004652 if (!t->data_ofs[data_type]) {
Willy Tarreau9d008692019-08-09 11:21:01 +02004653 cli_err(appctx, "Data type not stored in this table\n");
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004654 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004655 stktable_touch_local(t, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004656 return 1;
4657 }
4658
4659 if (!*args[cur_arg+1] || strl2llrc(args[cur_arg+1], strlen(args[cur_arg+1]), &value) != 0) {
Willy Tarreau9d008692019-08-09 11:21:01 +02004660 cli_err(appctx, "Require a valid integer value to store\n");
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004661 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004662 stktable_touch_local(t, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004663 return 1;
4664 }
4665
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004666 ptr = stktable_data_ptr(t, ts, data_type);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004667
4668 switch (stktable_data_types[data_type].std_type) {
4669 case STD_T_SINT:
4670 stktable_data_cast(ptr, std_t_sint) = value;
4671 break;
4672 case STD_T_UINT:
4673 stktable_data_cast(ptr, std_t_uint) = value;
4674 break;
4675 case STD_T_ULL:
4676 stktable_data_cast(ptr, std_t_ull) = value;
4677 break;
4678 case STD_T_FRQP:
4679 /* We set both the current and previous values. That way
4680 * the reported frequency is stable during all the period
4681 * then slowly fades out. This allows external tools to
4682 * push measures without having to update them too often.
4683 */
4684 frqp = &stktable_data_cast(ptr, std_t_frqp);
Willy Tarreaufa1258f2021-04-10 23:00:53 +02004685 /* First bit is reserved for the freq_ctr lock
Emeric Brunf2fc1fd2017-11-02 17:32:43 +01004686 Note: here we're still protected by the stksess lock
Willy Tarreaufa1258f2021-04-10 23:00:53 +02004687 so we don't need to update the update the freq_ctr
Emeric Brunf2fc1fd2017-11-02 17:32:43 +01004688 using its internal lock */
4689 frqp->curr_tick = now_ms & ~0x1;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004690 frqp->prev_ctr = 0;
4691 frqp->curr_ctr = value;
4692 break;
4693 }
4694 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004695 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004696 stktable_touch_local(t, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004697 break;
4698
4699 default:
Willy Tarreau9d008692019-08-09 11:21:01 +02004700 return cli_err(appctx, "Unknown action\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004701 }
4702 return 1;
4703}
4704
4705/* Prepares the appctx fields with the data-based filters from the command line.
4706 * Returns 0 if the dump can proceed, 1 if has ended processing.
4707 */
4708static int table_prepare_data_request(struct appctx *appctx, char **args)
4709{
Willy Tarreau3c69e082022-05-03 11:35:07 +02004710 struct show_table_ctx *ctx = appctx->svcctx;
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004711 int i;
Adis Nezirovicd0142e72020-01-22 16:50:27 +01004712 char *err = NULL;
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004713
Willy Tarreau3c69e082022-05-03 11:35:07 +02004714 if (ctx->action != STK_CLI_ACT_SHOW && ctx->action != STK_CLI_ACT_CLR)
Willy Tarreau9d008692019-08-09 11:21:01 +02004715 return cli_err(appctx, "content-based lookup is only supported with the \"show\" and \"clear\" actions\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004716
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004717 for (i = 0; i < STKTABLE_FILTER_LEN; i++) {
4718 if (i > 0 && !*args[3+3*i]) // number of filter entries can be less than STKTABLE_FILTER_LEN
4719 break;
4720 /* condition on stored data value */
Willy Tarreau3c69e082022-05-03 11:35:07 +02004721 ctx->data_type[i] = stktable_get_data_type(args[3+3*i] + 5);
4722 if (ctx->data_type[i] < 0)
Adis Nezirovicd0142e72020-01-22 16:50:27 +01004723 return cli_dynerr(appctx, memprintf(&err, "Filter entry #%i: Unknown data type\n", i + 1));
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004724
Willy Tarreau3c69e082022-05-03 11:35:07 +02004725 if (!((struct stktable *)ctx->target)->data_ofs[ctx->data_type[i]])
Adis Nezirovicd0142e72020-01-22 16:50:27 +01004726 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 +01004727
Willy Tarreau3c69e082022-05-03 11:35:07 +02004728 ctx->data_op[i] = get_std_op(args[4+3*i]);
4729 if (ctx->data_op[i] < 0)
Adis Nezirovicd0142e72020-01-22 16:50:27 +01004730 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 +01004731
Willy Tarreau3c69e082022-05-03 11:35:07 +02004732 if (!*args[5+3*i] || strl2llrc(args[5+3*i], strlen(args[5+3*i]), &ctx->value[i]) != 0)
Adis Nezirovicd0142e72020-01-22 16:50:27 +01004733 return cli_dynerr(appctx, memprintf(&err, "Filter entry #%i: Require a valid integer value to compare against\n", i + 1));
4734 }
4735
4736 if (*args[3+3*i]) {
4737 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 +01004738 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004739
4740 /* OK we're done, all the fields are set */
4741 return 0;
4742}
4743
4744/* returns 0 if wants to be called, 1 if has ended processing */
Aurélien Nephtaliabbf6072018-04-18 13:26:46 +02004745static int cli_parse_table_req(char **args, char *payload, struct appctx *appctx, void *private)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004746{
Willy Tarreau3c69e082022-05-03 11:35:07 +02004747 struct show_table_ctx *ctx = applet_reserve_svcctx(appctx, sizeof(*ctx));
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004748 int i;
4749
4750 for (i = 0; i < STKTABLE_FILTER_LEN; i++)
Willy Tarreau3c69e082022-05-03 11:35:07 +02004751 ctx->data_type[i] = -1;
4752 ctx->target = NULL;
4753 ctx->entry = NULL;
4754 ctx->action = (long)private; // keyword argument, one of STK_CLI_ACT_*
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004755
4756 if (*args[2]) {
Willy Tarreau0f154ed2022-05-03 12:02:36 +02004757 ctx->t = ctx->target = stktable_find_by_name(args[2]);
Willy Tarreau3c69e082022-05-03 11:35:07 +02004758 if (!ctx->target)
Willy Tarreau9d008692019-08-09 11:21:01 +02004759 return cli_err(appctx, "No such table\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004760 }
4761 else {
Willy Tarreau0f154ed2022-05-03 12:02:36 +02004762 ctx->t = stktables_list;
Willy Tarreau3c69e082022-05-03 11:35:07 +02004763 if (ctx->action != STK_CLI_ACT_SHOW)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004764 goto err_args;
4765 return 0;
4766 }
4767
4768 if (strcmp(args[3], "key") == 0)
4769 return table_process_entry_per_key(appctx, args);
4770 else if (strncmp(args[3], "data.", 5) == 0)
4771 return table_prepare_data_request(appctx, args);
4772 else if (*args[3])
4773 goto err_args;
4774
4775 return 0;
4776
4777err_args:
Willy Tarreau3c69e082022-05-03 11:35:07 +02004778 switch (ctx->action) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004779 case STK_CLI_ACT_SHOW:
Willy Tarreau9d008692019-08-09 11:21:01 +02004780 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 +01004781 case STK_CLI_ACT_CLR:
Willy Tarreau9d008692019-08-09 11:21:01 +02004782 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 +01004783 case STK_CLI_ACT_SET:
Willy Tarreau9d008692019-08-09 11:21:01 +02004784 return cli_err(appctx, "Required arguments: <table> key <key> [data.<store_data_type> <value>]*\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004785 default:
Willy Tarreau9d008692019-08-09 11:21:01 +02004786 return cli_err(appctx, "Unknown action\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004787 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004788}
4789
4790/* This function is used to deal with table operations (dump or clear depending
4791 * on the action stored in appctx->private). It returns 0 if the output buffer is
4792 * full and it needs to be called again, otherwise non-zero.
4793 */
4794static int cli_io_handler_table(struct appctx *appctx)
4795{
Willy Tarreau3c69e082022-05-03 11:35:07 +02004796 struct show_table_ctx *ctx = appctx->svcctx;
Willy Tarreauc12b3212022-05-27 11:08:15 +02004797 struct stconn *sc = appctx_sc(appctx);
Willy Tarreau475e4632022-05-27 10:26:46 +02004798 struct stream *s = __sc_strm(sc);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004799 struct ebmb_node *eb;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004800 int skip_entry;
Willy Tarreau3c69e082022-05-03 11:35:07 +02004801 int show = ctx->action == STK_CLI_ACT_SHOW;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004802
4803 /*
Willy Tarreau0f154ed2022-05-03 12:02:36 +02004804 * We have 3 possible states in ctx->state :
Willy Tarreau7849d4c2022-05-03 11:45:02 +02004805 * - STATE_NEXT : the proxy pointer points to the next table to
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004806 * dump, the entry pointer is NULL ;
Willy Tarreau7849d4c2022-05-03 11:45:02 +02004807 * - STATE_DUMP : the proxy pointer points to the current table
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004808 * and the entry pointer points to the next entry to be dumped,
4809 * and the refcount on the next entry is held ;
Willy Tarreau7849d4c2022-05-03 11:45:02 +02004810 * - STATE_DONE : nothing left to dump, the buffer may contain some
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004811 * data though.
4812 */
4813
Willy Tarreau475e4632022-05-27 10:26:46 +02004814 if (unlikely(sc_ic(sc)->flags & (CF_WRITE_ERROR|CF_SHUTW))) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004815 /* in case of abort, remove any refcount we might have set on an entry */
Willy Tarreau7849d4c2022-05-03 11:45:02 +02004816 if (ctx->state == STATE_DUMP) {
Willy Tarreau3c69e082022-05-03 11:35:07 +02004817 stksess_kill_if_expired(ctx->t, ctx->entry, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004818 }
4819 return 1;
4820 }
4821
4822 chunk_reset(&trash);
4823
Willy Tarreau7849d4c2022-05-03 11:45:02 +02004824 while (ctx->state != STATE_DONE) {
4825 switch (ctx->state) {
Willy Tarreau7849d4c2022-05-03 11:45:02 +02004826 case STATE_NEXT:
Willy Tarreau3c69e082022-05-03 11:35:07 +02004827 if (!ctx->t ||
4828 (ctx->target &&
4829 ctx->t != ctx->target)) {
Willy Tarreau7849d4c2022-05-03 11:45:02 +02004830 ctx->state = STATE_DONE;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004831 break;
4832 }
4833
Willy Tarreau3c69e082022-05-03 11:35:07 +02004834 if (ctx->t->size) {
Willy Tarreaud0a06d52022-05-18 15:07:19 +02004835 if (show && !table_dump_head_to_buffer(&trash, appctx, ctx->t, ctx->target))
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004836 return 0;
4837
Willy Tarreau3c69e082022-05-03 11:35:07 +02004838 if (ctx->target &&
William Lallemand07a62f72017-05-24 00:57:40 +02004839 (strm_li(s)->bind_conf->level & ACCESS_LVL_MASK) >= ACCESS_LVL_OPER) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004840 /* dump entries only if table explicitly requested */
Willy Tarreau76642222022-10-11 12:02:50 +02004841 HA_RWLOCK_WRLOCK(STK_TABLE_LOCK, &ctx->t->lock);
Willy Tarreau3c69e082022-05-03 11:35:07 +02004842 eb = ebmb_first(&ctx->t->keys);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004843 if (eb) {
Willy Tarreau3c69e082022-05-03 11:35:07 +02004844 ctx->entry = ebmb_entry(eb, struct stksess, key);
4845 ctx->entry->ref_cnt++;
Willy Tarreau7849d4c2022-05-03 11:45:02 +02004846 ctx->state = STATE_DUMP;
Willy Tarreau76642222022-10-11 12:02:50 +02004847 HA_RWLOCK_WRUNLOCK(STK_TABLE_LOCK, &ctx->t->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004848 break;
4849 }
Willy Tarreau76642222022-10-11 12:02:50 +02004850 HA_RWLOCK_WRUNLOCK(STK_TABLE_LOCK, &ctx->t->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004851 }
4852 }
Willy Tarreau3c69e082022-05-03 11:35:07 +02004853 ctx->t = ctx->t->next;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004854 break;
4855
Willy Tarreau7849d4c2022-05-03 11:45:02 +02004856 case STATE_DUMP:
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004857 skip_entry = 0;
4858
Willy Tarreau3c69e082022-05-03 11:35:07 +02004859 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &ctx->entry->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004860
Willy Tarreau3c69e082022-05-03 11:35:07 +02004861 if (ctx->data_type[0] >= 0) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004862 /* we're filtering on some data contents */
4863 void *ptr;
Willy Tarreau2b64a352020-01-22 17:09:47 +01004864 int dt, i;
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004865 signed char op;
4866 long long data, value;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004867
Emeric Brun819fc6f2017-06-13 19:37:32 +02004868
Willy Tarreau2b64a352020-01-22 17:09:47 +01004869 for (i = 0; i < STKTABLE_FILTER_LEN; i++) {
Willy Tarreau3c69e082022-05-03 11:35:07 +02004870 if (ctx->data_type[i] == -1)
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004871 break;
Willy Tarreau3c69e082022-05-03 11:35:07 +02004872 dt = ctx->data_type[i];
4873 ptr = stktable_data_ptr(ctx->t,
4874 ctx->entry,
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004875 dt);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004876
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004877 data = 0;
4878 switch (stktable_data_types[dt].std_type) {
4879 case STD_T_SINT:
4880 data = stktable_data_cast(ptr, std_t_sint);
4881 break;
4882 case STD_T_UINT:
4883 data = stktable_data_cast(ptr, std_t_uint);
4884 break;
4885 case STD_T_ULL:
4886 data = stktable_data_cast(ptr, std_t_ull);
4887 break;
4888 case STD_T_FRQP:
4889 data = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Willy Tarreau3c69e082022-05-03 11:35:07 +02004890 ctx->t->data_arg[dt].u);
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004891 break;
4892 }
4893
Willy Tarreau3c69e082022-05-03 11:35:07 +02004894 op = ctx->data_op[i];
4895 value = ctx->value[i];
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004896
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004897 /* skip the entry if the data does not match the test and the value */
4898 if ((data < value &&
4899 (op == STD_OP_EQ || op == STD_OP_GT || op == STD_OP_GE)) ||
4900 (data == value &&
4901 (op == STD_OP_NE || op == STD_OP_GT || op == STD_OP_LT)) ||
4902 (data > value &&
4903 (op == STD_OP_EQ || op == STD_OP_LT || op == STD_OP_LE))) {
4904 skip_entry = 1;
4905 break;
4906 }
4907 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004908 }
4909
4910 if (show && !skip_entry &&
Willy Tarreaud0a06d52022-05-18 15:07:19 +02004911 !table_dump_entry_to_buffer(&trash, appctx, ctx->t, ctx->entry)) {
Willy Tarreau3c69e082022-05-03 11:35:07 +02004912 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &ctx->entry->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004913 return 0;
4914 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004915
Willy Tarreau3c69e082022-05-03 11:35:07 +02004916 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &ctx->entry->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004917
Willy Tarreau76642222022-10-11 12:02:50 +02004918 HA_RWLOCK_WRLOCK(STK_TABLE_LOCK, &ctx->t->lock);
Willy Tarreau3c69e082022-05-03 11:35:07 +02004919 ctx->entry->ref_cnt--;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004920
Willy Tarreau3c69e082022-05-03 11:35:07 +02004921 eb = ebmb_next(&ctx->entry->key);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004922 if (eb) {
Willy Tarreau3c69e082022-05-03 11:35:07 +02004923 struct stksess *old = ctx->entry;
4924 ctx->entry = ebmb_entry(eb, struct stksess, key);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004925 if (show)
Willy Tarreau3c69e082022-05-03 11:35:07 +02004926 __stksess_kill_if_expired(ctx->t, old);
4927 else if (!skip_entry && !ctx->entry->ref_cnt)
4928 __stksess_kill(ctx->t, old);
4929 ctx->entry->ref_cnt++;
Willy Tarreau76642222022-10-11 12:02:50 +02004930 HA_RWLOCK_WRUNLOCK(STK_TABLE_LOCK, &ctx->t->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004931 break;
4932 }
4933
4934
4935 if (show)
Willy Tarreau3c69e082022-05-03 11:35:07 +02004936 __stksess_kill_if_expired(ctx->t, ctx->entry);
4937 else if (!skip_entry && !ctx->entry->ref_cnt)
4938 __stksess_kill(ctx->t, ctx->entry);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004939
Willy Tarreau76642222022-10-11 12:02:50 +02004940 HA_RWLOCK_WRUNLOCK(STK_TABLE_LOCK, &ctx->t->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004941
Willy Tarreau3c69e082022-05-03 11:35:07 +02004942 ctx->t = ctx->t->next;
Willy Tarreau7849d4c2022-05-03 11:45:02 +02004943 ctx->state = STATE_NEXT;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004944 break;
4945
Willy Tarreau7849d4c2022-05-03 11:45:02 +02004946 default:
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004947 break;
4948 }
4949 }
4950 return 1;
4951}
4952
4953static void cli_release_show_table(struct appctx *appctx)
4954{
Willy Tarreau3c69e082022-05-03 11:35:07 +02004955 struct show_table_ctx *ctx = appctx->svcctx;
4956
Willy Tarreau7849d4c2022-05-03 11:45:02 +02004957 if (ctx->state == STATE_DUMP) {
Willy Tarreau3c69e082022-05-03 11:35:07 +02004958 stksess_kill_if_expired(ctx->t, ctx->entry, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004959 }
4960}
4961
Willy Tarreau478331d2020-08-28 11:31:31 +02004962static void stkt_late_init(void)
4963{
4964 struct sample_fetch *f;
4965
4966 f = find_sample_fetch("src", strlen("src"));
4967 if (f)
4968 smp_fetch_src = f->process;
4969}
4970
4971INITCALL0(STG_INIT, stkt_late_init);
4972
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004973/* register cli keywords */
4974static struct cli_kw_list cli_kws = {{ },{
Willy Tarreaub205bfd2021-05-07 11:38:37 +02004975 { { "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 },
4976 { { "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 },
4977 { { "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 +01004978 {{},}
4979}};
4980
Willy Tarreau0108d902018-11-25 19:14:37 +01004981INITCALL1(STG_REGISTER, cli_register_kw, &cli_kws);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004982
Thierry FOURNIER236657b2015-08-19 08:25:14 +02004983static struct action_kw_list tcp_conn_kws = { { }, {
Emeric Brun4d7ada82021-06-30 19:04:16 +02004984 { "sc-inc-gpc", parse_inc_gpc, KWF_MATCH_PREFIX },
4985 { "sc-inc-gpc0", parse_inc_gpc, KWF_MATCH_PREFIX },
4986 { "sc-inc-gpc1", parse_inc_gpc, KWF_MATCH_PREFIX },
Emeric Brun877b0b52021-06-30 18:57:49 +02004987 { "sc-set-gpt", parse_set_gpt, KWF_MATCH_PREFIX },
4988 { "sc-set-gpt0", parse_set_gpt, KWF_MATCH_PREFIX },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02004989 { /* END */ }
4990}};
4991
Willy Tarreau0108d902018-11-25 19:14:37 +01004992INITCALL1(STG_REGISTER, tcp_req_conn_keywords_register, &tcp_conn_kws);
4993
Willy Tarreau620408f2016-10-21 16:37:51 +02004994static struct action_kw_list tcp_sess_kws = { { }, {
Emeric Brun4d7ada82021-06-30 19:04:16 +02004995 { "sc-inc-gpc", parse_inc_gpc, KWF_MATCH_PREFIX },
4996 { "sc-inc-gpc0", parse_inc_gpc, KWF_MATCH_PREFIX },
4997 { "sc-inc-gpc1", parse_inc_gpc, KWF_MATCH_PREFIX },
Emeric Brun877b0b52021-06-30 18:57:49 +02004998 { "sc-set-gpt", parse_set_gpt, KWF_MATCH_PREFIX },
4999 { "sc-set-gpt0", parse_set_gpt, KWF_MATCH_PREFIX },
Willy Tarreau620408f2016-10-21 16:37:51 +02005000 { /* END */ }
5001}};
5002
Willy Tarreau0108d902018-11-25 19:14:37 +01005003INITCALL1(STG_REGISTER, tcp_req_sess_keywords_register, &tcp_sess_kws);
5004
Thierry FOURNIER236657b2015-08-19 08:25:14 +02005005static struct action_kw_list tcp_req_kws = { { }, {
Emeric Brun4d7ada82021-06-30 19:04:16 +02005006 { "sc-inc-gpc", parse_inc_gpc, KWF_MATCH_PREFIX },
5007 { "sc-inc-gpc0", parse_inc_gpc, KWF_MATCH_PREFIX },
5008 { "sc-inc-gpc1", parse_inc_gpc, KWF_MATCH_PREFIX },
Emeric Brun877b0b52021-06-30 18:57:49 +02005009 { "sc-set-gpt", parse_set_gpt, KWF_MATCH_PREFIX },
5010 { "sc-set-gpt0", parse_set_gpt, KWF_MATCH_PREFIX },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02005011 { /* END */ }
5012}};
5013
Willy Tarreau0108d902018-11-25 19:14:37 +01005014INITCALL1(STG_REGISTER, tcp_req_cont_keywords_register, &tcp_req_kws);
5015
Thierry FOURNIER236657b2015-08-19 08:25:14 +02005016static struct action_kw_list tcp_res_kws = { { }, {
Emeric Brun4d7ada82021-06-30 19:04:16 +02005017 { "sc-inc-gpc", parse_inc_gpc, KWF_MATCH_PREFIX },
5018 { "sc-inc-gpc0", parse_inc_gpc, KWF_MATCH_PREFIX },
5019 { "sc-inc-gpc1", parse_inc_gpc, KWF_MATCH_PREFIX },
Emeric Brun877b0b52021-06-30 18:57:49 +02005020 { "sc-set-gpt", parse_set_gpt, KWF_MATCH_PREFIX },
5021 { "sc-set-gpt0", parse_set_gpt, KWF_MATCH_PREFIX },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02005022 { /* END */ }
5023}};
5024
Willy Tarreau0108d902018-11-25 19:14:37 +01005025INITCALL1(STG_REGISTER, tcp_res_cont_keywords_register, &tcp_res_kws);
5026
Thierry FOURNIER236657b2015-08-19 08:25:14 +02005027static struct action_kw_list http_req_kws = { { }, {
Emeric Brun4d7ada82021-06-30 19:04:16 +02005028 { "sc-inc-gpc", parse_inc_gpc, KWF_MATCH_PREFIX },
5029 { "sc-inc-gpc0", parse_inc_gpc, KWF_MATCH_PREFIX },
5030 { "sc-inc-gpc1", parse_inc_gpc, KWF_MATCH_PREFIX },
Emeric Brun877b0b52021-06-30 18:57:49 +02005031 { "sc-set-gpt", parse_set_gpt, KWF_MATCH_PREFIX },
5032 { "sc-set-gpt0", parse_set_gpt, KWF_MATCH_PREFIX },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02005033 { /* END */ }
5034}};
5035
Willy Tarreau0108d902018-11-25 19:14:37 +01005036INITCALL1(STG_REGISTER, http_req_keywords_register, &http_req_kws);
5037
Thierry FOURNIER236657b2015-08-19 08:25:14 +02005038static struct action_kw_list http_res_kws = { { }, {
Emeric Brun4d7ada82021-06-30 19:04:16 +02005039 { "sc-inc-gpc", parse_inc_gpc, KWF_MATCH_PREFIX },
5040 { "sc-inc-gpc0", parse_inc_gpc, KWF_MATCH_PREFIX },
5041 { "sc-inc-gpc1", parse_inc_gpc, KWF_MATCH_PREFIX },
Emeric Brun877b0b52021-06-30 18:57:49 +02005042 { "sc-set-gpt", parse_set_gpt, KWF_MATCH_PREFIX },
5043 { "sc-set-gpt0", parse_set_gpt, KWF_MATCH_PREFIX },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02005044 { /* END */ }
5045}};
5046
Willy Tarreau0108d902018-11-25 19:14:37 +01005047INITCALL1(STG_REGISTER, http_res_keywords_register, &http_res_kws);
5048
Willy Tarreau7d562212016-11-25 16:10:05 +01005049/* Note: must not be declared <const> as its list will be overwritten.
5050 * Please take care of keeping this list alphabetically sorted.
5051 */
5052static struct sample_fetch_kw_list smp_fetch_keywords = {ILH, {
5053 { "sc_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5054 { "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 +02005055 { "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 +01005056 { "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 +01005057 { "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 +01005058 { "sc_conn_cnt", smp_fetch_sc_conn_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5059 { "sc_conn_cur", smp_fetch_sc_conn_cur, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5060 { "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 +02005061 { "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 +01005062 { "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 +02005063 { "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 +01005064 { "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 +01005065 { "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 +02005066 { "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 +01005067 { "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 +01005068 { "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 +01005069 { "sc_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5070 { "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 +01005071 { "sc_http_fail_cnt", smp_fetch_sc_http_fail_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5072 { "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 +01005073 { "sc_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5074 { "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 +02005075 { "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 +01005076 { "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 +01005077 { "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 +01005078 { "sc_kbytes_in", smp_fetch_sc_kbytes_in, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5079 { "sc_kbytes_out", smp_fetch_sc_kbytes_out, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5080 { "sc_sess_cnt", smp_fetch_sc_sess_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5081 { "sc_sess_rate", smp_fetch_sc_sess_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5082 { "sc_tracked", smp_fetch_sc_tracked, ARG2(1,SINT,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
5083 { "sc_trackers", smp_fetch_sc_trackers, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5084 { "sc0_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5085 { "sc0_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5086 { "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 +01005087 { "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 +01005088 { "sc0_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5089 { "sc0_conn_cur", smp_fetch_sc_conn_cur, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5090 { "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 +01005091 { "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 +01005092 { "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 +01005093 { "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 +01005094 { "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 +01005095 { "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 +01005096 { "sc0_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5097 { "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 +01005098 { "sc0_http_fail_cnt", smp_fetch_sc_http_fail_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5099 { "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 +01005100 { "sc0_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5101 { "sc0_http_req_rate", smp_fetch_sc_http_req_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5102 { "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 +01005103 { "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 +01005104 { "sc0_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5105 { "sc0_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5106 { "sc0_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5107 { "sc0_sess_rate", smp_fetch_sc_sess_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5108 { "sc0_tracked", smp_fetch_sc_tracked, ARG1(0,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
5109 { "sc0_trackers", smp_fetch_sc_trackers, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5110 { "sc1_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5111 { "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 +02005112 { "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 +01005113 { "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 +01005114 { "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 +01005115 { "sc1_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5116 { "sc1_conn_cur", smp_fetch_sc_conn_cur, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5117 { "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 +01005118 { "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 +01005119 { "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 +01005120 { "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 +01005121 { "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 +01005122 { "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 +01005123 { "sc1_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5124 { "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 +01005125 { "sc1_http_fail_cnt", smp_fetch_sc_http_fail_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5126 { "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 +01005127 { "sc1_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5128 { "sc1_http_req_rate", smp_fetch_sc_http_req_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5129 { "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 +01005130 { "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 +01005131 { "sc1_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5132 { "sc1_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5133 { "sc1_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5134 { "sc1_sess_rate", smp_fetch_sc_sess_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5135 { "sc1_tracked", smp_fetch_sc_tracked, ARG1(0,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
5136 { "sc1_trackers", smp_fetch_sc_trackers, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5137 { "sc2_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5138 { "sc2_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5139 { "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 +01005140 { "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 +01005141 { "sc2_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5142 { "sc2_conn_cur", smp_fetch_sc_conn_cur, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5143 { "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 +01005144 { "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 +01005145 { "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 +01005146 { "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 +01005147 { "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 +01005148 { "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 +01005149 { "sc2_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5150 { "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 +01005151 { "sc2_http_fail_cnt", smp_fetch_sc_http_fail_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5152 { "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 +01005153 { "sc2_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5154 { "sc2_http_req_rate", smp_fetch_sc_http_req_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5155 { "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 +01005156 { "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 +01005157 { "sc2_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5158 { "sc2_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5159 { "sc2_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5160 { "sc2_sess_rate", smp_fetch_sc_sess_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5161 { "sc2_tracked", smp_fetch_sc_tracked, ARG1(0,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
5162 { "sc2_trackers", smp_fetch_sc_trackers, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5163 { "src_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5164 { "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 +02005165 { "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 +01005166 { "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 +01005167 { "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 +01005168 { "src_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5169 { "src_conn_cur", smp_fetch_sc_conn_cur, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5170 { "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 +02005171 { "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 +01005172 { "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 +02005173 { "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 +01005174 { "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 +01005175 { "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 +02005176 { "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 +01005177 { "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 +01005178 { "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 +01005179 { "src_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5180 { "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 +01005181 { "src_http_fail_cnt", smp_fetch_sc_http_fail_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5182 { "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 +01005183 { "src_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5184 { "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 +02005185 { "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 +01005186 { "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 +01005187 { "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 +01005188 { "src_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5189 { "src_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5190 { "src_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5191 { "src_sess_rate", smp_fetch_sc_sess_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5192 { "src_updt_conn_cnt", smp_fetch_src_updt_conn_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
5193 { "table_avl", smp_fetch_table_avl, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5194 { "table_cnt", smp_fetch_table_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
5195 { /* END */ },
5196}};
5197
Willy Tarreau0108d902018-11-25 19:14:37 +01005198INITCALL1(STG_REGISTER, sample_register_fetches, &smp_fetch_keywords);
Willy Tarreau7d562212016-11-25 16:10:05 +01005199
Willy Tarreaud9f316a2014-07-10 14:03:38 +02005200/* Note: must not be declared <const> as its list will be overwritten */
5201static struct sample_conv_kw_list sample_conv_kws = {ILH, {
Willy Tarreau2d17db52016-05-25 17:16:38 +02005202 { "in_table", sample_conv_in_table, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_BOOL },
5203 { "table_bytes_in_rate", sample_conv_table_bytes_in_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5204 { "table_bytes_out_rate", sample_conv_table_bytes_out_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5205 { "table_conn_cnt", sample_conv_table_conn_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5206 { "table_conn_cur", sample_conv_table_conn_cur, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5207 { "table_conn_rate", sample_conv_table_conn_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
Frédéric Lécaillebbeec372022-08-16 18:11:25 +02005208 { "table_expire", sample_conv_table_expire, ARG2(1,TAB,SINT), NULL, SMP_T_ANY, SMP_T_SINT },
Emeric Brun877b0b52021-06-30 18:57:49 +02005209 { "table_gpt", sample_conv_table_gpt, ARG2(2,SINT,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
Willy Tarreau2d17db52016-05-25 17:16:38 +02005210 { "table_gpt0", sample_conv_table_gpt0, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
Emeric Brun4d7ada82021-06-30 19:04:16 +02005211 { "table_gpc", sample_conv_table_gpc, ARG2(2,SINT,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
Willy Tarreau2d17db52016-05-25 17:16:38 +02005212 { "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 +01005213 { "table_gpc1", sample_conv_table_gpc1, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
Emeric Brun4d7ada82021-06-30 19:04:16 +02005214 { "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 +02005215 { "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 +01005216 { "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 +02005217 { "table_http_err_cnt", sample_conv_table_http_err_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5218 { "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 +01005219 { "table_http_fail_cnt", sample_conv_table_http_fail_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5220 { "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 +02005221 { "table_http_req_cnt", sample_conv_table_http_req_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5222 { "table_http_req_rate", sample_conv_table_http_req_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
Frédéric Lécaillebbeec372022-08-16 18:11:25 +02005223 { "table_idle", sample_conv_table_idle, ARG2(1,TAB,SINT), NULL, SMP_T_ANY, SMP_T_SINT },
Willy Tarreau2d17db52016-05-25 17:16:38 +02005224 { "table_kbytes_in", sample_conv_table_kbytes_in, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5225 { "table_kbytes_out", sample_conv_table_kbytes_out, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5226 { "table_server_id", sample_conv_table_server_id, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5227 { "table_sess_cnt", sample_conv_table_sess_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5228 { "table_sess_rate", sample_conv_table_sess_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
5229 { "table_trackers", sample_conv_table_trackers, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
Willy Tarreaud9f316a2014-07-10 14:03:38 +02005230 { /* END */ },
5231}};
5232
Willy Tarreau0108d902018-11-25 19:14:37 +01005233INITCALL1(STG_REGISTER, sample_register_convs, &sample_conv_kws);