blob: 67f21299b38aa11c11539915d2423f9ce77ec59c [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
678/*
679 * Configuration keywords of known table types
680 */
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200681struct stktable_type stktable_types[SMP_TYPES] = {
682 [SMP_T_SINT] = { "integer", 0, 4 },
683 [SMP_T_IPV4] = { "ip", 0, 4 },
684 [SMP_T_IPV6] = { "ipv6", 0, 16 },
685 [SMP_T_STR] = { "string", STK_F_CUSTOM_KEYSIZE, 32 },
686 [SMP_T_BIN] = { "binary", STK_F_CUSTOM_KEYSIZE, 32 }
687};
Emeric Brun3bd697e2010-01-04 15:23:48 +0100688
689/*
690 * Parse table type configuration.
691 * Returns 0 on successful parsing, else 1.
692 * <myidx> is set at next configuration <args> index.
693 */
694int stktable_parse_type(char **args, int *myidx, unsigned long *type, size_t *key_size)
695{
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200696 for (*type = 0; *type < SMP_TYPES; (*type)++) {
697 if (!stktable_types[*type].kw)
698 continue;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100699 if (strcmp(args[*myidx], stktable_types[*type].kw) != 0)
700 continue;
701
702 *key_size = stktable_types[*type].default_size;
703 (*myidx)++;
704
Willy Tarreauaea940e2010-06-06 11:56:36 +0200705 if (stktable_types[*type].flags & STK_F_CUSTOM_KEYSIZE) {
Emeric Brun3bd697e2010-01-04 15:23:48 +0100706 if (strcmp("len", args[*myidx]) == 0) {
707 (*myidx)++;
708 *key_size = atol(args[*myidx]);
Emeric Brun485479d2010-09-23 18:02:19 +0200709 if (!*key_size)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100710 break;
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200711 if (*type == SMP_T_STR) {
Emeric Brun485479d2010-09-23 18:02:19 +0200712 /* null terminated string needs +1 for '\0'. */
713 (*key_size)++;
714 }
Emeric Brun3bd697e2010-01-04 15:23:48 +0100715 (*myidx)++;
716 }
717 }
718 return 0;
719 }
720 return 1;
721}
722
Willy Tarreau3b63ca22021-05-08 14:10:42 +0200723/* reserve some space for data type <type>, and associate argument at <sa> if
724 * not NULL. Returns PE_NONE (0) if OK or an error code among :
725 * - PE_ENUM_OOR if <type> does not exist
726 * - PE_EXIST if <type> is already registered
727 * - PE_ARG_NOT_USE if <sa> was provided but not expected
728 * - PE_ARG_MISSING if <sa> was expected but not provided
729 */
730int stktable_alloc_data_type(struct stktable *t, int type, const char *sa)
731{
732 if (type >= STKTABLE_DATA_TYPES)
733 return PE_ENUM_OOR;
734
735 if (t->data_ofs[type])
736 /* already allocated */
737 return PE_EXIST;
738
739 switch (stktable_data_types[type].arg_type) {
740 case ARG_T_NONE:
741 if (sa)
742 return PE_ARG_NOT_USED;
743 break;
744 case ARG_T_INT:
745 if (!sa)
746 return PE_ARG_MISSING;
747 t->data_arg[type].i = atoi(sa);
748 break;
749 case ARG_T_DELAY:
750 if (!sa)
751 return PE_ARG_MISSING;
752 sa = parse_time_err(sa, &t->data_arg[type].u, TIME_UNIT_MS);
753 if (sa)
754 return PE_ARG_INVC; /* invalid char */
755 break;
756 }
757
758 t->data_size += stktable_type_size(stktable_data_types[type].std_type);
759 t->data_ofs[type] = -t->data_size;
760 return PE_NONE;
761}
762
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100763/*
Frédéric Lécaillec02766a2019-03-20 15:06:55 +0100764 * Parse a line with <linenum> as number in <file> configuration file to configure
765 * the stick-table with <t> as address and <id> as ID.
766 * <peers> provides the "peers" section pointer only if this function is called
767 * from a "peers" section.
768 * <nid> is the stick-table name which is sent over the network. It must be equal
769 * to <id> if this stick-table is parsed from a proxy section, and prefixed by <peers>
770 * "peers" section name followed by a '/' character if parsed from a "peers" section.
Ilya Shipitsind4259502020-04-08 01:07:56 +0500771 * This is the responsibility of the caller to check this.
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100772 * Return an error status with ERR_* flags set if required, 0 if no error was encountered.
773 */
774int parse_stick_table(const char *file, int linenum, char **args,
Frédéric Lécaillec02766a2019-03-20 15:06:55 +0100775 struct stktable *t, char *id, char *nid, struct peers *peers)
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100776{
777 int err_code = 0;
778 int idx = 1;
779 unsigned int val;
780
781 if (!id || !*id) {
782 ha_alert("parsing [%s:%d] : %s: ID not provided.\n", file, linenum, args[0]);
783 err_code |= ERR_ALERT | ERR_ABORT;
784 goto out;
785 }
786
787 /* Store the "peers" section if this function is called from a "peers" section. */
788 if (peers) {
789 t->peers.p = peers;
790 idx++;
791 }
792
793 t->id = id;
Frédéric Lécaillec02766a2019-03-20 15:06:55 +0100794 t->nid = nid;
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100795 t->type = (unsigned int)-1;
796 t->conf.file = file;
797 t->conf.line = linenum;
798
799 while (*args[idx]) {
800 const char *err;
801
802 if (strcmp(args[idx], "size") == 0) {
803 idx++;
804 if (!*(args[idx])) {
805 ha_alert("parsing [%s:%d] : %s: missing argument after '%s'.\n",
806 file, linenum, args[0], args[idx-1]);
807 err_code |= ERR_ALERT | ERR_FATAL;
808 goto out;
809 }
810 if ((err = parse_size_err(args[idx], &t->size))) {
811 ha_alert("parsing [%s:%d] : %s: unexpected character '%c' in argument of '%s'.\n",
812 file, linenum, args[0], *err, args[idx-1]);
813 err_code |= ERR_ALERT | ERR_FATAL;
814 goto out;
815 }
816 idx++;
817 }
818 /* This argument does not exit in "peers" section. */
819 else if (!peers && strcmp(args[idx], "peers") == 0) {
820 idx++;
821 if (!*(args[idx])) {
822 ha_alert("parsing [%s:%d] : %s: missing argument after '%s'.\n",
823 file, linenum, args[0], args[idx-1]);
824 err_code |= ERR_ALERT | ERR_FATAL;
825 goto out;
826 }
827 t->peers.name = strdup(args[idx++]);
828 }
829 else if (strcmp(args[idx], "expire") == 0) {
830 idx++;
831 if (!*(args[idx])) {
832 ha_alert("parsing [%s:%d] : %s: missing argument after '%s'.\n",
833 file, linenum, args[0], args[idx-1]);
834 err_code |= ERR_ALERT | ERR_FATAL;
835 goto out;
836 }
837 err = parse_time_err(args[idx], &val, TIME_UNIT_MS);
Willy Tarreau9faebe32019-06-07 19:00:37 +0200838 if (err == PARSE_TIME_OVER) {
839 ha_alert("parsing [%s:%d]: %s: timer overflow in argument <%s> to <%s>, maximum value is 2147483647 ms (~24.8 days).\n",
840 file, linenum, args[0], args[idx], args[idx-1]);
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100841 err_code |= ERR_ALERT | ERR_FATAL;
842 goto out;
843 }
Willy Tarreau9faebe32019-06-07 19:00:37 +0200844 else if (err == PARSE_TIME_UNDER) {
845 ha_alert("parsing [%s:%d]: %s: timer underflow in argument <%s> to <%s>, minimum non-null value is 1 ms.\n",
846 file, linenum, args[0], args[idx], args[idx-1]);
847 err_code |= ERR_ALERT | ERR_FATAL;
848 goto out;
849 }
850 else if (err) {
851 ha_alert("parsing [%s:%d] : %s: unexpected character '%c' in argument of '%s'.\n",
852 file, linenum, args[0], *err, args[idx-1]);
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100853 err_code |= ERR_ALERT | ERR_FATAL;
854 goto out;
855 }
856 t->expire = val;
857 idx++;
858 }
859 else if (strcmp(args[idx], "nopurge") == 0) {
860 t->nopurge = 1;
861 idx++;
862 }
863 else if (strcmp(args[idx], "type") == 0) {
864 idx++;
865 if (stktable_parse_type(args, &idx, &t->type, &t->key_size) != 0) {
866 ha_alert("parsing [%s:%d] : %s: unknown type '%s'.\n",
867 file, linenum, args[0], args[idx]);
868 err_code |= ERR_ALERT | ERR_FATAL;
869 goto out;
870 }
871 /* idx already points to next arg */
872 }
873 else if (strcmp(args[idx], "store") == 0) {
874 int type, err;
875 char *cw, *nw, *sa;
876
877 idx++;
878 nw = args[idx];
879 while (*nw) {
880 /* the "store" keyword supports a comma-separated list */
881 cw = nw;
882 sa = NULL; /* store arg */
883 while (*nw && *nw != ',') {
884 if (*nw == '(') {
885 *nw = 0;
886 sa = ++nw;
887 while (*nw != ')') {
888 if (!*nw) {
889 ha_alert("parsing [%s:%d] : %s: missing closing parenthesis after store option '%s'.\n",
890 file, linenum, args[0], cw);
891 err_code |= ERR_ALERT | ERR_FATAL;
892 goto out;
893 }
894 nw++;
895 }
896 *nw = '\0';
897 }
898 nw++;
899 }
900 if (*nw)
901 *nw++ = '\0';
902 type = stktable_get_data_type(cw);
903 if (type < 0) {
904 ha_alert("parsing [%s:%d] : %s: unknown store option '%s'.\n",
905 file, linenum, args[0], cw);
906 err_code |= ERR_ALERT | ERR_FATAL;
907 goto out;
908 }
909
910 err = stktable_alloc_data_type(t, type, sa);
911 switch (err) {
912 case PE_NONE: break;
913 case PE_EXIST:
914 ha_warning("parsing [%s:%d]: %s: store option '%s' already enabled, ignored.\n",
915 file, linenum, args[0], cw);
916 err_code |= ERR_WARN;
917 break;
918
919 case PE_ARG_MISSING:
920 ha_alert("parsing [%s:%d] : %s: missing argument to store option '%s'.\n",
921 file, linenum, args[0], cw);
922 err_code |= ERR_ALERT | ERR_FATAL;
923 goto out;
924
925 case PE_ARG_NOT_USED:
926 ha_alert("parsing [%s:%d] : %s: unexpected argument to store option '%s'.\n",
927 file, linenum, args[0], cw);
928 err_code |= ERR_ALERT | ERR_FATAL;
929 goto out;
930
931 default:
932 ha_alert("parsing [%s:%d] : %s: error when processing store option '%s'.\n",
933 file, linenum, args[0], cw);
934 err_code |= ERR_ALERT | ERR_FATAL;
935 goto out;
936 }
937 }
938 idx++;
939 }
Thayne McCombs92149f92020-11-20 01:28:26 -0700940 else if (strcmp(args[idx], "srvkey") == 0) {
941 char *keytype;
942 idx++;
943 keytype = args[idx];
944 if (strcmp(keytype, "name") == 0) {
945 t->server_key_type = STKTABLE_SRV_NAME;
946 }
947 else if (strcmp(keytype, "addr") == 0) {
948 t->server_key_type = STKTABLE_SRV_ADDR;
949 }
950 else {
951 ha_alert("parsing [%s:%d] : %s : unknown server key type '%s'.\n",
952 file, linenum, args[0], keytype);
953 err_code |= ERR_ALERT | ERR_FATAL;
954 goto out;
955
956 }
957 idx++;
958 }
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100959 else {
960 ha_alert("parsing [%s:%d] : %s: unknown argument '%s'.\n",
961 file, linenum, args[0], args[idx]);
962 err_code |= ERR_ALERT | ERR_FATAL;
963 goto out;
964 }
965 }
966
967 if (!t->size) {
968 ha_alert("parsing [%s:%d] : %s: missing size.\n",
969 file, linenum, args[0]);
970 err_code |= ERR_ALERT | ERR_FATAL;
971 goto out;
972 }
973
974 if (t->type == (unsigned int)-1) {
975 ha_alert("parsing [%s:%d] : %s: missing type.\n",
976 file, linenum, args[0]);
977 err_code |= ERR_ALERT | ERR_FATAL;
978 goto out;
979 }
980
981 out:
982 return err_code;
983}
984
Willy Tarreau8fed9032014-07-03 17:02:46 +0200985/* Prepares a stktable_key from a sample <smp> to search into table <t>.
Willy Tarreauf0c730a2016-05-25 17:07:56 +0200986 * Note that the sample *is* modified and that the returned key may point
987 * to it, so the sample must not be modified afterwards before the lookup.
Willy Tarreau8fed9032014-07-03 17:02:46 +0200988 * Returns NULL if the sample could not be converted (eg: no matching type),
989 * otherwise a pointer to the static stktable_key filled with what is needed
990 * for the lookup.
Willy Tarreauf0b38bf2010-06-06 13:22:23 +0200991 */
Willy Tarreau8fed9032014-07-03 17:02:46 +0200992struct stktable_key *smp_to_stkey(struct sample *smp, struct stktable *t)
Willy Tarreauf0b38bf2010-06-06 13:22:23 +0200993{
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200994 /* Convert sample. */
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200995 if (!sample_convert(smp, t->type))
Willy Tarreau7fc1c6e2012-04-26 11:03:17 +0200996 return NULL;
997
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200998 /* Fill static_table_key. */
999 switch (t->type) {
Emeric Brun485479d2010-09-23 18:02:19 +02001000
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +02001001 case SMP_T_IPV4:
Christopher Fauletca20d022017-08-29 15:30:31 +02001002 static_table_key.key = &smp->data.u.ipv4;
1003 static_table_key.key_len = 4;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001004 break;
Emeric Brun485479d2010-09-23 18:02:19 +02001005
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +02001006 case SMP_T_IPV6:
Christopher Fauletca20d022017-08-29 15:30:31 +02001007 static_table_key.key = &smp->data.u.ipv6;
1008 static_table_key.key_len = 16;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001009 break;
Emeric Brun485479d2010-09-23 18:02:19 +02001010
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +02001011 case SMP_T_SINT:
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001012 /* The stick table require a 32bit unsigned int, "sint" is a
1013 * signed 64 it, so we can convert it inplace.
1014 */
Willy Tarreau28c63c12019-10-23 06:21:05 +02001015 smp->data.u.sint = (unsigned int)smp->data.u.sint;
Christopher Fauletca20d022017-08-29 15:30:31 +02001016 static_table_key.key = &smp->data.u.sint;
1017 static_table_key.key_len = 4;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001018 break;
1019
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +02001020 case SMP_T_STR:
Willy Tarreauce6955e2016-08-09 11:59:12 +02001021 if (!smp_make_safe(smp))
1022 return NULL;
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001023 static_table_key.key = smp->data.u.str.area;
1024 static_table_key.key_len = smp->data.u.str.data;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001025 break;
Emeric Brun485479d2010-09-23 18:02:19 +02001026
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +02001027 case SMP_T_BIN:
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001028 if (smp->data.u.str.data < t->key_size) {
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001029 /* This type needs padding with 0. */
Willy Tarreauf65c6c02016-08-09 12:08:41 +02001030 if (!smp_make_rw(smp))
1031 return NULL;
1032
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001033 if (smp->data.u.str.size < t->key_size)
1034 if (!smp_dup(smp))
1035 return NULL;
1036 if (smp->data.u.str.size < t->key_size)
1037 return NULL;
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001038 memset(smp->data.u.str.area + smp->data.u.str.data, 0,
1039 t->key_size - smp->data.u.str.data);
1040 smp->data.u.str.data = t->key_size;
Emeric Brun485479d2010-09-23 18:02:19 +02001041 }
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001042 static_table_key.key = smp->data.u.str.area;
1043 static_table_key.key_len = smp->data.u.str.data;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001044 break;
Emeric Brun485479d2010-09-23 18:02:19 +02001045
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001046 default: /* impossible case. */
1047 return NULL;
Emeric Brun485479d2010-09-23 18:02:19 +02001048 }
1049
Christopher Fauletca20d022017-08-29 15:30:31 +02001050 return &static_table_key;
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001051}
1052
1053/*
Willy Tarreau8fed9032014-07-03 17:02:46 +02001054 * Process a fetch + format conversion as defined by the sample expression <expr>
1055 * on request or response considering the <opt> parameter. Returns either NULL if
1056 * no key could be extracted, or a pointer to the converted result stored in
1057 * static_table_key in format <table_type>. If <smp> is not NULL, it will be reset
1058 * and its flags will be initialized so that the caller gets a copy of the input
Willy Tarreau6bcb0a82014-07-30 08:56:35 +02001059 * sample, and knows why it was not accepted (eg: SMP_F_MAY_CHANGE is present
1060 * without SMP_OPT_FINAL). The output will be usable like this :
1061 *
1062 * return MAY_CHANGE FINAL Meaning for the sample
1063 * NULL 0 * Not present and will never be (eg: header)
1064 * NULL 1 0 Not present or unstable, could change (eg: req_len)
1065 * NULL 1 1 Not present, will not change anymore
1066 * smp 0 * Present and will not change (eg: header)
1067 * smp 1 0 not possible
1068 * smp 1 1 Present, last known value (eg: request length)
Willy Tarreau8fed9032014-07-03 17:02:46 +02001069 */
Willy Tarreau192252e2015-04-04 01:47:55 +02001070struct stktable_key *stktable_fetch_key(struct stktable *t, struct proxy *px, struct session *sess, struct stream *strm,
Willy Tarreau8fed9032014-07-03 17:02:46 +02001071 unsigned int opt, struct sample_expr *expr, struct sample *smp)
1072{
1073 if (smp)
1074 memset(smp, 0, sizeof(*smp));
1075
Willy Tarreau192252e2015-04-04 01:47:55 +02001076 smp = sample_process(px, sess, strm, opt, expr, smp);
Willy Tarreau8fed9032014-07-03 17:02:46 +02001077 if (!smp)
1078 return NULL;
1079
1080 if ((smp->flags & SMP_F_MAY_CHANGE) && !(opt & SMP_OPT_FINAL))
1081 return NULL; /* we can only use stable samples */
1082
1083 return smp_to_stkey(smp, t);
1084}
1085
1086/*
Willy Tarreau12785782012-04-27 21:37:17 +02001087 * Returns 1 if sample expression <expr> result can be converted to table key of
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001088 * type <table_type>, otherwise zero. Used in configuration check.
1089 */
Willy Tarreau12785782012-04-27 21:37:17 +02001090int stktable_compatible_sample(struct sample_expr *expr, unsigned long table_type)
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001091{
Thierry FOURNIERf73eb8f2013-11-27 15:30:55 +01001092 int out_type;
1093
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +02001094 if (table_type >= SMP_TYPES || !stktable_types[table_type].kw)
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001095 return 0;
1096
Thierry FOURNIERf73eb8f2013-11-27 15:30:55 +01001097 out_type = smp_expr_output_type(expr);
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001098
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001099 /* Convert sample. */
1100 if (!sample_casts[out_type][table_type])
Thierry FOURNIERf73eb8f2013-11-27 15:30:55 +01001101 return 0;
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001102
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001103 return 1;
1104}
Emeric Brun3bd697e2010-01-04 15:23:48 +01001105
Willy Tarreauedee1d62014-07-15 16:44:27 +02001106/* Extra data types processing : after the last one, some room may remain
1107 * before STKTABLE_DATA_TYPES that may be used to register extra data types
1108 * at run time.
1109 */
Willy Tarreau08d5f982010-06-06 13:34:54 +02001110struct stktable_data_type stktable_data_types[STKTABLE_DATA_TYPES] = {
Willy Tarreau3b9c6e02010-07-18 08:04:30 +02001111 [STKTABLE_DT_SERVER_ID] = { .name = "server_id", .std_type = STD_T_SINT },
Thierry FOURNIER3cf11112015-07-28 08:57:05 +02001112 [STKTABLE_DT_GPT0] = { .name = "gpt0", .std_type = STD_T_UINT },
Willy Tarreau3b9c6e02010-07-18 08:04:30 +02001113 [STKTABLE_DT_GPC0] = { .name = "gpc0", .std_type = STD_T_UINT },
Willy Tarreauba2ffd12013-05-29 15:54:14 +02001114 [STKTABLE_DT_GPC0_RATE] = { .name = "gpc0_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
Willy Tarreau3b9c6e02010-07-18 08:04:30 +02001115 [STKTABLE_DT_CONN_CNT] = { .name = "conn_cnt", .std_type = STD_T_UINT },
1116 [STKTABLE_DT_CONN_RATE] = { .name = "conn_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
1117 [STKTABLE_DT_CONN_CUR] = { .name = "conn_cur", .std_type = STD_T_UINT },
1118 [STKTABLE_DT_SESS_CNT] = { .name = "sess_cnt", .std_type = STD_T_UINT },
1119 [STKTABLE_DT_SESS_RATE] = { .name = "sess_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
1120 [STKTABLE_DT_HTTP_REQ_CNT] = { .name = "http_req_cnt", .std_type = STD_T_UINT },
1121 [STKTABLE_DT_HTTP_REQ_RATE] = { .name = "http_req_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
1122 [STKTABLE_DT_HTTP_ERR_CNT] = { .name = "http_err_cnt", .std_type = STD_T_UINT },
1123 [STKTABLE_DT_HTTP_ERR_RATE] = { .name = "http_err_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
1124 [STKTABLE_DT_BYTES_IN_CNT] = { .name = "bytes_in_cnt", .std_type = STD_T_ULL },
1125 [STKTABLE_DT_BYTES_IN_RATE] = { .name = "bytes_in_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
1126 [STKTABLE_DT_BYTES_OUT_CNT] = { .name = "bytes_out_cnt", .std_type = STD_T_ULL },
1127 [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 +01001128 [STKTABLE_DT_GPC1] = { .name = "gpc1", .std_type = STD_T_UINT },
1129 [STKTABLE_DT_GPC1_RATE] = { .name = "gpc1_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
Thayne McCombs92149f92020-11-20 01:28:26 -07001130 [STKTABLE_DT_SERVER_KEY] = { .name = "server_key", .std_type = STD_T_DICT },
Willy Tarreau826f3ab2021-02-10 12:07:15 +01001131 [STKTABLE_DT_HTTP_FAIL_CNT] = { .name = "http_fail_cnt", .std_type = STD_T_UINT },
1132 [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 +02001133};
1134
Willy Tarreauedee1d62014-07-15 16:44:27 +02001135/* Registers stick-table extra data type with index <idx>, name <name>, type
1136 * <std_type> and arg type <arg_type>. If the index is negative, the next free
1137 * index is automatically allocated. The allocated index is returned, or -1 if
1138 * no free index was found or <name> was already registered. The <name> is used
1139 * directly as a pointer, so if it's not stable, the caller must allocate it.
1140 */
1141int stktable_register_data_store(int idx, const char *name, int std_type, int arg_type)
1142{
1143 if (idx < 0) {
1144 for (idx = 0; idx < STKTABLE_DATA_TYPES; idx++) {
1145 if (!stktable_data_types[idx].name)
1146 break;
1147
1148 if (strcmp(stktable_data_types[idx].name, name) == 0)
1149 return -1;
1150 }
1151 }
1152
1153 if (idx >= STKTABLE_DATA_TYPES)
1154 return -1;
1155
1156 if (stktable_data_types[idx].name != NULL)
1157 return -1;
1158
1159 stktable_data_types[idx].name = name;
1160 stktable_data_types[idx].std_type = std_type;
1161 stktable_data_types[idx].arg_type = arg_type;
1162 return idx;
1163}
1164
Willy Tarreau08d5f982010-06-06 13:34:54 +02001165/*
1166 * Returns the data type number for the stktable_data_type whose name is <name>,
1167 * or <0 if not found.
1168 */
1169int stktable_get_data_type(char *name)
1170{
1171 int type;
1172
1173 for (type = 0; type < STKTABLE_DATA_TYPES; type++) {
Willy Tarreauedee1d62014-07-15 16:44:27 +02001174 if (!stktable_data_types[type].name)
1175 continue;
Willy Tarreau08d5f982010-06-06 13:34:54 +02001176 if (strcmp(name, stktable_data_types[type].name) == 0)
1177 return type;
1178 }
Thayne McCombs92149f92020-11-20 01:28:26 -07001179 /* For backwards compatibility */
1180 if (strcmp(name, "server_name") == 0)
1181 return STKTABLE_DT_SERVER_KEY;
Willy Tarreau08d5f982010-06-06 13:34:54 +02001182 return -1;
1183}
1184
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001185/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1186 * it up into this table. Returns true if found, false otherwise. The input
1187 * type is STR so that input samples are converted to string (since all types
1188 * can be converted to strings), then the function casts the string again into
1189 * the table's type. This is a double conversion, but in the future we might
1190 * support automatic input types to perform the cast on the fly.
1191 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001192static int sample_conv_in_table(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001193{
1194 struct stktable *t;
1195 struct stktable_key *key;
1196 struct stksess *ts;
1197
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001198 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001199
1200 key = smp_to_stkey(smp, t);
1201 if (!key)
1202 return 0;
1203
1204 ts = stktable_lookup_key(t, key);
1205
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001206 smp->data.type = SMP_T_BOOL;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001207 smp->data.u.sint = !!ts;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001208 smp->flags = SMP_F_VOL_TEST;
Willy Tarreau43e90352018-06-27 06:25:57 +02001209 stktable_release(t, ts);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001210 return 1;
1211}
1212
1213/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1214 * it up into this table. Returns the data rate received from clients in bytes/s
1215 * if the key is present in the table, otherwise zero, so that comparisons can
1216 * be easily performed. If the inspected parameter is not stored in the table,
1217 * <not found> is returned.
1218 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001219static int sample_conv_table_bytes_in_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001220{
1221 struct stktable *t;
1222 struct stktable_key *key;
1223 struct stksess *ts;
1224 void *ptr;
1225
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001226 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001227
1228 key = smp_to_stkey(smp, t);
1229 if (!key)
1230 return 0;
1231
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001232 ts = stktable_lookup_key(t, key);
1233
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001234 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001235 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001236 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001237
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001238 if (!ts) /* key not present */
1239 return 1;
1240
1241 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_IN_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001242 if (ptr)
1243 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, bytes_in_rate),
1244 t->data_arg[STKTABLE_DT_BYTES_IN_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001245
Daniel Corbett3e60b112018-05-27 09:47:12 -04001246 stktable_release(t, ts);
1247 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001248}
1249
1250/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1251 * it up into this table. Returns the cumulated number of connections for the key
1252 * if the key is present in the table, otherwise zero, so that comparisons can
1253 * be easily performed. If the inspected parameter is not stored in the table,
1254 * <not found> is returned.
1255 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001256static int sample_conv_table_conn_cnt(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001257{
1258 struct stktable *t;
1259 struct stktable_key *key;
1260 struct stksess *ts;
1261 void *ptr;
1262
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001263 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001264
1265 key = smp_to_stkey(smp, t);
1266 if (!key)
1267 return 0;
1268
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001269 ts = stktable_lookup_key(t, key);
1270
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001271 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001272 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001273 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001274
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001275 if (!ts) /* key not present */
1276 return 1;
1277
1278 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_CONN_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001279 if (ptr)
1280 smp->data.u.sint = stktable_data_cast(ptr, conn_cnt);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001281
Daniel Corbett3e60b112018-05-27 09:47:12 -04001282 stktable_release(t, ts);
1283 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001284}
1285
1286/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1287 * it up into this table. Returns the number of concurrent connections for the
1288 * key if the key is present in the table, otherwise zero, so that comparisons
1289 * can be easily performed. If the inspected parameter is not stored in the
1290 * table, <not found> is returned.
1291 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001292static int sample_conv_table_conn_cur(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001293{
1294 struct stktable *t;
1295 struct stktable_key *key;
1296 struct stksess *ts;
1297 void *ptr;
1298
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001299 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001300
1301 key = smp_to_stkey(smp, t);
1302 if (!key)
1303 return 0;
1304
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001305 ts = stktable_lookup_key(t, key);
1306
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001307 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001308 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001309 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001310
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001311 if (!ts) /* key not present */
1312 return 1;
1313
1314 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_CONN_CUR);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001315 if (ptr)
1316 smp->data.u.sint = stktable_data_cast(ptr, conn_cur);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001317
Daniel Corbett3e60b112018-05-27 09:47:12 -04001318 stktable_release(t, ts);
1319 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001320}
1321
1322/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1323 * it up into this table. Returns the rate of incoming connections from the key
1324 * if the key is present in the table, otherwise zero, so that comparisons can
1325 * be easily performed. If the inspected parameter is not stored in the table,
1326 * <not found> is returned.
1327 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001328static int sample_conv_table_conn_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001329{
1330 struct stktable *t;
1331 struct stktable_key *key;
1332 struct stksess *ts;
1333 void *ptr;
1334
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001335 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001336
1337 key = smp_to_stkey(smp, t);
1338 if (!key)
1339 return 0;
1340
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001341 ts = stktable_lookup_key(t, key);
1342
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001343 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001344 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001345 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001346
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001347 if (!ts) /* key not present */
1348 return 1;
1349
1350 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_CONN_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001351 if (ptr)
1352 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, conn_rate),
1353 t->data_arg[STKTABLE_DT_CONN_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001354
Daniel Corbett3e60b112018-05-27 09:47:12 -04001355 stktable_release(t, ts);
1356 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001357}
1358
1359/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1360 * it up into this table. Returns the data rate sent to clients in bytes/s
1361 * if the key is present in the table, otherwise zero, so that comparisons can
1362 * be easily performed. If the inspected parameter is not stored in the table,
1363 * <not found> is returned.
1364 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001365static int sample_conv_table_bytes_out_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001366{
1367 struct stktable *t;
1368 struct stktable_key *key;
1369 struct stksess *ts;
1370 void *ptr;
1371
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001372 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001373
1374 key = smp_to_stkey(smp, t);
1375 if (!key)
1376 return 0;
1377
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001378 ts = stktable_lookup_key(t, key);
1379
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001380 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001381 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001382 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001383
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001384 if (!ts) /* key not present */
1385 return 1;
1386
1387 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_OUT_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001388 if (ptr)
1389 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, bytes_out_rate),
1390 t->data_arg[STKTABLE_DT_BYTES_OUT_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001391
Daniel Corbett3e60b112018-05-27 09:47:12 -04001392 stktable_release(t, ts);
1393 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001394}
1395
1396/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001397 * it up into this table. Returns the value of the GPT0 tag for the key
1398 * if the key is present in the table, otherwise false, so that comparisons can
1399 * be easily performed. If the inspected parameter is not stored in the table,
1400 * <not found> is returned.
1401 */
1402static int sample_conv_table_gpt0(const struct arg *arg_p, struct sample *smp, void *private)
1403{
1404 struct stktable *t;
1405 struct stktable_key *key;
1406 struct stksess *ts;
1407 void *ptr;
1408
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001409 t = arg_p[0].data.t;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001410
1411 key = smp_to_stkey(smp, t);
1412 if (!key)
1413 return 0;
1414
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001415 ts = stktable_lookup_key(t, key);
1416
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001417 smp->flags = SMP_F_VOL_TEST;
1418 smp->data.type = SMP_T_SINT;
1419 smp->data.u.sint = 0;
1420
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001421 if (!ts) /* key not present */
1422 return 1;
1423
1424 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPT0);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001425 if (ptr)
1426 smp->data.u.sint = stktable_data_cast(ptr, gpt0);
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001427
Daniel Corbett3e60b112018-05-27 09:47:12 -04001428 stktable_release(t, ts);
1429 return !!ptr;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001430}
1431
1432/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001433 * it up into this table. Returns the value of the GPC0 counter for the key
1434 * if the key is present in the table, otherwise zero, so that comparisons can
1435 * be easily performed. If the inspected parameter is not stored in the table,
1436 * <not found> is returned.
1437 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001438static int sample_conv_table_gpc0(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001439{
1440 struct stktable *t;
1441 struct stktable_key *key;
1442 struct stksess *ts;
1443 void *ptr;
1444
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001445 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001446
1447 key = smp_to_stkey(smp, t);
1448 if (!key)
1449 return 0;
1450
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001451 ts = stktable_lookup_key(t, key);
1452
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001453 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001454 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001455 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001456
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001457 if (!ts) /* key not present */
1458 return 1;
1459
1460 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPC0);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001461 if (ptr)
1462 smp->data.u.sint = stktable_data_cast(ptr, gpc0);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001463
Daniel Corbett3e60b112018-05-27 09:47:12 -04001464 stktable_release(t, ts);
1465 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001466}
1467
1468/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1469 * it up into this table. Returns the event rate of the GPC0 counter for the key
1470 * if the key is present in the table, otherwise zero, so that comparisons can
1471 * be easily performed. If the inspected parameter is not stored in the table,
1472 * <not found> is returned.
1473 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001474static int sample_conv_table_gpc0_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001475{
1476 struct stktable *t;
1477 struct stktable_key *key;
1478 struct stksess *ts;
1479 void *ptr;
1480
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001481 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001482
1483 key = smp_to_stkey(smp, t);
1484 if (!key)
1485 return 0;
1486
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001487 ts = stktable_lookup_key(t, key);
1488
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001489 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001490 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001491 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001492
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001493 if (!ts) /* key not present */
1494 return 1;
1495
1496 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPC0_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001497 if (ptr)
1498 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, gpc0_rate),
1499 t->data_arg[STKTABLE_DT_GPC0_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001500
Daniel Corbett3e60b112018-05-27 09:47:12 -04001501 stktable_release(t, ts);
1502 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001503}
1504
1505/* 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 +01001506 * it up into this table. Returns the value of the GPC1 counter for the key
1507 * if the key is present in the table, otherwise zero, so that comparisons can
1508 * be easily performed. If the inspected parameter is not stored in the table,
1509 * <not found> is returned.
1510 */
1511static int sample_conv_table_gpc1(const struct arg *arg_p, struct sample *smp, void *private)
1512{
1513 struct stktable *t;
1514 struct stktable_key *key;
1515 struct stksess *ts;
1516 void *ptr;
1517
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001518 t = arg_p[0].data.t;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001519
1520 key = smp_to_stkey(smp, t);
1521 if (!key)
1522 return 0;
1523
1524 ts = stktable_lookup_key(t, key);
1525
1526 smp->flags = SMP_F_VOL_TEST;
1527 smp->data.type = SMP_T_SINT;
1528 smp->data.u.sint = 0;
1529
1530 if (!ts) /* key not present */
1531 return 1;
1532
1533 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPC1);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001534 if (ptr)
1535 smp->data.u.sint = stktable_data_cast(ptr, gpc1);
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001536
Daniel Corbett3e60b112018-05-27 09:47:12 -04001537 stktable_release(t, ts);
1538 return !!ptr;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001539}
1540
1541/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1542 * it up into this table. Returns the event rate of the GPC1 counter for the key
1543 * if the key is present in the table, otherwise zero, so that comparisons can
1544 * be easily performed. If the inspected parameter is not stored in the table,
1545 * <not found> is returned.
1546 */
1547static int sample_conv_table_gpc1_rate(const struct arg *arg_p, struct sample *smp, void *private)
1548{
1549 struct stktable *t;
1550 struct stktable_key *key;
1551 struct stksess *ts;
1552 void *ptr;
1553
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001554 t = arg_p[0].data.t;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001555
1556 key = smp_to_stkey(smp, t);
1557 if (!key)
1558 return 0;
1559
1560 ts = stktable_lookup_key(t, key);
1561
1562 smp->flags = SMP_F_VOL_TEST;
1563 smp->data.type = SMP_T_SINT;
1564 smp->data.u.sint = 0;
1565
1566 if (!ts) /* key not present */
1567 return 1;
1568
1569 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPC1_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001570 if (ptr)
1571 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, gpc1_rate),
1572 t->data_arg[STKTABLE_DT_GPC1_RATE].u);
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001573
Daniel Corbett3e60b112018-05-27 09:47:12 -04001574 stktable_release(t, ts);
1575 return !!ptr;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001576}
1577
1578/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001579 * it up into this table. Returns the cumulated number of HTTP request errors
1580 * for the key if the key is present in the table, otherwise zero, so that
1581 * comparisons can be easily performed. If the inspected parameter is not stored
1582 * in the table, <not found> is returned.
1583 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001584static int sample_conv_table_http_err_cnt(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001585{
1586 struct stktable *t;
1587 struct stktable_key *key;
1588 struct stksess *ts;
1589 void *ptr;
1590
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001591 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001592
1593 key = smp_to_stkey(smp, t);
1594 if (!key)
1595 return 0;
1596
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001597 ts = stktable_lookup_key(t, key);
1598
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001599 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001600 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001601 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001602
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001603 if (!ts) /* key not present */
1604 return 1;
1605
1606 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_ERR_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001607 if (ptr)
1608 smp->data.u.sint = stktable_data_cast(ptr, http_err_cnt);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001609
Daniel Corbett3e60b112018-05-27 09:47:12 -04001610 stktable_release(t, ts);
1611 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001612}
1613
1614/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1615 * it up into this table. Returns the HTTP request error rate the key
1616 * if the key is present in the table, otherwise zero, so that comparisons can
1617 * be easily performed. If the inspected parameter is not stored in the table,
1618 * <not found> is returned.
1619 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001620static int sample_conv_table_http_err_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001621{
1622 struct stktable *t;
1623 struct stktable_key *key;
1624 struct stksess *ts;
1625 void *ptr;
1626
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001627 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001628
1629 key = smp_to_stkey(smp, t);
1630 if (!key)
1631 return 0;
1632
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001633 ts = stktable_lookup_key(t, key);
1634
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001635 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001636 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001637 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001638
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001639 if (!ts) /* key not present */
1640 return 1;
1641
1642 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_ERR_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001643 if (ptr)
1644 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, http_err_rate),
1645 t->data_arg[STKTABLE_DT_HTTP_ERR_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001646
Daniel Corbett3e60b112018-05-27 09:47:12 -04001647 stktable_release(t, ts);
1648 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001649}
1650
1651/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Willy Tarreau826f3ab2021-02-10 12:07:15 +01001652 * it up into this table. Returns the cumulated number of HTTP response failures
1653 * for the key if the key is present in the table, otherwise zero, so that
1654 * comparisons can be easily performed. If the inspected parameter is not stored
1655 * in the table, <not found> is returned.
1656 */
1657static int sample_conv_table_http_fail_cnt(const struct arg *arg_p, struct sample *smp, void *private)
1658{
1659 struct stktable *t;
1660 struct stktable_key *key;
1661 struct stksess *ts;
1662 void *ptr;
1663
1664 t = arg_p[0].data.t;
1665
1666 key = smp_to_stkey(smp, t);
1667 if (!key)
1668 return 0;
1669
1670 ts = stktable_lookup_key(t, key);
1671
1672 smp->flags = SMP_F_VOL_TEST;
1673 smp->data.type = SMP_T_SINT;
1674 smp->data.u.sint = 0;
1675
1676 if (!ts) /* key not present */
1677 return 1;
1678
1679 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_FAIL_CNT);
1680 if (ptr)
1681 smp->data.u.sint = stktable_data_cast(ptr, http_fail_cnt);
1682
1683 stktable_release(t, ts);
1684 return !!ptr;
1685}
1686
1687/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1688 * it up into this table. Returns the HTTP response failure rate for the key
1689 * if the key is present in the table, otherwise zero, so that comparisons can
1690 * be easily performed. If the inspected parameter is not stored in the table,
1691 * <not found> is returned.
1692 */
1693static int sample_conv_table_http_fail_rate(const struct arg *arg_p, struct sample *smp, void *private)
1694{
1695 struct stktable *t;
1696 struct stktable_key *key;
1697 struct stksess *ts;
1698 void *ptr;
1699
1700 t = arg_p[0].data.t;
1701
1702 key = smp_to_stkey(smp, t);
1703 if (!key)
1704 return 0;
1705
1706 ts = stktable_lookup_key(t, key);
1707
1708 smp->flags = SMP_F_VOL_TEST;
1709 smp->data.type = SMP_T_SINT;
1710 smp->data.u.sint = 0;
1711
1712 if (!ts) /* key not present */
1713 return 1;
1714
1715 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_FAIL_RATE);
1716 if (ptr)
1717 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, http_fail_rate),
1718 t->data_arg[STKTABLE_DT_HTTP_FAIL_RATE].u);
1719
1720 stktable_release(t, ts);
1721 return !!ptr;
1722}
1723
1724/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001725 * it up into this table. Returns the cumulated number of HTTP request for the
1726 * key if the key is present in the table, otherwise zero, so that comparisons
1727 * can be easily performed. If the inspected parameter is not stored in the
1728 * table, <not found> is returned.
1729 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001730static int sample_conv_table_http_req_cnt(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001731{
1732 struct stktable *t;
1733 struct stktable_key *key;
1734 struct stksess *ts;
1735 void *ptr;
1736
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001737 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001738
1739 key = smp_to_stkey(smp, t);
1740 if (!key)
1741 return 0;
1742
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001743 ts = stktable_lookup_key(t, key);
1744
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001745 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001746 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001747 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001748
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001749 if (!ts) /* key not present */
1750 return 1;
1751
1752 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_REQ_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001753 if (ptr)
1754 smp->data.u.sint = stktable_data_cast(ptr, http_req_cnt);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001755
Daniel Corbett3e60b112018-05-27 09:47:12 -04001756 stktable_release(t, ts);
1757 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001758}
1759
1760/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1761 * it up into this table. Returns the HTTP request rate the key if the key is
1762 * present in the table, otherwise zero, so that comparisons can be easily
1763 * performed. If the inspected parameter is not stored in the table, <not found>
1764 * is returned.
1765 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001766static int sample_conv_table_http_req_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001767{
1768 struct stktable *t;
1769 struct stktable_key *key;
1770 struct stksess *ts;
1771 void *ptr;
1772
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001773 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001774
1775 key = smp_to_stkey(smp, t);
1776 if (!key)
1777 return 0;
1778
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001779 ts = stktable_lookup_key(t, key);
1780
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001781 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001782 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001783 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001784
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001785 if (!ts) /* key not present */
1786 return 1;
1787
1788 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_REQ_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001789 if (ptr)
1790 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, http_req_rate),
1791 t->data_arg[STKTABLE_DT_HTTP_REQ_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001792
Daniel Corbett3e60b112018-05-27 09:47:12 -04001793 stktable_release(t, ts);
1794 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001795}
1796
1797/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1798 * it up into this table. Returns the volume of datareceived from clients in kbytes
1799 * if the key is present in the table, otherwise zero, so that comparisons can
1800 * be easily performed. If the inspected parameter is not stored in the table,
1801 * <not found> is returned.
1802 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001803static int sample_conv_table_kbytes_in(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001804{
1805 struct stktable *t;
1806 struct stktable_key *key;
1807 struct stksess *ts;
1808 void *ptr;
1809
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001810 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001811
1812 key = smp_to_stkey(smp, t);
1813 if (!key)
1814 return 0;
1815
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001816 ts = stktable_lookup_key(t, key);
1817
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001818 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001819 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001820 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001821
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001822 if (!ts) /* key not present */
1823 return 1;
1824
1825 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_IN_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001826 if (ptr)
1827 smp->data.u.sint = stktable_data_cast(ptr, bytes_in_cnt) >> 10;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001828
Daniel Corbett3e60b112018-05-27 09:47:12 -04001829 stktable_release(t, ts);
1830 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001831}
1832
1833/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1834 * it up into this table. Returns the volume of data sent to clients in kbytes
1835 * if the key is present in the table, otherwise zero, so that comparisons can
1836 * be easily performed. If the inspected parameter is not stored in the table,
1837 * <not found> is returned.
1838 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001839static int sample_conv_table_kbytes_out(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001840{
1841 struct stktable *t;
1842 struct stktable_key *key;
1843 struct stksess *ts;
1844 void *ptr;
1845
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001846 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001847
1848 key = smp_to_stkey(smp, t);
1849 if (!key)
1850 return 0;
1851
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001852 ts = stktable_lookup_key(t, key);
1853
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001854 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001855 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001856 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001857
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001858 if (!ts) /* key not present */
1859 return 1;
1860
1861 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_OUT_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001862 if (ptr)
1863 smp->data.u.sint = stktable_data_cast(ptr, bytes_out_cnt) >> 10;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001864
Daniel Corbett3e60b112018-05-27 09:47:12 -04001865 stktable_release(t, ts);
1866 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001867}
1868
1869/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1870 * it up into this table. Returns the server ID associated with the key if the
1871 * key is present in the table, otherwise zero, so that comparisons can be
1872 * easily performed. If the inspected parameter is not stored in the table,
1873 * <not found> is returned.
1874 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001875static int sample_conv_table_server_id(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001876{
1877 struct stktable *t;
1878 struct stktable_key *key;
1879 struct stksess *ts;
1880 void *ptr;
1881
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001882 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001883
1884 key = smp_to_stkey(smp, t);
1885 if (!key)
1886 return 0;
1887
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001888 ts = stktable_lookup_key(t, key);
1889
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001890 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001891 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001892 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001893
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001894 if (!ts) /* key not present */
1895 return 1;
1896
1897 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_SERVER_ID);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001898 if (ptr)
1899 smp->data.u.sint = stktable_data_cast(ptr, server_id);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001900
Daniel Corbett3e60b112018-05-27 09:47:12 -04001901 stktable_release(t, ts);
1902 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001903}
1904
1905/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1906 * it up into this table. Returns the cumulated number of sessions for the
1907 * key if the key is present in the table, otherwise zero, so that comparisons
1908 * can be easily performed. If the inspected parameter is not stored in the
1909 * table, <not found> is returned.
1910 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001911static int sample_conv_table_sess_cnt(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001912{
1913 struct stktable *t;
1914 struct stktable_key *key;
1915 struct stksess *ts;
1916 void *ptr;
1917
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001918 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001919
1920 key = smp_to_stkey(smp, t);
1921 if (!key)
1922 return 0;
1923
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001924 ts = stktable_lookup_key(t, key);
1925
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001926 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001927 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001928 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001929
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001930 if (!ts) /* key not present */
1931 return 1;
1932
1933 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_SESS_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001934 if (ptr)
1935 smp->data.u.sint = stktable_data_cast(ptr, sess_cnt);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001936
Daniel Corbett3e60b112018-05-27 09:47:12 -04001937 stktable_release(t, ts);
1938 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001939}
1940
1941/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1942 * it up into this table. Returns the session rate the key if the key is
1943 * present in the table, otherwise zero, so that comparisons can be easily
1944 * performed. If the inspected parameter is not stored in the table, <not found>
1945 * is returned.
1946 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001947static int sample_conv_table_sess_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001948{
1949 struct stktable *t;
1950 struct stktable_key *key;
1951 struct stksess *ts;
1952 void *ptr;
1953
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001954 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001955
1956 key = smp_to_stkey(smp, t);
1957 if (!key)
1958 return 0;
1959
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001960 ts = stktable_lookup_key(t, key);
1961
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001962 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001963 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001964 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001965
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001966 if (!ts) /* key not present */
1967 return 1;
1968
1969 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_SESS_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001970 if (ptr)
1971 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, sess_rate),
1972 t->data_arg[STKTABLE_DT_SESS_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001973
Daniel Corbett3e60b112018-05-27 09:47:12 -04001974 stktable_release(t, ts);
1975 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001976}
1977
1978/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1979 * it up into this table. Returns the amount of concurrent connections tracking
1980 * the same key if the key is present in the table, otherwise zero, so that
1981 * comparisons can be easily performed. If the inspected parameter is not
1982 * stored in the table, <not found> is returned.
1983 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001984static int sample_conv_table_trackers(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001985{
1986 struct stktable *t;
1987 struct stktable_key *key;
1988 struct stksess *ts;
1989
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001990 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001991
1992 key = smp_to_stkey(smp, t);
1993 if (!key)
1994 return 0;
1995
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001996 ts = stktable_lookup_key(t, key);
1997
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001998 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001999 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02002000 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002001
Tim Duesterhus65189c12018-06-26 15:57:29 +02002002 if (!ts)
2003 return 1;
2004
2005 smp->data.u.sint = ts->ref_cnt;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002006
Daniel Corbett3e60b112018-05-27 09:47:12 -04002007 stktable_release(t, ts);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002008 return 1;
2009}
2010
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002011/* Always returns 1. */
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002012static enum act_return action_inc_gpc0(struct act_rule *rule, struct proxy *px,
Willy Tarreau658b85b2015-09-27 10:00:49 +02002013 struct session *sess, struct stream *s, int flags)
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002014{
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002015 struct stksess *ts;
2016 struct stkctr *stkctr;
2017
2018 /* Extract the stksess, return OK if no stksess available. */
2019 if (s)
2020 stkctr = &s->stkctr[rule->arg.gpc.sc];
2021 else
2022 stkctr = &sess->stkctr[rule->arg.gpc.sc];
Willy Tarreau79c1e912016-01-25 14:54:45 +01002023
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002024 ts = stkctr_entry(stkctr);
Willy Tarreau79c1e912016-01-25 14:54:45 +01002025 if (ts) {
2026 void *ptr1, *ptr2;
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002027
Willy Tarreau79c1e912016-01-25 14:54:45 +01002028 /* First, update gpc0_rate if it's tracked. Second, update its gpc0 if tracked. */
2029 ptr1 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC0_RATE);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002030 ptr2 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC0);
2031 if (ptr1 || ptr2) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002032 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002033
2034 if (ptr1)
2035 update_freq_ctr_period(&stktable_data_cast(ptr1, gpc0_rate),
Willy Tarreau79c1e912016-01-25 14:54:45 +01002036 stkctr->table->data_arg[STKTABLE_DT_GPC0_RATE].u, 1);
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002037
Emeric Brun819fc6f2017-06-13 19:37:32 +02002038 if (ptr2)
2039 stktable_data_cast(ptr2, gpc0)++;
Willy Tarreau79c1e912016-01-25 14:54:45 +01002040
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002041 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002042
2043 /* If data was modified, we need to touch to re-schedule sync */
2044 stktable_touch_local(stkctr->table, ts, 0);
2045 }
Willy Tarreau79c1e912016-01-25 14:54:45 +01002046 }
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002047 return ACT_RET_CONT;
2048}
2049
2050/* This function is a common parser for using variables. It understands
2051 * the formats:
2052 *
2053 * sc-inc-gpc0(<stick-table ID>)
2054 *
2055 * It returns 0 if fails and <err> is filled with an error message. Otherwise,
2056 * it returns 1 and the variable <expr> is filled with the pointer to the
2057 * expression to execute.
2058 */
2059static enum act_parse_ret parse_inc_gpc0(const char **args, int *arg, struct proxy *px,
2060 struct act_rule *rule, char **err)
2061{
2062 const char *cmd_name = args[*arg-1];
2063 char *error;
2064
2065 cmd_name += strlen("sc-inc-gpc0");
2066 if (*cmd_name == '\0') {
2067 /* default stick table id. */
2068 rule->arg.gpc.sc = 0;
2069 } else {
2070 /* parse the stick table id. */
2071 if (*cmd_name != '(') {
2072 memprintf(err, "invalid stick table track ID. Expects %s(<Track ID>)", args[*arg-1]);
2073 return ACT_RET_PRS_ERR;
2074 }
2075 cmd_name++; /* jump the '(' */
2076 rule->arg.gpc.sc = strtol(cmd_name, &error, 10); /* Convert stick table id. */
2077 if (*error != ')') {
2078 memprintf(err, "invalid stick table track ID. Expects %s(<Track ID>)", args[*arg-1]);
2079 return ACT_RET_PRS_ERR;
2080 }
2081
Christopher Faulet28436e22019-12-18 10:25:46 +01002082 if (rule->arg.gpc.sc >= MAX_SESS_STKCTR) {
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002083 memprintf(err, "invalid stick table track ID. The max allowed ID is %d",
Christopher Faulet28436e22019-12-18 10:25:46 +01002084 MAX_SESS_STKCTR-1);
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002085 return ACT_RET_PRS_ERR;
2086 }
2087 }
Thierry FOURNIER42148732015-09-02 17:17:33 +02002088 rule->action = ACT_CUSTOM;
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002089 rule->action_ptr = action_inc_gpc0;
2090 return ACT_RET_PRS_OK;
2091}
2092
2093/* Always returns 1. */
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002094static enum act_return action_inc_gpc1(struct act_rule *rule, struct proxy *px,
2095 struct session *sess, struct stream *s, int flags)
2096{
2097 struct stksess *ts;
2098 struct stkctr *stkctr;
2099
2100 /* Extract the stksess, return OK if no stksess available. */
2101 if (s)
2102 stkctr = &s->stkctr[rule->arg.gpc.sc];
2103 else
2104 stkctr = &sess->stkctr[rule->arg.gpc.sc];
2105
2106 ts = stkctr_entry(stkctr);
2107 if (ts) {
2108 void *ptr1, *ptr2;
2109
2110 /* First, update gpc1_rate if it's tracked. Second, update its gpc1 if tracked. */
2111 ptr1 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC1_RATE);
2112 ptr2 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC1);
2113 if (ptr1 || ptr2) {
2114 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
2115
2116 if (ptr1)
2117 update_freq_ctr_period(&stktable_data_cast(ptr1, gpc1_rate),
2118 stkctr->table->data_arg[STKTABLE_DT_GPC1_RATE].u, 1);
2119
2120 if (ptr2)
2121 stktable_data_cast(ptr2, gpc1)++;
2122
2123 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
2124
2125 /* If data was modified, we need to touch to re-schedule sync */
2126 stktable_touch_local(stkctr->table, ts, 0);
2127 }
2128 }
2129 return ACT_RET_CONT;
2130}
2131
2132/* This function is a common parser for using variables. It understands
2133 * the formats:
2134 *
2135 * sc-inc-gpc1(<stick-table ID>)
2136 *
2137 * It returns 0 if fails and <err> is filled with an error message. Otherwise,
2138 * it returns 1 and the variable <expr> is filled with the pointer to the
2139 * expression to execute.
2140 */
2141static enum act_parse_ret parse_inc_gpc1(const char **args, int *arg, struct proxy *px,
2142 struct act_rule *rule, char **err)
2143{
2144 const char *cmd_name = args[*arg-1];
2145 char *error;
2146
2147 cmd_name += strlen("sc-inc-gpc1");
2148 if (*cmd_name == '\0') {
2149 /* default stick table id. */
2150 rule->arg.gpc.sc = 0;
2151 } else {
2152 /* parse the stick table id. */
2153 if (*cmd_name != '(') {
2154 memprintf(err, "invalid stick table track ID. Expects %s(<Track ID>)", args[*arg-1]);
2155 return ACT_RET_PRS_ERR;
2156 }
2157 cmd_name++; /* jump the '(' */
2158 rule->arg.gpc.sc = strtol(cmd_name, &error, 10); /* Convert stick table id. */
2159 if (*error != ')') {
2160 memprintf(err, "invalid stick table track ID. Expects %s(<Track ID>)", args[*arg-1]);
2161 return ACT_RET_PRS_ERR;
2162 }
2163
Christopher Faulet28436e22019-12-18 10:25:46 +01002164 if (rule->arg.gpc.sc >= MAX_SESS_STKCTR) {
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002165 memprintf(err, "invalid stick table track ID. The max allowed ID is %d",
Christopher Faulet28436e22019-12-18 10:25:46 +01002166 MAX_SESS_STKCTR-1);
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002167 return ACT_RET_PRS_ERR;
2168 }
2169 }
2170 rule->action = ACT_CUSTOM;
2171 rule->action_ptr = action_inc_gpc1;
2172 return ACT_RET_PRS_OK;
2173}
2174
2175/* Always returns 1. */
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002176static enum act_return action_set_gpt0(struct act_rule *rule, struct proxy *px,
Willy Tarreau658b85b2015-09-27 10:00:49 +02002177 struct session *sess, struct stream *s, int flags)
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002178{
2179 void *ptr;
2180 struct stksess *ts;
2181 struct stkctr *stkctr;
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002182 unsigned int value = 0;
2183 struct sample *smp;
2184 int smp_opt_dir;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002185
2186 /* Extract the stksess, return OK if no stksess available. */
2187 if (s)
2188 stkctr = &s->stkctr[rule->arg.gpt.sc];
2189 else
2190 stkctr = &sess->stkctr[rule->arg.gpt.sc];
Willy Tarreau79c1e912016-01-25 14:54:45 +01002191
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002192 ts = stkctr_entry(stkctr);
2193 if (!ts)
2194 return ACT_RET_CONT;
2195
2196 /* Store the sample in the required sc, and ignore errors. */
2197 ptr = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPT0);
Willy Tarreau79c1e912016-01-25 14:54:45 +01002198 if (ptr) {
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002199 if (!rule->arg.gpt.expr)
2200 value = (unsigned int)(rule->arg.gpt.value);
2201 else {
2202 switch (rule->from) {
2203 case ACT_F_TCP_REQ_SES: smp_opt_dir = SMP_OPT_DIR_REQ; break;
2204 case ACT_F_TCP_REQ_CNT: smp_opt_dir = SMP_OPT_DIR_REQ; break;
2205 case ACT_F_TCP_RES_CNT: smp_opt_dir = SMP_OPT_DIR_RES; break;
2206 case ACT_F_HTTP_REQ: smp_opt_dir = SMP_OPT_DIR_REQ; break;
2207 case ACT_F_HTTP_RES: smp_opt_dir = SMP_OPT_DIR_RES; break;
2208 default:
2209 send_log(px, LOG_ERR, "stick table: internal error while setting gpt0.");
2210 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))
2211 ha_alert("stick table: internal error while executing setting gpt0.\n");
2212 return ACT_RET_CONT;
2213 }
2214
2215 /* Fetch and cast the expression. */
2216 smp = sample_fetch_as_type(px, sess, s, smp_opt_dir|SMP_OPT_FINAL, rule->arg.gpt.expr, SMP_T_SINT);
2217 if (!smp) {
2218 send_log(px, LOG_WARNING, "stick table: invalid expression or data type while setting gpt0.");
2219 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))
2220 ha_alert("stick table: invalid expression or data type while setting gpt0.\n");
2221 return ACT_RET_CONT;
2222 }
2223 value = (unsigned int)(smp->data.u.sint);
2224 }
2225
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002226 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002227
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002228 stktable_data_cast(ptr, gpt0) = value;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002229
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002230 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002231
2232 stktable_touch_local(stkctr->table, ts, 0);
Willy Tarreau79c1e912016-01-25 14:54:45 +01002233 }
2234
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002235 return ACT_RET_CONT;
2236}
2237
2238/* This function is a common parser for using variables. It understands
2239 * the format:
2240 *
2241 * set-gpt0(<stick-table ID>) <expression>
2242 *
2243 * It returns 0 if fails and <err> is filled with an error message. Otherwise,
2244 * it returns 1 and the variable <expr> is filled with the pointer to the
2245 * expression to execute.
2246 */
2247static enum act_parse_ret parse_set_gpt0(const char **args, int *arg, struct proxy *px,
2248 struct act_rule *rule, char **err)
2249
2250
2251{
2252 const char *cmd_name = args[*arg-1];
2253 char *error;
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002254 int smp_val;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002255
2256 cmd_name += strlen("sc-set-gpt0");
2257 if (*cmd_name == '\0') {
2258 /* default stick table id. */
2259 rule->arg.gpt.sc = 0;
2260 } else {
2261 /* parse the stick table id. */
2262 if (*cmd_name != '(') {
2263 memprintf(err, "invalid stick table track ID '%s'. Expects sc-set-gpt0(<Track ID>)", args[*arg-1]);
2264 return ACT_RET_PRS_ERR;
2265 }
2266 cmd_name++; /* jump the '(' */
2267 rule->arg.gpt.sc = strtol(cmd_name, &error, 10); /* Convert stick table id. */
2268 if (*error != ')') {
2269 memprintf(err, "invalid stick table track ID '%s'. Expects sc-set-gpt0(<Track ID>)", args[*arg-1]);
2270 return ACT_RET_PRS_ERR;
2271 }
2272
Christopher Faulet28436e22019-12-18 10:25:46 +01002273 if (rule->arg.gpt.sc >= MAX_SESS_STKCTR) {
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002274 memprintf(err, "invalid stick table track ID '%s'. The max allowed ID is %d",
Christopher Faulet28436e22019-12-18 10:25:46 +01002275 args[*arg-1], MAX_SESS_STKCTR-1);
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002276 return ACT_RET_PRS_ERR;
2277 }
2278 }
2279
Willy Tarreauf1e1c912021-08-24 14:57:28 +02002280 /* value may be either an integer or an expression */
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002281 rule->arg.gpt.expr = NULL;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002282 rule->arg.gpt.value = strtol(args[*arg], &error, 10);
Willy Tarreauf1e1c912021-08-24 14:57:28 +02002283 if (*error == '\0') {
2284 /* valid integer, skip it */
2285 (*arg)++;
2286 } else {
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002287 rule->arg.gpt.expr = sample_parse_expr((char **)args, arg, px->conf.args.file,
Willy Tarreaue3b57bf2020-02-14 16:50:14 +01002288 px->conf.args.line, err, &px->conf.args, NULL);
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002289 if (!rule->arg.gpt.expr)
2290 return ACT_RET_PRS_ERR;
2291
2292 switch (rule->from) {
2293 case ACT_F_TCP_REQ_SES: smp_val = SMP_VAL_FE_SES_ACC; break;
2294 case ACT_F_TCP_REQ_CNT: smp_val = SMP_VAL_FE_REQ_CNT; break;
2295 case ACT_F_TCP_RES_CNT: smp_val = SMP_VAL_BE_RES_CNT; break;
2296 case ACT_F_HTTP_REQ: smp_val = SMP_VAL_FE_HRQ_HDR; break;
2297 case ACT_F_HTTP_RES: smp_val = SMP_VAL_BE_HRS_HDR; break;
2298 default:
2299 memprintf(err, "internal error, unexpected rule->from=%d, please report this bug!", rule->from);
2300 return ACT_RET_PRS_ERR;
2301 }
2302 if (!(rule->arg.gpt.expr->fetch->val & smp_val)) {
2303 memprintf(err, "fetch method '%s' extracts information from '%s', none of which is available here", args[*arg-1],
2304 sample_src_names(rule->arg.gpt.expr->fetch->use));
2305 free(rule->arg.gpt.expr);
2306 return ACT_RET_PRS_ERR;
2307 }
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002308 }
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002309
Thierry FOURNIER42148732015-09-02 17:17:33 +02002310 rule->action = ACT_CUSTOM;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002311 rule->action_ptr = action_set_gpt0;
2312
2313 return ACT_RET_PRS_OK;
2314}
2315
Willy Tarreau7d562212016-11-25 16:10:05 +01002316/* set temp integer to the number of used entries in the table pointed to by expr.
2317 * Accepts exactly 1 argument of type table.
2318 */
2319static int
2320smp_fetch_table_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
2321{
2322 smp->flags = SMP_F_VOL_TEST;
2323 smp->data.type = SMP_T_SINT;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002324 smp->data.u.sint = args->data.t->current;
Willy Tarreau7d562212016-11-25 16:10:05 +01002325 return 1;
2326}
2327
2328/* set temp integer to the number of free entries in the table pointed to by expr.
2329 * Accepts exactly 1 argument of type table.
2330 */
2331static int
2332smp_fetch_table_avl(const struct arg *args, struct sample *smp, const char *kw, void *private)
2333{
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002334 struct stktable *t;
Willy Tarreau7d562212016-11-25 16:10:05 +01002335
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002336 t = args->data.t;
Willy Tarreau7d562212016-11-25 16:10:05 +01002337 smp->flags = SMP_F_VOL_TEST;
2338 smp->data.type = SMP_T_SINT;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002339 smp->data.u.sint = t->size - t->current;
Willy Tarreau7d562212016-11-25 16:10:05 +01002340 return 1;
2341}
2342
2343/* Returns a pointer to a stkctr depending on the fetch keyword name.
2344 * It is designed to be called as sc[0-9]_* sc_* or src_* exclusively.
2345 * sc[0-9]_* will return a pointer to the respective field in the
2346 * stream <l4>. sc_* requires an UINT argument specifying the stick
2347 * counter number. src_* will fill a locally allocated structure with
2348 * the table and entry corresponding to what is specified with src_*.
2349 * NULL may be returned if the designated stkctr is not tracked. For
2350 * the sc_* and sc[0-9]_* forms, an optional table argument may be
2351 * passed. When present, the currently tracked key is then looked up
2352 * in the specified table instead of the current table. The purpose is
Ilya Shipitsin47d17182020-06-21 21:42:57 +05002353 * to be able to convert multiple values per key (eg: have gpc0 from
Willy Tarreau7d562212016-11-25 16:10:05 +01002354 * multiple tables). <strm> is allowed to be NULL, in which case only
2355 * the session will be consulted.
2356 */
2357struct stkctr *
Emeric Brun819fc6f2017-06-13 19:37:32 +02002358smp_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 +01002359{
Willy Tarreau7d562212016-11-25 16:10:05 +01002360 struct stkctr *stkptr;
2361 struct stksess *stksess;
2362 unsigned int num = kw[2] - '0';
2363 int arg = 0;
2364
2365 if (num == '_' - '0') {
2366 /* sc_* variant, args[0] = ctr# (mandatory) */
2367 num = args[arg++].data.sint;
Willy Tarreau7d562212016-11-25 16:10:05 +01002368 }
2369 else if (num > 9) { /* src_* variant, args[0] = table */
2370 struct stktable_key *key;
2371 struct connection *conn = objt_conn(sess->origin);
2372 struct sample smp;
2373
2374 if (!conn)
2375 return NULL;
2376
Joseph Herlant5662fa42018-11-15 13:43:28 -08002377 /* Fetch source address in a sample. */
Willy Tarreau7d562212016-11-25 16:10:05 +01002378 smp.px = NULL;
2379 smp.sess = sess;
2380 smp.strm = strm;
Amaury Denoyellec460c702021-05-12 10:17:47 +02002381 if (!smp_fetch_src || !smp_fetch_src(empty_arg_list, &smp, "src", NULL))
Willy Tarreau7d562212016-11-25 16:10:05 +01002382 return NULL;
2383
2384 /* Converts into key. */
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002385 key = smp_to_stkey(&smp, args->data.t);
Willy Tarreau7d562212016-11-25 16:10:05 +01002386 if (!key)
2387 return NULL;
2388
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002389 stkctr->table = args->data.t;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002390 stkctr_set_entry(stkctr, stktable_lookup_key(stkctr->table, key));
2391 return stkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002392 }
2393
2394 /* Here, <num> contains the counter number from 0 to 9 for
2395 * the sc[0-9]_ form, or even higher using sc_(num) if needed.
2396 * args[arg] is the first optional argument. We first lookup the
2397 * ctr form the stream, then from the session if it was not there.
Christopher Fauleta9fa88a2019-10-21 10:53:34 +02002398 * But we must be sure the counter does not exceed MAX_SESS_STKCTR.
Willy Tarreau7d562212016-11-25 16:10:05 +01002399 */
Christopher Fauleta9fa88a2019-10-21 10:53:34 +02002400 if (num >= MAX_SESS_STKCTR)
2401 return NULL;
Willy Tarreau7d562212016-11-25 16:10:05 +01002402
2403 if (strm)
2404 stkptr = &strm->stkctr[num];
2405 if (!strm || !stkctr_entry(stkptr)) {
2406 stkptr = &sess->stkctr[num];
2407 if (!stkctr_entry(stkptr))
2408 return NULL;
2409 }
2410
2411 stksess = stkctr_entry(stkptr);
2412 if (!stksess)
2413 return NULL;
2414
2415 if (unlikely(args[arg].type == ARGT_TAB)) {
2416 /* an alternate table was specified, let's look up the same key there */
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002417 stkctr->table = args[arg].data.t;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002418 stkctr_set_entry(stkctr, stktable_lookup(stkctr->table, stksess));
2419 return stkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002420 }
2421 return stkptr;
2422}
2423
2424/* same as smp_fetch_sc_stkctr() but dedicated to src_* and can create
2425 * the entry if it doesn't exist yet. This is needed for a few fetch
2426 * functions which need to create an entry, such as src_inc_gpc* and
2427 * src_clr_gpc*.
2428 */
2429struct stkctr *
Emeric Brun819fc6f2017-06-13 19:37:32 +02002430smp_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 +01002431{
Willy Tarreau7d562212016-11-25 16:10:05 +01002432 struct stktable_key *key;
2433 struct connection *conn = objt_conn(sess->origin);
2434 struct sample smp;
2435
2436 if (strncmp(kw, "src_", 4) != 0)
2437 return NULL;
2438
2439 if (!conn)
2440 return NULL;
2441
Joseph Herlant5662fa42018-11-15 13:43:28 -08002442 /* Fetch source address in a sample. */
Willy Tarreau7d562212016-11-25 16:10:05 +01002443 smp.px = NULL;
2444 smp.sess = sess;
2445 smp.strm = strm;
Amaury Denoyellec460c702021-05-12 10:17:47 +02002446 if (!smp_fetch_src || !smp_fetch_src(empty_arg_list, &smp, "src", NULL))
Willy Tarreau7d562212016-11-25 16:10:05 +01002447 return NULL;
2448
2449 /* Converts into key. */
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002450 key = smp_to_stkey(&smp, args->data.t);
Willy Tarreau7d562212016-11-25 16:10:05 +01002451 if (!key)
2452 return NULL;
2453
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002454 stkctr->table = args->data.t;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002455 stkctr_set_entry(stkctr, stktable_get_entry(stkctr->table, key));
2456 return stkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002457}
2458
2459/* set return a boolean indicating if the requested stream counter is
2460 * currently being tracked or not.
2461 * Supports being called as "sc[0-9]_tracked" only.
2462 */
2463static int
2464smp_fetch_sc_tracked(const struct arg *args, struct sample *smp, const char *kw, void *private)
2465{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002466 struct stkctr tmpstkctr;
2467 struct stkctr *stkctr;
2468
Willy Tarreau7d562212016-11-25 16:10:05 +01002469 smp->flags = SMP_F_VOL_TEST;
2470 smp->data.type = SMP_T_BOOL;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002471 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2472 smp->data.u.sint = !!stkctr;
2473
2474 /* release the ref count */
Dirkjan Bussinkff57f1b2018-09-14 14:31:22 +02002475 if (stkctr == &tmpstkctr)
Emeric Brun819fc6f2017-06-13 19:37:32 +02002476 stktable_release(stkctr->table, stkctr_entry(stkctr));
2477
Willy Tarreau7d562212016-11-25 16:10:05 +01002478 return 1;
2479}
2480
2481/* set <smp> to the General Purpose Flag 0 value from the stream's tracked
2482 * frontend counters or from the src.
2483 * Supports being called as "sc[0-9]_get_gpc0" or "src_get_gpt0" only. Value
2484 * zero is returned if the key is new.
2485 */
2486static int
2487smp_fetch_sc_get_gpt0(const struct arg *args, struct sample *smp, const char *kw, void *private)
2488{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002489 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002490 struct stkctr *stkctr;
2491
Emeric Brun819fc6f2017-06-13 19:37:32 +02002492 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002493 if (!stkctr)
2494 return 0;
2495
2496 smp->flags = SMP_F_VOL_TEST;
2497 smp->data.type = SMP_T_SINT;
2498 smp->data.u.sint = 0;
2499
Emeric Brun819fc6f2017-06-13 19:37:32 +02002500 if (stkctr_entry(stkctr)) {
2501 void *ptr;
2502
2503 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPT0);
2504 if (!ptr) {
2505 if (stkctr == &tmpstkctr)
2506 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002507 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002508 }
2509
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002510 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002511
Willy Tarreau7d562212016-11-25 16:10:05 +01002512 smp->data.u.sint = stktable_data_cast(ptr, gpt0);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002513
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002514 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002515
2516 if (stkctr == &tmpstkctr)
2517 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002518 }
2519 return 1;
2520}
2521
2522/* set <smp> to the General Purpose Counter 0 value from the stream's tracked
2523 * frontend counters or from the src.
2524 * Supports being called as "sc[0-9]_get_gpc0" or "src_get_gpc0" only. Value
2525 * zero is returned if the key is new.
2526 */
2527static int
2528smp_fetch_sc_get_gpc0(const struct arg *args, struct sample *smp, const char *kw, void *private)
2529{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002530 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002531 struct stkctr *stkctr;
2532
Emeric Brun819fc6f2017-06-13 19:37:32 +02002533 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002534 if (!stkctr)
2535 return 0;
2536
2537 smp->flags = SMP_F_VOL_TEST;
2538 smp->data.type = SMP_T_SINT;
2539 smp->data.u.sint = 0;
2540
2541 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002542 void *ptr;
2543
2544 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0);
2545 if (!ptr) {
2546 if (stkctr == &tmpstkctr)
2547 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002548 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002549 }
2550
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002551 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002552
Willy Tarreau7d562212016-11-25 16:10:05 +01002553 smp->data.u.sint = stktable_data_cast(ptr, gpc0);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002554
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002555 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002556
2557 if (stkctr == &tmpstkctr)
2558 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002559 }
2560 return 1;
2561}
2562
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002563/* set <smp> to the General Purpose Counter 1 value from the stream's tracked
2564 * frontend counters or from the src.
2565 * Supports being called as "sc[0-9]_get_gpc1" or "src_get_gpc1" only. Value
2566 * zero is returned if the key is new.
2567 */
2568static int
2569smp_fetch_sc_get_gpc1(const struct arg *args, struct sample *smp, const char *kw, void *private)
2570{
2571 struct stkctr tmpstkctr;
2572 struct stkctr *stkctr;
2573
2574 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2575 if (!stkctr)
2576 return 0;
2577
2578 smp->flags = SMP_F_VOL_TEST;
2579 smp->data.type = SMP_T_SINT;
2580 smp->data.u.sint = 0;
2581
2582 if (stkctr_entry(stkctr) != NULL) {
2583 void *ptr;
2584
2585 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1);
2586 if (!ptr) {
2587 if (stkctr == &tmpstkctr)
2588 stktable_release(stkctr->table, stkctr_entry(stkctr));
2589 return 0; /* parameter not stored */
2590 }
2591
2592 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2593
2594 smp->data.u.sint = stktable_data_cast(ptr, gpc1);
2595
2596 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2597
2598 if (stkctr == &tmpstkctr)
2599 stktable_release(stkctr->table, stkctr_entry(stkctr));
2600 }
2601 return 1;
2602}
2603
Willy Tarreau7d562212016-11-25 16:10:05 +01002604/* set <smp> to the General Purpose Counter 0's event rate from the stream's
2605 * tracked frontend counters or from the src.
2606 * Supports being called as "sc[0-9]_gpc0_rate" or "src_gpc0_rate" only.
2607 * Value zero is returned if the key is new.
2608 */
2609static int
2610smp_fetch_sc_gpc0_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
2611{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002612 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002613 struct stkctr *stkctr;
2614
Emeric Brun819fc6f2017-06-13 19:37:32 +02002615 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002616 if (!stkctr)
2617 return 0;
2618
2619 smp->flags = SMP_F_VOL_TEST;
2620 smp->data.type = SMP_T_SINT;
2621 smp->data.u.sint = 0;
2622 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002623 void *ptr;
2624
2625 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0_RATE);
2626 if (!ptr) {
2627 if (stkctr == &tmpstkctr)
2628 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002629 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002630 }
2631
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002632 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002633
Willy Tarreau7d562212016-11-25 16:10:05 +01002634 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, gpc0_rate),
2635 stkctr->table->data_arg[STKTABLE_DT_GPC0_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002636
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002637 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002638
2639 if (stkctr == &tmpstkctr)
2640 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002641 }
2642 return 1;
2643}
2644
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002645/* set <smp> to the General Purpose Counter 1's event rate from the stream's
2646 * tracked frontend counters or from the src.
2647 * Supports being called as "sc[0-9]_gpc1_rate" or "src_gpc1_rate" only.
2648 * Value zero is returned if the key is new.
2649 */
2650static int
2651smp_fetch_sc_gpc1_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
2652{
2653 struct stkctr tmpstkctr;
2654 struct stkctr *stkctr;
2655
2656 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2657 if (!stkctr)
2658 return 0;
2659
2660 smp->flags = SMP_F_VOL_TEST;
2661 smp->data.type = SMP_T_SINT;
2662 smp->data.u.sint = 0;
2663 if (stkctr_entry(stkctr) != NULL) {
2664 void *ptr;
2665
2666 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1_RATE);
2667 if (!ptr) {
2668 if (stkctr == &tmpstkctr)
2669 stktable_release(stkctr->table, stkctr_entry(stkctr));
2670 return 0; /* parameter not stored */
2671 }
2672
2673 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2674
2675 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, gpc1_rate),
2676 stkctr->table->data_arg[STKTABLE_DT_GPC1_RATE].u);
2677
2678 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2679
2680 if (stkctr == &tmpstkctr)
2681 stktable_release(stkctr->table, stkctr_entry(stkctr));
2682 }
2683 return 1;
2684}
2685
Willy Tarreau7d562212016-11-25 16:10:05 +01002686/* Increment the General Purpose Counter 0 value from the stream's tracked
2687 * frontend counters and return it into temp integer.
2688 * Supports being called as "sc[0-9]_inc_gpc0" or "src_inc_gpc0" only.
2689 */
2690static int
2691smp_fetch_sc_inc_gpc0(const struct arg *args, struct sample *smp, const char *kw, void *private)
2692{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002693 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002694 struct stkctr *stkctr;
2695
Emeric Brun819fc6f2017-06-13 19:37:32 +02002696 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002697 if (!stkctr)
2698 return 0;
2699
2700 smp->flags = SMP_F_VOL_TEST;
2701 smp->data.type = SMP_T_SINT;
2702 smp->data.u.sint = 0;
2703
Emeric Brun819fc6f2017-06-13 19:37:32 +02002704 if (!stkctr_entry(stkctr))
2705 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002706
2707 if (stkctr && stkctr_entry(stkctr)) {
2708 void *ptr1,*ptr2;
2709
Emeric Brun819fc6f2017-06-13 19:37:32 +02002710
Willy Tarreau7d562212016-11-25 16:10:05 +01002711 /* First, update gpc0_rate if it's tracked. Second, update its
2712 * gpc0 if tracked. Returns gpc0's value otherwise the curr_ctr.
2713 */
2714 ptr1 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0_RATE);
Willy Tarreau7d562212016-11-25 16:10:05 +01002715 ptr2 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002716 if (ptr1 || ptr2) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002717 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Willy Tarreau7d562212016-11-25 16:10:05 +01002718
Emeric Brun819fc6f2017-06-13 19:37:32 +02002719 if (ptr1) {
2720 update_freq_ctr_period(&stktable_data_cast(ptr1, gpc0_rate),
2721 stkctr->table->data_arg[STKTABLE_DT_GPC0_RATE].u, 1);
2722 smp->data.u.sint = (&stktable_data_cast(ptr1, gpc0_rate))->curr_ctr;
2723 }
2724
2725 if (ptr2)
2726 smp->data.u.sint = ++stktable_data_cast(ptr2, gpc0);
2727
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002728 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002729
2730 /* If data was modified, we need to touch to re-schedule sync */
2731 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
2732 }
2733 else if (stkctr == &tmpstkctr)
2734 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002735 }
2736 return 1;
2737}
2738
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002739/* Increment the General Purpose Counter 1 value from the stream's tracked
2740 * frontend counters and return it into temp integer.
2741 * Supports being called as "sc[0-9]_inc_gpc1" or "src_inc_gpc1" only.
2742 */
2743static int
2744smp_fetch_sc_inc_gpc1(const struct arg *args, struct sample *smp, const char *kw, void *private)
2745{
2746 struct stkctr tmpstkctr;
2747 struct stkctr *stkctr;
2748
2749 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2750 if (!stkctr)
2751 return 0;
2752
2753 smp->flags = SMP_F_VOL_TEST;
2754 smp->data.type = SMP_T_SINT;
2755 smp->data.u.sint = 0;
2756
2757 if (!stkctr_entry(stkctr))
2758 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2759
2760 if (stkctr && stkctr_entry(stkctr)) {
2761 void *ptr1,*ptr2;
2762
2763
2764 /* First, update gpc1_rate if it's tracked. Second, update its
2765 * gpc1 if tracked. Returns gpc1's value otherwise the curr_ctr.
2766 */
2767 ptr1 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1_RATE);
2768 ptr2 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1);
2769 if (ptr1 || ptr2) {
2770 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2771
2772 if (ptr1) {
2773 update_freq_ctr_period(&stktable_data_cast(ptr1, gpc1_rate),
2774 stkctr->table->data_arg[STKTABLE_DT_GPC1_RATE].u, 1);
2775 smp->data.u.sint = (&stktable_data_cast(ptr1, gpc1_rate))->curr_ctr;
2776 }
2777
2778 if (ptr2)
2779 smp->data.u.sint = ++stktable_data_cast(ptr2, gpc1);
2780
2781 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2782
2783 /* If data was modified, we need to touch to re-schedule sync */
2784 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
2785 }
2786 else if (stkctr == &tmpstkctr)
2787 stktable_release(stkctr->table, stkctr_entry(stkctr));
2788 }
2789 return 1;
2790}
2791
Willy Tarreau7d562212016-11-25 16:10:05 +01002792/* Clear the General Purpose Counter 0 value from the stream's tracked
2793 * frontend counters and return its previous value into temp integer.
2794 * Supports being called as "sc[0-9]_clr_gpc0" or "src_clr_gpc0" only.
2795 */
2796static int
2797smp_fetch_sc_clr_gpc0(const struct arg *args, struct sample *smp, const char *kw, void *private)
2798{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002799 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002800 struct stkctr *stkctr;
2801
Emeric Brun819fc6f2017-06-13 19:37:32 +02002802 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002803 if (!stkctr)
2804 return 0;
2805
2806 smp->flags = SMP_F_VOL_TEST;
2807 smp->data.type = SMP_T_SINT;
2808 smp->data.u.sint = 0;
2809
Emeric Brun819fc6f2017-06-13 19:37:32 +02002810 if (!stkctr_entry(stkctr))
2811 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002812
Emeric Brun819fc6f2017-06-13 19:37:32 +02002813 if (stkctr && stkctr_entry(stkctr)) {
2814 void *ptr;
2815
2816 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0);
2817 if (!ptr) {
2818 if (stkctr == &tmpstkctr)
2819 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002820 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002821 }
2822
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002823 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002824
Willy Tarreau7d562212016-11-25 16:10:05 +01002825 smp->data.u.sint = stktable_data_cast(ptr, gpc0);
2826 stktable_data_cast(ptr, gpc0) = 0;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002827
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002828 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002829
Willy Tarreau7d562212016-11-25 16:10:05 +01002830 /* If data was modified, we need to touch to re-schedule sync */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002831 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
Willy Tarreau7d562212016-11-25 16:10:05 +01002832 }
2833 return 1;
2834}
2835
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002836/* Clear the General Purpose Counter 1 value from the stream's tracked
2837 * frontend counters and return its previous value into temp integer.
2838 * Supports being called as "sc[0-9]_clr_gpc1" or "src_clr_gpc1" only.
2839 */
2840static int
2841smp_fetch_sc_clr_gpc1(const struct arg *args, struct sample *smp, const char *kw, void *private)
2842{
2843 struct stkctr tmpstkctr;
2844 struct stkctr *stkctr;
2845
2846 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2847 if (!stkctr)
2848 return 0;
2849
2850 smp->flags = SMP_F_VOL_TEST;
2851 smp->data.type = SMP_T_SINT;
2852 smp->data.u.sint = 0;
2853
2854 if (!stkctr_entry(stkctr))
2855 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2856
2857 if (stkctr && stkctr_entry(stkctr)) {
2858 void *ptr;
2859
2860 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1);
2861 if (!ptr) {
2862 if (stkctr == &tmpstkctr)
2863 stktable_release(stkctr->table, stkctr_entry(stkctr));
2864 return 0; /* parameter not stored */
2865 }
2866
2867 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2868
2869 smp->data.u.sint = stktable_data_cast(ptr, gpc1);
2870 stktable_data_cast(ptr, gpc1) = 0;
2871
2872 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2873
2874 /* If data was modified, we need to touch to re-schedule sync */
2875 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
2876 }
2877 return 1;
2878}
2879
Willy Tarreau7d562212016-11-25 16:10:05 +01002880/* set <smp> to the cumulated number of connections from the stream's tracked
2881 * frontend counters. Supports being called as "sc[0-9]_conn_cnt" or
2882 * "src_conn_cnt" only.
2883 */
2884static int
2885smp_fetch_sc_conn_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
2886{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002887 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002888 struct stkctr *stkctr;
2889
Emeric Brun819fc6f2017-06-13 19:37:32 +02002890 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002891 if (!stkctr)
2892 return 0;
2893
2894 smp->flags = SMP_F_VOL_TEST;
2895 smp->data.type = SMP_T_SINT;
2896 smp->data.u.sint = 0;
2897 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002898 void *ptr;
2899
2900 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_CONN_CNT);
2901 if (!ptr) {
2902 if (stkctr == &tmpstkctr)
2903 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002904 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002905 }
2906
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002907 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002908
Willy Tarreau7d562212016-11-25 16:10:05 +01002909 smp->data.u.sint = stktable_data_cast(ptr, conn_cnt);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002910
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002911 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002912
2913 if (stkctr == &tmpstkctr)
2914 stktable_release(stkctr->table, stkctr_entry(stkctr));
2915
2916
Willy Tarreau7d562212016-11-25 16:10:05 +01002917 }
2918 return 1;
2919}
2920
2921/* set <smp> to the connection rate from the stream's tracked frontend
2922 * counters. Supports being called as "sc[0-9]_conn_rate" or "src_conn_rate"
2923 * only.
2924 */
2925static int
2926smp_fetch_sc_conn_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
2927{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002928 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002929 struct stkctr *stkctr;
2930
Emeric Brun819fc6f2017-06-13 19:37:32 +02002931 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002932 if (!stkctr)
2933 return 0;
2934
2935 smp->flags = SMP_F_VOL_TEST;
2936 smp->data.type = SMP_T_SINT;
2937 smp->data.u.sint = 0;
2938 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002939 void *ptr;
2940
2941 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_CONN_RATE);
2942 if (!ptr) {
2943 if (stkctr == &tmpstkctr)
2944 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002945 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002946 }
2947
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002948 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002949
Willy Tarreau7d562212016-11-25 16:10:05 +01002950 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, conn_rate),
2951 stkctr->table->data_arg[STKTABLE_DT_CONN_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002952
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002953 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002954
2955 if (stkctr == &tmpstkctr)
2956 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002957 }
2958 return 1;
2959}
2960
2961/* set temp integer to the number of connections from the stream's source address
2962 * in the table pointed to by expr, after updating it.
2963 * Accepts exactly 1 argument of type table.
2964 */
2965static int
2966smp_fetch_src_updt_conn_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
2967{
2968 struct connection *conn = objt_conn(smp->sess->origin);
2969 struct stksess *ts;
2970 struct stktable_key *key;
2971 void *ptr;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002972 struct stktable *t;
Willy Tarreau7d562212016-11-25 16:10:05 +01002973
2974 if (!conn)
2975 return 0;
2976
Joseph Herlant5662fa42018-11-15 13:43:28 -08002977 /* Fetch source address in a sample. */
Amaury Denoyellec460c702021-05-12 10:17:47 +02002978 if (!smp_fetch_src || !smp_fetch_src(empty_arg_list, smp, "src", NULL))
Willy Tarreau7d562212016-11-25 16:10:05 +01002979 return 0;
2980
2981 /* Converts into key. */
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002982 key = smp_to_stkey(smp, args->data.t);
Willy Tarreau7d562212016-11-25 16:10:05 +01002983 if (!key)
2984 return 0;
2985
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002986 t = args->data.t;
Willy Tarreau7d562212016-11-25 16:10:05 +01002987
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002988 if ((ts = stktable_get_entry(t, key)) == NULL)
Willy Tarreau7d562212016-11-25 16:10:05 +01002989 /* entry does not exist and could not be created */
2990 return 0;
2991
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002992 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_CONN_CNT);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002993 if (!ptr) {
Willy Tarreau7d562212016-11-25 16:10:05 +01002994 return 0; /* parameter not stored in this table */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002995 }
Willy Tarreau7d562212016-11-25 16:10:05 +01002996
2997 smp->data.type = SMP_T_SINT;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002998
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002999 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003000
Willy Tarreau7d562212016-11-25 16:10:05 +01003001 smp->data.u.sint = ++stktable_data_cast(ptr, conn_cnt);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003002
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003003 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003004
Willy Tarreau7d562212016-11-25 16:10:05 +01003005 smp->flags = SMP_F_VOL_TEST;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003006
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003007 stktable_touch_local(t, ts, 1);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003008
3009 /* Touch was previously performed by stktable_update_key */
Willy Tarreau7d562212016-11-25 16:10:05 +01003010 return 1;
3011}
3012
3013/* set <smp> to the number of concurrent connections from the stream's tracked
3014 * frontend counters. Supports being called as "sc[0-9]_conn_cur" or
3015 * "src_conn_cur" only.
3016 */
3017static int
3018smp_fetch_sc_conn_cur(const struct arg *args, struct sample *smp, const char *kw, void *private)
3019{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003020 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003021 struct stkctr *stkctr;
3022
Emeric Brun819fc6f2017-06-13 19:37:32 +02003023 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003024 if (!stkctr)
3025 return 0;
3026
3027 smp->flags = SMP_F_VOL_TEST;
3028 smp->data.type = SMP_T_SINT;
3029 smp->data.u.sint = 0;
3030 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003031 void *ptr;
3032
3033 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_CONN_CUR);
3034 if (!ptr) {
3035 if (stkctr == &tmpstkctr)
3036 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003037 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003038 }
3039
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003040 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003041
Willy Tarreau7d562212016-11-25 16:10:05 +01003042 smp->data.u.sint = stktable_data_cast(ptr, conn_cur);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003043
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003044 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003045
3046 if (stkctr == &tmpstkctr)
3047 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003048 }
3049 return 1;
3050}
3051
3052/* set <smp> to the cumulated number of streams from the stream's tracked
3053 * frontend counters. Supports being called as "sc[0-9]_sess_cnt" or
3054 * "src_sess_cnt" only.
3055 */
3056static int
3057smp_fetch_sc_sess_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
3058{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003059 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003060 struct stkctr *stkctr;
3061
Emeric Brun819fc6f2017-06-13 19:37:32 +02003062 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003063 if (!stkctr)
3064 return 0;
3065
3066 smp->flags = SMP_F_VOL_TEST;
3067 smp->data.type = SMP_T_SINT;
3068 smp->data.u.sint = 0;
3069 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003070 void *ptr;
3071
3072 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_SESS_CNT);
3073 if (!ptr) {
3074 if (stkctr == &tmpstkctr)
3075 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003076 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003077 }
3078
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003079 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003080
Willy Tarreau7d562212016-11-25 16:10:05 +01003081 smp->data.u.sint = stktable_data_cast(ptr, sess_cnt);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003082
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003083 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003084
3085 if (stkctr == &tmpstkctr)
3086 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003087 }
3088 return 1;
3089}
3090
3091/* set <smp> to the stream rate from the stream's tracked frontend counters.
3092 * Supports being called as "sc[0-9]_sess_rate" or "src_sess_rate" only.
3093 */
3094static int
3095smp_fetch_sc_sess_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3096{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003097 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003098 struct stkctr *stkctr;
3099
Emeric Brun819fc6f2017-06-13 19:37:32 +02003100 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003101 if (!stkctr)
3102 return 0;
3103
3104 smp->flags = SMP_F_VOL_TEST;
3105 smp->data.type = SMP_T_SINT;
3106 smp->data.u.sint = 0;
3107 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003108 void *ptr;
3109
3110 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_SESS_RATE);
3111 if (!ptr) {
3112 if (stkctr == &tmpstkctr)
3113 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003114 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003115 }
3116
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003117 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003118
Willy Tarreau7d562212016-11-25 16:10:05 +01003119 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, sess_rate),
3120 stkctr->table->data_arg[STKTABLE_DT_SESS_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003121
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003122 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003123
3124 if (stkctr == &tmpstkctr)
3125 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003126 }
3127 return 1;
3128}
3129
3130/* set <smp> to the cumulated number of HTTP requests from the stream's tracked
3131 * frontend counters. Supports being called as "sc[0-9]_http_req_cnt" or
3132 * "src_http_req_cnt" only.
3133 */
3134static int
3135smp_fetch_sc_http_req_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
3136{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003137 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003138 struct stkctr *stkctr;
3139
Emeric Brun819fc6f2017-06-13 19:37:32 +02003140 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003141 if (!stkctr)
3142 return 0;
3143
3144 smp->flags = SMP_F_VOL_TEST;
3145 smp->data.type = SMP_T_SINT;
3146 smp->data.u.sint = 0;
3147 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003148 void *ptr;
3149
3150 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_REQ_CNT);
3151 if (!ptr) {
3152 if (stkctr == &tmpstkctr)
3153 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003154 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003155 }
3156
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003157 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003158
Willy Tarreau7d562212016-11-25 16:10:05 +01003159 smp->data.u.sint = stktable_data_cast(ptr, http_req_cnt);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003160
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003161 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003162
3163 if (stkctr == &tmpstkctr)
3164 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003165 }
3166 return 1;
3167}
3168
3169/* set <smp> to the HTTP request rate from the stream's tracked frontend
3170 * counters. Supports being called as "sc[0-9]_http_req_rate" or
3171 * "src_http_req_rate" only.
3172 */
3173static int
3174smp_fetch_sc_http_req_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3175{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003176 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003177 struct stkctr *stkctr;
3178
Emeric Brun819fc6f2017-06-13 19:37:32 +02003179 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003180 if (!stkctr)
3181 return 0;
3182
3183 smp->flags = SMP_F_VOL_TEST;
3184 smp->data.type = SMP_T_SINT;
3185 smp->data.u.sint = 0;
3186 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003187 void *ptr;
3188
3189 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_REQ_RATE);
3190 if (!ptr) {
3191 if (stkctr == &tmpstkctr)
3192 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003193 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003194 }
3195
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003196 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003197
Willy Tarreau7d562212016-11-25 16:10:05 +01003198 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, http_req_rate),
3199 stkctr->table->data_arg[STKTABLE_DT_HTTP_REQ_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003200
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003201 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003202
3203 if (stkctr == &tmpstkctr)
3204 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003205 }
3206 return 1;
3207}
3208
3209/* set <smp> to the cumulated number of HTTP requests errors from the stream's
3210 * tracked frontend counters. Supports being called as "sc[0-9]_http_err_cnt" or
3211 * "src_http_err_cnt" only.
3212 */
3213static int
3214smp_fetch_sc_http_err_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
3215{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003216 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003217 struct stkctr *stkctr;
3218
Emeric Brun819fc6f2017-06-13 19:37:32 +02003219 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003220 if (!stkctr)
3221 return 0;
3222
3223 smp->flags = SMP_F_VOL_TEST;
3224 smp->data.type = SMP_T_SINT;
3225 smp->data.u.sint = 0;
3226 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003227 void *ptr;
3228
3229 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_ERR_CNT);
3230 if (!ptr) {
3231 if (stkctr == &tmpstkctr)
3232 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003233 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003234 }
3235
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003236 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003237
Willy Tarreau7d562212016-11-25 16:10:05 +01003238 smp->data.u.sint = stktable_data_cast(ptr, http_err_cnt);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003239
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003240 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003241
3242 if (stkctr == &tmpstkctr)
3243 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003244 }
3245 return 1;
3246}
3247
3248/* set <smp> to the HTTP request error rate from the stream's tracked frontend
3249 * counters. Supports being called as "sc[0-9]_http_err_rate" or
3250 * "src_http_err_rate" only.
3251 */
3252static int
3253smp_fetch_sc_http_err_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3254{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003255 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003256 struct stkctr *stkctr;
3257
Emeric Brun819fc6f2017-06-13 19:37:32 +02003258 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003259 if (!stkctr)
3260 return 0;
3261
3262 smp->flags = SMP_F_VOL_TEST;
3263 smp->data.type = SMP_T_SINT;
3264 smp->data.u.sint = 0;
3265 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003266 void *ptr;
3267
3268 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_ERR_RATE);
3269 if (!ptr) {
3270 if (stkctr == &tmpstkctr)
3271 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003272 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003273 }
3274
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003275 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003276
Willy Tarreau7d562212016-11-25 16:10:05 +01003277 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, http_err_rate),
3278 stkctr->table->data_arg[STKTABLE_DT_HTTP_ERR_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003279
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003280 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003281
3282 if (stkctr == &tmpstkctr)
3283 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003284 }
3285 return 1;
3286}
3287
Willy Tarreau826f3ab2021-02-10 12:07:15 +01003288/* set <smp> to the cumulated number of HTTP response failures from the stream's
3289 * tracked frontend counters. Supports being called as "sc[0-9]_http_fail_cnt" or
3290 * "src_http_fail_cnt" only.
3291 */
3292static int
3293smp_fetch_sc_http_fail_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
3294{
3295 struct stkctr tmpstkctr;
3296 struct stkctr *stkctr;
3297
3298 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
3299 if (!stkctr)
3300 return 0;
3301
3302 smp->flags = SMP_F_VOL_TEST;
3303 smp->data.type = SMP_T_SINT;
3304 smp->data.u.sint = 0;
3305 if (stkctr_entry(stkctr) != NULL) {
3306 void *ptr;
3307
3308 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_FAIL_CNT);
3309 if (!ptr) {
3310 if (stkctr == &tmpstkctr)
3311 stktable_release(stkctr->table, stkctr_entry(stkctr));
3312 return 0; /* parameter not stored */
3313 }
3314
3315 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3316
3317 smp->data.u.sint = stktable_data_cast(ptr, http_fail_cnt);
3318
3319 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3320
3321 if (stkctr == &tmpstkctr)
3322 stktable_release(stkctr->table, stkctr_entry(stkctr));
3323 }
3324 return 1;
3325}
3326
3327/* set <smp> to the HTTP response failure rate from the stream's tracked frontend
3328 * counters. Supports being called as "sc[0-9]_http_fail_rate" or
3329 * "src_http_fail_rate" only.
3330 */
3331static int
3332smp_fetch_sc_http_fail_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3333{
3334 struct stkctr tmpstkctr;
3335 struct stkctr *stkctr;
3336
3337 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
3338 if (!stkctr)
3339 return 0;
3340
3341 smp->flags = SMP_F_VOL_TEST;
3342 smp->data.type = SMP_T_SINT;
3343 smp->data.u.sint = 0;
3344 if (stkctr_entry(stkctr) != NULL) {
3345 void *ptr;
3346
3347 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_FAIL_RATE);
3348 if (!ptr) {
3349 if (stkctr == &tmpstkctr)
3350 stktable_release(stkctr->table, stkctr_entry(stkctr));
3351 return 0; /* parameter not stored */
3352 }
3353
3354 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3355
3356 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, http_fail_rate),
3357 stkctr->table->data_arg[STKTABLE_DT_HTTP_FAIL_RATE].u);
3358
3359 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3360
3361 if (stkctr == &tmpstkctr)
3362 stktable_release(stkctr->table, stkctr_entry(stkctr));
3363 }
3364 return 1;
3365}
3366
Willy Tarreau7d562212016-11-25 16:10:05 +01003367/* set <smp> to the number of kbytes received from clients, as found in the
3368 * stream's tracked frontend counters. Supports being called as
3369 * "sc[0-9]_kbytes_in" or "src_kbytes_in" only.
3370 */
3371static int
3372smp_fetch_sc_kbytes_in(const struct arg *args, struct sample *smp, const char *kw, void *private)
3373{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003374 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003375 struct stkctr *stkctr;
3376
Emeric Brun819fc6f2017-06-13 19:37:32 +02003377 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003378 if (!stkctr)
3379 return 0;
3380
3381 smp->flags = SMP_F_VOL_TEST;
3382 smp->data.type = SMP_T_SINT;
3383 smp->data.u.sint = 0;
3384 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003385 void *ptr;
3386
3387 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_IN_CNT);
3388 if (!ptr) {
3389 if (stkctr == &tmpstkctr)
3390 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003391 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003392 }
3393
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003394 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003395
Willy Tarreau7d562212016-11-25 16:10:05 +01003396 smp->data.u.sint = stktable_data_cast(ptr, bytes_in_cnt) >> 10;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003397
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003398 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003399
3400 if (stkctr == &tmpstkctr)
3401 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003402 }
3403 return 1;
3404}
3405
3406/* set <smp> to the data rate received from clients in bytes/s, as found
3407 * in the stream's tracked frontend counters. Supports being called as
3408 * "sc[0-9]_bytes_in_rate" or "src_bytes_in_rate" only.
3409 */
3410static int
3411smp_fetch_sc_bytes_in_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3412{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003413 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003414 struct stkctr *stkctr;
3415
Emeric Brun819fc6f2017-06-13 19:37:32 +02003416 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003417 if (!stkctr)
3418 return 0;
3419
3420 smp->flags = SMP_F_VOL_TEST;
3421 smp->data.type = SMP_T_SINT;
3422 smp->data.u.sint = 0;
3423 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003424 void *ptr;
3425
3426 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_IN_RATE);
3427 if (!ptr) {
3428 if (stkctr == &tmpstkctr)
3429 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003430 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003431 }
3432
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003433 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003434
Willy Tarreau7d562212016-11-25 16:10:05 +01003435 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, bytes_in_rate),
3436 stkctr->table->data_arg[STKTABLE_DT_BYTES_IN_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003437
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003438 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003439
3440 if (stkctr == &tmpstkctr)
3441 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003442 }
3443 return 1;
3444}
3445
3446/* set <smp> to the number of kbytes sent to clients, as found in the
3447 * stream's tracked frontend counters. Supports being called as
3448 * "sc[0-9]_kbytes_out" or "src_kbytes_out" only.
3449 */
3450static int
3451smp_fetch_sc_kbytes_out(const struct arg *args, struct sample *smp, const char *kw, void *private)
3452{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003453 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003454 struct stkctr *stkctr;
3455
Emeric Brun819fc6f2017-06-13 19:37:32 +02003456 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003457 if (!stkctr)
3458 return 0;
3459
3460 smp->flags = SMP_F_VOL_TEST;
3461 smp->data.type = SMP_T_SINT;
3462 smp->data.u.sint = 0;
3463 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003464 void *ptr;
3465
3466 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_OUT_CNT);
3467 if (!ptr) {
3468 if (stkctr == &tmpstkctr)
3469 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003470 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003471 }
3472
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003473 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003474
Willy Tarreau7d562212016-11-25 16:10:05 +01003475 smp->data.u.sint = stktable_data_cast(ptr, bytes_out_cnt) >> 10;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003476
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003477 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003478
3479 if (stkctr == &tmpstkctr)
3480 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003481 }
3482 return 1;
3483}
3484
3485/* set <smp> to the data rate sent to clients in bytes/s, as found in the
3486 * stream's tracked frontend counters. Supports being called as
3487 * "sc[0-9]_bytes_out_rate" or "src_bytes_out_rate" only.
3488 */
3489static int
3490smp_fetch_sc_bytes_out_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3491{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003492 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003493 struct stkctr *stkctr;
3494
Emeric Brun819fc6f2017-06-13 19:37:32 +02003495 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003496 if (!stkctr)
3497 return 0;
3498
3499 smp->flags = SMP_F_VOL_TEST;
3500 smp->data.type = SMP_T_SINT;
3501 smp->data.u.sint = 0;
3502 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003503 void *ptr;
3504
3505 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_OUT_RATE);
3506 if (!ptr) {
3507 if (stkctr == &tmpstkctr)
3508 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003509 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003510 }
3511
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003512 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003513
Willy Tarreau7d562212016-11-25 16:10:05 +01003514 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, bytes_out_rate),
3515 stkctr->table->data_arg[STKTABLE_DT_BYTES_OUT_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003516
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003517 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003518
3519 if (stkctr == &tmpstkctr)
3520 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003521 }
3522 return 1;
3523}
3524
3525/* set <smp> to the number of active trackers on the SC entry in the stream's
3526 * tracked frontend counters. Supports being called as "sc[0-9]_trackers" only.
3527 */
3528static int
3529smp_fetch_sc_trackers(const struct arg *args, struct sample *smp, const char *kw, void *private)
3530{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003531 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003532 struct stkctr *stkctr;
3533
Emeric Brun819fc6f2017-06-13 19:37:32 +02003534 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003535 if (!stkctr)
3536 return 0;
3537
3538 smp->flags = SMP_F_VOL_TEST;
3539 smp->data.type = SMP_T_SINT;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003540 if (stkctr == &tmpstkctr) {
3541 smp->data.u.sint = stkctr_entry(stkctr) ? (stkctr_entry(stkctr)->ref_cnt-1) : 0;
3542 stktable_release(stkctr->table, stkctr_entry(stkctr));
3543 }
3544 else {
3545 smp->data.u.sint = stkctr_entry(stkctr) ? stkctr_entry(stkctr)->ref_cnt : 0;
3546 }
3547
Willy Tarreau7d562212016-11-25 16:10:05 +01003548 return 1;
3549}
3550
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003551
3552/* The functions below are used to manipulate table contents from the CLI.
3553 * There are 3 main actions, "clear", "set" and "show". The code is shared
3554 * between all actions, and the action is encoded in the void *private in
3555 * the appctx as well as in the keyword registration, among one of the
3556 * following values.
3557 */
3558
3559enum {
3560 STK_CLI_ACT_CLR,
3561 STK_CLI_ACT_SET,
3562 STK_CLI_ACT_SHOW,
3563};
3564
3565/* Dump the status of a table to a stream interface's
3566 * read buffer. It returns 0 if the output buffer is full
3567 * and needs to be called again, otherwise non-zero.
3568 */
Willy Tarreau83061a82018-07-13 11:56:34 +02003569static int table_dump_head_to_buffer(struct buffer *msg,
3570 struct stream_interface *si,
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003571 struct stktable *t, struct stktable *target)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003572{
3573 struct stream *s = si_strm(si);
3574
3575 chunk_appendf(msg, "# table: %s, type: %s, size:%d, used:%d\n",
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003576 t->id, stktable_types[t->type].kw, t->size, t->current);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003577
3578 /* any other information should be dumped here */
3579
William Lallemand07a62f72017-05-24 00:57:40 +02003580 if (target && (strm_li(s)->bind_conf->level & ACCESS_LVL_MASK) < ACCESS_LVL_OPER)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003581 chunk_appendf(msg, "# contents not dumped due to insufficient privileges\n");
3582
Willy Tarreau06d80a92017-10-19 14:32:15 +02003583 if (ci_putchk(si_ic(si), msg) == -1) {
Willy Tarreaudb398432018-11-15 11:08:52 +01003584 si_rx_room_blk(si);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003585 return 0;
3586 }
3587
3588 return 1;
3589}
3590
3591/* Dump a table entry to a stream interface's
3592 * read buffer. It returns 0 if the output buffer is full
3593 * and needs to be called again, otherwise non-zero.
3594 */
Willy Tarreau83061a82018-07-13 11:56:34 +02003595static int table_dump_entry_to_buffer(struct buffer *msg,
3596 struct stream_interface *si,
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003597 struct stktable *t, struct stksess *entry)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003598{
3599 int dt;
3600
3601 chunk_appendf(msg, "%p:", entry);
3602
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003603 if (t->type == SMP_T_IPV4) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003604 char addr[INET_ADDRSTRLEN];
3605 inet_ntop(AF_INET, (const void *)&entry->key.key, addr, sizeof(addr));
3606 chunk_appendf(msg, " key=%s", addr);
3607 }
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003608 else if (t->type == SMP_T_IPV6) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003609 char addr[INET6_ADDRSTRLEN];
3610 inet_ntop(AF_INET6, (const void *)&entry->key.key, addr, sizeof(addr));
3611 chunk_appendf(msg, " key=%s", addr);
3612 }
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003613 else if (t->type == SMP_T_SINT) {
Willy Tarreau6cde5d82020-02-25 09:41:22 +01003614 chunk_appendf(msg, " key=%u", read_u32(entry->key.key));
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003615 }
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003616 else if (t->type == SMP_T_STR) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003617 chunk_appendf(msg, " key=");
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003618 dump_text(msg, (const char *)entry->key.key, t->key_size);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003619 }
3620 else {
3621 chunk_appendf(msg, " key=");
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003622 dump_binary(msg, (const char *)entry->key.key, t->key_size);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003623 }
3624
3625 chunk_appendf(msg, " use=%d exp=%d", entry->ref_cnt - 1, tick_remain(now_ms, entry->expire));
3626
3627 for (dt = 0; dt < STKTABLE_DATA_TYPES; dt++) {
3628 void *ptr;
3629
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003630 if (t->data_ofs[dt] == 0)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003631 continue;
3632 if (stktable_data_types[dt].arg_type == ARG_T_DELAY)
Emeric Brunc24b4142021-06-30 16:24:04 +02003633 chunk_appendf(msg, " %s(%u)=", stktable_data_types[dt].name, t->data_arg[dt].u);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003634 else
3635 chunk_appendf(msg, " %s=", stktable_data_types[dt].name);
3636
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003637 ptr = stktable_data_ptr(t, entry, dt);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003638 switch (stktable_data_types[dt].std_type) {
3639 case STD_T_SINT:
3640 chunk_appendf(msg, "%d", stktable_data_cast(ptr, std_t_sint));
3641 break;
3642 case STD_T_UINT:
3643 chunk_appendf(msg, "%u", stktable_data_cast(ptr, std_t_uint));
3644 break;
3645 case STD_T_ULL:
Emeric Brunc24b4142021-06-30 16:24:04 +02003646 chunk_appendf(msg, "%llu", stktable_data_cast(ptr, std_t_ull));
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003647 break;
3648 case STD_T_FRQP:
Emeric Brunc24b4142021-06-30 16:24:04 +02003649 chunk_appendf(msg, "%u",
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003650 read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003651 t->data_arg[dt].u));
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003652 break;
Frédéric Lécaille16b4f542019-05-23 12:15:04 +02003653 case STD_T_DICT: {
3654 struct dict_entry *de;
3655 de = stktable_data_cast(ptr, std_t_dict);
3656 chunk_appendf(msg, "%s", de ? (char *)de->value.key : "-");
3657 break;
3658 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003659 }
3660 }
3661 chunk_appendf(msg, "\n");
3662
Willy Tarreau06d80a92017-10-19 14:32:15 +02003663 if (ci_putchk(si_ic(si), msg) == -1) {
Willy Tarreaudb398432018-11-15 11:08:52 +01003664 si_rx_room_blk(si);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003665 return 0;
3666 }
3667
3668 return 1;
3669}
3670
3671
3672/* Processes a single table entry matching a specific key passed in argument.
3673 * returns 0 if wants to be called again, 1 if has ended processing.
3674 */
3675static int table_process_entry_per_key(struct appctx *appctx, char **args)
3676{
3677 struct stream_interface *si = appctx->owner;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003678 struct stktable *t = appctx->ctx.table.target;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003679 struct stksess *ts;
3680 uint32_t uint32_key;
3681 unsigned char ip6_key[sizeof(struct in6_addr)];
3682 long long value;
3683 int data_type;
3684 int cur_arg;
3685 void *ptr;
Willy Tarreaufa1258f2021-04-10 23:00:53 +02003686 struct freq_ctr *frqp;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003687
Willy Tarreau9d008692019-08-09 11:21:01 +02003688 if (!*args[4])
3689 return cli_err(appctx, "Key value expected\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003690
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003691 switch (t->type) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003692 case SMP_T_IPV4:
3693 uint32_key = htonl(inetaddr_host(args[4]));
Christopher Fauletca20d022017-08-29 15:30:31 +02003694 static_table_key.key = &uint32_key;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003695 break;
3696 case SMP_T_IPV6:
Christopher Faulet1e850b52021-11-15 09:17:25 +01003697 if (inet_pton(AF_INET6, args[4], ip6_key) <= 0)
3698 return cli_err(appctx, "Invalid key\n");
Christopher Fauletca20d022017-08-29 15:30:31 +02003699 static_table_key.key = &ip6_key;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003700 break;
3701 case SMP_T_SINT:
3702 {
3703 char *endptr;
3704 unsigned long val;
3705 errno = 0;
3706 val = strtoul(args[4], &endptr, 10);
3707 if ((errno == ERANGE && val == ULONG_MAX) ||
3708 (errno != 0 && val == 0) || endptr == args[4] ||
Willy Tarreau9d008692019-08-09 11:21:01 +02003709 val > 0xffffffff)
3710 return cli_err(appctx, "Invalid key\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003711 uint32_key = (uint32_t) val;
Christopher Fauletca20d022017-08-29 15:30:31 +02003712 static_table_key.key = &uint32_key;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003713 break;
3714 }
3715 break;
3716 case SMP_T_STR:
Christopher Fauletca20d022017-08-29 15:30:31 +02003717 static_table_key.key = args[4];
3718 static_table_key.key_len = strlen(args[4]);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003719 break;
3720 default:
Willy Tarreaua24bc782016-12-14 15:50:35 +01003721 switch (appctx->ctx.table.action) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003722 case STK_CLI_ACT_SHOW:
Willy Tarreau9d008692019-08-09 11:21:01 +02003723 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 +01003724 case STK_CLI_ACT_CLR:
Willy Tarreau9d008692019-08-09 11:21:01 +02003725 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 +01003726 case STK_CLI_ACT_SET:
Willy Tarreau9d008692019-08-09 11:21:01 +02003727 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 +01003728 default:
Willy Tarreau9d008692019-08-09 11:21:01 +02003729 return cli_err(appctx, "Unknown action\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003730 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003731 }
3732
3733 /* check permissions */
3734 if (!cli_has_level(appctx, ACCESS_LVL_OPER))
3735 return 1;
3736
Willy Tarreaua24bc782016-12-14 15:50:35 +01003737 switch (appctx->ctx.table.action) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003738 case STK_CLI_ACT_SHOW:
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003739 ts = stktable_lookup_key(t, &static_table_key);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003740 if (!ts)
3741 return 1;
3742 chunk_reset(&trash);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003743 if (!table_dump_head_to_buffer(&trash, si, t, t)) {
3744 stktable_release(t, ts);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003745 return 0;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003746 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003747 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003748 if (!table_dump_entry_to_buffer(&trash, si, t, ts)) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003749 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003750 stktable_release(t, ts);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003751 return 0;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003752 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003753 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003754 stktable_release(t, ts);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003755 break;
3756
3757 case STK_CLI_ACT_CLR:
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003758 ts = stktable_lookup_key(t, &static_table_key);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003759 if (!ts)
3760 return 1;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003761
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003762 if (!stksess_kill(t, ts, 1)) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003763 /* don't delete an entry which is currently referenced */
Willy Tarreau9d008692019-08-09 11:21:01 +02003764 return cli_err(appctx, "Entry currently in use, cannot remove\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003765 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003766 break;
3767
3768 case STK_CLI_ACT_SET:
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003769 ts = stktable_get_entry(t, &static_table_key);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003770 if (!ts) {
3771 /* don't delete an entry which is currently referenced */
Willy Tarreau9d008692019-08-09 11:21:01 +02003772 return cli_err(appctx, "Unable to allocate a new entry\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003773 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003774 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003775 for (cur_arg = 5; *args[cur_arg]; cur_arg += 2) {
3776 if (strncmp(args[cur_arg], "data.", 5) != 0) {
Willy Tarreau9d008692019-08-09 11:21:01 +02003777 cli_err(appctx, "\"data.<type>\" followed by a value expected\n");
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003778 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003779 stktable_touch_local(t, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003780 return 1;
3781 }
3782
3783 data_type = stktable_get_data_type(args[cur_arg] + 5);
3784 if (data_type < 0) {
Willy Tarreau9d008692019-08-09 11:21:01 +02003785 cli_err(appctx, "Unknown data type\n");
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003786 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003787 stktable_touch_local(t, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003788 return 1;
3789 }
3790
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003791 if (!t->data_ofs[data_type]) {
Willy Tarreau9d008692019-08-09 11:21:01 +02003792 cli_err(appctx, "Data type not stored in this table\n");
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003793 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003794 stktable_touch_local(t, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003795 return 1;
3796 }
3797
3798 if (!*args[cur_arg+1] || strl2llrc(args[cur_arg+1], strlen(args[cur_arg+1]), &value) != 0) {
Willy Tarreau9d008692019-08-09 11:21:01 +02003799 cli_err(appctx, "Require a valid integer value to store\n");
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003800 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003801 stktable_touch_local(t, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003802 return 1;
3803 }
3804
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003805 ptr = stktable_data_ptr(t, ts, data_type);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003806
3807 switch (stktable_data_types[data_type].std_type) {
3808 case STD_T_SINT:
3809 stktable_data_cast(ptr, std_t_sint) = value;
3810 break;
3811 case STD_T_UINT:
3812 stktable_data_cast(ptr, std_t_uint) = value;
3813 break;
3814 case STD_T_ULL:
3815 stktable_data_cast(ptr, std_t_ull) = value;
3816 break;
3817 case STD_T_FRQP:
3818 /* We set both the current and previous values. That way
3819 * the reported frequency is stable during all the period
3820 * then slowly fades out. This allows external tools to
3821 * push measures without having to update them too often.
3822 */
3823 frqp = &stktable_data_cast(ptr, std_t_frqp);
Willy Tarreaufa1258f2021-04-10 23:00:53 +02003824 /* First bit is reserved for the freq_ctr lock
Emeric Brunf2fc1fd2017-11-02 17:32:43 +01003825 Note: here we're still protected by the stksess lock
Willy Tarreaufa1258f2021-04-10 23:00:53 +02003826 so we don't need to update the update the freq_ctr
Emeric Brunf2fc1fd2017-11-02 17:32:43 +01003827 using its internal lock */
3828 frqp->curr_tick = now_ms & ~0x1;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003829 frqp->prev_ctr = 0;
3830 frqp->curr_ctr = value;
3831 break;
3832 }
3833 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003834 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003835 stktable_touch_local(t, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003836 break;
3837
3838 default:
Willy Tarreau9d008692019-08-09 11:21:01 +02003839 return cli_err(appctx, "Unknown action\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003840 }
3841 return 1;
3842}
3843
3844/* Prepares the appctx fields with the data-based filters from the command line.
3845 * Returns 0 if the dump can proceed, 1 if has ended processing.
3846 */
3847static int table_prepare_data_request(struct appctx *appctx, char **args)
3848{
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01003849 int i;
Adis Nezirovicd0142e72020-01-22 16:50:27 +01003850 char *err = NULL;
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01003851
Willy Tarreau9d008692019-08-09 11:21:01 +02003852 if (appctx->ctx.table.action != STK_CLI_ACT_SHOW && appctx->ctx.table.action != STK_CLI_ACT_CLR)
3853 return cli_err(appctx, "content-based lookup is only supported with the \"show\" and \"clear\" actions\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003854
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01003855 for (i = 0; i < STKTABLE_FILTER_LEN; i++) {
3856 if (i > 0 && !*args[3+3*i]) // number of filter entries can be less than STKTABLE_FILTER_LEN
3857 break;
3858 /* condition on stored data value */
3859 appctx->ctx.table.data_type[i] = stktable_get_data_type(args[3+3*i] + 5);
3860 if (appctx->ctx.table.data_type[i] < 0)
Adis Nezirovicd0142e72020-01-22 16:50:27 +01003861 return cli_dynerr(appctx, memprintf(&err, "Filter entry #%i: Unknown data type\n", i + 1));
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003862
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01003863 if (!((struct stktable *)appctx->ctx.table.target)->data_ofs[appctx->ctx.table.data_type[i]])
Adis Nezirovicd0142e72020-01-22 16:50:27 +01003864 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 +01003865
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01003866 appctx->ctx.table.data_op[i] = get_std_op(args[4+3*i]);
Willy Tarreau2b64a352020-01-22 17:09:47 +01003867 if (appctx->ctx.table.data_op[i] < 0)
Adis Nezirovicd0142e72020-01-22 16:50:27 +01003868 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 +01003869
Adis Nezirovic56dd3542020-01-22 16:16:48 +01003870 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 +01003871 return cli_dynerr(appctx, memprintf(&err, "Filter entry #%i: Require a valid integer value to compare against\n", i + 1));
3872 }
3873
3874 if (*args[3+3*i]) {
3875 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 +01003876 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003877
3878 /* OK we're done, all the fields are set */
3879 return 0;
3880}
3881
3882/* returns 0 if wants to be called, 1 if has ended processing */
Aurélien Nephtaliabbf6072018-04-18 13:26:46 +02003883static int cli_parse_table_req(char **args, char *payload, struct appctx *appctx, void *private)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003884{
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01003885 int i;
3886
3887 for (i = 0; i < STKTABLE_FILTER_LEN; i++)
3888 appctx->ctx.table.data_type[i] = -1;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003889 appctx->ctx.table.target = NULL;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003890 appctx->ctx.table.entry = NULL;
Willy Tarreaua24bc782016-12-14 15:50:35 +01003891 appctx->ctx.table.action = (long)private; // keyword argument, one of STK_CLI_ACT_*
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003892
3893 if (*args[2]) {
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003894 appctx->ctx.table.target = stktable_find_by_name(args[2]);
Willy Tarreau9d008692019-08-09 11:21:01 +02003895 if (!appctx->ctx.table.target)
3896 return cli_err(appctx, "No such table\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003897 }
3898 else {
Willy Tarreaua24bc782016-12-14 15:50:35 +01003899 if (appctx->ctx.table.action != STK_CLI_ACT_SHOW)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003900 goto err_args;
3901 return 0;
3902 }
3903
3904 if (strcmp(args[3], "key") == 0)
3905 return table_process_entry_per_key(appctx, args);
3906 else if (strncmp(args[3], "data.", 5) == 0)
3907 return table_prepare_data_request(appctx, args);
3908 else if (*args[3])
3909 goto err_args;
3910
3911 return 0;
3912
3913err_args:
Willy Tarreaua24bc782016-12-14 15:50:35 +01003914 switch (appctx->ctx.table.action) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003915 case STK_CLI_ACT_SHOW:
Willy Tarreau9d008692019-08-09 11:21:01 +02003916 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 +01003917 case STK_CLI_ACT_CLR:
Willy Tarreau9d008692019-08-09 11:21:01 +02003918 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 +01003919 case STK_CLI_ACT_SET:
Willy Tarreau9d008692019-08-09 11:21:01 +02003920 return cli_err(appctx, "Required arguments: <table> key <key> [data.<store_data_type> <value>]*\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003921 default:
Willy Tarreau9d008692019-08-09 11:21:01 +02003922 return cli_err(appctx, "Unknown action\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003923 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003924}
3925
3926/* This function is used to deal with table operations (dump or clear depending
3927 * on the action stored in appctx->private). It returns 0 if the output buffer is
3928 * full and it needs to be called again, otherwise non-zero.
3929 */
3930static int cli_io_handler_table(struct appctx *appctx)
3931{
3932 struct stream_interface *si = appctx->owner;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003933 struct stream *s = si_strm(si);
3934 struct ebmb_node *eb;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003935 int skip_entry;
Willy Tarreaua24bc782016-12-14 15:50:35 +01003936 int show = appctx->ctx.table.action == STK_CLI_ACT_SHOW;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003937
3938 /*
3939 * We have 3 possible states in appctx->st2 :
3940 * - STAT_ST_INIT : the first call
3941 * - STAT_ST_INFO : the proxy pointer points to the next table to
3942 * dump, the entry pointer is NULL ;
3943 * - STAT_ST_LIST : the proxy pointer points to the current table
3944 * and the entry pointer points to the next entry to be dumped,
3945 * and the refcount on the next entry is held ;
3946 * - STAT_ST_END : nothing left to dump, the buffer may contain some
3947 * data though.
3948 */
3949
3950 if (unlikely(si_ic(si)->flags & (CF_WRITE_ERROR|CF_SHUTW))) {
3951 /* in case of abort, remove any refcount we might have set on an entry */
3952 if (appctx->st2 == STAT_ST_LIST) {
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003953 stksess_kill_if_expired(appctx->ctx.table.t, appctx->ctx.table.entry, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003954 }
3955 return 1;
3956 }
3957
3958 chunk_reset(&trash);
3959
3960 while (appctx->st2 != STAT_ST_FIN) {
3961 switch (appctx->st2) {
3962 case STAT_ST_INIT:
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003963 appctx->ctx.table.t = appctx->ctx.table.target;
3964 if (!appctx->ctx.table.t)
3965 appctx->ctx.table.t = stktables_list;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003966
3967 appctx->ctx.table.entry = NULL;
3968 appctx->st2 = STAT_ST_INFO;
3969 break;
3970
3971 case STAT_ST_INFO:
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003972 if (!appctx->ctx.table.t ||
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003973 (appctx->ctx.table.target &&
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003974 appctx->ctx.table.t != appctx->ctx.table.target)) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003975 appctx->st2 = STAT_ST_END;
3976 break;
3977 }
3978
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003979 if (appctx->ctx.table.t->size) {
3980 if (show && !table_dump_head_to_buffer(&trash, si, appctx->ctx.table.t, appctx->ctx.table.target))
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003981 return 0;
3982
3983 if (appctx->ctx.table.target &&
William Lallemand07a62f72017-05-24 00:57:40 +02003984 (strm_li(s)->bind_conf->level & ACCESS_LVL_MASK) >= ACCESS_LVL_OPER) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003985 /* dump entries only if table explicitly requested */
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003986 HA_SPIN_LOCK(STK_TABLE_LOCK, &appctx->ctx.table.t->lock);
3987 eb = ebmb_first(&appctx->ctx.table.t->keys);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003988 if (eb) {
3989 appctx->ctx.table.entry = ebmb_entry(eb, struct stksess, key);
3990 appctx->ctx.table.entry->ref_cnt++;
3991 appctx->st2 = STAT_ST_LIST;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003992 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &appctx->ctx.table.t->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003993 break;
3994 }
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003995 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &appctx->ctx.table.t->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003996 }
3997 }
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003998 appctx->ctx.table.t = appctx->ctx.table.t->next;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003999 break;
4000
4001 case STAT_ST_LIST:
4002 skip_entry = 0;
4003
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004004 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &appctx->ctx.table.entry->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004005
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004006 if (appctx->ctx.table.data_type[0] >= 0) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004007 /* we're filtering on some data contents */
4008 void *ptr;
Willy Tarreau2b64a352020-01-22 17:09:47 +01004009 int dt, i;
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004010 signed char op;
4011 long long data, value;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004012
Emeric Brun819fc6f2017-06-13 19:37:32 +02004013
Willy Tarreau2b64a352020-01-22 17:09:47 +01004014 for (i = 0; i < STKTABLE_FILTER_LEN; i++) {
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004015 if (appctx->ctx.table.data_type[i] == -1)
4016 break;
4017 dt = appctx->ctx.table.data_type[i];
4018 ptr = stktable_data_ptr(appctx->ctx.table.t,
4019 appctx->ctx.table.entry,
4020 dt);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004021
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004022 data = 0;
4023 switch (stktable_data_types[dt].std_type) {
4024 case STD_T_SINT:
4025 data = stktable_data_cast(ptr, std_t_sint);
4026 break;
4027 case STD_T_UINT:
4028 data = stktable_data_cast(ptr, std_t_uint);
4029 break;
4030 case STD_T_ULL:
4031 data = stktable_data_cast(ptr, std_t_ull);
4032 break;
4033 case STD_T_FRQP:
4034 data = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
4035 appctx->ctx.table.t->data_arg[dt].u);
4036 break;
4037 }
4038
4039 op = appctx->ctx.table.data_op[i];
4040 value = appctx->ctx.table.value[i];
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004041
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004042 /* skip the entry if the data does not match the test and the value */
4043 if ((data < value &&
4044 (op == STD_OP_EQ || op == STD_OP_GT || op == STD_OP_GE)) ||
4045 (data == value &&
4046 (op == STD_OP_NE || op == STD_OP_GT || op == STD_OP_LT)) ||
4047 (data > value &&
4048 (op == STD_OP_EQ || op == STD_OP_LT || op == STD_OP_LE))) {
4049 skip_entry = 1;
4050 break;
4051 }
4052 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004053 }
4054
4055 if (show && !skip_entry &&
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004056 !table_dump_entry_to_buffer(&trash, si, appctx->ctx.table.t, appctx->ctx.table.entry)) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004057 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &appctx->ctx.table.entry->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004058 return 0;
4059 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004060
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004061 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &appctx->ctx.table.entry->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004062
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004063 HA_SPIN_LOCK(STK_TABLE_LOCK, &appctx->ctx.table.t->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004064 appctx->ctx.table.entry->ref_cnt--;
4065
4066 eb = ebmb_next(&appctx->ctx.table.entry->key);
4067 if (eb) {
4068 struct stksess *old = appctx->ctx.table.entry;
4069 appctx->ctx.table.entry = ebmb_entry(eb, struct stksess, key);
4070 if (show)
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004071 __stksess_kill_if_expired(appctx->ctx.table.t, old);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004072 else if (!skip_entry && !appctx->ctx.table.entry->ref_cnt)
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004073 __stksess_kill(appctx->ctx.table.t, old);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004074 appctx->ctx.table.entry->ref_cnt++;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004075 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &appctx->ctx.table.t->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004076 break;
4077 }
4078
4079
4080 if (show)
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004081 __stksess_kill_if_expired(appctx->ctx.table.t, appctx->ctx.table.entry);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004082 else if (!skip_entry && !appctx->ctx.table.entry->ref_cnt)
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004083 __stksess_kill(appctx->ctx.table.t, appctx->ctx.table.entry);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004084
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004085 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &appctx->ctx.table.t->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004086
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004087 appctx->ctx.table.t = appctx->ctx.table.t->next;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004088 appctx->st2 = STAT_ST_INFO;
4089 break;
4090
4091 case STAT_ST_END:
4092 appctx->st2 = STAT_ST_FIN;
4093 break;
4094 }
4095 }
4096 return 1;
4097}
4098
4099static void cli_release_show_table(struct appctx *appctx)
4100{
4101 if (appctx->st2 == STAT_ST_LIST) {
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004102 stksess_kill_if_expired(appctx->ctx.table.t, appctx->ctx.table.entry, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004103 }
4104}
4105
Willy Tarreau478331d2020-08-28 11:31:31 +02004106static void stkt_late_init(void)
4107{
4108 struct sample_fetch *f;
4109
4110 f = find_sample_fetch("src", strlen("src"));
4111 if (f)
4112 smp_fetch_src = f->process;
4113}
4114
4115INITCALL0(STG_INIT, stkt_late_init);
4116
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004117/* register cli keywords */
4118static struct cli_kw_list cli_kws = {{ },{
Willy Tarreaub205bfd2021-05-07 11:38:37 +02004119 { { "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 },
4120 { { "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 },
4121 { { "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 +01004122 {{},}
4123}};
4124
Willy Tarreau0108d902018-11-25 19:14:37 +01004125INITCALL1(STG_REGISTER, cli_register_kw, &cli_kws);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004126
Thierry FOURNIER236657b2015-08-19 08:25:14 +02004127static struct action_kw_list tcp_conn_kws = { { }, {
Amaury Denoyellee4a617c2021-05-06 15:33:09 +02004128 { "sc-inc-gpc0", parse_inc_gpc0, KWF_MATCH_PREFIX },
4129 { "sc-inc-gpc1", parse_inc_gpc1, KWF_MATCH_PREFIX },
4130 { "sc-set-gpt0", parse_set_gpt0, KWF_MATCH_PREFIX },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02004131 { /* END */ }
4132}};
4133
Willy Tarreau0108d902018-11-25 19:14:37 +01004134INITCALL1(STG_REGISTER, tcp_req_conn_keywords_register, &tcp_conn_kws);
4135
Willy Tarreau620408f2016-10-21 16:37:51 +02004136static struct action_kw_list tcp_sess_kws = { { }, {
Amaury Denoyellee4a617c2021-05-06 15:33:09 +02004137 { "sc-inc-gpc0", parse_inc_gpc0, KWF_MATCH_PREFIX },
4138 { "sc-inc-gpc1", parse_inc_gpc1, KWF_MATCH_PREFIX },
4139 { "sc-set-gpt0", parse_set_gpt0, KWF_MATCH_PREFIX },
Willy Tarreau620408f2016-10-21 16:37:51 +02004140 { /* END */ }
4141}};
4142
Willy Tarreau0108d902018-11-25 19:14:37 +01004143INITCALL1(STG_REGISTER, tcp_req_sess_keywords_register, &tcp_sess_kws);
4144
Thierry FOURNIER236657b2015-08-19 08:25:14 +02004145static struct action_kw_list tcp_req_kws = { { }, {
Amaury Denoyellee4a617c2021-05-06 15:33:09 +02004146 { "sc-inc-gpc0", parse_inc_gpc0, KWF_MATCH_PREFIX },
4147 { "sc-inc-gpc1", parse_inc_gpc1, KWF_MATCH_PREFIX },
4148 { "sc-set-gpt0", parse_set_gpt0, KWF_MATCH_PREFIX },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02004149 { /* END */ }
4150}};
4151
Willy Tarreau0108d902018-11-25 19:14:37 +01004152INITCALL1(STG_REGISTER, tcp_req_cont_keywords_register, &tcp_req_kws);
4153
Thierry FOURNIER236657b2015-08-19 08:25:14 +02004154static struct action_kw_list tcp_res_kws = { { }, {
Amaury Denoyellee4a617c2021-05-06 15:33:09 +02004155 { "sc-inc-gpc0", parse_inc_gpc0, KWF_MATCH_PREFIX },
4156 { "sc-inc-gpc1", parse_inc_gpc1, KWF_MATCH_PREFIX },
4157 { "sc-set-gpt0", parse_set_gpt0, KWF_MATCH_PREFIX },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02004158 { /* END */ }
4159}};
4160
Willy Tarreau0108d902018-11-25 19:14:37 +01004161INITCALL1(STG_REGISTER, tcp_res_cont_keywords_register, &tcp_res_kws);
4162
Thierry FOURNIER236657b2015-08-19 08:25:14 +02004163static struct action_kw_list http_req_kws = { { }, {
Amaury Denoyellee4a617c2021-05-06 15:33:09 +02004164 { "sc-inc-gpc0", parse_inc_gpc0, KWF_MATCH_PREFIX },
4165 { "sc-inc-gpc1", parse_inc_gpc1, KWF_MATCH_PREFIX },
4166 { "sc-set-gpt0", parse_set_gpt0, KWF_MATCH_PREFIX },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02004167 { /* END */ }
4168}};
4169
Willy Tarreau0108d902018-11-25 19:14:37 +01004170INITCALL1(STG_REGISTER, http_req_keywords_register, &http_req_kws);
4171
Thierry FOURNIER236657b2015-08-19 08:25:14 +02004172static struct action_kw_list http_res_kws = { { }, {
Amaury Denoyellee4a617c2021-05-06 15:33:09 +02004173 { "sc-inc-gpc0", parse_inc_gpc0, KWF_MATCH_PREFIX },
4174 { "sc-inc-gpc1", parse_inc_gpc1, KWF_MATCH_PREFIX },
4175 { "sc-set-gpt0", parse_set_gpt0, KWF_MATCH_PREFIX },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02004176 { /* END */ }
4177}};
4178
Willy Tarreau0108d902018-11-25 19:14:37 +01004179INITCALL1(STG_REGISTER, http_res_keywords_register, &http_res_kws);
4180
Willy Tarreau7d562212016-11-25 16:10:05 +01004181/* Note: must not be declared <const> as its list will be overwritten.
4182 * Please take care of keeping this list alphabetically sorted.
4183 */
4184static struct sample_fetch_kw_list smp_fetch_keywords = {ILH, {
4185 { "sc_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4186 { "sc_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4187 { "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 +01004188 { "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 +01004189 { "sc_conn_cnt", smp_fetch_sc_conn_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4190 { "sc_conn_cur", smp_fetch_sc_conn_cur, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4191 { "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 +01004192 { "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 +01004193 { "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 +01004194 { "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 +01004195 { "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 +01004196 { "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 +01004197 { "sc_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4198 { "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 +01004199 { "sc_http_fail_cnt", smp_fetch_sc_http_fail_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4200 { "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 +01004201 { "sc_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4202 { "sc_http_req_rate", smp_fetch_sc_http_req_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4203 { "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 +01004204 { "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 +01004205 { "sc_kbytes_in", smp_fetch_sc_kbytes_in, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4206 { "sc_kbytes_out", smp_fetch_sc_kbytes_out, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4207 { "sc_sess_cnt", smp_fetch_sc_sess_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4208 { "sc_sess_rate", smp_fetch_sc_sess_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4209 { "sc_tracked", smp_fetch_sc_tracked, ARG2(1,SINT,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
4210 { "sc_trackers", smp_fetch_sc_trackers, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4211 { "sc0_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4212 { "sc0_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4213 { "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 +01004214 { "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 +01004215 { "sc0_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4216 { "sc0_conn_cur", smp_fetch_sc_conn_cur, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4217 { "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 +01004218 { "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 +01004219 { "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 +01004220 { "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 +01004221 { "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 +01004222 { "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 +01004223 { "sc0_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4224 { "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 +01004225 { "sc0_http_fail_cnt", smp_fetch_sc_http_fail_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4226 { "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 +01004227 { "sc0_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4228 { "sc0_http_req_rate", smp_fetch_sc_http_req_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4229 { "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 +01004230 { "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 +01004231 { "sc0_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4232 { "sc0_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4233 { "sc0_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4234 { "sc0_sess_rate", smp_fetch_sc_sess_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4235 { "sc0_tracked", smp_fetch_sc_tracked, ARG1(0,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
4236 { "sc0_trackers", smp_fetch_sc_trackers, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4237 { "sc1_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4238 { "sc1_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4239 { "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 +01004240 { "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 +01004241 { "sc1_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4242 { "sc1_conn_cur", smp_fetch_sc_conn_cur, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4243 { "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 +01004244 { "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 +01004245 { "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 +01004246 { "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 +01004247 { "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 +01004248 { "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 +01004249 { "sc1_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4250 { "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 +01004251 { "sc1_http_fail_cnt", smp_fetch_sc_http_fail_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4252 { "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 +01004253 { "sc1_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4254 { "sc1_http_req_rate", smp_fetch_sc_http_req_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4255 { "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 +01004256 { "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 +01004257 { "sc1_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4258 { "sc1_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4259 { "sc1_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4260 { "sc1_sess_rate", smp_fetch_sc_sess_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4261 { "sc1_tracked", smp_fetch_sc_tracked, ARG1(0,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
4262 { "sc1_trackers", smp_fetch_sc_trackers, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4263 { "sc2_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4264 { "sc2_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4265 { "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 +01004266 { "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 +01004267 { "sc2_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4268 { "sc2_conn_cur", smp_fetch_sc_conn_cur, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4269 { "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 +01004270 { "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 +01004271 { "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 +01004272 { "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 +01004273 { "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 +01004274 { "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 +01004275 { "sc2_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4276 { "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 +01004277 { "sc2_http_fail_cnt", smp_fetch_sc_http_fail_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4278 { "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 +01004279 { "sc2_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4280 { "sc2_http_req_rate", smp_fetch_sc_http_req_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4281 { "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 +01004282 { "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 +01004283 { "sc2_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4284 { "sc2_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4285 { "sc2_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4286 { "sc2_sess_rate", smp_fetch_sc_sess_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4287 { "sc2_tracked", smp_fetch_sc_tracked, ARG1(0,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
4288 { "sc2_trackers", smp_fetch_sc_trackers, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4289 { "src_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4290 { "src_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4291 { "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 +01004292 { "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 +01004293 { "src_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4294 { "src_conn_cur", smp_fetch_sc_conn_cur, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4295 { "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 +01004296 { "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 +01004297 { "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 +01004298 { "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 +01004299 { "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 +01004300 { "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 +01004301 { "src_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4302 { "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 +01004303 { "src_http_fail_cnt", smp_fetch_sc_http_fail_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4304 { "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 +01004305 { "src_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4306 { "src_http_req_rate", smp_fetch_sc_http_req_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4307 { "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 +01004308 { "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 +01004309 { "src_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4310 { "src_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4311 { "src_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4312 { "src_sess_rate", smp_fetch_sc_sess_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4313 { "src_updt_conn_cnt", smp_fetch_src_updt_conn_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4314 { "table_avl", smp_fetch_table_avl, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4315 { "table_cnt", smp_fetch_table_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4316 { /* END */ },
4317}};
4318
Willy Tarreau0108d902018-11-25 19:14:37 +01004319INITCALL1(STG_REGISTER, sample_register_fetches, &smp_fetch_keywords);
Willy Tarreau7d562212016-11-25 16:10:05 +01004320
Willy Tarreaud9f316a2014-07-10 14:03:38 +02004321/* Note: must not be declared <const> as its list will be overwritten */
4322static struct sample_conv_kw_list sample_conv_kws = {ILH, {
Willy Tarreau2d17db52016-05-25 17:16:38 +02004323 { "in_table", sample_conv_in_table, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_BOOL },
4324 { "table_bytes_in_rate", sample_conv_table_bytes_in_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4325 { "table_bytes_out_rate", sample_conv_table_bytes_out_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4326 { "table_conn_cnt", sample_conv_table_conn_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4327 { "table_conn_cur", sample_conv_table_conn_cur, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4328 { "table_conn_rate", sample_conv_table_conn_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4329 { "table_gpt0", sample_conv_table_gpt0, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4330 { "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 +01004331 { "table_gpc1", sample_conv_table_gpc1, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
Willy Tarreau2d17db52016-05-25 17:16:38 +02004332 { "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 +01004333 { "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 +02004334 { "table_http_err_cnt", sample_conv_table_http_err_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4335 { "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 +01004336 { "table_http_fail_cnt", sample_conv_table_http_fail_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4337 { "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 +02004338 { "table_http_req_cnt", sample_conv_table_http_req_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4339 { "table_http_req_rate", sample_conv_table_http_req_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4340 { "table_kbytes_in", sample_conv_table_kbytes_in, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4341 { "table_kbytes_out", sample_conv_table_kbytes_out, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4342 { "table_server_id", sample_conv_table_server_id, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4343 { "table_sess_cnt", sample_conv_table_sess_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4344 { "table_sess_rate", sample_conv_table_sess_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4345 { "table_trackers", sample_conv_table_trackers, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
Willy Tarreaud9f316a2014-07-10 14:03:38 +02004346 { /* END */ },
4347}};
4348
Willy Tarreau0108d902018-11-25 19:14:37 +01004349INITCALL1(STG_REGISTER, sample_register_convs, &sample_conv_kws);