blob: 7fcda827bb7772f21fa72686b8322ea12afe3b67 [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) {
Emeric Brun0e3457b2021-06-30 17:18:28 +0200101 dict_entry_unref(&server_key_dict, stktable_data_cast(data, std_t_dict));
102 stktable_data_cast(data, std_t_dict) = NULL;
Thayne McCombs92149f92020-11-20 01:28:26 -0700103 }
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
Willy Tarreau86257dc2010-06-06 12:57:10 +0200225 if (!eb || eb->key > ts->exp.key)
226 eb = &ts->exp;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100227
228 continue;
229 }
Emeric Brun3bd697e2010-01-04 15:23:48 +0100230
Willy Tarreauaea940e2010-06-06 11:56:36 +0200231 /* session expired, trash it */
Willy Tarreau86257dc2010-06-06 12:57:10 +0200232 ebmb_delete(&ts->key);
Emeric Brun85e77c72010-09-23 18:16:52 +0200233 eb32_delete(&ts->upd);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200234 __stksess_free(t, ts);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100235 batched++;
236 }
237
238 return batched;
239}
240
241/*
Emeric Brun819fc6f2017-06-13 19:37:32 +0200242 * Trash oldest <to_batch> sticky sessions from table <t>
243 * Returns number of trashed sticky sessions.
244 * This function locks the table
245 */
246int stktable_trash_oldest(struct stktable *t, int to_batch)
247{
248 int ret;
249
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100250 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200251 ret = __stktable_trash_oldest(t, to_batch);
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100252 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200253
254 return ret;
255}
256/*
Willy Tarreauaea940e2010-06-06 11:56:36 +0200257 * Allocate and initialise a new sticky session.
258 * The new sticky session is returned or NULL in case of lack of memory.
259 * Sticky sessions should only be allocated this way, and must be freed using
Willy Tarreaua7b46b52013-04-11 16:55:37 +0200260 * stksess_free(). Table <t>'s sticky session counter is increased. If <key>
261 * is not NULL, it is assigned to the new session.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100262 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200263struct stksess *__stksess_new(struct stktable *t, struct stktable_key *key)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100264{
265 struct stksess *ts;
266
267 if (unlikely(t->current == t->size)) {
268 if ( t->nopurge )
269 return NULL;
270
Emeric Brun819fc6f2017-06-13 19:37:32 +0200271 if (!__stktable_trash_oldest(t, (t->size >> 8) + 1))
Emeric Brun3bd697e2010-01-04 15:23:48 +0100272 return NULL;
273 }
274
Willy Tarreaubafbe012017-11-24 17:34:44 +0100275 ts = pool_alloc(t->pool);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100276 if (ts) {
277 t->current++;
Olivier Houchard52dabbc2018-11-14 17:54:36 +0100278 ts = (void *)ts + round_ptr_size(t->data_size);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200279 __stksess_init(t, ts);
Willy Tarreaua7b46b52013-04-11 16:55:37 +0200280 if (key)
281 stksess_setkey(t, ts, key);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100282 }
283
284 return ts;
285}
Emeric Brun819fc6f2017-06-13 19:37:32 +0200286/*
287 * Allocate and initialise a new sticky session.
288 * The new sticky session is returned or NULL in case of lack of memory.
289 * Sticky sessions should only be allocated this way, and must be freed using
290 * stksess_free(). Table <t>'s sticky session counter is increased. If <key>
291 * is not NULL, it is assigned to the new session.
292 * This function locks the table
293 */
294struct stksess *stksess_new(struct stktable *t, struct stktable_key *key)
295{
296 struct stksess *ts;
297
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100298 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200299 ts = __stksess_new(t, key);
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100300 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200301
302 return ts;
303}
Emeric Brun3bd697e2010-01-04 15:23:48 +0100304
305/*
Willy Tarreauf16d2b82010-06-06 15:38:59 +0200306 * Looks in table <t> for a sticky session matching key <key>.
Willy Tarreauaea940e2010-06-06 11:56:36 +0200307 * Returns pointer on requested sticky session or NULL if none was found.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100308 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200309struct stksess *__stktable_lookup_key(struct stktable *t, struct stktable_key *key)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100310{
311 struct ebmb_node *eb;
312
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200313 if (t->type == SMP_T_STR)
Emeric Brun485479d2010-09-23 18:02:19 +0200314 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 +0100315 else
316 eb = ebmb_lookup(&t->keys, key->key, t->key_size);
317
318 if (unlikely(!eb)) {
319 /* no session found */
320 return NULL;
321 }
322
Willy Tarreau86257dc2010-06-06 12:57:10 +0200323 return ebmb_entry(eb, struct stksess, key);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100324}
325
Emeric Brun819fc6f2017-06-13 19:37:32 +0200326/*
327 * Looks in table <t> for a sticky session matching key <key>.
328 * Returns pointer on requested sticky session or NULL if none was found.
329 * The refcount of the found entry is increased and this function
330 * is protected using the table lock
Willy Tarreau1f7e9252010-06-20 12:27:21 +0200331 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200332struct stksess *stktable_lookup_key(struct stktable *t, struct stktable_key *key)
Willy Tarreau1f7e9252010-06-20 12:27:21 +0200333{
334 struct stksess *ts;
335
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100336 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200337 ts = __stktable_lookup_key(t, key);
338 if (ts)
339 ts->ref_cnt++;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100340 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Willy Tarreau1f7e9252010-06-20 12:27:21 +0200341
Willy Tarreau1f7e9252010-06-20 12:27:21 +0200342 return ts;
343}
344
Willy Tarreauf16d2b82010-06-06 15:38:59 +0200345/*
346 * Looks in table <t> for a sticky session with same key as <ts>.
347 * Returns pointer on requested sticky session or NULL if none was found.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100348 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200349struct stksess *__stktable_lookup(struct stktable *t, struct stksess *ts)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100350{
Emeric Brun3bd697e2010-01-04 15:23:48 +0100351 struct ebmb_node *eb;
352
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200353 if (t->type == SMP_T_STR)
Willy Tarreau86257dc2010-06-06 12:57:10 +0200354 eb = ebst_lookup(&(t->keys), (char *)ts->key.key);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100355 else
Willy Tarreau86257dc2010-06-06 12:57:10 +0200356 eb = ebmb_lookup(&(t->keys), ts->key.key, t->key_size);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100357
Willy Tarreauf16d2b82010-06-06 15:38:59 +0200358 if (unlikely(!eb))
359 return NULL;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100360
Willy Tarreauf16d2b82010-06-06 15:38:59 +0200361 return ebmb_entry(eb, struct stksess, key);
362}
Emeric Brun3bd697e2010-01-04 15:23:48 +0100363
Emeric Brun819fc6f2017-06-13 19:37:32 +0200364/*
365 * Looks in table <t> for a sticky session with same key as <ts>.
366 * Returns pointer on requested sticky session or NULL if none was found.
367 * The refcount of the found entry is increased and this function
368 * is protected using the table lock
369 */
370struct stksess *stktable_lookup(struct stktable *t, struct stksess *ts)
371{
372 struct stksess *lts;
373
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100374 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200375 lts = __stktable_lookup(t, ts);
376 if (lts)
377 lts->ref_cnt++;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100378 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200379
380 return lts;
381}
382
Willy Tarreaucb183642010-06-06 17:58:34 +0200383/* Update the expiration timer for <ts> but do not touch its expiration node.
384 * The table's expiration timer is updated if set.
Emeric Brun819fc6f2017-06-13 19:37:32 +0200385 * The node will be also inserted into the update tree if needed, at a position
386 * depending if the update is a local or coming from a remote node
Willy Tarreaucb183642010-06-06 17:58:34 +0200387 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200388void __stktable_touch_with_exp(struct stktable *t, struct stksess *ts, int local, int expire)
Willy Tarreaucb183642010-06-06 17:58:34 +0200389{
Emeric Brun85e77c72010-09-23 18:16:52 +0200390 struct eb32_node * eb;
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200391 ts->expire = expire;
Willy Tarreaucb183642010-06-06 17:58:34 +0200392 if (t->expire) {
393 t->exp_task->expire = t->exp_next = tick_first(ts->expire, t->exp_next);
394 task_queue(t->exp_task);
395 }
Emeric Brun85e77c72010-09-23 18:16:52 +0200396
Emeric Brun819fc6f2017-06-13 19:37:32 +0200397 /* If sync is enabled */
398 if (t->sync_task) {
399 if (local) {
400 /* If this entry is not in the tree
401 or not scheduled for at least one peer */
402 if (!ts->upd.node.leaf_p
403 || (int)(t->commitupdate - ts->upd.key) >= 0
404 || (int)(ts->upd.key - t->localupdate) >= 0) {
405 ts->upd.key = ++t->update;
406 t->localupdate = t->update;
407 eb32_delete(&ts->upd);
408 eb = eb32_insert(&t->updates, &ts->upd);
409 if (eb != &ts->upd) {
410 eb32_delete(eb);
411 eb32_insert(&t->updates, &ts->upd);
412 }
Emeric Brunaaf58602015-06-15 17:23:30 +0200413 }
Emeric Brun819fc6f2017-06-13 19:37:32 +0200414 task_wakeup(t->sync_task, TASK_WOKEN_MSG);
Emeric Brun85e77c72010-09-23 18:16:52 +0200415 }
Emeric Brun819fc6f2017-06-13 19:37:32 +0200416 else {
417 /* If this entry is not in the tree */
418 if (!ts->upd.node.leaf_p) {
419 ts->upd.key= (++t->update)+(2147483648U);
420 eb = eb32_insert(&t->updates, &ts->upd);
421 if (eb != &ts->upd) {
422 eb32_delete(eb);
423 eb32_insert(&t->updates, &ts->upd);
424 }
425 }
426 }
Emeric Brun85e77c72010-09-23 18:16:52 +0200427 }
Willy Tarreaucb183642010-06-06 17:58:34 +0200428}
429
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200430/* Update the expiration timer for <ts> but do not touch its expiration node.
Emeric Brun819fc6f2017-06-13 19:37:32 +0200431 * The table's expiration timer is updated using the date of expiration coming from
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200432 * <t> stick-table configuration.
Emeric Brun819fc6f2017-06-13 19:37:32 +0200433 * The node will be also inserted into the update tree if needed, at a position
434 * considering the update is coming from a remote node
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200435 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200436void stktable_touch_remote(struct stktable *t, struct stksess *ts, int decrefcnt)
437{
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100438 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200439 __stktable_touch_with_exp(t, ts, 0, ts->expire);
440 if (decrefcnt)
441 ts->ref_cnt--;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100442 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200443}
444
445/* Update the expiration timer for <ts> but do not touch its expiration node.
446 * The table's expiration timer is updated using the date of expiration coming from
447 * <t> stick-table configuration.
448 * The node will be also inserted into the update tree if needed, at a position
449 * considering the update was made locally
450 */
451void stktable_touch_local(struct stktable *t, struct stksess *ts, int decrefcnt)
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200452{
453 int expire = tick_add(now_ms, MS_TO_TICKS(t->expire));
454
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100455 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200456 __stktable_touch_with_exp(t, ts, 1, expire);
457 if (decrefcnt)
458 ts->ref_cnt--;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100459 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200460}
Willy Tarreau43e90352018-06-27 06:25:57 +0200461/* Just decrease the ref_cnt of the current session. Does nothing if <ts> is NULL */
462static void stktable_release(struct stktable *t, struct stksess *ts)
Emeric Brun819fc6f2017-06-13 19:37:32 +0200463{
Willy Tarreau43e90352018-06-27 06:25:57 +0200464 if (!ts)
465 return;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100466 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200467 ts->ref_cnt--;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100468 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200469}
470
Willy Tarreauf16d2b82010-06-06 15:38:59 +0200471/* Insert new sticky session <ts> in the table. It is assumed that it does not
472 * yet exist (the caller must check this). The table's timeout is updated if it
473 * is set. <ts> is returned.
474 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200475void __stktable_store(struct stktable *t, struct stksess *ts)
Willy Tarreauf16d2b82010-06-06 15:38:59 +0200476{
Emeric Brun3bd697e2010-01-04 15:23:48 +0100477
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200478 ebmb_insert(&t->keys, &ts->key, t->key_size);
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200479 ts->exp.key = ts->expire;
480 eb32_insert(&t->exps, &ts->exp);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200481 if (t->expire) {
482 t->exp_task->expire = t->exp_next = tick_first(ts->expire, t->exp_next);
483 task_queue(t->exp_task);
484 }
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200485}
486
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200487/* Returns a valid or initialized stksess for the specified stktable_key in the
488 * specified table, or NULL if the key was NULL, or if no entry was found nor
489 * could be created. The entry's expiration is updated.
490 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200491struct stksess *__stktable_get_entry(struct stktable *table, struct stktable_key *key)
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200492{
493 struct stksess *ts;
494
495 if (!key)
496 return NULL;
497
Emeric Brun819fc6f2017-06-13 19:37:32 +0200498 ts = __stktable_lookup_key(table, key);
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200499 if (ts == NULL) {
500 /* entry does not exist, initialize a new one */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200501 ts = __stksess_new(table, key);
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200502 if (!ts)
503 return NULL;
Emeric Brun819fc6f2017-06-13 19:37:32 +0200504 __stktable_store(table, ts);
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200505 }
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200506 return ts;
507}
Emeric Brun819fc6f2017-06-13 19:37:32 +0200508/* Returns a valid or initialized stksess for the specified stktable_key in the
509 * specified table, or NULL if the key was NULL, or if no entry was found nor
510 * could be created. The entry's expiration is updated.
511 * This function locks the table, and the refcount of the entry is increased.
512 */
513struct stksess *stktable_get_entry(struct stktable *table, struct stktable_key *key)
514{
515 struct stksess *ts;
516
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100517 HA_SPIN_LOCK(STK_TABLE_LOCK, &table->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200518 ts = __stktable_get_entry(table, key);
519 if (ts)
520 ts->ref_cnt++;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100521 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &table->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200522
523 return ts;
524}
525
526/* Lookup for an entry with the same key and store the submitted
527 * stksess if not found.
528 */
529struct stksess *__stktable_set_entry(struct stktable *table, struct stksess *nts)
530{
531 struct stksess *ts;
532
533 ts = __stktable_lookup(table, nts);
534 if (ts == NULL) {
535 ts = nts;
536 __stktable_store(table, ts);
537 }
538 return ts;
539}
540
541/* Lookup for an entry with the same key and store the submitted
542 * stksess if not found.
543 * This function locks the table, and the refcount of the entry is increased.
544 */
545struct stksess *stktable_set_entry(struct stktable *table, struct stksess *nts)
546{
547 struct stksess *ts;
548
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100549 HA_SPIN_LOCK(STK_TABLE_LOCK, &table->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200550 ts = __stktable_set_entry(table, nts);
551 ts->ref_cnt++;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100552 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &table->lock);
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200553
Emeric Brun819fc6f2017-06-13 19:37:32 +0200554 return ts;
555}
Emeric Brun3bd697e2010-01-04 15:23:48 +0100556/*
Willy Tarreauaea940e2010-06-06 11:56:36 +0200557 * Trash expired sticky sessions from table <t>. The next expiration date is
558 * returned.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100559 */
560static int stktable_trash_expired(struct stktable *t)
561{
562 struct stksess *ts;
563 struct eb32_node *eb;
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200564 int looped = 0;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100565
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100566 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100567 eb = eb32_lookup_ge(&t->exps, now_ms - TIMER_LOOK_BACK);
568
569 while (1) {
570 if (unlikely(!eb)) {
571 /* we might have reached the end of the tree, typically because
572 * <now_ms> is in the first half and we're first scanning the last
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200573 * half. Let's loop back to the beginning of the tree now if we
574 * have not yet visited it.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100575 */
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200576 if (looped)
577 break;
578 looped = 1;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100579 eb = eb32_first(&t->exps);
580 if (likely(!eb))
581 break;
582 }
583
584 if (likely(tick_is_lt(now_ms, eb->key))) {
585 /* timer not expired yet, revisit it later */
586 t->exp_next = eb->key;
Willy Tarreau4d5f13c2017-11-05 11:04:47 +0100587 goto out_unlock;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100588 }
589
590 /* timer looks expired, detach it from the queue */
Willy Tarreau86257dc2010-06-06 12:57:10 +0200591 ts = eb32_entry(eb, struct stksess, exp);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100592 eb = eb32_next(eb);
593
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200594 /* don't delete an entry which is currently referenced */
595 if (ts->ref_cnt)
596 continue;
597
Willy Tarreau86257dc2010-06-06 12:57:10 +0200598 eb32_delete(&ts->exp);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100599
600 if (!tick_is_expired(ts->expire, now_ms)) {
601 if (!tick_isset(ts->expire))
602 continue;
603
Willy Tarreau86257dc2010-06-06 12:57:10 +0200604 ts->exp.key = ts->expire;
605 eb32_insert(&t->exps, &ts->exp);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100606
Willy Tarreau86257dc2010-06-06 12:57:10 +0200607 if (!eb || eb->key > ts->exp.key)
608 eb = &ts->exp;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100609 continue;
610 }
611
612 /* session expired, trash it */
Willy Tarreau86257dc2010-06-06 12:57:10 +0200613 ebmb_delete(&ts->key);
Emeric Brun85e77c72010-09-23 18:16:52 +0200614 eb32_delete(&ts->upd);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200615 __stksess_free(t, ts);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100616 }
617
618 /* We have found no task to expire in any tree */
619 t->exp_next = TICK_ETERNITY;
Willy Tarreau4d5f13c2017-11-05 11:04:47 +0100620out_unlock:
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100621 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100622 return t->exp_next;
623}
624
625/*
Willy Tarreauaea940e2010-06-06 11:56:36 +0200626 * Task processing function to trash expired sticky sessions. A pointer to the
627 * task itself is returned since it never dies.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100628 */
Willy Tarreau144f84a2021-03-02 16:09:26 +0100629struct task *process_table_expire(struct task *task, void *context, unsigned int state)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100630{
Olivier Houchard9f6af332018-05-25 14:04:04 +0200631 struct stktable *t = context;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100632
633 task->expire = stktable_trash_expired(t);
634 return task;
635}
636
Willy Tarreauaea940e2010-06-06 11:56:36 +0200637/* Perform minimal stick table intializations, report 0 in case of error, 1 if OK. */
Emeric Brun3bd697e2010-01-04 15:23:48 +0100638int stktable_init(struct stktable *t)
639{
Remi Tricot-Le Breton208ff012021-05-12 17:39:04 +0200640 int peers_retval = 0;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100641 if (t->size) {
Emeric Brun819fc6f2017-06-13 19:37:32 +0200642 t->keys = EB_ROOT_UNIQUE;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100643 memset(&t->exps, 0, sizeof(t->exps));
Emeric Brun1c6235d2015-12-16 15:28:12 +0100644 t->updates = EB_ROOT_UNIQUE;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100645 HA_SPIN_INIT(&t->lock);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100646
Olivier Houchard52dabbc2018-11-14 17:54:36 +0100647 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 +0100648
649 t->exp_next = TICK_ETERNITY;
650 if ( t->expire ) {
Emeric Brunc60def82017-09-27 14:59:38 +0200651 t->exp_task = task_new(MAX_THREADS_MASK);
Willy Tarreau848522f2018-10-15 11:12:15 +0200652 if (!t->exp_task)
653 return 0;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100654 t->exp_task->process = process_table_expire;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100655 t->exp_task->context = (void *)t;
656 }
Willy Tarreauc3914d42020-09-24 08:39:22 +0200657 if (t->peers.p && t->peers.p->peers_fe && !t->peers.p->peers_fe->disabled) {
Remi Tricot-Le Breton208ff012021-05-12 17:39:04 +0200658 peers_retval = peers_register_table(t->peers.p, t);
Emeric Brun32da3c42010-09-23 18:39:19 +0200659 }
660
Remi Tricot-Le Breton208ff012021-05-12 17:39:04 +0200661 return (t->pool != NULL) && !peers_retval;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100662 }
663 return 1;
664}
665
666/*
667 * Configuration keywords of known table types
668 */
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200669struct stktable_type stktable_types[SMP_TYPES] = {
670 [SMP_T_SINT] = { "integer", 0, 4 },
671 [SMP_T_IPV4] = { "ip", 0, 4 },
672 [SMP_T_IPV6] = { "ipv6", 0, 16 },
673 [SMP_T_STR] = { "string", STK_F_CUSTOM_KEYSIZE, 32 },
674 [SMP_T_BIN] = { "binary", STK_F_CUSTOM_KEYSIZE, 32 }
675};
Emeric Brun3bd697e2010-01-04 15:23:48 +0100676
677/*
678 * Parse table type configuration.
679 * Returns 0 on successful parsing, else 1.
680 * <myidx> is set at next configuration <args> index.
681 */
682int stktable_parse_type(char **args, int *myidx, unsigned long *type, size_t *key_size)
683{
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200684 for (*type = 0; *type < SMP_TYPES; (*type)++) {
685 if (!stktable_types[*type].kw)
686 continue;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100687 if (strcmp(args[*myidx], stktable_types[*type].kw) != 0)
688 continue;
689
690 *key_size = stktable_types[*type].default_size;
691 (*myidx)++;
692
Willy Tarreauaea940e2010-06-06 11:56:36 +0200693 if (stktable_types[*type].flags & STK_F_CUSTOM_KEYSIZE) {
Emeric Brun3bd697e2010-01-04 15:23:48 +0100694 if (strcmp("len", args[*myidx]) == 0) {
695 (*myidx)++;
696 *key_size = atol(args[*myidx]);
Emeric Brun485479d2010-09-23 18:02:19 +0200697 if (!*key_size)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100698 break;
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200699 if (*type == SMP_T_STR) {
Emeric Brun485479d2010-09-23 18:02:19 +0200700 /* null terminated string needs +1 for '\0'. */
701 (*key_size)++;
702 }
Emeric Brun3bd697e2010-01-04 15:23:48 +0100703 (*myidx)++;
704 }
705 }
706 return 0;
707 }
708 return 1;
709}
710
Emeric Brunc64a2a32021-06-30 18:01:02 +0200711/* reserve some space for data type <type>, there is 2 optionnals
712 * argument at <sa> and <sa2> to configure this data type and
713 * they can be NULL if unused for a given type.
714 * Returns PE_NONE (0) if OK or an error code among :
Willy Tarreau3b63ca22021-05-08 14:10:42 +0200715 * - PE_ENUM_OOR if <type> does not exist
716 * - PE_EXIST if <type> is already registered
Emeric Brunc64a2a32021-06-30 18:01:02 +0200717 * - PE_ARG_NOT_USE if <sa>/<sa2> was provided but not expected
718 * - PE_ARG_MISSING if <sa>/<sa2> was expected but not provided
719 * - PE_ARG_VALUE_OOR if type is an array and <sa> it out of array size range.
Willy Tarreau3b63ca22021-05-08 14:10:42 +0200720 */
Emeric Brunc64a2a32021-06-30 18:01:02 +0200721int stktable_alloc_data_type(struct stktable *t, int type, const char *sa, const char *sa2)
722
Willy Tarreau3b63ca22021-05-08 14:10:42 +0200723{
724 if (type >= STKTABLE_DATA_TYPES)
725 return PE_ENUM_OOR;
726
727 if (t->data_ofs[type])
728 /* already allocated */
729 return PE_EXIST;
730
Emeric Brunc64a2a32021-06-30 18:01:02 +0200731 t->data_nbelem[type] = 1;
732 if (stktable_data_types[type].is_array) {
733 /* arrays take their element count on first argument */
734 if (!sa)
735 return PE_ARG_MISSING;
736 t->data_nbelem[type] = atoi(sa);
737 if (!t->data_nbelem[type] || (t->data_nbelem[type] > STKTABLE_MAX_DT_ARRAY_SIZE))
738 return PE_ARG_VALUE_OOR;
739 sa = sa2;
740 }
741
Willy Tarreau3b63ca22021-05-08 14:10:42 +0200742 switch (stktable_data_types[type].arg_type) {
743 case ARG_T_NONE:
744 if (sa)
745 return PE_ARG_NOT_USED;
746 break;
747 case ARG_T_INT:
748 if (!sa)
749 return PE_ARG_MISSING;
750 t->data_arg[type].i = atoi(sa);
751 break;
752 case ARG_T_DELAY:
753 if (!sa)
754 return PE_ARG_MISSING;
755 sa = parse_time_err(sa, &t->data_arg[type].u, TIME_UNIT_MS);
756 if (sa)
757 return PE_ARG_INVC; /* invalid char */
758 break;
759 }
760
Emeric Brunc64a2a32021-06-30 18:01:02 +0200761 t->data_size += t->data_nbelem[type] * stktable_type_size(stktable_data_types[type].std_type);
Willy Tarreau3b63ca22021-05-08 14:10:42 +0200762 t->data_ofs[type] = -t->data_size;
763 return PE_NONE;
764}
765
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100766/*
Frédéric Lécaillec02766a2019-03-20 15:06:55 +0100767 * Parse a line with <linenum> as number in <file> configuration file to configure
768 * the stick-table with <t> as address and <id> as ID.
769 * <peers> provides the "peers" section pointer only if this function is called
770 * from a "peers" section.
771 * <nid> is the stick-table name which is sent over the network. It must be equal
772 * to <id> if this stick-table is parsed from a proxy section, and prefixed by <peers>
773 * "peers" section name followed by a '/' character if parsed from a "peers" section.
Ilya Shipitsind4259502020-04-08 01:07:56 +0500774 * This is the responsibility of the caller to check this.
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100775 * Return an error status with ERR_* flags set if required, 0 if no error was encountered.
776 */
777int parse_stick_table(const char *file, int linenum, char **args,
Frédéric Lécaillec02766a2019-03-20 15:06:55 +0100778 struct stktable *t, char *id, char *nid, struct peers *peers)
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100779{
780 int err_code = 0;
781 int idx = 1;
782 unsigned int val;
783
784 if (!id || !*id) {
785 ha_alert("parsing [%s:%d] : %s: ID not provided.\n", file, linenum, args[0]);
786 err_code |= ERR_ALERT | ERR_ABORT;
787 goto out;
788 }
789
790 /* Store the "peers" section if this function is called from a "peers" section. */
791 if (peers) {
792 t->peers.p = peers;
793 idx++;
794 }
795
796 t->id = id;
Frédéric Lécaillec02766a2019-03-20 15:06:55 +0100797 t->nid = nid;
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100798 t->type = (unsigned int)-1;
799 t->conf.file = file;
800 t->conf.line = linenum;
801
802 while (*args[idx]) {
803 const char *err;
804
805 if (strcmp(args[idx], "size") == 0) {
806 idx++;
807 if (!*(args[idx])) {
808 ha_alert("parsing [%s:%d] : %s: missing argument after '%s'.\n",
809 file, linenum, args[0], args[idx-1]);
810 err_code |= ERR_ALERT | ERR_FATAL;
811 goto out;
812 }
813 if ((err = parse_size_err(args[idx], &t->size))) {
814 ha_alert("parsing [%s:%d] : %s: unexpected character '%c' in argument of '%s'.\n",
815 file, linenum, args[0], *err, args[idx-1]);
816 err_code |= ERR_ALERT | ERR_FATAL;
817 goto out;
818 }
819 idx++;
820 }
821 /* This argument does not exit in "peers" section. */
822 else if (!peers && strcmp(args[idx], "peers") == 0) {
823 idx++;
824 if (!*(args[idx])) {
825 ha_alert("parsing [%s:%d] : %s: missing argument after '%s'.\n",
826 file, linenum, args[0], args[idx-1]);
827 err_code |= ERR_ALERT | ERR_FATAL;
828 goto out;
829 }
830 t->peers.name = strdup(args[idx++]);
831 }
832 else if (strcmp(args[idx], "expire") == 0) {
833 idx++;
834 if (!*(args[idx])) {
835 ha_alert("parsing [%s:%d] : %s: missing argument after '%s'.\n",
836 file, linenum, args[0], args[idx-1]);
837 err_code |= ERR_ALERT | ERR_FATAL;
838 goto out;
839 }
840 err = parse_time_err(args[idx], &val, TIME_UNIT_MS);
Willy Tarreau9faebe32019-06-07 19:00:37 +0200841 if (err == PARSE_TIME_OVER) {
842 ha_alert("parsing [%s:%d]: %s: timer overflow in argument <%s> to <%s>, maximum value is 2147483647 ms (~24.8 days).\n",
843 file, linenum, args[0], args[idx], args[idx-1]);
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100844 err_code |= ERR_ALERT | ERR_FATAL;
845 goto out;
846 }
Willy Tarreau9faebe32019-06-07 19:00:37 +0200847 else if (err == PARSE_TIME_UNDER) {
848 ha_alert("parsing [%s:%d]: %s: timer underflow in argument <%s> to <%s>, minimum non-null value is 1 ms.\n",
849 file, linenum, args[0], args[idx], args[idx-1]);
850 err_code |= ERR_ALERT | ERR_FATAL;
851 goto out;
852 }
853 else if (err) {
854 ha_alert("parsing [%s:%d] : %s: unexpected character '%c' in argument of '%s'.\n",
855 file, linenum, args[0], *err, args[idx-1]);
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100856 err_code |= ERR_ALERT | ERR_FATAL;
857 goto out;
858 }
859 t->expire = val;
860 idx++;
861 }
862 else if (strcmp(args[idx], "nopurge") == 0) {
863 t->nopurge = 1;
864 idx++;
865 }
866 else if (strcmp(args[idx], "type") == 0) {
867 idx++;
868 if (stktable_parse_type(args, &idx, &t->type, &t->key_size) != 0) {
869 ha_alert("parsing [%s:%d] : %s: unknown type '%s'.\n",
870 file, linenum, args[0], args[idx]);
871 err_code |= ERR_ALERT | ERR_FATAL;
872 goto out;
873 }
874 /* idx already points to next arg */
875 }
876 else if (strcmp(args[idx], "store") == 0) {
877 int type, err;
Emeric Brunc64a2a32021-06-30 18:01:02 +0200878 char *cw, *nw, *sa, *sa2;
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100879
880 idx++;
881 nw = args[idx];
882 while (*nw) {
883 /* the "store" keyword supports a comma-separated list */
884 cw = nw;
885 sa = NULL; /* store arg */
Emeric Brunc64a2a32021-06-30 18:01:02 +0200886 sa2 = NULL;
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100887 while (*nw && *nw != ',') {
888 if (*nw == '(') {
889 *nw = 0;
890 sa = ++nw;
891 while (*nw != ')') {
892 if (!*nw) {
893 ha_alert("parsing [%s:%d] : %s: missing closing parenthesis after store option '%s'.\n",
894 file, linenum, args[0], cw);
895 err_code |= ERR_ALERT | ERR_FATAL;
896 goto out;
897 }
Emeric Brunc64a2a32021-06-30 18:01:02 +0200898 if (*nw == ',') {
899 *nw = '\0';
900 sa2 = nw + 1;
901 }
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100902 nw++;
903 }
904 *nw = '\0';
905 }
906 nw++;
907 }
908 if (*nw)
909 *nw++ = '\0';
910 type = stktable_get_data_type(cw);
911 if (type < 0) {
912 ha_alert("parsing [%s:%d] : %s: unknown store option '%s'.\n",
913 file, linenum, args[0], cw);
914 err_code |= ERR_ALERT | ERR_FATAL;
915 goto out;
916 }
917
Emeric Brunc64a2a32021-06-30 18:01:02 +0200918 err = stktable_alloc_data_type(t, type, sa, sa2);
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100919 switch (err) {
920 case PE_NONE: break;
921 case PE_EXIST:
922 ha_warning("parsing [%s:%d]: %s: store option '%s' already enabled, ignored.\n",
923 file, linenum, args[0], cw);
924 err_code |= ERR_WARN;
925 break;
926
927 case PE_ARG_MISSING:
928 ha_alert("parsing [%s:%d] : %s: missing argument to store option '%s'.\n",
929 file, linenum, args[0], cw);
930 err_code |= ERR_ALERT | ERR_FATAL;
931 goto out;
932
933 case PE_ARG_NOT_USED:
934 ha_alert("parsing [%s:%d] : %s: unexpected argument to store option '%s'.\n",
935 file, linenum, args[0], cw);
936 err_code |= ERR_ALERT | ERR_FATAL;
937 goto out;
Emeric Brunc64a2a32021-06-30 18:01:02 +0200938 case PE_ARG_VALUE_OOR:
939 ha_alert("parsing [%s:%d] : %s: array size is out of allowed range (1-%d) for store option '%s'.\n",
940 file, linenum, args[0], STKTABLE_MAX_DT_ARRAY_SIZE, cw);
941 err_code |= ERR_ALERT | ERR_FATAL;
942 goto out;
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100943
944 default:
945 ha_alert("parsing [%s:%d] : %s: error when processing store option '%s'.\n",
946 file, linenum, args[0], cw);
947 err_code |= ERR_ALERT | ERR_FATAL;
948 goto out;
949 }
950 }
951 idx++;
952 }
Thayne McCombs92149f92020-11-20 01:28:26 -0700953 else if (strcmp(args[idx], "srvkey") == 0) {
954 char *keytype;
955 idx++;
956 keytype = args[idx];
957 if (strcmp(keytype, "name") == 0) {
958 t->server_key_type = STKTABLE_SRV_NAME;
959 }
960 else if (strcmp(keytype, "addr") == 0) {
961 t->server_key_type = STKTABLE_SRV_ADDR;
962 }
963 else {
964 ha_alert("parsing [%s:%d] : %s : unknown server key type '%s'.\n",
965 file, linenum, args[0], keytype);
966 err_code |= ERR_ALERT | ERR_FATAL;
967 goto out;
968
969 }
970 idx++;
971 }
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100972 else {
973 ha_alert("parsing [%s:%d] : %s: unknown argument '%s'.\n",
974 file, linenum, args[0], args[idx]);
975 err_code |= ERR_ALERT | ERR_FATAL;
976 goto out;
977 }
978 }
979
980 if (!t->size) {
981 ha_alert("parsing [%s:%d] : %s: missing size.\n",
982 file, linenum, args[0]);
983 err_code |= ERR_ALERT | ERR_FATAL;
984 goto out;
985 }
986
987 if (t->type == (unsigned int)-1) {
988 ha_alert("parsing [%s:%d] : %s: missing type.\n",
989 file, linenum, args[0]);
990 err_code |= ERR_ALERT | ERR_FATAL;
991 goto out;
992 }
993
994 out:
995 return err_code;
996}
997
Willy Tarreau8fed9032014-07-03 17:02:46 +0200998/* Prepares a stktable_key from a sample <smp> to search into table <t>.
Willy Tarreauf0c730a2016-05-25 17:07:56 +0200999 * Note that the sample *is* modified and that the returned key may point
1000 * to it, so the sample must not be modified afterwards before the lookup.
Willy Tarreau8fed9032014-07-03 17:02:46 +02001001 * Returns NULL if the sample could not be converted (eg: no matching type),
1002 * otherwise a pointer to the static stktable_key filled with what is needed
1003 * for the lookup.
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001004 */
Willy Tarreau8fed9032014-07-03 17:02:46 +02001005struct stktable_key *smp_to_stkey(struct sample *smp, struct stktable *t)
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001006{
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001007 /* Convert sample. */
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +02001008 if (!sample_convert(smp, t->type))
Willy Tarreau7fc1c6e2012-04-26 11:03:17 +02001009 return NULL;
1010
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001011 /* Fill static_table_key. */
1012 switch (t->type) {
Emeric Brun485479d2010-09-23 18:02:19 +02001013
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +02001014 case SMP_T_IPV4:
Christopher Fauletca20d022017-08-29 15:30:31 +02001015 static_table_key.key = &smp->data.u.ipv4;
1016 static_table_key.key_len = 4;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001017 break;
Emeric Brun485479d2010-09-23 18:02:19 +02001018
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +02001019 case SMP_T_IPV6:
Christopher Fauletca20d022017-08-29 15:30:31 +02001020 static_table_key.key = &smp->data.u.ipv6;
1021 static_table_key.key_len = 16;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001022 break;
Emeric Brun485479d2010-09-23 18:02:19 +02001023
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +02001024 case SMP_T_SINT:
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001025 /* The stick table require a 32bit unsigned int, "sint" is a
1026 * signed 64 it, so we can convert it inplace.
1027 */
Willy Tarreau28c63c12019-10-23 06:21:05 +02001028 smp->data.u.sint = (unsigned int)smp->data.u.sint;
Christopher Fauletca20d022017-08-29 15:30:31 +02001029 static_table_key.key = &smp->data.u.sint;
1030 static_table_key.key_len = 4;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001031 break;
1032
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +02001033 case SMP_T_STR:
Willy Tarreauce6955e2016-08-09 11:59:12 +02001034 if (!smp_make_safe(smp))
1035 return NULL;
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001036 static_table_key.key = smp->data.u.str.area;
1037 static_table_key.key_len = smp->data.u.str.data;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001038 break;
Emeric Brun485479d2010-09-23 18:02:19 +02001039
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +02001040 case SMP_T_BIN:
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001041 if (smp->data.u.str.data < t->key_size) {
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001042 /* This type needs padding with 0. */
Willy Tarreauf65c6c02016-08-09 12:08:41 +02001043 if (!smp_make_rw(smp))
1044 return NULL;
1045
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001046 if (smp->data.u.str.size < t->key_size)
1047 if (!smp_dup(smp))
1048 return NULL;
1049 if (smp->data.u.str.size < t->key_size)
1050 return NULL;
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001051 memset(smp->data.u.str.area + smp->data.u.str.data, 0,
1052 t->key_size - smp->data.u.str.data);
1053 smp->data.u.str.data = t->key_size;
Emeric Brun485479d2010-09-23 18:02:19 +02001054 }
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001055 static_table_key.key = smp->data.u.str.area;
1056 static_table_key.key_len = smp->data.u.str.data;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001057 break;
Emeric Brun485479d2010-09-23 18:02:19 +02001058
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001059 default: /* impossible case. */
1060 return NULL;
Emeric Brun485479d2010-09-23 18:02:19 +02001061 }
1062
Christopher Fauletca20d022017-08-29 15:30:31 +02001063 return &static_table_key;
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001064}
1065
1066/*
Willy Tarreau8fed9032014-07-03 17:02:46 +02001067 * Process a fetch + format conversion as defined by the sample expression <expr>
1068 * on request or response considering the <opt> parameter. Returns either NULL if
1069 * no key could be extracted, or a pointer to the converted result stored in
1070 * static_table_key in format <table_type>. If <smp> is not NULL, it will be reset
1071 * and its flags will be initialized so that the caller gets a copy of the input
Willy Tarreau6bcb0a82014-07-30 08:56:35 +02001072 * sample, and knows why it was not accepted (eg: SMP_F_MAY_CHANGE is present
1073 * without SMP_OPT_FINAL). The output will be usable like this :
1074 *
1075 * return MAY_CHANGE FINAL Meaning for the sample
1076 * NULL 0 * Not present and will never be (eg: header)
1077 * NULL 1 0 Not present or unstable, could change (eg: req_len)
1078 * NULL 1 1 Not present, will not change anymore
1079 * smp 0 * Present and will not change (eg: header)
1080 * smp 1 0 not possible
1081 * smp 1 1 Present, last known value (eg: request length)
Willy Tarreau8fed9032014-07-03 17:02:46 +02001082 */
Willy Tarreau192252e2015-04-04 01:47:55 +02001083struct stktable_key *stktable_fetch_key(struct stktable *t, struct proxy *px, struct session *sess, struct stream *strm,
Willy Tarreau8fed9032014-07-03 17:02:46 +02001084 unsigned int opt, struct sample_expr *expr, struct sample *smp)
1085{
1086 if (smp)
1087 memset(smp, 0, sizeof(*smp));
1088
Willy Tarreau192252e2015-04-04 01:47:55 +02001089 smp = sample_process(px, sess, strm, opt, expr, smp);
Willy Tarreau8fed9032014-07-03 17:02:46 +02001090 if (!smp)
1091 return NULL;
1092
1093 if ((smp->flags & SMP_F_MAY_CHANGE) && !(opt & SMP_OPT_FINAL))
1094 return NULL; /* we can only use stable samples */
1095
1096 return smp_to_stkey(smp, t);
1097}
1098
1099/*
Willy Tarreau12785782012-04-27 21:37:17 +02001100 * Returns 1 if sample expression <expr> result can be converted to table key of
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001101 * type <table_type>, otherwise zero. Used in configuration check.
1102 */
Willy Tarreau12785782012-04-27 21:37:17 +02001103int stktable_compatible_sample(struct sample_expr *expr, unsigned long table_type)
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001104{
Thierry FOURNIERf73eb8f2013-11-27 15:30:55 +01001105 int out_type;
1106
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +02001107 if (table_type >= SMP_TYPES || !stktable_types[table_type].kw)
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001108 return 0;
1109
Thierry FOURNIERf73eb8f2013-11-27 15:30:55 +01001110 out_type = smp_expr_output_type(expr);
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001111
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001112 /* Convert sample. */
1113 if (!sample_casts[out_type][table_type])
Thierry FOURNIERf73eb8f2013-11-27 15:30:55 +01001114 return 0;
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001115
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001116 return 1;
1117}
Emeric Brun3bd697e2010-01-04 15:23:48 +01001118
Willy Tarreauedee1d62014-07-15 16:44:27 +02001119/* Extra data types processing : after the last one, some room may remain
1120 * before STKTABLE_DATA_TYPES that may be used to register extra data types
1121 * at run time.
1122 */
Willy Tarreau08d5f982010-06-06 13:34:54 +02001123struct stktable_data_type stktable_data_types[STKTABLE_DATA_TYPES] = {
Willy Tarreau3b9c6e02010-07-18 08:04:30 +02001124 [STKTABLE_DT_SERVER_ID] = { .name = "server_id", .std_type = STD_T_SINT },
Thierry FOURNIER3cf11112015-07-28 08:57:05 +02001125 [STKTABLE_DT_GPT0] = { .name = "gpt0", .std_type = STD_T_UINT },
Willy Tarreau3b9c6e02010-07-18 08:04:30 +02001126 [STKTABLE_DT_GPC0] = { .name = "gpc0", .std_type = STD_T_UINT },
Willy Tarreauba2ffd12013-05-29 15:54:14 +02001127 [STKTABLE_DT_GPC0_RATE] = { .name = "gpc0_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
Willy Tarreau3b9c6e02010-07-18 08:04:30 +02001128 [STKTABLE_DT_CONN_CNT] = { .name = "conn_cnt", .std_type = STD_T_UINT },
1129 [STKTABLE_DT_CONN_RATE] = { .name = "conn_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
1130 [STKTABLE_DT_CONN_CUR] = { .name = "conn_cur", .std_type = STD_T_UINT },
1131 [STKTABLE_DT_SESS_CNT] = { .name = "sess_cnt", .std_type = STD_T_UINT },
1132 [STKTABLE_DT_SESS_RATE] = { .name = "sess_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
1133 [STKTABLE_DT_HTTP_REQ_CNT] = { .name = "http_req_cnt", .std_type = STD_T_UINT },
1134 [STKTABLE_DT_HTTP_REQ_RATE] = { .name = "http_req_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
1135 [STKTABLE_DT_HTTP_ERR_CNT] = { .name = "http_err_cnt", .std_type = STD_T_UINT },
1136 [STKTABLE_DT_HTTP_ERR_RATE] = { .name = "http_err_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
1137 [STKTABLE_DT_BYTES_IN_CNT] = { .name = "bytes_in_cnt", .std_type = STD_T_ULL },
1138 [STKTABLE_DT_BYTES_IN_RATE] = { .name = "bytes_in_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
1139 [STKTABLE_DT_BYTES_OUT_CNT] = { .name = "bytes_out_cnt", .std_type = STD_T_ULL },
1140 [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 +01001141 [STKTABLE_DT_GPC1] = { .name = "gpc1", .std_type = STD_T_UINT },
1142 [STKTABLE_DT_GPC1_RATE] = { .name = "gpc1_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
Thayne McCombs92149f92020-11-20 01:28:26 -07001143 [STKTABLE_DT_SERVER_KEY] = { .name = "server_key", .std_type = STD_T_DICT },
Willy Tarreau826f3ab2021-02-10 12:07:15 +01001144 [STKTABLE_DT_HTTP_FAIL_CNT] = { .name = "http_fail_cnt", .std_type = STD_T_UINT },
1145 [STKTABLE_DT_HTTP_FAIL_RATE]= { .name = "http_fail_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
Emeric Brun877b0b52021-06-30 18:57:49 +02001146 [STKTABLE_DT_GPT] = { .name = "gpt", .std_type = STD_T_UINT, .is_array = 1 },
Willy Tarreau08d5f982010-06-06 13:34:54 +02001147};
1148
Willy Tarreauedee1d62014-07-15 16:44:27 +02001149/* Registers stick-table extra data type with index <idx>, name <name>, type
1150 * <std_type> and arg type <arg_type>. If the index is negative, the next free
1151 * index is automatically allocated. The allocated index is returned, or -1 if
1152 * no free index was found or <name> was already registered. The <name> is used
1153 * directly as a pointer, so if it's not stable, the caller must allocate it.
1154 */
1155int stktable_register_data_store(int idx, const char *name, int std_type, int arg_type)
1156{
1157 if (idx < 0) {
1158 for (idx = 0; idx < STKTABLE_DATA_TYPES; idx++) {
1159 if (!stktable_data_types[idx].name)
1160 break;
1161
1162 if (strcmp(stktable_data_types[idx].name, name) == 0)
1163 return -1;
1164 }
1165 }
1166
1167 if (idx >= STKTABLE_DATA_TYPES)
1168 return -1;
1169
1170 if (stktable_data_types[idx].name != NULL)
1171 return -1;
1172
1173 stktable_data_types[idx].name = name;
1174 stktable_data_types[idx].std_type = std_type;
1175 stktable_data_types[idx].arg_type = arg_type;
1176 return idx;
1177}
1178
Willy Tarreau08d5f982010-06-06 13:34:54 +02001179/*
1180 * Returns the data type number for the stktable_data_type whose name is <name>,
1181 * or <0 if not found.
1182 */
1183int stktable_get_data_type(char *name)
1184{
1185 int type;
1186
1187 for (type = 0; type < STKTABLE_DATA_TYPES; type++) {
Willy Tarreauedee1d62014-07-15 16:44:27 +02001188 if (!stktable_data_types[type].name)
1189 continue;
Willy Tarreau08d5f982010-06-06 13:34:54 +02001190 if (strcmp(name, stktable_data_types[type].name) == 0)
1191 return type;
1192 }
Thayne McCombs92149f92020-11-20 01:28:26 -07001193 /* For backwards compatibility */
1194 if (strcmp(name, "server_name") == 0)
1195 return STKTABLE_DT_SERVER_KEY;
Willy Tarreau08d5f982010-06-06 13:34:54 +02001196 return -1;
1197}
1198
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001199/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1200 * it up into this table. Returns true if found, false otherwise. The input
1201 * type is STR so that input samples are converted to string (since all types
1202 * can be converted to strings), then the function casts the string again into
1203 * the table's type. This is a double conversion, but in the future we might
1204 * support automatic input types to perform the cast on the fly.
1205 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001206static int sample_conv_in_table(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001207{
1208 struct stktable *t;
1209 struct stktable_key *key;
1210 struct stksess *ts;
1211
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001212 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001213
1214 key = smp_to_stkey(smp, t);
1215 if (!key)
1216 return 0;
1217
1218 ts = stktable_lookup_key(t, key);
1219
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001220 smp->data.type = SMP_T_BOOL;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001221 smp->data.u.sint = !!ts;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001222 smp->flags = SMP_F_VOL_TEST;
Willy Tarreau43e90352018-06-27 06:25:57 +02001223 stktable_release(t, ts);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001224 return 1;
1225}
1226
1227/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1228 * it up into this table. Returns the data rate received from clients in bytes/s
1229 * if the key is present in the table, otherwise zero, so that comparisons can
1230 * be easily performed. If the inspected parameter is not stored in the table,
1231 * <not found> is returned.
1232 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001233static int sample_conv_table_bytes_in_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001234{
1235 struct stktable *t;
1236 struct stktable_key *key;
1237 struct stksess *ts;
1238 void *ptr;
1239
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001240 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001241
1242 key = smp_to_stkey(smp, t);
1243 if (!key)
1244 return 0;
1245
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001246 ts = stktable_lookup_key(t, key);
1247
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001248 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001249 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001250 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001251
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001252 if (!ts) /* key not present */
1253 return 1;
1254
1255 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_IN_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001256 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001257 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Daniel Corbett3e60b112018-05-27 09:47:12 -04001258 t->data_arg[STKTABLE_DT_BYTES_IN_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001259
Daniel Corbett3e60b112018-05-27 09:47:12 -04001260 stktable_release(t, ts);
1261 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001262}
1263
1264/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1265 * it up into this table. Returns the cumulated number of connections for the key
1266 * if the key is present in the table, otherwise zero, so that comparisons can
1267 * be easily performed. If the inspected parameter is not stored in the table,
1268 * <not found> is returned.
1269 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001270static int sample_conv_table_conn_cnt(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001271{
1272 struct stktable *t;
1273 struct stktable_key *key;
1274 struct stksess *ts;
1275 void *ptr;
1276
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001277 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001278
1279 key = smp_to_stkey(smp, t);
1280 if (!key)
1281 return 0;
1282
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001283 ts = stktable_lookup_key(t, key);
1284
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001285 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001286 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001287 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001288
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001289 if (!ts) /* key not present */
1290 return 1;
1291
1292 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_CONN_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001293 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001294 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001295
Daniel Corbett3e60b112018-05-27 09:47:12 -04001296 stktable_release(t, ts);
1297 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001298}
1299
1300/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1301 * it up into this table. Returns the number of concurrent connections for the
1302 * key if the key is present in the table, otherwise zero, so that comparisons
1303 * can be easily performed. If the inspected parameter is not stored in the
1304 * table, <not found> is returned.
1305 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001306static int sample_conv_table_conn_cur(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001307{
1308 struct stktable *t;
1309 struct stktable_key *key;
1310 struct stksess *ts;
1311 void *ptr;
1312
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001313 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001314
1315 key = smp_to_stkey(smp, t);
1316 if (!key)
1317 return 0;
1318
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001319 ts = stktable_lookup_key(t, key);
1320
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001321 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001322 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001323 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001324
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001325 if (!ts) /* key not present */
1326 return 1;
1327
1328 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_CONN_CUR);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001329 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001330 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001331
Daniel Corbett3e60b112018-05-27 09:47:12 -04001332 stktable_release(t, ts);
1333 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001334}
1335
1336/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1337 * it up into this table. Returns the rate of incoming connections from the key
1338 * if the key is present in the table, otherwise zero, so that comparisons can
1339 * be easily performed. If the inspected parameter is not stored in the table,
1340 * <not found> is returned.
1341 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001342static int sample_conv_table_conn_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001343{
1344 struct stktable *t;
1345 struct stktable_key *key;
1346 struct stksess *ts;
1347 void *ptr;
1348
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001349 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001350
1351 key = smp_to_stkey(smp, t);
1352 if (!key)
1353 return 0;
1354
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001355 ts = stktable_lookup_key(t, key);
1356
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001357 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001358 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001359 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001360
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001361 if (!ts) /* key not present */
1362 return 1;
1363
1364 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_CONN_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001365 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001366 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Daniel Corbett3e60b112018-05-27 09:47:12 -04001367 t->data_arg[STKTABLE_DT_CONN_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001368
Daniel Corbett3e60b112018-05-27 09:47:12 -04001369 stktable_release(t, ts);
1370 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001371}
1372
1373/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1374 * it up into this table. Returns the data rate sent to clients in bytes/s
1375 * if the key is present in the table, otherwise zero, so that comparisons can
1376 * be easily performed. If the inspected parameter is not stored in the table,
1377 * <not found> is returned.
1378 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001379static int sample_conv_table_bytes_out_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001380{
1381 struct stktable *t;
1382 struct stktable_key *key;
1383 struct stksess *ts;
1384 void *ptr;
1385
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001386 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001387
1388 key = smp_to_stkey(smp, t);
1389 if (!key)
1390 return 0;
1391
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001392 ts = stktable_lookup_key(t, key);
1393
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001394 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001395 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001396 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001397
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001398 if (!ts) /* key not present */
1399 return 1;
1400
1401 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_OUT_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001402 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001403 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Daniel Corbett3e60b112018-05-27 09:47:12 -04001404 t->data_arg[STKTABLE_DT_BYTES_OUT_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001405
Daniel Corbett3e60b112018-05-27 09:47:12 -04001406 stktable_release(t, ts);
1407 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001408}
1409
Emeric Brun877b0b52021-06-30 18:57:49 +02001410/* Casts sample <smp> to the type of the table specified in arg_p(1), and looks
1411 * it up into this table. Returns the value of the GPT[arg_p(0)] tag for the key
1412 * if the key is present in the table, otherwise false, so that comparisons can
1413 * be easily performed. If the inspected parameter is not stored in the table,
1414 * <not found> is returned.
1415 */
1416static int sample_conv_table_gpt(const struct arg *arg_p, struct sample *smp, void *private)
1417{
1418 struct stktable *t;
1419 struct stktable_key *key;
1420 struct stksess *ts;
1421 void *ptr;
1422 unsigned int idx;
1423
1424 idx = arg_p[0].data.sint;
1425
1426 t = arg_p[1].data.t;
1427
1428 key = smp_to_stkey(smp, t);
1429 if (!key)
1430 return 0;
1431
1432 ts = stktable_lookup_key(t, key);
1433
1434 smp->flags = SMP_F_VOL_TEST;
1435 smp->data.type = SMP_T_SINT;
1436 smp->data.u.sint = 0;
1437
1438 if (!ts) /* key not present */
1439 return 1;
1440
1441 ptr = stktable_data_ptr_idx(t, ts, STKTABLE_DT_GPT, idx);
1442 if (ptr)
1443 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
1444
1445 stktable_release(t, ts);
1446 return !!ptr;
1447}
1448
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001449/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001450 * it up into this table. Returns the value of the GPT0 tag for the key
1451 * if the key is present in the table, otherwise false, so that comparisons can
1452 * be easily performed. If the inspected parameter is not stored in the table,
1453 * <not found> is returned.
1454 */
1455static int sample_conv_table_gpt0(const struct arg *arg_p, struct sample *smp, void *private)
1456{
1457 struct stktable *t;
1458 struct stktable_key *key;
1459 struct stksess *ts;
1460 void *ptr;
1461
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001462 t = arg_p[0].data.t;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001463
1464 key = smp_to_stkey(smp, t);
1465 if (!key)
1466 return 0;
1467
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001468 ts = stktable_lookup_key(t, key);
1469
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001470 smp->flags = SMP_F_VOL_TEST;
1471 smp->data.type = SMP_T_SINT;
1472 smp->data.u.sint = 0;
1473
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001474 if (!ts) /* key not present */
1475 return 1;
1476
1477 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPT0);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001478 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001479 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001480
Daniel Corbett3e60b112018-05-27 09:47:12 -04001481 stktable_release(t, ts);
1482 return !!ptr;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001483}
1484
1485/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001486 * it up into this table. Returns the value of the GPC0 counter for the key
1487 * if the key is present in the table, otherwise zero, so that comparisons can
1488 * be easily performed. If the inspected parameter is not stored in the table,
1489 * <not found> is returned.
1490 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001491static int sample_conv_table_gpc0(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001492{
1493 struct stktable *t;
1494 struct stktable_key *key;
1495 struct stksess *ts;
1496 void *ptr;
1497
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001498 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001499
1500 key = smp_to_stkey(smp, t);
1501 if (!key)
1502 return 0;
1503
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001504 ts = stktable_lookup_key(t, key);
1505
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001506 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001507 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001508 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001509
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001510 if (!ts) /* key not present */
1511 return 1;
1512
1513 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPC0);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001514 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001515 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001516
Daniel Corbett3e60b112018-05-27 09:47:12 -04001517 stktable_release(t, ts);
1518 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001519}
1520
1521/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1522 * it up into this table. Returns the event rate of the GPC0 counter for the key
1523 * if the key is present in the table, otherwise zero, so that comparisons can
1524 * be easily performed. If the inspected parameter is not stored in the table,
1525 * <not found> is returned.
1526 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001527static int sample_conv_table_gpc0_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001528{
1529 struct stktable *t;
1530 struct stktable_key *key;
1531 struct stksess *ts;
1532 void *ptr;
1533
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001534 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001535
1536 key = smp_to_stkey(smp, t);
1537 if (!key)
1538 return 0;
1539
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001540 ts = stktable_lookup_key(t, key);
1541
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001542 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001543 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001544 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001545
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001546 if (!ts) /* key not present */
1547 return 1;
1548
1549 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPC0_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001550 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001551 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Daniel Corbett3e60b112018-05-27 09:47:12 -04001552 t->data_arg[STKTABLE_DT_GPC0_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001553
Daniel Corbett3e60b112018-05-27 09:47:12 -04001554 stktable_release(t, ts);
1555 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001556}
1557
1558/* 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 +01001559 * it up into this table. Returns the value of the GPC1 counter for the key
1560 * if the key is present in the table, otherwise zero, so that comparisons can
1561 * be easily performed. If the inspected parameter is not stored in the table,
1562 * <not found> is returned.
1563 */
1564static int sample_conv_table_gpc1(const struct arg *arg_p, struct sample *smp, void *private)
1565{
1566 struct stktable *t;
1567 struct stktable_key *key;
1568 struct stksess *ts;
1569 void *ptr;
1570
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001571 t = arg_p[0].data.t;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001572
1573 key = smp_to_stkey(smp, t);
1574 if (!key)
1575 return 0;
1576
1577 ts = stktable_lookup_key(t, key);
1578
1579 smp->flags = SMP_F_VOL_TEST;
1580 smp->data.type = SMP_T_SINT;
1581 smp->data.u.sint = 0;
1582
1583 if (!ts) /* key not present */
1584 return 1;
1585
1586 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPC1);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001587 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001588 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001589
Daniel Corbett3e60b112018-05-27 09:47:12 -04001590 stktable_release(t, ts);
1591 return !!ptr;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001592}
1593
1594/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1595 * it up into this table. Returns the event rate of the GPC1 counter for the key
1596 * if the key is present in the table, otherwise zero, so that comparisons can
1597 * be easily performed. If the inspected parameter is not stored in the table,
1598 * <not found> is returned.
1599 */
1600static int sample_conv_table_gpc1_rate(const struct arg *arg_p, struct sample *smp, void *private)
1601{
1602 struct stktable *t;
1603 struct stktable_key *key;
1604 struct stksess *ts;
1605 void *ptr;
1606
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001607 t = arg_p[0].data.t;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001608
1609 key = smp_to_stkey(smp, t);
1610 if (!key)
1611 return 0;
1612
1613 ts = stktable_lookup_key(t, key);
1614
1615 smp->flags = SMP_F_VOL_TEST;
1616 smp->data.type = SMP_T_SINT;
1617 smp->data.u.sint = 0;
1618
1619 if (!ts) /* key not present */
1620 return 1;
1621
1622 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPC1_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001623 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001624 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Daniel Corbett3e60b112018-05-27 09:47:12 -04001625 t->data_arg[STKTABLE_DT_GPC1_RATE].u);
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001626
Daniel Corbett3e60b112018-05-27 09:47:12 -04001627 stktable_release(t, ts);
1628 return !!ptr;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001629}
1630
1631/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001632 * it up into this table. Returns the cumulated number of HTTP request errors
1633 * for the key if the key is present in the table, otherwise zero, so that
1634 * comparisons can be easily performed. If the inspected parameter is not stored
1635 * in the table, <not found> is returned.
1636 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001637static int sample_conv_table_http_err_cnt(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001638{
1639 struct stktable *t;
1640 struct stktable_key *key;
1641 struct stksess *ts;
1642 void *ptr;
1643
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001644 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001645
1646 key = smp_to_stkey(smp, t);
1647 if (!key)
1648 return 0;
1649
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001650 ts = stktable_lookup_key(t, key);
1651
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001652 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001653 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001654 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001655
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001656 if (!ts) /* key not present */
1657 return 1;
1658
1659 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_ERR_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001660 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001661 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001662
Daniel Corbett3e60b112018-05-27 09:47:12 -04001663 stktable_release(t, ts);
1664 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001665}
1666
1667/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1668 * it up into this table. Returns the HTTP request error rate the key
1669 * if the key is present in the table, otherwise zero, so that comparisons can
1670 * be easily performed. If the inspected parameter is not stored in the table,
1671 * <not found> is returned.
1672 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001673static int sample_conv_table_http_err_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001674{
1675 struct stktable *t;
1676 struct stktable_key *key;
1677 struct stksess *ts;
1678 void *ptr;
1679
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001680 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001681
1682 key = smp_to_stkey(smp, t);
1683 if (!key)
1684 return 0;
1685
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001686 ts = stktable_lookup_key(t, key);
1687
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001688 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001689 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001690 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001691
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001692 if (!ts) /* key not present */
1693 return 1;
1694
1695 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_ERR_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001696 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001697 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Daniel Corbett3e60b112018-05-27 09:47:12 -04001698 t->data_arg[STKTABLE_DT_HTTP_ERR_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001699
Daniel Corbett3e60b112018-05-27 09:47:12 -04001700 stktable_release(t, ts);
1701 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001702}
1703
1704/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Willy Tarreau826f3ab2021-02-10 12:07:15 +01001705 * it up into this table. Returns the cumulated number of HTTP response failures
1706 * for the key if the key is present in the table, otherwise zero, so that
1707 * comparisons can be easily performed. If the inspected parameter is not stored
1708 * in the table, <not found> is returned.
1709 */
1710static int sample_conv_table_http_fail_cnt(const struct arg *arg_p, struct sample *smp, void *private)
1711{
1712 struct stktable *t;
1713 struct stktable_key *key;
1714 struct stksess *ts;
1715 void *ptr;
1716
1717 t = arg_p[0].data.t;
1718
1719 key = smp_to_stkey(smp, t);
1720 if (!key)
1721 return 0;
1722
1723 ts = stktable_lookup_key(t, key);
1724
1725 smp->flags = SMP_F_VOL_TEST;
1726 smp->data.type = SMP_T_SINT;
1727 smp->data.u.sint = 0;
1728
1729 if (!ts) /* key not present */
1730 return 1;
1731
1732 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_FAIL_CNT);
1733 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001734 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Willy Tarreau826f3ab2021-02-10 12:07:15 +01001735
1736 stktable_release(t, ts);
1737 return !!ptr;
1738}
1739
1740/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1741 * it up into this table. Returns the HTTP response failure rate for the key
1742 * if the key is present in the table, otherwise zero, so that comparisons can
1743 * be easily performed. If the inspected parameter is not stored in the table,
1744 * <not found> is returned.
1745 */
1746static int sample_conv_table_http_fail_rate(const struct arg *arg_p, struct sample *smp, void *private)
1747{
1748 struct stktable *t;
1749 struct stktable_key *key;
1750 struct stksess *ts;
1751 void *ptr;
1752
1753 t = arg_p[0].data.t;
1754
1755 key = smp_to_stkey(smp, t);
1756 if (!key)
1757 return 0;
1758
1759 ts = stktable_lookup_key(t, key);
1760
1761 smp->flags = SMP_F_VOL_TEST;
1762 smp->data.type = SMP_T_SINT;
1763 smp->data.u.sint = 0;
1764
1765 if (!ts) /* key not present */
1766 return 1;
1767
1768 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_FAIL_RATE);
1769 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001770 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Willy Tarreau826f3ab2021-02-10 12:07:15 +01001771 t->data_arg[STKTABLE_DT_HTTP_FAIL_RATE].u);
1772
1773 stktable_release(t, ts);
1774 return !!ptr;
1775}
1776
1777/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001778 * it up into this table. Returns the cumulated number of HTTP request for the
1779 * key if the key is present in the table, otherwise zero, so that comparisons
1780 * can be easily performed. If the inspected parameter is not stored in the
1781 * table, <not found> is returned.
1782 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001783static int sample_conv_table_http_req_cnt(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001784{
1785 struct stktable *t;
1786 struct stktable_key *key;
1787 struct stksess *ts;
1788 void *ptr;
1789
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001790 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001791
1792 key = smp_to_stkey(smp, t);
1793 if (!key)
1794 return 0;
1795
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001796 ts = stktable_lookup_key(t, key);
1797
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001798 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001799 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001800 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001801
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001802 if (!ts) /* key not present */
1803 return 1;
1804
1805 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_REQ_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001806 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001807 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001808
Daniel Corbett3e60b112018-05-27 09:47:12 -04001809 stktable_release(t, ts);
1810 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001811}
1812
1813/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1814 * it up into this table. Returns the HTTP request rate the key if the key is
1815 * present in the table, otherwise zero, so that comparisons can be easily
1816 * performed. If the inspected parameter is not stored in the table, <not found>
1817 * is returned.
1818 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001819static int sample_conv_table_http_req_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001820{
1821 struct stktable *t;
1822 struct stktable_key *key;
1823 struct stksess *ts;
1824 void *ptr;
1825
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001826 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001827
1828 key = smp_to_stkey(smp, t);
1829 if (!key)
1830 return 0;
1831
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001832 ts = stktable_lookup_key(t, key);
1833
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001834 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001835 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001836 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001837
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001838 if (!ts) /* key not present */
1839 return 1;
1840
1841 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_REQ_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001842 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001843 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Daniel Corbett3e60b112018-05-27 09:47:12 -04001844 t->data_arg[STKTABLE_DT_HTTP_REQ_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001845
Daniel Corbett3e60b112018-05-27 09:47:12 -04001846 stktable_release(t, ts);
1847 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001848}
1849
1850/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1851 * it up into this table. Returns the volume of datareceived from clients in kbytes
1852 * if the key is present in the table, otherwise zero, so that comparisons can
1853 * be easily performed. If the inspected parameter is not stored in the table,
1854 * <not found> is returned.
1855 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001856static int sample_conv_table_kbytes_in(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001857{
1858 struct stktable *t;
1859 struct stktable_key *key;
1860 struct stksess *ts;
1861 void *ptr;
1862
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001863 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001864
1865 key = smp_to_stkey(smp, t);
1866 if (!key)
1867 return 0;
1868
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001869 ts = stktable_lookup_key(t, key);
1870
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001871 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001872 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001873 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001874
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001875 if (!ts) /* key not present */
1876 return 1;
1877
1878 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_IN_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001879 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001880 smp->data.u.sint = stktable_data_cast(ptr, std_t_ull) >> 10;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001881
Daniel Corbett3e60b112018-05-27 09:47:12 -04001882 stktable_release(t, ts);
1883 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001884}
1885
1886/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1887 * it up into this table. Returns the volume of data sent to clients in kbytes
1888 * if the key is present in the table, otherwise zero, so that comparisons can
1889 * be easily performed. If the inspected parameter is not stored in the table,
1890 * <not found> is returned.
1891 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001892static int sample_conv_table_kbytes_out(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001893{
1894 struct stktable *t;
1895 struct stktable_key *key;
1896 struct stksess *ts;
1897 void *ptr;
1898
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001899 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001900
1901 key = smp_to_stkey(smp, t);
1902 if (!key)
1903 return 0;
1904
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001905 ts = stktable_lookup_key(t, key);
1906
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001907 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001908 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001909 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001910
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001911 if (!ts) /* key not present */
1912 return 1;
1913
1914 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_OUT_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001915 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001916 smp->data.u.sint = stktable_data_cast(ptr, std_t_ull) >> 10;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001917
Daniel Corbett3e60b112018-05-27 09:47:12 -04001918 stktable_release(t, ts);
1919 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001920}
1921
1922/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1923 * it up into this table. Returns the server ID associated with the key if the
1924 * key is present in the table, otherwise zero, so that comparisons can be
1925 * easily performed. If the inspected parameter is not stored in the table,
1926 * <not found> is returned.
1927 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001928static int sample_conv_table_server_id(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001929{
1930 struct stktable *t;
1931 struct stktable_key *key;
1932 struct stksess *ts;
1933 void *ptr;
1934
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001935 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001936
1937 key = smp_to_stkey(smp, t);
1938 if (!key)
1939 return 0;
1940
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001941 ts = stktable_lookup_key(t, key);
1942
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001943 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001944 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001945 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001946
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001947 if (!ts) /* key not present */
1948 return 1;
1949
1950 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_SERVER_ID);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001951 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001952 smp->data.u.sint = stktable_data_cast(ptr, std_t_sint);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001953
Daniel Corbett3e60b112018-05-27 09:47:12 -04001954 stktable_release(t, ts);
1955 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001956}
1957
1958/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1959 * it up into this table. Returns the cumulated number of sessions for the
1960 * key if the key is present in the table, otherwise zero, so that comparisons
1961 * can be easily performed. If the inspected parameter is not stored in the
1962 * table, <not found> is returned.
1963 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001964static int sample_conv_table_sess_cnt(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001965{
1966 struct stktable *t;
1967 struct stktable_key *key;
1968 struct stksess *ts;
1969 void *ptr;
1970
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001971 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001972
1973 key = smp_to_stkey(smp, t);
1974 if (!key)
1975 return 0;
1976
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001977 ts = stktable_lookup_key(t, key);
1978
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001979 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001980 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001981 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001982
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001983 if (!ts) /* key not present */
1984 return 1;
1985
1986 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_SESS_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001987 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02001988 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001989
Daniel Corbett3e60b112018-05-27 09:47:12 -04001990 stktable_release(t, ts);
1991 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001992}
1993
1994/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1995 * it up into this table. Returns the session rate the key if the key is
1996 * present in the table, otherwise zero, so that comparisons can be easily
1997 * performed. If the inspected parameter is not stored in the table, <not found>
1998 * is returned.
1999 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02002000static int sample_conv_table_sess_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002001{
2002 struct stktable *t;
2003 struct stktable_key *key;
2004 struct stksess *ts;
2005 void *ptr;
2006
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002007 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002008
2009 key = smp_to_stkey(smp, t);
2010 if (!key)
2011 return 0;
2012
Willy Tarreauf0c730a2016-05-25 17:07:56 +02002013 ts = stktable_lookup_key(t, key);
2014
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002015 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02002016 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02002017 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002018
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002019 if (!ts) /* key not present */
2020 return 1;
2021
2022 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_SESS_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04002023 if (ptr)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002024 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Daniel Corbett3e60b112018-05-27 09:47:12 -04002025 t->data_arg[STKTABLE_DT_SESS_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002026
Daniel Corbett3e60b112018-05-27 09:47:12 -04002027 stktable_release(t, ts);
2028 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002029}
2030
2031/* Casts sample <smp> to the type of the table specified in arg(0), and looks
2032 * it up into this table. Returns the amount of concurrent connections tracking
2033 * the same key if the key is present in the table, otherwise zero, so that
2034 * comparisons can be easily performed. If the inspected parameter is not
2035 * stored in the table, <not found> is returned.
2036 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02002037static int sample_conv_table_trackers(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002038{
2039 struct stktable *t;
2040 struct stktable_key *key;
2041 struct stksess *ts;
2042
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002043 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002044
2045 key = smp_to_stkey(smp, t);
2046 if (!key)
2047 return 0;
2048
Willy Tarreauf0c730a2016-05-25 17:07:56 +02002049 ts = stktable_lookup_key(t, key);
2050
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002051 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02002052 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02002053 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002054
Tim Duesterhus65189c12018-06-26 15:57:29 +02002055 if (!ts)
2056 return 1;
2057
2058 smp->data.u.sint = ts->ref_cnt;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002059
Daniel Corbett3e60b112018-05-27 09:47:12 -04002060 stktable_release(t, ts);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02002061 return 1;
2062}
2063
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002064/* Always returns 1. */
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002065static enum act_return action_inc_gpc0(struct act_rule *rule, struct proxy *px,
Willy Tarreau658b85b2015-09-27 10:00:49 +02002066 struct session *sess, struct stream *s, int flags)
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002067{
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002068 struct stksess *ts;
2069 struct stkctr *stkctr;
2070
2071 /* Extract the stksess, return OK if no stksess available. */
2072 if (s)
2073 stkctr = &s->stkctr[rule->arg.gpc.sc];
2074 else
2075 stkctr = &sess->stkctr[rule->arg.gpc.sc];
Willy Tarreau79c1e912016-01-25 14:54:45 +01002076
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002077 ts = stkctr_entry(stkctr);
Willy Tarreau79c1e912016-01-25 14:54:45 +01002078 if (ts) {
2079 void *ptr1, *ptr2;
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002080
Willy Tarreau79c1e912016-01-25 14:54:45 +01002081 /* First, update gpc0_rate if it's tracked. Second, update its gpc0 if tracked. */
2082 ptr1 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC0_RATE);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002083 ptr2 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC0);
2084 if (ptr1 || ptr2) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002085 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002086
2087 if (ptr1)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002088 update_freq_ctr_period(&stktable_data_cast(ptr1, std_t_frqp),
Willy Tarreau79c1e912016-01-25 14:54:45 +01002089 stkctr->table->data_arg[STKTABLE_DT_GPC0_RATE].u, 1);
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002090
Emeric Brun819fc6f2017-06-13 19:37:32 +02002091 if (ptr2)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002092 stktable_data_cast(ptr2, std_t_uint)++;
Willy Tarreau79c1e912016-01-25 14:54:45 +01002093
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002094 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002095
2096 /* If data was modified, we need to touch to re-schedule sync */
2097 stktable_touch_local(stkctr->table, ts, 0);
2098 }
Willy Tarreau79c1e912016-01-25 14:54:45 +01002099 }
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002100 return ACT_RET_CONT;
2101}
2102
2103/* This function is a common parser for using variables. It understands
2104 * the formats:
2105 *
2106 * sc-inc-gpc0(<stick-table ID>)
2107 *
2108 * It returns 0 if fails and <err> is filled with an error message. Otherwise,
2109 * it returns 1 and the variable <expr> is filled with the pointer to the
2110 * expression to execute.
2111 */
2112static enum act_parse_ret parse_inc_gpc0(const char **args, int *arg, struct proxy *px,
2113 struct act_rule *rule, char **err)
2114{
2115 const char *cmd_name = args[*arg-1];
2116 char *error;
2117
2118 cmd_name += strlen("sc-inc-gpc0");
2119 if (*cmd_name == '\0') {
2120 /* default stick table id. */
2121 rule->arg.gpc.sc = 0;
2122 } else {
2123 /* parse the stick table id. */
2124 if (*cmd_name != '(') {
2125 memprintf(err, "invalid stick table track ID. Expects %s(<Track ID>)", args[*arg-1]);
2126 return ACT_RET_PRS_ERR;
2127 }
2128 cmd_name++; /* jump the '(' */
2129 rule->arg.gpc.sc = strtol(cmd_name, &error, 10); /* Convert stick table id. */
2130 if (*error != ')') {
2131 memprintf(err, "invalid stick table track ID. Expects %s(<Track ID>)", args[*arg-1]);
2132 return ACT_RET_PRS_ERR;
2133 }
2134
Christopher Faulet28436e22019-12-18 10:25:46 +01002135 if (rule->arg.gpc.sc >= MAX_SESS_STKCTR) {
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002136 memprintf(err, "invalid stick table track ID. The max allowed ID is %d",
Christopher Faulet28436e22019-12-18 10:25:46 +01002137 MAX_SESS_STKCTR-1);
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002138 return ACT_RET_PRS_ERR;
2139 }
2140 }
Thierry FOURNIER42148732015-09-02 17:17:33 +02002141 rule->action = ACT_CUSTOM;
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002142 rule->action_ptr = action_inc_gpc0;
2143 return ACT_RET_PRS_OK;
2144}
2145
2146/* Always returns 1. */
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002147static enum act_return action_inc_gpc1(struct act_rule *rule, struct proxy *px,
2148 struct session *sess, struct stream *s, int flags)
2149{
2150 struct stksess *ts;
2151 struct stkctr *stkctr;
2152
2153 /* Extract the stksess, return OK if no stksess available. */
2154 if (s)
2155 stkctr = &s->stkctr[rule->arg.gpc.sc];
2156 else
2157 stkctr = &sess->stkctr[rule->arg.gpc.sc];
2158
2159 ts = stkctr_entry(stkctr);
2160 if (ts) {
2161 void *ptr1, *ptr2;
2162
2163 /* First, update gpc1_rate if it's tracked. Second, update its gpc1 if tracked. */
2164 ptr1 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC1_RATE);
2165 ptr2 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC1);
2166 if (ptr1 || ptr2) {
2167 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
2168
2169 if (ptr1)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002170 update_freq_ctr_period(&stktable_data_cast(ptr1, std_t_frqp),
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002171 stkctr->table->data_arg[STKTABLE_DT_GPC1_RATE].u, 1);
2172
2173 if (ptr2)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002174 stktable_data_cast(ptr2, std_t_uint)++;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002175
2176 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
2177
2178 /* If data was modified, we need to touch to re-schedule sync */
2179 stktable_touch_local(stkctr->table, ts, 0);
2180 }
2181 }
2182 return ACT_RET_CONT;
2183}
2184
2185/* This function is a common parser for using variables. It understands
2186 * the formats:
2187 *
2188 * sc-inc-gpc1(<stick-table ID>)
2189 *
2190 * It returns 0 if fails and <err> is filled with an error message. Otherwise,
2191 * it returns 1 and the variable <expr> is filled with the pointer to the
2192 * expression to execute.
2193 */
2194static enum act_parse_ret parse_inc_gpc1(const char **args, int *arg, struct proxy *px,
2195 struct act_rule *rule, char **err)
2196{
2197 const char *cmd_name = args[*arg-1];
2198 char *error;
2199
2200 cmd_name += strlen("sc-inc-gpc1");
2201 if (*cmd_name == '\0') {
2202 /* default stick table id. */
2203 rule->arg.gpc.sc = 0;
2204 } else {
2205 /* parse the stick table id. */
2206 if (*cmd_name != '(') {
2207 memprintf(err, "invalid stick table track ID. Expects %s(<Track ID>)", args[*arg-1]);
2208 return ACT_RET_PRS_ERR;
2209 }
2210 cmd_name++; /* jump the '(' */
2211 rule->arg.gpc.sc = strtol(cmd_name, &error, 10); /* Convert stick table id. */
2212 if (*error != ')') {
2213 memprintf(err, "invalid stick table track ID. Expects %s(<Track ID>)", args[*arg-1]);
2214 return ACT_RET_PRS_ERR;
2215 }
2216
Christopher Faulet28436e22019-12-18 10:25:46 +01002217 if (rule->arg.gpc.sc >= MAX_SESS_STKCTR) {
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002218 memprintf(err, "invalid stick table track ID. The max allowed ID is %d",
Christopher Faulet28436e22019-12-18 10:25:46 +01002219 MAX_SESS_STKCTR-1);
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002220 return ACT_RET_PRS_ERR;
2221 }
2222 }
2223 rule->action = ACT_CUSTOM;
2224 rule->action_ptr = action_inc_gpc1;
2225 return ACT_RET_PRS_OK;
2226}
2227
Emeric Brun877b0b52021-06-30 18:57:49 +02002228/* This function sets the gpt at index 'rule->arg.gpt.idx' of the array on the
2229 * tracksc counter of index 'rule->arg.gpt.sc' stored into the <stream> or
2230 * directly in the session <sess> if <stream> is set to NULL. This gpt is
2231 * set to the value computed by the expression 'rule->arg.gpt.expr' or if
2232 * 'rule->arg.gpt.expr' is null directly to the value of 'rule->arg.gpt.value'.
2233 *
2234 * This function always returns ACT_RET_CONT and parameter flags is unused.
2235 */
2236static enum act_return action_set_gpt(struct act_rule *rule, struct proxy *px,
2237 struct session *sess, struct stream *s, int flags)
2238{
2239 void *ptr;
2240 struct stksess *ts;
2241 struct stkctr *stkctr;
2242 unsigned int value = 0;
2243 struct sample *smp;
2244 int smp_opt_dir;
2245
2246 /* Extract the stksess, return OK if no stksess available. */
2247 if (s)
2248 stkctr = &s->stkctr[rule->arg.gpt.sc];
2249 else
2250 stkctr = &sess->stkctr[rule->arg.gpt.sc];
2251
2252 ts = stkctr_entry(stkctr);
2253 if (!ts)
2254 return ACT_RET_CONT;
2255
2256 /* Store the sample in the required sc, and ignore errors. */
2257 ptr = stktable_data_ptr_idx(stkctr->table, ts, STKTABLE_DT_GPT, rule->arg.gpt.idx);
2258 if (ptr) {
2259
2260 if (!rule->arg.gpt.expr)
2261 value = (unsigned int)(rule->arg.gpt.value);
2262 else {
2263 switch (rule->from) {
2264 case ACT_F_TCP_REQ_SES: smp_opt_dir = SMP_OPT_DIR_REQ; break;
2265 case ACT_F_TCP_REQ_CNT: smp_opt_dir = SMP_OPT_DIR_REQ; break;
2266 case ACT_F_TCP_RES_CNT: smp_opt_dir = SMP_OPT_DIR_RES; break;
2267 case ACT_F_HTTP_REQ: smp_opt_dir = SMP_OPT_DIR_REQ; break;
2268 case ACT_F_HTTP_RES: smp_opt_dir = SMP_OPT_DIR_RES; break;
2269 default:
2270 send_log(px, LOG_ERR, "stick table: internal error while setting gpt%u.", rule->arg.gpt.idx);
2271 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))
2272 ha_alert("stick table: internal error while executing setting gpt%u.\n", rule->arg.gpt.idx);
2273 return ACT_RET_CONT;
2274 }
2275
2276 /* Fetch and cast the expression. */
2277 smp = sample_fetch_as_type(px, sess, s, smp_opt_dir|SMP_OPT_FINAL, rule->arg.gpt.expr, SMP_T_SINT);
2278 if (!smp) {
2279 send_log(px, LOG_WARNING, "stick table: invalid expression or data type while setting gpt%u.", rule->arg.gpt.idx);
2280 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))
2281 ha_alert("stick table: invalid expression or data type while setting gpt%u.\n", rule->arg.gpt.idx);
2282 return ACT_RET_CONT;
2283 }
2284 value = (unsigned int)(smp->data.u.sint);
2285 }
2286
2287 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
2288
2289 stktable_data_cast(ptr, std_t_uint) = value;
2290
2291 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
2292
2293 stktable_touch_local(stkctr->table, ts, 0);
2294 }
2295
2296 return ACT_RET_CONT;
2297}
2298
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002299/* Always returns 1. */
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002300static enum act_return action_set_gpt0(struct act_rule *rule, struct proxy *px,
Willy Tarreau658b85b2015-09-27 10:00:49 +02002301 struct session *sess, struct stream *s, int flags)
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002302{
2303 void *ptr;
2304 struct stksess *ts;
2305 struct stkctr *stkctr;
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002306 unsigned int value = 0;
2307 struct sample *smp;
2308 int smp_opt_dir;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002309
2310 /* Extract the stksess, return OK if no stksess available. */
2311 if (s)
2312 stkctr = &s->stkctr[rule->arg.gpt.sc];
2313 else
2314 stkctr = &sess->stkctr[rule->arg.gpt.sc];
Willy Tarreau79c1e912016-01-25 14:54:45 +01002315
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002316 ts = stkctr_entry(stkctr);
2317 if (!ts)
2318 return ACT_RET_CONT;
2319
2320 /* Store the sample in the required sc, and ignore errors. */
2321 ptr = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPT0);
Willy Tarreau79c1e912016-01-25 14:54:45 +01002322 if (ptr) {
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002323 if (!rule->arg.gpt.expr)
2324 value = (unsigned int)(rule->arg.gpt.value);
2325 else {
2326 switch (rule->from) {
2327 case ACT_F_TCP_REQ_SES: smp_opt_dir = SMP_OPT_DIR_REQ; break;
2328 case ACT_F_TCP_REQ_CNT: smp_opt_dir = SMP_OPT_DIR_REQ; break;
2329 case ACT_F_TCP_RES_CNT: smp_opt_dir = SMP_OPT_DIR_RES; break;
2330 case ACT_F_HTTP_REQ: smp_opt_dir = SMP_OPT_DIR_REQ; break;
2331 case ACT_F_HTTP_RES: smp_opt_dir = SMP_OPT_DIR_RES; break;
2332 default:
2333 send_log(px, LOG_ERR, "stick table: internal error while setting gpt0.");
2334 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))
2335 ha_alert("stick table: internal error while executing setting gpt0.\n");
2336 return ACT_RET_CONT;
2337 }
2338
2339 /* Fetch and cast the expression. */
2340 smp = sample_fetch_as_type(px, sess, s, smp_opt_dir|SMP_OPT_FINAL, rule->arg.gpt.expr, SMP_T_SINT);
2341 if (!smp) {
2342 send_log(px, LOG_WARNING, "stick table: invalid expression or data type while setting gpt0.");
2343 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))
2344 ha_alert("stick table: invalid expression or data type while setting gpt0.\n");
2345 return ACT_RET_CONT;
2346 }
2347 value = (unsigned int)(smp->data.u.sint);
2348 }
2349
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002350 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002351
Emeric Brun0e3457b2021-06-30 17:18:28 +02002352 stktable_data_cast(ptr, std_t_uint) = value;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002353
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002354 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002355
2356 stktable_touch_local(stkctr->table, ts, 0);
Willy Tarreau79c1e912016-01-25 14:54:45 +01002357 }
2358
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002359 return ACT_RET_CONT;
2360}
2361
Emeric Brun877b0b52021-06-30 18:57:49 +02002362/* This function is a parser for the "sc-set-gpt" and "sc-set-gpt0" actions.
2363 * It understands the formats:
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002364 *
Emeric Brun877b0b52021-06-30 18:57:49 +02002365 * sc-set-gpt(<gpt IDX>,<track ID>) <expression>
2366 * sc-set-gpt0(<track ID>) <expression>
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002367 *
Emeric Brun877b0b52021-06-30 18:57:49 +02002368 * It returns ACT_RET_PRS_ERR if fails and <err> is filled with an error message.
2369 * Otherwise, it returns ACT_RET_PRS_OK and the variable 'rule->arg.gpt.expr'
2370 * is filled with the pointer to the expression to execute or NULL if the arg
2371 * is directly an integer stored into 'rule->arg.gpt.value'.
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002372 */
Emeric Brun877b0b52021-06-30 18:57:49 +02002373static enum act_parse_ret parse_set_gpt(const char **args, int *arg, struct proxy *px,
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002374 struct act_rule *rule, char **err)
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002375{
2376 const char *cmd_name = args[*arg-1];
2377 char *error;
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002378 int smp_val;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002379
Emeric Brun877b0b52021-06-30 18:57:49 +02002380 cmd_name += strlen("sc-set-gpt");
2381 if (*cmd_name == '(') {
2382 cmd_name++; /* skip the '(' */
2383 rule->arg.gpt.idx = strtoul(cmd_name, &error, 10); /* Convert stick table id. */
2384 if (*error != ',') {
2385 memprintf(err, "Missing gpt ID '%s'. Expects sc-set-gpt(<GPT ID>,<Track ID>)", args[*arg-1]);
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002386 return ACT_RET_PRS_ERR;
2387 }
Emeric Brun877b0b52021-06-30 18:57:49 +02002388 else {
2389 cmd_name = error + 1; /* skip the ',' */
2390 rule->arg.gpt.sc = strtol(cmd_name, &error, 10); /* Convert stick table id. */
2391 if (*error != ')') {
2392 memprintf(err, "invalid stick table track ID '%s'. Expects sc-set-gpt(<GPT ID>,<Track ID>)", args[*arg-1]);
2393 return ACT_RET_PRS_ERR;
2394 }
2395
2396 if (rule->arg.gpt.sc >= MAX_SESS_STKCTR) {
2397 memprintf(err, "invalid stick table track ID '%s'. The max allowed ID is %d",
2398 args[*arg-1], MAX_SESS_STKCTR-1);
2399 return ACT_RET_PRS_ERR;
2400 }
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002401 }
Emeric Brun877b0b52021-06-30 18:57:49 +02002402 rule->action_ptr = action_set_gpt;
2403 }
2404 else if (*cmd_name == '0') {
2405 cmd_name++;
2406 if (*cmd_name == '\0') {
2407 /* default stick table id. */
2408 rule->arg.gpt.sc = 0;
2409 } else {
2410 /* parse the stick table id. */
2411 if (*cmd_name != '(') {
2412 memprintf(err, "invalid stick table track ID '%s'. Expects sc-set-gpt0(<Track ID>)", args[*arg-1]);
2413 return ACT_RET_PRS_ERR;
2414 }
2415 cmd_name++; /* jump the '(' */
2416 rule->arg.gpt.sc = strtol(cmd_name, &error, 10); /* Convert stick table id. */
2417 if (*error != ')') {
2418 memprintf(err, "invalid stick table track ID '%s'. Expects sc-set-gpt0(<Track ID>)", args[*arg-1]);
2419 return ACT_RET_PRS_ERR;
2420 }
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002421
Emeric Brun877b0b52021-06-30 18:57:49 +02002422 if (rule->arg.gpt.sc >= MAX_SESS_STKCTR) {
2423 memprintf(err, "invalid stick table track ID '%s'. The max allowed ID is %d",
2424 args[*arg-1], MAX_SESS_STKCTR-1);
2425 return ACT_RET_PRS_ERR;
2426 }
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002427 }
Emeric Brun877b0b52021-06-30 18:57:49 +02002428 rule->action_ptr = action_set_gpt0;
2429 }
2430 else {
2431 /* default stick table id. */
2432 memprintf(err, "invalid gpt ID '%s'. Expects sc-set-gpt(<GPT ID>,<Track ID>)", args[*arg-1]);
2433 return ACT_RET_PRS_ERR;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002434 }
2435
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002436 rule->arg.gpt.expr = NULL;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002437 rule->arg.gpt.value = strtol(args[*arg], &error, 10);
2438 if (*error != '\0') {
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002439 rule->arg.gpt.expr = sample_parse_expr((char **)args, arg, px->conf.args.file,
Willy Tarreaue3b57bf2020-02-14 16:50:14 +01002440 px->conf.args.line, err, &px->conf.args, NULL);
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002441 if (!rule->arg.gpt.expr)
2442 return ACT_RET_PRS_ERR;
2443
2444 switch (rule->from) {
2445 case ACT_F_TCP_REQ_SES: smp_val = SMP_VAL_FE_SES_ACC; break;
2446 case ACT_F_TCP_REQ_CNT: smp_val = SMP_VAL_FE_REQ_CNT; break;
2447 case ACT_F_TCP_RES_CNT: smp_val = SMP_VAL_BE_RES_CNT; break;
2448 case ACT_F_HTTP_REQ: smp_val = SMP_VAL_FE_HRQ_HDR; break;
2449 case ACT_F_HTTP_RES: smp_val = SMP_VAL_BE_HRS_HDR; break;
2450 default:
2451 memprintf(err, "internal error, unexpected rule->from=%d, please report this bug!", rule->from);
2452 return ACT_RET_PRS_ERR;
2453 }
2454 if (!(rule->arg.gpt.expr->fetch->val & smp_val)) {
2455 memprintf(err, "fetch method '%s' extracts information from '%s', none of which is available here", args[*arg-1],
2456 sample_src_names(rule->arg.gpt.expr->fetch->use));
2457 free(rule->arg.gpt.expr);
2458 return ACT_RET_PRS_ERR;
2459 }
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002460 }
2461 (*arg)++;
2462
Thierry FOURNIER42148732015-09-02 17:17:33 +02002463 rule->action = ACT_CUSTOM;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002464
2465 return ACT_RET_PRS_OK;
2466}
2467
Willy Tarreau7d562212016-11-25 16:10:05 +01002468/* set temp integer to the number of used entries in the table pointed to by expr.
2469 * Accepts exactly 1 argument of type table.
2470 */
2471static int
2472smp_fetch_table_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
2473{
2474 smp->flags = SMP_F_VOL_TEST;
2475 smp->data.type = SMP_T_SINT;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002476 smp->data.u.sint = args->data.t->current;
Willy Tarreau7d562212016-11-25 16:10:05 +01002477 return 1;
2478}
2479
2480/* set temp integer to the number of free entries in the table pointed to by expr.
2481 * Accepts exactly 1 argument of type table.
2482 */
2483static int
2484smp_fetch_table_avl(const struct arg *args, struct sample *smp, const char *kw, void *private)
2485{
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002486 struct stktable *t;
Willy Tarreau7d562212016-11-25 16:10:05 +01002487
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002488 t = args->data.t;
Willy Tarreau7d562212016-11-25 16:10:05 +01002489 smp->flags = SMP_F_VOL_TEST;
2490 smp->data.type = SMP_T_SINT;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002491 smp->data.u.sint = t->size - t->current;
Willy Tarreau7d562212016-11-25 16:10:05 +01002492 return 1;
2493}
2494
2495/* Returns a pointer to a stkctr depending on the fetch keyword name.
2496 * It is designed to be called as sc[0-9]_* sc_* or src_* exclusively.
2497 * sc[0-9]_* will return a pointer to the respective field in the
2498 * stream <l4>. sc_* requires an UINT argument specifying the stick
2499 * counter number. src_* will fill a locally allocated structure with
2500 * the table and entry corresponding to what is specified with src_*.
2501 * NULL may be returned if the designated stkctr is not tracked. For
2502 * the sc_* and sc[0-9]_* forms, an optional table argument may be
2503 * passed. When present, the currently tracked key is then looked up
2504 * in the specified table instead of the current table. The purpose is
Ilya Shipitsin47d17182020-06-21 21:42:57 +05002505 * to be able to convert multiple values per key (eg: have gpc0 from
Willy Tarreau7d562212016-11-25 16:10:05 +01002506 * multiple tables). <strm> is allowed to be NULL, in which case only
2507 * the session will be consulted.
2508 */
2509struct stkctr *
Emeric Brun819fc6f2017-06-13 19:37:32 +02002510smp_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 +01002511{
Willy Tarreau7d562212016-11-25 16:10:05 +01002512 struct stkctr *stkptr;
2513 struct stksess *stksess;
2514 unsigned int num = kw[2] - '0';
2515 int arg = 0;
2516
2517 if (num == '_' - '0') {
2518 /* sc_* variant, args[0] = ctr# (mandatory) */
2519 num = args[arg++].data.sint;
Willy Tarreau7d562212016-11-25 16:10:05 +01002520 }
2521 else if (num > 9) { /* src_* variant, args[0] = table */
2522 struct stktable_key *key;
2523 struct connection *conn = objt_conn(sess->origin);
2524 struct sample smp;
2525
2526 if (!conn)
2527 return NULL;
2528
Joseph Herlant5662fa42018-11-15 13:43:28 -08002529 /* Fetch source address in a sample. */
Willy Tarreau7d562212016-11-25 16:10:05 +01002530 smp.px = NULL;
2531 smp.sess = sess;
2532 smp.strm = strm;
Amaury Denoyellec460c702021-05-12 10:17:47 +02002533 if (!smp_fetch_src || !smp_fetch_src(empty_arg_list, &smp, "src", NULL))
Willy Tarreau7d562212016-11-25 16:10:05 +01002534 return NULL;
2535
2536 /* Converts into key. */
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002537 key = smp_to_stkey(&smp, args->data.t);
Willy Tarreau7d562212016-11-25 16:10:05 +01002538 if (!key)
2539 return NULL;
2540
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002541 stkctr->table = args->data.t;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002542 stkctr_set_entry(stkctr, stktable_lookup_key(stkctr->table, key));
2543 return stkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002544 }
2545
2546 /* Here, <num> contains the counter number from 0 to 9 for
2547 * the sc[0-9]_ form, or even higher using sc_(num) if needed.
2548 * args[arg] is the first optional argument. We first lookup the
2549 * ctr form the stream, then from the session if it was not there.
Christopher Fauleta9fa88a2019-10-21 10:53:34 +02002550 * But we must be sure the counter does not exceed MAX_SESS_STKCTR.
Willy Tarreau7d562212016-11-25 16:10:05 +01002551 */
Christopher Fauleta9fa88a2019-10-21 10:53:34 +02002552 if (num >= MAX_SESS_STKCTR)
2553 return NULL;
Willy Tarreau7d562212016-11-25 16:10:05 +01002554
2555 if (strm)
2556 stkptr = &strm->stkctr[num];
2557 if (!strm || !stkctr_entry(stkptr)) {
2558 stkptr = &sess->stkctr[num];
2559 if (!stkctr_entry(stkptr))
2560 return NULL;
2561 }
2562
2563 stksess = stkctr_entry(stkptr);
2564 if (!stksess)
2565 return NULL;
2566
2567 if (unlikely(args[arg].type == ARGT_TAB)) {
2568 /* an alternate table was specified, let's look up the same key there */
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002569 stkctr->table = args[arg].data.t;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002570 stkctr_set_entry(stkctr, stktable_lookup(stkctr->table, stksess));
2571 return stkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002572 }
2573 return stkptr;
2574}
2575
2576/* same as smp_fetch_sc_stkctr() but dedicated to src_* and can create
2577 * the entry if it doesn't exist yet. This is needed for a few fetch
2578 * functions which need to create an entry, such as src_inc_gpc* and
2579 * src_clr_gpc*.
2580 */
2581struct stkctr *
Emeric Brun819fc6f2017-06-13 19:37:32 +02002582smp_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 +01002583{
Willy Tarreau7d562212016-11-25 16:10:05 +01002584 struct stktable_key *key;
2585 struct connection *conn = objt_conn(sess->origin);
2586 struct sample smp;
2587
2588 if (strncmp(kw, "src_", 4) != 0)
2589 return NULL;
2590
2591 if (!conn)
2592 return NULL;
2593
Joseph Herlant5662fa42018-11-15 13:43:28 -08002594 /* Fetch source address in a sample. */
Willy Tarreau7d562212016-11-25 16:10:05 +01002595 smp.px = NULL;
2596 smp.sess = sess;
2597 smp.strm = strm;
Amaury Denoyellec460c702021-05-12 10:17:47 +02002598 if (!smp_fetch_src || !smp_fetch_src(empty_arg_list, &smp, "src", NULL))
Willy Tarreau7d562212016-11-25 16:10:05 +01002599 return NULL;
2600
2601 /* Converts into key. */
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002602 key = smp_to_stkey(&smp, args->data.t);
Willy Tarreau7d562212016-11-25 16:10:05 +01002603 if (!key)
2604 return NULL;
2605
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002606 stkctr->table = args->data.t;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002607 stkctr_set_entry(stkctr, stktable_get_entry(stkctr->table, key));
2608 return stkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002609}
2610
2611/* set return a boolean indicating if the requested stream counter is
2612 * currently being tracked or not.
2613 * Supports being called as "sc[0-9]_tracked" only.
2614 */
2615static int
2616smp_fetch_sc_tracked(const struct arg *args, struct sample *smp, const char *kw, void *private)
2617{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002618 struct stkctr tmpstkctr;
2619 struct stkctr *stkctr;
2620
Willy Tarreau7d562212016-11-25 16:10:05 +01002621 smp->flags = SMP_F_VOL_TEST;
2622 smp->data.type = SMP_T_BOOL;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002623 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2624 smp->data.u.sint = !!stkctr;
2625
2626 /* release the ref count */
Dirkjan Bussinkff57f1b2018-09-14 14:31:22 +02002627 if (stkctr == &tmpstkctr)
Emeric Brun819fc6f2017-06-13 19:37:32 +02002628 stktable_release(stkctr->table, stkctr_entry(stkctr));
2629
Emeric Brun877b0b52021-06-30 18:57:49 +02002630 return 1;
2631}
2632
2633/* set <smp> to the General Purpose Tag of index set as first arg
2634 * to value from the stream's tracked frontend counters or from the src.
2635 * Supports being called as "sc_get_gpt(<gpt-idx>,<sc-idx>[,<table>])" or
2636 * "src_get_gpt(<gpt-idx>[,<table>])" only. Value zero is returned if
2637 * the key is new or gpt is not stored.
2638 */
2639static int
2640smp_fetch_sc_get_gpt(const struct arg *args, struct sample *smp, const char *kw, void *private)
2641{
2642 struct stkctr tmpstkctr;
2643 struct stkctr *stkctr;
2644 unsigned int idx;
2645
2646 idx = args[0].data.sint;
2647
2648 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args + 1, kw, &tmpstkctr);
2649 if (!stkctr)
2650 return 0;
2651
2652 smp->flags = SMP_F_VOL_TEST;
2653 smp->data.type = SMP_T_SINT;
2654 smp->data.u.sint = 0;
2655
2656 if (stkctr_entry(stkctr)) {
2657 void *ptr;
2658
2659 ptr = stktable_data_ptr_idx(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPT, idx);
2660 if (!ptr) {
2661 if (stkctr == &tmpstkctr)
2662 stktable_release(stkctr->table, stkctr_entry(stkctr));
2663 return 0; /* parameter not stored */
2664 }
2665
2666 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2667
2668 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
2669
2670 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2671
2672 if (stkctr == &tmpstkctr)
2673 stktable_release(stkctr->table, stkctr_entry(stkctr));
2674 }
Willy Tarreau7d562212016-11-25 16:10:05 +01002675 return 1;
2676}
2677
2678/* set <smp> to the General Purpose Flag 0 value from the stream's tracked
2679 * frontend counters or from the src.
2680 * Supports being called as "sc[0-9]_get_gpc0" or "src_get_gpt0" only. Value
2681 * zero is returned if the key is new.
2682 */
2683static int
2684smp_fetch_sc_get_gpt0(const struct arg *args, struct sample *smp, const char *kw, void *private)
2685{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002686 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002687 struct stkctr *stkctr;
2688
Emeric Brun819fc6f2017-06-13 19:37:32 +02002689 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002690 if (!stkctr)
2691 return 0;
2692
2693 smp->flags = SMP_F_VOL_TEST;
2694 smp->data.type = SMP_T_SINT;
2695 smp->data.u.sint = 0;
2696
Emeric Brun819fc6f2017-06-13 19:37:32 +02002697 if (stkctr_entry(stkctr)) {
2698 void *ptr;
2699
2700 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPT0);
2701 if (!ptr) {
2702 if (stkctr == &tmpstkctr)
2703 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002704 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002705 }
2706
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002707 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002708
Emeric Brun0e3457b2021-06-30 17:18:28 +02002709 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002710
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002711 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002712
2713 if (stkctr == &tmpstkctr)
2714 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002715 }
2716 return 1;
2717}
2718
2719/* set <smp> to the General Purpose Counter 0 value from the stream's tracked
2720 * frontend counters or from the src.
2721 * Supports being called as "sc[0-9]_get_gpc0" or "src_get_gpc0" only. Value
2722 * zero is returned if the key is new.
2723 */
2724static int
2725smp_fetch_sc_get_gpc0(const struct arg *args, struct sample *smp, const char *kw, void *private)
2726{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002727 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002728 struct stkctr *stkctr;
2729
Emeric Brun819fc6f2017-06-13 19:37:32 +02002730 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002731 if (!stkctr)
2732 return 0;
2733
2734 smp->flags = SMP_F_VOL_TEST;
2735 smp->data.type = SMP_T_SINT;
2736 smp->data.u.sint = 0;
2737
2738 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002739 void *ptr;
2740
2741 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0);
2742 if (!ptr) {
2743 if (stkctr == &tmpstkctr)
2744 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002745 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002746 }
2747
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002748 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002749
Emeric Brun0e3457b2021-06-30 17:18:28 +02002750 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002751
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002752 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002753
2754 if (stkctr == &tmpstkctr)
2755 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002756 }
2757 return 1;
2758}
2759
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002760/* set <smp> to the General Purpose Counter 1 value from the stream's tracked
2761 * frontend counters or from the src.
2762 * Supports being called as "sc[0-9]_get_gpc1" or "src_get_gpc1" only. Value
2763 * zero is returned if the key is new.
2764 */
2765static int
2766smp_fetch_sc_get_gpc1(const struct arg *args, struct sample *smp, const char *kw, void *private)
2767{
2768 struct stkctr tmpstkctr;
2769 struct stkctr *stkctr;
2770
2771 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2772 if (!stkctr)
2773 return 0;
2774
2775 smp->flags = SMP_F_VOL_TEST;
2776 smp->data.type = SMP_T_SINT;
2777 smp->data.u.sint = 0;
2778
2779 if (stkctr_entry(stkctr) != NULL) {
2780 void *ptr;
2781
2782 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1);
2783 if (!ptr) {
2784 if (stkctr == &tmpstkctr)
2785 stktable_release(stkctr->table, stkctr_entry(stkctr));
2786 return 0; /* parameter not stored */
2787 }
2788
2789 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2790
Emeric Brun0e3457b2021-06-30 17:18:28 +02002791 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002792
2793 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2794
2795 if (stkctr == &tmpstkctr)
2796 stktable_release(stkctr->table, stkctr_entry(stkctr));
2797 }
2798 return 1;
2799}
2800
Willy Tarreau7d562212016-11-25 16:10:05 +01002801/* set <smp> to the General Purpose Counter 0's event rate from the stream's
2802 * tracked frontend counters or from the src.
2803 * Supports being called as "sc[0-9]_gpc0_rate" or "src_gpc0_rate" only.
2804 * Value zero is returned if the key is new.
2805 */
2806static int
2807smp_fetch_sc_gpc0_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
2808{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002809 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002810 struct stkctr *stkctr;
2811
Emeric Brun819fc6f2017-06-13 19:37:32 +02002812 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002813 if (!stkctr)
2814 return 0;
2815
2816 smp->flags = SMP_F_VOL_TEST;
2817 smp->data.type = SMP_T_SINT;
2818 smp->data.u.sint = 0;
2819 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002820 void *ptr;
2821
2822 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0_RATE);
2823 if (!ptr) {
2824 if (stkctr == &tmpstkctr)
2825 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002826 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002827 }
2828
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002829 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002830
Emeric Brun0e3457b2021-06-30 17:18:28 +02002831 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Willy Tarreau7d562212016-11-25 16:10:05 +01002832 stkctr->table->data_arg[STKTABLE_DT_GPC0_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002833
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002834 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002835
2836 if (stkctr == &tmpstkctr)
2837 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002838 }
2839 return 1;
2840}
2841
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002842/* set <smp> to the General Purpose Counter 1's event rate from the stream's
2843 * tracked frontend counters or from the src.
2844 * Supports being called as "sc[0-9]_gpc1_rate" or "src_gpc1_rate" only.
2845 * Value zero is returned if the key is new.
2846 */
2847static int
2848smp_fetch_sc_gpc1_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
2849{
2850 struct stkctr tmpstkctr;
2851 struct stkctr *stkctr;
2852
2853 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2854 if (!stkctr)
2855 return 0;
2856
2857 smp->flags = SMP_F_VOL_TEST;
2858 smp->data.type = SMP_T_SINT;
2859 smp->data.u.sint = 0;
2860 if (stkctr_entry(stkctr) != NULL) {
2861 void *ptr;
2862
2863 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1_RATE);
2864 if (!ptr) {
2865 if (stkctr == &tmpstkctr)
2866 stktable_release(stkctr->table, stkctr_entry(stkctr));
2867 return 0; /* parameter not stored */
2868 }
2869
2870 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2871
Emeric Brun0e3457b2021-06-30 17:18:28 +02002872 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002873 stkctr->table->data_arg[STKTABLE_DT_GPC1_RATE].u);
2874
2875 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2876
2877 if (stkctr == &tmpstkctr)
2878 stktable_release(stkctr->table, stkctr_entry(stkctr));
2879 }
2880 return 1;
2881}
2882
Willy Tarreau7d562212016-11-25 16:10:05 +01002883/* Increment the General Purpose Counter 0 value from the stream's tracked
2884 * frontend counters and return it into temp integer.
2885 * Supports being called as "sc[0-9]_inc_gpc0" or "src_inc_gpc0" only.
2886 */
2887static int
2888smp_fetch_sc_inc_gpc0(const struct arg *args, struct sample *smp, const char *kw, void *private)
2889{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002890 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002891 struct stkctr *stkctr;
2892
Emeric Brun819fc6f2017-06-13 19:37:32 +02002893 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002894 if (!stkctr)
2895 return 0;
2896
2897 smp->flags = SMP_F_VOL_TEST;
2898 smp->data.type = SMP_T_SINT;
2899 smp->data.u.sint = 0;
2900
Emeric Brun819fc6f2017-06-13 19:37:32 +02002901 if (!stkctr_entry(stkctr))
2902 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002903
2904 if (stkctr && stkctr_entry(stkctr)) {
2905 void *ptr1,*ptr2;
2906
Emeric Brun819fc6f2017-06-13 19:37:32 +02002907
Willy Tarreau7d562212016-11-25 16:10:05 +01002908 /* First, update gpc0_rate if it's tracked. Second, update its
2909 * gpc0 if tracked. Returns gpc0's value otherwise the curr_ctr.
2910 */
2911 ptr1 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0_RATE);
Willy Tarreau7d562212016-11-25 16:10:05 +01002912 ptr2 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002913 if (ptr1 || ptr2) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002914 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Willy Tarreau7d562212016-11-25 16:10:05 +01002915
Emeric Brun819fc6f2017-06-13 19:37:32 +02002916 if (ptr1) {
Emeric Brun0e3457b2021-06-30 17:18:28 +02002917 update_freq_ctr_period(&stktable_data_cast(ptr1, std_t_frqp),
Emeric Brun819fc6f2017-06-13 19:37:32 +02002918 stkctr->table->data_arg[STKTABLE_DT_GPC0_RATE].u, 1);
Emeric Brun0e3457b2021-06-30 17:18:28 +02002919 smp->data.u.sint = (&stktable_data_cast(ptr1, std_t_frqp))->curr_ctr;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002920 }
2921
2922 if (ptr2)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002923 smp->data.u.sint = ++stktable_data_cast(ptr2, std_t_uint);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002924
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002925 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002926
2927 /* If data was modified, we need to touch to re-schedule sync */
2928 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
2929 }
2930 else if (stkctr == &tmpstkctr)
2931 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002932 }
2933 return 1;
2934}
2935
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002936/* Increment the General Purpose Counter 1 value from the stream's tracked
2937 * frontend counters and return it into temp integer.
2938 * Supports being called as "sc[0-9]_inc_gpc1" or "src_inc_gpc1" only.
2939 */
2940static int
2941smp_fetch_sc_inc_gpc1(const struct arg *args, struct sample *smp, const char *kw, void *private)
2942{
2943 struct stkctr tmpstkctr;
2944 struct stkctr *stkctr;
2945
2946 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2947 if (!stkctr)
2948 return 0;
2949
2950 smp->flags = SMP_F_VOL_TEST;
2951 smp->data.type = SMP_T_SINT;
2952 smp->data.u.sint = 0;
2953
2954 if (!stkctr_entry(stkctr))
2955 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2956
2957 if (stkctr && stkctr_entry(stkctr)) {
2958 void *ptr1,*ptr2;
2959
2960
2961 /* First, update gpc1_rate if it's tracked. Second, update its
2962 * gpc1 if tracked. Returns gpc1's value otherwise the curr_ctr.
2963 */
2964 ptr1 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1_RATE);
2965 ptr2 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1);
2966 if (ptr1 || ptr2) {
2967 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2968
2969 if (ptr1) {
Emeric Brun0e3457b2021-06-30 17:18:28 +02002970 update_freq_ctr_period(&stktable_data_cast(ptr1, std_t_frqp),
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002971 stkctr->table->data_arg[STKTABLE_DT_GPC1_RATE].u, 1);
Emeric Brun0e3457b2021-06-30 17:18:28 +02002972 smp->data.u.sint = (&stktable_data_cast(ptr1, std_t_frqp))->curr_ctr;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002973 }
2974
2975 if (ptr2)
Emeric Brun0e3457b2021-06-30 17:18:28 +02002976 smp->data.u.sint = ++stktable_data_cast(ptr2, std_t_uint);
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002977
2978 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2979
2980 /* If data was modified, we need to touch to re-schedule sync */
2981 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
2982 }
2983 else if (stkctr == &tmpstkctr)
2984 stktable_release(stkctr->table, stkctr_entry(stkctr));
2985 }
2986 return 1;
2987}
2988
Willy Tarreau7d562212016-11-25 16:10:05 +01002989/* Clear the General Purpose Counter 0 value from the stream's tracked
2990 * frontend counters and return its previous value into temp integer.
2991 * Supports being called as "sc[0-9]_clr_gpc0" or "src_clr_gpc0" only.
2992 */
2993static int
2994smp_fetch_sc_clr_gpc0(const struct arg *args, struct sample *smp, const char *kw, void *private)
2995{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002996 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002997 struct stkctr *stkctr;
2998
Emeric Brun819fc6f2017-06-13 19:37:32 +02002999 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003000 if (!stkctr)
3001 return 0;
3002
3003 smp->flags = SMP_F_VOL_TEST;
3004 smp->data.type = SMP_T_SINT;
3005 smp->data.u.sint = 0;
3006
Emeric Brun819fc6f2017-06-13 19:37:32 +02003007 if (!stkctr_entry(stkctr))
3008 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003009
Emeric Brun819fc6f2017-06-13 19:37:32 +02003010 if (stkctr && stkctr_entry(stkctr)) {
3011 void *ptr;
3012
3013 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0);
3014 if (!ptr) {
3015 if (stkctr == &tmpstkctr)
3016 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003017 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003018 }
3019
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003020 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003021
Emeric Brun0e3457b2021-06-30 17:18:28 +02003022 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
3023 stktable_data_cast(ptr, std_t_uint) = 0;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003024
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003025 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003026
Willy Tarreau7d562212016-11-25 16:10:05 +01003027 /* If data was modified, we need to touch to re-schedule sync */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003028 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
Willy Tarreau7d562212016-11-25 16:10:05 +01003029 }
3030 return 1;
3031}
3032
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003033/* Clear the General Purpose Counter 1 value from the stream's tracked
3034 * frontend counters and return its previous value into temp integer.
3035 * Supports being called as "sc[0-9]_clr_gpc1" or "src_clr_gpc1" only.
3036 */
3037static int
3038smp_fetch_sc_clr_gpc1(const struct arg *args, struct sample *smp, const char *kw, void *private)
3039{
3040 struct stkctr tmpstkctr;
3041 struct stkctr *stkctr;
3042
3043 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
3044 if (!stkctr)
3045 return 0;
3046
3047 smp->flags = SMP_F_VOL_TEST;
3048 smp->data.type = SMP_T_SINT;
3049 smp->data.u.sint = 0;
3050
3051 if (!stkctr_entry(stkctr))
3052 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
3053
3054 if (stkctr && stkctr_entry(stkctr)) {
3055 void *ptr;
3056
3057 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1);
3058 if (!ptr) {
3059 if (stkctr == &tmpstkctr)
3060 stktable_release(stkctr->table, stkctr_entry(stkctr));
3061 return 0; /* parameter not stored */
3062 }
3063
3064 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3065
Emeric Brun0e3457b2021-06-30 17:18:28 +02003066 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
3067 stktable_data_cast(ptr, std_t_uint) = 0;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003068
3069 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3070
3071 /* If data was modified, we need to touch to re-schedule sync */
3072 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
3073 }
3074 return 1;
3075}
3076
Willy Tarreau7d562212016-11-25 16:10:05 +01003077/* set <smp> to the cumulated number of connections from the stream's tracked
3078 * frontend counters. Supports being called as "sc[0-9]_conn_cnt" or
3079 * "src_conn_cnt" only.
3080 */
3081static int
3082smp_fetch_sc_conn_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
3083{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003084 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003085 struct stkctr *stkctr;
3086
Emeric Brun819fc6f2017-06-13 19:37:32 +02003087 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003088 if (!stkctr)
3089 return 0;
3090
3091 smp->flags = SMP_F_VOL_TEST;
3092 smp->data.type = SMP_T_SINT;
3093 smp->data.u.sint = 0;
3094 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003095 void *ptr;
3096
3097 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_CONN_CNT);
3098 if (!ptr) {
3099 if (stkctr == &tmpstkctr)
3100 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003101 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003102 }
3103
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003104 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003105
Emeric Brun0e3457b2021-06-30 17:18:28 +02003106 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003107
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003108 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003109
3110 if (stkctr == &tmpstkctr)
3111 stktable_release(stkctr->table, stkctr_entry(stkctr));
3112
3113
Willy Tarreau7d562212016-11-25 16:10:05 +01003114 }
3115 return 1;
3116}
3117
3118/* set <smp> to the connection rate from the stream's tracked frontend
3119 * counters. Supports being called as "sc[0-9]_conn_rate" or "src_conn_rate"
3120 * only.
3121 */
3122static int
3123smp_fetch_sc_conn_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3124{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003125 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003126 struct stkctr *stkctr;
3127
Emeric Brun819fc6f2017-06-13 19:37:32 +02003128 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003129 if (!stkctr)
3130 return 0;
3131
3132 smp->flags = SMP_F_VOL_TEST;
3133 smp->data.type = SMP_T_SINT;
3134 smp->data.u.sint = 0;
3135 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003136 void *ptr;
3137
3138 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_CONN_RATE);
3139 if (!ptr) {
3140 if (stkctr == &tmpstkctr)
3141 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003142 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003143 }
3144
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003145 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003146
Emeric Brun0e3457b2021-06-30 17:18:28 +02003147 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Willy Tarreau7d562212016-11-25 16:10:05 +01003148 stkctr->table->data_arg[STKTABLE_DT_CONN_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003149
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003150 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003151
3152 if (stkctr == &tmpstkctr)
3153 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003154 }
3155 return 1;
3156}
3157
3158/* set temp integer to the number of connections from the stream's source address
3159 * in the table pointed to by expr, after updating it.
3160 * Accepts exactly 1 argument of type table.
3161 */
3162static int
3163smp_fetch_src_updt_conn_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
3164{
3165 struct connection *conn = objt_conn(smp->sess->origin);
3166 struct stksess *ts;
3167 struct stktable_key *key;
3168 void *ptr;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003169 struct stktable *t;
Willy Tarreau7d562212016-11-25 16:10:05 +01003170
3171 if (!conn)
3172 return 0;
3173
Joseph Herlant5662fa42018-11-15 13:43:28 -08003174 /* Fetch source address in a sample. */
Amaury Denoyellec460c702021-05-12 10:17:47 +02003175 if (!smp_fetch_src || !smp_fetch_src(empty_arg_list, smp, "src", NULL))
Willy Tarreau7d562212016-11-25 16:10:05 +01003176 return 0;
3177
3178 /* Converts into key. */
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003179 key = smp_to_stkey(smp, args->data.t);
Willy Tarreau7d562212016-11-25 16:10:05 +01003180 if (!key)
3181 return 0;
3182
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003183 t = args->data.t;
Willy Tarreau7d562212016-11-25 16:10:05 +01003184
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003185 if ((ts = stktable_get_entry(t, key)) == NULL)
Willy Tarreau7d562212016-11-25 16:10:05 +01003186 /* entry does not exist and could not be created */
3187 return 0;
3188
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003189 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_CONN_CNT);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003190 if (!ptr) {
Willy Tarreau7d562212016-11-25 16:10:05 +01003191 return 0; /* parameter not stored in this table */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003192 }
Willy Tarreau7d562212016-11-25 16:10:05 +01003193
3194 smp->data.type = SMP_T_SINT;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003195
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003196 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003197
Emeric Brun0e3457b2021-06-30 17:18:28 +02003198 smp->data.u.sint = ++stktable_data_cast(ptr, std_t_uint);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003199
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003200 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003201
Willy Tarreau7d562212016-11-25 16:10:05 +01003202 smp->flags = SMP_F_VOL_TEST;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003203
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003204 stktable_touch_local(t, ts, 1);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003205
3206 /* Touch was previously performed by stktable_update_key */
Willy Tarreau7d562212016-11-25 16:10:05 +01003207 return 1;
3208}
3209
3210/* set <smp> to the number of concurrent connections from the stream's tracked
3211 * frontend counters. Supports being called as "sc[0-9]_conn_cur" or
3212 * "src_conn_cur" only.
3213 */
3214static int
3215smp_fetch_sc_conn_cur(const struct arg *args, struct sample *smp, const char *kw, void *private)
3216{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003217 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003218 struct stkctr *stkctr;
3219
Emeric Brun819fc6f2017-06-13 19:37:32 +02003220 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003221 if (!stkctr)
3222 return 0;
3223
3224 smp->flags = SMP_F_VOL_TEST;
3225 smp->data.type = SMP_T_SINT;
3226 smp->data.u.sint = 0;
3227 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003228 void *ptr;
3229
3230 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_CONN_CUR);
3231 if (!ptr) {
3232 if (stkctr == &tmpstkctr)
3233 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003234 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003235 }
3236
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003237 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003238
Emeric Brun0e3457b2021-06-30 17:18:28 +02003239 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003240
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003241 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003242
3243 if (stkctr == &tmpstkctr)
3244 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003245 }
3246 return 1;
3247}
3248
3249/* set <smp> to the cumulated number of streams from the stream's tracked
3250 * frontend counters. Supports being called as "sc[0-9]_sess_cnt" or
3251 * "src_sess_cnt" only.
3252 */
3253static int
3254smp_fetch_sc_sess_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
3255{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003256 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003257 struct stkctr *stkctr;
3258
Emeric Brun819fc6f2017-06-13 19:37:32 +02003259 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003260 if (!stkctr)
3261 return 0;
3262
3263 smp->flags = SMP_F_VOL_TEST;
3264 smp->data.type = SMP_T_SINT;
3265 smp->data.u.sint = 0;
3266 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003267 void *ptr;
3268
3269 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_SESS_CNT);
3270 if (!ptr) {
3271 if (stkctr == &tmpstkctr)
3272 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003273 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003274 }
3275
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003276 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003277
Emeric Brun0e3457b2021-06-30 17:18:28 +02003278 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
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
3288/* set <smp> to the stream rate from the stream's tracked frontend counters.
3289 * Supports being called as "sc[0-9]_sess_rate" or "src_sess_rate" only.
3290 */
3291static int
3292smp_fetch_sc_sess_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3293{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003294 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003295 struct stkctr *stkctr;
3296
Emeric Brun819fc6f2017-06-13 19:37:32 +02003297 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003298 if (!stkctr)
3299 return 0;
3300
3301 smp->flags = SMP_F_VOL_TEST;
3302 smp->data.type = SMP_T_SINT;
3303 smp->data.u.sint = 0;
3304 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003305 void *ptr;
3306
3307 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_SESS_RATE);
3308 if (!ptr) {
3309 if (stkctr == &tmpstkctr)
3310 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003311 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003312 }
3313
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003314 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003315
Emeric Brun0e3457b2021-06-30 17:18:28 +02003316 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Willy Tarreau7d562212016-11-25 16:10:05 +01003317 stkctr->table->data_arg[STKTABLE_DT_SESS_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003318
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003319 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003320
3321 if (stkctr == &tmpstkctr)
3322 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003323 }
3324 return 1;
3325}
3326
3327/* set <smp> to the cumulated number of HTTP requests from the stream's tracked
3328 * frontend counters. Supports being called as "sc[0-9]_http_req_cnt" or
3329 * "src_http_req_cnt" only.
3330 */
3331static int
3332smp_fetch_sc_http_req_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
3333{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003334 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003335 struct stkctr *stkctr;
3336
Emeric Brun819fc6f2017-06-13 19:37:32 +02003337 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003338 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) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003345 void *ptr;
3346
3347 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_REQ_CNT);
3348 if (!ptr) {
3349 if (stkctr == &tmpstkctr)
3350 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003351 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003352 }
3353
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003354 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003355
Emeric Brun0e3457b2021-06-30 17:18:28 +02003356 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003357
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003358 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003359
3360 if (stkctr == &tmpstkctr)
3361 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003362 }
3363 return 1;
3364}
3365
3366/* set <smp> to the HTTP request rate from the stream's tracked frontend
3367 * counters. Supports being called as "sc[0-9]_http_req_rate" or
3368 * "src_http_req_rate" only.
3369 */
3370static int
3371smp_fetch_sc_http_req_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3372{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003373 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003374 struct stkctr *stkctr;
3375
Emeric Brun819fc6f2017-06-13 19:37:32 +02003376 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003377 if (!stkctr)
3378 return 0;
3379
3380 smp->flags = SMP_F_VOL_TEST;
3381 smp->data.type = SMP_T_SINT;
3382 smp->data.u.sint = 0;
3383 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003384 void *ptr;
3385
3386 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_REQ_RATE);
3387 if (!ptr) {
3388 if (stkctr == &tmpstkctr)
3389 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003390 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003391 }
3392
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003393 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003394
Emeric Brun0e3457b2021-06-30 17:18:28 +02003395 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Willy Tarreau7d562212016-11-25 16:10:05 +01003396 stkctr->table->data_arg[STKTABLE_DT_HTTP_REQ_RATE].u);
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 cumulated number of HTTP requests errors from the stream's
3407 * tracked frontend counters. Supports being called as "sc[0-9]_http_err_cnt" or
3408 * "src_http_err_cnt" only.
3409 */
3410static int
3411smp_fetch_sc_http_err_cnt(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_HTTP_ERR_CNT);
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
Emeric Brun0e3457b2021-06-30 17:18:28 +02003435 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003436
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003437 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003438
3439 if (stkctr == &tmpstkctr)
3440 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003441 }
3442 return 1;
3443}
3444
3445/* set <smp> to the HTTP request error rate from the stream's tracked frontend
3446 * counters. Supports being called as "sc[0-9]_http_err_rate" or
3447 * "src_http_err_rate" only.
3448 */
3449static int
3450smp_fetch_sc_http_err_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3451{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003452 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003453 struct stkctr *stkctr;
3454
Emeric Brun819fc6f2017-06-13 19:37:32 +02003455 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003456 if (!stkctr)
3457 return 0;
3458
3459 smp->flags = SMP_F_VOL_TEST;
3460 smp->data.type = SMP_T_SINT;
3461 smp->data.u.sint = 0;
3462 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003463 void *ptr;
3464
3465 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_ERR_RATE);
3466 if (!ptr) {
3467 if (stkctr == &tmpstkctr)
3468 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003469 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003470 }
3471
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003472 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003473
Emeric Brun0e3457b2021-06-30 17:18:28 +02003474 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Willy Tarreau7d562212016-11-25 16:10:05 +01003475 stkctr->table->data_arg[STKTABLE_DT_HTTP_ERR_RATE].u);
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
Willy Tarreau826f3ab2021-02-10 12:07:15 +01003485/* set <smp> to the cumulated number of HTTP response failures from the stream's
3486 * tracked frontend counters. Supports being called as "sc[0-9]_http_fail_cnt" or
3487 * "src_http_fail_cnt" only.
3488 */
3489static int
3490smp_fetch_sc_http_fail_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
3491{
3492 struct stkctr tmpstkctr;
3493 struct stkctr *stkctr;
3494
3495 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
3496 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) {
3503 void *ptr;
3504
3505 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_FAIL_CNT);
3506 if (!ptr) {
3507 if (stkctr == &tmpstkctr)
3508 stktable_release(stkctr->table, stkctr_entry(stkctr));
3509 return 0; /* parameter not stored */
3510 }
3511
3512 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3513
Emeric Brun0e3457b2021-06-30 17:18:28 +02003514 smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
Willy Tarreau826f3ab2021-02-10 12:07:15 +01003515
3516 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3517
3518 if (stkctr == &tmpstkctr)
3519 stktable_release(stkctr->table, stkctr_entry(stkctr));
3520 }
3521 return 1;
3522}
3523
3524/* set <smp> to the HTTP response failure rate from the stream's tracked frontend
3525 * counters. Supports being called as "sc[0-9]_http_fail_rate" or
3526 * "src_http_fail_rate" only.
3527 */
3528static int
3529smp_fetch_sc_http_fail_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3530{
3531 struct stkctr tmpstkctr;
3532 struct stkctr *stkctr;
3533
3534 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
3535 if (!stkctr)
3536 return 0;
3537
3538 smp->flags = SMP_F_VOL_TEST;
3539 smp->data.type = SMP_T_SINT;
3540 smp->data.u.sint = 0;
3541 if (stkctr_entry(stkctr) != NULL) {
3542 void *ptr;
3543
3544 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_FAIL_RATE);
3545 if (!ptr) {
3546 if (stkctr == &tmpstkctr)
3547 stktable_release(stkctr->table, stkctr_entry(stkctr));
3548 return 0; /* parameter not stored */
3549 }
3550
3551 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3552
Emeric Brun0e3457b2021-06-30 17:18:28 +02003553 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Willy Tarreau826f3ab2021-02-10 12:07:15 +01003554 stkctr->table->data_arg[STKTABLE_DT_HTTP_FAIL_RATE].u);
3555
3556 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3557
3558 if (stkctr == &tmpstkctr)
3559 stktable_release(stkctr->table, stkctr_entry(stkctr));
3560 }
3561 return 1;
3562}
3563
Willy Tarreau7d562212016-11-25 16:10:05 +01003564/* set <smp> to the number of kbytes received from clients, as found in the
3565 * stream's tracked frontend counters. Supports being called as
3566 * "sc[0-9]_kbytes_in" or "src_kbytes_in" only.
3567 */
3568static int
3569smp_fetch_sc_kbytes_in(const struct arg *args, struct sample *smp, const char *kw, void *private)
3570{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003571 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003572 struct stkctr *stkctr;
3573
Emeric Brun819fc6f2017-06-13 19:37:32 +02003574 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003575 if (!stkctr)
3576 return 0;
3577
3578 smp->flags = SMP_F_VOL_TEST;
3579 smp->data.type = SMP_T_SINT;
3580 smp->data.u.sint = 0;
3581 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003582 void *ptr;
3583
3584 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_IN_CNT);
3585 if (!ptr) {
3586 if (stkctr == &tmpstkctr)
3587 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003588 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003589 }
3590
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003591 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003592
Emeric Brun0e3457b2021-06-30 17:18:28 +02003593 smp->data.u.sint = stktable_data_cast(ptr, std_t_ull) >> 10;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003594
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003595 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003596
3597 if (stkctr == &tmpstkctr)
3598 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003599 }
3600 return 1;
3601}
3602
3603/* set <smp> to the data rate received from clients in bytes/s, as found
3604 * in the stream's tracked frontend counters. Supports being called as
3605 * "sc[0-9]_bytes_in_rate" or "src_bytes_in_rate" only.
3606 */
3607static int
3608smp_fetch_sc_bytes_in_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3609{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003610 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003611 struct stkctr *stkctr;
3612
Emeric Brun819fc6f2017-06-13 19:37:32 +02003613 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003614 if (!stkctr)
3615 return 0;
3616
3617 smp->flags = SMP_F_VOL_TEST;
3618 smp->data.type = SMP_T_SINT;
3619 smp->data.u.sint = 0;
3620 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003621 void *ptr;
3622
3623 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_IN_RATE);
3624 if (!ptr) {
3625 if (stkctr == &tmpstkctr)
3626 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003627 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003628 }
3629
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003630 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003631
Emeric Brun0e3457b2021-06-30 17:18:28 +02003632 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Willy Tarreau7d562212016-11-25 16:10:05 +01003633 stkctr->table->data_arg[STKTABLE_DT_BYTES_IN_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003634
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003635 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003636
3637 if (stkctr == &tmpstkctr)
3638 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003639 }
3640 return 1;
3641}
3642
3643/* set <smp> to the number of kbytes sent to clients, as found in the
3644 * stream's tracked frontend counters. Supports being called as
3645 * "sc[0-9]_kbytes_out" or "src_kbytes_out" only.
3646 */
3647static int
3648smp_fetch_sc_kbytes_out(const struct arg *args, struct sample *smp, const char *kw, void *private)
3649{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003650 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003651 struct stkctr *stkctr;
3652
Emeric Brun819fc6f2017-06-13 19:37:32 +02003653 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003654 if (!stkctr)
3655 return 0;
3656
3657 smp->flags = SMP_F_VOL_TEST;
3658 smp->data.type = SMP_T_SINT;
3659 smp->data.u.sint = 0;
3660 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003661 void *ptr;
3662
3663 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_OUT_CNT);
3664 if (!ptr) {
3665 if (stkctr == &tmpstkctr)
3666 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003667 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003668 }
3669
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003670 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003671
Emeric Brun0e3457b2021-06-30 17:18:28 +02003672 smp->data.u.sint = stktable_data_cast(ptr, std_t_ull) >> 10;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003673
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003674 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003675
3676 if (stkctr == &tmpstkctr)
3677 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003678 }
3679 return 1;
3680}
3681
3682/* set <smp> to the data rate sent to clients in bytes/s, as found in the
3683 * stream's tracked frontend counters. Supports being called as
3684 * "sc[0-9]_bytes_out_rate" or "src_bytes_out_rate" only.
3685 */
3686static int
3687smp_fetch_sc_bytes_out_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3688{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003689 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003690 struct stkctr *stkctr;
3691
Emeric Brun819fc6f2017-06-13 19:37:32 +02003692 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003693 if (!stkctr)
3694 return 0;
3695
3696 smp->flags = SMP_F_VOL_TEST;
3697 smp->data.type = SMP_T_SINT;
3698 smp->data.u.sint = 0;
3699 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003700 void *ptr;
3701
3702 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_OUT_RATE);
3703 if (!ptr) {
3704 if (stkctr == &tmpstkctr)
3705 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003706 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003707 }
3708
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003709 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003710
Emeric Brun0e3457b2021-06-30 17:18:28 +02003711 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Willy Tarreau7d562212016-11-25 16:10:05 +01003712 stkctr->table->data_arg[STKTABLE_DT_BYTES_OUT_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003713
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003714 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003715
3716 if (stkctr == &tmpstkctr)
3717 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003718 }
3719 return 1;
3720}
3721
3722/* set <smp> to the number of active trackers on the SC entry in the stream's
3723 * tracked frontend counters. Supports being called as "sc[0-9]_trackers" only.
3724 */
3725static int
3726smp_fetch_sc_trackers(const struct arg *args, struct sample *smp, const char *kw, void *private)
3727{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003728 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003729 struct stkctr *stkctr;
3730
Emeric Brun819fc6f2017-06-13 19:37:32 +02003731 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003732 if (!stkctr)
3733 return 0;
3734
3735 smp->flags = SMP_F_VOL_TEST;
3736 smp->data.type = SMP_T_SINT;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003737 if (stkctr == &tmpstkctr) {
3738 smp->data.u.sint = stkctr_entry(stkctr) ? (stkctr_entry(stkctr)->ref_cnt-1) : 0;
3739 stktable_release(stkctr->table, stkctr_entry(stkctr));
3740 }
3741 else {
3742 smp->data.u.sint = stkctr_entry(stkctr) ? stkctr_entry(stkctr)->ref_cnt : 0;
3743 }
3744
Willy Tarreau7d562212016-11-25 16:10:05 +01003745 return 1;
3746}
3747
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003748
3749/* The functions below are used to manipulate table contents from the CLI.
3750 * There are 3 main actions, "clear", "set" and "show". The code is shared
3751 * between all actions, and the action is encoded in the void *private in
3752 * the appctx as well as in the keyword registration, among one of the
3753 * following values.
3754 */
3755
3756enum {
3757 STK_CLI_ACT_CLR,
3758 STK_CLI_ACT_SET,
3759 STK_CLI_ACT_SHOW,
3760};
3761
3762/* Dump the status of a table to a stream interface's
3763 * read buffer. It returns 0 if the output buffer is full
3764 * and needs to be called again, otherwise non-zero.
3765 */
Willy Tarreau83061a82018-07-13 11:56:34 +02003766static int table_dump_head_to_buffer(struct buffer *msg,
3767 struct stream_interface *si,
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003768 struct stktable *t, struct stktable *target)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003769{
3770 struct stream *s = si_strm(si);
3771
3772 chunk_appendf(msg, "# table: %s, type: %s, size:%d, used:%d\n",
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003773 t->id, stktable_types[t->type].kw, t->size, t->current);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003774
3775 /* any other information should be dumped here */
3776
William Lallemand07a62f72017-05-24 00:57:40 +02003777 if (target && (strm_li(s)->bind_conf->level & ACCESS_LVL_MASK) < ACCESS_LVL_OPER)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003778 chunk_appendf(msg, "# contents not dumped due to insufficient privileges\n");
3779
Willy Tarreau06d80a92017-10-19 14:32:15 +02003780 if (ci_putchk(si_ic(si), msg) == -1) {
Willy Tarreaudb398432018-11-15 11:08:52 +01003781 si_rx_room_blk(si);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003782 return 0;
3783 }
3784
3785 return 1;
3786}
3787
3788/* Dump a table entry to a stream interface's
3789 * read buffer. It returns 0 if the output buffer is full
3790 * and needs to be called again, otherwise non-zero.
3791 */
Willy Tarreau83061a82018-07-13 11:56:34 +02003792static int table_dump_entry_to_buffer(struct buffer *msg,
3793 struct stream_interface *si,
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003794 struct stktable *t, struct stksess *entry)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003795{
3796 int dt;
3797
3798 chunk_appendf(msg, "%p:", entry);
3799
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003800 if (t->type == SMP_T_IPV4) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003801 char addr[INET_ADDRSTRLEN];
3802 inet_ntop(AF_INET, (const void *)&entry->key.key, addr, sizeof(addr));
3803 chunk_appendf(msg, " key=%s", addr);
3804 }
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003805 else if (t->type == SMP_T_IPV6) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003806 char addr[INET6_ADDRSTRLEN];
3807 inet_ntop(AF_INET6, (const void *)&entry->key.key, addr, sizeof(addr));
3808 chunk_appendf(msg, " key=%s", addr);
3809 }
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003810 else if (t->type == SMP_T_SINT) {
Willy Tarreau6cde5d82020-02-25 09:41:22 +01003811 chunk_appendf(msg, " key=%u", read_u32(entry->key.key));
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003812 }
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003813 else if (t->type == SMP_T_STR) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003814 chunk_appendf(msg, " key=");
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003815 dump_text(msg, (const char *)entry->key.key, t->key_size);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003816 }
3817 else {
3818 chunk_appendf(msg, " key=");
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003819 dump_binary(msg, (const char *)entry->key.key, t->key_size);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003820 }
3821
3822 chunk_appendf(msg, " use=%d exp=%d", entry->ref_cnt - 1, tick_remain(now_ms, entry->expire));
3823
3824 for (dt = 0; dt < STKTABLE_DATA_TYPES; dt++) {
3825 void *ptr;
3826
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003827 if (t->data_ofs[dt] == 0)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003828 continue;
Emeric Brunc64a2a32021-06-30 18:01:02 +02003829 if (stktable_data_types[dt].is_array) {
3830 char tmp[16] = {};
3831 const char *name_pfx = stktable_data_types[dt].name;
3832 const char *name_sfx = NULL;
3833 unsigned int idx = 0;
3834 int i = 0;
3835
3836 /* split name to show index before first _ of the name
3837 * for example: 'gpc3_rate' if array name is 'gpc_rate'.
3838 */
3839 for (i = 0 ; i < (sizeof(tmp) - 1); i++) {
3840 if (!name_pfx[i])
3841 break;
3842 if (name_pfx[i] == '_') {
3843 name_pfx = &tmp[0];
3844 name_sfx = &stktable_data_types[dt].name[i];
3845 break;
3846 }
3847 tmp[i] = name_pfx[i];
3848 }
3849
3850 ptr = stktable_data_ptr_idx(t, entry, dt, idx);
3851 while (ptr) {
3852 if (stktable_data_types[dt].arg_type == ARG_T_DELAY)
3853 chunk_appendf(msg, " %s%u%s(%u)=", name_pfx, idx, name_sfx ? name_sfx : "", t->data_arg[dt].u);
3854 else
3855 chunk_appendf(msg, " %s%u%s=", name_pfx, idx, name_sfx ? name_sfx : "");
3856 switch (stktable_data_types[dt].std_type) {
3857 case STD_T_SINT:
3858 chunk_appendf(msg, "%d", stktable_data_cast(ptr, std_t_sint));
3859 break;
3860 case STD_T_UINT:
3861 chunk_appendf(msg, "%u", stktable_data_cast(ptr, std_t_uint));
3862 break;
3863 case STD_T_ULL:
3864 chunk_appendf(msg, "%llu", stktable_data_cast(ptr, std_t_ull));
3865 break;
3866 case STD_T_FRQP:
3867 chunk_appendf(msg, "%u",
3868 read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
3869 t->data_arg[dt].u));
3870 break;
3871 }
3872 ptr = stktable_data_ptr_idx(t, entry, dt, ++idx);
3873 }
3874 continue;
3875 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003876 if (stktable_data_types[dt].arg_type == ARG_T_DELAY)
Emeric Brun01928ae2021-06-30 16:24:04 +02003877 chunk_appendf(msg, " %s(%u)=", stktable_data_types[dt].name, t->data_arg[dt].u);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003878 else
3879 chunk_appendf(msg, " %s=", stktable_data_types[dt].name);
3880
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003881 ptr = stktable_data_ptr(t, entry, dt);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003882 switch (stktable_data_types[dt].std_type) {
3883 case STD_T_SINT:
3884 chunk_appendf(msg, "%d", stktable_data_cast(ptr, std_t_sint));
3885 break;
3886 case STD_T_UINT:
3887 chunk_appendf(msg, "%u", stktable_data_cast(ptr, std_t_uint));
3888 break;
3889 case STD_T_ULL:
Emeric Brun01928ae2021-06-30 16:24:04 +02003890 chunk_appendf(msg, "%llu", stktable_data_cast(ptr, std_t_ull));
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003891 break;
3892 case STD_T_FRQP:
Emeric Brun01928ae2021-06-30 16:24:04 +02003893 chunk_appendf(msg, "%u",
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003894 read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003895 t->data_arg[dt].u));
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003896 break;
Frédéric Lécaille16b4f542019-05-23 12:15:04 +02003897 case STD_T_DICT: {
3898 struct dict_entry *de;
3899 de = stktable_data_cast(ptr, std_t_dict);
3900 chunk_appendf(msg, "%s", de ? (char *)de->value.key : "-");
3901 break;
3902 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003903 }
3904 }
3905 chunk_appendf(msg, "\n");
3906
Willy Tarreau06d80a92017-10-19 14:32:15 +02003907 if (ci_putchk(si_ic(si), msg) == -1) {
Willy Tarreaudb398432018-11-15 11:08:52 +01003908 si_rx_room_blk(si);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003909 return 0;
3910 }
3911
3912 return 1;
3913}
3914
3915
3916/* Processes a single table entry matching a specific key passed in argument.
3917 * returns 0 if wants to be called again, 1 if has ended processing.
3918 */
3919static int table_process_entry_per_key(struct appctx *appctx, char **args)
3920{
3921 struct stream_interface *si = appctx->owner;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003922 struct stktable *t = appctx->ctx.table.target;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003923 struct stksess *ts;
3924 uint32_t uint32_key;
3925 unsigned char ip6_key[sizeof(struct in6_addr)];
3926 long long value;
3927 int data_type;
3928 int cur_arg;
3929 void *ptr;
Willy Tarreaufa1258f2021-04-10 23:00:53 +02003930 struct freq_ctr *frqp;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003931
Willy Tarreau9d008692019-08-09 11:21:01 +02003932 if (!*args[4])
3933 return cli_err(appctx, "Key value expected\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003934
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003935 switch (t->type) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003936 case SMP_T_IPV4:
3937 uint32_key = htonl(inetaddr_host(args[4]));
Christopher Fauletca20d022017-08-29 15:30:31 +02003938 static_table_key.key = &uint32_key;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003939 break;
3940 case SMP_T_IPV6:
3941 inet_pton(AF_INET6, args[4], ip6_key);
Christopher Fauletca20d022017-08-29 15:30:31 +02003942 static_table_key.key = &ip6_key;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003943 break;
3944 case SMP_T_SINT:
3945 {
3946 char *endptr;
3947 unsigned long val;
3948 errno = 0;
3949 val = strtoul(args[4], &endptr, 10);
3950 if ((errno == ERANGE && val == ULONG_MAX) ||
3951 (errno != 0 && val == 0) || endptr == args[4] ||
Willy Tarreau9d008692019-08-09 11:21:01 +02003952 val > 0xffffffff)
3953 return cli_err(appctx, "Invalid key\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003954 uint32_key = (uint32_t) val;
Christopher Fauletca20d022017-08-29 15:30:31 +02003955 static_table_key.key = &uint32_key;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003956 break;
3957 }
3958 break;
3959 case SMP_T_STR:
Christopher Fauletca20d022017-08-29 15:30:31 +02003960 static_table_key.key = args[4];
3961 static_table_key.key_len = strlen(args[4]);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003962 break;
3963 default:
Willy Tarreaua24bc782016-12-14 15:50:35 +01003964 switch (appctx->ctx.table.action) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003965 case STK_CLI_ACT_SHOW:
Willy Tarreau9d008692019-08-09 11:21:01 +02003966 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 +01003967 case STK_CLI_ACT_CLR:
Willy Tarreau9d008692019-08-09 11:21:01 +02003968 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 +01003969 case STK_CLI_ACT_SET:
Willy Tarreau9d008692019-08-09 11:21:01 +02003970 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 +01003971 default:
Willy Tarreau9d008692019-08-09 11:21:01 +02003972 return cli_err(appctx, "Unknown action\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003973 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003974 }
3975
3976 /* check permissions */
3977 if (!cli_has_level(appctx, ACCESS_LVL_OPER))
3978 return 1;
3979
Willy Tarreaua24bc782016-12-14 15:50:35 +01003980 switch (appctx->ctx.table.action) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003981 case STK_CLI_ACT_SHOW:
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003982 ts = stktable_lookup_key(t, &static_table_key);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003983 if (!ts)
3984 return 1;
3985 chunk_reset(&trash);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003986 if (!table_dump_head_to_buffer(&trash, si, t, t)) {
3987 stktable_release(t, ts);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003988 return 0;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003989 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003990 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003991 if (!table_dump_entry_to_buffer(&trash, si, t, ts)) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003992 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003993 stktable_release(t, ts);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003994 return 0;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003995 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003996 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003997 stktable_release(t, ts);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003998 break;
3999
4000 case STK_CLI_ACT_CLR:
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004001 ts = stktable_lookup_key(t, &static_table_key);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004002 if (!ts)
4003 return 1;
Emeric Brun819fc6f2017-06-13 19:37:32 +02004004
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004005 if (!stksess_kill(t, ts, 1)) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004006 /* don't delete an entry which is currently referenced */
Willy Tarreau9d008692019-08-09 11:21:01 +02004007 return cli_err(appctx, "Entry currently in use, cannot remove\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004008 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004009 break;
4010
4011 case STK_CLI_ACT_SET:
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004012 ts = stktable_get_entry(t, &static_table_key);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004013 if (!ts) {
4014 /* don't delete an entry which is currently referenced */
Willy Tarreau9d008692019-08-09 11:21:01 +02004015 return cli_err(appctx, "Unable to allocate a new entry\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004016 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004017 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004018 for (cur_arg = 5; *args[cur_arg]; cur_arg += 2) {
4019 if (strncmp(args[cur_arg], "data.", 5) != 0) {
Willy Tarreau9d008692019-08-09 11:21:01 +02004020 cli_err(appctx, "\"data.<type>\" followed by a value expected\n");
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004021 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004022 stktable_touch_local(t, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004023 return 1;
4024 }
4025
4026 data_type = stktable_get_data_type(args[cur_arg] + 5);
4027 if (data_type < 0) {
Willy Tarreau9d008692019-08-09 11:21:01 +02004028 cli_err(appctx, "Unknown data type\n");
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004029 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004030 stktable_touch_local(t, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004031 return 1;
4032 }
4033
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004034 if (!t->data_ofs[data_type]) {
Willy Tarreau9d008692019-08-09 11:21:01 +02004035 cli_err(appctx, "Data type not stored in this table\n");
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004036 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004037 stktable_touch_local(t, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004038 return 1;
4039 }
4040
4041 if (!*args[cur_arg+1] || strl2llrc(args[cur_arg+1], strlen(args[cur_arg+1]), &value) != 0) {
Willy Tarreau9d008692019-08-09 11:21:01 +02004042 cli_err(appctx, "Require a valid integer value to store\n");
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004043 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004044 stktable_touch_local(t, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004045 return 1;
4046 }
4047
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004048 ptr = stktable_data_ptr(t, ts, data_type);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004049
4050 switch (stktable_data_types[data_type].std_type) {
4051 case STD_T_SINT:
4052 stktable_data_cast(ptr, std_t_sint) = value;
4053 break;
4054 case STD_T_UINT:
4055 stktable_data_cast(ptr, std_t_uint) = value;
4056 break;
4057 case STD_T_ULL:
4058 stktable_data_cast(ptr, std_t_ull) = value;
4059 break;
4060 case STD_T_FRQP:
4061 /* We set both the current and previous values. That way
4062 * the reported frequency is stable during all the period
4063 * then slowly fades out. This allows external tools to
4064 * push measures without having to update them too often.
4065 */
4066 frqp = &stktable_data_cast(ptr, std_t_frqp);
Willy Tarreaufa1258f2021-04-10 23:00:53 +02004067 /* First bit is reserved for the freq_ctr lock
Emeric Brunf2fc1fd2017-11-02 17:32:43 +01004068 Note: here we're still protected by the stksess lock
Willy Tarreaufa1258f2021-04-10 23:00:53 +02004069 so we don't need to update the update the freq_ctr
Emeric Brunf2fc1fd2017-11-02 17:32:43 +01004070 using its internal lock */
4071 frqp->curr_tick = now_ms & ~0x1;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004072 frqp->prev_ctr = 0;
4073 frqp->curr_ctr = value;
4074 break;
4075 }
4076 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004077 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004078 stktable_touch_local(t, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004079 break;
4080
4081 default:
Willy Tarreau9d008692019-08-09 11:21:01 +02004082 return cli_err(appctx, "Unknown action\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004083 }
4084 return 1;
4085}
4086
4087/* Prepares the appctx fields with the data-based filters from the command line.
4088 * Returns 0 if the dump can proceed, 1 if has ended processing.
4089 */
4090static int table_prepare_data_request(struct appctx *appctx, char **args)
4091{
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004092 int i;
Adis Nezirovicd0142e72020-01-22 16:50:27 +01004093 char *err = NULL;
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004094
Willy Tarreau9d008692019-08-09 11:21:01 +02004095 if (appctx->ctx.table.action != STK_CLI_ACT_SHOW && appctx->ctx.table.action != STK_CLI_ACT_CLR)
4096 return cli_err(appctx, "content-based lookup is only supported with the \"show\" and \"clear\" actions\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004097
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004098 for (i = 0; i < STKTABLE_FILTER_LEN; i++) {
4099 if (i > 0 && !*args[3+3*i]) // number of filter entries can be less than STKTABLE_FILTER_LEN
4100 break;
4101 /* condition on stored data value */
4102 appctx->ctx.table.data_type[i] = stktable_get_data_type(args[3+3*i] + 5);
4103 if (appctx->ctx.table.data_type[i] < 0)
Adis Nezirovicd0142e72020-01-22 16:50:27 +01004104 return cli_dynerr(appctx, memprintf(&err, "Filter entry #%i: Unknown data type\n", i + 1));
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004105
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004106 if (!((struct stktable *)appctx->ctx.table.target)->data_ofs[appctx->ctx.table.data_type[i]])
Adis Nezirovicd0142e72020-01-22 16:50:27 +01004107 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 +01004108
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004109 appctx->ctx.table.data_op[i] = get_std_op(args[4+3*i]);
Willy Tarreau2b64a352020-01-22 17:09:47 +01004110 if (appctx->ctx.table.data_op[i] < 0)
Adis Nezirovicd0142e72020-01-22 16:50:27 +01004111 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 +01004112
Adis Nezirovic56dd3542020-01-22 16:16:48 +01004113 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 +01004114 return cli_dynerr(appctx, memprintf(&err, "Filter entry #%i: Require a valid integer value to compare against\n", i + 1));
4115 }
4116
4117 if (*args[3+3*i]) {
4118 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 +01004119 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004120
4121 /* OK we're done, all the fields are set */
4122 return 0;
4123}
4124
4125/* returns 0 if wants to be called, 1 if has ended processing */
Aurélien Nephtaliabbf6072018-04-18 13:26:46 +02004126static int cli_parse_table_req(char **args, char *payload, struct appctx *appctx, void *private)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004127{
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004128 int i;
4129
4130 for (i = 0; i < STKTABLE_FILTER_LEN; i++)
4131 appctx->ctx.table.data_type[i] = -1;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004132 appctx->ctx.table.target = NULL;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004133 appctx->ctx.table.entry = NULL;
Willy Tarreaua24bc782016-12-14 15:50:35 +01004134 appctx->ctx.table.action = (long)private; // keyword argument, one of STK_CLI_ACT_*
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004135
4136 if (*args[2]) {
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004137 appctx->ctx.table.target = stktable_find_by_name(args[2]);
Willy Tarreau9d008692019-08-09 11:21:01 +02004138 if (!appctx->ctx.table.target)
4139 return cli_err(appctx, "No such table\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004140 }
4141 else {
Willy Tarreaua24bc782016-12-14 15:50:35 +01004142 if (appctx->ctx.table.action != STK_CLI_ACT_SHOW)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004143 goto err_args;
4144 return 0;
4145 }
4146
4147 if (strcmp(args[3], "key") == 0)
4148 return table_process_entry_per_key(appctx, args);
4149 else if (strncmp(args[3], "data.", 5) == 0)
4150 return table_prepare_data_request(appctx, args);
4151 else if (*args[3])
4152 goto err_args;
4153
4154 return 0;
4155
4156err_args:
Willy Tarreaua24bc782016-12-14 15:50:35 +01004157 switch (appctx->ctx.table.action) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004158 case STK_CLI_ACT_SHOW:
Willy Tarreau9d008692019-08-09 11:21:01 +02004159 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 +01004160 case STK_CLI_ACT_CLR:
Willy Tarreau9d008692019-08-09 11:21:01 +02004161 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 +01004162 case STK_CLI_ACT_SET:
Willy Tarreau9d008692019-08-09 11:21:01 +02004163 return cli_err(appctx, "Required arguments: <table> key <key> [data.<store_data_type> <value>]*\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004164 default:
Willy Tarreau9d008692019-08-09 11:21:01 +02004165 return cli_err(appctx, "Unknown action\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004166 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004167}
4168
4169/* This function is used to deal with table operations (dump or clear depending
4170 * on the action stored in appctx->private). It returns 0 if the output buffer is
4171 * full and it needs to be called again, otherwise non-zero.
4172 */
4173static int cli_io_handler_table(struct appctx *appctx)
4174{
4175 struct stream_interface *si = appctx->owner;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004176 struct stream *s = si_strm(si);
4177 struct ebmb_node *eb;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004178 int skip_entry;
Willy Tarreaua24bc782016-12-14 15:50:35 +01004179 int show = appctx->ctx.table.action == STK_CLI_ACT_SHOW;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004180
4181 /*
4182 * We have 3 possible states in appctx->st2 :
4183 * - STAT_ST_INIT : the first call
4184 * - STAT_ST_INFO : the proxy pointer points to the next table to
4185 * dump, the entry pointer is NULL ;
4186 * - STAT_ST_LIST : the proxy pointer points to the current table
4187 * and the entry pointer points to the next entry to be dumped,
4188 * and the refcount on the next entry is held ;
4189 * - STAT_ST_END : nothing left to dump, the buffer may contain some
4190 * data though.
4191 */
4192
4193 if (unlikely(si_ic(si)->flags & (CF_WRITE_ERROR|CF_SHUTW))) {
4194 /* in case of abort, remove any refcount we might have set on an entry */
4195 if (appctx->st2 == STAT_ST_LIST) {
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004196 stksess_kill_if_expired(appctx->ctx.table.t, appctx->ctx.table.entry, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004197 }
4198 return 1;
4199 }
4200
4201 chunk_reset(&trash);
4202
4203 while (appctx->st2 != STAT_ST_FIN) {
4204 switch (appctx->st2) {
4205 case STAT_ST_INIT:
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004206 appctx->ctx.table.t = appctx->ctx.table.target;
4207 if (!appctx->ctx.table.t)
4208 appctx->ctx.table.t = stktables_list;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004209
4210 appctx->ctx.table.entry = NULL;
4211 appctx->st2 = STAT_ST_INFO;
4212 break;
4213
4214 case STAT_ST_INFO:
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004215 if (!appctx->ctx.table.t ||
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004216 (appctx->ctx.table.target &&
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004217 appctx->ctx.table.t != appctx->ctx.table.target)) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004218 appctx->st2 = STAT_ST_END;
4219 break;
4220 }
4221
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004222 if (appctx->ctx.table.t->size) {
4223 if (show && !table_dump_head_to_buffer(&trash, si, appctx->ctx.table.t, appctx->ctx.table.target))
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004224 return 0;
4225
4226 if (appctx->ctx.table.target &&
William Lallemand07a62f72017-05-24 00:57:40 +02004227 (strm_li(s)->bind_conf->level & ACCESS_LVL_MASK) >= ACCESS_LVL_OPER) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004228 /* dump entries only if table explicitly requested */
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004229 HA_SPIN_LOCK(STK_TABLE_LOCK, &appctx->ctx.table.t->lock);
4230 eb = ebmb_first(&appctx->ctx.table.t->keys);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004231 if (eb) {
4232 appctx->ctx.table.entry = ebmb_entry(eb, struct stksess, key);
4233 appctx->ctx.table.entry->ref_cnt++;
4234 appctx->st2 = STAT_ST_LIST;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004235 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &appctx->ctx.table.t->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004236 break;
4237 }
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004238 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &appctx->ctx.table.t->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004239 }
4240 }
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004241 appctx->ctx.table.t = appctx->ctx.table.t->next;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004242 break;
4243
4244 case STAT_ST_LIST:
4245 skip_entry = 0;
4246
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004247 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &appctx->ctx.table.entry->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004248
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004249 if (appctx->ctx.table.data_type[0] >= 0) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004250 /* we're filtering on some data contents */
4251 void *ptr;
Willy Tarreau2b64a352020-01-22 17:09:47 +01004252 int dt, i;
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004253 signed char op;
4254 long long data, value;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004255
Emeric Brun819fc6f2017-06-13 19:37:32 +02004256
Willy Tarreau2b64a352020-01-22 17:09:47 +01004257 for (i = 0; i < STKTABLE_FILTER_LEN; i++) {
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004258 if (appctx->ctx.table.data_type[i] == -1)
4259 break;
4260 dt = appctx->ctx.table.data_type[i];
4261 ptr = stktable_data_ptr(appctx->ctx.table.t,
4262 appctx->ctx.table.entry,
4263 dt);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004264
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004265 data = 0;
4266 switch (stktable_data_types[dt].std_type) {
4267 case STD_T_SINT:
4268 data = stktable_data_cast(ptr, std_t_sint);
4269 break;
4270 case STD_T_UINT:
4271 data = stktable_data_cast(ptr, std_t_uint);
4272 break;
4273 case STD_T_ULL:
4274 data = stktable_data_cast(ptr, std_t_ull);
4275 break;
4276 case STD_T_FRQP:
4277 data = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
4278 appctx->ctx.table.t->data_arg[dt].u);
4279 break;
4280 }
4281
4282 op = appctx->ctx.table.data_op[i];
4283 value = appctx->ctx.table.value[i];
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004284
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004285 /* skip the entry if the data does not match the test and the value */
4286 if ((data < value &&
4287 (op == STD_OP_EQ || op == STD_OP_GT || op == STD_OP_GE)) ||
4288 (data == value &&
4289 (op == STD_OP_NE || op == STD_OP_GT || op == STD_OP_LT)) ||
4290 (data > value &&
4291 (op == STD_OP_EQ || op == STD_OP_LT || op == STD_OP_LE))) {
4292 skip_entry = 1;
4293 break;
4294 }
4295 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004296 }
4297
4298 if (show && !skip_entry &&
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004299 !table_dump_entry_to_buffer(&trash, si, appctx->ctx.table.t, appctx->ctx.table.entry)) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004300 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &appctx->ctx.table.entry->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004301 return 0;
4302 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004303
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004304 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &appctx->ctx.table.entry->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004305
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004306 HA_SPIN_LOCK(STK_TABLE_LOCK, &appctx->ctx.table.t->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004307 appctx->ctx.table.entry->ref_cnt--;
4308
4309 eb = ebmb_next(&appctx->ctx.table.entry->key);
4310 if (eb) {
4311 struct stksess *old = appctx->ctx.table.entry;
4312 appctx->ctx.table.entry = ebmb_entry(eb, struct stksess, key);
4313 if (show)
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004314 __stksess_kill_if_expired(appctx->ctx.table.t, old);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004315 else if (!skip_entry && !appctx->ctx.table.entry->ref_cnt)
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004316 __stksess_kill(appctx->ctx.table.t, old);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004317 appctx->ctx.table.entry->ref_cnt++;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004318 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &appctx->ctx.table.t->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004319 break;
4320 }
4321
4322
4323 if (show)
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004324 __stksess_kill_if_expired(appctx->ctx.table.t, appctx->ctx.table.entry);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004325 else if (!skip_entry && !appctx->ctx.table.entry->ref_cnt)
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004326 __stksess_kill(appctx->ctx.table.t, appctx->ctx.table.entry);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004327
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004328 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &appctx->ctx.table.t->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004329
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004330 appctx->ctx.table.t = appctx->ctx.table.t->next;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004331 appctx->st2 = STAT_ST_INFO;
4332 break;
4333
4334 case STAT_ST_END:
4335 appctx->st2 = STAT_ST_FIN;
4336 break;
4337 }
4338 }
4339 return 1;
4340}
4341
4342static void cli_release_show_table(struct appctx *appctx)
4343{
4344 if (appctx->st2 == STAT_ST_LIST) {
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004345 stksess_kill_if_expired(appctx->ctx.table.t, appctx->ctx.table.entry, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004346 }
4347}
4348
Willy Tarreau478331d2020-08-28 11:31:31 +02004349static void stkt_late_init(void)
4350{
4351 struct sample_fetch *f;
4352
4353 f = find_sample_fetch("src", strlen("src"));
4354 if (f)
4355 smp_fetch_src = f->process;
4356}
4357
4358INITCALL0(STG_INIT, stkt_late_init);
4359
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004360/* register cli keywords */
4361static struct cli_kw_list cli_kws = {{ },{
Willy Tarreaub205bfd2021-05-07 11:38:37 +02004362 { { "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 },
4363 { { "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 },
4364 { { "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 +01004365 {{},}
4366}};
4367
Willy Tarreau0108d902018-11-25 19:14:37 +01004368INITCALL1(STG_REGISTER, cli_register_kw, &cli_kws);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004369
Thierry FOURNIER236657b2015-08-19 08:25:14 +02004370static struct action_kw_list tcp_conn_kws = { { }, {
Amaury Denoyellee4a617c2021-05-06 15:33:09 +02004371 { "sc-inc-gpc0", parse_inc_gpc0, KWF_MATCH_PREFIX },
4372 { "sc-inc-gpc1", parse_inc_gpc1, KWF_MATCH_PREFIX },
Emeric Brun877b0b52021-06-30 18:57:49 +02004373 { "sc-set-gpt", parse_set_gpt, KWF_MATCH_PREFIX },
4374 { "sc-set-gpt0", parse_set_gpt, KWF_MATCH_PREFIX },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02004375 { /* END */ }
4376}};
4377
Willy Tarreau0108d902018-11-25 19:14:37 +01004378INITCALL1(STG_REGISTER, tcp_req_conn_keywords_register, &tcp_conn_kws);
4379
Willy Tarreau620408f2016-10-21 16:37:51 +02004380static struct action_kw_list tcp_sess_kws = { { }, {
Amaury Denoyellee4a617c2021-05-06 15:33:09 +02004381 { "sc-inc-gpc0", parse_inc_gpc0, KWF_MATCH_PREFIX },
4382 { "sc-inc-gpc1", parse_inc_gpc1, KWF_MATCH_PREFIX },
Emeric Brun877b0b52021-06-30 18:57:49 +02004383 { "sc-set-gpt", parse_set_gpt, KWF_MATCH_PREFIX },
4384 { "sc-set-gpt0", parse_set_gpt, KWF_MATCH_PREFIX },
Willy Tarreau620408f2016-10-21 16:37:51 +02004385 { /* END */ }
4386}};
4387
Willy Tarreau0108d902018-11-25 19:14:37 +01004388INITCALL1(STG_REGISTER, tcp_req_sess_keywords_register, &tcp_sess_kws);
4389
Thierry FOURNIER236657b2015-08-19 08:25:14 +02004390static struct action_kw_list tcp_req_kws = { { }, {
Amaury Denoyellee4a617c2021-05-06 15:33:09 +02004391 { "sc-inc-gpc0", parse_inc_gpc0, KWF_MATCH_PREFIX },
4392 { "sc-inc-gpc1", parse_inc_gpc1, KWF_MATCH_PREFIX },
Emeric Brun877b0b52021-06-30 18:57:49 +02004393 { "sc-set-gpt", parse_set_gpt, KWF_MATCH_PREFIX },
4394 { "sc-set-gpt0", parse_set_gpt, KWF_MATCH_PREFIX },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02004395 { /* END */ }
4396}};
4397
Willy Tarreau0108d902018-11-25 19:14:37 +01004398INITCALL1(STG_REGISTER, tcp_req_cont_keywords_register, &tcp_req_kws);
4399
Thierry FOURNIER236657b2015-08-19 08:25:14 +02004400static struct action_kw_list tcp_res_kws = { { }, {
Amaury Denoyellee4a617c2021-05-06 15:33:09 +02004401 { "sc-inc-gpc0", parse_inc_gpc0, KWF_MATCH_PREFIX },
4402 { "sc-inc-gpc1", parse_inc_gpc1, KWF_MATCH_PREFIX },
Emeric Brun877b0b52021-06-30 18:57:49 +02004403 { "sc-set-gpt", parse_set_gpt, KWF_MATCH_PREFIX },
4404 { "sc-set-gpt0", parse_set_gpt, KWF_MATCH_PREFIX },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02004405 { /* END */ }
4406}};
4407
Willy Tarreau0108d902018-11-25 19:14:37 +01004408INITCALL1(STG_REGISTER, tcp_res_cont_keywords_register, &tcp_res_kws);
4409
Thierry FOURNIER236657b2015-08-19 08:25:14 +02004410static struct action_kw_list http_req_kws = { { }, {
Amaury Denoyellee4a617c2021-05-06 15:33:09 +02004411 { "sc-inc-gpc0", parse_inc_gpc0, KWF_MATCH_PREFIX },
4412 { "sc-inc-gpc1", parse_inc_gpc1, KWF_MATCH_PREFIX },
Emeric Brun877b0b52021-06-30 18:57:49 +02004413 { "sc-set-gpt", parse_set_gpt, KWF_MATCH_PREFIX },
4414 { "sc-set-gpt0", parse_set_gpt, KWF_MATCH_PREFIX },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02004415 { /* END */ }
4416}};
4417
Willy Tarreau0108d902018-11-25 19:14:37 +01004418INITCALL1(STG_REGISTER, http_req_keywords_register, &http_req_kws);
4419
Thierry FOURNIER236657b2015-08-19 08:25:14 +02004420static struct action_kw_list http_res_kws = { { }, {
Amaury Denoyellee4a617c2021-05-06 15:33:09 +02004421 { "sc-inc-gpc0", parse_inc_gpc0, KWF_MATCH_PREFIX },
4422 { "sc-inc-gpc1", parse_inc_gpc1, KWF_MATCH_PREFIX },
Emeric Brun877b0b52021-06-30 18:57:49 +02004423 { "sc-set-gpt", parse_set_gpt, KWF_MATCH_PREFIX },
4424 { "sc-set-gpt0", parse_set_gpt, KWF_MATCH_PREFIX },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02004425 { /* END */ }
4426}};
4427
Willy Tarreau0108d902018-11-25 19:14:37 +01004428INITCALL1(STG_REGISTER, http_res_keywords_register, &http_res_kws);
4429
Willy Tarreau7d562212016-11-25 16:10:05 +01004430/* Note: must not be declared <const> as its list will be overwritten.
4431 * Please take care of keeping this list alphabetically sorted.
4432 */
4433static struct sample_fetch_kw_list smp_fetch_keywords = {ILH, {
4434 { "sc_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4435 { "sc_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4436 { "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 +01004437 { "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 +01004438 { "sc_conn_cnt", smp_fetch_sc_conn_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4439 { "sc_conn_cur", smp_fetch_sc_conn_cur, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4440 { "sc_conn_rate", smp_fetch_sc_conn_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
Emeric Brun877b0b52021-06-30 18:57:49 +02004441 { "sc_get_gpt", smp_fetch_sc_get_gpt, ARG3(2,SINT,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
Thierry FOURNIER401c64b2017-01-05 11:44:09 +01004442 { "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 +01004443 { "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 +01004444 { "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 +01004445 { "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 +01004446 { "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 +01004447 { "sc_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4448 { "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 +01004449 { "sc_http_fail_cnt", smp_fetch_sc_http_fail_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4450 { "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 +01004451 { "sc_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4452 { "sc_http_req_rate", smp_fetch_sc_http_req_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4453 { "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 +01004454 { "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 +01004455 { "sc_kbytes_in", smp_fetch_sc_kbytes_in, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4456 { "sc_kbytes_out", smp_fetch_sc_kbytes_out, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4457 { "sc_sess_cnt", smp_fetch_sc_sess_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4458 { "sc_sess_rate", smp_fetch_sc_sess_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4459 { "sc_tracked", smp_fetch_sc_tracked, ARG2(1,SINT,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
4460 { "sc_trackers", smp_fetch_sc_trackers, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4461 { "sc0_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4462 { "sc0_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4463 { "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 +01004464 { "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 +01004465 { "sc0_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4466 { "sc0_conn_cur", smp_fetch_sc_conn_cur, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4467 { "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 +01004468 { "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 +01004469 { "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 +01004470 { "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 +01004471 { "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 +01004472 { "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 +01004473 { "sc0_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4474 { "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 +01004475 { "sc0_http_fail_cnt", smp_fetch_sc_http_fail_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4476 { "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 +01004477 { "sc0_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4478 { "sc0_http_req_rate", smp_fetch_sc_http_req_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4479 { "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 +01004480 { "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 +01004481 { "sc0_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4482 { "sc0_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4483 { "sc0_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4484 { "sc0_sess_rate", smp_fetch_sc_sess_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4485 { "sc0_tracked", smp_fetch_sc_tracked, ARG1(0,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
4486 { "sc0_trackers", smp_fetch_sc_trackers, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4487 { "sc1_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4488 { "sc1_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4489 { "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 +01004490 { "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 +01004491 { "sc1_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4492 { "sc1_conn_cur", smp_fetch_sc_conn_cur, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4493 { "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 +01004494 { "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 +01004495 { "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 +01004496 { "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 +01004497 { "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 +01004498 { "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 +01004499 { "sc1_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4500 { "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 +01004501 { "sc1_http_fail_cnt", smp_fetch_sc_http_fail_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4502 { "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 +01004503 { "sc1_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4504 { "sc1_http_req_rate", smp_fetch_sc_http_req_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4505 { "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 +01004506 { "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 +01004507 { "sc1_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4508 { "sc1_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4509 { "sc1_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4510 { "sc1_sess_rate", smp_fetch_sc_sess_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4511 { "sc1_tracked", smp_fetch_sc_tracked, ARG1(0,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
4512 { "sc1_trackers", smp_fetch_sc_trackers, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4513 { "sc2_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4514 { "sc2_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4515 { "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 +01004516 { "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 +01004517 { "sc2_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4518 { "sc2_conn_cur", smp_fetch_sc_conn_cur, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4519 { "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 +01004520 { "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 +01004521 { "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 +01004522 { "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 +01004523 { "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 +01004524 { "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 +01004525 { "sc2_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4526 { "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 +01004527 { "sc2_http_fail_cnt", smp_fetch_sc_http_fail_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4528 { "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 +01004529 { "sc2_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4530 { "sc2_http_req_rate", smp_fetch_sc_http_req_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4531 { "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 +01004532 { "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 +01004533 { "sc2_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4534 { "sc2_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4535 { "sc2_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4536 { "sc2_sess_rate", smp_fetch_sc_sess_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4537 { "sc2_tracked", smp_fetch_sc_tracked, ARG1(0,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
4538 { "sc2_trackers", smp_fetch_sc_trackers, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4539 { "src_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4540 { "src_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4541 { "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 +01004542 { "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 +01004543 { "src_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4544 { "src_conn_cur", smp_fetch_sc_conn_cur, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4545 { "src_conn_rate", smp_fetch_sc_conn_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
Emeric Brun877b0b52021-06-30 18:57:49 +02004546 { "src_get_gpt" , smp_fetch_sc_get_gpt, ARG2(2,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
Thierry FOURNIER401c64b2017-01-05 11:44:09 +01004547 { "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 +01004548 { "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 +01004549 { "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 +01004550 { "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 +01004551 { "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 +01004552 { "src_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4553 { "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 +01004554 { "src_http_fail_cnt", smp_fetch_sc_http_fail_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4555 { "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 +01004556 { "src_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4557 { "src_http_req_rate", smp_fetch_sc_http_req_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4558 { "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 +01004559 { "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 +01004560 { "src_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4561 { "src_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4562 { "src_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4563 { "src_sess_rate", smp_fetch_sc_sess_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4564 { "src_updt_conn_cnt", smp_fetch_src_updt_conn_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4565 { "table_avl", smp_fetch_table_avl, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4566 { "table_cnt", smp_fetch_table_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4567 { /* END */ },
4568}};
4569
Willy Tarreau0108d902018-11-25 19:14:37 +01004570INITCALL1(STG_REGISTER, sample_register_fetches, &smp_fetch_keywords);
Willy Tarreau7d562212016-11-25 16:10:05 +01004571
Willy Tarreaud9f316a2014-07-10 14:03:38 +02004572/* Note: must not be declared <const> as its list will be overwritten */
4573static struct sample_conv_kw_list sample_conv_kws = {ILH, {
Willy Tarreau2d17db52016-05-25 17:16:38 +02004574 { "in_table", sample_conv_in_table, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_BOOL },
4575 { "table_bytes_in_rate", sample_conv_table_bytes_in_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4576 { "table_bytes_out_rate", sample_conv_table_bytes_out_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4577 { "table_conn_cnt", sample_conv_table_conn_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4578 { "table_conn_cur", sample_conv_table_conn_cur, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4579 { "table_conn_rate", sample_conv_table_conn_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
Emeric Brun877b0b52021-06-30 18:57:49 +02004580 { "table_gpt", sample_conv_table_gpt, ARG2(2,SINT,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
Willy Tarreau2d17db52016-05-25 17:16:38 +02004581 { "table_gpt0", sample_conv_table_gpt0, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4582 { "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 +01004583 { "table_gpc1", sample_conv_table_gpc1, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
Willy Tarreau2d17db52016-05-25 17:16:38 +02004584 { "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 +01004585 { "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 +02004586 { "table_http_err_cnt", sample_conv_table_http_err_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4587 { "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 +01004588 { "table_http_fail_cnt", sample_conv_table_http_fail_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4589 { "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 +02004590 { "table_http_req_cnt", sample_conv_table_http_req_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4591 { "table_http_req_rate", sample_conv_table_http_req_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4592 { "table_kbytes_in", sample_conv_table_kbytes_in, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4593 { "table_kbytes_out", sample_conv_table_kbytes_out, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4594 { "table_server_id", sample_conv_table_server_id, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4595 { "table_sess_cnt", sample_conv_table_sess_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4596 { "table_sess_rate", sample_conv_table_sess_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4597 { "table_trackers", sample_conv_table_trackers, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
Willy Tarreaud9f316a2014-07-10 14:03:38 +02004598 { /* END */ },
4599}};
4600
Willy Tarreau0108d902018-11-25 19:14:37 +01004601INITCALL1(STG_REGISTER, sample_register_convs, &sample_conv_kws);