blob: becca299aef448c432ade7d183602bfc387178e1 [file] [log] [blame]
Emeric Brun3bd697e2010-01-04 15:23:48 +01001/*
2 * Stick tables management functions.
3 *
4 * Copyright 2009-2010 EXCELIANCE, Emeric Brun <ebrun@exceliance.fr>
Willy Tarreau08d5f982010-06-06 13:34:54 +02005 * Copyright (C) 2010 Willy Tarreau <w@1wt.eu>
Emeric Brun3bd697e2010-01-04 15:23:48 +01006 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version
10 * 2 of the License, or (at your option) any later version.
11 *
12 */
13
14#include <string.h>
Willy Tarreauf13ebdf2016-11-22 18:00:53 +010015#include <errno.h>
Emeric Brun3bd697e2010-01-04 15:23:48 +010016
Willy Tarreaub2551052020-06-09 09:07:15 +020017#include <import/ebmbtree.h>
18#include <import/ebsttree.h>
19#include <import/ebistree.h>
20
Willy Tarreau4c7e4b72020-05-27 12:58:42 +020021#include <haproxy/api.h>
Willy Tarreaub2551052020-06-09 09:07:15 +020022#include <haproxy/arg.h>
Willy Tarreau6be78492020-06-05 00:00:29 +020023#include <haproxy/cfgparse.h>
Willy Tarreau83487a82020-06-04 20:19:54 +020024#include <haproxy/cli.h>
Thayne McCombs92149f92020-11-20 01:28:26 -070025#include <haproxy/dict.h>
Willy Tarreau36979d92020-06-05 17:27:29 +020026#include <haproxy/errors.h>
Willy Tarreauf268ee82020-06-04 17:05:57 +020027#include <haproxy/global.h>
Willy Tarreauc761f842020-06-04 11:40:28 +020028#include <haproxy/http_rules.h>
Willy Tarreau853b2972020-05-27 18:01:47 +020029#include <haproxy/list.h>
Willy Tarreauaeed4a82020-06-04 22:01:04 +020030#include <haproxy/log.h>
Willy Tarreau6131d6a2020-06-02 16:48:09 +020031#include <haproxy/net_helper.h>
Willy Tarreau3c2a7c22020-06-04 18:38:21 +020032#include <haproxy/peers.h>
Willy Tarreaub2551052020-06-09 09:07:15 +020033#include <haproxy/pool.h>
34#include <haproxy/proto_tcp.h>
Willy Tarreaua264d962020-06-04 22:29:18 +020035#include <haproxy/proxy.h>
Willy Tarreaub2551052020-06-09 09:07:15 +020036#include <haproxy/sample.h>
Willy Tarreau2eec9b52020-06-04 19:58:55 +020037#include <haproxy/stats-t.h>
Willy Tarreaub2551052020-06-09 09:07:15 +020038#include <haproxy/stick_table.h>
Willy Tarreaudfd3de82020-06-04 23:46:14 +020039#include <haproxy/stream.h>
Willy Tarreau5e539c92020-06-04 20:45:39 +020040#include <haproxy/stream_interface.h>
Willy Tarreaucea0e1b2020-06-04 17:25:40 +020041#include <haproxy/task.h>
Willy Tarreau8b550af2020-06-04 17:42:48 +020042#include <haproxy/tcp_rules.h>
Willy Tarreau92b4f132020-06-01 11:05:15 +020043#include <haproxy/time.h>
Willy Tarreaub2551052020-06-09 09:07:15 +020044#include <haproxy/tools.h>
Emeric Brun3bd697e2010-01-04 15:23:48 +010045
Emeric Brun3bd697e2010-01-04 15:23:48 +010046
Willy Tarreau12785782012-04-27 21:37:17 +020047/* structure used to return a table key built from a sample */
Emeric Brun819fc6f2017-06-13 19:37:32 +020048static THREAD_LOCAL struct stktable_key static_table_key;
Willy Tarreau478331d2020-08-28 11:31:31 +020049static int (*smp_fetch_src)(const struct arg *, struct sample *, const char *, void *);
Willy Tarreauf0b38bf2010-06-06 13:22:23 +020050
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +010051struct stktable *stktables_list;
52struct eb_root stktable_by_name = EB_ROOT;
53
Olivier Houchard52dabbc2018-11-14 17:54:36 +010054#define round_ptr_size(i) (((i) + (sizeof(void *) - 1)) &~ (sizeof(void *) - 1))
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +010055
56/* This function inserts stktable <t> into the tree of known stick-table.
57 * The stick-table ID is used as the storing key so it must already have
58 * been initialized.
59 */
60void stktable_store_name(struct stktable *t)
61{
62 t->name.key = t->id;
63 ebis_insert(&stktable_by_name, &t->name);
64}
65
66struct stktable *stktable_find_by_name(const char *name)
67{
68 struct ebpt_node *node;
69 struct stktable *t;
70
71 node = ebis_lookup(&stktable_by_name, name);
72 if (node) {
73 t = container_of(node, struct stktable, name);
Tim Duesterhuse5ff1412021-01-02 22:31:53 +010074 if (strcmp(t->id, name) == 0)
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +010075 return t;
76 }
77
78 return NULL;
79}
80
Emeric Brun3bd697e2010-01-04 15:23:48 +010081/*
Willy Tarreauaea940e2010-06-06 11:56:36 +020082 * Free an allocated sticky session <ts>, and decrease sticky sessions counter
83 * in table <t>.
Emeric Brun3bd697e2010-01-04 15:23:48 +010084 */
Emeric Brun819fc6f2017-06-13 19:37:32 +020085void __stksess_free(struct stktable *t, struct stksess *ts)
Emeric Brun3bd697e2010-01-04 15:23:48 +010086{
87 t->current--;
Olivier Houchard52dabbc2018-11-14 17:54:36 +010088 pool_free(t->pool, (void *)ts - round_ptr_size(t->data_size));
Emeric Brun3bd697e2010-01-04 15:23:48 +010089}
90
91/*
Emeric Brun819fc6f2017-06-13 19:37:32 +020092 * Free an allocated sticky session <ts>, and decrease sticky sessions counter
93 * in table <t>.
94 * This function locks the table
95 */
96void stksess_free(struct stktable *t, struct stksess *ts)
97{
Thayne McCombs92149f92020-11-20 01:28:26 -070098 void *data;
99 data = stktable_data_ptr(t, ts, STKTABLE_DT_SERVER_KEY);
100 if (data) {
101 dict_entry_unref(&server_key_dict, stktable_data_cast(data, server_key));
102 stktable_data_cast(data, server_key) = NULL;
103 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100104 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200105 __stksess_free(t, ts);
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100106 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200107}
108
109/*
Willy Tarreauf6efda12010-08-03 20:34:06 +0200110 * Kill an stksess (only if its ref_cnt is zero).
111 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200112int __stksess_kill(struct stktable *t, struct stksess *ts)
Willy Tarreauf6efda12010-08-03 20:34:06 +0200113{
114 if (ts->ref_cnt)
Emeric Brun819fc6f2017-06-13 19:37:32 +0200115 return 0;
Willy Tarreauf6efda12010-08-03 20:34:06 +0200116
117 eb32_delete(&ts->exp);
Emeric Brun85e77c72010-09-23 18:16:52 +0200118 eb32_delete(&ts->upd);
Willy Tarreauf6efda12010-08-03 20:34:06 +0200119 ebmb_delete(&ts->key);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200120 __stksess_free(t, ts);
121 return 1;
Willy Tarreauf6efda12010-08-03 20:34:06 +0200122}
123
124/*
Emeric Brun819fc6f2017-06-13 19:37:32 +0200125 * Decrease the refcount if decrefcnt is not 0.
126 * and try to kill the stksess
127 * This function locks the table
128 */
129int stksess_kill(struct stktable *t, struct stksess *ts, int decrefcnt)
130{
131 int ret;
132
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100133 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200134 if (decrefcnt)
135 ts->ref_cnt--;
136 ret = __stksess_kill(t, ts);
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100137 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200138
139 return ret;
140}
141
142/*
Willy Tarreauaea940e2010-06-06 11:56:36 +0200143 * Initialize or update the key in the sticky session <ts> present in table <t>
144 * from the value present in <key>.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100145 */
Willy Tarreau393379c2010-06-06 12:11:37 +0200146void stksess_setkey(struct stktable *t, struct stksess *ts, struct stktable_key *key)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100147{
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200148 if (t->type != SMP_T_STR)
Willy Tarreau86257dc2010-06-06 12:57:10 +0200149 memcpy(ts->key.key, key->key, t->key_size);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100150 else {
Willy Tarreau86257dc2010-06-06 12:57:10 +0200151 memcpy(ts->key.key, key->key, MIN(t->key_size - 1, key->key_len));
152 ts->key.key[MIN(t->key_size - 1, key->key_len)] = 0;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100153 }
154}
155
156
157/*
Willy Tarreau393379c2010-06-06 12:11:37 +0200158 * Init sticky session <ts> of table <t>. The data parts are cleared and <ts>
159 * is returned.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100160 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200161static struct stksess *__stksess_init(struct stktable *t, struct stksess * ts)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100162{
Willy Tarreau393379c2010-06-06 12:11:37 +0200163 memset((void *)ts - t->data_size, 0, t->data_size);
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200164 ts->ref_cnt = 0;
Willy Tarreau86257dc2010-06-06 12:57:10 +0200165 ts->key.node.leaf_p = NULL;
166 ts->exp.node.leaf_p = NULL;
Emeric Brun85e77c72010-09-23 18:16:52 +0200167 ts->upd.node.leaf_p = NULL;
Emeric Brun819fc6f2017-06-13 19:37:32 +0200168 ts->expire = tick_add(now_ms, MS_TO_TICKS(t->expire));
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100169 HA_RWLOCK_INIT(&ts->lock);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100170 return ts;
171}
172
173/*
Willy Tarreauaea940e2010-06-06 11:56:36 +0200174 * Trash oldest <to_batch> sticky sessions from table <t>
Willy Tarreaudfe79252020-11-03 17:47:41 +0100175 * Returns number of trashed sticky sessions. It may actually trash less
176 * than expected if finding these requires too long a search time (e.g.
177 * most of them have ts->ref_cnt>0).
Emeric Brun3bd697e2010-01-04 15:23:48 +0100178 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200179int __stktable_trash_oldest(struct stktable *t, int to_batch)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100180{
181 struct stksess *ts;
182 struct eb32_node *eb;
Willy Tarreaudfe79252020-11-03 17:47:41 +0100183 int max_search = to_batch * 2; // no more than 50% misses
Emeric Brun3bd697e2010-01-04 15:23:48 +0100184 int batched = 0;
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200185 int looped = 0;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100186
187 eb = eb32_lookup_ge(&t->exps, now_ms - TIMER_LOOK_BACK);
188
189 while (batched < to_batch) {
190
191 if (unlikely(!eb)) {
192 /* we might have reached the end of the tree, typically because
193 * <now_ms> is in the first half and we're first scanning the last
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200194 * half. Let's loop back to the beginning of the tree now if we
195 * have not yet visited it.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100196 */
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200197 if (looped)
198 break;
199 looped = 1;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100200 eb = eb32_first(&t->exps);
201 if (likely(!eb))
202 break;
203 }
204
Willy Tarreaudfe79252020-11-03 17:47:41 +0100205 if (--max_search < 0)
206 break;
207
Emeric Brun3bd697e2010-01-04 15:23:48 +0100208 /* timer looks expired, detach it from the queue */
Willy Tarreau86257dc2010-06-06 12:57:10 +0200209 ts = eb32_entry(eb, struct stksess, exp);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100210 eb = eb32_next(eb);
211
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200212 /* don't delete an entry which is currently referenced */
213 if (ts->ref_cnt)
214 continue;
215
Willy Tarreau86257dc2010-06-06 12:57:10 +0200216 eb32_delete(&ts->exp);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100217
Willy Tarreau86257dc2010-06-06 12:57:10 +0200218 if (ts->expire != ts->exp.key) {
Emeric Brun3bd697e2010-01-04 15:23:48 +0100219 if (!tick_isset(ts->expire))
220 continue;
221
Willy Tarreau86257dc2010-06-06 12:57:10 +0200222 ts->exp.key = ts->expire;
223 eb32_insert(&t->exps, &ts->exp);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100224
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 Tarreaud2636522022-11-14 18:02:44 +0100557 * Task processing function to trash expired sticky sessions. A pointer to the
558 * task itself is returned since it never dies.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100559 */
Willy Tarreaud2636522022-11-14 18:02:44 +0100560struct task *process_table_expire(struct task *task, void *context, unsigned int state)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100561{
Willy Tarreaud2636522022-11-14 18:02:44 +0100562 struct stktable *t = context;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100563 struct stksess *ts;
564 struct eb32_node *eb;
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200565 int looped = 0;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100566
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100567 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100568 eb = eb32_lookup_ge(&t->exps, now_ms - TIMER_LOOK_BACK);
569
570 while (1) {
571 if (unlikely(!eb)) {
572 /* we might have reached the end of the tree, typically because
573 * <now_ms> is in the first half and we're first scanning the last
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200574 * half. Let's loop back to the beginning of the tree now if we
575 * have not yet visited it.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100576 */
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200577 if (looped)
578 break;
579 looped = 1;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100580 eb = eb32_first(&t->exps);
581 if (likely(!eb))
582 break;
583 }
584
585 if (likely(tick_is_lt(now_ms, eb->key))) {
586 /* timer not expired yet, revisit it later */
587 t->exp_next = eb->key;
Willy Tarreau4d5f13c2017-11-05 11:04:47 +0100588 goto out_unlock;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100589 }
590
591 /* timer looks expired, detach it from the queue */
Willy Tarreau86257dc2010-06-06 12:57:10 +0200592 ts = eb32_entry(eb, struct stksess, exp);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100593 eb = eb32_next(eb);
594
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200595 /* don't delete an entry which is currently referenced */
596 if (ts->ref_cnt)
597 continue;
598
Willy Tarreau86257dc2010-06-06 12:57:10 +0200599 eb32_delete(&ts->exp);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100600
601 if (!tick_is_expired(ts->expire, now_ms)) {
602 if (!tick_isset(ts->expire))
603 continue;
604
Willy Tarreau86257dc2010-06-06 12:57:10 +0200605 ts->exp.key = ts->expire;
606 eb32_insert(&t->exps, &ts->exp);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100607
Willy Tarreau86257dc2010-06-06 12:57:10 +0200608 if (!eb || eb->key > ts->exp.key)
609 eb = &ts->exp;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100610 continue;
611 }
612
613 /* session expired, trash it */
Willy Tarreau86257dc2010-06-06 12:57:10 +0200614 ebmb_delete(&ts->key);
Emeric Brun85e77c72010-09-23 18:16:52 +0200615 eb32_delete(&ts->upd);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200616 __stksess_free(t, ts);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100617 }
618
619 /* We have found no task to expire in any tree */
620 t->exp_next = TICK_ETERNITY;
Willy Tarreau4d5f13c2017-11-05 11:04:47 +0100621out_unlock:
Willy Tarreaud2636522022-11-14 18:02:44 +0100622 task->expire = t->exp_next;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100623 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100624 return task;
625}
626
Willy Tarreauaea940e2010-06-06 11:56:36 +0200627/* Perform minimal stick table intializations, report 0 in case of error, 1 if OK. */
Emeric Brun3bd697e2010-01-04 15:23:48 +0100628int stktable_init(struct stktable *t)
629{
Remi Tricot-Le Bretonbe5b1bb2021-05-12 17:39:04 +0200630 int peers_retval = 0;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100631 if (t->size) {
Emeric Brun819fc6f2017-06-13 19:37:32 +0200632 t->keys = EB_ROOT_UNIQUE;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100633 memset(&t->exps, 0, sizeof(t->exps));
Emeric Brun1c6235d2015-12-16 15:28:12 +0100634 t->updates = EB_ROOT_UNIQUE;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100635 HA_SPIN_INIT(&t->lock);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100636
Olivier Houchard52dabbc2018-11-14 17:54:36 +0100637 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 +0100638
639 t->exp_next = TICK_ETERNITY;
640 if ( t->expire ) {
Emeric Brunc60def82017-09-27 14:59:38 +0200641 t->exp_task = task_new(MAX_THREADS_MASK);
Willy Tarreau848522f2018-10-15 11:12:15 +0200642 if (!t->exp_task)
643 return 0;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100644 t->exp_task->process = process_table_expire;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100645 t->exp_task->context = (void *)t;
646 }
Willy Tarreauc3914d42020-09-24 08:39:22 +0200647 if (t->peers.p && t->peers.p->peers_fe && !t->peers.p->peers_fe->disabled) {
Remi Tricot-Le Bretonbe5b1bb2021-05-12 17:39:04 +0200648 peers_retval = peers_register_table(t->peers.p, t);
Emeric Brun32da3c42010-09-23 18:39:19 +0200649 }
650
Remi Tricot-Le Bretonbe5b1bb2021-05-12 17:39:04 +0200651 return (t->pool != NULL) && !peers_retval;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100652 }
653 return 1;
654}
655
656/*
657 * Configuration keywords of known table types
658 */
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200659struct stktable_type stktable_types[SMP_TYPES] = {
660 [SMP_T_SINT] = { "integer", 0, 4 },
661 [SMP_T_IPV4] = { "ip", 0, 4 },
662 [SMP_T_IPV6] = { "ipv6", 0, 16 },
663 [SMP_T_STR] = { "string", STK_F_CUSTOM_KEYSIZE, 32 },
664 [SMP_T_BIN] = { "binary", STK_F_CUSTOM_KEYSIZE, 32 }
665};
Emeric Brun3bd697e2010-01-04 15:23:48 +0100666
667/*
668 * Parse table type configuration.
669 * Returns 0 on successful parsing, else 1.
670 * <myidx> is set at next configuration <args> index.
671 */
672int stktable_parse_type(char **args, int *myidx, unsigned long *type, size_t *key_size)
673{
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200674 for (*type = 0; *type < SMP_TYPES; (*type)++) {
675 if (!stktable_types[*type].kw)
676 continue;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100677 if (strcmp(args[*myidx], stktable_types[*type].kw) != 0)
678 continue;
679
680 *key_size = stktable_types[*type].default_size;
681 (*myidx)++;
682
Willy Tarreauaea940e2010-06-06 11:56:36 +0200683 if (stktable_types[*type].flags & STK_F_CUSTOM_KEYSIZE) {
Emeric Brun3bd697e2010-01-04 15:23:48 +0100684 if (strcmp("len", args[*myidx]) == 0) {
685 (*myidx)++;
686 *key_size = atol(args[*myidx]);
Emeric Brun485479d2010-09-23 18:02:19 +0200687 if (!*key_size)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100688 break;
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200689 if (*type == SMP_T_STR) {
Emeric Brun485479d2010-09-23 18:02:19 +0200690 /* null terminated string needs +1 for '\0'. */
691 (*key_size)++;
692 }
Emeric Brun3bd697e2010-01-04 15:23:48 +0100693 (*myidx)++;
694 }
695 }
696 return 0;
697 }
698 return 1;
699}
700
Willy Tarreau3b63ca22021-05-08 14:10:42 +0200701/* reserve some space for data type <type>, and associate argument at <sa> if
702 * not NULL. Returns PE_NONE (0) if OK or an error code among :
703 * - PE_ENUM_OOR if <type> does not exist
704 * - PE_EXIST if <type> is already registered
705 * - PE_ARG_NOT_USE if <sa> was provided but not expected
706 * - PE_ARG_MISSING if <sa> was expected but not provided
707 */
708int stktable_alloc_data_type(struct stktable *t, int type, const char *sa)
709{
710 if (type >= STKTABLE_DATA_TYPES)
711 return PE_ENUM_OOR;
712
713 if (t->data_ofs[type])
714 /* already allocated */
715 return PE_EXIST;
716
717 switch (stktable_data_types[type].arg_type) {
718 case ARG_T_NONE:
719 if (sa)
720 return PE_ARG_NOT_USED;
721 break;
722 case ARG_T_INT:
723 if (!sa)
724 return PE_ARG_MISSING;
725 t->data_arg[type].i = atoi(sa);
726 break;
727 case ARG_T_DELAY:
728 if (!sa)
729 return PE_ARG_MISSING;
730 sa = parse_time_err(sa, &t->data_arg[type].u, TIME_UNIT_MS);
731 if (sa)
732 return PE_ARG_INVC; /* invalid char */
733 break;
734 }
735
736 t->data_size += stktable_type_size(stktable_data_types[type].std_type);
737 t->data_ofs[type] = -t->data_size;
738 return PE_NONE;
739}
740
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100741/*
Frédéric Lécaillec02766a2019-03-20 15:06:55 +0100742 * Parse a line with <linenum> as number in <file> configuration file to configure
743 * the stick-table with <t> as address and <id> as ID.
744 * <peers> provides the "peers" section pointer only if this function is called
745 * from a "peers" section.
746 * <nid> is the stick-table name which is sent over the network. It must be equal
747 * to <id> if this stick-table is parsed from a proxy section, and prefixed by <peers>
748 * "peers" section name followed by a '/' character if parsed from a "peers" section.
Ilya Shipitsind4259502020-04-08 01:07:56 +0500749 * This is the responsibility of the caller to check this.
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100750 * Return an error status with ERR_* flags set if required, 0 if no error was encountered.
751 */
752int parse_stick_table(const char *file, int linenum, char **args,
Frédéric Lécaillec02766a2019-03-20 15:06:55 +0100753 struct stktable *t, char *id, char *nid, struct peers *peers)
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100754{
755 int err_code = 0;
756 int idx = 1;
757 unsigned int val;
758
759 if (!id || !*id) {
760 ha_alert("parsing [%s:%d] : %s: ID not provided.\n", file, linenum, args[0]);
761 err_code |= ERR_ALERT | ERR_ABORT;
762 goto out;
763 }
764
765 /* Store the "peers" section if this function is called from a "peers" section. */
766 if (peers) {
767 t->peers.p = peers;
768 idx++;
769 }
770
771 t->id = id;
Frédéric Lécaillec02766a2019-03-20 15:06:55 +0100772 t->nid = nid;
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100773 t->type = (unsigned int)-1;
774 t->conf.file = file;
775 t->conf.line = linenum;
776
777 while (*args[idx]) {
778 const char *err;
779
780 if (strcmp(args[idx], "size") == 0) {
781 idx++;
782 if (!*(args[idx])) {
783 ha_alert("parsing [%s:%d] : %s: missing argument after '%s'.\n",
784 file, linenum, args[0], args[idx-1]);
785 err_code |= ERR_ALERT | ERR_FATAL;
786 goto out;
787 }
788 if ((err = parse_size_err(args[idx], &t->size))) {
789 ha_alert("parsing [%s:%d] : %s: unexpected character '%c' in argument of '%s'.\n",
790 file, linenum, args[0], *err, args[idx-1]);
791 err_code |= ERR_ALERT | ERR_FATAL;
792 goto out;
793 }
794 idx++;
795 }
796 /* This argument does not exit in "peers" section. */
797 else if (!peers && strcmp(args[idx], "peers") == 0) {
798 idx++;
799 if (!*(args[idx])) {
800 ha_alert("parsing [%s:%d] : %s: missing argument after '%s'.\n",
801 file, linenum, args[0], args[idx-1]);
802 err_code |= ERR_ALERT | ERR_FATAL;
803 goto out;
804 }
805 t->peers.name = strdup(args[idx++]);
806 }
807 else if (strcmp(args[idx], "expire") == 0) {
808 idx++;
809 if (!*(args[idx])) {
810 ha_alert("parsing [%s:%d] : %s: missing argument after '%s'.\n",
811 file, linenum, args[0], args[idx-1]);
812 err_code |= ERR_ALERT | ERR_FATAL;
813 goto out;
814 }
815 err = parse_time_err(args[idx], &val, TIME_UNIT_MS);
Willy Tarreau9faebe32019-06-07 19:00:37 +0200816 if (err == PARSE_TIME_OVER) {
817 ha_alert("parsing [%s:%d]: %s: timer overflow in argument <%s> to <%s>, maximum value is 2147483647 ms (~24.8 days).\n",
818 file, linenum, args[0], args[idx], args[idx-1]);
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100819 err_code |= ERR_ALERT | ERR_FATAL;
820 goto out;
821 }
Willy Tarreau9faebe32019-06-07 19:00:37 +0200822 else if (err == PARSE_TIME_UNDER) {
823 ha_alert("parsing [%s:%d]: %s: timer underflow in argument <%s> to <%s>, minimum non-null value is 1 ms.\n",
824 file, linenum, args[0], args[idx], args[idx-1]);
825 err_code |= ERR_ALERT | ERR_FATAL;
826 goto out;
827 }
828 else if (err) {
829 ha_alert("parsing [%s:%d] : %s: unexpected character '%c' in argument of '%s'.\n",
830 file, linenum, args[0], *err, args[idx-1]);
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100831 err_code |= ERR_ALERT | ERR_FATAL;
832 goto out;
833 }
834 t->expire = val;
835 idx++;
836 }
837 else if (strcmp(args[idx], "nopurge") == 0) {
838 t->nopurge = 1;
839 idx++;
840 }
841 else if (strcmp(args[idx], "type") == 0) {
842 idx++;
843 if (stktable_parse_type(args, &idx, &t->type, &t->key_size) != 0) {
844 ha_alert("parsing [%s:%d] : %s: unknown type '%s'.\n",
845 file, linenum, args[0], args[idx]);
846 err_code |= ERR_ALERT | ERR_FATAL;
847 goto out;
848 }
849 /* idx already points to next arg */
850 }
851 else if (strcmp(args[idx], "store") == 0) {
852 int type, err;
853 char *cw, *nw, *sa;
854
855 idx++;
856 nw = args[idx];
857 while (*nw) {
858 /* the "store" keyword supports a comma-separated list */
859 cw = nw;
860 sa = NULL; /* store arg */
861 while (*nw && *nw != ',') {
862 if (*nw == '(') {
863 *nw = 0;
864 sa = ++nw;
865 while (*nw != ')') {
866 if (!*nw) {
867 ha_alert("parsing [%s:%d] : %s: missing closing parenthesis after store option '%s'.\n",
868 file, linenum, args[0], cw);
869 err_code |= ERR_ALERT | ERR_FATAL;
870 goto out;
871 }
872 nw++;
873 }
874 *nw = '\0';
875 }
876 nw++;
877 }
878 if (*nw)
879 *nw++ = '\0';
880 type = stktable_get_data_type(cw);
881 if (type < 0) {
882 ha_alert("parsing [%s:%d] : %s: unknown store option '%s'.\n",
883 file, linenum, args[0], cw);
884 err_code |= ERR_ALERT | ERR_FATAL;
885 goto out;
886 }
887
888 err = stktable_alloc_data_type(t, type, sa);
889 switch (err) {
890 case PE_NONE: break;
891 case PE_EXIST:
892 ha_warning("parsing [%s:%d]: %s: store option '%s' already enabled, ignored.\n",
893 file, linenum, args[0], cw);
894 err_code |= ERR_WARN;
895 break;
896
897 case PE_ARG_MISSING:
898 ha_alert("parsing [%s:%d] : %s: missing argument to store option '%s'.\n",
899 file, linenum, args[0], cw);
900 err_code |= ERR_ALERT | ERR_FATAL;
901 goto out;
902
903 case PE_ARG_NOT_USED:
904 ha_alert("parsing [%s:%d] : %s: unexpected argument to store option '%s'.\n",
905 file, linenum, args[0], cw);
906 err_code |= ERR_ALERT | ERR_FATAL;
907 goto out;
908
909 default:
910 ha_alert("parsing [%s:%d] : %s: error when processing store option '%s'.\n",
911 file, linenum, args[0], cw);
912 err_code |= ERR_ALERT | ERR_FATAL;
913 goto out;
914 }
915 }
916 idx++;
917 }
Thayne McCombs92149f92020-11-20 01:28:26 -0700918 else if (strcmp(args[idx], "srvkey") == 0) {
919 char *keytype;
920 idx++;
921 keytype = args[idx];
922 if (strcmp(keytype, "name") == 0) {
923 t->server_key_type = STKTABLE_SRV_NAME;
924 }
925 else if (strcmp(keytype, "addr") == 0) {
926 t->server_key_type = STKTABLE_SRV_ADDR;
927 }
928 else {
929 ha_alert("parsing [%s:%d] : %s : unknown server key type '%s'.\n",
930 file, linenum, args[0], keytype);
931 err_code |= ERR_ALERT | ERR_FATAL;
932 goto out;
933
934 }
935 idx++;
936 }
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100937 else {
938 ha_alert("parsing [%s:%d] : %s: unknown argument '%s'.\n",
939 file, linenum, args[0], args[idx]);
940 err_code |= ERR_ALERT | ERR_FATAL;
941 goto out;
942 }
943 }
944
945 if (!t->size) {
946 ha_alert("parsing [%s:%d] : %s: missing size.\n",
947 file, linenum, args[0]);
948 err_code |= ERR_ALERT | ERR_FATAL;
949 goto out;
950 }
951
952 if (t->type == (unsigned int)-1) {
953 ha_alert("parsing [%s:%d] : %s: missing type.\n",
954 file, linenum, args[0]);
955 err_code |= ERR_ALERT | ERR_FATAL;
956 goto out;
957 }
958
959 out:
960 return err_code;
961}
962
Willy Tarreau8fed9032014-07-03 17:02:46 +0200963/* Prepares a stktable_key from a sample <smp> to search into table <t>.
Willy Tarreauf0c730a2016-05-25 17:07:56 +0200964 * Note that the sample *is* modified and that the returned key may point
965 * to it, so the sample must not be modified afterwards before the lookup.
Willy Tarreau8fed9032014-07-03 17:02:46 +0200966 * Returns NULL if the sample could not be converted (eg: no matching type),
967 * otherwise a pointer to the static stktable_key filled with what is needed
968 * for the lookup.
Willy Tarreauf0b38bf2010-06-06 13:22:23 +0200969 */
Willy Tarreau8fed9032014-07-03 17:02:46 +0200970struct stktable_key *smp_to_stkey(struct sample *smp, struct stktable *t)
Willy Tarreauf0b38bf2010-06-06 13:22:23 +0200971{
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200972 /* Convert sample. */
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200973 if (!sample_convert(smp, t->type))
Willy Tarreau7fc1c6e2012-04-26 11:03:17 +0200974 return NULL;
975
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200976 /* Fill static_table_key. */
977 switch (t->type) {
Emeric Brun485479d2010-09-23 18:02:19 +0200978
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200979 case SMP_T_IPV4:
Christopher Fauletca20d022017-08-29 15:30:31 +0200980 static_table_key.key = &smp->data.u.ipv4;
981 static_table_key.key_len = 4;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200982 break;
Emeric Brun485479d2010-09-23 18:02:19 +0200983
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200984 case SMP_T_IPV6:
Christopher Fauletca20d022017-08-29 15:30:31 +0200985 static_table_key.key = &smp->data.u.ipv6;
986 static_table_key.key_len = 16;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200987 break;
Emeric Brun485479d2010-09-23 18:02:19 +0200988
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200989 case SMP_T_SINT:
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200990 /* The stick table require a 32bit unsigned int, "sint" is a
991 * signed 64 it, so we can convert it inplace.
992 */
Willy Tarreau28c63c12019-10-23 06:21:05 +0200993 smp->data.u.sint = (unsigned int)smp->data.u.sint;
Christopher Fauletca20d022017-08-29 15:30:31 +0200994 static_table_key.key = &smp->data.u.sint;
995 static_table_key.key_len = 4;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200996 break;
997
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200998 case SMP_T_STR:
Willy Tarreauce6955e2016-08-09 11:59:12 +0200999 if (!smp_make_safe(smp))
1000 return NULL;
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001001 static_table_key.key = smp->data.u.str.area;
1002 static_table_key.key_len = smp->data.u.str.data;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001003 break;
Emeric Brun485479d2010-09-23 18:02:19 +02001004
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +02001005 case SMP_T_BIN:
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001006 if (smp->data.u.str.data < t->key_size) {
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001007 /* This type needs padding with 0. */
Willy Tarreauf65c6c02016-08-09 12:08:41 +02001008 if (!smp_make_rw(smp))
1009 return NULL;
1010
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001011 if (smp->data.u.str.size < t->key_size)
1012 if (!smp_dup(smp))
1013 return NULL;
1014 if (smp->data.u.str.size < t->key_size)
1015 return NULL;
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001016 memset(smp->data.u.str.area + smp->data.u.str.data, 0,
1017 t->key_size - smp->data.u.str.data);
1018 smp->data.u.str.data = t->key_size;
Emeric Brun485479d2010-09-23 18:02:19 +02001019 }
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001020 static_table_key.key = smp->data.u.str.area;
1021 static_table_key.key_len = smp->data.u.str.data;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001022 break;
Emeric Brun485479d2010-09-23 18:02:19 +02001023
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001024 default: /* impossible case. */
1025 return NULL;
Emeric Brun485479d2010-09-23 18:02:19 +02001026 }
1027
Christopher Fauletca20d022017-08-29 15:30:31 +02001028 return &static_table_key;
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001029}
1030
1031/*
Willy Tarreau8fed9032014-07-03 17:02:46 +02001032 * Process a fetch + format conversion as defined by the sample expression <expr>
1033 * on request or response considering the <opt> parameter. Returns either NULL if
1034 * no key could be extracted, or a pointer to the converted result stored in
1035 * static_table_key in format <table_type>. If <smp> is not NULL, it will be reset
1036 * and its flags will be initialized so that the caller gets a copy of the input
Willy Tarreau6bcb0a82014-07-30 08:56:35 +02001037 * sample, and knows why it was not accepted (eg: SMP_F_MAY_CHANGE is present
1038 * without SMP_OPT_FINAL). The output will be usable like this :
1039 *
1040 * return MAY_CHANGE FINAL Meaning for the sample
1041 * NULL 0 * Not present and will never be (eg: header)
1042 * NULL 1 0 Not present or unstable, could change (eg: req_len)
1043 * NULL 1 1 Not present, will not change anymore
1044 * smp 0 * Present and will not change (eg: header)
1045 * smp 1 0 not possible
1046 * smp 1 1 Present, last known value (eg: request length)
Willy Tarreau8fed9032014-07-03 17:02:46 +02001047 */
Willy Tarreau192252e2015-04-04 01:47:55 +02001048struct stktable_key *stktable_fetch_key(struct stktable *t, struct proxy *px, struct session *sess, struct stream *strm,
Willy Tarreau8fed9032014-07-03 17:02:46 +02001049 unsigned int opt, struct sample_expr *expr, struct sample *smp)
1050{
1051 if (smp)
1052 memset(smp, 0, sizeof(*smp));
1053
Willy Tarreau192252e2015-04-04 01:47:55 +02001054 smp = sample_process(px, sess, strm, opt, expr, smp);
Willy Tarreau8fed9032014-07-03 17:02:46 +02001055 if (!smp)
1056 return NULL;
1057
1058 if ((smp->flags & SMP_F_MAY_CHANGE) && !(opt & SMP_OPT_FINAL))
1059 return NULL; /* we can only use stable samples */
1060
1061 return smp_to_stkey(smp, t);
1062}
1063
1064/*
Willy Tarreau12785782012-04-27 21:37:17 +02001065 * Returns 1 if sample expression <expr> result can be converted to table key of
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001066 * type <table_type>, otherwise zero. Used in configuration check.
1067 */
Willy Tarreau12785782012-04-27 21:37:17 +02001068int stktable_compatible_sample(struct sample_expr *expr, unsigned long table_type)
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001069{
Thierry FOURNIERf73eb8f2013-11-27 15:30:55 +01001070 int out_type;
1071
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +02001072 if (table_type >= SMP_TYPES || !stktable_types[table_type].kw)
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001073 return 0;
1074
Thierry FOURNIERf73eb8f2013-11-27 15:30:55 +01001075 out_type = smp_expr_output_type(expr);
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001076
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001077 /* Convert sample. */
1078 if (!sample_casts[out_type][table_type])
Thierry FOURNIERf73eb8f2013-11-27 15:30:55 +01001079 return 0;
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001080
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001081 return 1;
1082}
Emeric Brun3bd697e2010-01-04 15:23:48 +01001083
Willy Tarreauedee1d62014-07-15 16:44:27 +02001084/* Extra data types processing : after the last one, some room may remain
1085 * before STKTABLE_DATA_TYPES that may be used to register extra data types
1086 * at run time.
1087 */
Willy Tarreau08d5f982010-06-06 13:34:54 +02001088struct stktable_data_type stktable_data_types[STKTABLE_DATA_TYPES] = {
Willy Tarreau3b9c6e02010-07-18 08:04:30 +02001089 [STKTABLE_DT_SERVER_ID] = { .name = "server_id", .std_type = STD_T_SINT },
Thierry FOURNIER3cf11112015-07-28 08:57:05 +02001090 [STKTABLE_DT_GPT0] = { .name = "gpt0", .std_type = STD_T_UINT },
Willy Tarreau3b9c6e02010-07-18 08:04:30 +02001091 [STKTABLE_DT_GPC0] = { .name = "gpc0", .std_type = STD_T_UINT },
Willy Tarreauba2ffd12013-05-29 15:54:14 +02001092 [STKTABLE_DT_GPC0_RATE] = { .name = "gpc0_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
Willy Tarreau3b9c6e02010-07-18 08:04:30 +02001093 [STKTABLE_DT_CONN_CNT] = { .name = "conn_cnt", .std_type = STD_T_UINT },
1094 [STKTABLE_DT_CONN_RATE] = { .name = "conn_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
1095 [STKTABLE_DT_CONN_CUR] = { .name = "conn_cur", .std_type = STD_T_UINT },
1096 [STKTABLE_DT_SESS_CNT] = { .name = "sess_cnt", .std_type = STD_T_UINT },
1097 [STKTABLE_DT_SESS_RATE] = { .name = "sess_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
1098 [STKTABLE_DT_HTTP_REQ_CNT] = { .name = "http_req_cnt", .std_type = STD_T_UINT },
1099 [STKTABLE_DT_HTTP_REQ_RATE] = { .name = "http_req_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
1100 [STKTABLE_DT_HTTP_ERR_CNT] = { .name = "http_err_cnt", .std_type = STD_T_UINT },
1101 [STKTABLE_DT_HTTP_ERR_RATE] = { .name = "http_err_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
1102 [STKTABLE_DT_BYTES_IN_CNT] = { .name = "bytes_in_cnt", .std_type = STD_T_ULL },
1103 [STKTABLE_DT_BYTES_IN_RATE] = { .name = "bytes_in_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
1104 [STKTABLE_DT_BYTES_OUT_CNT] = { .name = "bytes_out_cnt", .std_type = STD_T_ULL },
1105 [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 +01001106 [STKTABLE_DT_GPC1] = { .name = "gpc1", .std_type = STD_T_UINT },
1107 [STKTABLE_DT_GPC1_RATE] = { .name = "gpc1_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
Thayne McCombs92149f92020-11-20 01:28:26 -07001108 [STKTABLE_DT_SERVER_KEY] = { .name = "server_key", .std_type = STD_T_DICT },
Willy Tarreau826f3ab2021-02-10 12:07:15 +01001109 [STKTABLE_DT_HTTP_FAIL_CNT] = { .name = "http_fail_cnt", .std_type = STD_T_UINT },
1110 [STKTABLE_DT_HTTP_FAIL_RATE]= { .name = "http_fail_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
Willy Tarreau08d5f982010-06-06 13:34:54 +02001111};
1112
Willy Tarreauedee1d62014-07-15 16:44:27 +02001113/* Registers stick-table extra data type with index <idx>, name <name>, type
1114 * <std_type> and arg type <arg_type>. If the index is negative, the next free
1115 * index is automatically allocated. The allocated index is returned, or -1 if
1116 * no free index was found or <name> was already registered. The <name> is used
1117 * directly as a pointer, so if it's not stable, the caller must allocate it.
1118 */
1119int stktable_register_data_store(int idx, const char *name, int std_type, int arg_type)
1120{
1121 if (idx < 0) {
1122 for (idx = 0; idx < STKTABLE_DATA_TYPES; idx++) {
1123 if (!stktable_data_types[idx].name)
1124 break;
1125
1126 if (strcmp(stktable_data_types[idx].name, name) == 0)
1127 return -1;
1128 }
1129 }
1130
1131 if (idx >= STKTABLE_DATA_TYPES)
1132 return -1;
1133
1134 if (stktable_data_types[idx].name != NULL)
1135 return -1;
1136
1137 stktable_data_types[idx].name = name;
1138 stktable_data_types[idx].std_type = std_type;
1139 stktable_data_types[idx].arg_type = arg_type;
1140 return idx;
1141}
1142
Willy Tarreau08d5f982010-06-06 13:34:54 +02001143/*
1144 * Returns the data type number for the stktable_data_type whose name is <name>,
1145 * or <0 if not found.
1146 */
1147int stktable_get_data_type(char *name)
1148{
1149 int type;
1150
1151 for (type = 0; type < STKTABLE_DATA_TYPES; type++) {
Willy Tarreauedee1d62014-07-15 16:44:27 +02001152 if (!stktable_data_types[type].name)
1153 continue;
Willy Tarreau08d5f982010-06-06 13:34:54 +02001154 if (strcmp(name, stktable_data_types[type].name) == 0)
1155 return type;
1156 }
Thayne McCombs92149f92020-11-20 01:28:26 -07001157 /* For backwards compatibility */
1158 if (strcmp(name, "server_name") == 0)
1159 return STKTABLE_DT_SERVER_KEY;
Willy Tarreau08d5f982010-06-06 13:34:54 +02001160 return -1;
1161}
1162
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001163/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1164 * it up into this table. Returns true if found, false otherwise. The input
1165 * type is STR so that input samples are converted to string (since all types
1166 * can be converted to strings), then the function casts the string again into
1167 * the table's type. This is a double conversion, but in the future we might
1168 * support automatic input types to perform the cast on the fly.
1169 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001170static int sample_conv_in_table(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001171{
1172 struct stktable *t;
1173 struct stktable_key *key;
1174 struct stksess *ts;
1175
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001176 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001177
1178 key = smp_to_stkey(smp, t);
1179 if (!key)
1180 return 0;
1181
1182 ts = stktable_lookup_key(t, key);
1183
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001184 smp->data.type = SMP_T_BOOL;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001185 smp->data.u.sint = !!ts;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001186 smp->flags = SMP_F_VOL_TEST;
Willy Tarreau43e90352018-06-27 06:25:57 +02001187 stktable_release(t, ts);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001188 return 1;
1189}
1190
1191/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1192 * it up into this table. Returns the data rate received from clients in bytes/s
1193 * if the key is present in the table, otherwise zero, so that comparisons can
1194 * be easily performed. If the inspected parameter is not stored in the table,
1195 * <not found> is returned.
1196 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001197static int sample_conv_table_bytes_in_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001198{
1199 struct stktable *t;
1200 struct stktable_key *key;
1201 struct stksess *ts;
1202 void *ptr;
1203
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001204 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001205
1206 key = smp_to_stkey(smp, t);
1207 if (!key)
1208 return 0;
1209
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001210 ts = stktable_lookup_key(t, key);
1211
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001212 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001213 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001214 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001215
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001216 if (!ts) /* key not present */
1217 return 1;
1218
1219 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_IN_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001220 if (ptr)
1221 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, bytes_in_rate),
1222 t->data_arg[STKTABLE_DT_BYTES_IN_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001223
Daniel Corbett3e60b112018-05-27 09:47:12 -04001224 stktable_release(t, ts);
1225 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001226}
1227
1228/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1229 * it up into this table. Returns the cumulated number of connections for the key
1230 * if the key is present in the table, otherwise zero, so that comparisons can
1231 * be easily performed. If the inspected parameter is not stored in the table,
1232 * <not found> is returned.
1233 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001234static int sample_conv_table_conn_cnt(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001235{
1236 struct stktable *t;
1237 struct stktable_key *key;
1238 struct stksess *ts;
1239 void *ptr;
1240
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001241 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001242
1243 key = smp_to_stkey(smp, t);
1244 if (!key)
1245 return 0;
1246
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001247 ts = stktable_lookup_key(t, key);
1248
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001249 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001250 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001251 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001252
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001253 if (!ts) /* key not present */
1254 return 1;
1255
1256 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_CONN_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001257 if (ptr)
1258 smp->data.u.sint = stktable_data_cast(ptr, conn_cnt);
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 number of concurrent connections for the
1266 * key if the key is present in the table, otherwise zero, so that comparisons
1267 * can be easily performed. If the inspected parameter is not stored in the
1268 * table, <not found> is returned.
1269 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001270static int sample_conv_table_conn_cur(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_CUR);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001293 if (ptr)
1294 smp->data.u.sint = stktable_data_cast(ptr, conn_cur);
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 rate of incoming connections from the key
1302 * if the key is present in the table, otherwise zero, so that comparisons can
1303 * be easily performed. If the inspected parameter is not stored in the table,
1304 * <not found> is returned.
1305 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001306static int sample_conv_table_conn_rate(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_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001329 if (ptr)
1330 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, conn_rate),
1331 t->data_arg[STKTABLE_DT_CONN_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001332
Daniel Corbett3e60b112018-05-27 09:47:12 -04001333 stktable_release(t, ts);
1334 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001335}
1336
1337/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1338 * it up into this table. Returns the data rate sent to clients in bytes/s
1339 * if the key is present in the table, otherwise zero, so that comparisons can
1340 * be easily performed. If the inspected parameter is not stored in the table,
1341 * <not found> is returned.
1342 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001343static int sample_conv_table_bytes_out_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001344{
1345 struct stktable *t;
1346 struct stktable_key *key;
1347 struct stksess *ts;
1348 void *ptr;
1349
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001350 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001351
1352 key = smp_to_stkey(smp, t);
1353 if (!key)
1354 return 0;
1355
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001356 ts = stktable_lookup_key(t, key);
1357
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001358 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001359 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001360 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001361
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001362 if (!ts) /* key not present */
1363 return 1;
1364
1365 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_OUT_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001366 if (ptr)
1367 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, bytes_out_rate),
1368 t->data_arg[STKTABLE_DT_BYTES_OUT_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001369
Daniel Corbett3e60b112018-05-27 09:47:12 -04001370 stktable_release(t, ts);
1371 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001372}
1373
1374/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001375 * it up into this table. Returns the value of the GPT0 tag for the key
1376 * if the key is present in the table, otherwise false, so that comparisons can
1377 * be easily performed. If the inspected parameter is not stored in the table,
1378 * <not found> is returned.
1379 */
1380static int sample_conv_table_gpt0(const struct arg *arg_p, struct sample *smp, void *private)
1381{
1382 struct stktable *t;
1383 struct stktable_key *key;
1384 struct stksess *ts;
1385 void *ptr;
1386
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001387 t = arg_p[0].data.t;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001388
1389 key = smp_to_stkey(smp, t);
1390 if (!key)
1391 return 0;
1392
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001393 ts = stktable_lookup_key(t, key);
1394
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001395 smp->flags = SMP_F_VOL_TEST;
1396 smp->data.type = SMP_T_SINT;
1397 smp->data.u.sint = 0;
1398
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001399 if (!ts) /* key not present */
1400 return 1;
1401
1402 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPT0);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001403 if (ptr)
1404 smp->data.u.sint = stktable_data_cast(ptr, gpt0);
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001405
Daniel Corbett3e60b112018-05-27 09:47:12 -04001406 stktable_release(t, ts);
1407 return !!ptr;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001408}
1409
1410/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001411 * it up into this table. Returns the value of the GPC0 counter for the key
1412 * if the key is present in the table, otherwise zero, so that comparisons can
1413 * be easily performed. If the inspected parameter is not stored in the table,
1414 * <not found> is returned.
1415 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001416static int sample_conv_table_gpc0(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001417{
1418 struct stktable *t;
1419 struct stktable_key *key;
1420 struct stksess *ts;
1421 void *ptr;
1422
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001423 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001424
1425 key = smp_to_stkey(smp, t);
1426 if (!key)
1427 return 0;
1428
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001429 ts = stktable_lookup_key(t, key);
1430
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001431 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001432 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001433 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001434
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001435 if (!ts) /* key not present */
1436 return 1;
1437
1438 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPC0);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001439 if (ptr)
1440 smp->data.u.sint = stktable_data_cast(ptr, gpc0);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001441
Daniel Corbett3e60b112018-05-27 09:47:12 -04001442 stktable_release(t, ts);
1443 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001444}
1445
1446/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1447 * it up into this table. Returns the event rate of the GPC0 counter for the key
1448 * if the key is present in the table, otherwise zero, so that comparisons can
1449 * be easily performed. If the inspected parameter is not stored in the table,
1450 * <not found> is returned.
1451 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001452static int sample_conv_table_gpc0_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001453{
1454 struct stktable *t;
1455 struct stktable_key *key;
1456 struct stksess *ts;
1457 void *ptr;
1458
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001459 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001460
1461 key = smp_to_stkey(smp, t);
1462 if (!key)
1463 return 0;
1464
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001465 ts = stktable_lookup_key(t, key);
1466
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001467 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001468 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001469 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001470
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001471 if (!ts) /* key not present */
1472 return 1;
1473
1474 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPC0_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001475 if (ptr)
1476 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, gpc0_rate),
1477 t->data_arg[STKTABLE_DT_GPC0_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001478
Daniel Corbett3e60b112018-05-27 09:47:12 -04001479 stktable_release(t, ts);
1480 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001481}
1482
1483/* 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 +01001484 * it up into this table. Returns the value of the GPC1 counter for the key
1485 * if the key is present in the table, otherwise zero, so that comparisons can
1486 * be easily performed. If the inspected parameter is not stored in the table,
1487 * <not found> is returned.
1488 */
1489static int sample_conv_table_gpc1(const struct arg *arg_p, struct sample *smp, void *private)
1490{
1491 struct stktable *t;
1492 struct stktable_key *key;
1493 struct stksess *ts;
1494 void *ptr;
1495
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001496 t = arg_p[0].data.t;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001497
1498 key = smp_to_stkey(smp, t);
1499 if (!key)
1500 return 0;
1501
1502 ts = stktable_lookup_key(t, key);
1503
1504 smp->flags = SMP_F_VOL_TEST;
1505 smp->data.type = SMP_T_SINT;
1506 smp->data.u.sint = 0;
1507
1508 if (!ts) /* key not present */
1509 return 1;
1510
1511 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPC1);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001512 if (ptr)
1513 smp->data.u.sint = stktable_data_cast(ptr, gpc1);
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001514
Daniel Corbett3e60b112018-05-27 09:47:12 -04001515 stktable_release(t, ts);
1516 return !!ptr;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001517}
1518
1519/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1520 * it up into this table. Returns the event rate of the GPC1 counter for the key
1521 * if the key is present in the table, otherwise zero, so that comparisons can
1522 * be easily performed. If the inspected parameter is not stored in the table,
1523 * <not found> is returned.
1524 */
1525static int sample_conv_table_gpc1_rate(const struct arg *arg_p, struct sample *smp, void *private)
1526{
1527 struct stktable *t;
1528 struct stktable_key *key;
1529 struct stksess *ts;
1530 void *ptr;
1531
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001532 t = arg_p[0].data.t;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001533
1534 key = smp_to_stkey(smp, t);
1535 if (!key)
1536 return 0;
1537
1538 ts = stktable_lookup_key(t, key);
1539
1540 smp->flags = SMP_F_VOL_TEST;
1541 smp->data.type = SMP_T_SINT;
1542 smp->data.u.sint = 0;
1543
1544 if (!ts) /* key not present */
1545 return 1;
1546
1547 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPC1_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001548 if (ptr)
1549 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, gpc1_rate),
1550 t->data_arg[STKTABLE_DT_GPC1_RATE].u);
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001551
Daniel Corbett3e60b112018-05-27 09:47:12 -04001552 stktable_release(t, ts);
1553 return !!ptr;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001554}
1555
1556/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001557 * it up into this table. Returns the cumulated number of HTTP request errors
1558 * for the key if the key is present in the table, otherwise zero, so that
1559 * comparisons can be easily performed. If the inspected parameter is not stored
1560 * in the table, <not found> is returned.
1561 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001562static int sample_conv_table_http_err_cnt(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001563{
1564 struct stktable *t;
1565 struct stktable_key *key;
1566 struct stksess *ts;
1567 void *ptr;
1568
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001569 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001570
1571 key = smp_to_stkey(smp, t);
1572 if (!key)
1573 return 0;
1574
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001575 ts = stktable_lookup_key(t, key);
1576
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001577 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001578 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001579 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001580
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001581 if (!ts) /* key not present */
1582 return 1;
1583
1584 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_ERR_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001585 if (ptr)
1586 smp->data.u.sint = stktable_data_cast(ptr, http_err_cnt);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001587
Daniel Corbett3e60b112018-05-27 09:47:12 -04001588 stktable_release(t, ts);
1589 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001590}
1591
1592/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1593 * it up into this table. Returns the HTTP request error rate the key
1594 * if the key is present in the table, otherwise zero, so that comparisons can
1595 * be easily performed. If the inspected parameter is not stored in the table,
1596 * <not found> is returned.
1597 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001598static int sample_conv_table_http_err_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001599{
1600 struct stktable *t;
1601 struct stktable_key *key;
1602 struct stksess *ts;
1603 void *ptr;
1604
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001605 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001606
1607 key = smp_to_stkey(smp, t);
1608 if (!key)
1609 return 0;
1610
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001611 ts = stktable_lookup_key(t, key);
1612
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001613 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001614 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001615 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001616
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001617 if (!ts) /* key not present */
1618 return 1;
1619
1620 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_ERR_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001621 if (ptr)
1622 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, http_err_rate),
1623 t->data_arg[STKTABLE_DT_HTTP_ERR_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001624
Daniel Corbett3e60b112018-05-27 09:47:12 -04001625 stktable_release(t, ts);
1626 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001627}
1628
1629/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Willy Tarreau826f3ab2021-02-10 12:07:15 +01001630 * it up into this table. Returns the cumulated number of HTTP response failures
1631 * for the key if the key is present in the table, otherwise zero, so that
1632 * comparisons can be easily performed. If the inspected parameter is not stored
1633 * in the table, <not found> is returned.
1634 */
1635static int sample_conv_table_http_fail_cnt(const struct arg *arg_p, struct sample *smp, void *private)
1636{
1637 struct stktable *t;
1638 struct stktable_key *key;
1639 struct stksess *ts;
1640 void *ptr;
1641
1642 t = arg_p[0].data.t;
1643
1644 key = smp_to_stkey(smp, t);
1645 if (!key)
1646 return 0;
1647
1648 ts = stktable_lookup_key(t, key);
1649
1650 smp->flags = SMP_F_VOL_TEST;
1651 smp->data.type = SMP_T_SINT;
1652 smp->data.u.sint = 0;
1653
1654 if (!ts) /* key not present */
1655 return 1;
1656
1657 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_FAIL_CNT);
1658 if (ptr)
1659 smp->data.u.sint = stktable_data_cast(ptr, http_fail_cnt);
1660
1661 stktable_release(t, ts);
1662 return !!ptr;
1663}
1664
1665/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1666 * it up into this table. Returns the HTTP response failure rate for the key
1667 * if the key is present in the table, otherwise zero, so that comparisons can
1668 * be easily performed. If the inspected parameter is not stored in the table,
1669 * <not found> is returned.
1670 */
1671static int sample_conv_table_http_fail_rate(const struct arg *arg_p, struct sample *smp, void *private)
1672{
1673 struct stktable *t;
1674 struct stktable_key *key;
1675 struct stksess *ts;
1676 void *ptr;
1677
1678 t = arg_p[0].data.t;
1679
1680 key = smp_to_stkey(smp, t);
1681 if (!key)
1682 return 0;
1683
1684 ts = stktable_lookup_key(t, key);
1685
1686 smp->flags = SMP_F_VOL_TEST;
1687 smp->data.type = SMP_T_SINT;
1688 smp->data.u.sint = 0;
1689
1690 if (!ts) /* key not present */
1691 return 1;
1692
1693 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_FAIL_RATE);
1694 if (ptr)
1695 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, http_fail_rate),
1696 t->data_arg[STKTABLE_DT_HTTP_FAIL_RATE].u);
1697
1698 stktable_release(t, ts);
1699 return !!ptr;
1700}
1701
1702/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001703 * it up into this table. Returns the cumulated number of HTTP request for the
1704 * key if the key is present in the table, otherwise zero, so that comparisons
1705 * can be easily performed. If the inspected parameter is not stored in the
1706 * table, <not found> is returned.
1707 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001708static int sample_conv_table_http_req_cnt(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001709{
1710 struct stktable *t;
1711 struct stktable_key *key;
1712 struct stksess *ts;
1713 void *ptr;
1714
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001715 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001716
1717 key = smp_to_stkey(smp, t);
1718 if (!key)
1719 return 0;
1720
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001721 ts = stktable_lookup_key(t, key);
1722
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001723 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001724 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001725 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001726
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001727 if (!ts) /* key not present */
1728 return 1;
1729
1730 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_REQ_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001731 if (ptr)
1732 smp->data.u.sint = stktable_data_cast(ptr, http_req_cnt);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001733
Daniel Corbett3e60b112018-05-27 09:47:12 -04001734 stktable_release(t, ts);
1735 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001736}
1737
1738/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1739 * it up into this table. Returns the HTTP request rate the key if the key is
1740 * present in the table, otherwise zero, so that comparisons can be easily
1741 * performed. If the inspected parameter is not stored in the table, <not found>
1742 * is returned.
1743 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001744static int sample_conv_table_http_req_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001745{
1746 struct stktable *t;
1747 struct stktable_key *key;
1748 struct stksess *ts;
1749 void *ptr;
1750
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001751 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001752
1753 key = smp_to_stkey(smp, t);
1754 if (!key)
1755 return 0;
1756
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001757 ts = stktable_lookup_key(t, key);
1758
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001759 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001760 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001761 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001762
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001763 if (!ts) /* key not present */
1764 return 1;
1765
1766 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_REQ_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001767 if (ptr)
1768 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, http_req_rate),
1769 t->data_arg[STKTABLE_DT_HTTP_REQ_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001770
Daniel Corbett3e60b112018-05-27 09:47:12 -04001771 stktable_release(t, ts);
1772 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001773}
1774
1775/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1776 * it up into this table. Returns the volume of datareceived from clients in kbytes
1777 * if the key is present in the table, otherwise zero, so that comparisons can
1778 * be easily performed. If the inspected parameter is not stored in the table,
1779 * <not found> is returned.
1780 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001781static int sample_conv_table_kbytes_in(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001782{
1783 struct stktable *t;
1784 struct stktable_key *key;
1785 struct stksess *ts;
1786 void *ptr;
1787
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001788 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001789
1790 key = smp_to_stkey(smp, t);
1791 if (!key)
1792 return 0;
1793
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001794 ts = stktable_lookup_key(t, key);
1795
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001796 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001797 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001798 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001799
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001800 if (!ts) /* key not present */
1801 return 1;
1802
1803 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_IN_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001804 if (ptr)
1805 smp->data.u.sint = stktable_data_cast(ptr, bytes_in_cnt) >> 10;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001806
Daniel Corbett3e60b112018-05-27 09:47:12 -04001807 stktable_release(t, ts);
1808 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001809}
1810
1811/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1812 * it up into this table. Returns the volume of data sent to clients in kbytes
1813 * if the key is present in the table, otherwise zero, so that comparisons can
1814 * be easily performed. If the inspected parameter is not stored in the table,
1815 * <not found> is returned.
1816 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001817static int sample_conv_table_kbytes_out(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001818{
1819 struct stktable *t;
1820 struct stktable_key *key;
1821 struct stksess *ts;
1822 void *ptr;
1823
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001824 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001825
1826 key = smp_to_stkey(smp, t);
1827 if (!key)
1828 return 0;
1829
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001830 ts = stktable_lookup_key(t, key);
1831
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001832 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001833 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001834 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001835
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001836 if (!ts) /* key not present */
1837 return 1;
1838
1839 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_OUT_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001840 if (ptr)
1841 smp->data.u.sint = stktable_data_cast(ptr, bytes_out_cnt) >> 10;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001842
Daniel Corbett3e60b112018-05-27 09:47:12 -04001843 stktable_release(t, ts);
1844 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001845}
1846
1847/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1848 * it up into this table. Returns the server ID associated with the key if the
1849 * key is present in the table, otherwise zero, so that comparisons can be
1850 * easily performed. If the inspected parameter is not stored in the table,
1851 * <not found> is returned.
1852 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001853static int sample_conv_table_server_id(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001854{
1855 struct stktable *t;
1856 struct stktable_key *key;
1857 struct stksess *ts;
1858 void *ptr;
1859
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001860 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001861
1862 key = smp_to_stkey(smp, t);
1863 if (!key)
1864 return 0;
1865
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001866 ts = stktable_lookup_key(t, key);
1867
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001868 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001869 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001870 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001871
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001872 if (!ts) /* key not present */
1873 return 1;
1874
1875 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_SERVER_ID);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001876 if (ptr)
1877 smp->data.u.sint = stktable_data_cast(ptr, server_id);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001878
Daniel Corbett3e60b112018-05-27 09:47:12 -04001879 stktable_release(t, ts);
1880 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001881}
1882
1883/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1884 * it up into this table. Returns the cumulated number of sessions for the
1885 * key if the key is present in the table, otherwise zero, so that comparisons
1886 * can be easily performed. If the inspected parameter is not stored in the
1887 * table, <not found> is returned.
1888 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001889static int sample_conv_table_sess_cnt(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001890{
1891 struct stktable *t;
1892 struct stktable_key *key;
1893 struct stksess *ts;
1894 void *ptr;
1895
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001896 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001897
1898 key = smp_to_stkey(smp, t);
1899 if (!key)
1900 return 0;
1901
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001902 ts = stktable_lookup_key(t, key);
1903
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001904 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001905 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001906 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001907
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001908 if (!ts) /* key not present */
1909 return 1;
1910
1911 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_SESS_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001912 if (ptr)
1913 smp->data.u.sint = stktable_data_cast(ptr, sess_cnt);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001914
Daniel Corbett3e60b112018-05-27 09:47:12 -04001915 stktable_release(t, ts);
1916 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001917}
1918
1919/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1920 * it up into this table. Returns the session rate the key if the key is
1921 * present in the table, otherwise zero, so that comparisons can be easily
1922 * performed. If the inspected parameter is not stored in the table, <not found>
1923 * is returned.
1924 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001925static int sample_conv_table_sess_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001926{
1927 struct stktable *t;
1928 struct stktable_key *key;
1929 struct stksess *ts;
1930 void *ptr;
1931
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001932 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001933
1934 key = smp_to_stkey(smp, t);
1935 if (!key)
1936 return 0;
1937
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001938 ts = stktable_lookup_key(t, key);
1939
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001940 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001941 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001942 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001943
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001944 if (!ts) /* key not present */
1945 return 1;
1946
1947 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_SESS_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001948 if (ptr)
1949 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, sess_rate),
1950 t->data_arg[STKTABLE_DT_SESS_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001951
Daniel Corbett3e60b112018-05-27 09:47:12 -04001952 stktable_release(t, ts);
1953 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001954}
1955
1956/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1957 * it up into this table. Returns the amount of concurrent connections tracking
1958 * the same key if the key is present in the table, otherwise zero, so that
1959 * comparisons can be easily performed. If the inspected parameter is not
1960 * stored in the table, <not found> is returned.
1961 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001962static int sample_conv_table_trackers(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001963{
1964 struct stktable *t;
1965 struct stktable_key *key;
1966 struct stksess *ts;
1967
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001968 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001969
1970 key = smp_to_stkey(smp, t);
1971 if (!key)
1972 return 0;
1973
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001974 ts = stktable_lookup_key(t, key);
1975
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001976 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001977 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001978 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001979
Tim Duesterhus65189c12018-06-26 15:57:29 +02001980 if (!ts)
1981 return 1;
1982
1983 smp->data.u.sint = ts->ref_cnt;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001984
Daniel Corbett3e60b112018-05-27 09:47:12 -04001985 stktable_release(t, ts);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001986 return 1;
1987}
1988
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001989/* Always returns 1. */
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001990static enum act_return action_inc_gpc0(struct act_rule *rule, struct proxy *px,
Willy Tarreau658b85b2015-09-27 10:00:49 +02001991 struct session *sess, struct stream *s, int flags)
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001992{
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001993 struct stksess *ts;
1994 struct stkctr *stkctr;
1995
1996 /* Extract the stksess, return OK if no stksess available. */
1997 if (s)
1998 stkctr = &s->stkctr[rule->arg.gpc.sc];
1999 else
2000 stkctr = &sess->stkctr[rule->arg.gpc.sc];
Willy Tarreau79c1e912016-01-25 14:54:45 +01002001
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002002 ts = stkctr_entry(stkctr);
Willy Tarreau79c1e912016-01-25 14:54:45 +01002003 if (ts) {
2004 void *ptr1, *ptr2;
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002005
Willy Tarreau79c1e912016-01-25 14:54:45 +01002006 /* First, update gpc0_rate if it's tracked. Second, update its gpc0 if tracked. */
2007 ptr1 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC0_RATE);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002008 ptr2 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC0);
2009 if (ptr1 || ptr2) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002010 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002011
2012 if (ptr1)
2013 update_freq_ctr_period(&stktable_data_cast(ptr1, gpc0_rate),
Willy Tarreau79c1e912016-01-25 14:54:45 +01002014 stkctr->table->data_arg[STKTABLE_DT_GPC0_RATE].u, 1);
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002015
Emeric Brun819fc6f2017-06-13 19:37:32 +02002016 if (ptr2)
2017 stktable_data_cast(ptr2, gpc0)++;
Willy Tarreau79c1e912016-01-25 14:54:45 +01002018
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002019 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002020
2021 /* If data was modified, we need to touch to re-schedule sync */
2022 stktable_touch_local(stkctr->table, ts, 0);
2023 }
Willy Tarreau79c1e912016-01-25 14:54:45 +01002024 }
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002025 return ACT_RET_CONT;
2026}
2027
2028/* This function is a common parser for using variables. It understands
2029 * the formats:
2030 *
2031 * sc-inc-gpc0(<stick-table ID>)
2032 *
2033 * It returns 0 if fails and <err> is filled with an error message. Otherwise,
2034 * it returns 1 and the variable <expr> is filled with the pointer to the
2035 * expression to execute.
2036 */
2037static enum act_parse_ret parse_inc_gpc0(const char **args, int *arg, struct proxy *px,
2038 struct act_rule *rule, char **err)
2039{
2040 const char *cmd_name = args[*arg-1];
2041 char *error;
2042
2043 cmd_name += strlen("sc-inc-gpc0");
2044 if (*cmd_name == '\0') {
2045 /* default stick table id. */
2046 rule->arg.gpc.sc = 0;
2047 } else {
2048 /* parse the stick table id. */
2049 if (*cmd_name != '(') {
2050 memprintf(err, "invalid stick table track ID. Expects %s(<Track ID>)", args[*arg-1]);
2051 return ACT_RET_PRS_ERR;
2052 }
2053 cmd_name++; /* jump the '(' */
2054 rule->arg.gpc.sc = strtol(cmd_name, &error, 10); /* Convert stick table id. */
2055 if (*error != ')') {
2056 memprintf(err, "invalid stick table track ID. Expects %s(<Track ID>)", args[*arg-1]);
2057 return ACT_RET_PRS_ERR;
2058 }
2059
Christopher Faulet28436e22019-12-18 10:25:46 +01002060 if (rule->arg.gpc.sc >= MAX_SESS_STKCTR) {
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002061 memprintf(err, "invalid stick table track ID. The max allowed ID is %d",
Christopher Faulet28436e22019-12-18 10:25:46 +01002062 MAX_SESS_STKCTR-1);
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002063 return ACT_RET_PRS_ERR;
2064 }
2065 }
Thierry FOURNIER42148732015-09-02 17:17:33 +02002066 rule->action = ACT_CUSTOM;
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002067 rule->action_ptr = action_inc_gpc0;
2068 return ACT_RET_PRS_OK;
2069}
2070
2071/* Always returns 1. */
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002072static enum act_return action_inc_gpc1(struct act_rule *rule, struct proxy *px,
2073 struct session *sess, struct stream *s, int flags)
2074{
2075 struct stksess *ts;
2076 struct stkctr *stkctr;
2077
2078 /* Extract the stksess, return OK if no stksess available. */
2079 if (s)
2080 stkctr = &s->stkctr[rule->arg.gpc.sc];
2081 else
2082 stkctr = &sess->stkctr[rule->arg.gpc.sc];
2083
2084 ts = stkctr_entry(stkctr);
2085 if (ts) {
2086 void *ptr1, *ptr2;
2087
2088 /* First, update gpc1_rate if it's tracked. Second, update its gpc1 if tracked. */
2089 ptr1 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC1_RATE);
2090 ptr2 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC1);
2091 if (ptr1 || ptr2) {
2092 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
2093
2094 if (ptr1)
2095 update_freq_ctr_period(&stktable_data_cast(ptr1, gpc1_rate),
2096 stkctr->table->data_arg[STKTABLE_DT_GPC1_RATE].u, 1);
2097
2098 if (ptr2)
2099 stktable_data_cast(ptr2, gpc1)++;
2100
2101 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
2102
2103 /* If data was modified, we need to touch to re-schedule sync */
2104 stktable_touch_local(stkctr->table, ts, 0);
2105 }
2106 }
2107 return ACT_RET_CONT;
2108}
2109
2110/* This function is a common parser for using variables. It understands
2111 * the formats:
2112 *
2113 * sc-inc-gpc1(<stick-table ID>)
2114 *
2115 * It returns 0 if fails and <err> is filled with an error message. Otherwise,
2116 * it returns 1 and the variable <expr> is filled with the pointer to the
2117 * expression to execute.
2118 */
2119static enum act_parse_ret parse_inc_gpc1(const char **args, int *arg, struct proxy *px,
2120 struct act_rule *rule, char **err)
2121{
2122 const char *cmd_name = args[*arg-1];
2123 char *error;
2124
2125 cmd_name += strlen("sc-inc-gpc1");
2126 if (*cmd_name == '\0') {
2127 /* default stick table id. */
2128 rule->arg.gpc.sc = 0;
2129 } else {
2130 /* parse the stick table id. */
2131 if (*cmd_name != '(') {
2132 memprintf(err, "invalid stick table track ID. Expects %s(<Track ID>)", args[*arg-1]);
2133 return ACT_RET_PRS_ERR;
2134 }
2135 cmd_name++; /* jump the '(' */
2136 rule->arg.gpc.sc = strtol(cmd_name, &error, 10); /* Convert stick table id. */
2137 if (*error != ')') {
2138 memprintf(err, "invalid stick table track ID. Expects %s(<Track ID>)", args[*arg-1]);
2139 return ACT_RET_PRS_ERR;
2140 }
2141
Christopher Faulet28436e22019-12-18 10:25:46 +01002142 if (rule->arg.gpc.sc >= MAX_SESS_STKCTR) {
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002143 memprintf(err, "invalid stick table track ID. The max allowed ID is %d",
Christopher Faulet28436e22019-12-18 10:25:46 +01002144 MAX_SESS_STKCTR-1);
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002145 return ACT_RET_PRS_ERR;
2146 }
2147 }
2148 rule->action = ACT_CUSTOM;
2149 rule->action_ptr = action_inc_gpc1;
2150 return ACT_RET_PRS_OK;
2151}
2152
2153/* Always returns 1. */
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002154static enum act_return action_set_gpt0(struct act_rule *rule, struct proxy *px,
Willy Tarreau658b85b2015-09-27 10:00:49 +02002155 struct session *sess, struct stream *s, int flags)
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002156{
2157 void *ptr;
2158 struct stksess *ts;
2159 struct stkctr *stkctr;
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002160 unsigned int value = 0;
2161 struct sample *smp;
2162 int smp_opt_dir;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002163
2164 /* Extract the stksess, return OK if no stksess available. */
2165 if (s)
2166 stkctr = &s->stkctr[rule->arg.gpt.sc];
2167 else
2168 stkctr = &sess->stkctr[rule->arg.gpt.sc];
Willy Tarreau79c1e912016-01-25 14:54:45 +01002169
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002170 ts = stkctr_entry(stkctr);
2171 if (!ts)
2172 return ACT_RET_CONT;
2173
2174 /* Store the sample in the required sc, and ignore errors. */
2175 ptr = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPT0);
Willy Tarreau79c1e912016-01-25 14:54:45 +01002176 if (ptr) {
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002177 if (!rule->arg.gpt.expr)
2178 value = (unsigned int)(rule->arg.gpt.value);
2179 else {
2180 switch (rule->from) {
2181 case ACT_F_TCP_REQ_SES: smp_opt_dir = SMP_OPT_DIR_REQ; break;
2182 case ACT_F_TCP_REQ_CNT: smp_opt_dir = SMP_OPT_DIR_REQ; break;
2183 case ACT_F_TCP_RES_CNT: smp_opt_dir = SMP_OPT_DIR_RES; break;
2184 case ACT_F_HTTP_REQ: smp_opt_dir = SMP_OPT_DIR_REQ; break;
2185 case ACT_F_HTTP_RES: smp_opt_dir = SMP_OPT_DIR_RES; break;
2186 default:
2187 send_log(px, LOG_ERR, "stick table: internal error while setting gpt0.");
2188 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))
2189 ha_alert("stick table: internal error while executing setting gpt0.\n");
2190 return ACT_RET_CONT;
2191 }
2192
2193 /* Fetch and cast the expression. */
2194 smp = sample_fetch_as_type(px, sess, s, smp_opt_dir|SMP_OPT_FINAL, rule->arg.gpt.expr, SMP_T_SINT);
2195 if (!smp) {
2196 send_log(px, LOG_WARNING, "stick table: invalid expression or data type while setting gpt0.");
2197 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))
2198 ha_alert("stick table: invalid expression or data type while setting gpt0.\n");
2199 return ACT_RET_CONT;
2200 }
2201 value = (unsigned int)(smp->data.u.sint);
2202 }
2203
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002204 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002205
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002206 stktable_data_cast(ptr, gpt0) = value;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002207
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002208 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002209
2210 stktable_touch_local(stkctr->table, ts, 0);
Willy Tarreau79c1e912016-01-25 14:54:45 +01002211 }
2212
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002213 return ACT_RET_CONT;
2214}
2215
2216/* This function is a common parser for using variables. It understands
2217 * the format:
2218 *
2219 * set-gpt0(<stick-table ID>) <expression>
2220 *
2221 * It returns 0 if fails and <err> is filled with an error message. Otherwise,
2222 * it returns 1 and the variable <expr> is filled with the pointer to the
2223 * expression to execute.
2224 */
2225static enum act_parse_ret parse_set_gpt0(const char **args, int *arg, struct proxy *px,
2226 struct act_rule *rule, char **err)
2227
2228
2229{
2230 const char *cmd_name = args[*arg-1];
2231 char *error;
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002232 int smp_val;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002233
2234 cmd_name += strlen("sc-set-gpt0");
2235 if (*cmd_name == '\0') {
2236 /* default stick table id. */
2237 rule->arg.gpt.sc = 0;
2238 } else {
2239 /* parse the stick table id. */
2240 if (*cmd_name != '(') {
2241 memprintf(err, "invalid stick table track ID '%s'. Expects sc-set-gpt0(<Track ID>)", args[*arg-1]);
2242 return ACT_RET_PRS_ERR;
2243 }
2244 cmd_name++; /* jump the '(' */
2245 rule->arg.gpt.sc = strtol(cmd_name, &error, 10); /* Convert stick table id. */
2246 if (*error != ')') {
2247 memprintf(err, "invalid stick table track ID '%s'. Expects sc-set-gpt0(<Track ID>)", args[*arg-1]);
2248 return ACT_RET_PRS_ERR;
2249 }
2250
Christopher Faulet28436e22019-12-18 10:25:46 +01002251 if (rule->arg.gpt.sc >= MAX_SESS_STKCTR) {
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002252 memprintf(err, "invalid stick table track ID '%s'. The max allowed ID is %d",
Christopher Faulet28436e22019-12-18 10:25:46 +01002253 args[*arg-1], MAX_SESS_STKCTR-1);
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002254 return ACT_RET_PRS_ERR;
2255 }
2256 }
2257
Willy Tarreauf1e1c912021-08-24 14:57:28 +02002258 /* value may be either an integer or an expression */
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002259 rule->arg.gpt.expr = NULL;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002260 rule->arg.gpt.value = strtol(args[*arg], &error, 10);
Willy Tarreauf1e1c912021-08-24 14:57:28 +02002261 if (*error == '\0') {
2262 /* valid integer, skip it */
2263 (*arg)++;
2264 } else {
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002265 rule->arg.gpt.expr = sample_parse_expr((char **)args, arg, px->conf.args.file,
Willy Tarreaue3b57bf2020-02-14 16:50:14 +01002266 px->conf.args.line, err, &px->conf.args, NULL);
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002267 if (!rule->arg.gpt.expr)
2268 return ACT_RET_PRS_ERR;
2269
2270 switch (rule->from) {
2271 case ACT_F_TCP_REQ_SES: smp_val = SMP_VAL_FE_SES_ACC; break;
2272 case ACT_F_TCP_REQ_CNT: smp_val = SMP_VAL_FE_REQ_CNT; break;
2273 case ACT_F_TCP_RES_CNT: smp_val = SMP_VAL_BE_RES_CNT; break;
2274 case ACT_F_HTTP_REQ: smp_val = SMP_VAL_FE_HRQ_HDR; break;
2275 case ACT_F_HTTP_RES: smp_val = SMP_VAL_BE_HRS_HDR; break;
2276 default:
2277 memprintf(err, "internal error, unexpected rule->from=%d, please report this bug!", rule->from);
2278 return ACT_RET_PRS_ERR;
2279 }
2280 if (!(rule->arg.gpt.expr->fetch->val & smp_val)) {
2281 memprintf(err, "fetch method '%s' extracts information from '%s', none of which is available here", args[*arg-1],
2282 sample_src_names(rule->arg.gpt.expr->fetch->use));
2283 free(rule->arg.gpt.expr);
2284 return ACT_RET_PRS_ERR;
2285 }
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002286 }
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002287
Thierry FOURNIER42148732015-09-02 17:17:33 +02002288 rule->action = ACT_CUSTOM;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002289 rule->action_ptr = action_set_gpt0;
2290
2291 return ACT_RET_PRS_OK;
2292}
2293
Willy Tarreau7d562212016-11-25 16:10:05 +01002294/* set temp integer to the number of used entries in the table pointed to by expr.
2295 * Accepts exactly 1 argument of type table.
2296 */
2297static int
2298smp_fetch_table_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
2299{
2300 smp->flags = SMP_F_VOL_TEST;
2301 smp->data.type = SMP_T_SINT;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002302 smp->data.u.sint = args->data.t->current;
Willy Tarreau7d562212016-11-25 16:10:05 +01002303 return 1;
2304}
2305
2306/* set temp integer to the number of free entries in the table pointed to by expr.
2307 * Accepts exactly 1 argument of type table.
2308 */
2309static int
2310smp_fetch_table_avl(const struct arg *args, struct sample *smp, const char *kw, void *private)
2311{
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002312 struct stktable *t;
Willy Tarreau7d562212016-11-25 16:10:05 +01002313
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002314 t = args->data.t;
Willy Tarreau7d562212016-11-25 16:10:05 +01002315 smp->flags = SMP_F_VOL_TEST;
2316 smp->data.type = SMP_T_SINT;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002317 smp->data.u.sint = t->size - t->current;
Willy Tarreau7d562212016-11-25 16:10:05 +01002318 return 1;
2319}
2320
2321/* Returns a pointer to a stkctr depending on the fetch keyword name.
2322 * It is designed to be called as sc[0-9]_* sc_* or src_* exclusively.
2323 * sc[0-9]_* will return a pointer to the respective field in the
2324 * stream <l4>. sc_* requires an UINT argument specifying the stick
2325 * counter number. src_* will fill a locally allocated structure with
2326 * the table and entry corresponding to what is specified with src_*.
2327 * NULL may be returned if the designated stkctr is not tracked. For
2328 * the sc_* and sc[0-9]_* forms, an optional table argument may be
2329 * passed. When present, the currently tracked key is then looked up
2330 * in the specified table instead of the current table. The purpose is
Ilya Shipitsin47d17182020-06-21 21:42:57 +05002331 * to be able to convert multiple values per key (eg: have gpc0 from
Willy Tarreau7d562212016-11-25 16:10:05 +01002332 * multiple tables). <strm> is allowed to be NULL, in which case only
2333 * the session will be consulted.
2334 */
2335struct stkctr *
Emeric Brun819fc6f2017-06-13 19:37:32 +02002336smp_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 +01002337{
Willy Tarreau7d562212016-11-25 16:10:05 +01002338 struct stkctr *stkptr;
2339 struct stksess *stksess;
2340 unsigned int num = kw[2] - '0';
2341 int arg = 0;
2342
2343 if (num == '_' - '0') {
2344 /* sc_* variant, args[0] = ctr# (mandatory) */
2345 num = args[arg++].data.sint;
Willy Tarreau7d562212016-11-25 16:10:05 +01002346 }
2347 else if (num > 9) { /* src_* variant, args[0] = table */
2348 struct stktable_key *key;
2349 struct connection *conn = objt_conn(sess->origin);
2350 struct sample smp;
2351
2352 if (!conn)
2353 return NULL;
2354
Joseph Herlant5662fa42018-11-15 13:43:28 -08002355 /* Fetch source address in a sample. */
Willy Tarreau7d562212016-11-25 16:10:05 +01002356 smp.px = NULL;
2357 smp.sess = sess;
2358 smp.strm = strm;
Amaury Denoyellec460c702021-05-12 10:17:47 +02002359 if (!smp_fetch_src || !smp_fetch_src(empty_arg_list, &smp, "src", NULL))
Willy Tarreau7d562212016-11-25 16:10:05 +01002360 return NULL;
2361
2362 /* Converts into key. */
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002363 key = smp_to_stkey(&smp, args->data.t);
Willy Tarreau7d562212016-11-25 16:10:05 +01002364 if (!key)
2365 return NULL;
2366
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002367 stkctr->table = args->data.t;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002368 stkctr_set_entry(stkctr, stktable_lookup_key(stkctr->table, key));
2369 return stkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002370 }
2371
2372 /* Here, <num> contains the counter number from 0 to 9 for
2373 * the sc[0-9]_ form, or even higher using sc_(num) if needed.
2374 * args[arg] is the first optional argument. We first lookup the
2375 * ctr form the stream, then from the session if it was not there.
Christopher Fauleta9fa88a2019-10-21 10:53:34 +02002376 * But we must be sure the counter does not exceed MAX_SESS_STKCTR.
Willy Tarreau7d562212016-11-25 16:10:05 +01002377 */
Christopher Fauleta9fa88a2019-10-21 10:53:34 +02002378 if (num >= MAX_SESS_STKCTR)
2379 return NULL;
Willy Tarreau7d562212016-11-25 16:10:05 +01002380
2381 if (strm)
2382 stkptr = &strm->stkctr[num];
2383 if (!strm || !stkctr_entry(stkptr)) {
2384 stkptr = &sess->stkctr[num];
2385 if (!stkctr_entry(stkptr))
2386 return NULL;
2387 }
2388
2389 stksess = stkctr_entry(stkptr);
2390 if (!stksess)
2391 return NULL;
2392
2393 if (unlikely(args[arg].type == ARGT_TAB)) {
2394 /* an alternate table was specified, let's look up the same key there */
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002395 stkctr->table = args[arg].data.t;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002396 stkctr_set_entry(stkctr, stktable_lookup(stkctr->table, stksess));
2397 return stkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002398 }
2399 return stkptr;
2400}
2401
2402/* same as smp_fetch_sc_stkctr() but dedicated to src_* and can create
2403 * the entry if it doesn't exist yet. This is needed for a few fetch
2404 * functions which need to create an entry, such as src_inc_gpc* and
2405 * src_clr_gpc*.
2406 */
2407struct stkctr *
Emeric Brun819fc6f2017-06-13 19:37:32 +02002408smp_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 +01002409{
Willy Tarreau7d562212016-11-25 16:10:05 +01002410 struct stktable_key *key;
2411 struct connection *conn = objt_conn(sess->origin);
2412 struct sample smp;
2413
2414 if (strncmp(kw, "src_", 4) != 0)
2415 return NULL;
2416
2417 if (!conn)
2418 return NULL;
2419
Joseph Herlant5662fa42018-11-15 13:43:28 -08002420 /* Fetch source address in a sample. */
Willy Tarreau7d562212016-11-25 16:10:05 +01002421 smp.px = NULL;
2422 smp.sess = sess;
2423 smp.strm = strm;
Amaury Denoyellec460c702021-05-12 10:17:47 +02002424 if (!smp_fetch_src || !smp_fetch_src(empty_arg_list, &smp, "src", NULL))
Willy Tarreau7d562212016-11-25 16:10:05 +01002425 return NULL;
2426
2427 /* Converts into key. */
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002428 key = smp_to_stkey(&smp, args->data.t);
Willy Tarreau7d562212016-11-25 16:10:05 +01002429 if (!key)
2430 return NULL;
2431
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002432 stkctr->table = args->data.t;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002433 stkctr_set_entry(stkctr, stktable_get_entry(stkctr->table, key));
2434 return stkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002435}
2436
2437/* set return a boolean indicating if the requested stream counter is
2438 * currently being tracked or not.
2439 * Supports being called as "sc[0-9]_tracked" only.
2440 */
2441static int
2442smp_fetch_sc_tracked(const struct arg *args, struct sample *smp, const char *kw, void *private)
2443{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002444 struct stkctr tmpstkctr;
2445 struct stkctr *stkctr;
2446
Willy Tarreau7d562212016-11-25 16:10:05 +01002447 smp->flags = SMP_F_VOL_TEST;
2448 smp->data.type = SMP_T_BOOL;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002449 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2450 smp->data.u.sint = !!stkctr;
2451
2452 /* release the ref count */
Dirkjan Bussinkff57f1b2018-09-14 14:31:22 +02002453 if (stkctr == &tmpstkctr)
Emeric Brun819fc6f2017-06-13 19:37:32 +02002454 stktable_release(stkctr->table, stkctr_entry(stkctr));
2455
Willy Tarreau7d562212016-11-25 16:10:05 +01002456 return 1;
2457}
2458
2459/* set <smp> to the General Purpose Flag 0 value from the stream's tracked
2460 * frontend counters or from the src.
2461 * Supports being called as "sc[0-9]_get_gpc0" or "src_get_gpt0" only. Value
2462 * zero is returned if the key is new.
2463 */
2464static int
2465smp_fetch_sc_get_gpt0(const struct arg *args, struct sample *smp, const char *kw, void *private)
2466{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002467 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002468 struct stkctr *stkctr;
2469
Emeric Brun819fc6f2017-06-13 19:37:32 +02002470 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002471 if (!stkctr)
2472 return 0;
2473
2474 smp->flags = SMP_F_VOL_TEST;
2475 smp->data.type = SMP_T_SINT;
2476 smp->data.u.sint = 0;
2477
Emeric Brun819fc6f2017-06-13 19:37:32 +02002478 if (stkctr_entry(stkctr)) {
2479 void *ptr;
2480
2481 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPT0);
2482 if (!ptr) {
2483 if (stkctr == &tmpstkctr)
2484 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002485 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002486 }
2487
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002488 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002489
Willy Tarreau7d562212016-11-25 16:10:05 +01002490 smp->data.u.sint = stktable_data_cast(ptr, gpt0);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002491
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002492 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002493
2494 if (stkctr == &tmpstkctr)
2495 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002496 }
2497 return 1;
2498}
2499
2500/* set <smp> to the General Purpose Counter 0 value from the stream's tracked
2501 * frontend counters or from the src.
2502 * Supports being called as "sc[0-9]_get_gpc0" or "src_get_gpc0" only. Value
2503 * zero is returned if the key is new.
2504 */
2505static int
2506smp_fetch_sc_get_gpc0(const struct arg *args, struct sample *smp, const char *kw, void *private)
2507{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002508 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002509 struct stkctr *stkctr;
2510
Emeric Brun819fc6f2017-06-13 19:37:32 +02002511 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002512 if (!stkctr)
2513 return 0;
2514
2515 smp->flags = SMP_F_VOL_TEST;
2516 smp->data.type = SMP_T_SINT;
2517 smp->data.u.sint = 0;
2518
2519 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002520 void *ptr;
2521
2522 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0);
2523 if (!ptr) {
2524 if (stkctr == &tmpstkctr)
2525 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002526 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002527 }
2528
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002529 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002530
Willy Tarreau7d562212016-11-25 16:10:05 +01002531 smp->data.u.sint = stktable_data_cast(ptr, gpc0);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002532
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002533 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002534
2535 if (stkctr == &tmpstkctr)
2536 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002537 }
2538 return 1;
2539}
2540
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002541/* set <smp> to the General Purpose Counter 1 value from the stream's tracked
2542 * frontend counters or from the src.
2543 * Supports being called as "sc[0-9]_get_gpc1" or "src_get_gpc1" only. Value
2544 * zero is returned if the key is new.
2545 */
2546static int
2547smp_fetch_sc_get_gpc1(const struct arg *args, struct sample *smp, const char *kw, void *private)
2548{
2549 struct stkctr tmpstkctr;
2550 struct stkctr *stkctr;
2551
2552 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2553 if (!stkctr)
2554 return 0;
2555
2556 smp->flags = SMP_F_VOL_TEST;
2557 smp->data.type = SMP_T_SINT;
2558 smp->data.u.sint = 0;
2559
2560 if (stkctr_entry(stkctr) != NULL) {
2561 void *ptr;
2562
2563 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1);
2564 if (!ptr) {
2565 if (stkctr == &tmpstkctr)
2566 stktable_release(stkctr->table, stkctr_entry(stkctr));
2567 return 0; /* parameter not stored */
2568 }
2569
2570 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2571
2572 smp->data.u.sint = stktable_data_cast(ptr, gpc1);
2573
2574 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2575
2576 if (stkctr == &tmpstkctr)
2577 stktable_release(stkctr->table, stkctr_entry(stkctr));
2578 }
2579 return 1;
2580}
2581
Willy Tarreau7d562212016-11-25 16:10:05 +01002582/* set <smp> to the General Purpose Counter 0's event rate from the stream's
2583 * tracked frontend counters or from the src.
2584 * Supports being called as "sc[0-9]_gpc0_rate" or "src_gpc0_rate" only.
2585 * Value zero is returned if the key is new.
2586 */
2587static int
2588smp_fetch_sc_gpc0_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
2589{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002590 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002591 struct stkctr *stkctr;
2592
Emeric Brun819fc6f2017-06-13 19:37:32 +02002593 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002594 if (!stkctr)
2595 return 0;
2596
2597 smp->flags = SMP_F_VOL_TEST;
2598 smp->data.type = SMP_T_SINT;
2599 smp->data.u.sint = 0;
2600 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002601 void *ptr;
2602
2603 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0_RATE);
2604 if (!ptr) {
2605 if (stkctr == &tmpstkctr)
2606 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002607 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002608 }
2609
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002610 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002611
Willy Tarreau7d562212016-11-25 16:10:05 +01002612 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, gpc0_rate),
2613 stkctr->table->data_arg[STKTABLE_DT_GPC0_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002614
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002615 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002616
2617 if (stkctr == &tmpstkctr)
2618 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002619 }
2620 return 1;
2621}
2622
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002623/* set <smp> to the General Purpose Counter 1's event rate from the stream's
2624 * tracked frontend counters or from the src.
2625 * Supports being called as "sc[0-9]_gpc1_rate" or "src_gpc1_rate" only.
2626 * Value zero is returned if the key is new.
2627 */
2628static int
2629smp_fetch_sc_gpc1_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
2630{
2631 struct stkctr tmpstkctr;
2632 struct stkctr *stkctr;
2633
2634 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2635 if (!stkctr)
2636 return 0;
2637
2638 smp->flags = SMP_F_VOL_TEST;
2639 smp->data.type = SMP_T_SINT;
2640 smp->data.u.sint = 0;
2641 if (stkctr_entry(stkctr) != NULL) {
2642 void *ptr;
2643
2644 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1_RATE);
2645 if (!ptr) {
2646 if (stkctr == &tmpstkctr)
2647 stktable_release(stkctr->table, stkctr_entry(stkctr));
2648 return 0; /* parameter not stored */
2649 }
2650
2651 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2652
2653 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, gpc1_rate),
2654 stkctr->table->data_arg[STKTABLE_DT_GPC1_RATE].u);
2655
2656 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2657
2658 if (stkctr == &tmpstkctr)
2659 stktable_release(stkctr->table, stkctr_entry(stkctr));
2660 }
2661 return 1;
2662}
2663
Willy Tarreau7d562212016-11-25 16:10:05 +01002664/* Increment the General Purpose Counter 0 value from the stream's tracked
2665 * frontend counters and return it into temp integer.
2666 * Supports being called as "sc[0-9]_inc_gpc0" or "src_inc_gpc0" only.
2667 */
2668static int
2669smp_fetch_sc_inc_gpc0(const struct arg *args, struct sample *smp, const char *kw, void *private)
2670{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002671 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002672 struct stkctr *stkctr;
2673
Emeric Brun819fc6f2017-06-13 19:37:32 +02002674 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002675 if (!stkctr)
2676 return 0;
2677
2678 smp->flags = SMP_F_VOL_TEST;
2679 smp->data.type = SMP_T_SINT;
2680 smp->data.u.sint = 0;
2681
Emeric Brun819fc6f2017-06-13 19:37:32 +02002682 if (!stkctr_entry(stkctr))
2683 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002684
2685 if (stkctr && stkctr_entry(stkctr)) {
2686 void *ptr1,*ptr2;
2687
Emeric Brun819fc6f2017-06-13 19:37:32 +02002688
Willy Tarreau7d562212016-11-25 16:10:05 +01002689 /* First, update gpc0_rate if it's tracked. Second, update its
2690 * gpc0 if tracked. Returns gpc0's value otherwise the curr_ctr.
2691 */
2692 ptr1 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0_RATE);
Willy Tarreau7d562212016-11-25 16:10:05 +01002693 ptr2 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002694 if (ptr1 || ptr2) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002695 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Willy Tarreau7d562212016-11-25 16:10:05 +01002696
Emeric Brun819fc6f2017-06-13 19:37:32 +02002697 if (ptr1) {
2698 update_freq_ctr_period(&stktable_data_cast(ptr1, gpc0_rate),
2699 stkctr->table->data_arg[STKTABLE_DT_GPC0_RATE].u, 1);
2700 smp->data.u.sint = (&stktable_data_cast(ptr1, gpc0_rate))->curr_ctr;
2701 }
2702
2703 if (ptr2)
2704 smp->data.u.sint = ++stktable_data_cast(ptr2, gpc0);
2705
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002706 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002707
2708 /* If data was modified, we need to touch to re-schedule sync */
2709 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
2710 }
2711 else if (stkctr == &tmpstkctr)
2712 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002713 }
2714 return 1;
2715}
2716
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002717/* Increment the General Purpose Counter 1 value from the stream's tracked
2718 * frontend counters and return it into temp integer.
2719 * Supports being called as "sc[0-9]_inc_gpc1" or "src_inc_gpc1" only.
2720 */
2721static int
2722smp_fetch_sc_inc_gpc1(const struct arg *args, struct sample *smp, const char *kw, void *private)
2723{
2724 struct stkctr tmpstkctr;
2725 struct stkctr *stkctr;
2726
2727 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2728 if (!stkctr)
2729 return 0;
2730
2731 smp->flags = SMP_F_VOL_TEST;
2732 smp->data.type = SMP_T_SINT;
2733 smp->data.u.sint = 0;
2734
2735 if (!stkctr_entry(stkctr))
2736 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2737
2738 if (stkctr && stkctr_entry(stkctr)) {
2739 void *ptr1,*ptr2;
2740
2741
2742 /* First, update gpc1_rate if it's tracked. Second, update its
2743 * gpc1 if tracked. Returns gpc1's value otherwise the curr_ctr.
2744 */
2745 ptr1 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1_RATE);
2746 ptr2 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1);
2747 if (ptr1 || ptr2) {
2748 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2749
2750 if (ptr1) {
2751 update_freq_ctr_period(&stktable_data_cast(ptr1, gpc1_rate),
2752 stkctr->table->data_arg[STKTABLE_DT_GPC1_RATE].u, 1);
2753 smp->data.u.sint = (&stktable_data_cast(ptr1, gpc1_rate))->curr_ctr;
2754 }
2755
2756 if (ptr2)
2757 smp->data.u.sint = ++stktable_data_cast(ptr2, gpc1);
2758
2759 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2760
2761 /* If data was modified, we need to touch to re-schedule sync */
2762 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
2763 }
2764 else if (stkctr == &tmpstkctr)
2765 stktable_release(stkctr->table, stkctr_entry(stkctr));
2766 }
2767 return 1;
2768}
2769
Willy Tarreau7d562212016-11-25 16:10:05 +01002770/* Clear the General Purpose Counter 0 value from the stream's tracked
2771 * frontend counters and return its previous value into temp integer.
2772 * Supports being called as "sc[0-9]_clr_gpc0" or "src_clr_gpc0" only.
2773 */
2774static int
2775smp_fetch_sc_clr_gpc0(const struct arg *args, struct sample *smp, const char *kw, void *private)
2776{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002777 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002778 struct stkctr *stkctr;
2779
Emeric Brun819fc6f2017-06-13 19:37:32 +02002780 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002781 if (!stkctr)
2782 return 0;
2783
2784 smp->flags = SMP_F_VOL_TEST;
2785 smp->data.type = SMP_T_SINT;
2786 smp->data.u.sint = 0;
2787
Emeric Brun819fc6f2017-06-13 19:37:32 +02002788 if (!stkctr_entry(stkctr))
2789 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002790
Emeric Brun819fc6f2017-06-13 19:37:32 +02002791 if (stkctr && stkctr_entry(stkctr)) {
2792 void *ptr;
2793
2794 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0);
2795 if (!ptr) {
2796 if (stkctr == &tmpstkctr)
2797 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002798 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002799 }
2800
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002801 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002802
Willy Tarreau7d562212016-11-25 16:10:05 +01002803 smp->data.u.sint = stktable_data_cast(ptr, gpc0);
2804 stktable_data_cast(ptr, gpc0) = 0;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002805
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002806 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002807
Willy Tarreau7d562212016-11-25 16:10:05 +01002808 /* If data was modified, we need to touch to re-schedule sync */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002809 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
Willy Tarreau7d562212016-11-25 16:10:05 +01002810 }
2811 return 1;
2812}
2813
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002814/* Clear the General Purpose Counter 1 value from the stream's tracked
2815 * frontend counters and return its previous value into temp integer.
2816 * Supports being called as "sc[0-9]_clr_gpc1" or "src_clr_gpc1" only.
2817 */
2818static int
2819smp_fetch_sc_clr_gpc1(const struct arg *args, struct sample *smp, const char *kw, void *private)
2820{
2821 struct stkctr tmpstkctr;
2822 struct stkctr *stkctr;
2823
2824 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2825 if (!stkctr)
2826 return 0;
2827
2828 smp->flags = SMP_F_VOL_TEST;
2829 smp->data.type = SMP_T_SINT;
2830 smp->data.u.sint = 0;
2831
2832 if (!stkctr_entry(stkctr))
2833 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2834
2835 if (stkctr && stkctr_entry(stkctr)) {
2836 void *ptr;
2837
2838 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1);
2839 if (!ptr) {
2840 if (stkctr == &tmpstkctr)
2841 stktable_release(stkctr->table, stkctr_entry(stkctr));
2842 return 0; /* parameter not stored */
2843 }
2844
2845 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2846
2847 smp->data.u.sint = stktable_data_cast(ptr, gpc1);
2848 stktable_data_cast(ptr, gpc1) = 0;
2849
2850 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2851
2852 /* If data was modified, we need to touch to re-schedule sync */
2853 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
2854 }
2855 return 1;
2856}
2857
Willy Tarreau7d562212016-11-25 16:10:05 +01002858/* set <smp> to the cumulated number of connections from the stream's tracked
2859 * frontend counters. Supports being called as "sc[0-9]_conn_cnt" or
2860 * "src_conn_cnt" only.
2861 */
2862static int
2863smp_fetch_sc_conn_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
2864{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002865 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002866 struct stkctr *stkctr;
2867
Emeric Brun819fc6f2017-06-13 19:37:32 +02002868 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002869 if (!stkctr)
2870 return 0;
2871
2872 smp->flags = SMP_F_VOL_TEST;
2873 smp->data.type = SMP_T_SINT;
2874 smp->data.u.sint = 0;
2875 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002876 void *ptr;
2877
2878 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_CONN_CNT);
2879 if (!ptr) {
2880 if (stkctr == &tmpstkctr)
2881 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002882 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002883 }
2884
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002885 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002886
Willy Tarreau7d562212016-11-25 16:10:05 +01002887 smp->data.u.sint = stktable_data_cast(ptr, conn_cnt);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002888
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002889 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002890
2891 if (stkctr == &tmpstkctr)
2892 stktable_release(stkctr->table, stkctr_entry(stkctr));
2893
2894
Willy Tarreau7d562212016-11-25 16:10:05 +01002895 }
2896 return 1;
2897}
2898
2899/* set <smp> to the connection rate from the stream's tracked frontend
2900 * counters. Supports being called as "sc[0-9]_conn_rate" or "src_conn_rate"
2901 * only.
2902 */
2903static int
2904smp_fetch_sc_conn_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
2905{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002906 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002907 struct stkctr *stkctr;
2908
Emeric Brun819fc6f2017-06-13 19:37:32 +02002909 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002910 if (!stkctr)
2911 return 0;
2912
2913 smp->flags = SMP_F_VOL_TEST;
2914 smp->data.type = SMP_T_SINT;
2915 smp->data.u.sint = 0;
2916 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002917 void *ptr;
2918
2919 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_CONN_RATE);
2920 if (!ptr) {
2921 if (stkctr == &tmpstkctr)
2922 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002923 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002924 }
2925
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002926 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002927
Willy Tarreau7d562212016-11-25 16:10:05 +01002928 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, conn_rate),
2929 stkctr->table->data_arg[STKTABLE_DT_CONN_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002930
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002931 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002932
2933 if (stkctr == &tmpstkctr)
2934 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002935 }
2936 return 1;
2937}
2938
2939/* set temp integer to the number of connections from the stream's source address
2940 * in the table pointed to by expr, after updating it.
2941 * Accepts exactly 1 argument of type table.
2942 */
2943static int
2944smp_fetch_src_updt_conn_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
2945{
2946 struct connection *conn = objt_conn(smp->sess->origin);
2947 struct stksess *ts;
2948 struct stktable_key *key;
2949 void *ptr;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002950 struct stktable *t;
Willy Tarreau7d562212016-11-25 16:10:05 +01002951
2952 if (!conn)
2953 return 0;
2954
Joseph Herlant5662fa42018-11-15 13:43:28 -08002955 /* Fetch source address in a sample. */
Amaury Denoyellec460c702021-05-12 10:17:47 +02002956 if (!smp_fetch_src || !smp_fetch_src(empty_arg_list, smp, "src", NULL))
Willy Tarreau7d562212016-11-25 16:10:05 +01002957 return 0;
2958
2959 /* Converts into key. */
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002960 key = smp_to_stkey(smp, args->data.t);
Willy Tarreau7d562212016-11-25 16:10:05 +01002961 if (!key)
2962 return 0;
2963
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002964 t = args->data.t;
Willy Tarreau7d562212016-11-25 16:10:05 +01002965
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002966 if ((ts = stktable_get_entry(t, key)) == NULL)
Willy Tarreau7d562212016-11-25 16:10:05 +01002967 /* entry does not exist and could not be created */
2968 return 0;
2969
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002970 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_CONN_CNT);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002971 if (!ptr) {
Willy Tarreau7d562212016-11-25 16:10:05 +01002972 return 0; /* parameter not stored in this table */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002973 }
Willy Tarreau7d562212016-11-25 16:10:05 +01002974
2975 smp->data.type = SMP_T_SINT;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002976
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002977 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002978
Willy Tarreau7d562212016-11-25 16:10:05 +01002979 smp->data.u.sint = ++stktable_data_cast(ptr, conn_cnt);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002980
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002981 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002982
Willy Tarreau7d562212016-11-25 16:10:05 +01002983 smp->flags = SMP_F_VOL_TEST;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002984
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002985 stktable_touch_local(t, ts, 1);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002986
2987 /* Touch was previously performed by stktable_update_key */
Willy Tarreau7d562212016-11-25 16:10:05 +01002988 return 1;
2989}
2990
2991/* set <smp> to the number of concurrent connections from the stream's tracked
2992 * frontend counters. Supports being called as "sc[0-9]_conn_cur" or
2993 * "src_conn_cur" only.
2994 */
2995static int
2996smp_fetch_sc_conn_cur(const struct arg *args, struct sample *smp, const char *kw, void *private)
2997{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002998 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002999 struct stkctr *stkctr;
3000
Emeric Brun819fc6f2017-06-13 19:37:32 +02003001 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003002 if (!stkctr)
3003 return 0;
3004
3005 smp->flags = SMP_F_VOL_TEST;
3006 smp->data.type = SMP_T_SINT;
3007 smp->data.u.sint = 0;
3008 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003009 void *ptr;
3010
3011 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_CONN_CUR);
3012 if (!ptr) {
3013 if (stkctr == &tmpstkctr)
3014 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003015 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003016 }
3017
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003018 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003019
Willy Tarreau7d562212016-11-25 16:10:05 +01003020 smp->data.u.sint = stktable_data_cast(ptr, conn_cur);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003021
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003022 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003023
3024 if (stkctr == &tmpstkctr)
3025 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003026 }
3027 return 1;
3028}
3029
3030/* set <smp> to the cumulated number of streams from the stream's tracked
3031 * frontend counters. Supports being called as "sc[0-9]_sess_cnt" or
3032 * "src_sess_cnt" only.
3033 */
3034static int
3035smp_fetch_sc_sess_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
3036{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003037 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003038 struct stkctr *stkctr;
3039
Emeric Brun819fc6f2017-06-13 19:37:32 +02003040 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003041 if (!stkctr)
3042 return 0;
3043
3044 smp->flags = SMP_F_VOL_TEST;
3045 smp->data.type = SMP_T_SINT;
3046 smp->data.u.sint = 0;
3047 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003048 void *ptr;
3049
3050 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_SESS_CNT);
3051 if (!ptr) {
3052 if (stkctr == &tmpstkctr)
3053 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003054 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003055 }
3056
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003057 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003058
Willy Tarreau7d562212016-11-25 16:10:05 +01003059 smp->data.u.sint = stktable_data_cast(ptr, sess_cnt);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003060
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003061 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003062
3063 if (stkctr == &tmpstkctr)
3064 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003065 }
3066 return 1;
3067}
3068
3069/* set <smp> to the stream rate from the stream's tracked frontend counters.
3070 * Supports being called as "sc[0-9]_sess_rate" or "src_sess_rate" only.
3071 */
3072static int
3073smp_fetch_sc_sess_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3074{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003075 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003076 struct stkctr *stkctr;
3077
Emeric Brun819fc6f2017-06-13 19:37:32 +02003078 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003079 if (!stkctr)
3080 return 0;
3081
3082 smp->flags = SMP_F_VOL_TEST;
3083 smp->data.type = SMP_T_SINT;
3084 smp->data.u.sint = 0;
3085 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003086 void *ptr;
3087
3088 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_SESS_RATE);
3089 if (!ptr) {
3090 if (stkctr == &tmpstkctr)
3091 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003092 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003093 }
3094
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003095 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003096
Willy Tarreau7d562212016-11-25 16:10:05 +01003097 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, sess_rate),
3098 stkctr->table->data_arg[STKTABLE_DT_SESS_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003099
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003100 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003101
3102 if (stkctr == &tmpstkctr)
3103 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003104 }
3105 return 1;
3106}
3107
3108/* set <smp> to the cumulated number of HTTP requests from the stream's tracked
3109 * frontend counters. Supports being called as "sc[0-9]_http_req_cnt" or
3110 * "src_http_req_cnt" only.
3111 */
3112static int
3113smp_fetch_sc_http_req_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
3114{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003115 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003116 struct stkctr *stkctr;
3117
Emeric Brun819fc6f2017-06-13 19:37:32 +02003118 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003119 if (!stkctr)
3120 return 0;
3121
3122 smp->flags = SMP_F_VOL_TEST;
3123 smp->data.type = SMP_T_SINT;
3124 smp->data.u.sint = 0;
3125 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003126 void *ptr;
3127
3128 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_REQ_CNT);
3129 if (!ptr) {
3130 if (stkctr == &tmpstkctr)
3131 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003132 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003133 }
3134
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003135 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003136
Willy Tarreau7d562212016-11-25 16:10:05 +01003137 smp->data.u.sint = stktable_data_cast(ptr, http_req_cnt);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003138
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003139 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003140
3141 if (stkctr == &tmpstkctr)
3142 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003143 }
3144 return 1;
3145}
3146
3147/* set <smp> to the HTTP request rate from the stream's tracked frontend
3148 * counters. Supports being called as "sc[0-9]_http_req_rate" or
3149 * "src_http_req_rate" only.
3150 */
3151static int
3152smp_fetch_sc_http_req_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3153{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003154 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003155 struct stkctr *stkctr;
3156
Emeric Brun819fc6f2017-06-13 19:37:32 +02003157 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003158 if (!stkctr)
3159 return 0;
3160
3161 smp->flags = SMP_F_VOL_TEST;
3162 smp->data.type = SMP_T_SINT;
3163 smp->data.u.sint = 0;
3164 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003165 void *ptr;
3166
3167 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_REQ_RATE);
3168 if (!ptr) {
3169 if (stkctr == &tmpstkctr)
3170 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003171 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003172 }
3173
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003174 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003175
Willy Tarreau7d562212016-11-25 16:10:05 +01003176 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, http_req_rate),
3177 stkctr->table->data_arg[STKTABLE_DT_HTTP_REQ_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003178
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003179 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003180
3181 if (stkctr == &tmpstkctr)
3182 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003183 }
3184 return 1;
3185}
3186
3187/* set <smp> to the cumulated number of HTTP requests errors from the stream's
3188 * tracked frontend counters. Supports being called as "sc[0-9]_http_err_cnt" or
3189 * "src_http_err_cnt" only.
3190 */
3191static int
3192smp_fetch_sc_http_err_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
3193{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003194 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003195 struct stkctr *stkctr;
3196
Emeric Brun819fc6f2017-06-13 19:37:32 +02003197 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003198 if (!stkctr)
3199 return 0;
3200
3201 smp->flags = SMP_F_VOL_TEST;
3202 smp->data.type = SMP_T_SINT;
3203 smp->data.u.sint = 0;
3204 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003205 void *ptr;
3206
3207 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_ERR_CNT);
3208 if (!ptr) {
3209 if (stkctr == &tmpstkctr)
3210 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003211 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003212 }
3213
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003214 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003215
Willy Tarreau7d562212016-11-25 16:10:05 +01003216 smp->data.u.sint = stktable_data_cast(ptr, http_err_cnt);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003217
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003218 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003219
3220 if (stkctr == &tmpstkctr)
3221 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003222 }
3223 return 1;
3224}
3225
3226/* set <smp> to the HTTP request error rate from the stream's tracked frontend
3227 * counters. Supports being called as "sc[0-9]_http_err_rate" or
3228 * "src_http_err_rate" only.
3229 */
3230static int
3231smp_fetch_sc_http_err_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3232{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003233 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003234 struct stkctr *stkctr;
3235
Emeric Brun819fc6f2017-06-13 19:37:32 +02003236 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003237 if (!stkctr)
3238 return 0;
3239
3240 smp->flags = SMP_F_VOL_TEST;
3241 smp->data.type = SMP_T_SINT;
3242 smp->data.u.sint = 0;
3243 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003244 void *ptr;
3245
3246 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_ERR_RATE);
3247 if (!ptr) {
3248 if (stkctr == &tmpstkctr)
3249 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003250 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003251 }
3252
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003253 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003254
Willy Tarreau7d562212016-11-25 16:10:05 +01003255 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, http_err_rate),
3256 stkctr->table->data_arg[STKTABLE_DT_HTTP_ERR_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003257
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003258 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003259
3260 if (stkctr == &tmpstkctr)
3261 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003262 }
3263 return 1;
3264}
3265
Willy Tarreau826f3ab2021-02-10 12:07:15 +01003266/* set <smp> to the cumulated number of HTTP response failures from the stream's
3267 * tracked frontend counters. Supports being called as "sc[0-9]_http_fail_cnt" or
3268 * "src_http_fail_cnt" only.
3269 */
3270static int
3271smp_fetch_sc_http_fail_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
3272{
3273 struct stkctr tmpstkctr;
3274 struct stkctr *stkctr;
3275
3276 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
3277 if (!stkctr)
3278 return 0;
3279
3280 smp->flags = SMP_F_VOL_TEST;
3281 smp->data.type = SMP_T_SINT;
3282 smp->data.u.sint = 0;
3283 if (stkctr_entry(stkctr) != NULL) {
3284 void *ptr;
3285
3286 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_FAIL_CNT);
3287 if (!ptr) {
3288 if (stkctr == &tmpstkctr)
3289 stktable_release(stkctr->table, stkctr_entry(stkctr));
3290 return 0; /* parameter not stored */
3291 }
3292
3293 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3294
3295 smp->data.u.sint = stktable_data_cast(ptr, http_fail_cnt);
3296
3297 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3298
3299 if (stkctr == &tmpstkctr)
3300 stktable_release(stkctr->table, stkctr_entry(stkctr));
3301 }
3302 return 1;
3303}
3304
3305/* set <smp> to the HTTP response failure rate from the stream's tracked frontend
3306 * counters. Supports being called as "sc[0-9]_http_fail_rate" or
3307 * "src_http_fail_rate" only.
3308 */
3309static int
3310smp_fetch_sc_http_fail_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3311{
3312 struct stkctr tmpstkctr;
3313 struct stkctr *stkctr;
3314
3315 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
3316 if (!stkctr)
3317 return 0;
3318
3319 smp->flags = SMP_F_VOL_TEST;
3320 smp->data.type = SMP_T_SINT;
3321 smp->data.u.sint = 0;
3322 if (stkctr_entry(stkctr) != NULL) {
3323 void *ptr;
3324
3325 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_FAIL_RATE);
3326 if (!ptr) {
3327 if (stkctr == &tmpstkctr)
3328 stktable_release(stkctr->table, stkctr_entry(stkctr));
3329 return 0; /* parameter not stored */
3330 }
3331
3332 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3333
3334 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, http_fail_rate),
3335 stkctr->table->data_arg[STKTABLE_DT_HTTP_FAIL_RATE].u);
3336
3337 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3338
3339 if (stkctr == &tmpstkctr)
3340 stktable_release(stkctr->table, stkctr_entry(stkctr));
3341 }
3342 return 1;
3343}
3344
Willy Tarreau7d562212016-11-25 16:10:05 +01003345/* set <smp> to the number of kbytes received from clients, as found in the
3346 * stream's tracked frontend counters. Supports being called as
3347 * "sc[0-9]_kbytes_in" or "src_kbytes_in" only.
3348 */
3349static int
3350smp_fetch_sc_kbytes_in(const struct arg *args, struct sample *smp, const char *kw, void *private)
3351{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003352 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003353 struct stkctr *stkctr;
3354
Emeric Brun819fc6f2017-06-13 19:37:32 +02003355 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003356 if (!stkctr)
3357 return 0;
3358
3359 smp->flags = SMP_F_VOL_TEST;
3360 smp->data.type = SMP_T_SINT;
3361 smp->data.u.sint = 0;
3362 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003363 void *ptr;
3364
3365 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_IN_CNT);
3366 if (!ptr) {
3367 if (stkctr == &tmpstkctr)
3368 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003369 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003370 }
3371
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003372 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003373
Willy Tarreau7d562212016-11-25 16:10:05 +01003374 smp->data.u.sint = stktable_data_cast(ptr, bytes_in_cnt) >> 10;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003375
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003376 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003377
3378 if (stkctr == &tmpstkctr)
3379 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003380 }
3381 return 1;
3382}
3383
3384/* set <smp> to the data rate received from clients in bytes/s, as found
3385 * in the stream's tracked frontend counters. Supports being called as
3386 * "sc[0-9]_bytes_in_rate" or "src_bytes_in_rate" only.
3387 */
3388static int
3389smp_fetch_sc_bytes_in_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3390{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003391 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003392 struct stkctr *stkctr;
3393
Emeric Brun819fc6f2017-06-13 19:37:32 +02003394 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003395 if (!stkctr)
3396 return 0;
3397
3398 smp->flags = SMP_F_VOL_TEST;
3399 smp->data.type = SMP_T_SINT;
3400 smp->data.u.sint = 0;
3401 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003402 void *ptr;
3403
3404 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_IN_RATE);
3405 if (!ptr) {
3406 if (stkctr == &tmpstkctr)
3407 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003408 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003409 }
3410
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003411 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003412
Willy Tarreau7d562212016-11-25 16:10:05 +01003413 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, bytes_in_rate),
3414 stkctr->table->data_arg[STKTABLE_DT_BYTES_IN_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003415
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003416 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003417
3418 if (stkctr == &tmpstkctr)
3419 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003420 }
3421 return 1;
3422}
3423
3424/* set <smp> to the number of kbytes sent to clients, as found in the
3425 * stream's tracked frontend counters. Supports being called as
3426 * "sc[0-9]_kbytes_out" or "src_kbytes_out" only.
3427 */
3428static int
3429smp_fetch_sc_kbytes_out(const struct arg *args, struct sample *smp, const char *kw, void *private)
3430{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003431 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003432 struct stkctr *stkctr;
3433
Emeric Brun819fc6f2017-06-13 19:37:32 +02003434 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003435 if (!stkctr)
3436 return 0;
3437
3438 smp->flags = SMP_F_VOL_TEST;
3439 smp->data.type = SMP_T_SINT;
3440 smp->data.u.sint = 0;
3441 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003442 void *ptr;
3443
3444 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_OUT_CNT);
3445 if (!ptr) {
3446 if (stkctr == &tmpstkctr)
3447 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003448 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003449 }
3450
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003451 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003452
Willy Tarreau7d562212016-11-25 16:10:05 +01003453 smp->data.u.sint = stktable_data_cast(ptr, bytes_out_cnt) >> 10;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003454
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003455 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003456
3457 if (stkctr == &tmpstkctr)
3458 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003459 }
3460 return 1;
3461}
3462
3463/* set <smp> to the data rate sent to clients in bytes/s, as found in the
3464 * stream's tracked frontend counters. Supports being called as
3465 * "sc[0-9]_bytes_out_rate" or "src_bytes_out_rate" only.
3466 */
3467static int
3468smp_fetch_sc_bytes_out_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3469{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003470 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003471 struct stkctr *stkctr;
3472
Emeric Brun819fc6f2017-06-13 19:37:32 +02003473 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003474 if (!stkctr)
3475 return 0;
3476
3477 smp->flags = SMP_F_VOL_TEST;
3478 smp->data.type = SMP_T_SINT;
3479 smp->data.u.sint = 0;
3480 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003481 void *ptr;
3482
3483 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_OUT_RATE);
3484 if (!ptr) {
3485 if (stkctr == &tmpstkctr)
3486 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003487 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003488 }
3489
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003490 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003491
Willy Tarreau7d562212016-11-25 16:10:05 +01003492 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, bytes_out_rate),
3493 stkctr->table->data_arg[STKTABLE_DT_BYTES_OUT_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003494
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003495 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003496
3497 if (stkctr == &tmpstkctr)
3498 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003499 }
3500 return 1;
3501}
3502
3503/* set <smp> to the number of active trackers on the SC entry in the stream's
3504 * tracked frontend counters. Supports being called as "sc[0-9]_trackers" only.
3505 */
3506static int
3507smp_fetch_sc_trackers(const struct arg *args, struct sample *smp, const char *kw, void *private)
3508{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003509 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003510 struct stkctr *stkctr;
3511
Emeric Brun819fc6f2017-06-13 19:37:32 +02003512 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003513 if (!stkctr)
3514 return 0;
3515
3516 smp->flags = SMP_F_VOL_TEST;
3517 smp->data.type = SMP_T_SINT;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003518 if (stkctr == &tmpstkctr) {
3519 smp->data.u.sint = stkctr_entry(stkctr) ? (stkctr_entry(stkctr)->ref_cnt-1) : 0;
3520 stktable_release(stkctr->table, stkctr_entry(stkctr));
3521 }
3522 else {
3523 smp->data.u.sint = stkctr_entry(stkctr) ? stkctr_entry(stkctr)->ref_cnt : 0;
3524 }
3525
Willy Tarreau7d562212016-11-25 16:10:05 +01003526 return 1;
3527}
3528
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003529
3530/* The functions below are used to manipulate table contents from the CLI.
3531 * There are 3 main actions, "clear", "set" and "show". The code is shared
3532 * between all actions, and the action is encoded in the void *private in
3533 * the appctx as well as in the keyword registration, among one of the
3534 * following values.
3535 */
3536
3537enum {
3538 STK_CLI_ACT_CLR,
3539 STK_CLI_ACT_SET,
3540 STK_CLI_ACT_SHOW,
3541};
3542
3543/* Dump the status of a table to a stream interface's
3544 * read buffer. It returns 0 if the output buffer is full
3545 * and needs to be called again, otherwise non-zero.
3546 */
Willy Tarreau83061a82018-07-13 11:56:34 +02003547static int table_dump_head_to_buffer(struct buffer *msg,
3548 struct stream_interface *si,
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003549 struct stktable *t, struct stktable *target)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003550{
3551 struct stream *s = si_strm(si);
3552
3553 chunk_appendf(msg, "# table: %s, type: %s, size:%d, used:%d\n",
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003554 t->id, stktable_types[t->type].kw, t->size, t->current);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003555
3556 /* any other information should be dumped here */
3557
William Lallemand07a62f72017-05-24 00:57:40 +02003558 if (target && (strm_li(s)->bind_conf->level & ACCESS_LVL_MASK) < ACCESS_LVL_OPER)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003559 chunk_appendf(msg, "# contents not dumped due to insufficient privileges\n");
3560
Willy Tarreau06d80a92017-10-19 14:32:15 +02003561 if (ci_putchk(si_ic(si), msg) == -1) {
Willy Tarreaudb398432018-11-15 11:08:52 +01003562 si_rx_room_blk(si);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003563 return 0;
3564 }
3565
3566 return 1;
3567}
3568
3569/* Dump a table entry to a stream interface's
3570 * read buffer. It returns 0 if the output buffer is full
3571 * and needs to be called again, otherwise non-zero.
3572 */
Willy Tarreau83061a82018-07-13 11:56:34 +02003573static int table_dump_entry_to_buffer(struct buffer *msg,
3574 struct stream_interface *si,
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003575 struct stktable *t, struct stksess *entry)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003576{
3577 int dt;
3578
3579 chunk_appendf(msg, "%p:", entry);
3580
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003581 if (t->type == SMP_T_IPV4) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003582 char addr[INET_ADDRSTRLEN];
3583 inet_ntop(AF_INET, (const void *)&entry->key.key, addr, sizeof(addr));
3584 chunk_appendf(msg, " key=%s", addr);
3585 }
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003586 else if (t->type == SMP_T_IPV6) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003587 char addr[INET6_ADDRSTRLEN];
3588 inet_ntop(AF_INET6, (const void *)&entry->key.key, addr, sizeof(addr));
3589 chunk_appendf(msg, " key=%s", addr);
3590 }
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003591 else if (t->type == SMP_T_SINT) {
Willy Tarreau6cde5d82020-02-25 09:41:22 +01003592 chunk_appendf(msg, " key=%u", read_u32(entry->key.key));
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003593 }
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003594 else if (t->type == SMP_T_STR) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003595 chunk_appendf(msg, " key=");
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003596 dump_text(msg, (const char *)entry->key.key, t->key_size);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003597 }
3598 else {
3599 chunk_appendf(msg, " key=");
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003600 dump_binary(msg, (const char *)entry->key.key, t->key_size);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003601 }
3602
3603 chunk_appendf(msg, " use=%d exp=%d", entry->ref_cnt - 1, tick_remain(now_ms, entry->expire));
3604
3605 for (dt = 0; dt < STKTABLE_DATA_TYPES; dt++) {
3606 void *ptr;
3607
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003608 if (t->data_ofs[dt] == 0)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003609 continue;
3610 if (stktable_data_types[dt].arg_type == ARG_T_DELAY)
Emeric Brunc24b4142021-06-30 16:24:04 +02003611 chunk_appendf(msg, " %s(%u)=", stktable_data_types[dt].name, t->data_arg[dt].u);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003612 else
3613 chunk_appendf(msg, " %s=", stktable_data_types[dt].name);
3614
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003615 ptr = stktable_data_ptr(t, entry, dt);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003616 switch (stktable_data_types[dt].std_type) {
3617 case STD_T_SINT:
3618 chunk_appendf(msg, "%d", stktable_data_cast(ptr, std_t_sint));
3619 break;
3620 case STD_T_UINT:
3621 chunk_appendf(msg, "%u", stktable_data_cast(ptr, std_t_uint));
3622 break;
3623 case STD_T_ULL:
Emeric Brunc24b4142021-06-30 16:24:04 +02003624 chunk_appendf(msg, "%llu", stktable_data_cast(ptr, std_t_ull));
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003625 break;
3626 case STD_T_FRQP:
Emeric Brunc24b4142021-06-30 16:24:04 +02003627 chunk_appendf(msg, "%u",
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003628 read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003629 t->data_arg[dt].u));
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003630 break;
Frédéric Lécaille16b4f542019-05-23 12:15:04 +02003631 case STD_T_DICT: {
3632 struct dict_entry *de;
3633 de = stktable_data_cast(ptr, std_t_dict);
3634 chunk_appendf(msg, "%s", de ? (char *)de->value.key : "-");
3635 break;
3636 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003637 }
3638 }
3639 chunk_appendf(msg, "\n");
3640
Willy Tarreau06d80a92017-10-19 14:32:15 +02003641 if (ci_putchk(si_ic(si), msg) == -1) {
Willy Tarreaudb398432018-11-15 11:08:52 +01003642 si_rx_room_blk(si);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003643 return 0;
3644 }
3645
3646 return 1;
3647}
3648
3649
3650/* Processes a single table entry matching a specific key passed in argument.
3651 * returns 0 if wants to be called again, 1 if has ended processing.
3652 */
3653static int table_process_entry_per_key(struct appctx *appctx, char **args)
3654{
3655 struct stream_interface *si = appctx->owner;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003656 struct stktable *t = appctx->ctx.table.target;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003657 struct stksess *ts;
3658 uint32_t uint32_key;
3659 unsigned char ip6_key[sizeof(struct in6_addr)];
3660 long long value;
3661 int data_type;
3662 int cur_arg;
3663 void *ptr;
Willy Tarreaufa1258f2021-04-10 23:00:53 +02003664 struct freq_ctr *frqp;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003665
Willy Tarreau9d008692019-08-09 11:21:01 +02003666 if (!*args[4])
3667 return cli_err(appctx, "Key value expected\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003668
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003669 switch (t->type) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003670 case SMP_T_IPV4:
3671 uint32_key = htonl(inetaddr_host(args[4]));
Christopher Fauletca20d022017-08-29 15:30:31 +02003672 static_table_key.key = &uint32_key;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003673 break;
3674 case SMP_T_IPV6:
Christopher Faulet1e850b52021-11-15 09:17:25 +01003675 if (inet_pton(AF_INET6, args[4], ip6_key) <= 0)
3676 return cli_err(appctx, "Invalid key\n");
Christopher Fauletca20d022017-08-29 15:30:31 +02003677 static_table_key.key = &ip6_key;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003678 break;
3679 case SMP_T_SINT:
3680 {
3681 char *endptr;
3682 unsigned long val;
3683 errno = 0;
3684 val = strtoul(args[4], &endptr, 10);
3685 if ((errno == ERANGE && val == ULONG_MAX) ||
3686 (errno != 0 && val == 0) || endptr == args[4] ||
Willy Tarreau9d008692019-08-09 11:21:01 +02003687 val > 0xffffffff)
3688 return cli_err(appctx, "Invalid key\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003689 uint32_key = (uint32_t) val;
Christopher Fauletca20d022017-08-29 15:30:31 +02003690 static_table_key.key = &uint32_key;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003691 break;
3692 }
3693 break;
3694 case SMP_T_STR:
Christopher Fauletca20d022017-08-29 15:30:31 +02003695 static_table_key.key = args[4];
3696 static_table_key.key_len = strlen(args[4]);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003697 break;
3698 default:
Willy Tarreaua24bc782016-12-14 15:50:35 +01003699 switch (appctx->ctx.table.action) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003700 case STK_CLI_ACT_SHOW:
Willy Tarreau9d008692019-08-09 11:21:01 +02003701 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 +01003702 case STK_CLI_ACT_CLR:
Willy Tarreau9d008692019-08-09 11:21:01 +02003703 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 +01003704 case STK_CLI_ACT_SET:
Willy Tarreau9d008692019-08-09 11:21:01 +02003705 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 +01003706 default:
Willy Tarreau9d008692019-08-09 11:21:01 +02003707 return cli_err(appctx, "Unknown action\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003708 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003709 }
3710
3711 /* check permissions */
3712 if (!cli_has_level(appctx, ACCESS_LVL_OPER))
3713 return 1;
3714
Willy Tarreaua24bc782016-12-14 15:50:35 +01003715 switch (appctx->ctx.table.action) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003716 case STK_CLI_ACT_SHOW:
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003717 ts = stktable_lookup_key(t, &static_table_key);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003718 if (!ts)
3719 return 1;
3720 chunk_reset(&trash);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003721 if (!table_dump_head_to_buffer(&trash, si, t, t)) {
3722 stktable_release(t, ts);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003723 return 0;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003724 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003725 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003726 if (!table_dump_entry_to_buffer(&trash, si, t, ts)) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003727 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003728 stktable_release(t, ts);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003729 return 0;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003730 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003731 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003732 stktable_release(t, ts);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003733 break;
3734
3735 case STK_CLI_ACT_CLR:
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003736 ts = stktable_lookup_key(t, &static_table_key);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003737 if (!ts)
3738 return 1;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003739
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003740 if (!stksess_kill(t, ts, 1)) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003741 /* don't delete an entry which is currently referenced */
Willy Tarreau9d008692019-08-09 11:21:01 +02003742 return cli_err(appctx, "Entry currently in use, cannot remove\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003743 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003744 break;
3745
3746 case STK_CLI_ACT_SET:
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003747 ts = stktable_get_entry(t, &static_table_key);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003748 if (!ts) {
3749 /* don't delete an entry which is currently referenced */
Willy Tarreau9d008692019-08-09 11:21:01 +02003750 return cli_err(appctx, "Unable to allocate a new entry\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003751 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003752 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003753 for (cur_arg = 5; *args[cur_arg]; cur_arg += 2) {
3754 if (strncmp(args[cur_arg], "data.", 5) != 0) {
Willy Tarreau9d008692019-08-09 11:21:01 +02003755 cli_err(appctx, "\"data.<type>\" followed by a value expected\n");
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003756 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003757 stktable_touch_local(t, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003758 return 1;
3759 }
3760
3761 data_type = stktable_get_data_type(args[cur_arg] + 5);
3762 if (data_type < 0) {
Willy Tarreau9d008692019-08-09 11:21:01 +02003763 cli_err(appctx, "Unknown data type\n");
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003764 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003765 stktable_touch_local(t, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003766 return 1;
3767 }
3768
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003769 if (!t->data_ofs[data_type]) {
Willy Tarreau9d008692019-08-09 11:21:01 +02003770 cli_err(appctx, "Data type not stored in this table\n");
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003771 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003772 stktable_touch_local(t, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003773 return 1;
3774 }
3775
3776 if (!*args[cur_arg+1] || strl2llrc(args[cur_arg+1], strlen(args[cur_arg+1]), &value) != 0) {
Willy Tarreau9d008692019-08-09 11:21:01 +02003777 cli_err(appctx, "Require a valid integer value to store\n");
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003778 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003779 stktable_touch_local(t, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003780 return 1;
3781 }
3782
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003783 ptr = stktable_data_ptr(t, ts, data_type);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003784
3785 switch (stktable_data_types[data_type].std_type) {
3786 case STD_T_SINT:
3787 stktable_data_cast(ptr, std_t_sint) = value;
3788 break;
3789 case STD_T_UINT:
3790 stktable_data_cast(ptr, std_t_uint) = value;
3791 break;
3792 case STD_T_ULL:
3793 stktable_data_cast(ptr, std_t_ull) = value;
3794 break;
3795 case STD_T_FRQP:
3796 /* We set both the current and previous values. That way
3797 * the reported frequency is stable during all the period
3798 * then slowly fades out. This allows external tools to
3799 * push measures without having to update them too often.
3800 */
3801 frqp = &stktable_data_cast(ptr, std_t_frqp);
Willy Tarreaufa1258f2021-04-10 23:00:53 +02003802 /* First bit is reserved for the freq_ctr lock
Emeric Brunf2fc1fd2017-11-02 17:32:43 +01003803 Note: here we're still protected by the stksess lock
Willy Tarreaufa1258f2021-04-10 23:00:53 +02003804 so we don't need to update the update the freq_ctr
Emeric Brunf2fc1fd2017-11-02 17:32:43 +01003805 using its internal lock */
3806 frqp->curr_tick = now_ms & ~0x1;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003807 frqp->prev_ctr = 0;
3808 frqp->curr_ctr = value;
3809 break;
3810 }
3811 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003812 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003813 stktable_touch_local(t, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003814 break;
3815
3816 default:
Willy Tarreau9d008692019-08-09 11:21:01 +02003817 return cli_err(appctx, "Unknown action\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003818 }
3819 return 1;
3820}
3821
3822/* Prepares the appctx fields with the data-based filters from the command line.
3823 * Returns 0 if the dump can proceed, 1 if has ended processing.
3824 */
3825static int table_prepare_data_request(struct appctx *appctx, char **args)
3826{
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01003827 int i;
Adis Nezirovicd0142e72020-01-22 16:50:27 +01003828 char *err = NULL;
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01003829
Willy Tarreau9d008692019-08-09 11:21:01 +02003830 if (appctx->ctx.table.action != STK_CLI_ACT_SHOW && appctx->ctx.table.action != STK_CLI_ACT_CLR)
3831 return cli_err(appctx, "content-based lookup is only supported with the \"show\" and \"clear\" actions\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003832
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01003833 for (i = 0; i < STKTABLE_FILTER_LEN; i++) {
3834 if (i > 0 && !*args[3+3*i]) // number of filter entries can be less than STKTABLE_FILTER_LEN
3835 break;
3836 /* condition on stored data value */
3837 appctx->ctx.table.data_type[i] = stktable_get_data_type(args[3+3*i] + 5);
3838 if (appctx->ctx.table.data_type[i] < 0)
Adis Nezirovicd0142e72020-01-22 16:50:27 +01003839 return cli_dynerr(appctx, memprintf(&err, "Filter entry #%i: Unknown data type\n", i + 1));
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003840
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01003841 if (!((struct stktable *)appctx->ctx.table.target)->data_ofs[appctx->ctx.table.data_type[i]])
Adis Nezirovicd0142e72020-01-22 16:50:27 +01003842 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 +01003843
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01003844 appctx->ctx.table.data_op[i] = get_std_op(args[4+3*i]);
Willy Tarreau2b64a352020-01-22 17:09:47 +01003845 if (appctx->ctx.table.data_op[i] < 0)
Adis Nezirovicd0142e72020-01-22 16:50:27 +01003846 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 +01003847
Adis Nezirovic56dd3542020-01-22 16:16:48 +01003848 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 +01003849 return cli_dynerr(appctx, memprintf(&err, "Filter entry #%i: Require a valid integer value to compare against\n", i + 1));
3850 }
3851
3852 if (*args[3+3*i]) {
3853 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 +01003854 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003855
3856 /* OK we're done, all the fields are set */
3857 return 0;
3858}
3859
3860/* returns 0 if wants to be called, 1 if has ended processing */
Aurélien Nephtaliabbf6072018-04-18 13:26:46 +02003861static int cli_parse_table_req(char **args, char *payload, struct appctx *appctx, void *private)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003862{
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01003863 int i;
3864
3865 for (i = 0; i < STKTABLE_FILTER_LEN; i++)
3866 appctx->ctx.table.data_type[i] = -1;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003867 appctx->ctx.table.target = NULL;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003868 appctx->ctx.table.entry = NULL;
Willy Tarreaua24bc782016-12-14 15:50:35 +01003869 appctx->ctx.table.action = (long)private; // keyword argument, one of STK_CLI_ACT_*
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003870
3871 if (*args[2]) {
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003872 appctx->ctx.table.target = stktable_find_by_name(args[2]);
Willy Tarreau9d008692019-08-09 11:21:01 +02003873 if (!appctx->ctx.table.target)
3874 return cli_err(appctx, "No such table\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003875 }
3876 else {
Willy Tarreaua24bc782016-12-14 15:50:35 +01003877 if (appctx->ctx.table.action != STK_CLI_ACT_SHOW)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003878 goto err_args;
3879 return 0;
3880 }
3881
3882 if (strcmp(args[3], "key") == 0)
3883 return table_process_entry_per_key(appctx, args);
3884 else if (strncmp(args[3], "data.", 5) == 0)
3885 return table_prepare_data_request(appctx, args);
3886 else if (*args[3])
3887 goto err_args;
3888
3889 return 0;
3890
3891err_args:
Willy Tarreaua24bc782016-12-14 15:50:35 +01003892 switch (appctx->ctx.table.action) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003893 case STK_CLI_ACT_SHOW:
Willy Tarreau9d008692019-08-09 11:21:01 +02003894 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 +01003895 case STK_CLI_ACT_CLR:
Willy Tarreau9d008692019-08-09 11:21:01 +02003896 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 +01003897 case STK_CLI_ACT_SET:
Willy Tarreau9d008692019-08-09 11:21:01 +02003898 return cli_err(appctx, "Required arguments: <table> key <key> [data.<store_data_type> <value>]*\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003899 default:
Willy Tarreau9d008692019-08-09 11:21:01 +02003900 return cli_err(appctx, "Unknown action\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003901 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003902}
3903
3904/* This function is used to deal with table operations (dump or clear depending
3905 * on the action stored in appctx->private). It returns 0 if the output buffer is
3906 * full and it needs to be called again, otherwise non-zero.
3907 */
3908static int cli_io_handler_table(struct appctx *appctx)
3909{
3910 struct stream_interface *si = appctx->owner;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003911 struct stream *s = si_strm(si);
3912 struct ebmb_node *eb;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003913 int skip_entry;
Willy Tarreaua24bc782016-12-14 15:50:35 +01003914 int show = appctx->ctx.table.action == STK_CLI_ACT_SHOW;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003915
3916 /*
3917 * We have 3 possible states in appctx->st2 :
3918 * - STAT_ST_INIT : the first call
3919 * - STAT_ST_INFO : the proxy pointer points to the next table to
3920 * dump, the entry pointer is NULL ;
3921 * - STAT_ST_LIST : the proxy pointer points to the current table
3922 * and the entry pointer points to the next entry to be dumped,
3923 * and the refcount on the next entry is held ;
3924 * - STAT_ST_END : nothing left to dump, the buffer may contain some
3925 * data though.
3926 */
3927
3928 if (unlikely(si_ic(si)->flags & (CF_WRITE_ERROR|CF_SHUTW))) {
3929 /* in case of abort, remove any refcount we might have set on an entry */
3930 if (appctx->st2 == STAT_ST_LIST) {
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003931 stksess_kill_if_expired(appctx->ctx.table.t, appctx->ctx.table.entry, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003932 }
3933 return 1;
3934 }
3935
3936 chunk_reset(&trash);
3937
3938 while (appctx->st2 != STAT_ST_FIN) {
3939 switch (appctx->st2) {
3940 case STAT_ST_INIT:
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003941 appctx->ctx.table.t = appctx->ctx.table.target;
3942 if (!appctx->ctx.table.t)
3943 appctx->ctx.table.t = stktables_list;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003944
3945 appctx->ctx.table.entry = NULL;
3946 appctx->st2 = STAT_ST_INFO;
3947 break;
3948
3949 case STAT_ST_INFO:
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003950 if (!appctx->ctx.table.t ||
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003951 (appctx->ctx.table.target &&
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003952 appctx->ctx.table.t != appctx->ctx.table.target)) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003953 appctx->st2 = STAT_ST_END;
3954 break;
3955 }
3956
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003957 if (appctx->ctx.table.t->size) {
3958 if (show && !table_dump_head_to_buffer(&trash, si, appctx->ctx.table.t, appctx->ctx.table.target))
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003959 return 0;
3960
3961 if (appctx->ctx.table.target &&
William Lallemand07a62f72017-05-24 00:57:40 +02003962 (strm_li(s)->bind_conf->level & ACCESS_LVL_MASK) >= ACCESS_LVL_OPER) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003963 /* dump entries only if table explicitly requested */
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003964 HA_SPIN_LOCK(STK_TABLE_LOCK, &appctx->ctx.table.t->lock);
3965 eb = ebmb_first(&appctx->ctx.table.t->keys);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003966 if (eb) {
3967 appctx->ctx.table.entry = ebmb_entry(eb, struct stksess, key);
3968 appctx->ctx.table.entry->ref_cnt++;
3969 appctx->st2 = STAT_ST_LIST;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003970 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &appctx->ctx.table.t->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003971 break;
3972 }
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003973 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &appctx->ctx.table.t->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003974 }
3975 }
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003976 appctx->ctx.table.t = appctx->ctx.table.t->next;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003977 break;
3978
3979 case STAT_ST_LIST:
3980 skip_entry = 0;
3981
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003982 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &appctx->ctx.table.entry->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003983
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01003984 if (appctx->ctx.table.data_type[0] >= 0) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003985 /* we're filtering on some data contents */
3986 void *ptr;
Willy Tarreau2b64a352020-01-22 17:09:47 +01003987 int dt, i;
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01003988 signed char op;
3989 long long data, value;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003990
Emeric Brun819fc6f2017-06-13 19:37:32 +02003991
Willy Tarreau2b64a352020-01-22 17:09:47 +01003992 for (i = 0; i < STKTABLE_FILTER_LEN; i++) {
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01003993 if (appctx->ctx.table.data_type[i] == -1)
3994 break;
3995 dt = appctx->ctx.table.data_type[i];
3996 ptr = stktable_data_ptr(appctx->ctx.table.t,
3997 appctx->ctx.table.entry,
3998 dt);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003999
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004000 data = 0;
4001 switch (stktable_data_types[dt].std_type) {
4002 case STD_T_SINT:
4003 data = stktable_data_cast(ptr, std_t_sint);
4004 break;
4005 case STD_T_UINT:
4006 data = stktable_data_cast(ptr, std_t_uint);
4007 break;
4008 case STD_T_ULL:
4009 data = stktable_data_cast(ptr, std_t_ull);
4010 break;
4011 case STD_T_FRQP:
4012 data = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
4013 appctx->ctx.table.t->data_arg[dt].u);
4014 break;
4015 }
4016
4017 op = appctx->ctx.table.data_op[i];
4018 value = appctx->ctx.table.value[i];
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004019
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004020 /* skip the entry if the data does not match the test and the value */
4021 if ((data < value &&
4022 (op == STD_OP_EQ || op == STD_OP_GT || op == STD_OP_GE)) ||
4023 (data == value &&
4024 (op == STD_OP_NE || op == STD_OP_GT || op == STD_OP_LT)) ||
4025 (data > value &&
4026 (op == STD_OP_EQ || op == STD_OP_LT || op == STD_OP_LE))) {
4027 skip_entry = 1;
4028 break;
4029 }
4030 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004031 }
4032
4033 if (show && !skip_entry &&
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004034 !table_dump_entry_to_buffer(&trash, si, appctx->ctx.table.t, appctx->ctx.table.entry)) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004035 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &appctx->ctx.table.entry->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004036 return 0;
4037 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004038
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004039 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &appctx->ctx.table.entry->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004040
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004041 HA_SPIN_LOCK(STK_TABLE_LOCK, &appctx->ctx.table.t->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004042 appctx->ctx.table.entry->ref_cnt--;
4043
4044 eb = ebmb_next(&appctx->ctx.table.entry->key);
4045 if (eb) {
4046 struct stksess *old = appctx->ctx.table.entry;
4047 appctx->ctx.table.entry = ebmb_entry(eb, struct stksess, key);
4048 if (show)
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004049 __stksess_kill_if_expired(appctx->ctx.table.t, old);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004050 else if (!skip_entry && !appctx->ctx.table.entry->ref_cnt)
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004051 __stksess_kill(appctx->ctx.table.t, old);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004052 appctx->ctx.table.entry->ref_cnt++;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004053 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &appctx->ctx.table.t->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004054 break;
4055 }
4056
4057
4058 if (show)
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004059 __stksess_kill_if_expired(appctx->ctx.table.t, appctx->ctx.table.entry);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004060 else if (!skip_entry && !appctx->ctx.table.entry->ref_cnt)
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004061 __stksess_kill(appctx->ctx.table.t, appctx->ctx.table.entry);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004062
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004063 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &appctx->ctx.table.t->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004064
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004065 appctx->ctx.table.t = appctx->ctx.table.t->next;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004066 appctx->st2 = STAT_ST_INFO;
4067 break;
4068
4069 case STAT_ST_END:
4070 appctx->st2 = STAT_ST_FIN;
4071 break;
4072 }
4073 }
4074 return 1;
4075}
4076
4077static void cli_release_show_table(struct appctx *appctx)
4078{
4079 if (appctx->st2 == STAT_ST_LIST) {
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004080 stksess_kill_if_expired(appctx->ctx.table.t, appctx->ctx.table.entry, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004081 }
4082}
4083
Willy Tarreau478331d2020-08-28 11:31:31 +02004084static void stkt_late_init(void)
4085{
4086 struct sample_fetch *f;
4087
4088 f = find_sample_fetch("src", strlen("src"));
4089 if (f)
4090 smp_fetch_src = f->process;
4091}
4092
4093INITCALL0(STG_INIT, stkt_late_init);
4094
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004095/* register cli keywords */
4096static struct cli_kw_list cli_kws = {{ },{
Willy Tarreaub205bfd2021-05-07 11:38:37 +02004097 { { "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 },
4098 { { "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 },
4099 { { "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 +01004100 {{},}
4101}};
4102
Willy Tarreau0108d902018-11-25 19:14:37 +01004103INITCALL1(STG_REGISTER, cli_register_kw, &cli_kws);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004104
Thierry FOURNIER236657b2015-08-19 08:25:14 +02004105static struct action_kw_list tcp_conn_kws = { { }, {
Amaury Denoyellee4a617c2021-05-06 15:33:09 +02004106 { "sc-inc-gpc0", parse_inc_gpc0, KWF_MATCH_PREFIX },
4107 { "sc-inc-gpc1", parse_inc_gpc1, KWF_MATCH_PREFIX },
4108 { "sc-set-gpt0", parse_set_gpt0, KWF_MATCH_PREFIX },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02004109 { /* END */ }
4110}};
4111
Willy Tarreau0108d902018-11-25 19:14:37 +01004112INITCALL1(STG_REGISTER, tcp_req_conn_keywords_register, &tcp_conn_kws);
4113
Willy Tarreau620408f2016-10-21 16:37:51 +02004114static struct action_kw_list tcp_sess_kws = { { }, {
Amaury Denoyellee4a617c2021-05-06 15:33:09 +02004115 { "sc-inc-gpc0", parse_inc_gpc0, KWF_MATCH_PREFIX },
4116 { "sc-inc-gpc1", parse_inc_gpc1, KWF_MATCH_PREFIX },
4117 { "sc-set-gpt0", parse_set_gpt0, KWF_MATCH_PREFIX },
Willy Tarreau620408f2016-10-21 16:37:51 +02004118 { /* END */ }
4119}};
4120
Willy Tarreau0108d902018-11-25 19:14:37 +01004121INITCALL1(STG_REGISTER, tcp_req_sess_keywords_register, &tcp_sess_kws);
4122
Thierry FOURNIER236657b2015-08-19 08:25:14 +02004123static struct action_kw_list tcp_req_kws = { { }, {
Amaury Denoyellee4a617c2021-05-06 15:33:09 +02004124 { "sc-inc-gpc0", parse_inc_gpc0, KWF_MATCH_PREFIX },
4125 { "sc-inc-gpc1", parse_inc_gpc1, KWF_MATCH_PREFIX },
4126 { "sc-set-gpt0", parse_set_gpt0, KWF_MATCH_PREFIX },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02004127 { /* END */ }
4128}};
4129
Willy Tarreau0108d902018-11-25 19:14:37 +01004130INITCALL1(STG_REGISTER, tcp_req_cont_keywords_register, &tcp_req_kws);
4131
Thierry FOURNIER236657b2015-08-19 08:25:14 +02004132static struct action_kw_list tcp_res_kws = { { }, {
Amaury Denoyellee4a617c2021-05-06 15:33:09 +02004133 { "sc-inc-gpc0", parse_inc_gpc0, KWF_MATCH_PREFIX },
4134 { "sc-inc-gpc1", parse_inc_gpc1, KWF_MATCH_PREFIX },
4135 { "sc-set-gpt0", parse_set_gpt0, KWF_MATCH_PREFIX },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02004136 { /* END */ }
4137}};
4138
Willy Tarreau0108d902018-11-25 19:14:37 +01004139INITCALL1(STG_REGISTER, tcp_res_cont_keywords_register, &tcp_res_kws);
4140
Thierry FOURNIER236657b2015-08-19 08:25:14 +02004141static struct action_kw_list http_req_kws = { { }, {
Amaury Denoyellee4a617c2021-05-06 15:33:09 +02004142 { "sc-inc-gpc0", parse_inc_gpc0, KWF_MATCH_PREFIX },
4143 { "sc-inc-gpc1", parse_inc_gpc1, KWF_MATCH_PREFIX },
4144 { "sc-set-gpt0", parse_set_gpt0, KWF_MATCH_PREFIX },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02004145 { /* END */ }
4146}};
4147
Willy Tarreau0108d902018-11-25 19:14:37 +01004148INITCALL1(STG_REGISTER, http_req_keywords_register, &http_req_kws);
4149
Thierry FOURNIER236657b2015-08-19 08:25:14 +02004150static struct action_kw_list http_res_kws = { { }, {
Amaury Denoyellee4a617c2021-05-06 15:33:09 +02004151 { "sc-inc-gpc0", parse_inc_gpc0, KWF_MATCH_PREFIX },
4152 { "sc-inc-gpc1", parse_inc_gpc1, KWF_MATCH_PREFIX },
4153 { "sc-set-gpt0", parse_set_gpt0, KWF_MATCH_PREFIX },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02004154 { /* END */ }
4155}};
4156
Willy Tarreau0108d902018-11-25 19:14:37 +01004157INITCALL1(STG_REGISTER, http_res_keywords_register, &http_res_kws);
4158
Willy Tarreau7d562212016-11-25 16:10:05 +01004159/* Note: must not be declared <const> as its list will be overwritten.
4160 * Please take care of keeping this list alphabetically sorted.
4161 */
4162static struct sample_fetch_kw_list smp_fetch_keywords = {ILH, {
4163 { "sc_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4164 { "sc_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4165 { "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 +01004166 { "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 +01004167 { "sc_conn_cnt", smp_fetch_sc_conn_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4168 { "sc_conn_cur", smp_fetch_sc_conn_cur, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4169 { "sc_conn_rate", smp_fetch_sc_conn_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
Thierry FOURNIER401c64b2017-01-05 11:44:09 +01004170 { "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 +01004171 { "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 +01004172 { "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 +01004173 { "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 +01004174 { "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 +01004175 { "sc_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4176 { "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 +01004177 { "sc_http_fail_cnt", smp_fetch_sc_http_fail_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4178 { "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 +01004179 { "sc_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4180 { "sc_http_req_rate", smp_fetch_sc_http_req_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4181 { "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 +01004182 { "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 +01004183 { "sc_kbytes_in", smp_fetch_sc_kbytes_in, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4184 { "sc_kbytes_out", smp_fetch_sc_kbytes_out, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4185 { "sc_sess_cnt", smp_fetch_sc_sess_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4186 { "sc_sess_rate", smp_fetch_sc_sess_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4187 { "sc_tracked", smp_fetch_sc_tracked, ARG2(1,SINT,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
4188 { "sc_trackers", smp_fetch_sc_trackers, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4189 { "sc0_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4190 { "sc0_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4191 { "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 +01004192 { "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 +01004193 { "sc0_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4194 { "sc0_conn_cur", smp_fetch_sc_conn_cur, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4195 { "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 +01004196 { "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 +01004197 { "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 +01004198 { "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 +01004199 { "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 +01004200 { "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 +01004201 { "sc0_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4202 { "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 +01004203 { "sc0_http_fail_cnt", smp_fetch_sc_http_fail_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4204 { "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 +01004205 { "sc0_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4206 { "sc0_http_req_rate", smp_fetch_sc_http_req_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4207 { "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 +01004208 { "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 +01004209 { "sc0_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4210 { "sc0_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4211 { "sc0_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4212 { "sc0_sess_rate", smp_fetch_sc_sess_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4213 { "sc0_tracked", smp_fetch_sc_tracked, ARG1(0,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
4214 { "sc0_trackers", smp_fetch_sc_trackers, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4215 { "sc1_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4216 { "sc1_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4217 { "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 +01004218 { "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 +01004219 { "sc1_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4220 { "sc1_conn_cur", smp_fetch_sc_conn_cur, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4221 { "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 +01004222 { "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 +01004223 { "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 +01004224 { "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 +01004225 { "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 +01004226 { "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 +01004227 { "sc1_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4228 { "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 +01004229 { "sc1_http_fail_cnt", smp_fetch_sc_http_fail_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4230 { "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 +01004231 { "sc1_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4232 { "sc1_http_req_rate", smp_fetch_sc_http_req_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4233 { "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 +01004234 { "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 +01004235 { "sc1_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4236 { "sc1_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4237 { "sc1_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4238 { "sc1_sess_rate", smp_fetch_sc_sess_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4239 { "sc1_tracked", smp_fetch_sc_tracked, ARG1(0,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
4240 { "sc1_trackers", smp_fetch_sc_trackers, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4241 { "sc2_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4242 { "sc2_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4243 { "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 +01004244 { "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 +01004245 { "sc2_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4246 { "sc2_conn_cur", smp_fetch_sc_conn_cur, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4247 { "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 +01004248 { "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 +01004249 { "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 +01004250 { "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 +01004251 { "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 +01004252 { "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 +01004253 { "sc2_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4254 { "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 +01004255 { "sc2_http_fail_cnt", smp_fetch_sc_http_fail_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4256 { "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 +01004257 { "sc2_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4258 { "sc2_http_req_rate", smp_fetch_sc_http_req_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4259 { "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 +01004260 { "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 +01004261 { "sc2_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4262 { "sc2_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4263 { "sc2_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4264 { "sc2_sess_rate", smp_fetch_sc_sess_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4265 { "sc2_tracked", smp_fetch_sc_tracked, ARG1(0,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
4266 { "sc2_trackers", smp_fetch_sc_trackers, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4267 { "src_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4268 { "src_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4269 { "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 +01004270 { "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 +01004271 { "src_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4272 { "src_conn_cur", smp_fetch_sc_conn_cur, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4273 { "src_conn_rate", smp_fetch_sc_conn_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
Thierry FOURNIER401c64b2017-01-05 11:44:09 +01004274 { "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 +01004275 { "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 +01004276 { "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 +01004277 { "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 +01004278 { "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 +01004279 { "src_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4280 { "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 +01004281 { "src_http_fail_cnt", smp_fetch_sc_http_fail_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4282 { "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 +01004283 { "src_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4284 { "src_http_req_rate", smp_fetch_sc_http_req_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4285 { "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 +01004286 { "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 +01004287 { "src_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4288 { "src_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4289 { "src_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4290 { "src_sess_rate", smp_fetch_sc_sess_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4291 { "src_updt_conn_cnt", smp_fetch_src_updt_conn_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4292 { "table_avl", smp_fetch_table_avl, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4293 { "table_cnt", smp_fetch_table_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4294 { /* END */ },
4295}};
4296
Willy Tarreau0108d902018-11-25 19:14:37 +01004297INITCALL1(STG_REGISTER, sample_register_fetches, &smp_fetch_keywords);
Willy Tarreau7d562212016-11-25 16:10:05 +01004298
Willy Tarreaud9f316a2014-07-10 14:03:38 +02004299/* Note: must not be declared <const> as its list will be overwritten */
4300static struct sample_conv_kw_list sample_conv_kws = {ILH, {
Willy Tarreau2d17db52016-05-25 17:16:38 +02004301 { "in_table", sample_conv_in_table, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_BOOL },
4302 { "table_bytes_in_rate", sample_conv_table_bytes_in_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4303 { "table_bytes_out_rate", sample_conv_table_bytes_out_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4304 { "table_conn_cnt", sample_conv_table_conn_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4305 { "table_conn_cur", sample_conv_table_conn_cur, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4306 { "table_conn_rate", sample_conv_table_conn_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4307 { "table_gpt0", sample_conv_table_gpt0, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4308 { "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 +01004309 { "table_gpc1", sample_conv_table_gpc1, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
Willy Tarreau2d17db52016-05-25 17:16:38 +02004310 { "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 +01004311 { "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 +02004312 { "table_http_err_cnt", sample_conv_table_http_err_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4313 { "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 +01004314 { "table_http_fail_cnt", sample_conv_table_http_fail_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4315 { "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 +02004316 { "table_http_req_cnt", sample_conv_table_http_req_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4317 { "table_http_req_rate", sample_conv_table_http_req_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4318 { "table_kbytes_in", sample_conv_table_kbytes_in, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4319 { "table_kbytes_out", sample_conv_table_kbytes_out, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4320 { "table_server_id", sample_conv_table_server_id, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4321 { "table_sess_cnt", sample_conv_table_sess_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4322 { "table_sess_rate", sample_conv_table_sess_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4323 { "table_trackers", sample_conv_table_trackers, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
Willy Tarreaud9f316a2014-07-10 14:03:38 +02004324 { /* END */ },
4325}};
4326
Willy Tarreau0108d902018-11-25 19:14:37 +01004327INITCALL1(STG_REGISTER, sample_register_convs, &sample_conv_kws);