blob: 5f0505e3e82aeddb2a94482c93c15a7cf9409a82 [file] [log] [blame]
Emeric Brun3bd697e2010-01-04 15:23:48 +01001/*
2 * Stick tables management functions.
3 *
4 * Copyright 2009-2010 EXCELIANCE, Emeric Brun <ebrun@exceliance.fr>
Willy Tarreau08d5f982010-06-06 13:34:54 +02005 * Copyright (C) 2010 Willy Tarreau <w@1wt.eu>
Emeric Brun3bd697e2010-01-04 15:23:48 +01006 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version
10 * 2 of the License, or (at your option) any later version.
11 *
12 */
13
14#include <string.h>
Willy Tarreauf13ebdf2016-11-22 18:00:53 +010015#include <errno.h>
Emeric Brun3bd697e2010-01-04 15:23:48 +010016
Willy Tarreaub2551052020-06-09 09:07:15 +020017#include <import/ebmbtree.h>
18#include <import/ebsttree.h>
19#include <import/ebistree.h>
20
Willy Tarreau4c7e4b72020-05-27 12:58:42 +020021#include <haproxy/api.h>
Willy Tarreaub2551052020-06-09 09:07:15 +020022#include <haproxy/arg.h>
Willy Tarreau6be78492020-06-05 00:00:29 +020023#include <haproxy/cfgparse.h>
Willy Tarreau83487a82020-06-04 20:19:54 +020024#include <haproxy/cli.h>
Thayne McCombs92149f92020-11-20 01:28:26 -070025#include <haproxy/dict.h>
Willy Tarreau36979d92020-06-05 17:27:29 +020026#include <haproxy/errors.h>
Willy Tarreauf268ee82020-06-04 17:05:57 +020027#include <haproxy/global.h>
Willy Tarreauc761f842020-06-04 11:40:28 +020028#include <haproxy/http_rules.h>
Willy Tarreau853b2972020-05-27 18:01:47 +020029#include <haproxy/list.h>
Willy Tarreauaeed4a82020-06-04 22:01:04 +020030#include <haproxy/log.h>
Willy Tarreau6131d6a2020-06-02 16:48:09 +020031#include <haproxy/net_helper.h>
Willy Tarreau3c2a7c22020-06-04 18:38:21 +020032#include <haproxy/peers.h>
Willy Tarreaub2551052020-06-09 09:07:15 +020033#include <haproxy/pool.h>
34#include <haproxy/proto_tcp.h>
Willy Tarreaua264d962020-06-04 22:29:18 +020035#include <haproxy/proxy.h>
Willy Tarreaub2551052020-06-09 09:07:15 +020036#include <haproxy/sample.h>
Willy Tarreau2eec9b52020-06-04 19:58:55 +020037#include <haproxy/stats-t.h>
Willy Tarreaub2551052020-06-09 09:07:15 +020038#include <haproxy/stick_table.h>
Willy Tarreaudfd3de82020-06-04 23:46:14 +020039#include <haproxy/stream.h>
Willy Tarreau5e539c92020-06-04 20:45:39 +020040#include <haproxy/stream_interface.h>
Willy Tarreaucea0e1b2020-06-04 17:25:40 +020041#include <haproxy/task.h>
Willy Tarreau8b550af2020-06-04 17:42:48 +020042#include <haproxy/tcp_rules.h>
Willy Tarreau92b4f132020-06-01 11:05:15 +020043#include <haproxy/time.h>
Willy Tarreaub2551052020-06-09 09:07:15 +020044#include <haproxy/tools.h>
Emeric Brun3bd697e2010-01-04 15:23:48 +010045
Emeric Brun3bd697e2010-01-04 15:23:48 +010046
Willy Tarreau12785782012-04-27 21:37:17 +020047/* structure used to return a table key built from a sample */
Emeric Brun819fc6f2017-06-13 19:37:32 +020048static THREAD_LOCAL struct stktable_key static_table_key;
Willy Tarreau478331d2020-08-28 11:31:31 +020049static int (*smp_fetch_src)(const struct arg *, struct sample *, const char *, void *);
Willy Tarreauf0b38bf2010-06-06 13:22:23 +020050
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +010051struct stktable *stktables_list;
52struct eb_root stktable_by_name = EB_ROOT;
53
Olivier Houchard52dabbc2018-11-14 17:54:36 +010054#define round_ptr_size(i) (((i) + (sizeof(void *) - 1)) &~ (sizeof(void *) - 1))
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +010055
56/* This function inserts stktable <t> into the tree of known stick-table.
57 * The stick-table ID is used as the storing key so it must already have
58 * been initialized.
59 */
60void stktable_store_name(struct stktable *t)
61{
62 t->name.key = t->id;
63 ebis_insert(&stktable_by_name, &t->name);
64}
65
66struct stktable *stktable_find_by_name(const char *name)
67{
68 struct ebpt_node *node;
69 struct stktable *t;
70
71 node = ebis_lookup(&stktable_by_name, name);
72 if (node) {
73 t = container_of(node, struct stktable, name);
Tim Duesterhuse5ff1412021-01-02 22:31:53 +010074 if (strcmp(t->id, name) == 0)
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +010075 return t;
76 }
77
78 return NULL;
79}
80
Emeric Brun3bd697e2010-01-04 15:23:48 +010081/*
Willy Tarreauaea940e2010-06-06 11:56:36 +020082 * Free an allocated sticky session <ts>, and decrease sticky sessions counter
83 * in table <t>.
Emeric Brun3bd697e2010-01-04 15:23:48 +010084 */
Emeric Brun819fc6f2017-06-13 19:37:32 +020085void __stksess_free(struct stktable *t, struct stksess *ts)
Emeric Brun3bd697e2010-01-04 15:23:48 +010086{
87 t->current--;
Olivier Houchard52dabbc2018-11-14 17:54:36 +010088 pool_free(t->pool, (void *)ts - round_ptr_size(t->data_size));
Emeric Brun3bd697e2010-01-04 15:23:48 +010089}
90
91/*
Emeric Brun819fc6f2017-06-13 19:37:32 +020092 * Free an allocated sticky session <ts>, and decrease sticky sessions counter
93 * in table <t>.
94 * This function locks the table
95 */
96void stksess_free(struct stktable *t, struct stksess *ts)
97{
Thayne McCombs92149f92020-11-20 01:28:26 -070098 void *data;
99 data = stktable_data_ptr(t, ts, STKTABLE_DT_SERVER_KEY);
100 if (data) {
101 dict_entry_unref(&server_key_dict, stktable_data_cast(data, server_key));
102 stktable_data_cast(data, server_key) = NULL;
103 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100104 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200105 __stksess_free(t, ts);
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100106 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200107}
108
109/*
Willy Tarreauf6efda12010-08-03 20:34:06 +0200110 * Kill an stksess (only if its ref_cnt is zero).
111 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200112int __stksess_kill(struct stktable *t, struct stksess *ts)
Willy Tarreauf6efda12010-08-03 20:34:06 +0200113{
114 if (ts->ref_cnt)
Emeric Brun819fc6f2017-06-13 19:37:32 +0200115 return 0;
Willy Tarreauf6efda12010-08-03 20:34:06 +0200116
117 eb32_delete(&ts->exp);
Emeric Brun85e77c72010-09-23 18:16:52 +0200118 eb32_delete(&ts->upd);
Willy Tarreauf6efda12010-08-03 20:34:06 +0200119 ebmb_delete(&ts->key);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200120 __stksess_free(t, ts);
121 return 1;
Willy Tarreauf6efda12010-08-03 20:34:06 +0200122}
123
124/*
Emeric Brun819fc6f2017-06-13 19:37:32 +0200125 * Decrease the refcount if decrefcnt is not 0.
126 * and try to kill the stksess
127 * This function locks the table
128 */
129int stksess_kill(struct stktable *t, struct stksess *ts, int decrefcnt)
130{
131 int ret;
132
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100133 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200134 if (decrefcnt)
135 ts->ref_cnt--;
136 ret = __stksess_kill(t, ts);
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100137 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200138
139 return ret;
140}
141
142/*
Willy Tarreauaea940e2010-06-06 11:56:36 +0200143 * Initialize or update the key in the sticky session <ts> present in table <t>
144 * from the value present in <key>.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100145 */
Willy Tarreau393379c2010-06-06 12:11:37 +0200146void stksess_setkey(struct stktable *t, struct stksess *ts, struct stktable_key *key)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100147{
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200148 if (t->type != SMP_T_STR)
Willy Tarreau86257dc2010-06-06 12:57:10 +0200149 memcpy(ts->key.key, key->key, t->key_size);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100150 else {
Willy Tarreau86257dc2010-06-06 12:57:10 +0200151 memcpy(ts->key.key, key->key, MIN(t->key_size - 1, key->key_len));
152 ts->key.key[MIN(t->key_size - 1, key->key_len)] = 0;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100153 }
154}
155
156
157/*
Willy Tarreau393379c2010-06-06 12:11:37 +0200158 * Init sticky session <ts> of table <t>. The data parts are cleared and <ts>
159 * is returned.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100160 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200161static struct stksess *__stksess_init(struct stktable *t, struct stksess * ts)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100162{
Willy Tarreau393379c2010-06-06 12:11:37 +0200163 memset((void *)ts - t->data_size, 0, t->data_size);
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200164 ts->ref_cnt = 0;
Willy Tarreau86257dc2010-06-06 12:57:10 +0200165 ts->key.node.leaf_p = NULL;
166 ts->exp.node.leaf_p = NULL;
Emeric Brun85e77c72010-09-23 18:16:52 +0200167 ts->upd.node.leaf_p = NULL;
Emeric Brun819fc6f2017-06-13 19:37:32 +0200168 ts->expire = tick_add(now_ms, MS_TO_TICKS(t->expire));
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100169 HA_RWLOCK_INIT(&ts->lock);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100170 return ts;
171}
172
173/*
Willy Tarreauaea940e2010-06-06 11:56:36 +0200174 * Trash oldest <to_batch> sticky sessions from table <t>
Willy Tarreaudfe79252020-11-03 17:47:41 +0100175 * Returns number of trashed sticky sessions. It may actually trash less
176 * than expected if finding these requires too long a search time (e.g.
177 * most of them have ts->ref_cnt>0).
Emeric Brun3bd697e2010-01-04 15:23:48 +0100178 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200179int __stktable_trash_oldest(struct stktable *t, int to_batch)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100180{
181 struct stksess *ts;
182 struct eb32_node *eb;
Willy Tarreaudfe79252020-11-03 17:47:41 +0100183 int max_search = to_batch * 2; // no more than 50% misses
Emeric Brun3bd697e2010-01-04 15:23:48 +0100184 int batched = 0;
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200185 int looped = 0;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100186
187 eb = eb32_lookup_ge(&t->exps, now_ms - TIMER_LOOK_BACK);
188
189 while (batched < to_batch) {
190
191 if (unlikely(!eb)) {
192 /* we might have reached the end of the tree, typically because
193 * <now_ms> is in the first half and we're first scanning the last
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200194 * half. Let's loop back to the beginning of the tree now if we
195 * have not yet visited it.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100196 */
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200197 if (looped)
198 break;
199 looped = 1;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100200 eb = eb32_first(&t->exps);
201 if (likely(!eb))
202 break;
203 }
204
Willy Tarreaudfe79252020-11-03 17:47:41 +0100205 if (--max_search < 0)
206 break;
207
Emeric Brun3bd697e2010-01-04 15:23:48 +0100208 /* timer looks expired, detach it from the queue */
Willy Tarreau86257dc2010-06-06 12:57:10 +0200209 ts = eb32_entry(eb, struct stksess, exp);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100210 eb = eb32_next(eb);
211
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200212 /* don't delete an entry which is currently referenced */
213 if (ts->ref_cnt)
214 continue;
215
Willy Tarreau86257dc2010-06-06 12:57:10 +0200216 eb32_delete(&ts->exp);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100217
Willy Tarreau86257dc2010-06-06 12:57:10 +0200218 if (ts->expire != ts->exp.key) {
Emeric Brun3bd697e2010-01-04 15:23:48 +0100219 if (!tick_isset(ts->expire))
220 continue;
221
Willy Tarreau86257dc2010-06-06 12:57:10 +0200222 ts->exp.key = ts->expire;
223 eb32_insert(&t->exps, &ts->exp);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100224
Aleksey Ponomaryovb38ad122023-02-07 19:27:06 +0100225 /* the update might have jumped beyond the next element,
226 * possibly causing a wrapping. We need to check whether
227 * the next element should be used instead. If the next
228 * element doesn't exist it means we're on the right
229 * side and have to check the first one then. If it
230 * exists and is closer, we must use it, otherwise we
231 * use the current one.
232 */
233 if (!eb)
234 eb = eb32_first(&t->exps);
235
236 if (!eb || tick_is_lt(ts->exp.key, eb->key))
Willy Tarreau86257dc2010-06-06 12:57:10 +0200237 eb = &ts->exp;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100238
239 continue;
240 }
Emeric Brun3bd697e2010-01-04 15:23:48 +0100241
Willy Tarreauaea940e2010-06-06 11:56:36 +0200242 /* session expired, trash it */
Willy Tarreau86257dc2010-06-06 12:57:10 +0200243 ebmb_delete(&ts->key);
Emeric Brun85e77c72010-09-23 18:16:52 +0200244 eb32_delete(&ts->upd);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200245 __stksess_free(t, ts);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100246 batched++;
247 }
248
249 return batched;
250}
251
252/*
Emeric Brun819fc6f2017-06-13 19:37:32 +0200253 * Trash oldest <to_batch> sticky sessions from table <t>
254 * Returns number of trashed sticky sessions.
255 * This function locks the table
256 */
257int stktable_trash_oldest(struct stktable *t, int to_batch)
258{
259 int ret;
260
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100261 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200262 ret = __stktable_trash_oldest(t, to_batch);
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100263 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200264
265 return ret;
266}
267/*
Willy Tarreauaea940e2010-06-06 11:56:36 +0200268 * Allocate and initialise a new sticky session.
269 * The new sticky session is returned or NULL in case of lack of memory.
270 * Sticky sessions should only be allocated this way, and must be freed using
Willy Tarreaua7b46b52013-04-11 16:55:37 +0200271 * stksess_free(). Table <t>'s sticky session counter is increased. If <key>
272 * is not NULL, it is assigned to the new session.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100273 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200274struct stksess *__stksess_new(struct stktable *t, struct stktable_key *key)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100275{
276 struct stksess *ts;
277
278 if (unlikely(t->current == t->size)) {
279 if ( t->nopurge )
280 return NULL;
281
Emeric Brun819fc6f2017-06-13 19:37:32 +0200282 if (!__stktable_trash_oldest(t, (t->size >> 8) + 1))
Emeric Brun3bd697e2010-01-04 15:23:48 +0100283 return NULL;
284 }
285
Willy Tarreaubafbe012017-11-24 17:34:44 +0100286 ts = pool_alloc(t->pool);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100287 if (ts) {
288 t->current++;
Olivier Houchard52dabbc2018-11-14 17:54:36 +0100289 ts = (void *)ts + round_ptr_size(t->data_size);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200290 __stksess_init(t, ts);
Willy Tarreaua7b46b52013-04-11 16:55:37 +0200291 if (key)
292 stksess_setkey(t, ts, key);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100293 }
294
295 return ts;
296}
Emeric Brun819fc6f2017-06-13 19:37:32 +0200297/*
298 * Allocate and initialise a new sticky session.
299 * The new sticky session is returned or NULL in case of lack of memory.
300 * Sticky sessions should only be allocated this way, and must be freed using
301 * stksess_free(). Table <t>'s sticky session counter is increased. If <key>
302 * is not NULL, it is assigned to the new session.
303 * This function locks the table
304 */
305struct stksess *stksess_new(struct stktable *t, struct stktable_key *key)
306{
307 struct stksess *ts;
308
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100309 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200310 ts = __stksess_new(t, key);
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100311 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200312
313 return ts;
314}
Emeric Brun3bd697e2010-01-04 15:23:48 +0100315
316/*
Willy Tarreauf16d2b82010-06-06 15:38:59 +0200317 * Looks in table <t> for a sticky session matching key <key>.
Willy Tarreauaea940e2010-06-06 11:56:36 +0200318 * Returns pointer on requested sticky session or NULL if none was found.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100319 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200320struct stksess *__stktable_lookup_key(struct stktable *t, struct stktable_key *key)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100321{
322 struct ebmb_node *eb;
323
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200324 if (t->type == SMP_T_STR)
Emeric Brun485479d2010-09-23 18:02:19 +0200325 eb = ebst_lookup_len(&t->keys, key->key, key->key_len+1 < t->key_size ? key->key_len : t->key_size-1);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100326 else
327 eb = ebmb_lookup(&t->keys, key->key, t->key_size);
328
329 if (unlikely(!eb)) {
330 /* no session found */
331 return NULL;
332 }
333
Willy Tarreau86257dc2010-06-06 12:57:10 +0200334 return ebmb_entry(eb, struct stksess, key);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100335}
336
Emeric Brun819fc6f2017-06-13 19:37:32 +0200337/*
338 * Looks in table <t> for a sticky session matching key <key>.
339 * Returns pointer on requested sticky session or NULL if none was found.
340 * The refcount of the found entry is increased and this function
341 * is protected using the table lock
Willy Tarreau1f7e9252010-06-20 12:27:21 +0200342 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200343struct stksess *stktable_lookup_key(struct stktable *t, struct stktable_key *key)
Willy Tarreau1f7e9252010-06-20 12:27:21 +0200344{
345 struct stksess *ts;
346
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100347 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200348 ts = __stktable_lookup_key(t, key);
349 if (ts)
350 ts->ref_cnt++;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100351 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Willy Tarreau1f7e9252010-06-20 12:27:21 +0200352
Willy Tarreau1f7e9252010-06-20 12:27:21 +0200353 return ts;
354}
355
Willy Tarreauf16d2b82010-06-06 15:38:59 +0200356/*
357 * Looks in table <t> for a sticky session with same key as <ts>.
358 * Returns pointer on requested sticky session or NULL if none was found.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100359 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200360struct stksess *__stktable_lookup(struct stktable *t, struct stksess *ts)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100361{
Emeric Brun3bd697e2010-01-04 15:23:48 +0100362 struct ebmb_node *eb;
363
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200364 if (t->type == SMP_T_STR)
Willy Tarreau86257dc2010-06-06 12:57:10 +0200365 eb = ebst_lookup(&(t->keys), (char *)ts->key.key);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100366 else
Willy Tarreau86257dc2010-06-06 12:57:10 +0200367 eb = ebmb_lookup(&(t->keys), ts->key.key, t->key_size);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100368
Willy Tarreauf16d2b82010-06-06 15:38:59 +0200369 if (unlikely(!eb))
370 return NULL;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100371
Willy Tarreauf16d2b82010-06-06 15:38:59 +0200372 return ebmb_entry(eb, struct stksess, key);
373}
Emeric Brun3bd697e2010-01-04 15:23:48 +0100374
Emeric Brun819fc6f2017-06-13 19:37:32 +0200375/*
376 * Looks in table <t> for a sticky session with same key as <ts>.
377 * Returns pointer on requested sticky session or NULL if none was found.
378 * The refcount of the found entry is increased and this function
379 * is protected using the table lock
380 */
381struct stksess *stktable_lookup(struct stktable *t, struct stksess *ts)
382{
383 struct stksess *lts;
384
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100385 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200386 lts = __stktable_lookup(t, ts);
387 if (lts)
388 lts->ref_cnt++;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100389 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200390
391 return lts;
392}
393
Willy Tarreaucb183642010-06-06 17:58:34 +0200394/* Update the expiration timer for <ts> but do not touch its expiration node.
395 * The table's expiration timer is updated if set.
Emeric Brun819fc6f2017-06-13 19:37:32 +0200396 * The node will be also inserted into the update tree if needed, at a position
397 * depending if the update is a local or coming from a remote node
Willy Tarreaucb183642010-06-06 17:58:34 +0200398 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200399void __stktable_touch_with_exp(struct stktable *t, struct stksess *ts, int local, int expire)
Willy Tarreaucb183642010-06-06 17:58:34 +0200400{
Emeric Brun85e77c72010-09-23 18:16:52 +0200401 struct eb32_node * eb;
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200402 ts->expire = expire;
Willy Tarreaucb183642010-06-06 17:58:34 +0200403 if (t->expire) {
404 t->exp_task->expire = t->exp_next = tick_first(ts->expire, t->exp_next);
405 task_queue(t->exp_task);
406 }
Emeric Brun85e77c72010-09-23 18:16:52 +0200407
Emeric Brun819fc6f2017-06-13 19:37:32 +0200408 /* If sync is enabled */
409 if (t->sync_task) {
410 if (local) {
411 /* If this entry is not in the tree
412 or not scheduled for at least one peer */
413 if (!ts->upd.node.leaf_p
414 || (int)(t->commitupdate - ts->upd.key) >= 0
415 || (int)(ts->upd.key - t->localupdate) >= 0) {
416 ts->upd.key = ++t->update;
417 t->localupdate = t->update;
418 eb32_delete(&ts->upd);
419 eb = eb32_insert(&t->updates, &ts->upd);
420 if (eb != &ts->upd) {
421 eb32_delete(eb);
422 eb32_insert(&t->updates, &ts->upd);
423 }
Emeric Brunaaf58602015-06-15 17:23:30 +0200424 }
Emeric Brun819fc6f2017-06-13 19:37:32 +0200425 task_wakeup(t->sync_task, TASK_WOKEN_MSG);
Emeric Brun85e77c72010-09-23 18:16:52 +0200426 }
Emeric Brun819fc6f2017-06-13 19:37:32 +0200427 else {
428 /* If this entry is not in the tree */
429 if (!ts->upd.node.leaf_p) {
430 ts->upd.key= (++t->update)+(2147483648U);
431 eb = eb32_insert(&t->updates, &ts->upd);
432 if (eb != &ts->upd) {
433 eb32_delete(eb);
434 eb32_insert(&t->updates, &ts->upd);
435 }
436 }
437 }
Emeric Brun85e77c72010-09-23 18:16:52 +0200438 }
Willy Tarreaucb183642010-06-06 17:58:34 +0200439}
440
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200441/* Update the expiration timer for <ts> but do not touch its expiration node.
Emeric Brun819fc6f2017-06-13 19:37:32 +0200442 * The table's expiration timer is updated using the date of expiration coming from
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200443 * <t> stick-table configuration.
Emeric Brun819fc6f2017-06-13 19:37:32 +0200444 * The node will be also inserted into the update tree if needed, at a position
445 * considering the update is coming from a remote node
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200446 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200447void stktable_touch_remote(struct stktable *t, struct stksess *ts, int decrefcnt)
448{
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100449 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200450 __stktable_touch_with_exp(t, ts, 0, ts->expire);
451 if (decrefcnt)
452 ts->ref_cnt--;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100453 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200454}
455
456/* Update the expiration timer for <ts> but do not touch its expiration node.
457 * The table's expiration timer is updated using the date of expiration coming from
458 * <t> stick-table configuration.
459 * The node will be also inserted into the update tree if needed, at a position
460 * considering the update was made locally
461 */
462void stktable_touch_local(struct stktable *t, struct stksess *ts, int decrefcnt)
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200463{
464 int expire = tick_add(now_ms, MS_TO_TICKS(t->expire));
465
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100466 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200467 __stktable_touch_with_exp(t, ts, 1, expire);
468 if (decrefcnt)
469 ts->ref_cnt--;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100470 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200471}
Willy Tarreau43e90352018-06-27 06:25:57 +0200472/* Just decrease the ref_cnt of the current session. Does nothing if <ts> is NULL */
473static void stktable_release(struct stktable *t, struct stksess *ts)
Emeric Brun819fc6f2017-06-13 19:37:32 +0200474{
Willy Tarreau43e90352018-06-27 06:25:57 +0200475 if (!ts)
476 return;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100477 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200478 ts->ref_cnt--;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100479 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200480}
481
Willy Tarreauf16d2b82010-06-06 15:38:59 +0200482/* Insert new sticky session <ts> in the table. It is assumed that it does not
483 * yet exist (the caller must check this). The table's timeout is updated if it
484 * is set. <ts> is returned.
485 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200486void __stktable_store(struct stktable *t, struct stksess *ts)
Willy Tarreauf16d2b82010-06-06 15:38:59 +0200487{
Emeric Brun3bd697e2010-01-04 15:23:48 +0100488
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200489 ebmb_insert(&t->keys, &ts->key, t->key_size);
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200490 ts->exp.key = ts->expire;
491 eb32_insert(&t->exps, &ts->exp);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200492 if (t->expire) {
493 t->exp_task->expire = t->exp_next = tick_first(ts->expire, t->exp_next);
494 task_queue(t->exp_task);
495 }
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200496}
497
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200498/* Returns a valid or initialized stksess for the specified stktable_key in the
499 * specified table, or NULL if the key was NULL, or if no entry was found nor
500 * could be created. The entry's expiration is updated.
501 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200502struct stksess *__stktable_get_entry(struct stktable *table, struct stktable_key *key)
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200503{
504 struct stksess *ts;
505
506 if (!key)
507 return NULL;
508
Emeric Brun819fc6f2017-06-13 19:37:32 +0200509 ts = __stktable_lookup_key(table, key);
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200510 if (ts == NULL) {
511 /* entry does not exist, initialize a new one */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200512 ts = __stksess_new(table, key);
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200513 if (!ts)
514 return NULL;
Emeric Brun819fc6f2017-06-13 19:37:32 +0200515 __stktable_store(table, ts);
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200516 }
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200517 return ts;
518}
Emeric Brun819fc6f2017-06-13 19:37:32 +0200519/* Returns a valid or initialized stksess for the specified stktable_key in the
520 * specified table, or NULL if the key was NULL, or if no entry was found nor
521 * could be created. The entry's expiration is updated.
522 * This function locks the table, and the refcount of the entry is increased.
523 */
524struct stksess *stktable_get_entry(struct stktable *table, struct stktable_key *key)
525{
526 struct stksess *ts;
527
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100528 HA_SPIN_LOCK(STK_TABLE_LOCK, &table->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200529 ts = __stktable_get_entry(table, key);
530 if (ts)
531 ts->ref_cnt++;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100532 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &table->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200533
534 return ts;
535}
536
537/* Lookup for an entry with the same key and store the submitted
538 * stksess if not found.
539 */
540struct stksess *__stktable_set_entry(struct stktable *table, struct stksess *nts)
541{
542 struct stksess *ts;
543
544 ts = __stktable_lookup(table, nts);
545 if (ts == NULL) {
546 ts = nts;
547 __stktable_store(table, ts);
548 }
549 return ts;
550}
551
552/* Lookup for an entry with the same key and store the submitted
553 * stksess if not found.
554 * This function locks the table, and the refcount of the entry is increased.
555 */
556struct stksess *stktable_set_entry(struct stktable *table, struct stksess *nts)
557{
558 struct stksess *ts;
559
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100560 HA_SPIN_LOCK(STK_TABLE_LOCK, &table->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200561 ts = __stktable_set_entry(table, nts);
562 ts->ref_cnt++;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100563 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &table->lock);
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200564
Emeric Brun819fc6f2017-06-13 19:37:32 +0200565 return ts;
566}
Emeric Brun3bd697e2010-01-04 15:23:48 +0100567/*
Willy Tarreaud2636522022-11-14 18:02:44 +0100568 * Task processing function to trash expired sticky sessions. A pointer to the
569 * task itself is returned since it never dies.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100570 */
Willy Tarreaud2636522022-11-14 18:02:44 +0100571struct task *process_table_expire(struct task *task, void *context, unsigned int state)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100572{
Willy Tarreaud2636522022-11-14 18:02:44 +0100573 struct stktable *t = context;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100574 struct stksess *ts;
575 struct eb32_node *eb;
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200576 int looped = 0;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100577
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100578 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100579 eb = eb32_lookup_ge(&t->exps, now_ms - TIMER_LOOK_BACK);
580
581 while (1) {
582 if (unlikely(!eb)) {
583 /* we might have reached the end of the tree, typically because
584 * <now_ms> is in the first half and we're first scanning the last
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200585 * half. Let's loop back to the beginning of the tree now if we
586 * have not yet visited it.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100587 */
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200588 if (looped)
589 break;
590 looped = 1;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100591 eb = eb32_first(&t->exps);
592 if (likely(!eb))
593 break;
594 }
595
596 if (likely(tick_is_lt(now_ms, eb->key))) {
597 /* timer not expired yet, revisit it later */
598 t->exp_next = eb->key;
Willy Tarreau4d5f13c2017-11-05 11:04:47 +0100599 goto out_unlock;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100600 }
601
602 /* timer looks expired, detach it from the queue */
Willy Tarreau86257dc2010-06-06 12:57:10 +0200603 ts = eb32_entry(eb, struct stksess, exp);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100604 eb = eb32_next(eb);
605
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200606 /* don't delete an entry which is currently referenced */
607 if (ts->ref_cnt)
608 continue;
609
Willy Tarreau86257dc2010-06-06 12:57:10 +0200610 eb32_delete(&ts->exp);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100611
612 if (!tick_is_expired(ts->expire, now_ms)) {
613 if (!tick_isset(ts->expire))
614 continue;
615
Willy Tarreau86257dc2010-06-06 12:57:10 +0200616 ts->exp.key = ts->expire;
617 eb32_insert(&t->exps, &ts->exp);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100618
Aleksey Ponomaryovb38ad122023-02-07 19:27:06 +0100619 /* the update might have jumped beyond the next element,
620 * possibly causing a wrapping. We need to check whether
621 * the next element should be used instead. If the next
622 * element doesn't exist it means we're on the right
623 * side and have to check the first one then. If it
624 * exists and is closer, we must use it, otherwise we
625 * use the current one.
626 */
627 if (!eb)
628 eb = eb32_first(&t->exps);
629
630 if (!eb || tick_is_lt(ts->exp.key, eb->key))
Willy Tarreau86257dc2010-06-06 12:57:10 +0200631 eb = &ts->exp;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100632 continue;
633 }
634
635 /* session expired, trash it */
Willy Tarreau86257dc2010-06-06 12:57:10 +0200636 ebmb_delete(&ts->key);
Emeric Brun85e77c72010-09-23 18:16:52 +0200637 eb32_delete(&ts->upd);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200638 __stksess_free(t, ts);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100639 }
640
641 /* We have found no task to expire in any tree */
642 t->exp_next = TICK_ETERNITY;
Willy Tarreau4d5f13c2017-11-05 11:04:47 +0100643out_unlock:
Willy Tarreaud2636522022-11-14 18:02:44 +0100644 task->expire = t->exp_next;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100645 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100646 return task;
647}
648
Willy Tarreauaea940e2010-06-06 11:56:36 +0200649/* Perform minimal stick table intializations, report 0 in case of error, 1 if OK. */
Emeric Brun3bd697e2010-01-04 15:23:48 +0100650int stktable_init(struct stktable *t)
651{
Remi Tricot-Le Bretonbe5b1bb2021-05-12 17:39:04 +0200652 int peers_retval = 0;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100653 if (t->size) {
Emeric Brun819fc6f2017-06-13 19:37:32 +0200654 t->keys = EB_ROOT_UNIQUE;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100655 memset(&t->exps, 0, sizeof(t->exps));
Emeric Brun1c6235d2015-12-16 15:28:12 +0100656 t->updates = EB_ROOT_UNIQUE;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100657 HA_SPIN_INIT(&t->lock);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100658
Olivier Houchard52dabbc2018-11-14 17:54:36 +0100659 t->pool = create_pool("sticktables", sizeof(struct stksess) + round_ptr_size(t->data_size) + t->key_size, MEM_F_SHARED);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100660
661 t->exp_next = TICK_ETERNITY;
662 if ( t->expire ) {
Emeric Brunc60def82017-09-27 14:59:38 +0200663 t->exp_task = task_new(MAX_THREADS_MASK);
Willy Tarreau848522f2018-10-15 11:12:15 +0200664 if (!t->exp_task)
665 return 0;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100666 t->exp_task->process = process_table_expire;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100667 t->exp_task->context = (void *)t;
668 }
Willy Tarreauc3914d42020-09-24 08:39:22 +0200669 if (t->peers.p && t->peers.p->peers_fe && !t->peers.p->peers_fe->disabled) {
Remi Tricot-Le Bretonbe5b1bb2021-05-12 17:39:04 +0200670 peers_retval = peers_register_table(t->peers.p, t);
Emeric Brun32da3c42010-09-23 18:39:19 +0200671 }
672
Remi Tricot-Le Bretonbe5b1bb2021-05-12 17:39:04 +0200673 return (t->pool != NULL) && !peers_retval;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100674 }
675 return 1;
676}
677
Aurelien DARRAGON57049052023-11-16 16:17:12 +0100678/* Performs stick table cleanup: it's meant to be called after the table
679 * has been initialized ith stktable_init(), else it will lead to undefined
680 * behavior.
681 *
682 * However it does not free the table pointer itself
683 */
684void stktable_deinit(struct stktable *t)
685{
686 if (!t)
687 return;
Aurelien DARRAGONb34f6c42023-11-16 16:18:14 +0100688 task_destroy(t->exp_task);
Aurelien DARRAGON57049052023-11-16 16:17:12 +0100689 pool_destroy(t->pool);
690}
691
Emeric Brun3bd697e2010-01-04 15:23:48 +0100692/*
693 * Configuration keywords of known table types
694 */
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200695struct stktable_type stktable_types[SMP_TYPES] = {
696 [SMP_T_SINT] = { "integer", 0, 4 },
697 [SMP_T_IPV4] = { "ip", 0, 4 },
698 [SMP_T_IPV6] = { "ipv6", 0, 16 },
699 [SMP_T_STR] = { "string", STK_F_CUSTOM_KEYSIZE, 32 },
700 [SMP_T_BIN] = { "binary", STK_F_CUSTOM_KEYSIZE, 32 }
701};
Emeric Brun3bd697e2010-01-04 15:23:48 +0100702
703/*
704 * Parse table type configuration.
705 * Returns 0 on successful parsing, else 1.
706 * <myidx> is set at next configuration <args> index.
707 */
William Lallemand42b46252023-04-13 14:33:52 +0200708int stktable_parse_type(char **args, int *myidx, unsigned long *type, size_t *key_size, const char *file, int linenum)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100709{
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200710 for (*type = 0; *type < SMP_TYPES; (*type)++) {
711 if (!stktable_types[*type].kw)
712 continue;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100713 if (strcmp(args[*myidx], stktable_types[*type].kw) != 0)
714 continue;
715
716 *key_size = stktable_types[*type].default_size;
717 (*myidx)++;
718
Willy Tarreauaea940e2010-06-06 11:56:36 +0200719 if (stktable_types[*type].flags & STK_F_CUSTOM_KEYSIZE) {
Emeric Brun3bd697e2010-01-04 15:23:48 +0100720 if (strcmp("len", args[*myidx]) == 0) {
William Lallemand42b46252023-04-13 14:33:52 +0200721 char *stop;
722
Emeric Brun3bd697e2010-01-04 15:23:48 +0100723 (*myidx)++;
William Lallemand42b46252023-04-13 14:33:52 +0200724 *key_size = strtol(args[*myidx], &stop, 10);
725 if (*stop != '\0' || !*key_size) {
726 ha_alert("parsing [%s:%d] : 'len' expects a positive integer argument.\n", file, linenum);
727 return 1;
728 }
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200729 if (*type == SMP_T_STR) {
Emeric Brun485479d2010-09-23 18:02:19 +0200730 /* null terminated string needs +1 for '\0'. */
731 (*key_size)++;
732 }
Emeric Brun3bd697e2010-01-04 15:23:48 +0100733 (*myidx)++;
734 }
735 }
736 return 0;
737 }
William Lallemand42b46252023-04-13 14:33:52 +0200738 ha_alert("parsing [%s:%d] : %s: unknown type '%s'.\n", file, linenum, args[0], args[*myidx]);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100739 return 1;
740}
741
Willy Tarreau3b63ca22021-05-08 14:10:42 +0200742/* reserve some space for data type <type>, and associate argument at <sa> if
743 * not NULL. Returns PE_NONE (0) if OK or an error code among :
744 * - PE_ENUM_OOR if <type> does not exist
745 * - PE_EXIST if <type> is already registered
746 * - PE_ARG_NOT_USE if <sa> was provided but not expected
747 * - PE_ARG_MISSING if <sa> was expected but not provided
748 */
749int stktable_alloc_data_type(struct stktable *t, int type, const char *sa)
750{
751 if (type >= STKTABLE_DATA_TYPES)
752 return PE_ENUM_OOR;
753
754 if (t->data_ofs[type])
755 /* already allocated */
756 return PE_EXIST;
757
758 switch (stktable_data_types[type].arg_type) {
759 case ARG_T_NONE:
760 if (sa)
761 return PE_ARG_NOT_USED;
762 break;
763 case ARG_T_INT:
764 if (!sa)
765 return PE_ARG_MISSING;
766 t->data_arg[type].i = atoi(sa);
767 break;
768 case ARG_T_DELAY:
769 if (!sa)
770 return PE_ARG_MISSING;
771 sa = parse_time_err(sa, &t->data_arg[type].u, TIME_UNIT_MS);
772 if (sa)
773 return PE_ARG_INVC; /* invalid char */
774 break;
775 }
776
777 t->data_size += stktable_type_size(stktable_data_types[type].std_type);
778 t->data_ofs[type] = -t->data_size;
779 return PE_NONE;
780}
781
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100782/*
Frédéric Lécaillec02766a2019-03-20 15:06:55 +0100783 * Parse a line with <linenum> as number in <file> configuration file to configure
784 * the stick-table with <t> as address and <id> as ID.
785 * <peers> provides the "peers" section pointer only if this function is called
786 * from a "peers" section.
787 * <nid> is the stick-table name which is sent over the network. It must be equal
788 * to <id> if this stick-table is parsed from a proxy section, and prefixed by <peers>
789 * "peers" section name followed by a '/' character if parsed from a "peers" section.
Ilya Shipitsind4259502020-04-08 01:07:56 +0500790 * This is the responsibility of the caller to check this.
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100791 * Return an error status with ERR_* flags set if required, 0 if no error was encountered.
792 */
793int parse_stick_table(const char *file, int linenum, char **args,
Frédéric Lécaillec02766a2019-03-20 15:06:55 +0100794 struct stktable *t, char *id, char *nid, struct peers *peers)
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100795{
796 int err_code = 0;
797 int idx = 1;
798 unsigned int val;
799
800 if (!id || !*id) {
801 ha_alert("parsing [%s:%d] : %s: ID not provided.\n", file, linenum, args[0]);
802 err_code |= ERR_ALERT | ERR_ABORT;
803 goto out;
804 }
805
806 /* Store the "peers" section if this function is called from a "peers" section. */
807 if (peers) {
808 t->peers.p = peers;
809 idx++;
810 }
811
812 t->id = id;
Frédéric Lécaillec02766a2019-03-20 15:06:55 +0100813 t->nid = nid;
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100814 t->type = (unsigned int)-1;
815 t->conf.file = file;
816 t->conf.line = linenum;
817
818 while (*args[idx]) {
819 const char *err;
820
821 if (strcmp(args[idx], "size") == 0) {
822 idx++;
823 if (!*(args[idx])) {
824 ha_alert("parsing [%s:%d] : %s: missing argument after '%s'.\n",
825 file, linenum, args[0], args[idx-1]);
826 err_code |= ERR_ALERT | ERR_FATAL;
827 goto out;
828 }
829 if ((err = parse_size_err(args[idx], &t->size))) {
830 ha_alert("parsing [%s:%d] : %s: unexpected character '%c' in argument of '%s'.\n",
831 file, linenum, args[0], *err, args[idx-1]);
832 err_code |= ERR_ALERT | ERR_FATAL;
833 goto out;
834 }
835 idx++;
836 }
837 /* This argument does not exit in "peers" section. */
838 else if (!peers && strcmp(args[idx], "peers") == 0) {
839 idx++;
840 if (!*(args[idx])) {
841 ha_alert("parsing [%s:%d] : %s: missing argument after '%s'.\n",
842 file, linenum, args[0], args[idx-1]);
843 err_code |= ERR_ALERT | ERR_FATAL;
844 goto out;
845 }
Aurelien DARRAGON7228dfd2023-11-02 09:18:55 +0100846 ha_free(&t->peers.name);
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100847 t->peers.name = strdup(args[idx++]);
848 }
849 else if (strcmp(args[idx], "expire") == 0) {
850 idx++;
851 if (!*(args[idx])) {
852 ha_alert("parsing [%s:%d] : %s: missing argument after '%s'.\n",
853 file, linenum, args[0], args[idx-1]);
854 err_code |= ERR_ALERT | ERR_FATAL;
855 goto out;
856 }
857 err = parse_time_err(args[idx], &val, TIME_UNIT_MS);
Willy Tarreau9faebe32019-06-07 19:00:37 +0200858 if (err == PARSE_TIME_OVER) {
859 ha_alert("parsing [%s:%d]: %s: timer overflow in argument <%s> to <%s>, maximum value is 2147483647 ms (~24.8 days).\n",
860 file, linenum, args[0], args[idx], args[idx-1]);
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100861 err_code |= ERR_ALERT | ERR_FATAL;
862 goto out;
863 }
Willy Tarreau9faebe32019-06-07 19:00:37 +0200864 else if (err == PARSE_TIME_UNDER) {
865 ha_alert("parsing [%s:%d]: %s: timer underflow in argument <%s> to <%s>, minimum non-null value is 1 ms.\n",
866 file, linenum, args[0], args[idx], args[idx-1]);
867 err_code |= ERR_ALERT | ERR_FATAL;
868 goto out;
869 }
870 else if (err) {
871 ha_alert("parsing [%s:%d] : %s: unexpected character '%c' in argument of '%s'.\n",
872 file, linenum, args[0], *err, args[idx-1]);
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100873 err_code |= ERR_ALERT | ERR_FATAL;
874 goto out;
875 }
876 t->expire = val;
877 idx++;
878 }
879 else if (strcmp(args[idx], "nopurge") == 0) {
880 t->nopurge = 1;
881 idx++;
882 }
883 else if (strcmp(args[idx], "type") == 0) {
884 idx++;
William Lallemand42b46252023-04-13 14:33:52 +0200885 if (stktable_parse_type(args, &idx, &t->type, &t->key_size, file, linenum) != 0) {
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100886 err_code |= ERR_ALERT | ERR_FATAL;
887 goto out;
888 }
889 /* idx already points to next arg */
890 }
891 else if (strcmp(args[idx], "store") == 0) {
892 int type, err;
893 char *cw, *nw, *sa;
894
895 idx++;
896 nw = args[idx];
897 while (*nw) {
898 /* the "store" keyword supports a comma-separated list */
899 cw = nw;
900 sa = NULL; /* store arg */
901 while (*nw && *nw != ',') {
902 if (*nw == '(') {
903 *nw = 0;
904 sa = ++nw;
905 while (*nw != ')') {
906 if (!*nw) {
907 ha_alert("parsing [%s:%d] : %s: missing closing parenthesis after store option '%s'.\n",
908 file, linenum, args[0], cw);
909 err_code |= ERR_ALERT | ERR_FATAL;
910 goto out;
911 }
912 nw++;
913 }
914 *nw = '\0';
915 }
916 nw++;
917 }
918 if (*nw)
919 *nw++ = '\0';
920 type = stktable_get_data_type(cw);
921 if (type < 0) {
922 ha_alert("parsing [%s:%d] : %s: unknown store option '%s'.\n",
923 file, linenum, args[0], cw);
924 err_code |= ERR_ALERT | ERR_FATAL;
925 goto out;
926 }
927
928 err = stktable_alloc_data_type(t, type, sa);
929 switch (err) {
930 case PE_NONE: break;
931 case PE_EXIST:
932 ha_warning("parsing [%s:%d]: %s: store option '%s' already enabled, ignored.\n",
933 file, linenum, args[0], cw);
934 err_code |= ERR_WARN;
935 break;
936
937 case PE_ARG_MISSING:
938 ha_alert("parsing [%s:%d] : %s: missing argument to store option '%s'.\n",
939 file, linenum, args[0], cw);
940 err_code |= ERR_ALERT | ERR_FATAL;
941 goto out;
942
943 case PE_ARG_NOT_USED:
944 ha_alert("parsing [%s:%d] : %s: unexpected argument to store option '%s'.\n",
945 file, linenum, args[0], cw);
946 err_code |= ERR_ALERT | ERR_FATAL;
947 goto out;
948
949 default:
950 ha_alert("parsing [%s:%d] : %s: error when processing store option '%s'.\n",
951 file, linenum, args[0], cw);
952 err_code |= ERR_ALERT | ERR_FATAL;
953 goto out;
954 }
955 }
956 idx++;
957 }
Thayne McCombs92149f92020-11-20 01:28:26 -0700958 else if (strcmp(args[idx], "srvkey") == 0) {
959 char *keytype;
960 idx++;
961 keytype = args[idx];
962 if (strcmp(keytype, "name") == 0) {
963 t->server_key_type = STKTABLE_SRV_NAME;
964 }
965 else if (strcmp(keytype, "addr") == 0) {
966 t->server_key_type = STKTABLE_SRV_ADDR;
967 }
968 else {
969 ha_alert("parsing [%s:%d] : %s : unknown server key type '%s'.\n",
970 file, linenum, args[0], keytype);
971 err_code |= ERR_ALERT | ERR_FATAL;
972 goto out;
973
974 }
975 idx++;
976 }
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100977 else {
978 ha_alert("parsing [%s:%d] : %s: unknown argument '%s'.\n",
979 file, linenum, args[0], args[idx]);
980 err_code |= ERR_ALERT | ERR_FATAL;
981 goto out;
982 }
983 }
984
985 if (!t->size) {
986 ha_alert("parsing [%s:%d] : %s: missing size.\n",
987 file, linenum, args[0]);
988 err_code |= ERR_ALERT | ERR_FATAL;
989 goto out;
990 }
991
992 if (t->type == (unsigned int)-1) {
993 ha_alert("parsing [%s:%d] : %s: missing type.\n",
994 file, linenum, args[0]);
995 err_code |= ERR_ALERT | ERR_FATAL;
996 goto out;
997 }
998
999 out:
1000 return err_code;
1001}
1002
Willy Tarreau8fed9032014-07-03 17:02:46 +02001003/* Prepares a stktable_key from a sample <smp> to search into table <t>.
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001004 * Note that the sample *is* modified and that the returned key may point
1005 * to it, so the sample must not be modified afterwards before the lookup.
Willy Tarreau8fed9032014-07-03 17:02:46 +02001006 * Returns NULL if the sample could not be converted (eg: no matching type),
1007 * otherwise a pointer to the static stktable_key filled with what is needed
1008 * for the lookup.
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001009 */
Willy Tarreau8fed9032014-07-03 17:02:46 +02001010struct stktable_key *smp_to_stkey(struct sample *smp, struct stktable *t)
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001011{
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001012 /* Convert sample. */
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +02001013 if (!sample_convert(smp, t->type))
Willy Tarreau7fc1c6e2012-04-26 11:03:17 +02001014 return NULL;
1015
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001016 /* Fill static_table_key. */
1017 switch (t->type) {
Emeric Brun485479d2010-09-23 18:02:19 +02001018
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +02001019 case SMP_T_IPV4:
Christopher Fauletca20d022017-08-29 15:30:31 +02001020 static_table_key.key = &smp->data.u.ipv4;
1021 static_table_key.key_len = 4;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001022 break;
Emeric Brun485479d2010-09-23 18:02:19 +02001023
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +02001024 case SMP_T_IPV6:
Christopher Fauletca20d022017-08-29 15:30:31 +02001025 static_table_key.key = &smp->data.u.ipv6;
1026 static_table_key.key_len = 16;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001027 break;
Emeric Brun485479d2010-09-23 18:02:19 +02001028
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +02001029 case SMP_T_SINT:
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001030 /* The stick table require a 32bit unsigned int, "sint" is a
1031 * signed 64 it, so we can convert it inplace.
1032 */
Willy Tarreau28c63c12019-10-23 06:21:05 +02001033 smp->data.u.sint = (unsigned int)smp->data.u.sint;
Christopher Fauletca20d022017-08-29 15:30:31 +02001034 static_table_key.key = &smp->data.u.sint;
1035 static_table_key.key_len = 4;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001036 break;
1037
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +02001038 case SMP_T_STR:
Willy Tarreauce6955e2016-08-09 11:59:12 +02001039 if (!smp_make_safe(smp))
1040 return NULL;
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001041 static_table_key.key = smp->data.u.str.area;
1042 static_table_key.key_len = smp->data.u.str.data;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001043 break;
Emeric Brun485479d2010-09-23 18:02:19 +02001044
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +02001045 case SMP_T_BIN:
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001046 if (smp->data.u.str.data < t->key_size) {
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001047 /* This type needs padding with 0. */
Willy Tarreauf65c6c02016-08-09 12:08:41 +02001048 if (!smp_make_rw(smp))
1049 return NULL;
1050
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001051 if (smp->data.u.str.size < t->key_size)
1052 if (!smp_dup(smp))
1053 return NULL;
1054 if (smp->data.u.str.size < t->key_size)
1055 return NULL;
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001056 memset(smp->data.u.str.area + smp->data.u.str.data, 0,
1057 t->key_size - smp->data.u.str.data);
1058 smp->data.u.str.data = t->key_size;
Emeric Brun485479d2010-09-23 18:02:19 +02001059 }
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001060 static_table_key.key = smp->data.u.str.area;
1061 static_table_key.key_len = smp->data.u.str.data;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001062 break;
Emeric Brun485479d2010-09-23 18:02:19 +02001063
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001064 default: /* impossible case. */
1065 return NULL;
Emeric Brun485479d2010-09-23 18:02:19 +02001066 }
1067
Christopher Fauletca20d022017-08-29 15:30:31 +02001068 return &static_table_key;
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001069}
1070
1071/*
Willy Tarreau8fed9032014-07-03 17:02:46 +02001072 * Process a fetch + format conversion as defined by the sample expression <expr>
1073 * on request or response considering the <opt> parameter. Returns either NULL if
1074 * no key could be extracted, or a pointer to the converted result stored in
1075 * static_table_key in format <table_type>. If <smp> is not NULL, it will be reset
1076 * and its flags will be initialized so that the caller gets a copy of the input
Willy Tarreau6bcb0a82014-07-30 08:56:35 +02001077 * sample, and knows why it was not accepted (eg: SMP_F_MAY_CHANGE is present
1078 * without SMP_OPT_FINAL). The output will be usable like this :
1079 *
1080 * return MAY_CHANGE FINAL Meaning for the sample
1081 * NULL 0 * Not present and will never be (eg: header)
1082 * NULL 1 0 Not present or unstable, could change (eg: req_len)
1083 * NULL 1 1 Not present, will not change anymore
1084 * smp 0 * Present and will not change (eg: header)
1085 * smp 1 0 not possible
1086 * smp 1 1 Present, last known value (eg: request length)
Willy Tarreau8fed9032014-07-03 17:02:46 +02001087 */
Willy Tarreau192252e2015-04-04 01:47:55 +02001088struct stktable_key *stktable_fetch_key(struct stktable *t, struct proxy *px, struct session *sess, struct stream *strm,
Willy Tarreau8fed9032014-07-03 17:02:46 +02001089 unsigned int opt, struct sample_expr *expr, struct sample *smp)
1090{
1091 if (smp)
1092 memset(smp, 0, sizeof(*smp));
1093
Willy Tarreau192252e2015-04-04 01:47:55 +02001094 smp = sample_process(px, sess, strm, opt, expr, smp);
Willy Tarreau8fed9032014-07-03 17:02:46 +02001095 if (!smp)
1096 return NULL;
1097
1098 if ((smp->flags & SMP_F_MAY_CHANGE) && !(opt & SMP_OPT_FINAL))
1099 return NULL; /* we can only use stable samples */
1100
1101 return smp_to_stkey(smp, t);
1102}
1103
1104/*
Willy Tarreau12785782012-04-27 21:37:17 +02001105 * Returns 1 if sample expression <expr> result can be converted to table key of
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001106 * type <table_type>, otherwise zero. Used in configuration check.
1107 */
Willy Tarreau12785782012-04-27 21:37:17 +02001108int stktable_compatible_sample(struct sample_expr *expr, unsigned long table_type)
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001109{
Thierry FOURNIERf73eb8f2013-11-27 15:30:55 +01001110 int out_type;
1111
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +02001112 if (table_type >= SMP_TYPES || !stktable_types[table_type].kw)
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001113 return 0;
1114
Thierry FOURNIERf73eb8f2013-11-27 15:30:55 +01001115 out_type = smp_expr_output_type(expr);
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001116
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001117 /* Convert sample. */
1118 if (!sample_casts[out_type][table_type])
Thierry FOURNIERf73eb8f2013-11-27 15:30:55 +01001119 return 0;
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001120
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001121 return 1;
1122}
Emeric Brun3bd697e2010-01-04 15:23:48 +01001123
Willy Tarreauedee1d62014-07-15 16:44:27 +02001124/* Extra data types processing : after the last one, some room may remain
1125 * before STKTABLE_DATA_TYPES that may be used to register extra data types
1126 * at run time.
1127 */
Willy Tarreau08d5f982010-06-06 13:34:54 +02001128struct stktable_data_type stktable_data_types[STKTABLE_DATA_TYPES] = {
Willy Tarreau3b9c6e02010-07-18 08:04:30 +02001129 [STKTABLE_DT_SERVER_ID] = { .name = "server_id", .std_type = STD_T_SINT },
Thierry FOURNIER3cf11112015-07-28 08:57:05 +02001130 [STKTABLE_DT_GPT0] = { .name = "gpt0", .std_type = STD_T_UINT },
Willy Tarreau3b9c6e02010-07-18 08:04:30 +02001131 [STKTABLE_DT_GPC0] = { .name = "gpc0", .std_type = STD_T_UINT },
Willy Tarreauba2ffd12013-05-29 15:54:14 +02001132 [STKTABLE_DT_GPC0_RATE] = { .name = "gpc0_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
Willy Tarreau3b9c6e02010-07-18 08:04:30 +02001133 [STKTABLE_DT_CONN_CNT] = { .name = "conn_cnt", .std_type = STD_T_UINT },
1134 [STKTABLE_DT_CONN_RATE] = { .name = "conn_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
1135 [STKTABLE_DT_CONN_CUR] = { .name = "conn_cur", .std_type = STD_T_UINT },
1136 [STKTABLE_DT_SESS_CNT] = { .name = "sess_cnt", .std_type = STD_T_UINT },
1137 [STKTABLE_DT_SESS_RATE] = { .name = "sess_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
1138 [STKTABLE_DT_HTTP_REQ_CNT] = { .name = "http_req_cnt", .std_type = STD_T_UINT },
1139 [STKTABLE_DT_HTTP_REQ_RATE] = { .name = "http_req_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
1140 [STKTABLE_DT_HTTP_ERR_CNT] = { .name = "http_err_cnt", .std_type = STD_T_UINT },
1141 [STKTABLE_DT_HTTP_ERR_RATE] = { .name = "http_err_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
1142 [STKTABLE_DT_BYTES_IN_CNT] = { .name = "bytes_in_cnt", .std_type = STD_T_ULL },
1143 [STKTABLE_DT_BYTES_IN_RATE] = { .name = "bytes_in_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
1144 [STKTABLE_DT_BYTES_OUT_CNT] = { .name = "bytes_out_cnt", .std_type = STD_T_ULL },
1145 [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 +01001146 [STKTABLE_DT_GPC1] = { .name = "gpc1", .std_type = STD_T_UINT },
1147 [STKTABLE_DT_GPC1_RATE] = { .name = "gpc1_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
Thayne McCombs92149f92020-11-20 01:28:26 -07001148 [STKTABLE_DT_SERVER_KEY] = { .name = "server_key", .std_type = STD_T_DICT },
Willy Tarreau826f3ab2021-02-10 12:07:15 +01001149 [STKTABLE_DT_HTTP_FAIL_CNT] = { .name = "http_fail_cnt", .std_type = STD_T_UINT },
1150 [STKTABLE_DT_HTTP_FAIL_RATE]= { .name = "http_fail_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
Willy Tarreau08d5f982010-06-06 13:34:54 +02001151};
1152
Willy Tarreauedee1d62014-07-15 16:44:27 +02001153/* Registers stick-table extra data type with index <idx>, name <name>, type
1154 * <std_type> and arg type <arg_type>. If the index is negative, the next free
1155 * index is automatically allocated. The allocated index is returned, or -1 if
1156 * no free index was found or <name> was already registered. The <name> is used
1157 * directly as a pointer, so if it's not stable, the caller must allocate it.
1158 */
1159int stktable_register_data_store(int idx, const char *name, int std_type, int arg_type)
1160{
1161 if (idx < 0) {
1162 for (idx = 0; idx < STKTABLE_DATA_TYPES; idx++) {
1163 if (!stktable_data_types[idx].name)
1164 break;
1165
1166 if (strcmp(stktable_data_types[idx].name, name) == 0)
1167 return -1;
1168 }
1169 }
1170
1171 if (idx >= STKTABLE_DATA_TYPES)
1172 return -1;
1173
1174 if (stktable_data_types[idx].name != NULL)
1175 return -1;
1176
1177 stktable_data_types[idx].name = name;
1178 stktable_data_types[idx].std_type = std_type;
1179 stktable_data_types[idx].arg_type = arg_type;
1180 return idx;
1181}
1182
Willy Tarreau08d5f982010-06-06 13:34:54 +02001183/*
1184 * Returns the data type number for the stktable_data_type whose name is <name>,
1185 * or <0 if not found.
1186 */
1187int stktable_get_data_type(char *name)
1188{
1189 int type;
1190
1191 for (type = 0; type < STKTABLE_DATA_TYPES; type++) {
Willy Tarreauedee1d62014-07-15 16:44:27 +02001192 if (!stktable_data_types[type].name)
1193 continue;
Willy Tarreau08d5f982010-06-06 13:34:54 +02001194 if (strcmp(name, stktable_data_types[type].name) == 0)
1195 return type;
1196 }
Thayne McCombs92149f92020-11-20 01:28:26 -07001197 /* For backwards compatibility */
1198 if (strcmp(name, "server_name") == 0)
1199 return STKTABLE_DT_SERVER_KEY;
Willy Tarreau08d5f982010-06-06 13:34:54 +02001200 return -1;
1201}
1202
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001203/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1204 * it up into this table. Returns true if found, false otherwise. The input
1205 * type is STR so that input samples are converted to string (since all types
1206 * can be converted to strings), then the function casts the string again into
1207 * the table's type. This is a double conversion, but in the future we might
1208 * support automatic input types to perform the cast on the fly.
1209 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001210static int sample_conv_in_table(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001211{
1212 struct stktable *t;
1213 struct stktable_key *key;
1214 struct stksess *ts;
1215
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001216 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001217
1218 key = smp_to_stkey(smp, t);
1219 if (!key)
1220 return 0;
1221
1222 ts = stktable_lookup_key(t, key);
1223
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001224 smp->data.type = SMP_T_BOOL;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001225 smp->data.u.sint = !!ts;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001226 smp->flags = SMP_F_VOL_TEST;
Willy Tarreau43e90352018-06-27 06:25:57 +02001227 stktable_release(t, ts);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001228 return 1;
1229}
1230
1231/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1232 * it up into this table. Returns the data rate received from clients in bytes/s
1233 * if the key is present in the table, otherwise zero, so that comparisons can
1234 * be easily performed. If the inspected parameter is not stored in the table,
1235 * <not found> is returned.
1236 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001237static int sample_conv_table_bytes_in_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001238{
1239 struct stktable *t;
1240 struct stktable_key *key;
1241 struct stksess *ts;
1242 void *ptr;
1243
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001244 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001245
1246 key = smp_to_stkey(smp, t);
1247 if (!key)
1248 return 0;
1249
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001250 ts = stktable_lookup_key(t, key);
1251
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001252 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001253 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001254 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001255
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001256 if (!ts) /* key not present */
1257 return 1;
1258
1259 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_IN_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001260 if (ptr)
1261 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, bytes_in_rate),
1262 t->data_arg[STKTABLE_DT_BYTES_IN_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001263
Daniel Corbett3e60b112018-05-27 09:47:12 -04001264 stktable_release(t, ts);
1265 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001266}
1267
1268/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1269 * it up into this table. Returns the cumulated number of connections for the key
1270 * if the key is present in the table, otherwise zero, so that comparisons can
1271 * be easily performed. If the inspected parameter is not stored in the table,
1272 * <not found> is returned.
1273 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001274static int sample_conv_table_conn_cnt(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001275{
1276 struct stktable *t;
1277 struct stktable_key *key;
1278 struct stksess *ts;
1279 void *ptr;
1280
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001281 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001282
1283 key = smp_to_stkey(smp, t);
1284 if (!key)
1285 return 0;
1286
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001287 ts = stktable_lookup_key(t, key);
1288
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001289 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001290 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001291 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001292
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001293 if (!ts) /* key not present */
1294 return 1;
1295
1296 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_CONN_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001297 if (ptr)
1298 smp->data.u.sint = stktable_data_cast(ptr, conn_cnt);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001299
Daniel Corbett3e60b112018-05-27 09:47:12 -04001300 stktable_release(t, ts);
1301 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001302}
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 number of concurrent connections for the
1306 * key if the key is present in the table, otherwise zero, so that comparisons
1307 * can be easily performed. If the inspected parameter is not stored in the
1308 * table, <not found> is returned.
1309 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001310static int sample_conv_table_conn_cur(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_CONN_CUR);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001333 if (ptr)
1334 smp->data.u.sint = stktable_data_cast(ptr, conn_cur);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001335
Daniel Corbett3e60b112018-05-27 09:47:12 -04001336 stktable_release(t, ts);
1337 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001338}
1339
1340/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1341 * it up into this table. Returns the rate of incoming connections from the key
1342 * if the key is present in the table, otherwise zero, so that comparisons can
1343 * be easily performed. If the inspected parameter is not stored in the table,
1344 * <not found> is returned.
1345 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001346static int sample_conv_table_conn_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001347{
1348 struct stktable *t;
1349 struct stktable_key *key;
1350 struct stksess *ts;
1351 void *ptr;
1352
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001353 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001354
1355 key = smp_to_stkey(smp, t);
1356 if (!key)
1357 return 0;
1358
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001359 ts = stktable_lookup_key(t, key);
1360
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001361 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001362 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001363 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001364
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001365 if (!ts) /* key not present */
1366 return 1;
1367
1368 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_CONN_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001369 if (ptr)
1370 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, conn_rate),
1371 t->data_arg[STKTABLE_DT_CONN_RATE].u);
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 data rate sent to clients in bytes/s
1379 * if the key is present in the table, otherwise zero, so that comparisons can
1380 * be easily performed. If the inspected parameter is not stored in the table,
1381 * <not found> is returned.
1382 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001383static int sample_conv_table_bytes_out_rate(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_BYTES_OUT_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001406 if (ptr)
1407 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, bytes_out_rate),
1408 t->data_arg[STKTABLE_DT_BYTES_OUT_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001409
Daniel Corbett3e60b112018-05-27 09:47:12 -04001410 stktable_release(t, ts);
1411 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001412}
1413
1414/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001415 * it up into this table. Returns the value of the GPT0 tag for the key
1416 * if the key is present in the table, otherwise false, so that comparisons can
1417 * be easily performed. If the inspected parameter is not stored in the table,
1418 * <not found> is returned.
1419 */
1420static int sample_conv_table_gpt0(const struct arg *arg_p, struct sample *smp, void *private)
1421{
1422 struct stktable *t;
1423 struct stktable_key *key;
1424 struct stksess *ts;
1425 void *ptr;
1426
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001427 t = arg_p[0].data.t;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001428
1429 key = smp_to_stkey(smp, t);
1430 if (!key)
1431 return 0;
1432
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001433 ts = stktable_lookup_key(t, key);
1434
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001435 smp->flags = SMP_F_VOL_TEST;
1436 smp->data.type = SMP_T_SINT;
1437 smp->data.u.sint = 0;
1438
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001439 if (!ts) /* key not present */
1440 return 1;
1441
1442 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPT0);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001443 if (ptr)
1444 smp->data.u.sint = stktable_data_cast(ptr, gpt0);
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001445
Daniel Corbett3e60b112018-05-27 09:47:12 -04001446 stktable_release(t, ts);
1447 return !!ptr;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001448}
1449
1450/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001451 * it up into this table. Returns the value of the GPC0 counter for the key
1452 * if the key is present in the table, otherwise zero, so that comparisons can
1453 * be easily performed. If the inspected parameter is not stored in the table,
1454 * <not found> is returned.
1455 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001456static int sample_conv_table_gpc0(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001457{
1458 struct stktable *t;
1459 struct stktable_key *key;
1460 struct stksess *ts;
1461 void *ptr;
1462
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001463 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001464
1465 key = smp_to_stkey(smp, t);
1466 if (!key)
1467 return 0;
1468
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001469 ts = stktable_lookup_key(t, key);
1470
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001471 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001472 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001473 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001474
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001475 if (!ts) /* key not present */
1476 return 1;
1477
1478 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPC0);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001479 if (ptr)
1480 smp->data.u.sint = stktable_data_cast(ptr, gpc0);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001481
Daniel Corbett3e60b112018-05-27 09:47:12 -04001482 stktable_release(t, ts);
1483 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001484}
1485
1486/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1487 * it up into this table. Returns the event rate of the GPC0 counter for the key
1488 * if the key is present in the table, otherwise zero, so that comparisons can
1489 * be easily performed. If the inspected parameter is not stored in the table,
1490 * <not found> is returned.
1491 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001492static int sample_conv_table_gpc0_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001493{
1494 struct stktable *t;
1495 struct stktable_key *key;
1496 struct stksess *ts;
1497 void *ptr;
1498
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001499 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001500
1501 key = smp_to_stkey(smp, t);
1502 if (!key)
1503 return 0;
1504
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001505 ts = stktable_lookup_key(t, key);
1506
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001507 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001508 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001509 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001510
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001511 if (!ts) /* key not present */
1512 return 1;
1513
1514 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPC0_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001515 if (ptr)
1516 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, gpc0_rate),
1517 t->data_arg[STKTABLE_DT_GPC0_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001518
Daniel Corbett3e60b112018-05-27 09:47:12 -04001519 stktable_release(t, ts);
1520 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001521}
1522
1523/* 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 +01001524 * it up into this table. Returns the value of the GPC1 counter for the key
1525 * if the key is present in the table, otherwise zero, so that comparisons can
1526 * be easily performed. If the inspected parameter is not stored in the table,
1527 * <not found> is returned.
1528 */
1529static int sample_conv_table_gpc1(const struct arg *arg_p, struct sample *smp, void *private)
1530{
1531 struct stktable *t;
1532 struct stktable_key *key;
1533 struct stksess *ts;
1534 void *ptr;
1535
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001536 t = arg_p[0].data.t;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001537
1538 key = smp_to_stkey(smp, t);
1539 if (!key)
1540 return 0;
1541
1542 ts = stktable_lookup_key(t, key);
1543
1544 smp->flags = SMP_F_VOL_TEST;
1545 smp->data.type = SMP_T_SINT;
1546 smp->data.u.sint = 0;
1547
1548 if (!ts) /* key not present */
1549 return 1;
1550
1551 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPC1);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001552 if (ptr)
1553 smp->data.u.sint = stktable_data_cast(ptr, gpc1);
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001554
Daniel Corbett3e60b112018-05-27 09:47:12 -04001555 stktable_release(t, ts);
1556 return !!ptr;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001557}
1558
1559/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1560 * it up into this table. Returns the event rate of the GPC1 counter for the key
1561 * if the key is present in the table, otherwise zero, so that comparisons can
1562 * be easily performed. If the inspected parameter is not stored in the table,
1563 * <not found> is returned.
1564 */
1565static int sample_conv_table_gpc1_rate(const struct arg *arg_p, struct sample *smp, void *private)
1566{
1567 struct stktable *t;
1568 struct stktable_key *key;
1569 struct stksess *ts;
1570 void *ptr;
1571
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001572 t = arg_p[0].data.t;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001573
1574 key = smp_to_stkey(smp, t);
1575 if (!key)
1576 return 0;
1577
1578 ts = stktable_lookup_key(t, key);
1579
1580 smp->flags = SMP_F_VOL_TEST;
1581 smp->data.type = SMP_T_SINT;
1582 smp->data.u.sint = 0;
1583
1584 if (!ts) /* key not present */
1585 return 1;
1586
1587 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPC1_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001588 if (ptr)
1589 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, gpc1_rate),
1590 t->data_arg[STKTABLE_DT_GPC1_RATE].u);
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001591
Daniel Corbett3e60b112018-05-27 09:47:12 -04001592 stktable_release(t, ts);
1593 return !!ptr;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001594}
1595
1596/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001597 * it up into this table. Returns the cumulated number of HTTP request errors
1598 * for the key if the key is present in the table, otherwise zero, so that
1599 * comparisons can be easily performed. If the inspected parameter is not stored
1600 * in the table, <not found> is returned.
1601 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001602static int sample_conv_table_http_err_cnt(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001603{
1604 struct stktable *t;
1605 struct stktable_key *key;
1606 struct stksess *ts;
1607 void *ptr;
1608
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001609 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001610
1611 key = smp_to_stkey(smp, t);
1612 if (!key)
1613 return 0;
1614
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001615 ts = stktable_lookup_key(t, key);
1616
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001617 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001618 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001619 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001620
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001621 if (!ts) /* key not present */
1622 return 1;
1623
1624 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_ERR_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001625 if (ptr)
1626 smp->data.u.sint = stktable_data_cast(ptr, http_err_cnt);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001627
Daniel Corbett3e60b112018-05-27 09:47:12 -04001628 stktable_release(t, ts);
1629 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001630}
1631
1632/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1633 * it up into this table. Returns the HTTP request error rate the key
1634 * if the key is present in the table, otherwise zero, so that comparisons can
1635 * be easily performed. If the inspected parameter is not stored in the table,
1636 * <not found> is returned.
1637 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001638static int sample_conv_table_http_err_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001639{
1640 struct stktable *t;
1641 struct stktable_key *key;
1642 struct stksess *ts;
1643 void *ptr;
1644
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001645 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001646
1647 key = smp_to_stkey(smp, t);
1648 if (!key)
1649 return 0;
1650
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001651 ts = stktable_lookup_key(t, key);
1652
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001653 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001654 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001655 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001656
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001657 if (!ts) /* key not present */
1658 return 1;
1659
1660 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_ERR_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001661 if (ptr)
1662 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, http_err_rate),
1663 t->data_arg[STKTABLE_DT_HTTP_ERR_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001664
Daniel Corbett3e60b112018-05-27 09:47:12 -04001665 stktable_release(t, ts);
1666 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001667}
1668
1669/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Willy Tarreau826f3ab2021-02-10 12:07:15 +01001670 * it up into this table. Returns the cumulated number of HTTP response failures
1671 * for the key if the key is present in the table, otherwise zero, so that
1672 * comparisons can be easily performed. If the inspected parameter is not stored
1673 * in the table, <not found> is returned.
1674 */
1675static int sample_conv_table_http_fail_cnt(const struct arg *arg_p, struct sample *smp, void *private)
1676{
1677 struct stktable *t;
1678 struct stktable_key *key;
1679 struct stksess *ts;
1680 void *ptr;
1681
1682 t = arg_p[0].data.t;
1683
1684 key = smp_to_stkey(smp, t);
1685 if (!key)
1686 return 0;
1687
1688 ts = stktable_lookup_key(t, key);
1689
1690 smp->flags = SMP_F_VOL_TEST;
1691 smp->data.type = SMP_T_SINT;
1692 smp->data.u.sint = 0;
1693
1694 if (!ts) /* key not present */
1695 return 1;
1696
1697 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_FAIL_CNT);
1698 if (ptr)
1699 smp->data.u.sint = stktable_data_cast(ptr, http_fail_cnt);
1700
1701 stktable_release(t, ts);
1702 return !!ptr;
1703}
1704
1705/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1706 * it up into this table. Returns the HTTP response failure rate for the key
1707 * if the key is present in the table, otherwise zero, so that comparisons can
1708 * be easily performed. If the inspected parameter is not stored in the table,
1709 * <not found> is returned.
1710 */
1711static int sample_conv_table_http_fail_rate(const struct arg *arg_p, struct sample *smp, void *private)
1712{
1713 struct stktable *t;
1714 struct stktable_key *key;
1715 struct stksess *ts;
1716 void *ptr;
1717
1718 t = arg_p[0].data.t;
1719
1720 key = smp_to_stkey(smp, t);
1721 if (!key)
1722 return 0;
1723
1724 ts = stktable_lookup_key(t, key);
1725
1726 smp->flags = SMP_F_VOL_TEST;
1727 smp->data.type = SMP_T_SINT;
1728 smp->data.u.sint = 0;
1729
1730 if (!ts) /* key not present */
1731 return 1;
1732
1733 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_FAIL_RATE);
1734 if (ptr)
1735 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, http_fail_rate),
1736 t->data_arg[STKTABLE_DT_HTTP_FAIL_RATE].u);
1737
1738 stktable_release(t, ts);
1739 return !!ptr;
1740}
1741
1742/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001743 * it up into this table. Returns the cumulated number of HTTP request for the
1744 * key if the key is present in the table, otherwise zero, so that comparisons
1745 * can be easily performed. If the inspected parameter is not stored in the
1746 * table, <not found> is returned.
1747 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001748static int sample_conv_table_http_req_cnt(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001749{
1750 struct stktable *t;
1751 struct stktable_key *key;
1752 struct stksess *ts;
1753 void *ptr;
1754
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001755 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001756
1757 key = smp_to_stkey(smp, t);
1758 if (!key)
1759 return 0;
1760
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001761 ts = stktable_lookup_key(t, key);
1762
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001763 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001764 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001765 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001766
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001767 if (!ts) /* key not present */
1768 return 1;
1769
1770 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_REQ_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001771 if (ptr)
1772 smp->data.u.sint = stktable_data_cast(ptr, http_req_cnt);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001773
Daniel Corbett3e60b112018-05-27 09:47:12 -04001774 stktable_release(t, ts);
1775 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001776}
1777
1778/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1779 * it up into this table. Returns the HTTP request rate the key if the key is
1780 * present in the table, otherwise zero, so that comparisons can be easily
1781 * performed. If the inspected parameter is not stored in the table, <not found>
1782 * is returned.
1783 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001784static int sample_conv_table_http_req_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001785{
1786 struct stktable *t;
1787 struct stktable_key *key;
1788 struct stksess *ts;
1789 void *ptr;
1790
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001791 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001792
1793 key = smp_to_stkey(smp, t);
1794 if (!key)
1795 return 0;
1796
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001797 ts = stktable_lookup_key(t, key);
1798
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001799 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001800 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001801 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001802
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001803 if (!ts) /* key not present */
1804 return 1;
1805
1806 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_REQ_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001807 if (ptr)
1808 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, http_req_rate),
1809 t->data_arg[STKTABLE_DT_HTTP_REQ_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001810
Daniel Corbett3e60b112018-05-27 09:47:12 -04001811 stktable_release(t, ts);
1812 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001813}
1814
1815/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1816 * it up into this table. Returns the volume of datareceived from clients in kbytes
1817 * if the key is present in the table, otherwise zero, so that comparisons can
1818 * be easily performed. If the inspected parameter is not stored in the table,
1819 * <not found> is returned.
1820 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001821static int sample_conv_table_kbytes_in(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001822{
1823 struct stktable *t;
1824 struct stktable_key *key;
1825 struct stksess *ts;
1826 void *ptr;
1827
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001828 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001829
1830 key = smp_to_stkey(smp, t);
1831 if (!key)
1832 return 0;
1833
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001834 ts = stktable_lookup_key(t, key);
1835
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001836 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001837 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001838 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001839
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001840 if (!ts) /* key not present */
1841 return 1;
1842
1843 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_IN_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001844 if (ptr)
1845 smp->data.u.sint = stktable_data_cast(ptr, bytes_in_cnt) >> 10;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001846
Daniel Corbett3e60b112018-05-27 09:47:12 -04001847 stktable_release(t, ts);
1848 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001849}
1850
1851/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1852 * it up into this table. Returns the volume of data sent to clients in kbytes
1853 * if the key is present in the table, otherwise zero, so that comparisons can
1854 * be easily performed. If the inspected parameter is not stored in the table,
1855 * <not found> is returned.
1856 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001857static int sample_conv_table_kbytes_out(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001858{
1859 struct stktable *t;
1860 struct stktable_key *key;
1861 struct stksess *ts;
1862 void *ptr;
1863
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001864 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001865
1866 key = smp_to_stkey(smp, t);
1867 if (!key)
1868 return 0;
1869
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001870 ts = stktable_lookup_key(t, key);
1871
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001872 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001873 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001874 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001875
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001876 if (!ts) /* key not present */
1877 return 1;
1878
1879 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_OUT_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001880 if (ptr)
1881 smp->data.u.sint = stktable_data_cast(ptr, bytes_out_cnt) >> 10;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001882
Daniel Corbett3e60b112018-05-27 09:47:12 -04001883 stktable_release(t, ts);
1884 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001885}
1886
1887/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1888 * it up into this table. Returns the server ID associated with the key if the
1889 * key is present in the table, otherwise zero, so that comparisons can be
1890 * easily performed. If the inspected parameter is not stored in the table,
1891 * <not found> is returned.
1892 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001893static int sample_conv_table_server_id(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001894{
1895 struct stktable *t;
1896 struct stktable_key *key;
1897 struct stksess *ts;
1898 void *ptr;
1899
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001900 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001901
1902 key = smp_to_stkey(smp, t);
1903 if (!key)
1904 return 0;
1905
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001906 ts = stktable_lookup_key(t, key);
1907
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001908 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001909 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001910 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001911
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001912 if (!ts) /* key not present */
1913 return 1;
1914
1915 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_SERVER_ID);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001916 if (ptr)
1917 smp->data.u.sint = stktable_data_cast(ptr, server_id);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001918
Daniel Corbett3e60b112018-05-27 09:47:12 -04001919 stktable_release(t, ts);
1920 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001921}
1922
1923/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1924 * it up into this table. Returns the cumulated number of sessions for the
1925 * key if the key is present in the table, otherwise zero, so that comparisons
1926 * can be easily performed. If the inspected parameter is not stored in the
1927 * table, <not found> is returned.
1928 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001929static int sample_conv_table_sess_cnt(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001930{
1931 struct stktable *t;
1932 struct stktable_key *key;
1933 struct stksess *ts;
1934 void *ptr;
1935
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001936 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001937
1938 key = smp_to_stkey(smp, t);
1939 if (!key)
1940 return 0;
1941
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001942 ts = stktable_lookup_key(t, key);
1943
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001944 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001945 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001946 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001947
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001948 if (!ts) /* key not present */
1949 return 1;
1950
1951 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_SESS_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001952 if (ptr)
1953 smp->data.u.sint = stktable_data_cast(ptr, sess_cnt);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001954
Daniel Corbett3e60b112018-05-27 09:47:12 -04001955 stktable_release(t, ts);
1956 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001957}
1958
1959/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1960 * it up into this table. Returns the session rate the key if the key is
1961 * present in the table, otherwise zero, so that comparisons can be easily
1962 * performed. If the inspected parameter is not stored in the table, <not found>
1963 * is returned.
1964 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001965static int sample_conv_table_sess_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001966{
1967 struct stktable *t;
1968 struct stktable_key *key;
1969 struct stksess *ts;
1970 void *ptr;
1971
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001972 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001973
1974 key = smp_to_stkey(smp, t);
1975 if (!key)
1976 return 0;
1977
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001978 ts = stktable_lookup_key(t, key);
1979
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001980 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001981 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001982 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001983
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001984 if (!ts) /* key not present */
1985 return 1;
1986
1987 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_SESS_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001988 if (ptr)
1989 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, sess_rate),
1990 t->data_arg[STKTABLE_DT_SESS_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001991
Daniel Corbett3e60b112018-05-27 09:47:12 -04001992 stktable_release(t, ts);
1993 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001994}
1995
1996/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1997 * it up into this table. Returns the amount of concurrent connections tracking
1998 * the same key if the key is present in the table, otherwise zero, so that
1999 * comparisons can be easily performed. If the inspected parameter is not
2000 * stored in the table, <not found> is returned.
2001 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02002002static int sample_conv_table_trackers(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002003{
2004 struct stktable *t;
2005 struct stktable_key *key;
2006 struct stksess *ts;
2007
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002008 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002009
2010 key = smp_to_stkey(smp, t);
2011 if (!key)
2012 return 0;
2013
Willy Tarreauf0c730a2016-05-25 17:07:56 +02002014 ts = stktable_lookup_key(t, key);
2015
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002016 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02002017 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02002018 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002019
Tim Duesterhus65189c12018-06-26 15:57:29 +02002020 if (!ts)
2021 return 1;
2022
2023 smp->data.u.sint = ts->ref_cnt;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002024
Daniel Corbett3e60b112018-05-27 09:47:12 -04002025 stktable_release(t, ts);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002026 return 1;
2027}
2028
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002029/* Always returns 1. */
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002030static enum act_return action_inc_gpc0(struct act_rule *rule, struct proxy *px,
Willy Tarreau658b85b2015-09-27 10:00:49 +02002031 struct session *sess, struct stream *s, int flags)
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002032{
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002033 struct stksess *ts;
2034 struct stkctr *stkctr;
2035
2036 /* Extract the stksess, return OK if no stksess available. */
2037 if (s)
2038 stkctr = &s->stkctr[rule->arg.gpc.sc];
2039 else
2040 stkctr = &sess->stkctr[rule->arg.gpc.sc];
Willy Tarreau79c1e912016-01-25 14:54:45 +01002041
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002042 ts = stkctr_entry(stkctr);
Willy Tarreau79c1e912016-01-25 14:54:45 +01002043 if (ts) {
2044 void *ptr1, *ptr2;
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002045
Willy Tarreau79c1e912016-01-25 14:54:45 +01002046 /* First, update gpc0_rate if it's tracked. Second, update its gpc0 if tracked. */
2047 ptr1 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC0_RATE);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002048 ptr2 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC0);
2049 if (ptr1 || ptr2) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002050 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002051
2052 if (ptr1)
2053 update_freq_ctr_period(&stktable_data_cast(ptr1, gpc0_rate),
Willy Tarreau79c1e912016-01-25 14:54:45 +01002054 stkctr->table->data_arg[STKTABLE_DT_GPC0_RATE].u, 1);
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002055
Emeric Brun819fc6f2017-06-13 19:37:32 +02002056 if (ptr2)
2057 stktable_data_cast(ptr2, gpc0)++;
Willy Tarreau79c1e912016-01-25 14:54:45 +01002058
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002059 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002060
2061 /* If data was modified, we need to touch to re-schedule sync */
2062 stktable_touch_local(stkctr->table, ts, 0);
2063 }
Willy Tarreau79c1e912016-01-25 14:54:45 +01002064 }
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002065 return ACT_RET_CONT;
2066}
2067
2068/* This function is a common parser for using variables. It understands
2069 * the formats:
2070 *
2071 * sc-inc-gpc0(<stick-table ID>)
2072 *
2073 * It returns 0 if fails and <err> is filled with an error message. Otherwise,
2074 * it returns 1 and the variable <expr> is filled with the pointer to the
2075 * expression to execute.
2076 */
2077static enum act_parse_ret parse_inc_gpc0(const char **args, int *arg, struct proxy *px,
2078 struct act_rule *rule, char **err)
2079{
2080 const char *cmd_name = args[*arg-1];
2081 char *error;
2082
2083 cmd_name += strlen("sc-inc-gpc0");
2084 if (*cmd_name == '\0') {
2085 /* default stick table id. */
2086 rule->arg.gpc.sc = 0;
2087 } else {
2088 /* parse the stick table id. */
2089 if (*cmd_name != '(') {
2090 memprintf(err, "invalid stick table track ID. Expects %s(<Track ID>)", args[*arg-1]);
2091 return ACT_RET_PRS_ERR;
2092 }
2093 cmd_name++; /* jump the '(' */
2094 rule->arg.gpc.sc = strtol(cmd_name, &error, 10); /* Convert stick table id. */
2095 if (*error != ')') {
2096 memprintf(err, "invalid stick table track ID. Expects %s(<Track ID>)", args[*arg-1]);
2097 return ACT_RET_PRS_ERR;
2098 }
2099
Christopher Faulet28436e22019-12-18 10:25:46 +01002100 if (rule->arg.gpc.sc >= MAX_SESS_STKCTR) {
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002101 memprintf(err, "invalid stick table track ID. The max allowed ID is %d",
Christopher Faulet28436e22019-12-18 10:25:46 +01002102 MAX_SESS_STKCTR-1);
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002103 return ACT_RET_PRS_ERR;
2104 }
2105 }
Thierry FOURNIER42148732015-09-02 17:17:33 +02002106 rule->action = ACT_CUSTOM;
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002107 rule->action_ptr = action_inc_gpc0;
2108 return ACT_RET_PRS_OK;
2109}
2110
2111/* Always returns 1. */
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002112static enum act_return action_inc_gpc1(struct act_rule *rule, struct proxy *px,
2113 struct session *sess, struct stream *s, int flags)
2114{
2115 struct stksess *ts;
2116 struct stkctr *stkctr;
2117
2118 /* Extract the stksess, return OK if no stksess available. */
2119 if (s)
2120 stkctr = &s->stkctr[rule->arg.gpc.sc];
2121 else
2122 stkctr = &sess->stkctr[rule->arg.gpc.sc];
2123
2124 ts = stkctr_entry(stkctr);
2125 if (ts) {
2126 void *ptr1, *ptr2;
2127
2128 /* First, update gpc1_rate if it's tracked. Second, update its gpc1 if tracked. */
2129 ptr1 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC1_RATE);
2130 ptr2 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC1);
2131 if (ptr1 || ptr2) {
2132 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
2133
2134 if (ptr1)
2135 update_freq_ctr_period(&stktable_data_cast(ptr1, gpc1_rate),
2136 stkctr->table->data_arg[STKTABLE_DT_GPC1_RATE].u, 1);
2137
2138 if (ptr2)
2139 stktable_data_cast(ptr2, gpc1)++;
2140
2141 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
2142
2143 /* If data was modified, we need to touch to re-schedule sync */
2144 stktable_touch_local(stkctr->table, ts, 0);
2145 }
2146 }
2147 return ACT_RET_CONT;
2148}
2149
2150/* This function is a common parser for using variables. It understands
2151 * the formats:
2152 *
2153 * sc-inc-gpc1(<stick-table ID>)
2154 *
2155 * It returns 0 if fails and <err> is filled with an error message. Otherwise,
2156 * it returns 1 and the variable <expr> is filled with the pointer to the
2157 * expression to execute.
2158 */
2159static enum act_parse_ret parse_inc_gpc1(const char **args, int *arg, struct proxy *px,
2160 struct act_rule *rule, char **err)
2161{
2162 const char *cmd_name = args[*arg-1];
2163 char *error;
2164
2165 cmd_name += strlen("sc-inc-gpc1");
2166 if (*cmd_name == '\0') {
2167 /* default stick table id. */
2168 rule->arg.gpc.sc = 0;
2169 } else {
2170 /* parse the stick table id. */
2171 if (*cmd_name != '(') {
2172 memprintf(err, "invalid stick table track ID. Expects %s(<Track ID>)", args[*arg-1]);
2173 return ACT_RET_PRS_ERR;
2174 }
2175 cmd_name++; /* jump the '(' */
2176 rule->arg.gpc.sc = strtol(cmd_name, &error, 10); /* Convert stick table id. */
2177 if (*error != ')') {
2178 memprintf(err, "invalid stick table track ID. Expects %s(<Track ID>)", args[*arg-1]);
2179 return ACT_RET_PRS_ERR;
2180 }
2181
Christopher Faulet28436e22019-12-18 10:25:46 +01002182 if (rule->arg.gpc.sc >= MAX_SESS_STKCTR) {
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002183 memprintf(err, "invalid stick table track ID. The max allowed ID is %d",
Christopher Faulet28436e22019-12-18 10:25:46 +01002184 MAX_SESS_STKCTR-1);
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002185 return ACT_RET_PRS_ERR;
2186 }
2187 }
2188 rule->action = ACT_CUSTOM;
2189 rule->action_ptr = action_inc_gpc1;
2190 return ACT_RET_PRS_OK;
2191}
2192
2193/* Always returns 1. */
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002194static enum act_return action_set_gpt0(struct act_rule *rule, struct proxy *px,
Willy Tarreau658b85b2015-09-27 10:00:49 +02002195 struct session *sess, struct stream *s, int flags)
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002196{
2197 void *ptr;
2198 struct stksess *ts;
2199 struct stkctr *stkctr;
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002200 unsigned int value = 0;
2201 struct sample *smp;
2202 int smp_opt_dir;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002203
2204 /* Extract the stksess, return OK if no stksess available. */
2205 if (s)
2206 stkctr = &s->stkctr[rule->arg.gpt.sc];
2207 else
2208 stkctr = &sess->stkctr[rule->arg.gpt.sc];
Willy Tarreau79c1e912016-01-25 14:54:45 +01002209
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002210 ts = stkctr_entry(stkctr);
2211 if (!ts)
2212 return ACT_RET_CONT;
2213
2214 /* Store the sample in the required sc, and ignore errors. */
2215 ptr = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPT0);
Willy Tarreau79c1e912016-01-25 14:54:45 +01002216 if (ptr) {
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002217 if (!rule->arg.gpt.expr)
2218 value = (unsigned int)(rule->arg.gpt.value);
2219 else {
2220 switch (rule->from) {
Aurelien DARRAGONa3d46bd2023-08-09 17:23:32 +02002221 case ACT_F_TCP_REQ_CON: smp_opt_dir = SMP_OPT_DIR_REQ; break;
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002222 case ACT_F_TCP_REQ_SES: smp_opt_dir = SMP_OPT_DIR_REQ; break;
2223 case ACT_F_TCP_REQ_CNT: smp_opt_dir = SMP_OPT_DIR_REQ; break;
2224 case ACT_F_TCP_RES_CNT: smp_opt_dir = SMP_OPT_DIR_RES; break;
2225 case ACT_F_HTTP_REQ: smp_opt_dir = SMP_OPT_DIR_REQ; break;
2226 case ACT_F_HTTP_RES: smp_opt_dir = SMP_OPT_DIR_RES; break;
2227 default:
2228 send_log(px, LOG_ERR, "stick table: internal error while setting gpt0.");
2229 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))
2230 ha_alert("stick table: internal error while executing setting gpt0.\n");
2231 return ACT_RET_CONT;
2232 }
2233
2234 /* Fetch and cast the expression. */
2235 smp = sample_fetch_as_type(px, sess, s, smp_opt_dir|SMP_OPT_FINAL, rule->arg.gpt.expr, SMP_T_SINT);
2236 if (!smp) {
2237 send_log(px, LOG_WARNING, "stick table: invalid expression or data type while setting gpt0.");
2238 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))
2239 ha_alert("stick table: invalid expression or data type while setting gpt0.\n");
2240 return ACT_RET_CONT;
2241 }
2242 value = (unsigned int)(smp->data.u.sint);
2243 }
2244
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002245 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002246
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002247 stktable_data_cast(ptr, gpt0) = value;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002248
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002249 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002250
2251 stktable_touch_local(stkctr->table, ts, 0);
Willy Tarreau79c1e912016-01-25 14:54:45 +01002252 }
2253
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002254 return ACT_RET_CONT;
2255}
2256
2257/* This function is a common parser for using variables. It understands
2258 * the format:
2259 *
2260 * set-gpt0(<stick-table ID>) <expression>
2261 *
2262 * It returns 0 if fails and <err> is filled with an error message. Otherwise,
2263 * it returns 1 and the variable <expr> is filled with the pointer to the
2264 * expression to execute.
2265 */
2266static enum act_parse_ret parse_set_gpt0(const char **args, int *arg, struct proxy *px,
2267 struct act_rule *rule, char **err)
2268
2269
2270{
2271 const char *cmd_name = args[*arg-1];
2272 char *error;
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002273 int smp_val;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002274
2275 cmd_name += strlen("sc-set-gpt0");
2276 if (*cmd_name == '\0') {
2277 /* default stick table id. */
2278 rule->arg.gpt.sc = 0;
2279 } else {
2280 /* parse the stick table id. */
2281 if (*cmd_name != '(') {
2282 memprintf(err, "invalid stick table track ID '%s'. Expects sc-set-gpt0(<Track ID>)", args[*arg-1]);
2283 return ACT_RET_PRS_ERR;
2284 }
2285 cmd_name++; /* jump the '(' */
2286 rule->arg.gpt.sc = strtol(cmd_name, &error, 10); /* Convert stick table id. */
2287 if (*error != ')') {
2288 memprintf(err, "invalid stick table track ID '%s'. Expects sc-set-gpt0(<Track ID>)", args[*arg-1]);
2289 return ACT_RET_PRS_ERR;
2290 }
2291
Christopher Faulet28436e22019-12-18 10:25:46 +01002292 if (rule->arg.gpt.sc >= MAX_SESS_STKCTR) {
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002293 memprintf(err, "invalid stick table track ID '%s'. The max allowed ID is %d",
Christopher Faulet28436e22019-12-18 10:25:46 +01002294 args[*arg-1], MAX_SESS_STKCTR-1);
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002295 return ACT_RET_PRS_ERR;
2296 }
2297 }
2298
Willy Tarreauf1e1c912021-08-24 14:57:28 +02002299 /* value may be either an integer or an expression */
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002300 rule->arg.gpt.expr = NULL;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002301 rule->arg.gpt.value = strtol(args[*arg], &error, 10);
Willy Tarreauf1e1c912021-08-24 14:57:28 +02002302 if (*error == '\0') {
2303 /* valid integer, skip it */
2304 (*arg)++;
2305 } else {
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002306 rule->arg.gpt.expr = sample_parse_expr((char **)args, arg, px->conf.args.file,
Willy Tarreaue3b57bf2020-02-14 16:50:14 +01002307 px->conf.args.line, err, &px->conf.args, NULL);
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002308 if (!rule->arg.gpt.expr)
2309 return ACT_RET_PRS_ERR;
2310
2311 switch (rule->from) {
Aurelien DARRAGONa3d46bd2023-08-09 17:23:32 +02002312 case ACT_F_TCP_REQ_CON: smp_val = SMP_VAL_FE_CON_ACC; break;
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002313 case ACT_F_TCP_REQ_SES: smp_val = SMP_VAL_FE_SES_ACC; break;
2314 case ACT_F_TCP_REQ_CNT: smp_val = SMP_VAL_FE_REQ_CNT; break;
2315 case ACT_F_TCP_RES_CNT: smp_val = SMP_VAL_BE_RES_CNT; break;
2316 case ACT_F_HTTP_REQ: smp_val = SMP_VAL_FE_HRQ_HDR; break;
2317 case ACT_F_HTTP_RES: smp_val = SMP_VAL_BE_HRS_HDR; break;
2318 default:
2319 memprintf(err, "internal error, unexpected rule->from=%d, please report this bug!", rule->from);
2320 return ACT_RET_PRS_ERR;
2321 }
2322 if (!(rule->arg.gpt.expr->fetch->val & smp_val)) {
2323 memprintf(err, "fetch method '%s' extracts information from '%s', none of which is available here", args[*arg-1],
2324 sample_src_names(rule->arg.gpt.expr->fetch->use));
2325 free(rule->arg.gpt.expr);
2326 return ACT_RET_PRS_ERR;
2327 }
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002328 }
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002329
Thierry FOURNIER42148732015-09-02 17:17:33 +02002330 rule->action = ACT_CUSTOM;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002331 rule->action_ptr = action_set_gpt0;
2332
2333 return ACT_RET_PRS_OK;
2334}
2335
Willy Tarreau7d562212016-11-25 16:10:05 +01002336/* set temp integer to the number of used entries in the table pointed to by expr.
2337 * Accepts exactly 1 argument of type table.
2338 */
2339static int
2340smp_fetch_table_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
2341{
2342 smp->flags = SMP_F_VOL_TEST;
2343 smp->data.type = SMP_T_SINT;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002344 smp->data.u.sint = args->data.t->current;
Willy Tarreau7d562212016-11-25 16:10:05 +01002345 return 1;
2346}
2347
2348/* set temp integer to the number of free entries in the table pointed to by expr.
2349 * Accepts exactly 1 argument of type table.
2350 */
2351static int
2352smp_fetch_table_avl(const struct arg *args, struct sample *smp, const char *kw, void *private)
2353{
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002354 struct stktable *t;
Willy Tarreau7d562212016-11-25 16:10:05 +01002355
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002356 t = args->data.t;
Willy Tarreau7d562212016-11-25 16:10:05 +01002357 smp->flags = SMP_F_VOL_TEST;
2358 smp->data.type = SMP_T_SINT;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002359 smp->data.u.sint = t->size - t->current;
Willy Tarreau7d562212016-11-25 16:10:05 +01002360 return 1;
2361}
2362
2363/* Returns a pointer to a stkctr depending on the fetch keyword name.
2364 * It is designed to be called as sc[0-9]_* sc_* or src_* exclusively.
2365 * sc[0-9]_* will return a pointer to the respective field in the
2366 * stream <l4>. sc_* requires an UINT argument specifying the stick
2367 * counter number. src_* will fill a locally allocated structure with
2368 * the table and entry corresponding to what is specified with src_*.
2369 * NULL may be returned if the designated stkctr is not tracked. For
2370 * the sc_* and sc[0-9]_* forms, an optional table argument may be
2371 * passed. When present, the currently tracked key is then looked up
2372 * in the specified table instead of the current table. The purpose is
Ilya Shipitsin47d17182020-06-21 21:42:57 +05002373 * to be able to convert multiple values per key (eg: have gpc0 from
Willy Tarreau7d562212016-11-25 16:10:05 +01002374 * multiple tables). <strm> is allowed to be NULL, in which case only
2375 * the session will be consulted.
2376 */
2377struct stkctr *
Emeric Brun819fc6f2017-06-13 19:37:32 +02002378smp_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 +01002379{
Willy Tarreau7d562212016-11-25 16:10:05 +01002380 struct stkctr *stkptr;
2381 struct stksess *stksess;
2382 unsigned int num = kw[2] - '0';
2383 int arg = 0;
2384
2385 if (num == '_' - '0') {
2386 /* sc_* variant, args[0] = ctr# (mandatory) */
2387 num = args[arg++].data.sint;
Willy Tarreau7d562212016-11-25 16:10:05 +01002388 }
2389 else if (num > 9) { /* src_* variant, args[0] = table */
2390 struct stktable_key *key;
2391 struct connection *conn = objt_conn(sess->origin);
2392 struct sample smp;
2393
2394 if (!conn)
2395 return NULL;
2396
Joseph Herlant5662fa42018-11-15 13:43:28 -08002397 /* Fetch source address in a sample. */
Willy Tarreau7d562212016-11-25 16:10:05 +01002398 smp.px = NULL;
2399 smp.sess = sess;
2400 smp.strm = strm;
Amaury Denoyellec460c702021-05-12 10:17:47 +02002401 if (!smp_fetch_src || !smp_fetch_src(empty_arg_list, &smp, "src", NULL))
Willy Tarreau7d562212016-11-25 16:10:05 +01002402 return NULL;
2403
2404 /* Converts into key. */
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002405 key = smp_to_stkey(&smp, args->data.t);
Willy Tarreau7d562212016-11-25 16:10:05 +01002406 if (!key)
2407 return NULL;
2408
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002409 stkctr->table = args->data.t;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002410 stkctr_set_entry(stkctr, stktable_lookup_key(stkctr->table, key));
2411 return stkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002412 }
2413
2414 /* Here, <num> contains the counter number from 0 to 9 for
2415 * the sc[0-9]_ form, or even higher using sc_(num) if needed.
2416 * args[arg] is the first optional argument. We first lookup the
2417 * ctr form the stream, then from the session if it was not there.
Christopher Fauleta9fa88a2019-10-21 10:53:34 +02002418 * But we must be sure the counter does not exceed MAX_SESS_STKCTR.
Willy Tarreau7d562212016-11-25 16:10:05 +01002419 */
Christopher Fauleta9fa88a2019-10-21 10:53:34 +02002420 if (num >= MAX_SESS_STKCTR)
2421 return NULL;
Willy Tarreau7d562212016-11-25 16:10:05 +01002422
2423 if (strm)
2424 stkptr = &strm->stkctr[num];
2425 if (!strm || !stkctr_entry(stkptr)) {
2426 stkptr = &sess->stkctr[num];
2427 if (!stkctr_entry(stkptr))
2428 return NULL;
2429 }
2430
2431 stksess = stkctr_entry(stkptr);
2432 if (!stksess)
2433 return NULL;
2434
2435 if (unlikely(args[arg].type == ARGT_TAB)) {
2436 /* an alternate table was specified, let's look up the same key there */
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002437 stkctr->table = args[arg].data.t;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002438 stkctr_set_entry(stkctr, stktable_lookup(stkctr->table, stksess));
2439 return stkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002440 }
2441 return stkptr;
2442}
2443
2444/* same as smp_fetch_sc_stkctr() but dedicated to src_* and can create
2445 * the entry if it doesn't exist yet. This is needed for a few fetch
2446 * functions which need to create an entry, such as src_inc_gpc* and
2447 * src_clr_gpc*.
2448 */
2449struct stkctr *
Emeric Brun819fc6f2017-06-13 19:37:32 +02002450smp_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 +01002451{
Willy Tarreau7d562212016-11-25 16:10:05 +01002452 struct stktable_key *key;
2453 struct connection *conn = objt_conn(sess->origin);
2454 struct sample smp;
2455
2456 if (strncmp(kw, "src_", 4) != 0)
2457 return NULL;
2458
2459 if (!conn)
2460 return NULL;
2461
Joseph Herlant5662fa42018-11-15 13:43:28 -08002462 /* Fetch source address in a sample. */
Willy Tarreau7d562212016-11-25 16:10:05 +01002463 smp.px = NULL;
2464 smp.sess = sess;
2465 smp.strm = strm;
Amaury Denoyellec460c702021-05-12 10:17:47 +02002466 if (!smp_fetch_src || !smp_fetch_src(empty_arg_list, &smp, "src", NULL))
Willy Tarreau7d562212016-11-25 16:10:05 +01002467 return NULL;
2468
2469 /* Converts into key. */
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002470 key = smp_to_stkey(&smp, args->data.t);
Willy Tarreau7d562212016-11-25 16:10:05 +01002471 if (!key)
2472 return NULL;
2473
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002474 stkctr->table = args->data.t;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002475 stkctr_set_entry(stkctr, stktable_get_entry(stkctr->table, key));
2476 return stkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002477}
2478
2479/* set return a boolean indicating if the requested stream counter is
2480 * currently being tracked or not.
2481 * Supports being called as "sc[0-9]_tracked" only.
2482 */
2483static int
2484smp_fetch_sc_tracked(const struct arg *args, struct sample *smp, const char *kw, void *private)
2485{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002486 struct stkctr tmpstkctr;
2487 struct stkctr *stkctr;
2488
Willy Tarreau7d562212016-11-25 16:10:05 +01002489 smp->flags = SMP_F_VOL_TEST;
2490 smp->data.type = SMP_T_BOOL;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002491 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2492 smp->data.u.sint = !!stkctr;
2493
2494 /* release the ref count */
Dirkjan Bussinkff57f1b2018-09-14 14:31:22 +02002495 if (stkctr == &tmpstkctr)
Emeric Brun819fc6f2017-06-13 19:37:32 +02002496 stktable_release(stkctr->table, stkctr_entry(stkctr));
2497
Willy Tarreau7d562212016-11-25 16:10:05 +01002498 return 1;
2499}
2500
2501/* set <smp> to the General Purpose Flag 0 value from the stream's tracked
2502 * frontend counters or from the src.
2503 * Supports being called as "sc[0-9]_get_gpc0" or "src_get_gpt0" only. Value
2504 * zero is returned if the key is new.
2505 */
2506static int
2507smp_fetch_sc_get_gpt0(const struct arg *args, struct sample *smp, const char *kw, void *private)
2508{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002509 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002510 struct stkctr *stkctr;
2511
Emeric Brun819fc6f2017-06-13 19:37:32 +02002512 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002513 if (!stkctr)
2514 return 0;
2515
2516 smp->flags = SMP_F_VOL_TEST;
2517 smp->data.type = SMP_T_SINT;
2518 smp->data.u.sint = 0;
2519
Emeric Brun819fc6f2017-06-13 19:37:32 +02002520 if (stkctr_entry(stkctr)) {
2521 void *ptr;
2522
2523 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPT0);
2524 if (!ptr) {
2525 if (stkctr == &tmpstkctr)
2526 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002527 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002528 }
2529
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002530 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002531
Willy Tarreau7d562212016-11-25 16:10:05 +01002532 smp->data.u.sint = stktable_data_cast(ptr, gpt0);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002533
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002534 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002535
2536 if (stkctr == &tmpstkctr)
2537 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002538 }
2539 return 1;
2540}
2541
2542/* set <smp> to the General Purpose Counter 0 value from the stream's tracked
2543 * frontend counters or from the src.
2544 * Supports being called as "sc[0-9]_get_gpc0" or "src_get_gpc0" only. Value
2545 * zero is returned if the key is new.
2546 */
2547static int
2548smp_fetch_sc_get_gpc0(const struct arg *args, struct sample *smp, const char *kw, void *private)
2549{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002550 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002551 struct stkctr *stkctr;
2552
Emeric Brun819fc6f2017-06-13 19:37:32 +02002553 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002554 if (!stkctr)
2555 return 0;
2556
2557 smp->flags = SMP_F_VOL_TEST;
2558 smp->data.type = SMP_T_SINT;
2559 smp->data.u.sint = 0;
2560
2561 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002562 void *ptr;
2563
2564 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0);
2565 if (!ptr) {
2566 if (stkctr == &tmpstkctr)
2567 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002568 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002569 }
2570
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002571 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002572
Willy Tarreau7d562212016-11-25 16:10:05 +01002573 smp->data.u.sint = stktable_data_cast(ptr, gpc0);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002574
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002575 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002576
2577 if (stkctr == &tmpstkctr)
2578 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002579 }
2580 return 1;
2581}
2582
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002583/* set <smp> to the General Purpose Counter 1 value from the stream's tracked
2584 * frontend counters or from the src.
2585 * Supports being called as "sc[0-9]_get_gpc1" or "src_get_gpc1" only. Value
2586 * zero is returned if the key is new.
2587 */
2588static int
2589smp_fetch_sc_get_gpc1(const struct arg *args, struct sample *smp, const char *kw, void *private)
2590{
2591 struct stkctr tmpstkctr;
2592 struct stkctr *stkctr;
2593
2594 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2595 if (!stkctr)
2596 return 0;
2597
2598 smp->flags = SMP_F_VOL_TEST;
2599 smp->data.type = SMP_T_SINT;
2600 smp->data.u.sint = 0;
2601
2602 if (stkctr_entry(stkctr) != NULL) {
2603 void *ptr;
2604
2605 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1);
2606 if (!ptr) {
2607 if (stkctr == &tmpstkctr)
2608 stktable_release(stkctr->table, stkctr_entry(stkctr));
2609 return 0; /* parameter not stored */
2610 }
2611
2612 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2613
2614 smp->data.u.sint = stktable_data_cast(ptr, gpc1);
2615
2616 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2617
2618 if (stkctr == &tmpstkctr)
2619 stktable_release(stkctr->table, stkctr_entry(stkctr));
2620 }
2621 return 1;
2622}
2623
Willy Tarreau7d562212016-11-25 16:10:05 +01002624/* set <smp> to the General Purpose Counter 0's event rate from the stream's
2625 * tracked frontend counters or from the src.
2626 * Supports being called as "sc[0-9]_gpc0_rate" or "src_gpc0_rate" only.
2627 * Value zero is returned if the key is new.
2628 */
2629static int
2630smp_fetch_sc_gpc0_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
2631{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002632 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002633 struct stkctr *stkctr;
2634
Emeric Brun819fc6f2017-06-13 19:37:32 +02002635 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002636 if (!stkctr)
2637 return 0;
2638
2639 smp->flags = SMP_F_VOL_TEST;
2640 smp->data.type = SMP_T_SINT;
2641 smp->data.u.sint = 0;
2642 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002643 void *ptr;
2644
2645 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0_RATE);
2646 if (!ptr) {
2647 if (stkctr == &tmpstkctr)
2648 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002649 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002650 }
2651
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002652 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002653
Willy Tarreau7d562212016-11-25 16:10:05 +01002654 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, gpc0_rate),
2655 stkctr->table->data_arg[STKTABLE_DT_GPC0_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002656
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002657 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002658
2659 if (stkctr == &tmpstkctr)
2660 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002661 }
2662 return 1;
2663}
2664
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002665/* set <smp> to the General Purpose Counter 1's event rate from the stream's
2666 * tracked frontend counters or from the src.
2667 * Supports being called as "sc[0-9]_gpc1_rate" or "src_gpc1_rate" only.
2668 * Value zero is returned if the key is new.
2669 */
2670static int
2671smp_fetch_sc_gpc1_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
2672{
2673 struct stkctr tmpstkctr;
2674 struct stkctr *stkctr;
2675
2676 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2677 if (!stkctr)
2678 return 0;
2679
2680 smp->flags = SMP_F_VOL_TEST;
2681 smp->data.type = SMP_T_SINT;
2682 smp->data.u.sint = 0;
2683 if (stkctr_entry(stkctr) != NULL) {
2684 void *ptr;
2685
2686 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1_RATE);
2687 if (!ptr) {
2688 if (stkctr == &tmpstkctr)
2689 stktable_release(stkctr->table, stkctr_entry(stkctr));
2690 return 0; /* parameter not stored */
2691 }
2692
2693 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2694
2695 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, gpc1_rate),
2696 stkctr->table->data_arg[STKTABLE_DT_GPC1_RATE].u);
2697
2698 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2699
2700 if (stkctr == &tmpstkctr)
2701 stktable_release(stkctr->table, stkctr_entry(stkctr));
2702 }
2703 return 1;
2704}
2705
Willy Tarreau7d562212016-11-25 16:10:05 +01002706/* Increment the General Purpose Counter 0 value from the stream's tracked
2707 * frontend counters and return it into temp integer.
2708 * Supports being called as "sc[0-9]_inc_gpc0" or "src_inc_gpc0" only.
2709 */
2710static int
2711smp_fetch_sc_inc_gpc0(const struct arg *args, struct sample *smp, const char *kw, void *private)
2712{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002713 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002714 struct stkctr *stkctr;
2715
Emeric Brun819fc6f2017-06-13 19:37:32 +02002716 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002717 if (!stkctr)
2718 return 0;
2719
2720 smp->flags = SMP_F_VOL_TEST;
2721 smp->data.type = SMP_T_SINT;
2722 smp->data.u.sint = 0;
2723
Emeric Brun819fc6f2017-06-13 19:37:32 +02002724 if (!stkctr_entry(stkctr))
2725 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002726
2727 if (stkctr && stkctr_entry(stkctr)) {
2728 void *ptr1,*ptr2;
2729
Emeric Brun819fc6f2017-06-13 19:37:32 +02002730
Willy Tarreau7d562212016-11-25 16:10:05 +01002731 /* First, update gpc0_rate if it's tracked. Second, update its
2732 * gpc0 if tracked. Returns gpc0's value otherwise the curr_ctr.
2733 */
2734 ptr1 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0_RATE);
Willy Tarreau7d562212016-11-25 16:10:05 +01002735 ptr2 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002736 if (ptr1 || ptr2) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002737 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Willy Tarreau7d562212016-11-25 16:10:05 +01002738
Emeric Brun819fc6f2017-06-13 19:37:32 +02002739 if (ptr1) {
2740 update_freq_ctr_period(&stktable_data_cast(ptr1, gpc0_rate),
2741 stkctr->table->data_arg[STKTABLE_DT_GPC0_RATE].u, 1);
2742 smp->data.u.sint = (&stktable_data_cast(ptr1, gpc0_rate))->curr_ctr;
2743 }
2744
2745 if (ptr2)
2746 smp->data.u.sint = ++stktable_data_cast(ptr2, gpc0);
2747
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002748 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002749
2750 /* If data was modified, we need to touch to re-schedule sync */
2751 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
2752 }
2753 else if (stkctr == &tmpstkctr)
2754 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002755 }
2756 return 1;
2757}
2758
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002759/* Increment the General Purpose Counter 1 value from the stream's tracked
2760 * frontend counters and return it into temp integer.
2761 * Supports being called as "sc[0-9]_inc_gpc1" or "src_inc_gpc1" only.
2762 */
2763static int
2764smp_fetch_sc_inc_gpc1(const struct arg *args, struct sample *smp, const char *kw, void *private)
2765{
2766 struct stkctr tmpstkctr;
2767 struct stkctr *stkctr;
2768
2769 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2770 if (!stkctr)
2771 return 0;
2772
2773 smp->flags = SMP_F_VOL_TEST;
2774 smp->data.type = SMP_T_SINT;
2775 smp->data.u.sint = 0;
2776
2777 if (!stkctr_entry(stkctr))
2778 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2779
2780 if (stkctr && stkctr_entry(stkctr)) {
2781 void *ptr1,*ptr2;
2782
2783
2784 /* First, update gpc1_rate if it's tracked. Second, update its
2785 * gpc1 if tracked. Returns gpc1's value otherwise the curr_ctr.
2786 */
2787 ptr1 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1_RATE);
2788 ptr2 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1);
2789 if (ptr1 || ptr2) {
2790 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2791
2792 if (ptr1) {
2793 update_freq_ctr_period(&stktable_data_cast(ptr1, gpc1_rate),
2794 stkctr->table->data_arg[STKTABLE_DT_GPC1_RATE].u, 1);
2795 smp->data.u.sint = (&stktable_data_cast(ptr1, gpc1_rate))->curr_ctr;
2796 }
2797
2798 if (ptr2)
2799 smp->data.u.sint = ++stktable_data_cast(ptr2, gpc1);
2800
2801 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2802
2803 /* If data was modified, we need to touch to re-schedule sync */
2804 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
2805 }
2806 else if (stkctr == &tmpstkctr)
2807 stktable_release(stkctr->table, stkctr_entry(stkctr));
2808 }
2809 return 1;
2810}
2811
Willy Tarreau7d562212016-11-25 16:10:05 +01002812/* Clear the General Purpose Counter 0 value from the stream's tracked
2813 * frontend counters and return its previous value into temp integer.
2814 * Supports being called as "sc[0-9]_clr_gpc0" or "src_clr_gpc0" only.
2815 */
2816static int
2817smp_fetch_sc_clr_gpc0(const struct arg *args, struct sample *smp, const char *kw, void *private)
2818{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002819 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002820 struct stkctr *stkctr;
2821
Emeric Brun819fc6f2017-06-13 19:37:32 +02002822 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002823 if (!stkctr)
2824 return 0;
2825
2826 smp->flags = SMP_F_VOL_TEST;
2827 smp->data.type = SMP_T_SINT;
2828 smp->data.u.sint = 0;
2829
Emeric Brun819fc6f2017-06-13 19:37:32 +02002830 if (!stkctr_entry(stkctr))
2831 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002832
Emeric Brun819fc6f2017-06-13 19:37:32 +02002833 if (stkctr && stkctr_entry(stkctr)) {
2834 void *ptr;
2835
2836 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0);
2837 if (!ptr) {
2838 if (stkctr == &tmpstkctr)
2839 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002840 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002841 }
2842
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002843 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002844
Willy Tarreau7d562212016-11-25 16:10:05 +01002845 smp->data.u.sint = stktable_data_cast(ptr, gpc0);
2846 stktable_data_cast(ptr, gpc0) = 0;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002847
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002848 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002849
Willy Tarreau7d562212016-11-25 16:10:05 +01002850 /* If data was modified, we need to touch to re-schedule sync */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002851 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
Willy Tarreau7d562212016-11-25 16:10:05 +01002852 }
2853 return 1;
2854}
2855
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002856/* Clear the General Purpose Counter 1 value from the stream's tracked
2857 * frontend counters and return its previous value into temp integer.
2858 * Supports being called as "sc[0-9]_clr_gpc1" or "src_clr_gpc1" only.
2859 */
2860static int
2861smp_fetch_sc_clr_gpc1(const struct arg *args, struct sample *smp, const char *kw, void *private)
2862{
2863 struct stkctr tmpstkctr;
2864 struct stkctr *stkctr;
2865
2866 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2867 if (!stkctr)
2868 return 0;
2869
2870 smp->flags = SMP_F_VOL_TEST;
2871 smp->data.type = SMP_T_SINT;
2872 smp->data.u.sint = 0;
2873
2874 if (!stkctr_entry(stkctr))
2875 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2876
2877 if (stkctr && stkctr_entry(stkctr)) {
2878 void *ptr;
2879
2880 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1);
2881 if (!ptr) {
2882 if (stkctr == &tmpstkctr)
2883 stktable_release(stkctr->table, stkctr_entry(stkctr));
2884 return 0; /* parameter not stored */
2885 }
2886
2887 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2888
2889 smp->data.u.sint = stktable_data_cast(ptr, gpc1);
2890 stktable_data_cast(ptr, gpc1) = 0;
2891
2892 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2893
2894 /* If data was modified, we need to touch to re-schedule sync */
2895 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
2896 }
2897 return 1;
2898}
2899
Willy Tarreau7d562212016-11-25 16:10:05 +01002900/* set <smp> to the cumulated number of connections from the stream's tracked
2901 * frontend counters. Supports being called as "sc[0-9]_conn_cnt" or
2902 * "src_conn_cnt" only.
2903 */
2904static int
2905smp_fetch_sc_conn_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
2906{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002907 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002908 struct stkctr *stkctr;
2909
Emeric Brun819fc6f2017-06-13 19:37:32 +02002910 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002911 if (!stkctr)
2912 return 0;
2913
2914 smp->flags = SMP_F_VOL_TEST;
2915 smp->data.type = SMP_T_SINT;
2916 smp->data.u.sint = 0;
2917 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002918 void *ptr;
2919
2920 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_CONN_CNT);
2921 if (!ptr) {
2922 if (stkctr == &tmpstkctr)
2923 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002924 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002925 }
2926
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002927 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002928
Willy Tarreau7d562212016-11-25 16:10:05 +01002929 smp->data.u.sint = stktable_data_cast(ptr, conn_cnt);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002930
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002931 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002932
2933 if (stkctr == &tmpstkctr)
2934 stktable_release(stkctr->table, stkctr_entry(stkctr));
2935
2936
Willy Tarreau7d562212016-11-25 16:10:05 +01002937 }
2938 return 1;
2939}
2940
2941/* set <smp> to the connection rate from the stream's tracked frontend
2942 * counters. Supports being called as "sc[0-9]_conn_rate" or "src_conn_rate"
2943 * only.
2944 */
2945static int
2946smp_fetch_sc_conn_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
2947{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002948 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002949 struct stkctr *stkctr;
2950
Emeric Brun819fc6f2017-06-13 19:37:32 +02002951 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002952 if (!stkctr)
2953 return 0;
2954
2955 smp->flags = SMP_F_VOL_TEST;
2956 smp->data.type = SMP_T_SINT;
2957 smp->data.u.sint = 0;
2958 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002959 void *ptr;
2960
2961 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_CONN_RATE);
2962 if (!ptr) {
2963 if (stkctr == &tmpstkctr)
2964 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002965 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002966 }
2967
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002968 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002969
Willy Tarreau7d562212016-11-25 16:10:05 +01002970 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, conn_rate),
2971 stkctr->table->data_arg[STKTABLE_DT_CONN_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002972
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002973 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002974
2975 if (stkctr == &tmpstkctr)
2976 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002977 }
2978 return 1;
2979}
2980
2981/* set temp integer to the number of connections from the stream's source address
2982 * in the table pointed to by expr, after updating it.
2983 * Accepts exactly 1 argument of type table.
2984 */
2985static int
2986smp_fetch_src_updt_conn_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
2987{
2988 struct connection *conn = objt_conn(smp->sess->origin);
2989 struct stksess *ts;
2990 struct stktable_key *key;
2991 void *ptr;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002992 struct stktable *t;
Willy Tarreau7d562212016-11-25 16:10:05 +01002993
2994 if (!conn)
2995 return 0;
2996
Joseph Herlant5662fa42018-11-15 13:43:28 -08002997 /* Fetch source address in a sample. */
Amaury Denoyellec460c702021-05-12 10:17:47 +02002998 if (!smp_fetch_src || !smp_fetch_src(empty_arg_list, smp, "src", NULL))
Willy Tarreau7d562212016-11-25 16:10:05 +01002999 return 0;
3000
3001 /* Converts into key. */
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003002 key = smp_to_stkey(smp, args->data.t);
Willy Tarreau7d562212016-11-25 16:10:05 +01003003 if (!key)
3004 return 0;
3005
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003006 t = args->data.t;
Willy Tarreau7d562212016-11-25 16:10:05 +01003007
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003008 if ((ts = stktable_get_entry(t, key)) == NULL)
Willy Tarreau7d562212016-11-25 16:10:05 +01003009 /* entry does not exist and could not be created */
3010 return 0;
3011
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003012 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_CONN_CNT);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003013 if (!ptr) {
Willy Tarreau7d562212016-11-25 16:10:05 +01003014 return 0; /* parameter not stored in this table */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003015 }
Willy Tarreau7d562212016-11-25 16:10:05 +01003016
3017 smp->data.type = SMP_T_SINT;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003018
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003019 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003020
Willy Tarreau7d562212016-11-25 16:10:05 +01003021 smp->data.u.sint = ++stktable_data_cast(ptr, conn_cnt);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003022
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003023 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003024
Willy Tarreau7d562212016-11-25 16:10:05 +01003025 smp->flags = SMP_F_VOL_TEST;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003026
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003027 stktable_touch_local(t, ts, 1);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003028
3029 /* Touch was previously performed by stktable_update_key */
Willy Tarreau7d562212016-11-25 16:10:05 +01003030 return 1;
3031}
3032
3033/* set <smp> to the number of concurrent connections from the stream's tracked
3034 * frontend counters. Supports being called as "sc[0-9]_conn_cur" or
3035 * "src_conn_cur" only.
3036 */
3037static int
3038smp_fetch_sc_conn_cur(const struct arg *args, struct sample *smp, const char *kw, void *private)
3039{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003040 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003041 struct stkctr *stkctr;
3042
Emeric Brun819fc6f2017-06-13 19:37:32 +02003043 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003044 if (!stkctr)
3045 return 0;
3046
3047 smp->flags = SMP_F_VOL_TEST;
3048 smp->data.type = SMP_T_SINT;
3049 smp->data.u.sint = 0;
3050 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003051 void *ptr;
3052
3053 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_CONN_CUR);
3054 if (!ptr) {
3055 if (stkctr == &tmpstkctr)
3056 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003057 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003058 }
3059
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003060 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003061
Willy Tarreau7d562212016-11-25 16:10:05 +01003062 smp->data.u.sint = stktable_data_cast(ptr, conn_cur);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003063
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003064 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003065
3066 if (stkctr == &tmpstkctr)
3067 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003068 }
3069 return 1;
3070}
3071
3072/* set <smp> to the cumulated number of streams from the stream's tracked
3073 * frontend counters. Supports being called as "sc[0-9]_sess_cnt" or
3074 * "src_sess_cnt" only.
3075 */
3076static int
3077smp_fetch_sc_sess_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
3078{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003079 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003080 struct stkctr *stkctr;
3081
Emeric Brun819fc6f2017-06-13 19:37:32 +02003082 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003083 if (!stkctr)
3084 return 0;
3085
3086 smp->flags = SMP_F_VOL_TEST;
3087 smp->data.type = SMP_T_SINT;
3088 smp->data.u.sint = 0;
3089 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003090 void *ptr;
3091
3092 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_SESS_CNT);
3093 if (!ptr) {
3094 if (stkctr == &tmpstkctr)
3095 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003096 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003097 }
3098
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003099 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003100
Willy Tarreau7d562212016-11-25 16:10:05 +01003101 smp->data.u.sint = stktable_data_cast(ptr, sess_cnt);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003102
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003103 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003104
3105 if (stkctr == &tmpstkctr)
3106 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003107 }
3108 return 1;
3109}
3110
3111/* set <smp> to the stream rate from the stream's tracked frontend counters.
3112 * Supports being called as "sc[0-9]_sess_rate" or "src_sess_rate" only.
3113 */
3114static int
3115smp_fetch_sc_sess_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3116{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003117 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003118 struct stkctr *stkctr;
3119
Emeric Brun819fc6f2017-06-13 19:37:32 +02003120 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003121 if (!stkctr)
3122 return 0;
3123
3124 smp->flags = SMP_F_VOL_TEST;
3125 smp->data.type = SMP_T_SINT;
3126 smp->data.u.sint = 0;
3127 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003128 void *ptr;
3129
3130 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_SESS_RATE);
3131 if (!ptr) {
3132 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
Willy Tarreau7d562212016-11-25 16:10:05 +01003139 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, sess_rate),
3140 stkctr->table->data_arg[STKTABLE_DT_SESS_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003141
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003142 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003143
3144 if (stkctr == &tmpstkctr)
3145 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003146 }
3147 return 1;
3148}
3149
3150/* set <smp> to the cumulated number of HTTP requests from the stream's tracked
3151 * frontend counters. Supports being called as "sc[0-9]_http_req_cnt" or
3152 * "src_http_req_cnt" only.
3153 */
3154static int
3155smp_fetch_sc_http_req_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
3156{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003157 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003158 struct stkctr *stkctr;
3159
Emeric Brun819fc6f2017-06-13 19:37:32 +02003160 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003161 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 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003168 void *ptr;
3169
3170 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_REQ_CNT);
3171 if (!ptr) {
3172 if (stkctr == &tmpstkctr)
3173 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003174 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003175 }
3176
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003177 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003178
Willy Tarreau7d562212016-11-25 16:10:05 +01003179 smp->data.u.sint = stktable_data_cast(ptr, http_req_cnt);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003180
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003181 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003182
3183 if (stkctr == &tmpstkctr)
3184 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003185 }
3186 return 1;
3187}
3188
3189/* set <smp> to the HTTP request rate from the stream's tracked frontend
3190 * counters. Supports being called as "sc[0-9]_http_req_rate" or
3191 * "src_http_req_rate" only.
3192 */
3193static int
3194smp_fetch_sc_http_req_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3195{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003196 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003197 struct stkctr *stkctr;
3198
Emeric Brun819fc6f2017-06-13 19:37:32 +02003199 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003200 if (!stkctr)
3201 return 0;
3202
3203 smp->flags = SMP_F_VOL_TEST;
3204 smp->data.type = SMP_T_SINT;
3205 smp->data.u.sint = 0;
3206 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003207 void *ptr;
3208
3209 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_REQ_RATE);
3210 if (!ptr) {
3211 if (stkctr == &tmpstkctr)
3212 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003213 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003214 }
3215
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003216 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003217
Willy Tarreau7d562212016-11-25 16:10:05 +01003218 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, http_req_rate),
3219 stkctr->table->data_arg[STKTABLE_DT_HTTP_REQ_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003220
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003221 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003222
3223 if (stkctr == &tmpstkctr)
3224 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003225 }
3226 return 1;
3227}
3228
3229/* set <smp> to the cumulated number of HTTP requests errors from the stream's
3230 * tracked frontend counters. Supports being called as "sc[0-9]_http_err_cnt" or
3231 * "src_http_err_cnt" only.
3232 */
3233static int
3234smp_fetch_sc_http_err_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
3235{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003236 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003237 struct stkctr *stkctr;
3238
Emeric Brun819fc6f2017-06-13 19:37:32 +02003239 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003240 if (!stkctr)
3241 return 0;
3242
3243 smp->flags = SMP_F_VOL_TEST;
3244 smp->data.type = SMP_T_SINT;
3245 smp->data.u.sint = 0;
3246 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003247 void *ptr;
3248
3249 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_ERR_CNT);
3250 if (!ptr) {
3251 if (stkctr == &tmpstkctr)
3252 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003253 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003254 }
3255
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003256 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003257
Willy Tarreau7d562212016-11-25 16:10:05 +01003258 smp->data.u.sint = stktable_data_cast(ptr, http_err_cnt);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003259
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003260 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003261
3262 if (stkctr == &tmpstkctr)
3263 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003264 }
3265 return 1;
3266}
3267
3268/* set <smp> to the HTTP request error rate from the stream's tracked frontend
3269 * counters. Supports being called as "sc[0-9]_http_err_rate" or
3270 * "src_http_err_rate" only.
3271 */
3272static int
3273smp_fetch_sc_http_err_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3274{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003275 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003276 struct stkctr *stkctr;
3277
Emeric Brun819fc6f2017-06-13 19:37:32 +02003278 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003279 if (!stkctr)
3280 return 0;
3281
3282 smp->flags = SMP_F_VOL_TEST;
3283 smp->data.type = SMP_T_SINT;
3284 smp->data.u.sint = 0;
3285 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003286 void *ptr;
3287
3288 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_ERR_RATE);
3289 if (!ptr) {
3290 if (stkctr == &tmpstkctr)
3291 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003292 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003293 }
3294
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003295 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003296
Willy Tarreau7d562212016-11-25 16:10:05 +01003297 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, http_err_rate),
3298 stkctr->table->data_arg[STKTABLE_DT_HTTP_ERR_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003299
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003300 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003301
3302 if (stkctr == &tmpstkctr)
3303 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003304 }
3305 return 1;
3306}
3307
Willy Tarreau826f3ab2021-02-10 12:07:15 +01003308/* set <smp> to the cumulated number of HTTP response failures from the stream's
3309 * tracked frontend counters. Supports being called as "sc[0-9]_http_fail_cnt" or
3310 * "src_http_fail_cnt" only.
3311 */
3312static int
3313smp_fetch_sc_http_fail_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
3314{
3315 struct stkctr tmpstkctr;
3316 struct stkctr *stkctr;
3317
3318 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
3319 if (!stkctr)
3320 return 0;
3321
3322 smp->flags = SMP_F_VOL_TEST;
3323 smp->data.type = SMP_T_SINT;
3324 smp->data.u.sint = 0;
3325 if (stkctr_entry(stkctr) != NULL) {
3326 void *ptr;
3327
3328 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_FAIL_CNT);
3329 if (!ptr) {
3330 if (stkctr == &tmpstkctr)
3331 stktable_release(stkctr->table, stkctr_entry(stkctr));
3332 return 0; /* parameter not stored */
3333 }
3334
3335 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3336
3337 smp->data.u.sint = stktable_data_cast(ptr, http_fail_cnt);
3338
3339 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3340
3341 if (stkctr == &tmpstkctr)
3342 stktable_release(stkctr->table, stkctr_entry(stkctr));
3343 }
3344 return 1;
3345}
3346
3347/* set <smp> to the HTTP response failure rate from the stream's tracked frontend
3348 * counters. Supports being called as "sc[0-9]_http_fail_rate" or
3349 * "src_http_fail_rate" only.
3350 */
3351static int
3352smp_fetch_sc_http_fail_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3353{
3354 struct stkctr tmpstkctr;
3355 struct stkctr *stkctr;
3356
3357 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
3358 if (!stkctr)
3359 return 0;
3360
3361 smp->flags = SMP_F_VOL_TEST;
3362 smp->data.type = SMP_T_SINT;
3363 smp->data.u.sint = 0;
3364 if (stkctr_entry(stkctr) != NULL) {
3365 void *ptr;
3366
3367 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_FAIL_RATE);
3368 if (!ptr) {
3369 if (stkctr == &tmpstkctr)
3370 stktable_release(stkctr->table, stkctr_entry(stkctr));
3371 return 0; /* parameter not stored */
3372 }
3373
3374 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3375
3376 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, http_fail_rate),
3377 stkctr->table->data_arg[STKTABLE_DT_HTTP_FAIL_RATE].u);
3378
3379 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3380
3381 if (stkctr == &tmpstkctr)
3382 stktable_release(stkctr->table, stkctr_entry(stkctr));
3383 }
3384 return 1;
3385}
3386
Willy Tarreau7d562212016-11-25 16:10:05 +01003387/* set <smp> to the number of kbytes received from clients, as found in the
3388 * stream's tracked frontend counters. Supports being called as
3389 * "sc[0-9]_kbytes_in" or "src_kbytes_in" only.
3390 */
3391static int
3392smp_fetch_sc_kbytes_in(const struct arg *args, struct sample *smp, const char *kw, void *private)
3393{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003394 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003395 struct stkctr *stkctr;
3396
Emeric Brun819fc6f2017-06-13 19:37:32 +02003397 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003398 if (!stkctr)
3399 return 0;
3400
3401 smp->flags = SMP_F_VOL_TEST;
3402 smp->data.type = SMP_T_SINT;
3403 smp->data.u.sint = 0;
3404 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003405 void *ptr;
3406
3407 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_IN_CNT);
3408 if (!ptr) {
3409 if (stkctr == &tmpstkctr)
3410 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003411 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003412 }
3413
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003414 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003415
Willy Tarreau7d562212016-11-25 16:10:05 +01003416 smp->data.u.sint = stktable_data_cast(ptr, bytes_in_cnt) >> 10;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003417
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003418 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003419
3420 if (stkctr == &tmpstkctr)
3421 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003422 }
3423 return 1;
3424}
3425
3426/* set <smp> to the data rate received from clients in bytes/s, as found
3427 * in the stream's tracked frontend counters. Supports being called as
3428 * "sc[0-9]_bytes_in_rate" or "src_bytes_in_rate" only.
3429 */
3430static int
3431smp_fetch_sc_bytes_in_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3432{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003433 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003434 struct stkctr *stkctr;
3435
Emeric Brun819fc6f2017-06-13 19:37:32 +02003436 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003437 if (!stkctr)
3438 return 0;
3439
3440 smp->flags = SMP_F_VOL_TEST;
3441 smp->data.type = SMP_T_SINT;
3442 smp->data.u.sint = 0;
3443 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003444 void *ptr;
3445
3446 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_IN_RATE);
3447 if (!ptr) {
3448 if (stkctr == &tmpstkctr)
3449 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003450 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003451 }
3452
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003453 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003454
Willy Tarreau7d562212016-11-25 16:10:05 +01003455 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, bytes_in_rate),
3456 stkctr->table->data_arg[STKTABLE_DT_BYTES_IN_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003457
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003458 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003459
3460 if (stkctr == &tmpstkctr)
3461 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003462 }
3463 return 1;
3464}
3465
3466/* set <smp> to the number of kbytes sent to clients, as found in the
3467 * stream's tracked frontend counters. Supports being called as
3468 * "sc[0-9]_kbytes_out" or "src_kbytes_out" only.
3469 */
3470static int
3471smp_fetch_sc_kbytes_out(const struct arg *args, struct sample *smp, const char *kw, void *private)
3472{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003473 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003474 struct stkctr *stkctr;
3475
Emeric Brun819fc6f2017-06-13 19:37:32 +02003476 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003477 if (!stkctr)
3478 return 0;
3479
3480 smp->flags = SMP_F_VOL_TEST;
3481 smp->data.type = SMP_T_SINT;
3482 smp->data.u.sint = 0;
3483 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003484 void *ptr;
3485
3486 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_OUT_CNT);
3487 if (!ptr) {
3488 if (stkctr == &tmpstkctr)
3489 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003490 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003491 }
3492
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003493 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003494
Willy Tarreau7d562212016-11-25 16:10:05 +01003495 smp->data.u.sint = stktable_data_cast(ptr, bytes_out_cnt) >> 10;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003496
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003497 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003498
3499 if (stkctr == &tmpstkctr)
3500 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003501 }
3502 return 1;
3503}
3504
3505/* set <smp> to the data rate sent to clients in bytes/s, as found in the
3506 * stream's tracked frontend counters. Supports being called as
3507 * "sc[0-9]_bytes_out_rate" or "src_bytes_out_rate" only.
3508 */
3509static int
3510smp_fetch_sc_bytes_out_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3511{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003512 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003513 struct stkctr *stkctr;
3514
Emeric Brun819fc6f2017-06-13 19:37:32 +02003515 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003516 if (!stkctr)
3517 return 0;
3518
3519 smp->flags = SMP_F_VOL_TEST;
3520 smp->data.type = SMP_T_SINT;
3521 smp->data.u.sint = 0;
3522 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003523 void *ptr;
3524
3525 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_OUT_RATE);
3526 if (!ptr) {
3527 if (stkctr == &tmpstkctr)
3528 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003529 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003530 }
3531
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003532 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003533
Willy Tarreau7d562212016-11-25 16:10:05 +01003534 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, bytes_out_rate),
3535 stkctr->table->data_arg[STKTABLE_DT_BYTES_OUT_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003536
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003537 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003538
3539 if (stkctr == &tmpstkctr)
3540 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003541 }
3542 return 1;
3543}
3544
3545/* set <smp> to the number of active trackers on the SC entry in the stream's
3546 * tracked frontend counters. Supports being called as "sc[0-9]_trackers" only.
3547 */
3548static int
3549smp_fetch_sc_trackers(const struct arg *args, struct sample *smp, const char *kw, void *private)
3550{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003551 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003552 struct stkctr *stkctr;
3553
Emeric Brun819fc6f2017-06-13 19:37:32 +02003554 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003555 if (!stkctr)
3556 return 0;
3557
3558 smp->flags = SMP_F_VOL_TEST;
3559 smp->data.type = SMP_T_SINT;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003560 if (stkctr == &tmpstkctr) {
3561 smp->data.u.sint = stkctr_entry(stkctr) ? (stkctr_entry(stkctr)->ref_cnt-1) : 0;
3562 stktable_release(stkctr->table, stkctr_entry(stkctr));
3563 }
3564 else {
3565 smp->data.u.sint = stkctr_entry(stkctr) ? stkctr_entry(stkctr)->ref_cnt : 0;
3566 }
3567
Willy Tarreau7d562212016-11-25 16:10:05 +01003568 return 1;
3569}
3570
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003571
3572/* The functions below are used to manipulate table contents from the CLI.
3573 * There are 3 main actions, "clear", "set" and "show". The code is shared
3574 * between all actions, and the action is encoded in the void *private in
3575 * the appctx as well as in the keyword registration, among one of the
3576 * following values.
3577 */
3578
3579enum {
3580 STK_CLI_ACT_CLR,
3581 STK_CLI_ACT_SET,
3582 STK_CLI_ACT_SHOW,
3583};
3584
3585/* Dump the status of a table to a stream interface's
3586 * read buffer. It returns 0 if the output buffer is full
3587 * and needs to be called again, otherwise non-zero.
3588 */
Willy Tarreau83061a82018-07-13 11:56:34 +02003589static int table_dump_head_to_buffer(struct buffer *msg,
3590 struct stream_interface *si,
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003591 struct stktable *t, struct stktable *target)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003592{
3593 struct stream *s = si_strm(si);
3594
3595 chunk_appendf(msg, "# table: %s, type: %s, size:%d, used:%d\n",
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003596 t->id, stktable_types[t->type].kw, t->size, t->current);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003597
3598 /* any other information should be dumped here */
3599
William Lallemand07a62f72017-05-24 00:57:40 +02003600 if (target && (strm_li(s)->bind_conf->level & ACCESS_LVL_MASK) < ACCESS_LVL_OPER)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003601 chunk_appendf(msg, "# contents not dumped due to insufficient privileges\n");
3602
Willy Tarreau06d80a92017-10-19 14:32:15 +02003603 if (ci_putchk(si_ic(si), msg) == -1) {
Willy Tarreaudb398432018-11-15 11:08:52 +01003604 si_rx_room_blk(si);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003605 return 0;
3606 }
3607
3608 return 1;
3609}
3610
3611/* Dump a table entry to a stream interface's
3612 * read buffer. It returns 0 if the output buffer is full
3613 * and needs to be called again, otherwise non-zero.
3614 */
Willy Tarreau83061a82018-07-13 11:56:34 +02003615static int table_dump_entry_to_buffer(struct buffer *msg,
3616 struct stream_interface *si,
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003617 struct stktable *t, struct stksess *entry)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003618{
3619 int dt;
3620
3621 chunk_appendf(msg, "%p:", entry);
3622
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003623 if (t->type == SMP_T_IPV4) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003624 char addr[INET_ADDRSTRLEN];
3625 inet_ntop(AF_INET, (const void *)&entry->key.key, addr, sizeof(addr));
3626 chunk_appendf(msg, " key=%s", addr);
3627 }
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003628 else if (t->type == SMP_T_IPV6) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003629 char addr[INET6_ADDRSTRLEN];
3630 inet_ntop(AF_INET6, (const void *)&entry->key.key, addr, sizeof(addr));
3631 chunk_appendf(msg, " key=%s", addr);
3632 }
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003633 else if (t->type == SMP_T_SINT) {
Willy Tarreau6cde5d82020-02-25 09:41:22 +01003634 chunk_appendf(msg, " key=%u", read_u32(entry->key.key));
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003635 }
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003636 else if (t->type == SMP_T_STR) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003637 chunk_appendf(msg, " key=");
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003638 dump_text(msg, (const char *)entry->key.key, t->key_size);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003639 }
3640 else {
3641 chunk_appendf(msg, " key=");
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003642 dump_binary(msg, (const char *)entry->key.key, t->key_size);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003643 }
3644
3645 chunk_appendf(msg, " use=%d exp=%d", entry->ref_cnt - 1, tick_remain(now_ms, entry->expire));
3646
3647 for (dt = 0; dt < STKTABLE_DATA_TYPES; dt++) {
3648 void *ptr;
3649
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003650 if (t->data_ofs[dt] == 0)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003651 continue;
3652 if (stktable_data_types[dt].arg_type == ARG_T_DELAY)
Emeric Brunc24b4142021-06-30 16:24:04 +02003653 chunk_appendf(msg, " %s(%u)=", stktable_data_types[dt].name, t->data_arg[dt].u);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003654 else
3655 chunk_appendf(msg, " %s=", stktable_data_types[dt].name);
3656
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003657 ptr = stktable_data_ptr(t, entry, dt);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003658 switch (stktable_data_types[dt].std_type) {
3659 case STD_T_SINT:
3660 chunk_appendf(msg, "%d", stktable_data_cast(ptr, std_t_sint));
3661 break;
3662 case STD_T_UINT:
3663 chunk_appendf(msg, "%u", stktable_data_cast(ptr, std_t_uint));
3664 break;
3665 case STD_T_ULL:
Emeric Brunc24b4142021-06-30 16:24:04 +02003666 chunk_appendf(msg, "%llu", stktable_data_cast(ptr, std_t_ull));
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003667 break;
3668 case STD_T_FRQP:
Emeric Brunc24b4142021-06-30 16:24:04 +02003669 chunk_appendf(msg, "%u",
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003670 read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003671 t->data_arg[dt].u));
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003672 break;
Frédéric Lécaille16b4f542019-05-23 12:15:04 +02003673 case STD_T_DICT: {
3674 struct dict_entry *de;
3675 de = stktable_data_cast(ptr, std_t_dict);
3676 chunk_appendf(msg, "%s", de ? (char *)de->value.key : "-");
3677 break;
3678 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003679 }
3680 }
3681 chunk_appendf(msg, "\n");
3682
Willy Tarreau06d80a92017-10-19 14:32:15 +02003683 if (ci_putchk(si_ic(si), msg) == -1) {
Willy Tarreaudb398432018-11-15 11:08:52 +01003684 si_rx_room_blk(si);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003685 return 0;
3686 }
3687
3688 return 1;
3689}
3690
3691
3692/* Processes a single table entry matching a specific key passed in argument.
3693 * returns 0 if wants to be called again, 1 if has ended processing.
3694 */
3695static int table_process_entry_per_key(struct appctx *appctx, char **args)
3696{
3697 struct stream_interface *si = appctx->owner;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003698 struct stktable *t = appctx->ctx.table.target;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003699 struct stksess *ts;
3700 uint32_t uint32_key;
3701 unsigned char ip6_key[sizeof(struct in6_addr)];
3702 long long value;
3703 int data_type;
3704 int cur_arg;
3705 void *ptr;
Willy Tarreaufa1258f2021-04-10 23:00:53 +02003706 struct freq_ctr *frqp;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003707
Willy Tarreau9d008692019-08-09 11:21:01 +02003708 if (!*args[4])
3709 return cli_err(appctx, "Key value expected\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003710
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003711 switch (t->type) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003712 case SMP_T_IPV4:
Aurelien DARRAGONe7489752023-08-28 13:57:19 +02003713 if (inet_pton(AF_INET, args[4], &uint32_key) <= 0)
3714 return cli_err(appctx, "Invalid key\n");
Christopher Fauletca20d022017-08-29 15:30:31 +02003715 static_table_key.key = &uint32_key;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003716 break;
3717 case SMP_T_IPV6:
Christopher Faulet1e850b52021-11-15 09:17:25 +01003718 if (inet_pton(AF_INET6, args[4], ip6_key) <= 0)
3719 return cli_err(appctx, "Invalid key\n");
Christopher Fauletca20d022017-08-29 15:30:31 +02003720 static_table_key.key = &ip6_key;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003721 break;
3722 case SMP_T_SINT:
3723 {
3724 char *endptr;
3725 unsigned long val;
3726 errno = 0;
3727 val = strtoul(args[4], &endptr, 10);
3728 if ((errno == ERANGE && val == ULONG_MAX) ||
3729 (errno != 0 && val == 0) || endptr == args[4] ||
Willy Tarreau9d008692019-08-09 11:21:01 +02003730 val > 0xffffffff)
3731 return cli_err(appctx, "Invalid key\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003732 uint32_key = (uint32_t) val;
Christopher Fauletca20d022017-08-29 15:30:31 +02003733 static_table_key.key = &uint32_key;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003734 break;
3735 }
3736 break;
3737 case SMP_T_STR:
Christopher Fauletca20d022017-08-29 15:30:31 +02003738 static_table_key.key = args[4];
3739 static_table_key.key_len = strlen(args[4]);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003740 break;
3741 default:
Willy Tarreaua24bc782016-12-14 15:50:35 +01003742 switch (appctx->ctx.table.action) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003743 case STK_CLI_ACT_SHOW:
Willy Tarreau9d008692019-08-09 11:21:01 +02003744 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 +01003745 case STK_CLI_ACT_CLR:
Willy Tarreau9d008692019-08-09 11:21:01 +02003746 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 +01003747 case STK_CLI_ACT_SET:
Willy Tarreau9d008692019-08-09 11:21:01 +02003748 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 +01003749 default:
Willy Tarreau9d008692019-08-09 11:21:01 +02003750 return cli_err(appctx, "Unknown action\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003751 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003752 }
3753
3754 /* check permissions */
3755 if (!cli_has_level(appctx, ACCESS_LVL_OPER))
3756 return 1;
3757
Willy Tarreaua24bc782016-12-14 15:50:35 +01003758 switch (appctx->ctx.table.action) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003759 case STK_CLI_ACT_SHOW:
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003760 ts = stktable_lookup_key(t, &static_table_key);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003761 if (!ts)
3762 return 1;
3763 chunk_reset(&trash);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003764 if (!table_dump_head_to_buffer(&trash, si, t, t)) {
3765 stktable_release(t, ts);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003766 return 0;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003767 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003768 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003769 if (!table_dump_entry_to_buffer(&trash, si, t, ts)) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003770 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003771 stktable_release(t, ts);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003772 return 0;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003773 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003774 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003775 stktable_release(t, ts);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003776 break;
3777
3778 case STK_CLI_ACT_CLR:
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003779 ts = stktable_lookup_key(t, &static_table_key);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003780 if (!ts)
3781 return 1;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003782
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003783 if (!stksess_kill(t, ts, 1)) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003784 /* don't delete an entry which is currently referenced */
Willy Tarreau9d008692019-08-09 11:21:01 +02003785 return cli_err(appctx, "Entry currently in use, cannot remove\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003786 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003787 break;
3788
3789 case STK_CLI_ACT_SET:
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003790 ts = stktable_get_entry(t, &static_table_key);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003791 if (!ts) {
3792 /* don't delete an entry which is currently referenced */
Willy Tarreau9d008692019-08-09 11:21:01 +02003793 return cli_err(appctx, "Unable to allocate a new entry\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003794 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003795 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003796 for (cur_arg = 5; *args[cur_arg]; cur_arg += 2) {
3797 if (strncmp(args[cur_arg], "data.", 5) != 0) {
Willy Tarreau9d008692019-08-09 11:21:01 +02003798 cli_err(appctx, "\"data.<type>\" followed by a value expected\n");
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003799 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003800 stktable_touch_local(t, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003801 return 1;
3802 }
3803
3804 data_type = stktable_get_data_type(args[cur_arg] + 5);
3805 if (data_type < 0) {
Willy Tarreau9d008692019-08-09 11:21:01 +02003806 cli_err(appctx, "Unknown data type\n");
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003807 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003808 stktable_touch_local(t, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003809 return 1;
3810 }
3811
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003812 if (!t->data_ofs[data_type]) {
Willy Tarreau9d008692019-08-09 11:21:01 +02003813 cli_err(appctx, "Data type not stored in this table\n");
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003814 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003815 stktable_touch_local(t, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003816 return 1;
3817 }
3818
3819 if (!*args[cur_arg+1] || strl2llrc(args[cur_arg+1], strlen(args[cur_arg+1]), &value) != 0) {
Willy Tarreau9d008692019-08-09 11:21:01 +02003820 cli_err(appctx, "Require a valid integer value to store\n");
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003821 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003822 stktable_touch_local(t, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003823 return 1;
3824 }
3825
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003826 ptr = stktable_data_ptr(t, ts, data_type);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003827
3828 switch (stktable_data_types[data_type].std_type) {
3829 case STD_T_SINT:
3830 stktable_data_cast(ptr, std_t_sint) = value;
3831 break;
3832 case STD_T_UINT:
3833 stktable_data_cast(ptr, std_t_uint) = value;
3834 break;
3835 case STD_T_ULL:
3836 stktable_data_cast(ptr, std_t_ull) = value;
3837 break;
3838 case STD_T_FRQP:
3839 /* We set both the current and previous values. That way
3840 * the reported frequency is stable during all the period
3841 * then slowly fades out. This allows external tools to
3842 * push measures without having to update them too often.
3843 */
3844 frqp = &stktable_data_cast(ptr, std_t_frqp);
Willy Tarreaufa1258f2021-04-10 23:00:53 +02003845 /* First bit is reserved for the freq_ctr lock
Emeric Brunf2fc1fd2017-11-02 17:32:43 +01003846 Note: here we're still protected by the stksess lock
Willy Tarreaufa1258f2021-04-10 23:00:53 +02003847 so we don't need to update the update the freq_ctr
Emeric Brunf2fc1fd2017-11-02 17:32:43 +01003848 using its internal lock */
3849 frqp->curr_tick = now_ms & ~0x1;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003850 frqp->prev_ctr = 0;
3851 frqp->curr_ctr = value;
3852 break;
3853 }
3854 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003855 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003856 stktable_touch_local(t, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003857 break;
3858
3859 default:
Willy Tarreau9d008692019-08-09 11:21:01 +02003860 return cli_err(appctx, "Unknown action\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003861 }
3862 return 1;
3863}
3864
3865/* Prepares the appctx fields with the data-based filters from the command line.
3866 * Returns 0 if the dump can proceed, 1 if has ended processing.
3867 */
3868static int table_prepare_data_request(struct appctx *appctx, char **args)
3869{
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01003870 int i;
Adis Nezirovicd0142e72020-01-22 16:50:27 +01003871 char *err = NULL;
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01003872
Willy Tarreau9d008692019-08-09 11:21:01 +02003873 if (appctx->ctx.table.action != STK_CLI_ACT_SHOW && appctx->ctx.table.action != STK_CLI_ACT_CLR)
3874 return cli_err(appctx, "content-based lookup is only supported with the \"show\" and \"clear\" actions\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003875
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01003876 for (i = 0; i < STKTABLE_FILTER_LEN; i++) {
3877 if (i > 0 && !*args[3+3*i]) // number of filter entries can be less than STKTABLE_FILTER_LEN
3878 break;
3879 /* condition on stored data value */
3880 appctx->ctx.table.data_type[i] = stktable_get_data_type(args[3+3*i] + 5);
3881 if (appctx->ctx.table.data_type[i] < 0)
Adis Nezirovicd0142e72020-01-22 16:50:27 +01003882 return cli_dynerr(appctx, memprintf(&err, "Filter entry #%i: Unknown data type\n", i + 1));
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003883
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01003884 if (!((struct stktable *)appctx->ctx.table.target)->data_ofs[appctx->ctx.table.data_type[i]])
Adis Nezirovicd0142e72020-01-22 16:50:27 +01003885 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 +01003886
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01003887 appctx->ctx.table.data_op[i] = get_std_op(args[4+3*i]);
Willy Tarreau2b64a352020-01-22 17:09:47 +01003888 if (appctx->ctx.table.data_op[i] < 0)
Adis Nezirovicd0142e72020-01-22 16:50:27 +01003889 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 +01003890
Adis Nezirovic56dd3542020-01-22 16:16:48 +01003891 if (!*args[5+3*i] || strl2llrc(args[5+3*i], strlen(args[5+3*i]), &appctx->ctx.table.value[i]) != 0)
Adis Nezirovicd0142e72020-01-22 16:50:27 +01003892 return cli_dynerr(appctx, memprintf(&err, "Filter entry #%i: Require a valid integer value to compare against\n", i + 1));
3893 }
3894
3895 if (*args[3+3*i]) {
3896 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 +01003897 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003898
3899 /* OK we're done, all the fields are set */
3900 return 0;
3901}
3902
3903/* returns 0 if wants to be called, 1 if has ended processing */
Aurélien Nephtaliabbf6072018-04-18 13:26:46 +02003904static int cli_parse_table_req(char **args, char *payload, struct appctx *appctx, void *private)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003905{
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01003906 int i;
3907
3908 for (i = 0; i < STKTABLE_FILTER_LEN; i++)
3909 appctx->ctx.table.data_type[i] = -1;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003910 appctx->ctx.table.target = NULL;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003911 appctx->ctx.table.entry = NULL;
Willy Tarreaua24bc782016-12-14 15:50:35 +01003912 appctx->ctx.table.action = (long)private; // keyword argument, one of STK_CLI_ACT_*
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003913
3914 if (*args[2]) {
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003915 appctx->ctx.table.target = stktable_find_by_name(args[2]);
Willy Tarreau9d008692019-08-09 11:21:01 +02003916 if (!appctx->ctx.table.target)
3917 return cli_err(appctx, "No such table\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003918 }
3919 else {
Willy Tarreaua24bc782016-12-14 15:50:35 +01003920 if (appctx->ctx.table.action != STK_CLI_ACT_SHOW)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003921 goto err_args;
3922 return 0;
3923 }
3924
3925 if (strcmp(args[3], "key") == 0)
3926 return table_process_entry_per_key(appctx, args);
3927 else if (strncmp(args[3], "data.", 5) == 0)
3928 return table_prepare_data_request(appctx, args);
3929 else if (*args[3])
3930 goto err_args;
3931
3932 return 0;
3933
3934err_args:
Willy Tarreaua24bc782016-12-14 15:50:35 +01003935 switch (appctx->ctx.table.action) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003936 case STK_CLI_ACT_SHOW:
Willy Tarreau9d008692019-08-09 11:21:01 +02003937 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 +01003938 case STK_CLI_ACT_CLR:
Willy Tarreau9d008692019-08-09 11:21:01 +02003939 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 +01003940 case STK_CLI_ACT_SET:
Willy Tarreau9d008692019-08-09 11:21:01 +02003941 return cli_err(appctx, "Required arguments: <table> key <key> [data.<store_data_type> <value>]*\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003942 default:
Willy Tarreau9d008692019-08-09 11:21:01 +02003943 return cli_err(appctx, "Unknown action\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003944 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003945}
3946
3947/* This function is used to deal with table operations (dump or clear depending
3948 * on the action stored in appctx->private). It returns 0 if the output buffer is
3949 * full and it needs to be called again, otherwise non-zero.
3950 */
3951static int cli_io_handler_table(struct appctx *appctx)
3952{
3953 struct stream_interface *si = appctx->owner;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003954 struct stream *s = si_strm(si);
3955 struct ebmb_node *eb;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003956 int skip_entry;
Willy Tarreaua24bc782016-12-14 15:50:35 +01003957 int show = appctx->ctx.table.action == STK_CLI_ACT_SHOW;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003958
3959 /*
3960 * We have 3 possible states in appctx->st2 :
3961 * - STAT_ST_INIT : the first call
3962 * - STAT_ST_INFO : the proxy pointer points to the next table to
3963 * dump, the entry pointer is NULL ;
3964 * - STAT_ST_LIST : the proxy pointer points to the current table
3965 * and the entry pointer points to the next entry to be dumped,
3966 * and the refcount on the next entry is held ;
3967 * - STAT_ST_END : nothing left to dump, the buffer may contain some
3968 * data though.
3969 */
3970
3971 if (unlikely(si_ic(si)->flags & (CF_WRITE_ERROR|CF_SHUTW))) {
3972 /* in case of abort, remove any refcount we might have set on an entry */
3973 if (appctx->st2 == STAT_ST_LIST) {
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003974 stksess_kill_if_expired(appctx->ctx.table.t, appctx->ctx.table.entry, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003975 }
3976 return 1;
3977 }
3978
3979 chunk_reset(&trash);
3980
3981 while (appctx->st2 != STAT_ST_FIN) {
3982 switch (appctx->st2) {
3983 case STAT_ST_INIT:
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003984 appctx->ctx.table.t = appctx->ctx.table.target;
3985 if (!appctx->ctx.table.t)
3986 appctx->ctx.table.t = stktables_list;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003987
3988 appctx->ctx.table.entry = NULL;
3989 appctx->st2 = STAT_ST_INFO;
3990 break;
3991
3992 case STAT_ST_INFO:
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003993 if (!appctx->ctx.table.t ||
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003994 (appctx->ctx.table.target &&
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003995 appctx->ctx.table.t != appctx->ctx.table.target)) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003996 appctx->st2 = STAT_ST_END;
3997 break;
3998 }
3999
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004000 if (appctx->ctx.table.t->size) {
4001 if (show && !table_dump_head_to_buffer(&trash, si, appctx->ctx.table.t, appctx->ctx.table.target))
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004002 return 0;
4003
4004 if (appctx->ctx.table.target &&
William Lallemand07a62f72017-05-24 00:57:40 +02004005 (strm_li(s)->bind_conf->level & ACCESS_LVL_MASK) >= ACCESS_LVL_OPER) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004006 /* dump entries only if table explicitly requested */
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004007 HA_SPIN_LOCK(STK_TABLE_LOCK, &appctx->ctx.table.t->lock);
4008 eb = ebmb_first(&appctx->ctx.table.t->keys);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004009 if (eb) {
4010 appctx->ctx.table.entry = ebmb_entry(eb, struct stksess, key);
4011 appctx->ctx.table.entry->ref_cnt++;
4012 appctx->st2 = STAT_ST_LIST;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004013 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &appctx->ctx.table.t->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004014 break;
4015 }
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004016 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &appctx->ctx.table.t->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004017 }
4018 }
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004019 appctx->ctx.table.t = appctx->ctx.table.t->next;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004020 break;
4021
4022 case STAT_ST_LIST:
4023 skip_entry = 0;
4024
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004025 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &appctx->ctx.table.entry->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004026
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004027 if (appctx->ctx.table.data_type[0] >= 0) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004028 /* we're filtering on some data contents */
4029 void *ptr;
Willy Tarreau2b64a352020-01-22 17:09:47 +01004030 int dt, i;
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004031 signed char op;
4032 long long data, value;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004033
Emeric Brun819fc6f2017-06-13 19:37:32 +02004034
Willy Tarreau2b64a352020-01-22 17:09:47 +01004035 for (i = 0; i < STKTABLE_FILTER_LEN; i++) {
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004036 if (appctx->ctx.table.data_type[i] == -1)
4037 break;
4038 dt = appctx->ctx.table.data_type[i];
4039 ptr = stktable_data_ptr(appctx->ctx.table.t,
4040 appctx->ctx.table.entry,
4041 dt);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004042
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004043 data = 0;
4044 switch (stktable_data_types[dt].std_type) {
4045 case STD_T_SINT:
4046 data = stktable_data_cast(ptr, std_t_sint);
4047 break;
4048 case STD_T_UINT:
4049 data = stktable_data_cast(ptr, std_t_uint);
4050 break;
4051 case STD_T_ULL:
4052 data = stktable_data_cast(ptr, std_t_ull);
4053 break;
4054 case STD_T_FRQP:
4055 data = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
4056 appctx->ctx.table.t->data_arg[dt].u);
4057 break;
4058 }
4059
4060 op = appctx->ctx.table.data_op[i];
4061 value = appctx->ctx.table.value[i];
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004062
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004063 /* skip the entry if the data does not match the test and the value */
4064 if ((data < value &&
4065 (op == STD_OP_EQ || op == STD_OP_GT || op == STD_OP_GE)) ||
4066 (data == value &&
4067 (op == STD_OP_NE || op == STD_OP_GT || op == STD_OP_LT)) ||
4068 (data > value &&
4069 (op == STD_OP_EQ || op == STD_OP_LT || op == STD_OP_LE))) {
4070 skip_entry = 1;
4071 break;
4072 }
4073 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004074 }
4075
4076 if (show && !skip_entry &&
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004077 !table_dump_entry_to_buffer(&trash, si, appctx->ctx.table.t, appctx->ctx.table.entry)) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004078 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &appctx->ctx.table.entry->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004079 return 0;
4080 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004081
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004082 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &appctx->ctx.table.entry->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004083
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004084 HA_SPIN_LOCK(STK_TABLE_LOCK, &appctx->ctx.table.t->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004085 appctx->ctx.table.entry->ref_cnt--;
4086
4087 eb = ebmb_next(&appctx->ctx.table.entry->key);
4088 if (eb) {
4089 struct stksess *old = appctx->ctx.table.entry;
4090 appctx->ctx.table.entry = ebmb_entry(eb, struct stksess, key);
4091 if (show)
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004092 __stksess_kill_if_expired(appctx->ctx.table.t, old);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004093 else if (!skip_entry && !appctx->ctx.table.entry->ref_cnt)
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004094 __stksess_kill(appctx->ctx.table.t, old);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004095 appctx->ctx.table.entry->ref_cnt++;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004096 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &appctx->ctx.table.t->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004097 break;
4098 }
4099
4100
4101 if (show)
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004102 __stksess_kill_if_expired(appctx->ctx.table.t, appctx->ctx.table.entry);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004103 else if (!skip_entry && !appctx->ctx.table.entry->ref_cnt)
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004104 __stksess_kill(appctx->ctx.table.t, appctx->ctx.table.entry);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004105
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004106 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &appctx->ctx.table.t->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004107
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004108 appctx->ctx.table.t = appctx->ctx.table.t->next;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004109 appctx->st2 = STAT_ST_INFO;
4110 break;
4111
4112 case STAT_ST_END:
4113 appctx->st2 = STAT_ST_FIN;
4114 break;
4115 }
4116 }
4117 return 1;
4118}
4119
4120static void cli_release_show_table(struct appctx *appctx)
4121{
4122 if (appctx->st2 == STAT_ST_LIST) {
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004123 stksess_kill_if_expired(appctx->ctx.table.t, appctx->ctx.table.entry, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004124 }
4125}
4126
Willy Tarreau478331d2020-08-28 11:31:31 +02004127static void stkt_late_init(void)
4128{
4129 struct sample_fetch *f;
4130
4131 f = find_sample_fetch("src", strlen("src"));
4132 if (f)
4133 smp_fetch_src = f->process;
4134}
4135
4136INITCALL0(STG_INIT, stkt_late_init);
4137
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004138/* register cli keywords */
4139static struct cli_kw_list cli_kws = {{ },{
Willy Tarreaub205bfd2021-05-07 11:38:37 +02004140 { { "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 },
4141 { { "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 },
4142 { { "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 +01004143 {{},}
4144}};
4145
Willy Tarreau0108d902018-11-25 19:14:37 +01004146INITCALL1(STG_REGISTER, cli_register_kw, &cli_kws);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004147
Thierry FOURNIER236657b2015-08-19 08:25:14 +02004148static struct action_kw_list tcp_conn_kws = { { }, {
Amaury Denoyellee4a617c2021-05-06 15:33:09 +02004149 { "sc-inc-gpc0", parse_inc_gpc0, KWF_MATCH_PREFIX },
4150 { "sc-inc-gpc1", parse_inc_gpc1, KWF_MATCH_PREFIX },
4151 { "sc-set-gpt0", parse_set_gpt0, KWF_MATCH_PREFIX },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02004152 { /* END */ }
4153}};
4154
Willy Tarreau0108d902018-11-25 19:14:37 +01004155INITCALL1(STG_REGISTER, tcp_req_conn_keywords_register, &tcp_conn_kws);
4156
Willy Tarreau620408f2016-10-21 16:37:51 +02004157static struct action_kw_list tcp_sess_kws = { { }, {
Amaury Denoyellee4a617c2021-05-06 15:33:09 +02004158 { "sc-inc-gpc0", parse_inc_gpc0, KWF_MATCH_PREFIX },
4159 { "sc-inc-gpc1", parse_inc_gpc1, KWF_MATCH_PREFIX },
4160 { "sc-set-gpt0", parse_set_gpt0, KWF_MATCH_PREFIX },
Willy Tarreau620408f2016-10-21 16:37:51 +02004161 { /* END */ }
4162}};
4163
Willy Tarreau0108d902018-11-25 19:14:37 +01004164INITCALL1(STG_REGISTER, tcp_req_sess_keywords_register, &tcp_sess_kws);
4165
Thierry FOURNIER236657b2015-08-19 08:25:14 +02004166static struct action_kw_list tcp_req_kws = { { }, {
Amaury Denoyellee4a617c2021-05-06 15:33:09 +02004167 { "sc-inc-gpc0", parse_inc_gpc0, KWF_MATCH_PREFIX },
4168 { "sc-inc-gpc1", parse_inc_gpc1, KWF_MATCH_PREFIX },
4169 { "sc-set-gpt0", parse_set_gpt0, KWF_MATCH_PREFIX },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02004170 { /* END */ }
4171}};
4172
Willy Tarreau0108d902018-11-25 19:14:37 +01004173INITCALL1(STG_REGISTER, tcp_req_cont_keywords_register, &tcp_req_kws);
4174
Thierry FOURNIER236657b2015-08-19 08:25:14 +02004175static struct action_kw_list tcp_res_kws = { { }, {
Amaury Denoyellee4a617c2021-05-06 15:33:09 +02004176 { "sc-inc-gpc0", parse_inc_gpc0, KWF_MATCH_PREFIX },
4177 { "sc-inc-gpc1", parse_inc_gpc1, KWF_MATCH_PREFIX },
4178 { "sc-set-gpt0", parse_set_gpt0, KWF_MATCH_PREFIX },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02004179 { /* END */ }
4180}};
4181
Willy Tarreau0108d902018-11-25 19:14:37 +01004182INITCALL1(STG_REGISTER, tcp_res_cont_keywords_register, &tcp_res_kws);
4183
Thierry FOURNIER236657b2015-08-19 08:25:14 +02004184static struct action_kw_list http_req_kws = { { }, {
Amaury Denoyellee4a617c2021-05-06 15:33:09 +02004185 { "sc-inc-gpc0", parse_inc_gpc0, KWF_MATCH_PREFIX },
4186 { "sc-inc-gpc1", parse_inc_gpc1, KWF_MATCH_PREFIX },
4187 { "sc-set-gpt0", parse_set_gpt0, KWF_MATCH_PREFIX },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02004188 { /* END */ }
4189}};
4190
Willy Tarreau0108d902018-11-25 19:14:37 +01004191INITCALL1(STG_REGISTER, http_req_keywords_register, &http_req_kws);
4192
Thierry FOURNIER236657b2015-08-19 08:25:14 +02004193static struct action_kw_list http_res_kws = { { }, {
Amaury Denoyellee4a617c2021-05-06 15:33:09 +02004194 { "sc-inc-gpc0", parse_inc_gpc0, KWF_MATCH_PREFIX },
4195 { "sc-inc-gpc1", parse_inc_gpc1, KWF_MATCH_PREFIX },
4196 { "sc-set-gpt0", parse_set_gpt0, KWF_MATCH_PREFIX },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02004197 { /* END */ }
4198}};
4199
Willy Tarreau0108d902018-11-25 19:14:37 +01004200INITCALL1(STG_REGISTER, http_res_keywords_register, &http_res_kws);
4201
Willy Tarreau7d562212016-11-25 16:10:05 +01004202/* Note: must not be declared <const> as its list will be overwritten.
4203 * Please take care of keeping this list alphabetically sorted.
4204 */
4205static struct sample_fetch_kw_list smp_fetch_keywords = {ILH, {
4206 { "sc_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4207 { "sc_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4208 { "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 +01004209 { "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 +01004210 { "sc_conn_cnt", smp_fetch_sc_conn_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4211 { "sc_conn_cur", smp_fetch_sc_conn_cur, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4212 { "sc_conn_rate", smp_fetch_sc_conn_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
Thierry FOURNIER401c64b2017-01-05 11:44:09 +01004213 { "sc_get_gpt0", smp_fetch_sc_get_gpt0, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
Willy Tarreau7d562212016-11-25 16:10:05 +01004214 { "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 +01004215 { "sc_get_gpc1", smp_fetch_sc_get_gpc1, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN },
Willy Tarreau7d562212016-11-25 16:10:05 +01004216 { "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 +01004217 { "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 +01004218 { "sc_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4219 { "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 +01004220 { "sc_http_fail_cnt", smp_fetch_sc_http_fail_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4221 { "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 +01004222 { "sc_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4223 { "sc_http_req_rate", smp_fetch_sc_http_req_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4224 { "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 +01004225 { "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 +01004226 { "sc_kbytes_in", smp_fetch_sc_kbytes_in, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4227 { "sc_kbytes_out", smp_fetch_sc_kbytes_out, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4228 { "sc_sess_cnt", smp_fetch_sc_sess_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4229 { "sc_sess_rate", smp_fetch_sc_sess_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4230 { "sc_tracked", smp_fetch_sc_tracked, ARG2(1,SINT,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
4231 { "sc_trackers", smp_fetch_sc_trackers, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4232 { "sc0_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4233 { "sc0_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4234 { "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 +01004235 { "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 +01004236 { "sc0_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4237 { "sc0_conn_cur", smp_fetch_sc_conn_cur, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4238 { "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 +01004239 { "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 +01004240 { "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 +01004241 { "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 +01004242 { "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 +01004243 { "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 +01004244 { "sc0_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4245 { "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 +01004246 { "sc0_http_fail_cnt", smp_fetch_sc_http_fail_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4247 { "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 +01004248 { "sc0_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4249 { "sc0_http_req_rate", smp_fetch_sc_http_req_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4250 { "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 +01004251 { "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 +01004252 { "sc0_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4253 { "sc0_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4254 { "sc0_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4255 { "sc0_sess_rate", smp_fetch_sc_sess_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4256 { "sc0_tracked", smp_fetch_sc_tracked, ARG1(0,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
4257 { "sc0_trackers", smp_fetch_sc_trackers, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4258 { "sc1_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4259 { "sc1_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4260 { "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 +01004261 { "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 +01004262 { "sc1_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4263 { "sc1_conn_cur", smp_fetch_sc_conn_cur, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4264 { "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 +01004265 { "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 +01004266 { "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 +01004267 { "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 +01004268 { "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 +01004269 { "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 +01004270 { "sc1_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4271 { "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 +01004272 { "sc1_http_fail_cnt", smp_fetch_sc_http_fail_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4273 { "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 +01004274 { "sc1_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4275 { "sc1_http_req_rate", smp_fetch_sc_http_req_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4276 { "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 +01004277 { "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 +01004278 { "sc1_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4279 { "sc1_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4280 { "sc1_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4281 { "sc1_sess_rate", smp_fetch_sc_sess_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4282 { "sc1_tracked", smp_fetch_sc_tracked, ARG1(0,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
4283 { "sc1_trackers", smp_fetch_sc_trackers, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4284 { "sc2_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4285 { "sc2_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4286 { "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 +01004287 { "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 +01004288 { "sc2_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4289 { "sc2_conn_cur", smp_fetch_sc_conn_cur, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4290 { "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 +01004291 { "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 +01004292 { "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 +01004293 { "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 +01004294 { "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 +01004295 { "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 +01004296 { "sc2_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4297 { "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 +01004298 { "sc2_http_fail_cnt", smp_fetch_sc_http_fail_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4299 { "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 +01004300 { "sc2_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4301 { "sc2_http_req_rate", smp_fetch_sc_http_req_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4302 { "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 +01004303 { "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 +01004304 { "sc2_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4305 { "sc2_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4306 { "sc2_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4307 { "sc2_sess_rate", smp_fetch_sc_sess_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4308 { "sc2_tracked", smp_fetch_sc_tracked, ARG1(0,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
4309 { "sc2_trackers", smp_fetch_sc_trackers, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4310 { "src_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4311 { "src_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4312 { "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 +01004313 { "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 +01004314 { "src_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4315 { "src_conn_cur", smp_fetch_sc_conn_cur, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4316 { "src_conn_rate", smp_fetch_sc_conn_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
Thierry FOURNIER401c64b2017-01-05 11:44:09 +01004317 { "src_get_gpt0", smp_fetch_sc_get_gpt0, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
Willy Tarreau7d562212016-11-25 16:10:05 +01004318 { "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 +01004319 { "src_get_gpc1", smp_fetch_sc_get_gpc1, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
Willy Tarreau7d562212016-11-25 16:10:05 +01004320 { "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 +01004321 { "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 +01004322 { "src_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4323 { "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 +01004324 { "src_http_fail_cnt", smp_fetch_sc_http_fail_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4325 { "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 +01004326 { "src_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4327 { "src_http_req_rate", smp_fetch_sc_http_req_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4328 { "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 +01004329 { "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 +01004330 { "src_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4331 { "src_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4332 { "src_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4333 { "src_sess_rate", smp_fetch_sc_sess_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4334 { "src_updt_conn_cnt", smp_fetch_src_updt_conn_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4335 { "table_avl", smp_fetch_table_avl, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4336 { "table_cnt", smp_fetch_table_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4337 { /* END */ },
4338}};
4339
Willy Tarreau0108d902018-11-25 19:14:37 +01004340INITCALL1(STG_REGISTER, sample_register_fetches, &smp_fetch_keywords);
Willy Tarreau7d562212016-11-25 16:10:05 +01004341
Willy Tarreaud9f316a2014-07-10 14:03:38 +02004342/* Note: must not be declared <const> as its list will be overwritten */
4343static struct sample_conv_kw_list sample_conv_kws = {ILH, {
Willy Tarreau2d17db52016-05-25 17:16:38 +02004344 { "in_table", sample_conv_in_table, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_BOOL },
4345 { "table_bytes_in_rate", sample_conv_table_bytes_in_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4346 { "table_bytes_out_rate", sample_conv_table_bytes_out_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4347 { "table_conn_cnt", sample_conv_table_conn_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4348 { "table_conn_cur", sample_conv_table_conn_cur, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4349 { "table_conn_rate", sample_conv_table_conn_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4350 { "table_gpt0", sample_conv_table_gpt0, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4351 { "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 +01004352 { "table_gpc1", sample_conv_table_gpc1, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
Willy Tarreau2d17db52016-05-25 17:16:38 +02004353 { "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 +01004354 { "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 +02004355 { "table_http_err_cnt", sample_conv_table_http_err_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4356 { "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 +01004357 { "table_http_fail_cnt", sample_conv_table_http_fail_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4358 { "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 +02004359 { "table_http_req_cnt", sample_conv_table_http_req_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4360 { "table_http_req_rate", sample_conv_table_http_req_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4361 { "table_kbytes_in", sample_conv_table_kbytes_in, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4362 { "table_kbytes_out", sample_conv_table_kbytes_out, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4363 { "table_server_id", sample_conv_table_server_id, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4364 { "table_sess_cnt", sample_conv_table_sess_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4365 { "table_sess_rate", sample_conv_table_sess_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4366 { "table_trackers", sample_conv_table_trackers, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
Willy Tarreaud9f316a2014-07-10 14:03:38 +02004367 { /* END */ },
4368}};
4369
Willy Tarreau0108d902018-11-25 19:14:37 +01004370INITCALL1(STG_REGISTER, sample_register_convs, &sample_conv_kws);