blob: 0255cd2762abfd1ce1e5bc46188f0cc16817b798 [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 Tarreauaea940e2010-06-06 11:56:36 +0200557 * Trash expired sticky sessions from table <t>. The next expiration date is
558 * returned.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100559 */
560static int stktable_trash_expired(struct stktable *t)
561{
562 struct stksess *ts;
563 struct eb32_node *eb;
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200564 int looped = 0;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100565
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100566 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100567 eb = eb32_lookup_ge(&t->exps, now_ms - TIMER_LOOK_BACK);
568
569 while (1) {
570 if (unlikely(!eb)) {
571 /* we might have reached the end of the tree, typically because
572 * <now_ms> is in the first half and we're first scanning the last
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200573 * half. Let's loop back to the beginning of the tree now if we
574 * have not yet visited it.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100575 */
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200576 if (looped)
577 break;
578 looped = 1;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100579 eb = eb32_first(&t->exps);
580 if (likely(!eb))
581 break;
582 }
583
584 if (likely(tick_is_lt(now_ms, eb->key))) {
585 /* timer not expired yet, revisit it later */
586 t->exp_next = eb->key;
Willy Tarreau4d5f13c2017-11-05 11:04:47 +0100587 goto out_unlock;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100588 }
589
590 /* timer looks expired, detach it from the queue */
Willy Tarreau86257dc2010-06-06 12:57:10 +0200591 ts = eb32_entry(eb, struct stksess, exp);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100592 eb = eb32_next(eb);
593
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200594 /* don't delete an entry which is currently referenced */
595 if (ts->ref_cnt)
596 continue;
597
Willy Tarreau86257dc2010-06-06 12:57:10 +0200598 eb32_delete(&ts->exp);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100599
600 if (!tick_is_expired(ts->expire, now_ms)) {
601 if (!tick_isset(ts->expire))
602 continue;
603
Willy Tarreau86257dc2010-06-06 12:57:10 +0200604 ts->exp.key = ts->expire;
605 eb32_insert(&t->exps, &ts->exp);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100606
Willy Tarreau86257dc2010-06-06 12:57:10 +0200607 if (!eb || eb->key > ts->exp.key)
608 eb = &ts->exp;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100609 continue;
610 }
611
612 /* session expired, trash it */
Willy Tarreau86257dc2010-06-06 12:57:10 +0200613 ebmb_delete(&ts->key);
Emeric Brun85e77c72010-09-23 18:16:52 +0200614 eb32_delete(&ts->upd);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200615 __stksess_free(t, ts);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100616 }
617
618 /* We have found no task to expire in any tree */
619 t->exp_next = TICK_ETERNITY;
Willy Tarreau4d5f13c2017-11-05 11:04:47 +0100620out_unlock:
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100621 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100622 return t->exp_next;
623}
624
625/*
Willy Tarreauaea940e2010-06-06 11:56:36 +0200626 * Task processing function to trash expired sticky sessions. A pointer to the
627 * task itself is returned since it never dies.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100628 */
Willy Tarreau144f84a2021-03-02 16:09:26 +0100629struct task *process_table_expire(struct task *task, void *context, unsigned int state)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100630{
Olivier Houchard9f6af332018-05-25 14:04:04 +0200631 struct stktable *t = context;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100632
633 task->expire = stktable_trash_expired(t);
634 return task;
635}
636
Willy Tarreauaea940e2010-06-06 11:56:36 +0200637/* Perform minimal stick table intializations, report 0 in case of error, 1 if OK. */
Emeric Brun3bd697e2010-01-04 15:23:48 +0100638int stktable_init(struct stktable *t)
639{
640 if (t->size) {
Emeric Brun819fc6f2017-06-13 19:37:32 +0200641 t->keys = EB_ROOT_UNIQUE;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100642 memset(&t->exps, 0, sizeof(t->exps));
Emeric Brun1c6235d2015-12-16 15:28:12 +0100643 t->updates = EB_ROOT_UNIQUE;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100644 HA_SPIN_INIT(&t->lock);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100645
Olivier Houchard52dabbc2018-11-14 17:54:36 +0100646 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 +0100647
648 t->exp_next = TICK_ETERNITY;
649 if ( t->expire ) {
Emeric Brunc60def82017-09-27 14:59:38 +0200650 t->exp_task = task_new(MAX_THREADS_MASK);
Willy Tarreau848522f2018-10-15 11:12:15 +0200651 if (!t->exp_task)
652 return 0;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100653 t->exp_task->process = process_table_expire;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100654 t->exp_task->context = (void *)t;
655 }
Willy Tarreauc3914d42020-09-24 08:39:22 +0200656 if (t->peers.p && t->peers.p->peers_fe && !t->peers.p->peers_fe->disabled) {
Emeric Brun32da3c42010-09-23 18:39:19 +0200657 peers_register_table(t->peers.p, t);
658 }
659
Emeric Brun3bd697e2010-01-04 15:23:48 +0100660 return t->pool != NULL;
661 }
662 return 1;
663}
664
665/*
666 * Configuration keywords of known table types
667 */
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200668struct stktable_type stktable_types[SMP_TYPES] = {
669 [SMP_T_SINT] = { "integer", 0, 4 },
670 [SMP_T_IPV4] = { "ip", 0, 4 },
671 [SMP_T_IPV6] = { "ipv6", 0, 16 },
672 [SMP_T_STR] = { "string", STK_F_CUSTOM_KEYSIZE, 32 },
673 [SMP_T_BIN] = { "binary", STK_F_CUSTOM_KEYSIZE, 32 }
674};
Emeric Brun3bd697e2010-01-04 15:23:48 +0100675
676/*
677 * Parse table type configuration.
678 * Returns 0 on successful parsing, else 1.
679 * <myidx> is set at next configuration <args> index.
680 */
681int stktable_parse_type(char **args, int *myidx, unsigned long *type, size_t *key_size)
682{
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200683 for (*type = 0; *type < SMP_TYPES; (*type)++) {
684 if (!stktable_types[*type].kw)
685 continue;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100686 if (strcmp(args[*myidx], stktable_types[*type].kw) != 0)
687 continue;
688
689 *key_size = stktable_types[*type].default_size;
690 (*myidx)++;
691
Willy Tarreauaea940e2010-06-06 11:56:36 +0200692 if (stktable_types[*type].flags & STK_F_CUSTOM_KEYSIZE) {
Emeric Brun3bd697e2010-01-04 15:23:48 +0100693 if (strcmp("len", args[*myidx]) == 0) {
694 (*myidx)++;
695 *key_size = atol(args[*myidx]);
Emeric Brun485479d2010-09-23 18:02:19 +0200696 if (!*key_size)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100697 break;
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200698 if (*type == SMP_T_STR) {
Emeric Brun485479d2010-09-23 18:02:19 +0200699 /* null terminated string needs +1 for '\0'. */
700 (*key_size)++;
701 }
Emeric Brun3bd697e2010-01-04 15:23:48 +0100702 (*myidx)++;
703 }
704 }
705 return 0;
706 }
707 return 1;
708}
709
Willy Tarreau3b63ca22021-05-08 14:10:42 +0200710/* reserve some space for data type <type>, and associate argument at <sa> if
711 * not NULL. Returns PE_NONE (0) if OK or an error code among :
712 * - PE_ENUM_OOR if <type> does not exist
713 * - PE_EXIST if <type> is already registered
714 * - PE_ARG_NOT_USE if <sa> was provided but not expected
715 * - PE_ARG_MISSING if <sa> was expected but not provided
716 */
717int stktable_alloc_data_type(struct stktable *t, int type, const char *sa)
718{
719 if (type >= STKTABLE_DATA_TYPES)
720 return PE_ENUM_OOR;
721
722 if (t->data_ofs[type])
723 /* already allocated */
724 return PE_EXIST;
725
726 switch (stktable_data_types[type].arg_type) {
727 case ARG_T_NONE:
728 if (sa)
729 return PE_ARG_NOT_USED;
730 break;
731 case ARG_T_INT:
732 if (!sa)
733 return PE_ARG_MISSING;
734 t->data_arg[type].i = atoi(sa);
735 break;
736 case ARG_T_DELAY:
737 if (!sa)
738 return PE_ARG_MISSING;
739 sa = parse_time_err(sa, &t->data_arg[type].u, TIME_UNIT_MS);
740 if (sa)
741 return PE_ARG_INVC; /* invalid char */
742 break;
743 }
744
745 t->data_size += stktable_type_size(stktable_data_types[type].std_type);
746 t->data_ofs[type] = -t->data_size;
747 return PE_NONE;
748}
749
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100750/*
Frédéric Lécaillec02766a2019-03-20 15:06:55 +0100751 * Parse a line with <linenum> as number in <file> configuration file to configure
752 * the stick-table with <t> as address and <id> as ID.
753 * <peers> provides the "peers" section pointer only if this function is called
754 * from a "peers" section.
755 * <nid> is the stick-table name which is sent over the network. It must be equal
756 * to <id> if this stick-table is parsed from a proxy section, and prefixed by <peers>
757 * "peers" section name followed by a '/' character if parsed from a "peers" section.
Ilya Shipitsind4259502020-04-08 01:07:56 +0500758 * This is the responsibility of the caller to check this.
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100759 * Return an error status with ERR_* flags set if required, 0 if no error was encountered.
760 */
761int parse_stick_table(const char *file, int linenum, char **args,
Frédéric Lécaillec02766a2019-03-20 15:06:55 +0100762 struct stktable *t, char *id, char *nid, struct peers *peers)
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100763{
764 int err_code = 0;
765 int idx = 1;
766 unsigned int val;
767
768 if (!id || !*id) {
769 ha_alert("parsing [%s:%d] : %s: ID not provided.\n", file, linenum, args[0]);
770 err_code |= ERR_ALERT | ERR_ABORT;
771 goto out;
772 }
773
774 /* Store the "peers" section if this function is called from a "peers" section. */
775 if (peers) {
776 t->peers.p = peers;
777 idx++;
778 }
779
780 t->id = id;
Frédéric Lécaillec02766a2019-03-20 15:06:55 +0100781 t->nid = nid;
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100782 t->type = (unsigned int)-1;
783 t->conf.file = file;
784 t->conf.line = linenum;
785
786 while (*args[idx]) {
787 const char *err;
788
789 if (strcmp(args[idx], "size") == 0) {
790 idx++;
791 if (!*(args[idx])) {
792 ha_alert("parsing [%s:%d] : %s: missing argument after '%s'.\n",
793 file, linenum, args[0], args[idx-1]);
794 err_code |= ERR_ALERT | ERR_FATAL;
795 goto out;
796 }
797 if ((err = parse_size_err(args[idx], &t->size))) {
798 ha_alert("parsing [%s:%d] : %s: unexpected character '%c' in argument of '%s'.\n",
799 file, linenum, args[0], *err, args[idx-1]);
800 err_code |= ERR_ALERT | ERR_FATAL;
801 goto out;
802 }
803 idx++;
804 }
805 /* This argument does not exit in "peers" section. */
806 else if (!peers && strcmp(args[idx], "peers") == 0) {
807 idx++;
808 if (!*(args[idx])) {
809 ha_alert("parsing [%s:%d] : %s: missing argument after '%s'.\n",
810 file, linenum, args[0], args[idx-1]);
811 err_code |= ERR_ALERT | ERR_FATAL;
812 goto out;
813 }
814 t->peers.name = strdup(args[idx++]);
815 }
816 else if (strcmp(args[idx], "expire") == 0) {
817 idx++;
818 if (!*(args[idx])) {
819 ha_alert("parsing [%s:%d] : %s: missing argument after '%s'.\n",
820 file, linenum, args[0], args[idx-1]);
821 err_code |= ERR_ALERT | ERR_FATAL;
822 goto out;
823 }
824 err = parse_time_err(args[idx], &val, TIME_UNIT_MS);
Willy Tarreau9faebe32019-06-07 19:00:37 +0200825 if (err == PARSE_TIME_OVER) {
826 ha_alert("parsing [%s:%d]: %s: timer overflow in argument <%s> to <%s>, maximum value is 2147483647 ms (~24.8 days).\n",
827 file, linenum, args[0], args[idx], args[idx-1]);
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100828 err_code |= ERR_ALERT | ERR_FATAL;
829 goto out;
830 }
Willy Tarreau9faebe32019-06-07 19:00:37 +0200831 else if (err == PARSE_TIME_UNDER) {
832 ha_alert("parsing [%s:%d]: %s: timer underflow in argument <%s> to <%s>, minimum non-null value is 1 ms.\n",
833 file, linenum, args[0], args[idx], args[idx-1]);
834 err_code |= ERR_ALERT | ERR_FATAL;
835 goto out;
836 }
837 else if (err) {
838 ha_alert("parsing [%s:%d] : %s: unexpected character '%c' in argument of '%s'.\n",
839 file, linenum, args[0], *err, args[idx-1]);
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100840 err_code |= ERR_ALERT | ERR_FATAL;
841 goto out;
842 }
843 t->expire = val;
844 idx++;
845 }
846 else if (strcmp(args[idx], "nopurge") == 0) {
847 t->nopurge = 1;
848 idx++;
849 }
850 else if (strcmp(args[idx], "type") == 0) {
851 idx++;
852 if (stktable_parse_type(args, &idx, &t->type, &t->key_size) != 0) {
853 ha_alert("parsing [%s:%d] : %s: unknown type '%s'.\n",
854 file, linenum, args[0], args[idx]);
855 err_code |= ERR_ALERT | ERR_FATAL;
856 goto out;
857 }
858 /* idx already points to next arg */
859 }
860 else if (strcmp(args[idx], "store") == 0) {
861 int type, err;
862 char *cw, *nw, *sa;
863
864 idx++;
865 nw = args[idx];
866 while (*nw) {
867 /* the "store" keyword supports a comma-separated list */
868 cw = nw;
869 sa = NULL; /* store arg */
870 while (*nw && *nw != ',') {
871 if (*nw == '(') {
872 *nw = 0;
873 sa = ++nw;
874 while (*nw != ')') {
875 if (!*nw) {
876 ha_alert("parsing [%s:%d] : %s: missing closing parenthesis after store option '%s'.\n",
877 file, linenum, args[0], cw);
878 err_code |= ERR_ALERT | ERR_FATAL;
879 goto out;
880 }
881 nw++;
882 }
883 *nw = '\0';
884 }
885 nw++;
886 }
887 if (*nw)
888 *nw++ = '\0';
889 type = stktable_get_data_type(cw);
890 if (type < 0) {
891 ha_alert("parsing [%s:%d] : %s: unknown store option '%s'.\n",
892 file, linenum, args[0], cw);
893 err_code |= ERR_ALERT | ERR_FATAL;
894 goto out;
895 }
896
897 err = stktable_alloc_data_type(t, type, sa);
898 switch (err) {
899 case PE_NONE: break;
900 case PE_EXIST:
901 ha_warning("parsing [%s:%d]: %s: store option '%s' already enabled, ignored.\n",
902 file, linenum, args[0], cw);
903 err_code |= ERR_WARN;
904 break;
905
906 case PE_ARG_MISSING:
907 ha_alert("parsing [%s:%d] : %s: missing argument to store option '%s'.\n",
908 file, linenum, args[0], cw);
909 err_code |= ERR_ALERT | ERR_FATAL;
910 goto out;
911
912 case PE_ARG_NOT_USED:
913 ha_alert("parsing [%s:%d] : %s: unexpected argument to store option '%s'.\n",
914 file, linenum, args[0], cw);
915 err_code |= ERR_ALERT | ERR_FATAL;
916 goto out;
917
918 default:
919 ha_alert("parsing [%s:%d] : %s: error when processing store option '%s'.\n",
920 file, linenum, args[0], cw);
921 err_code |= ERR_ALERT | ERR_FATAL;
922 goto out;
923 }
924 }
925 idx++;
926 }
Thayne McCombs92149f92020-11-20 01:28:26 -0700927 else if (strcmp(args[idx], "srvkey") == 0) {
928 char *keytype;
929 idx++;
930 keytype = args[idx];
931 if (strcmp(keytype, "name") == 0) {
932 t->server_key_type = STKTABLE_SRV_NAME;
933 }
934 else if (strcmp(keytype, "addr") == 0) {
935 t->server_key_type = STKTABLE_SRV_ADDR;
936 }
937 else {
938 ha_alert("parsing [%s:%d] : %s : unknown server key type '%s'.\n",
939 file, linenum, args[0], keytype);
940 err_code |= ERR_ALERT | ERR_FATAL;
941 goto out;
942
943 }
944 idx++;
945 }
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100946 else {
947 ha_alert("parsing [%s:%d] : %s: unknown argument '%s'.\n",
948 file, linenum, args[0], args[idx]);
949 err_code |= ERR_ALERT | ERR_FATAL;
950 goto out;
951 }
952 }
953
954 if (!t->size) {
955 ha_alert("parsing [%s:%d] : %s: missing size.\n",
956 file, linenum, args[0]);
957 err_code |= ERR_ALERT | ERR_FATAL;
958 goto out;
959 }
960
961 if (t->type == (unsigned int)-1) {
962 ha_alert("parsing [%s:%d] : %s: missing type.\n",
963 file, linenum, args[0]);
964 err_code |= ERR_ALERT | ERR_FATAL;
965 goto out;
966 }
967
968 out:
969 return err_code;
970}
971
Willy Tarreau8fed9032014-07-03 17:02:46 +0200972/* Prepares a stktable_key from a sample <smp> to search into table <t>.
Willy Tarreauf0c730a2016-05-25 17:07:56 +0200973 * Note that the sample *is* modified and that the returned key may point
974 * to it, so the sample must not be modified afterwards before the lookup.
Willy Tarreau8fed9032014-07-03 17:02:46 +0200975 * Returns NULL if the sample could not be converted (eg: no matching type),
976 * otherwise a pointer to the static stktable_key filled with what is needed
977 * for the lookup.
Willy Tarreauf0b38bf2010-06-06 13:22:23 +0200978 */
Willy Tarreau8fed9032014-07-03 17:02:46 +0200979struct stktable_key *smp_to_stkey(struct sample *smp, struct stktable *t)
Willy Tarreauf0b38bf2010-06-06 13:22:23 +0200980{
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200981 /* Convert sample. */
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200982 if (!sample_convert(smp, t->type))
Willy Tarreau7fc1c6e2012-04-26 11:03:17 +0200983 return NULL;
984
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200985 /* Fill static_table_key. */
986 switch (t->type) {
Emeric Brun485479d2010-09-23 18:02:19 +0200987
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200988 case SMP_T_IPV4:
Christopher Fauletca20d022017-08-29 15:30:31 +0200989 static_table_key.key = &smp->data.u.ipv4;
990 static_table_key.key_len = 4;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200991 break;
Emeric Brun485479d2010-09-23 18:02:19 +0200992
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200993 case SMP_T_IPV6:
Christopher Fauletca20d022017-08-29 15:30:31 +0200994 static_table_key.key = &smp->data.u.ipv6;
995 static_table_key.key_len = 16;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200996 break;
Emeric Brun485479d2010-09-23 18:02:19 +0200997
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200998 case SMP_T_SINT:
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200999 /* The stick table require a 32bit unsigned int, "sint" is a
1000 * signed 64 it, so we can convert it inplace.
1001 */
Willy Tarreau28c63c12019-10-23 06:21:05 +02001002 smp->data.u.sint = (unsigned int)smp->data.u.sint;
Christopher Fauletca20d022017-08-29 15:30:31 +02001003 static_table_key.key = &smp->data.u.sint;
1004 static_table_key.key_len = 4;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001005 break;
1006
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +02001007 case SMP_T_STR:
Willy Tarreauce6955e2016-08-09 11:59:12 +02001008 if (!smp_make_safe(smp))
1009 return NULL;
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001010 static_table_key.key = smp->data.u.str.area;
1011 static_table_key.key_len = smp->data.u.str.data;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001012 break;
Emeric Brun485479d2010-09-23 18:02:19 +02001013
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +02001014 case SMP_T_BIN:
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001015 if (smp->data.u.str.data < t->key_size) {
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001016 /* This type needs padding with 0. */
Willy Tarreauf65c6c02016-08-09 12:08:41 +02001017 if (!smp_make_rw(smp))
1018 return NULL;
1019
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001020 if (smp->data.u.str.size < t->key_size)
1021 if (!smp_dup(smp))
1022 return NULL;
1023 if (smp->data.u.str.size < t->key_size)
1024 return NULL;
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001025 memset(smp->data.u.str.area + smp->data.u.str.data, 0,
1026 t->key_size - smp->data.u.str.data);
1027 smp->data.u.str.data = t->key_size;
Emeric Brun485479d2010-09-23 18:02:19 +02001028 }
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001029 static_table_key.key = smp->data.u.str.area;
1030 static_table_key.key_len = smp->data.u.str.data;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001031 break;
Emeric Brun485479d2010-09-23 18:02:19 +02001032
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001033 default: /* impossible case. */
1034 return NULL;
Emeric Brun485479d2010-09-23 18:02:19 +02001035 }
1036
Christopher Fauletca20d022017-08-29 15:30:31 +02001037 return &static_table_key;
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001038}
1039
1040/*
Willy Tarreau8fed9032014-07-03 17:02:46 +02001041 * Process a fetch + format conversion as defined by the sample expression <expr>
1042 * on request or response considering the <opt> parameter. Returns either NULL if
1043 * no key could be extracted, or a pointer to the converted result stored in
1044 * static_table_key in format <table_type>. If <smp> is not NULL, it will be reset
1045 * and its flags will be initialized so that the caller gets a copy of the input
Willy Tarreau6bcb0a82014-07-30 08:56:35 +02001046 * sample, and knows why it was not accepted (eg: SMP_F_MAY_CHANGE is present
1047 * without SMP_OPT_FINAL). The output will be usable like this :
1048 *
1049 * return MAY_CHANGE FINAL Meaning for the sample
1050 * NULL 0 * Not present and will never be (eg: header)
1051 * NULL 1 0 Not present or unstable, could change (eg: req_len)
1052 * NULL 1 1 Not present, will not change anymore
1053 * smp 0 * Present and will not change (eg: header)
1054 * smp 1 0 not possible
1055 * smp 1 1 Present, last known value (eg: request length)
Willy Tarreau8fed9032014-07-03 17:02:46 +02001056 */
Willy Tarreau192252e2015-04-04 01:47:55 +02001057struct stktable_key *stktable_fetch_key(struct stktable *t, struct proxy *px, struct session *sess, struct stream *strm,
Willy Tarreau8fed9032014-07-03 17:02:46 +02001058 unsigned int opt, struct sample_expr *expr, struct sample *smp)
1059{
1060 if (smp)
1061 memset(smp, 0, sizeof(*smp));
1062
Willy Tarreau192252e2015-04-04 01:47:55 +02001063 smp = sample_process(px, sess, strm, opt, expr, smp);
Willy Tarreau8fed9032014-07-03 17:02:46 +02001064 if (!smp)
1065 return NULL;
1066
1067 if ((smp->flags & SMP_F_MAY_CHANGE) && !(opt & SMP_OPT_FINAL))
1068 return NULL; /* we can only use stable samples */
1069
1070 return smp_to_stkey(smp, t);
1071}
1072
1073/*
Willy Tarreau12785782012-04-27 21:37:17 +02001074 * Returns 1 if sample expression <expr> result can be converted to table key of
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001075 * type <table_type>, otherwise zero. Used in configuration check.
1076 */
Willy Tarreau12785782012-04-27 21:37:17 +02001077int stktable_compatible_sample(struct sample_expr *expr, unsigned long table_type)
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001078{
Thierry FOURNIERf73eb8f2013-11-27 15:30:55 +01001079 int out_type;
1080
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +02001081 if (table_type >= SMP_TYPES || !stktable_types[table_type].kw)
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001082 return 0;
1083
Thierry FOURNIERf73eb8f2013-11-27 15:30:55 +01001084 out_type = smp_expr_output_type(expr);
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001085
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001086 /* Convert sample. */
1087 if (!sample_casts[out_type][table_type])
Thierry FOURNIERf73eb8f2013-11-27 15:30:55 +01001088 return 0;
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001089
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001090 return 1;
1091}
Emeric Brun3bd697e2010-01-04 15:23:48 +01001092
Willy Tarreauedee1d62014-07-15 16:44:27 +02001093/* Extra data types processing : after the last one, some room may remain
1094 * before STKTABLE_DATA_TYPES that may be used to register extra data types
1095 * at run time.
1096 */
Willy Tarreau08d5f982010-06-06 13:34:54 +02001097struct stktable_data_type stktable_data_types[STKTABLE_DATA_TYPES] = {
Willy Tarreau3b9c6e02010-07-18 08:04:30 +02001098 [STKTABLE_DT_SERVER_ID] = { .name = "server_id", .std_type = STD_T_SINT },
Thierry FOURNIER3cf11112015-07-28 08:57:05 +02001099 [STKTABLE_DT_GPT0] = { .name = "gpt0", .std_type = STD_T_UINT },
Willy Tarreau3b9c6e02010-07-18 08:04:30 +02001100 [STKTABLE_DT_GPC0] = { .name = "gpc0", .std_type = STD_T_UINT },
Willy Tarreauba2ffd12013-05-29 15:54:14 +02001101 [STKTABLE_DT_GPC0_RATE] = { .name = "gpc0_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
Willy Tarreau3b9c6e02010-07-18 08:04:30 +02001102 [STKTABLE_DT_CONN_CNT] = { .name = "conn_cnt", .std_type = STD_T_UINT },
1103 [STKTABLE_DT_CONN_RATE] = { .name = "conn_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
1104 [STKTABLE_DT_CONN_CUR] = { .name = "conn_cur", .std_type = STD_T_UINT },
1105 [STKTABLE_DT_SESS_CNT] = { .name = "sess_cnt", .std_type = STD_T_UINT },
1106 [STKTABLE_DT_SESS_RATE] = { .name = "sess_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
1107 [STKTABLE_DT_HTTP_REQ_CNT] = { .name = "http_req_cnt", .std_type = STD_T_UINT },
1108 [STKTABLE_DT_HTTP_REQ_RATE] = { .name = "http_req_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
1109 [STKTABLE_DT_HTTP_ERR_CNT] = { .name = "http_err_cnt", .std_type = STD_T_UINT },
1110 [STKTABLE_DT_HTTP_ERR_RATE] = { .name = "http_err_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
1111 [STKTABLE_DT_BYTES_IN_CNT] = { .name = "bytes_in_cnt", .std_type = STD_T_ULL },
1112 [STKTABLE_DT_BYTES_IN_RATE] = { .name = "bytes_in_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
1113 [STKTABLE_DT_BYTES_OUT_CNT] = { .name = "bytes_out_cnt", .std_type = STD_T_ULL },
1114 [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 +01001115 [STKTABLE_DT_GPC1] = { .name = "gpc1", .std_type = STD_T_UINT },
1116 [STKTABLE_DT_GPC1_RATE] = { .name = "gpc1_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
Thayne McCombs92149f92020-11-20 01:28:26 -07001117 [STKTABLE_DT_SERVER_KEY] = { .name = "server_key", .std_type = STD_T_DICT },
Willy Tarreau826f3ab2021-02-10 12:07:15 +01001118 [STKTABLE_DT_HTTP_FAIL_CNT] = { .name = "http_fail_cnt", .std_type = STD_T_UINT },
1119 [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 +02001120};
1121
Willy Tarreauedee1d62014-07-15 16:44:27 +02001122/* Registers stick-table extra data type with index <idx>, name <name>, type
1123 * <std_type> and arg type <arg_type>. If the index is negative, the next free
1124 * index is automatically allocated. The allocated index is returned, or -1 if
1125 * no free index was found or <name> was already registered. The <name> is used
1126 * directly as a pointer, so if it's not stable, the caller must allocate it.
1127 */
1128int stktable_register_data_store(int idx, const char *name, int std_type, int arg_type)
1129{
1130 if (idx < 0) {
1131 for (idx = 0; idx < STKTABLE_DATA_TYPES; idx++) {
1132 if (!stktable_data_types[idx].name)
1133 break;
1134
1135 if (strcmp(stktable_data_types[idx].name, name) == 0)
1136 return -1;
1137 }
1138 }
1139
1140 if (idx >= STKTABLE_DATA_TYPES)
1141 return -1;
1142
1143 if (stktable_data_types[idx].name != NULL)
1144 return -1;
1145
1146 stktable_data_types[idx].name = name;
1147 stktable_data_types[idx].std_type = std_type;
1148 stktable_data_types[idx].arg_type = arg_type;
1149 return idx;
1150}
1151
Willy Tarreau08d5f982010-06-06 13:34:54 +02001152/*
1153 * Returns the data type number for the stktable_data_type whose name is <name>,
1154 * or <0 if not found.
1155 */
1156int stktable_get_data_type(char *name)
1157{
1158 int type;
1159
1160 for (type = 0; type < STKTABLE_DATA_TYPES; type++) {
Willy Tarreauedee1d62014-07-15 16:44:27 +02001161 if (!stktable_data_types[type].name)
1162 continue;
Willy Tarreau08d5f982010-06-06 13:34:54 +02001163 if (strcmp(name, stktable_data_types[type].name) == 0)
1164 return type;
1165 }
Thayne McCombs92149f92020-11-20 01:28:26 -07001166 /* For backwards compatibility */
1167 if (strcmp(name, "server_name") == 0)
1168 return STKTABLE_DT_SERVER_KEY;
Willy Tarreau08d5f982010-06-06 13:34:54 +02001169 return -1;
1170}
1171
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001172/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1173 * it up into this table. Returns true if found, false otherwise. The input
1174 * type is STR so that input samples are converted to string (since all types
1175 * can be converted to strings), then the function casts the string again into
1176 * the table's type. This is a double conversion, but in the future we might
1177 * support automatic input types to perform the cast on the fly.
1178 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001179static int sample_conv_in_table(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001180{
1181 struct stktable *t;
1182 struct stktable_key *key;
1183 struct stksess *ts;
1184
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001185 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001186
1187 key = smp_to_stkey(smp, t);
1188 if (!key)
1189 return 0;
1190
1191 ts = stktable_lookup_key(t, key);
1192
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001193 smp->data.type = SMP_T_BOOL;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001194 smp->data.u.sint = !!ts;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001195 smp->flags = SMP_F_VOL_TEST;
Willy Tarreau43e90352018-06-27 06:25:57 +02001196 stktable_release(t, ts);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001197 return 1;
1198}
1199
1200/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1201 * it up into this table. Returns the data rate received from clients in bytes/s
1202 * if the key is present in the table, otherwise zero, so that comparisons can
1203 * be easily performed. If the inspected parameter is not stored in the table,
1204 * <not found> is returned.
1205 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001206static int sample_conv_table_bytes_in_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001207{
1208 struct stktable *t;
1209 struct stktable_key *key;
1210 struct stksess *ts;
1211 void *ptr;
1212
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001213 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001214
1215 key = smp_to_stkey(smp, t);
1216 if (!key)
1217 return 0;
1218
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001219 ts = stktable_lookup_key(t, key);
1220
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001221 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001222 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001223 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001224
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001225 if (!ts) /* key not present */
1226 return 1;
1227
1228 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_IN_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001229 if (ptr)
1230 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, bytes_in_rate),
1231 t->data_arg[STKTABLE_DT_BYTES_IN_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001232
Daniel Corbett3e60b112018-05-27 09:47:12 -04001233 stktable_release(t, ts);
1234 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001235}
1236
1237/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1238 * it up into this table. Returns the cumulated number of connections for the key
1239 * if the key is present in the table, otherwise zero, so that comparisons can
1240 * be easily performed. If the inspected parameter is not stored in the table,
1241 * <not found> is returned.
1242 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001243static int sample_conv_table_conn_cnt(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001244{
1245 struct stktable *t;
1246 struct stktable_key *key;
1247 struct stksess *ts;
1248 void *ptr;
1249
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001250 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001251
1252 key = smp_to_stkey(smp, t);
1253 if (!key)
1254 return 0;
1255
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001256 ts = stktable_lookup_key(t, key);
1257
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001258 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001259 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001260 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001261
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001262 if (!ts) /* key not present */
1263 return 1;
1264
1265 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_CONN_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001266 if (ptr)
1267 smp->data.u.sint = stktable_data_cast(ptr, conn_cnt);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001268
Daniel Corbett3e60b112018-05-27 09:47:12 -04001269 stktable_release(t, ts);
1270 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001271}
1272
1273/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1274 * it up into this table. Returns the number of concurrent connections for the
1275 * key if the key is present in the table, otherwise zero, so that comparisons
1276 * can be easily performed. If the inspected parameter is not stored in the
1277 * table, <not found> is returned.
1278 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001279static int sample_conv_table_conn_cur(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001280{
1281 struct stktable *t;
1282 struct stktable_key *key;
1283 struct stksess *ts;
1284 void *ptr;
1285
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001286 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001287
1288 key = smp_to_stkey(smp, t);
1289 if (!key)
1290 return 0;
1291
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001292 ts = stktable_lookup_key(t, key);
1293
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001294 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001295 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001296 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001297
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001298 if (!ts) /* key not present */
1299 return 1;
1300
1301 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_CONN_CUR);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001302 if (ptr)
1303 smp->data.u.sint = stktable_data_cast(ptr, conn_cur);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001304
Daniel Corbett3e60b112018-05-27 09:47:12 -04001305 stktable_release(t, ts);
1306 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001307}
1308
1309/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1310 * it up into this table. Returns the rate of incoming connections from the key
1311 * if the key is present in the table, otherwise zero, so that comparisons can
1312 * be easily performed. If the inspected parameter is not stored in the table,
1313 * <not found> is returned.
1314 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001315static int sample_conv_table_conn_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001316{
1317 struct stktable *t;
1318 struct stktable_key *key;
1319 struct stksess *ts;
1320 void *ptr;
1321
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001322 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001323
1324 key = smp_to_stkey(smp, t);
1325 if (!key)
1326 return 0;
1327
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001328 ts = stktable_lookup_key(t, key);
1329
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001330 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001331 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001332 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001333
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001334 if (!ts) /* key not present */
1335 return 1;
1336
1337 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_CONN_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001338 if (ptr)
1339 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, conn_rate),
1340 t->data_arg[STKTABLE_DT_CONN_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001341
Daniel Corbett3e60b112018-05-27 09:47:12 -04001342 stktable_release(t, ts);
1343 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001344}
1345
1346/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1347 * it up into this table. Returns the data rate sent to clients in bytes/s
1348 * if the key is present in the table, otherwise zero, so that comparisons can
1349 * be easily performed. If the inspected parameter is not stored in the table,
1350 * <not found> is returned.
1351 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001352static int sample_conv_table_bytes_out_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001353{
1354 struct stktable *t;
1355 struct stktable_key *key;
1356 struct stksess *ts;
1357 void *ptr;
1358
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001359 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001360
1361 key = smp_to_stkey(smp, t);
1362 if (!key)
1363 return 0;
1364
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001365 ts = stktable_lookup_key(t, key);
1366
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001367 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001368 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001369 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001370
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001371 if (!ts) /* key not present */
1372 return 1;
1373
1374 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_OUT_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001375 if (ptr)
1376 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, bytes_out_rate),
1377 t->data_arg[STKTABLE_DT_BYTES_OUT_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001378
Daniel Corbett3e60b112018-05-27 09:47:12 -04001379 stktable_release(t, ts);
1380 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001381}
1382
1383/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001384 * it up into this table. Returns the value of the GPT0 tag for the key
1385 * if the key is present in the table, otherwise false, so that comparisons can
1386 * be easily performed. If the inspected parameter is not stored in the table,
1387 * <not found> is returned.
1388 */
1389static int sample_conv_table_gpt0(const struct arg *arg_p, struct sample *smp, void *private)
1390{
1391 struct stktable *t;
1392 struct stktable_key *key;
1393 struct stksess *ts;
1394 void *ptr;
1395
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001396 t = arg_p[0].data.t;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001397
1398 key = smp_to_stkey(smp, t);
1399 if (!key)
1400 return 0;
1401
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001402 ts = stktable_lookup_key(t, key);
1403
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001404 smp->flags = SMP_F_VOL_TEST;
1405 smp->data.type = SMP_T_SINT;
1406 smp->data.u.sint = 0;
1407
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001408 if (!ts) /* key not present */
1409 return 1;
1410
1411 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPT0);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001412 if (ptr)
1413 smp->data.u.sint = stktable_data_cast(ptr, gpt0);
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001414
Daniel Corbett3e60b112018-05-27 09:47:12 -04001415 stktable_release(t, ts);
1416 return !!ptr;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001417}
1418
1419/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001420 * it up into this table. Returns the value of the GPC0 counter for the key
1421 * if the key is present in the table, otherwise zero, so that comparisons can
1422 * be easily performed. If the inspected parameter is not stored in the table,
1423 * <not found> is returned.
1424 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001425static int sample_conv_table_gpc0(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001426{
1427 struct stktable *t;
1428 struct stktable_key *key;
1429 struct stksess *ts;
1430 void *ptr;
1431
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001432 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001433
1434 key = smp_to_stkey(smp, t);
1435 if (!key)
1436 return 0;
1437
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001438 ts = stktable_lookup_key(t, key);
1439
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001440 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001441 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001442 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001443
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001444 if (!ts) /* key not present */
1445 return 1;
1446
1447 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPC0);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001448 if (ptr)
1449 smp->data.u.sint = stktable_data_cast(ptr, gpc0);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001450
Daniel Corbett3e60b112018-05-27 09:47:12 -04001451 stktable_release(t, ts);
1452 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001453}
1454
1455/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1456 * it up into this table. Returns the event rate of the GPC0 counter for the key
1457 * if the key is present in the table, otherwise zero, so that comparisons can
1458 * be easily performed. If the inspected parameter is not stored in the table,
1459 * <not found> is returned.
1460 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001461static int sample_conv_table_gpc0_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001462{
1463 struct stktable *t;
1464 struct stktable_key *key;
1465 struct stksess *ts;
1466 void *ptr;
1467
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001468 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001469
1470 key = smp_to_stkey(smp, t);
1471 if (!key)
1472 return 0;
1473
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001474 ts = stktable_lookup_key(t, key);
1475
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001476 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001477 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001478 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001479
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001480 if (!ts) /* key not present */
1481 return 1;
1482
1483 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPC0_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001484 if (ptr)
1485 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, gpc0_rate),
1486 t->data_arg[STKTABLE_DT_GPC0_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001487
Daniel Corbett3e60b112018-05-27 09:47:12 -04001488 stktable_release(t, ts);
1489 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001490}
1491
1492/* 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 +01001493 * it up into this table. Returns the value of the GPC1 counter for the key
1494 * if the key is present in the table, otherwise zero, so that comparisons can
1495 * be easily performed. If the inspected parameter is not stored in the table,
1496 * <not found> is returned.
1497 */
1498static int sample_conv_table_gpc1(const struct arg *arg_p, struct sample *smp, void *private)
1499{
1500 struct stktable *t;
1501 struct stktable_key *key;
1502 struct stksess *ts;
1503 void *ptr;
1504
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001505 t = arg_p[0].data.t;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001506
1507 key = smp_to_stkey(smp, t);
1508 if (!key)
1509 return 0;
1510
1511 ts = stktable_lookup_key(t, key);
1512
1513 smp->flags = SMP_F_VOL_TEST;
1514 smp->data.type = SMP_T_SINT;
1515 smp->data.u.sint = 0;
1516
1517 if (!ts) /* key not present */
1518 return 1;
1519
1520 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPC1);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001521 if (ptr)
1522 smp->data.u.sint = stktable_data_cast(ptr, gpc1);
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001523
Daniel Corbett3e60b112018-05-27 09:47:12 -04001524 stktable_release(t, ts);
1525 return !!ptr;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001526}
1527
1528/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1529 * it up into this table. Returns the event rate of the GPC1 counter for the key
1530 * if the key is present in the table, otherwise zero, so that comparisons can
1531 * be easily performed. If the inspected parameter is not stored in the table,
1532 * <not found> is returned.
1533 */
1534static int sample_conv_table_gpc1_rate(const struct arg *arg_p, struct sample *smp, void *private)
1535{
1536 struct stktable *t;
1537 struct stktable_key *key;
1538 struct stksess *ts;
1539 void *ptr;
1540
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001541 t = arg_p[0].data.t;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001542
1543 key = smp_to_stkey(smp, t);
1544 if (!key)
1545 return 0;
1546
1547 ts = stktable_lookup_key(t, key);
1548
1549 smp->flags = SMP_F_VOL_TEST;
1550 smp->data.type = SMP_T_SINT;
1551 smp->data.u.sint = 0;
1552
1553 if (!ts) /* key not present */
1554 return 1;
1555
1556 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPC1_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001557 if (ptr)
1558 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, gpc1_rate),
1559 t->data_arg[STKTABLE_DT_GPC1_RATE].u);
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001560
Daniel Corbett3e60b112018-05-27 09:47:12 -04001561 stktable_release(t, ts);
1562 return !!ptr;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001563}
1564
1565/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001566 * it up into this table. Returns the cumulated number of HTTP request errors
1567 * for the key if the key is present in the table, otherwise zero, so that
1568 * comparisons can be easily performed. If the inspected parameter is not stored
1569 * in the table, <not found> is returned.
1570 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001571static int sample_conv_table_http_err_cnt(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001572{
1573 struct stktable *t;
1574 struct stktable_key *key;
1575 struct stksess *ts;
1576 void *ptr;
1577
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001578 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001579
1580 key = smp_to_stkey(smp, t);
1581 if (!key)
1582 return 0;
1583
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001584 ts = stktable_lookup_key(t, key);
1585
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001586 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001587 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001588 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001589
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001590 if (!ts) /* key not present */
1591 return 1;
1592
1593 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_ERR_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001594 if (ptr)
1595 smp->data.u.sint = stktable_data_cast(ptr, http_err_cnt);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001596
Daniel Corbett3e60b112018-05-27 09:47:12 -04001597 stktable_release(t, ts);
1598 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001599}
1600
1601/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1602 * it up into this table. Returns the HTTP request error rate the key
1603 * if the key is present in the table, otherwise zero, so that comparisons can
1604 * be easily performed. If the inspected parameter is not stored in the table,
1605 * <not found> is returned.
1606 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001607static int sample_conv_table_http_err_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001608{
1609 struct stktable *t;
1610 struct stktable_key *key;
1611 struct stksess *ts;
1612 void *ptr;
1613
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001614 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001615
1616 key = smp_to_stkey(smp, t);
1617 if (!key)
1618 return 0;
1619
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001620 ts = stktable_lookup_key(t, key);
1621
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001622 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001623 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001624 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001625
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001626 if (!ts) /* key not present */
1627 return 1;
1628
1629 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_ERR_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001630 if (ptr)
1631 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, http_err_rate),
1632 t->data_arg[STKTABLE_DT_HTTP_ERR_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001633
Daniel Corbett3e60b112018-05-27 09:47:12 -04001634 stktable_release(t, ts);
1635 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001636}
1637
1638/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Willy Tarreau826f3ab2021-02-10 12:07:15 +01001639 * it up into this table. Returns the cumulated number of HTTP response failures
1640 * for the key if the key is present in the table, otherwise zero, so that
1641 * comparisons can be easily performed. If the inspected parameter is not stored
1642 * in the table, <not found> is returned.
1643 */
1644static int sample_conv_table_http_fail_cnt(const struct arg *arg_p, struct sample *smp, void *private)
1645{
1646 struct stktable *t;
1647 struct stktable_key *key;
1648 struct stksess *ts;
1649 void *ptr;
1650
1651 t = arg_p[0].data.t;
1652
1653 key = smp_to_stkey(smp, t);
1654 if (!key)
1655 return 0;
1656
1657 ts = stktable_lookup_key(t, key);
1658
1659 smp->flags = SMP_F_VOL_TEST;
1660 smp->data.type = SMP_T_SINT;
1661 smp->data.u.sint = 0;
1662
1663 if (!ts) /* key not present */
1664 return 1;
1665
1666 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_FAIL_CNT);
1667 if (ptr)
1668 smp->data.u.sint = stktable_data_cast(ptr, http_fail_cnt);
1669
1670 stktable_release(t, ts);
1671 return !!ptr;
1672}
1673
1674/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1675 * it up into this table. Returns the HTTP response failure rate for the key
1676 * if the key is present in the table, otherwise zero, so that comparisons can
1677 * be easily performed. If the inspected parameter is not stored in the table,
1678 * <not found> is returned.
1679 */
1680static int sample_conv_table_http_fail_rate(const struct arg *arg_p, struct sample *smp, void *private)
1681{
1682 struct stktable *t;
1683 struct stktable_key *key;
1684 struct stksess *ts;
1685 void *ptr;
1686
1687 t = arg_p[0].data.t;
1688
1689 key = smp_to_stkey(smp, t);
1690 if (!key)
1691 return 0;
1692
1693 ts = stktable_lookup_key(t, key);
1694
1695 smp->flags = SMP_F_VOL_TEST;
1696 smp->data.type = SMP_T_SINT;
1697 smp->data.u.sint = 0;
1698
1699 if (!ts) /* key not present */
1700 return 1;
1701
1702 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_FAIL_RATE);
1703 if (ptr)
1704 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, http_fail_rate),
1705 t->data_arg[STKTABLE_DT_HTTP_FAIL_RATE].u);
1706
1707 stktable_release(t, ts);
1708 return !!ptr;
1709}
1710
1711/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001712 * it up into this table. Returns the cumulated number of HTTP request for the
1713 * key if the key is present in the table, otherwise zero, so that comparisons
1714 * can be easily performed. If the inspected parameter is not stored in the
1715 * table, <not found> is returned.
1716 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001717static int sample_conv_table_http_req_cnt(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001718{
1719 struct stktable *t;
1720 struct stktable_key *key;
1721 struct stksess *ts;
1722 void *ptr;
1723
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001724 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001725
1726 key = smp_to_stkey(smp, t);
1727 if (!key)
1728 return 0;
1729
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001730 ts = stktable_lookup_key(t, key);
1731
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001732 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001733 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001734 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001735
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001736 if (!ts) /* key not present */
1737 return 1;
1738
1739 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_REQ_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001740 if (ptr)
1741 smp->data.u.sint = stktable_data_cast(ptr, http_req_cnt);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001742
Daniel Corbett3e60b112018-05-27 09:47:12 -04001743 stktable_release(t, ts);
1744 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001745}
1746
1747/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1748 * it up into this table. Returns the HTTP request rate the key if the key is
1749 * present in the table, otherwise zero, so that comparisons can be easily
1750 * performed. If the inspected parameter is not stored in the table, <not found>
1751 * is returned.
1752 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001753static int sample_conv_table_http_req_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001754{
1755 struct stktable *t;
1756 struct stktable_key *key;
1757 struct stksess *ts;
1758 void *ptr;
1759
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001760 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001761
1762 key = smp_to_stkey(smp, t);
1763 if (!key)
1764 return 0;
1765
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001766 ts = stktable_lookup_key(t, key);
1767
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001768 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001769 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001770 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001771
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001772 if (!ts) /* key not present */
1773 return 1;
1774
1775 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_REQ_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001776 if (ptr)
1777 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, http_req_rate),
1778 t->data_arg[STKTABLE_DT_HTTP_REQ_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001779
Daniel Corbett3e60b112018-05-27 09:47:12 -04001780 stktable_release(t, ts);
1781 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001782}
1783
1784/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1785 * it up into this table. Returns the volume of datareceived from clients in kbytes
1786 * if the key is present in the table, otherwise zero, so that comparisons can
1787 * be easily performed. If the inspected parameter is not stored in the table,
1788 * <not found> is returned.
1789 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001790static int sample_conv_table_kbytes_in(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001791{
1792 struct stktable *t;
1793 struct stktable_key *key;
1794 struct stksess *ts;
1795 void *ptr;
1796
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001797 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001798
1799 key = smp_to_stkey(smp, t);
1800 if (!key)
1801 return 0;
1802
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001803 ts = stktable_lookup_key(t, key);
1804
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001805 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001806 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001807 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001808
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001809 if (!ts) /* key not present */
1810 return 1;
1811
1812 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_IN_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001813 if (ptr)
1814 smp->data.u.sint = stktable_data_cast(ptr, bytes_in_cnt) >> 10;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001815
Daniel Corbett3e60b112018-05-27 09:47:12 -04001816 stktable_release(t, ts);
1817 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001818}
1819
1820/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1821 * it up into this table. Returns the volume of data sent to clients in kbytes
1822 * if the key is present in the table, otherwise zero, so that comparisons can
1823 * be easily performed. If the inspected parameter is not stored in the table,
1824 * <not found> is returned.
1825 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001826static int sample_conv_table_kbytes_out(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001827{
1828 struct stktable *t;
1829 struct stktable_key *key;
1830 struct stksess *ts;
1831 void *ptr;
1832
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001833 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001834
1835 key = smp_to_stkey(smp, t);
1836 if (!key)
1837 return 0;
1838
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001839 ts = stktable_lookup_key(t, key);
1840
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001841 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001842 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001843 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001844
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001845 if (!ts) /* key not present */
1846 return 1;
1847
1848 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_OUT_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001849 if (ptr)
1850 smp->data.u.sint = stktable_data_cast(ptr, bytes_out_cnt) >> 10;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001851
Daniel Corbett3e60b112018-05-27 09:47:12 -04001852 stktable_release(t, ts);
1853 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001854}
1855
1856/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1857 * it up into this table. Returns the server ID associated with the key if the
1858 * key is present in the table, otherwise zero, so that comparisons can be
1859 * easily performed. If the inspected parameter is not stored in the table,
1860 * <not found> is returned.
1861 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001862static int sample_conv_table_server_id(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001863{
1864 struct stktable *t;
1865 struct stktable_key *key;
1866 struct stksess *ts;
1867 void *ptr;
1868
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001869 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001870
1871 key = smp_to_stkey(smp, t);
1872 if (!key)
1873 return 0;
1874
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001875 ts = stktable_lookup_key(t, key);
1876
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001877 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001878 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001879 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001880
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001881 if (!ts) /* key not present */
1882 return 1;
1883
1884 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_SERVER_ID);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001885 if (ptr)
1886 smp->data.u.sint = stktable_data_cast(ptr, server_id);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001887
Daniel Corbett3e60b112018-05-27 09:47:12 -04001888 stktable_release(t, ts);
1889 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001890}
1891
1892/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1893 * it up into this table. Returns the cumulated number of sessions for the
1894 * key if the key is present in the table, otherwise zero, so that comparisons
1895 * can be easily performed. If the inspected parameter is not stored in the
1896 * table, <not found> is returned.
1897 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001898static int sample_conv_table_sess_cnt(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001899{
1900 struct stktable *t;
1901 struct stktable_key *key;
1902 struct stksess *ts;
1903 void *ptr;
1904
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001905 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001906
1907 key = smp_to_stkey(smp, t);
1908 if (!key)
1909 return 0;
1910
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001911 ts = stktable_lookup_key(t, key);
1912
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001913 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001914 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001915 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001916
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001917 if (!ts) /* key not present */
1918 return 1;
1919
1920 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_SESS_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001921 if (ptr)
1922 smp->data.u.sint = stktable_data_cast(ptr, sess_cnt);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001923
Daniel Corbett3e60b112018-05-27 09:47:12 -04001924 stktable_release(t, ts);
1925 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001926}
1927
1928/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1929 * it up into this table. Returns the session rate the key if the key is
1930 * present in the table, otherwise zero, so that comparisons can be easily
1931 * performed. If the inspected parameter is not stored in the table, <not found>
1932 * is returned.
1933 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001934static int sample_conv_table_sess_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001935{
1936 struct stktable *t;
1937 struct stktable_key *key;
1938 struct stksess *ts;
1939 void *ptr;
1940
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001941 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001942
1943 key = smp_to_stkey(smp, t);
1944 if (!key)
1945 return 0;
1946
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001947 ts = stktable_lookup_key(t, key);
1948
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001949 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001950 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001951 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001952
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001953 if (!ts) /* key not present */
1954 return 1;
1955
1956 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_SESS_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001957 if (ptr)
1958 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, sess_rate),
1959 t->data_arg[STKTABLE_DT_SESS_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001960
Daniel Corbett3e60b112018-05-27 09:47:12 -04001961 stktable_release(t, ts);
1962 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001963}
1964
1965/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1966 * it up into this table. Returns the amount of concurrent connections tracking
1967 * the same key if the key is present in the table, otherwise zero, so that
1968 * comparisons can be easily performed. If the inspected parameter is not
1969 * stored in the table, <not found> is returned.
1970 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001971static int sample_conv_table_trackers(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001972{
1973 struct stktable *t;
1974 struct stktable_key *key;
1975 struct stksess *ts;
1976
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001977 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001978
1979 key = smp_to_stkey(smp, t);
1980 if (!key)
1981 return 0;
1982
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001983 ts = stktable_lookup_key(t, key);
1984
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001985 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001986 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001987 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001988
Tim Duesterhus65189c12018-06-26 15:57:29 +02001989 if (!ts)
1990 return 1;
1991
1992 smp->data.u.sint = ts->ref_cnt;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001993
Daniel Corbett3e60b112018-05-27 09:47:12 -04001994 stktable_release(t, ts);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001995 return 1;
1996}
1997
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001998/* Always returns 1. */
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001999static enum act_return action_inc_gpc0(struct act_rule *rule, struct proxy *px,
Willy Tarreau658b85b2015-09-27 10:00:49 +02002000 struct session *sess, struct stream *s, int flags)
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002001{
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002002 struct stksess *ts;
2003 struct stkctr *stkctr;
2004
2005 /* Extract the stksess, return OK if no stksess available. */
2006 if (s)
2007 stkctr = &s->stkctr[rule->arg.gpc.sc];
2008 else
2009 stkctr = &sess->stkctr[rule->arg.gpc.sc];
Willy Tarreau79c1e912016-01-25 14:54:45 +01002010
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002011 ts = stkctr_entry(stkctr);
Willy Tarreau79c1e912016-01-25 14:54:45 +01002012 if (ts) {
2013 void *ptr1, *ptr2;
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002014
Willy Tarreau79c1e912016-01-25 14:54:45 +01002015 /* First, update gpc0_rate if it's tracked. Second, update its gpc0 if tracked. */
2016 ptr1 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC0_RATE);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002017 ptr2 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC0);
2018 if (ptr1 || ptr2) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002019 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002020
2021 if (ptr1)
2022 update_freq_ctr_period(&stktable_data_cast(ptr1, gpc0_rate),
Willy Tarreau79c1e912016-01-25 14:54:45 +01002023 stkctr->table->data_arg[STKTABLE_DT_GPC0_RATE].u, 1);
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002024
Emeric Brun819fc6f2017-06-13 19:37:32 +02002025 if (ptr2)
2026 stktable_data_cast(ptr2, gpc0)++;
Willy Tarreau79c1e912016-01-25 14:54:45 +01002027
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002028 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002029
2030 /* If data was modified, we need to touch to re-schedule sync */
2031 stktable_touch_local(stkctr->table, ts, 0);
2032 }
Willy Tarreau79c1e912016-01-25 14:54:45 +01002033 }
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002034 return ACT_RET_CONT;
2035}
2036
2037/* This function is a common parser for using variables. It understands
2038 * the formats:
2039 *
2040 * sc-inc-gpc0(<stick-table ID>)
2041 *
2042 * It returns 0 if fails and <err> is filled with an error message. Otherwise,
2043 * it returns 1 and the variable <expr> is filled with the pointer to the
2044 * expression to execute.
2045 */
2046static enum act_parse_ret parse_inc_gpc0(const char **args, int *arg, struct proxy *px,
2047 struct act_rule *rule, char **err)
2048{
2049 const char *cmd_name = args[*arg-1];
2050 char *error;
2051
2052 cmd_name += strlen("sc-inc-gpc0");
2053 if (*cmd_name == '\0') {
2054 /* default stick table id. */
2055 rule->arg.gpc.sc = 0;
2056 } else {
2057 /* parse the stick table id. */
2058 if (*cmd_name != '(') {
2059 memprintf(err, "invalid stick table track ID. Expects %s(<Track ID>)", args[*arg-1]);
2060 return ACT_RET_PRS_ERR;
2061 }
2062 cmd_name++; /* jump the '(' */
2063 rule->arg.gpc.sc = strtol(cmd_name, &error, 10); /* Convert stick table id. */
2064 if (*error != ')') {
2065 memprintf(err, "invalid stick table track ID. Expects %s(<Track ID>)", args[*arg-1]);
2066 return ACT_RET_PRS_ERR;
2067 }
2068
Christopher Faulet28436e22019-12-18 10:25:46 +01002069 if (rule->arg.gpc.sc >= MAX_SESS_STKCTR) {
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002070 memprintf(err, "invalid stick table track ID. The max allowed ID is %d",
Christopher Faulet28436e22019-12-18 10:25:46 +01002071 MAX_SESS_STKCTR-1);
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002072 return ACT_RET_PRS_ERR;
2073 }
2074 }
Thierry FOURNIER42148732015-09-02 17:17:33 +02002075 rule->action = ACT_CUSTOM;
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002076 rule->action_ptr = action_inc_gpc0;
2077 return ACT_RET_PRS_OK;
2078}
2079
2080/* Always returns 1. */
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002081static enum act_return action_inc_gpc1(struct act_rule *rule, struct proxy *px,
2082 struct session *sess, struct stream *s, int flags)
2083{
2084 struct stksess *ts;
2085 struct stkctr *stkctr;
2086
2087 /* Extract the stksess, return OK if no stksess available. */
2088 if (s)
2089 stkctr = &s->stkctr[rule->arg.gpc.sc];
2090 else
2091 stkctr = &sess->stkctr[rule->arg.gpc.sc];
2092
2093 ts = stkctr_entry(stkctr);
2094 if (ts) {
2095 void *ptr1, *ptr2;
2096
2097 /* First, update gpc1_rate if it's tracked. Second, update its gpc1 if tracked. */
2098 ptr1 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC1_RATE);
2099 ptr2 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC1);
2100 if (ptr1 || ptr2) {
2101 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
2102
2103 if (ptr1)
2104 update_freq_ctr_period(&stktable_data_cast(ptr1, gpc1_rate),
2105 stkctr->table->data_arg[STKTABLE_DT_GPC1_RATE].u, 1);
2106
2107 if (ptr2)
2108 stktable_data_cast(ptr2, gpc1)++;
2109
2110 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
2111
2112 /* If data was modified, we need to touch to re-schedule sync */
2113 stktable_touch_local(stkctr->table, ts, 0);
2114 }
2115 }
2116 return ACT_RET_CONT;
2117}
2118
2119/* This function is a common parser for using variables. It understands
2120 * the formats:
2121 *
2122 * sc-inc-gpc1(<stick-table ID>)
2123 *
2124 * It returns 0 if fails and <err> is filled with an error message. Otherwise,
2125 * it returns 1 and the variable <expr> is filled with the pointer to the
2126 * expression to execute.
2127 */
2128static enum act_parse_ret parse_inc_gpc1(const char **args, int *arg, struct proxy *px,
2129 struct act_rule *rule, char **err)
2130{
2131 const char *cmd_name = args[*arg-1];
2132 char *error;
2133
2134 cmd_name += strlen("sc-inc-gpc1");
2135 if (*cmd_name == '\0') {
2136 /* default stick table id. */
2137 rule->arg.gpc.sc = 0;
2138 } else {
2139 /* parse the stick table id. */
2140 if (*cmd_name != '(') {
2141 memprintf(err, "invalid stick table track ID. Expects %s(<Track ID>)", args[*arg-1]);
2142 return ACT_RET_PRS_ERR;
2143 }
2144 cmd_name++; /* jump the '(' */
2145 rule->arg.gpc.sc = strtol(cmd_name, &error, 10); /* Convert stick table id. */
2146 if (*error != ')') {
2147 memprintf(err, "invalid stick table track ID. Expects %s(<Track ID>)", args[*arg-1]);
2148 return ACT_RET_PRS_ERR;
2149 }
2150
Christopher Faulet28436e22019-12-18 10:25:46 +01002151 if (rule->arg.gpc.sc >= MAX_SESS_STKCTR) {
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002152 memprintf(err, "invalid stick table track ID. The max allowed ID is %d",
Christopher Faulet28436e22019-12-18 10:25:46 +01002153 MAX_SESS_STKCTR-1);
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002154 return ACT_RET_PRS_ERR;
2155 }
2156 }
2157 rule->action = ACT_CUSTOM;
2158 rule->action_ptr = action_inc_gpc1;
2159 return ACT_RET_PRS_OK;
2160}
2161
2162/* Always returns 1. */
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002163static enum act_return action_set_gpt0(struct act_rule *rule, struct proxy *px,
Willy Tarreau658b85b2015-09-27 10:00:49 +02002164 struct session *sess, struct stream *s, int flags)
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002165{
2166 void *ptr;
2167 struct stksess *ts;
2168 struct stkctr *stkctr;
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002169 unsigned int value = 0;
2170 struct sample *smp;
2171 int smp_opt_dir;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002172
2173 /* Extract the stksess, return OK if no stksess available. */
2174 if (s)
2175 stkctr = &s->stkctr[rule->arg.gpt.sc];
2176 else
2177 stkctr = &sess->stkctr[rule->arg.gpt.sc];
Willy Tarreau79c1e912016-01-25 14:54:45 +01002178
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002179 ts = stkctr_entry(stkctr);
2180 if (!ts)
2181 return ACT_RET_CONT;
2182
2183 /* Store the sample in the required sc, and ignore errors. */
2184 ptr = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPT0);
Willy Tarreau79c1e912016-01-25 14:54:45 +01002185 if (ptr) {
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002186 if (!rule->arg.gpt.expr)
2187 value = (unsigned int)(rule->arg.gpt.value);
2188 else {
2189 switch (rule->from) {
2190 case ACT_F_TCP_REQ_SES: smp_opt_dir = SMP_OPT_DIR_REQ; break;
2191 case ACT_F_TCP_REQ_CNT: smp_opt_dir = SMP_OPT_DIR_REQ; break;
2192 case ACT_F_TCP_RES_CNT: smp_opt_dir = SMP_OPT_DIR_RES; break;
2193 case ACT_F_HTTP_REQ: smp_opt_dir = SMP_OPT_DIR_REQ; break;
2194 case ACT_F_HTTP_RES: smp_opt_dir = SMP_OPT_DIR_RES; break;
2195 default:
2196 send_log(px, LOG_ERR, "stick table: internal error while setting gpt0.");
2197 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))
2198 ha_alert("stick table: internal error while executing setting gpt0.\n");
2199 return ACT_RET_CONT;
2200 }
2201
2202 /* Fetch and cast the expression. */
2203 smp = sample_fetch_as_type(px, sess, s, smp_opt_dir|SMP_OPT_FINAL, rule->arg.gpt.expr, SMP_T_SINT);
2204 if (!smp) {
2205 send_log(px, LOG_WARNING, "stick table: invalid expression or data type while setting gpt0.");
2206 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))
2207 ha_alert("stick table: invalid expression or data type while setting gpt0.\n");
2208 return ACT_RET_CONT;
2209 }
2210 value = (unsigned int)(smp->data.u.sint);
2211 }
2212
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002213 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002214
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002215 stktable_data_cast(ptr, gpt0) = value;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002216
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002217 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002218
2219 stktable_touch_local(stkctr->table, ts, 0);
Willy Tarreau79c1e912016-01-25 14:54:45 +01002220 }
2221
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002222 return ACT_RET_CONT;
2223}
2224
2225/* This function is a common parser for using variables. It understands
2226 * the format:
2227 *
2228 * set-gpt0(<stick-table ID>) <expression>
2229 *
2230 * It returns 0 if fails and <err> is filled with an error message. Otherwise,
2231 * it returns 1 and the variable <expr> is filled with the pointer to the
2232 * expression to execute.
2233 */
2234static enum act_parse_ret parse_set_gpt0(const char **args, int *arg, struct proxy *px,
2235 struct act_rule *rule, char **err)
2236
2237
2238{
2239 const char *cmd_name = args[*arg-1];
2240 char *error;
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002241 int smp_val;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002242
2243 cmd_name += strlen("sc-set-gpt0");
2244 if (*cmd_name == '\0') {
2245 /* default stick table id. */
2246 rule->arg.gpt.sc = 0;
2247 } else {
2248 /* parse the stick table id. */
2249 if (*cmd_name != '(') {
2250 memprintf(err, "invalid stick table track ID '%s'. Expects sc-set-gpt0(<Track ID>)", args[*arg-1]);
2251 return ACT_RET_PRS_ERR;
2252 }
2253 cmd_name++; /* jump the '(' */
2254 rule->arg.gpt.sc = strtol(cmd_name, &error, 10); /* Convert stick table id. */
2255 if (*error != ')') {
2256 memprintf(err, "invalid stick table track ID '%s'. Expects sc-set-gpt0(<Track ID>)", args[*arg-1]);
2257 return ACT_RET_PRS_ERR;
2258 }
2259
Christopher Faulet28436e22019-12-18 10:25:46 +01002260 if (rule->arg.gpt.sc >= MAX_SESS_STKCTR) {
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002261 memprintf(err, "invalid stick table track ID '%s'. The max allowed ID is %d",
Christopher Faulet28436e22019-12-18 10:25:46 +01002262 args[*arg-1], MAX_SESS_STKCTR-1);
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002263 return ACT_RET_PRS_ERR;
2264 }
2265 }
2266
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002267 rule->arg.gpt.expr = NULL;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002268 rule->arg.gpt.value = strtol(args[*arg], &error, 10);
2269 if (*error != '\0') {
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002270 rule->arg.gpt.expr = sample_parse_expr((char **)args, arg, px->conf.args.file,
Willy Tarreaue3b57bf2020-02-14 16:50:14 +01002271 px->conf.args.line, err, &px->conf.args, NULL);
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002272 if (!rule->arg.gpt.expr)
2273 return ACT_RET_PRS_ERR;
2274
2275 switch (rule->from) {
2276 case ACT_F_TCP_REQ_SES: smp_val = SMP_VAL_FE_SES_ACC; break;
2277 case ACT_F_TCP_REQ_CNT: smp_val = SMP_VAL_FE_REQ_CNT; break;
2278 case ACT_F_TCP_RES_CNT: smp_val = SMP_VAL_BE_RES_CNT; break;
2279 case ACT_F_HTTP_REQ: smp_val = SMP_VAL_FE_HRQ_HDR; break;
2280 case ACT_F_HTTP_RES: smp_val = SMP_VAL_BE_HRS_HDR; break;
2281 default:
2282 memprintf(err, "internal error, unexpected rule->from=%d, please report this bug!", rule->from);
2283 return ACT_RET_PRS_ERR;
2284 }
2285 if (!(rule->arg.gpt.expr->fetch->val & smp_val)) {
2286 memprintf(err, "fetch method '%s' extracts information from '%s', none of which is available here", args[*arg-1],
2287 sample_src_names(rule->arg.gpt.expr->fetch->use));
2288 free(rule->arg.gpt.expr);
2289 return ACT_RET_PRS_ERR;
2290 }
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002291 }
2292 (*arg)++;
2293
Thierry FOURNIER42148732015-09-02 17:17:33 +02002294 rule->action = ACT_CUSTOM;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002295 rule->action_ptr = action_set_gpt0;
2296
2297 return ACT_RET_PRS_OK;
2298}
2299
Willy Tarreau7d562212016-11-25 16:10:05 +01002300/* set temp integer to the number of used entries in the table pointed to by expr.
2301 * Accepts exactly 1 argument of type table.
2302 */
2303static int
2304smp_fetch_table_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
2305{
2306 smp->flags = SMP_F_VOL_TEST;
2307 smp->data.type = SMP_T_SINT;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002308 smp->data.u.sint = args->data.t->current;
Willy Tarreau7d562212016-11-25 16:10:05 +01002309 return 1;
2310}
2311
2312/* set temp integer to the number of free entries in the table pointed to by expr.
2313 * Accepts exactly 1 argument of type table.
2314 */
2315static int
2316smp_fetch_table_avl(const struct arg *args, struct sample *smp, const char *kw, void *private)
2317{
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002318 struct stktable *t;
Willy Tarreau7d562212016-11-25 16:10:05 +01002319
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002320 t = args->data.t;
Willy Tarreau7d562212016-11-25 16:10:05 +01002321 smp->flags = SMP_F_VOL_TEST;
2322 smp->data.type = SMP_T_SINT;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002323 smp->data.u.sint = t->size - t->current;
Willy Tarreau7d562212016-11-25 16:10:05 +01002324 return 1;
2325}
2326
2327/* Returns a pointer to a stkctr depending on the fetch keyword name.
2328 * It is designed to be called as sc[0-9]_* sc_* or src_* exclusively.
2329 * sc[0-9]_* will return a pointer to the respective field in the
2330 * stream <l4>. sc_* requires an UINT argument specifying the stick
2331 * counter number. src_* will fill a locally allocated structure with
2332 * the table and entry corresponding to what is specified with src_*.
2333 * NULL may be returned if the designated stkctr is not tracked. For
2334 * the sc_* and sc[0-9]_* forms, an optional table argument may be
2335 * passed. When present, the currently tracked key is then looked up
2336 * in the specified table instead of the current table. The purpose is
Ilya Shipitsin47d17182020-06-21 21:42:57 +05002337 * to be able to convert multiple values per key (eg: have gpc0 from
Willy Tarreau7d562212016-11-25 16:10:05 +01002338 * multiple tables). <strm> is allowed to be NULL, in which case only
2339 * the session will be consulted.
2340 */
2341struct stkctr *
Emeric Brun819fc6f2017-06-13 19:37:32 +02002342smp_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 +01002343{
Willy Tarreau7d562212016-11-25 16:10:05 +01002344 struct stkctr *stkptr;
2345 struct stksess *stksess;
2346 unsigned int num = kw[2] - '0';
2347 int arg = 0;
2348
2349 if (num == '_' - '0') {
2350 /* sc_* variant, args[0] = ctr# (mandatory) */
2351 num = args[arg++].data.sint;
Willy Tarreau7d562212016-11-25 16:10:05 +01002352 }
2353 else if (num > 9) { /* src_* variant, args[0] = table */
2354 struct stktable_key *key;
2355 struct connection *conn = objt_conn(sess->origin);
2356 struct sample smp;
2357
2358 if (!conn)
2359 return NULL;
2360
Joseph Herlant5662fa42018-11-15 13:43:28 -08002361 /* Fetch source address in a sample. */
Willy Tarreau7d562212016-11-25 16:10:05 +01002362 smp.px = NULL;
2363 smp.sess = sess;
2364 smp.strm = strm;
Amaury Denoyellec460c702021-05-12 10:17:47 +02002365 if (!smp_fetch_src || !smp_fetch_src(empty_arg_list, &smp, "src", NULL))
Willy Tarreau7d562212016-11-25 16:10:05 +01002366 return NULL;
2367
2368 /* Converts into key. */
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002369 key = smp_to_stkey(&smp, args->data.t);
Willy Tarreau7d562212016-11-25 16:10:05 +01002370 if (!key)
2371 return NULL;
2372
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002373 stkctr->table = args->data.t;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002374 stkctr_set_entry(stkctr, stktable_lookup_key(stkctr->table, key));
2375 return stkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002376 }
2377
2378 /* Here, <num> contains the counter number from 0 to 9 for
2379 * the sc[0-9]_ form, or even higher using sc_(num) if needed.
2380 * args[arg] is the first optional argument. We first lookup the
2381 * ctr form the stream, then from the session if it was not there.
Christopher Fauleta9fa88a2019-10-21 10:53:34 +02002382 * But we must be sure the counter does not exceed MAX_SESS_STKCTR.
Willy Tarreau7d562212016-11-25 16:10:05 +01002383 */
Christopher Fauleta9fa88a2019-10-21 10:53:34 +02002384 if (num >= MAX_SESS_STKCTR)
2385 return NULL;
Willy Tarreau7d562212016-11-25 16:10:05 +01002386
2387 if (strm)
2388 stkptr = &strm->stkctr[num];
2389 if (!strm || !stkctr_entry(stkptr)) {
2390 stkptr = &sess->stkctr[num];
2391 if (!stkctr_entry(stkptr))
2392 return NULL;
2393 }
2394
2395 stksess = stkctr_entry(stkptr);
2396 if (!stksess)
2397 return NULL;
2398
2399 if (unlikely(args[arg].type == ARGT_TAB)) {
2400 /* an alternate table was specified, let's look up the same key there */
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002401 stkctr->table = args[arg].data.t;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002402 stkctr_set_entry(stkctr, stktable_lookup(stkctr->table, stksess));
2403 return stkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002404 }
2405 return stkptr;
2406}
2407
2408/* same as smp_fetch_sc_stkctr() but dedicated to src_* and can create
2409 * the entry if it doesn't exist yet. This is needed for a few fetch
2410 * functions which need to create an entry, such as src_inc_gpc* and
2411 * src_clr_gpc*.
2412 */
2413struct stkctr *
Emeric Brun819fc6f2017-06-13 19:37:32 +02002414smp_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 +01002415{
Willy Tarreau7d562212016-11-25 16:10:05 +01002416 struct stktable_key *key;
2417 struct connection *conn = objt_conn(sess->origin);
2418 struct sample smp;
2419
2420 if (strncmp(kw, "src_", 4) != 0)
2421 return NULL;
2422
2423 if (!conn)
2424 return NULL;
2425
Joseph Herlant5662fa42018-11-15 13:43:28 -08002426 /* Fetch source address in a sample. */
Willy Tarreau7d562212016-11-25 16:10:05 +01002427 smp.px = NULL;
2428 smp.sess = sess;
2429 smp.strm = strm;
Amaury Denoyellec460c702021-05-12 10:17:47 +02002430 if (!smp_fetch_src || !smp_fetch_src(empty_arg_list, &smp, "src", NULL))
Willy Tarreau7d562212016-11-25 16:10:05 +01002431 return NULL;
2432
2433 /* Converts into key. */
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002434 key = smp_to_stkey(&smp, args->data.t);
Willy Tarreau7d562212016-11-25 16:10:05 +01002435 if (!key)
2436 return NULL;
2437
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002438 stkctr->table = args->data.t;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002439 stkctr_set_entry(stkctr, stktable_get_entry(stkctr->table, key));
2440 return stkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002441}
2442
2443/* set return a boolean indicating if the requested stream counter is
2444 * currently being tracked or not.
2445 * Supports being called as "sc[0-9]_tracked" only.
2446 */
2447static int
2448smp_fetch_sc_tracked(const struct arg *args, struct sample *smp, const char *kw, void *private)
2449{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002450 struct stkctr tmpstkctr;
2451 struct stkctr *stkctr;
2452
Willy Tarreau7d562212016-11-25 16:10:05 +01002453 smp->flags = SMP_F_VOL_TEST;
2454 smp->data.type = SMP_T_BOOL;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002455 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2456 smp->data.u.sint = !!stkctr;
2457
2458 /* release the ref count */
Dirkjan Bussinkff57f1b2018-09-14 14:31:22 +02002459 if (stkctr == &tmpstkctr)
Emeric Brun819fc6f2017-06-13 19:37:32 +02002460 stktable_release(stkctr->table, stkctr_entry(stkctr));
2461
Willy Tarreau7d562212016-11-25 16:10:05 +01002462 return 1;
2463}
2464
2465/* set <smp> to the General Purpose Flag 0 value from the stream's tracked
2466 * frontend counters or from the src.
2467 * Supports being called as "sc[0-9]_get_gpc0" or "src_get_gpt0" only. Value
2468 * zero is returned if the key is new.
2469 */
2470static int
2471smp_fetch_sc_get_gpt0(const struct arg *args, struct sample *smp, const char *kw, void *private)
2472{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002473 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002474 struct stkctr *stkctr;
2475
Emeric Brun819fc6f2017-06-13 19:37:32 +02002476 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002477 if (!stkctr)
2478 return 0;
2479
2480 smp->flags = SMP_F_VOL_TEST;
2481 smp->data.type = SMP_T_SINT;
2482 smp->data.u.sint = 0;
2483
Emeric Brun819fc6f2017-06-13 19:37:32 +02002484 if (stkctr_entry(stkctr)) {
2485 void *ptr;
2486
2487 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPT0);
2488 if (!ptr) {
2489 if (stkctr == &tmpstkctr)
2490 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002491 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002492 }
2493
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002494 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002495
Willy Tarreau7d562212016-11-25 16:10:05 +01002496 smp->data.u.sint = stktable_data_cast(ptr, gpt0);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002497
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002498 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002499
2500 if (stkctr == &tmpstkctr)
2501 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002502 }
2503 return 1;
2504}
2505
2506/* set <smp> to the General Purpose Counter 0 value from the stream's tracked
2507 * frontend counters or from the src.
2508 * Supports being called as "sc[0-9]_get_gpc0" or "src_get_gpc0" only. Value
2509 * zero is returned if the key is new.
2510 */
2511static int
2512smp_fetch_sc_get_gpc0(const struct arg *args, struct sample *smp, const char *kw, void *private)
2513{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002514 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002515 struct stkctr *stkctr;
2516
Emeric Brun819fc6f2017-06-13 19:37:32 +02002517 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002518 if (!stkctr)
2519 return 0;
2520
2521 smp->flags = SMP_F_VOL_TEST;
2522 smp->data.type = SMP_T_SINT;
2523 smp->data.u.sint = 0;
2524
2525 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002526 void *ptr;
2527
2528 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0);
2529 if (!ptr) {
2530 if (stkctr == &tmpstkctr)
2531 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002532 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002533 }
2534
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002535 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002536
Willy Tarreau7d562212016-11-25 16:10:05 +01002537 smp->data.u.sint = stktable_data_cast(ptr, gpc0);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002538
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002539 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002540
2541 if (stkctr == &tmpstkctr)
2542 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002543 }
2544 return 1;
2545}
2546
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002547/* set <smp> to the General Purpose Counter 1 value from the stream's tracked
2548 * frontend counters or from the src.
2549 * Supports being called as "sc[0-9]_get_gpc1" or "src_get_gpc1" only. Value
2550 * zero is returned if the key is new.
2551 */
2552static int
2553smp_fetch_sc_get_gpc1(const struct arg *args, struct sample *smp, const char *kw, void *private)
2554{
2555 struct stkctr tmpstkctr;
2556 struct stkctr *stkctr;
2557
2558 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2559 if (!stkctr)
2560 return 0;
2561
2562 smp->flags = SMP_F_VOL_TEST;
2563 smp->data.type = SMP_T_SINT;
2564 smp->data.u.sint = 0;
2565
2566 if (stkctr_entry(stkctr) != NULL) {
2567 void *ptr;
2568
2569 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1);
2570 if (!ptr) {
2571 if (stkctr == &tmpstkctr)
2572 stktable_release(stkctr->table, stkctr_entry(stkctr));
2573 return 0; /* parameter not stored */
2574 }
2575
2576 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2577
2578 smp->data.u.sint = stktable_data_cast(ptr, gpc1);
2579
2580 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2581
2582 if (stkctr == &tmpstkctr)
2583 stktable_release(stkctr->table, stkctr_entry(stkctr));
2584 }
2585 return 1;
2586}
2587
Willy Tarreau7d562212016-11-25 16:10:05 +01002588/* set <smp> to the General Purpose Counter 0's event rate from the stream's
2589 * tracked frontend counters or from the src.
2590 * Supports being called as "sc[0-9]_gpc0_rate" or "src_gpc0_rate" only.
2591 * Value zero is returned if the key is new.
2592 */
2593static int
2594smp_fetch_sc_gpc0_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
2595{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002596 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002597 struct stkctr *stkctr;
2598
Emeric Brun819fc6f2017-06-13 19:37:32 +02002599 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002600 if (!stkctr)
2601 return 0;
2602
2603 smp->flags = SMP_F_VOL_TEST;
2604 smp->data.type = SMP_T_SINT;
2605 smp->data.u.sint = 0;
2606 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002607 void *ptr;
2608
2609 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0_RATE);
2610 if (!ptr) {
2611 if (stkctr == &tmpstkctr)
2612 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002613 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002614 }
2615
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002616 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002617
Willy Tarreau7d562212016-11-25 16:10:05 +01002618 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, gpc0_rate),
2619 stkctr->table->data_arg[STKTABLE_DT_GPC0_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002620
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002621 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002622
2623 if (stkctr == &tmpstkctr)
2624 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002625 }
2626 return 1;
2627}
2628
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002629/* set <smp> to the General Purpose Counter 1's event rate from the stream's
2630 * tracked frontend counters or from the src.
2631 * Supports being called as "sc[0-9]_gpc1_rate" or "src_gpc1_rate" only.
2632 * Value zero is returned if the key is new.
2633 */
2634static int
2635smp_fetch_sc_gpc1_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
2636{
2637 struct stkctr tmpstkctr;
2638 struct stkctr *stkctr;
2639
2640 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2641 if (!stkctr)
2642 return 0;
2643
2644 smp->flags = SMP_F_VOL_TEST;
2645 smp->data.type = SMP_T_SINT;
2646 smp->data.u.sint = 0;
2647 if (stkctr_entry(stkctr) != NULL) {
2648 void *ptr;
2649
2650 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1_RATE);
2651 if (!ptr) {
2652 if (stkctr == &tmpstkctr)
2653 stktable_release(stkctr->table, stkctr_entry(stkctr));
2654 return 0; /* parameter not stored */
2655 }
2656
2657 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2658
2659 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, gpc1_rate),
2660 stkctr->table->data_arg[STKTABLE_DT_GPC1_RATE].u);
2661
2662 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2663
2664 if (stkctr == &tmpstkctr)
2665 stktable_release(stkctr->table, stkctr_entry(stkctr));
2666 }
2667 return 1;
2668}
2669
Willy Tarreau7d562212016-11-25 16:10:05 +01002670/* Increment the General Purpose Counter 0 value from the stream's tracked
2671 * frontend counters and return it into temp integer.
2672 * Supports being called as "sc[0-9]_inc_gpc0" or "src_inc_gpc0" only.
2673 */
2674static int
2675smp_fetch_sc_inc_gpc0(const struct arg *args, struct sample *smp, const char *kw, void *private)
2676{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002677 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002678 struct stkctr *stkctr;
2679
Emeric Brun819fc6f2017-06-13 19:37:32 +02002680 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002681 if (!stkctr)
2682 return 0;
2683
2684 smp->flags = SMP_F_VOL_TEST;
2685 smp->data.type = SMP_T_SINT;
2686 smp->data.u.sint = 0;
2687
Emeric Brun819fc6f2017-06-13 19:37:32 +02002688 if (!stkctr_entry(stkctr))
2689 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002690
2691 if (stkctr && stkctr_entry(stkctr)) {
2692 void *ptr1,*ptr2;
2693
Emeric Brun819fc6f2017-06-13 19:37:32 +02002694
Willy Tarreau7d562212016-11-25 16:10:05 +01002695 /* First, update gpc0_rate if it's tracked. Second, update its
2696 * gpc0 if tracked. Returns gpc0's value otherwise the curr_ctr.
2697 */
2698 ptr1 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0_RATE);
Willy Tarreau7d562212016-11-25 16:10:05 +01002699 ptr2 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002700 if (ptr1 || ptr2) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002701 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Willy Tarreau7d562212016-11-25 16:10:05 +01002702
Emeric Brun819fc6f2017-06-13 19:37:32 +02002703 if (ptr1) {
2704 update_freq_ctr_period(&stktable_data_cast(ptr1, gpc0_rate),
2705 stkctr->table->data_arg[STKTABLE_DT_GPC0_RATE].u, 1);
2706 smp->data.u.sint = (&stktable_data_cast(ptr1, gpc0_rate))->curr_ctr;
2707 }
2708
2709 if (ptr2)
2710 smp->data.u.sint = ++stktable_data_cast(ptr2, gpc0);
2711
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002712 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002713
2714 /* If data was modified, we need to touch to re-schedule sync */
2715 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
2716 }
2717 else if (stkctr == &tmpstkctr)
2718 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002719 }
2720 return 1;
2721}
2722
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002723/* Increment the General Purpose Counter 1 value from the stream's tracked
2724 * frontend counters and return it into temp integer.
2725 * Supports being called as "sc[0-9]_inc_gpc1" or "src_inc_gpc1" only.
2726 */
2727static int
2728smp_fetch_sc_inc_gpc1(const struct arg *args, struct sample *smp, const char *kw, void *private)
2729{
2730 struct stkctr tmpstkctr;
2731 struct stkctr *stkctr;
2732
2733 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2734 if (!stkctr)
2735 return 0;
2736
2737 smp->flags = SMP_F_VOL_TEST;
2738 smp->data.type = SMP_T_SINT;
2739 smp->data.u.sint = 0;
2740
2741 if (!stkctr_entry(stkctr))
2742 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2743
2744 if (stkctr && stkctr_entry(stkctr)) {
2745 void *ptr1,*ptr2;
2746
2747
2748 /* First, update gpc1_rate if it's tracked. Second, update its
2749 * gpc1 if tracked. Returns gpc1's value otherwise the curr_ctr.
2750 */
2751 ptr1 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1_RATE);
2752 ptr2 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1);
2753 if (ptr1 || ptr2) {
2754 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2755
2756 if (ptr1) {
2757 update_freq_ctr_period(&stktable_data_cast(ptr1, gpc1_rate),
2758 stkctr->table->data_arg[STKTABLE_DT_GPC1_RATE].u, 1);
2759 smp->data.u.sint = (&stktable_data_cast(ptr1, gpc1_rate))->curr_ctr;
2760 }
2761
2762 if (ptr2)
2763 smp->data.u.sint = ++stktable_data_cast(ptr2, gpc1);
2764
2765 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2766
2767 /* If data was modified, we need to touch to re-schedule sync */
2768 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
2769 }
2770 else if (stkctr == &tmpstkctr)
2771 stktable_release(stkctr->table, stkctr_entry(stkctr));
2772 }
2773 return 1;
2774}
2775
Willy Tarreau7d562212016-11-25 16:10:05 +01002776/* Clear the General Purpose Counter 0 value from the stream's tracked
2777 * frontend counters and return its previous value into temp integer.
2778 * Supports being called as "sc[0-9]_clr_gpc0" or "src_clr_gpc0" only.
2779 */
2780static int
2781smp_fetch_sc_clr_gpc0(const struct arg *args, struct sample *smp, const char *kw, void *private)
2782{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002783 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002784 struct stkctr *stkctr;
2785
Emeric Brun819fc6f2017-06-13 19:37:32 +02002786 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002787 if (!stkctr)
2788 return 0;
2789
2790 smp->flags = SMP_F_VOL_TEST;
2791 smp->data.type = SMP_T_SINT;
2792 smp->data.u.sint = 0;
2793
Emeric Brun819fc6f2017-06-13 19:37:32 +02002794 if (!stkctr_entry(stkctr))
2795 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002796
Emeric Brun819fc6f2017-06-13 19:37:32 +02002797 if (stkctr && stkctr_entry(stkctr)) {
2798 void *ptr;
2799
2800 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0);
2801 if (!ptr) {
2802 if (stkctr == &tmpstkctr)
2803 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002804 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002805 }
2806
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002807 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002808
Willy Tarreau7d562212016-11-25 16:10:05 +01002809 smp->data.u.sint = stktable_data_cast(ptr, gpc0);
2810 stktable_data_cast(ptr, gpc0) = 0;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002811
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002812 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002813
Willy Tarreau7d562212016-11-25 16:10:05 +01002814 /* If data was modified, we need to touch to re-schedule sync */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002815 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
Willy Tarreau7d562212016-11-25 16:10:05 +01002816 }
2817 return 1;
2818}
2819
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002820/* Clear the General Purpose Counter 1 value from the stream's tracked
2821 * frontend counters and return its previous value into temp integer.
2822 * Supports being called as "sc[0-9]_clr_gpc1" or "src_clr_gpc1" only.
2823 */
2824static int
2825smp_fetch_sc_clr_gpc1(const struct arg *args, struct sample *smp, const char *kw, void *private)
2826{
2827 struct stkctr tmpstkctr;
2828 struct stkctr *stkctr;
2829
2830 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2831 if (!stkctr)
2832 return 0;
2833
2834 smp->flags = SMP_F_VOL_TEST;
2835 smp->data.type = SMP_T_SINT;
2836 smp->data.u.sint = 0;
2837
2838 if (!stkctr_entry(stkctr))
2839 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2840
2841 if (stkctr && stkctr_entry(stkctr)) {
2842 void *ptr;
2843
2844 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1);
2845 if (!ptr) {
2846 if (stkctr == &tmpstkctr)
2847 stktable_release(stkctr->table, stkctr_entry(stkctr));
2848 return 0; /* parameter not stored */
2849 }
2850
2851 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2852
2853 smp->data.u.sint = stktable_data_cast(ptr, gpc1);
2854 stktable_data_cast(ptr, gpc1) = 0;
2855
2856 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2857
2858 /* If data was modified, we need to touch to re-schedule sync */
2859 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
2860 }
2861 return 1;
2862}
2863
Willy Tarreau7d562212016-11-25 16:10:05 +01002864/* set <smp> to the cumulated number of connections from the stream's tracked
2865 * frontend counters. Supports being called as "sc[0-9]_conn_cnt" or
2866 * "src_conn_cnt" only.
2867 */
2868static int
2869smp_fetch_sc_conn_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
2870{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002871 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002872 struct stkctr *stkctr;
2873
Emeric Brun819fc6f2017-06-13 19:37:32 +02002874 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002875 if (!stkctr)
2876 return 0;
2877
2878 smp->flags = SMP_F_VOL_TEST;
2879 smp->data.type = SMP_T_SINT;
2880 smp->data.u.sint = 0;
2881 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002882 void *ptr;
2883
2884 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_CONN_CNT);
2885 if (!ptr) {
2886 if (stkctr == &tmpstkctr)
2887 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002888 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002889 }
2890
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002891 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002892
Willy Tarreau7d562212016-11-25 16:10:05 +01002893 smp->data.u.sint = stktable_data_cast(ptr, conn_cnt);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002894
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002895 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002896
2897 if (stkctr == &tmpstkctr)
2898 stktable_release(stkctr->table, stkctr_entry(stkctr));
2899
2900
Willy Tarreau7d562212016-11-25 16:10:05 +01002901 }
2902 return 1;
2903}
2904
2905/* set <smp> to the connection rate from the stream's tracked frontend
2906 * counters. Supports being called as "sc[0-9]_conn_rate" or "src_conn_rate"
2907 * only.
2908 */
2909static int
2910smp_fetch_sc_conn_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
2911{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002912 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002913 struct stkctr *stkctr;
2914
Emeric Brun819fc6f2017-06-13 19:37:32 +02002915 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002916 if (!stkctr)
2917 return 0;
2918
2919 smp->flags = SMP_F_VOL_TEST;
2920 smp->data.type = SMP_T_SINT;
2921 smp->data.u.sint = 0;
2922 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002923 void *ptr;
2924
2925 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_CONN_RATE);
2926 if (!ptr) {
2927 if (stkctr == &tmpstkctr)
2928 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002929 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002930 }
2931
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002932 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002933
Willy Tarreau7d562212016-11-25 16:10:05 +01002934 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, conn_rate),
2935 stkctr->table->data_arg[STKTABLE_DT_CONN_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002936
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002937 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002938
2939 if (stkctr == &tmpstkctr)
2940 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002941 }
2942 return 1;
2943}
2944
2945/* set temp integer to the number of connections from the stream's source address
2946 * in the table pointed to by expr, after updating it.
2947 * Accepts exactly 1 argument of type table.
2948 */
2949static int
2950smp_fetch_src_updt_conn_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
2951{
2952 struct connection *conn = objt_conn(smp->sess->origin);
2953 struct stksess *ts;
2954 struct stktable_key *key;
2955 void *ptr;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002956 struct stktable *t;
Willy Tarreau7d562212016-11-25 16:10:05 +01002957
2958 if (!conn)
2959 return 0;
2960
Joseph Herlant5662fa42018-11-15 13:43:28 -08002961 /* Fetch source address in a sample. */
Amaury Denoyellec460c702021-05-12 10:17:47 +02002962 if (!smp_fetch_src || !smp_fetch_src(empty_arg_list, smp, "src", NULL))
Willy Tarreau7d562212016-11-25 16:10:05 +01002963 return 0;
2964
2965 /* Converts into key. */
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002966 key = smp_to_stkey(smp, args->data.t);
Willy Tarreau7d562212016-11-25 16:10:05 +01002967 if (!key)
2968 return 0;
2969
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002970 t = args->data.t;
Willy Tarreau7d562212016-11-25 16:10:05 +01002971
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002972 if ((ts = stktable_get_entry(t, key)) == NULL)
Willy Tarreau7d562212016-11-25 16:10:05 +01002973 /* entry does not exist and could not be created */
2974 return 0;
2975
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002976 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_CONN_CNT);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002977 if (!ptr) {
Willy Tarreau7d562212016-11-25 16:10:05 +01002978 return 0; /* parameter not stored in this table */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002979 }
Willy Tarreau7d562212016-11-25 16:10:05 +01002980
2981 smp->data.type = SMP_T_SINT;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002982
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002983 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002984
Willy Tarreau7d562212016-11-25 16:10:05 +01002985 smp->data.u.sint = ++stktable_data_cast(ptr, conn_cnt);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002986
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002987 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002988
Willy Tarreau7d562212016-11-25 16:10:05 +01002989 smp->flags = SMP_F_VOL_TEST;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002990
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002991 stktable_touch_local(t, ts, 1);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002992
2993 /* Touch was previously performed by stktable_update_key */
Willy Tarreau7d562212016-11-25 16:10:05 +01002994 return 1;
2995}
2996
2997/* set <smp> to the number of concurrent connections from the stream's tracked
2998 * frontend counters. Supports being called as "sc[0-9]_conn_cur" or
2999 * "src_conn_cur" only.
3000 */
3001static int
3002smp_fetch_sc_conn_cur(const struct arg *args, struct sample *smp, const char *kw, void *private)
3003{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003004 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003005 struct stkctr *stkctr;
3006
Emeric Brun819fc6f2017-06-13 19:37:32 +02003007 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003008 if (!stkctr)
3009 return 0;
3010
3011 smp->flags = SMP_F_VOL_TEST;
3012 smp->data.type = SMP_T_SINT;
3013 smp->data.u.sint = 0;
3014 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003015 void *ptr;
3016
3017 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_CONN_CUR);
3018 if (!ptr) {
3019 if (stkctr == &tmpstkctr)
3020 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003021 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003022 }
3023
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003024 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003025
Willy Tarreau7d562212016-11-25 16:10:05 +01003026 smp->data.u.sint = stktable_data_cast(ptr, conn_cur);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003027
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003028 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003029
3030 if (stkctr == &tmpstkctr)
3031 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003032 }
3033 return 1;
3034}
3035
3036/* set <smp> to the cumulated number of streams from the stream's tracked
3037 * frontend counters. Supports being called as "sc[0-9]_sess_cnt" or
3038 * "src_sess_cnt" only.
3039 */
3040static int
3041smp_fetch_sc_sess_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
3042{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003043 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003044 struct stkctr *stkctr;
3045
Emeric Brun819fc6f2017-06-13 19:37:32 +02003046 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003047 if (!stkctr)
3048 return 0;
3049
3050 smp->flags = SMP_F_VOL_TEST;
3051 smp->data.type = SMP_T_SINT;
3052 smp->data.u.sint = 0;
3053 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003054 void *ptr;
3055
3056 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_SESS_CNT);
3057 if (!ptr) {
3058 if (stkctr == &tmpstkctr)
3059 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003060 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003061 }
3062
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003063 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003064
Willy Tarreau7d562212016-11-25 16:10:05 +01003065 smp->data.u.sint = stktable_data_cast(ptr, sess_cnt);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003066
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003067 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003068
3069 if (stkctr == &tmpstkctr)
3070 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003071 }
3072 return 1;
3073}
3074
3075/* set <smp> to the stream rate from the stream's tracked frontend counters.
3076 * Supports being called as "sc[0-9]_sess_rate" or "src_sess_rate" only.
3077 */
3078static int
3079smp_fetch_sc_sess_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3080{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003081 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003082 struct stkctr *stkctr;
3083
Emeric Brun819fc6f2017-06-13 19:37:32 +02003084 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003085 if (!stkctr)
3086 return 0;
3087
3088 smp->flags = SMP_F_VOL_TEST;
3089 smp->data.type = SMP_T_SINT;
3090 smp->data.u.sint = 0;
3091 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003092 void *ptr;
3093
3094 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_SESS_RATE);
3095 if (!ptr) {
3096 if (stkctr == &tmpstkctr)
3097 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003098 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003099 }
3100
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003101 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003102
Willy Tarreau7d562212016-11-25 16:10:05 +01003103 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, sess_rate),
3104 stkctr->table->data_arg[STKTABLE_DT_SESS_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003105
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003106 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003107
3108 if (stkctr == &tmpstkctr)
3109 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003110 }
3111 return 1;
3112}
3113
3114/* set <smp> to the cumulated number of HTTP requests from the stream's tracked
3115 * frontend counters. Supports being called as "sc[0-9]_http_req_cnt" or
3116 * "src_http_req_cnt" only.
3117 */
3118static int
3119smp_fetch_sc_http_req_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
3120{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003121 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003122 struct stkctr *stkctr;
3123
Emeric Brun819fc6f2017-06-13 19:37:32 +02003124 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003125 if (!stkctr)
3126 return 0;
3127
3128 smp->flags = SMP_F_VOL_TEST;
3129 smp->data.type = SMP_T_SINT;
3130 smp->data.u.sint = 0;
3131 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003132 void *ptr;
3133
3134 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_REQ_CNT);
3135 if (!ptr) {
3136 if (stkctr == &tmpstkctr)
3137 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003138 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003139 }
3140
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003141 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003142
Willy Tarreau7d562212016-11-25 16:10:05 +01003143 smp->data.u.sint = stktable_data_cast(ptr, http_req_cnt);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003144
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003145 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003146
3147 if (stkctr == &tmpstkctr)
3148 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003149 }
3150 return 1;
3151}
3152
3153/* set <smp> to the HTTP request rate from the stream's tracked frontend
3154 * counters. Supports being called as "sc[0-9]_http_req_rate" or
3155 * "src_http_req_rate" only.
3156 */
3157static int
3158smp_fetch_sc_http_req_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3159{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003160 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003161 struct stkctr *stkctr;
3162
Emeric Brun819fc6f2017-06-13 19:37:32 +02003163 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003164 if (!stkctr)
3165 return 0;
3166
3167 smp->flags = SMP_F_VOL_TEST;
3168 smp->data.type = SMP_T_SINT;
3169 smp->data.u.sint = 0;
3170 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003171 void *ptr;
3172
3173 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_REQ_RATE);
3174 if (!ptr) {
3175 if (stkctr == &tmpstkctr)
3176 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003177 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003178 }
3179
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003180 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003181
Willy Tarreau7d562212016-11-25 16:10:05 +01003182 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, http_req_rate),
3183 stkctr->table->data_arg[STKTABLE_DT_HTTP_REQ_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003184
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003185 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003186
3187 if (stkctr == &tmpstkctr)
3188 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003189 }
3190 return 1;
3191}
3192
3193/* set <smp> to the cumulated number of HTTP requests errors from the stream's
3194 * tracked frontend counters. Supports being called as "sc[0-9]_http_err_cnt" or
3195 * "src_http_err_cnt" only.
3196 */
3197static int
3198smp_fetch_sc_http_err_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
3199{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003200 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003201 struct stkctr *stkctr;
3202
Emeric Brun819fc6f2017-06-13 19:37:32 +02003203 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003204 if (!stkctr)
3205 return 0;
3206
3207 smp->flags = SMP_F_VOL_TEST;
3208 smp->data.type = SMP_T_SINT;
3209 smp->data.u.sint = 0;
3210 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003211 void *ptr;
3212
3213 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_ERR_CNT);
3214 if (!ptr) {
3215 if (stkctr == &tmpstkctr)
3216 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003217 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003218 }
3219
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003220 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003221
Willy Tarreau7d562212016-11-25 16:10:05 +01003222 smp->data.u.sint = stktable_data_cast(ptr, http_err_cnt);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003223
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003224 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003225
3226 if (stkctr == &tmpstkctr)
3227 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003228 }
3229 return 1;
3230}
3231
3232/* set <smp> to the HTTP request error rate from the stream's tracked frontend
3233 * counters. Supports being called as "sc[0-9]_http_err_rate" or
3234 * "src_http_err_rate" only.
3235 */
3236static int
3237smp_fetch_sc_http_err_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3238{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003239 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003240 struct stkctr *stkctr;
3241
Emeric Brun819fc6f2017-06-13 19:37:32 +02003242 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003243 if (!stkctr)
3244 return 0;
3245
3246 smp->flags = SMP_F_VOL_TEST;
3247 smp->data.type = SMP_T_SINT;
3248 smp->data.u.sint = 0;
3249 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003250 void *ptr;
3251
3252 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_ERR_RATE);
3253 if (!ptr) {
3254 if (stkctr == &tmpstkctr)
3255 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003256 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003257 }
3258
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003259 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003260
Willy Tarreau7d562212016-11-25 16:10:05 +01003261 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, http_err_rate),
3262 stkctr->table->data_arg[STKTABLE_DT_HTTP_ERR_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003263
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003264 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003265
3266 if (stkctr == &tmpstkctr)
3267 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003268 }
3269 return 1;
3270}
3271
Willy Tarreau826f3ab2021-02-10 12:07:15 +01003272/* set <smp> to the cumulated number of HTTP response failures from the stream's
3273 * tracked frontend counters. Supports being called as "sc[0-9]_http_fail_cnt" or
3274 * "src_http_fail_cnt" only.
3275 */
3276static int
3277smp_fetch_sc_http_fail_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
3278{
3279 struct stkctr tmpstkctr;
3280 struct stkctr *stkctr;
3281
3282 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
3283 if (!stkctr)
3284 return 0;
3285
3286 smp->flags = SMP_F_VOL_TEST;
3287 smp->data.type = SMP_T_SINT;
3288 smp->data.u.sint = 0;
3289 if (stkctr_entry(stkctr) != NULL) {
3290 void *ptr;
3291
3292 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_FAIL_CNT);
3293 if (!ptr) {
3294 if (stkctr == &tmpstkctr)
3295 stktable_release(stkctr->table, stkctr_entry(stkctr));
3296 return 0; /* parameter not stored */
3297 }
3298
3299 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3300
3301 smp->data.u.sint = stktable_data_cast(ptr, http_fail_cnt);
3302
3303 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3304
3305 if (stkctr == &tmpstkctr)
3306 stktable_release(stkctr->table, stkctr_entry(stkctr));
3307 }
3308 return 1;
3309}
3310
3311/* set <smp> to the HTTP response failure rate from the stream's tracked frontend
3312 * counters. Supports being called as "sc[0-9]_http_fail_rate" or
3313 * "src_http_fail_rate" only.
3314 */
3315static int
3316smp_fetch_sc_http_fail_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3317{
3318 struct stkctr tmpstkctr;
3319 struct stkctr *stkctr;
3320
3321 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
3322 if (!stkctr)
3323 return 0;
3324
3325 smp->flags = SMP_F_VOL_TEST;
3326 smp->data.type = SMP_T_SINT;
3327 smp->data.u.sint = 0;
3328 if (stkctr_entry(stkctr) != NULL) {
3329 void *ptr;
3330
3331 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_FAIL_RATE);
3332 if (!ptr) {
3333 if (stkctr == &tmpstkctr)
3334 stktable_release(stkctr->table, stkctr_entry(stkctr));
3335 return 0; /* parameter not stored */
3336 }
3337
3338 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3339
3340 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, http_fail_rate),
3341 stkctr->table->data_arg[STKTABLE_DT_HTTP_FAIL_RATE].u);
3342
3343 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3344
3345 if (stkctr == &tmpstkctr)
3346 stktable_release(stkctr->table, stkctr_entry(stkctr));
3347 }
3348 return 1;
3349}
3350
Willy Tarreau7d562212016-11-25 16:10:05 +01003351/* set <smp> to the number of kbytes received from clients, as found in the
3352 * stream's tracked frontend counters. Supports being called as
3353 * "sc[0-9]_kbytes_in" or "src_kbytes_in" only.
3354 */
3355static int
3356smp_fetch_sc_kbytes_in(const struct arg *args, struct sample *smp, const char *kw, void *private)
3357{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003358 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003359 struct stkctr *stkctr;
3360
Emeric Brun819fc6f2017-06-13 19:37:32 +02003361 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003362 if (!stkctr)
3363 return 0;
3364
3365 smp->flags = SMP_F_VOL_TEST;
3366 smp->data.type = SMP_T_SINT;
3367 smp->data.u.sint = 0;
3368 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003369 void *ptr;
3370
3371 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_IN_CNT);
3372 if (!ptr) {
3373 if (stkctr == &tmpstkctr)
3374 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003375 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003376 }
3377
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003378 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003379
Willy Tarreau7d562212016-11-25 16:10:05 +01003380 smp->data.u.sint = stktable_data_cast(ptr, bytes_in_cnt) >> 10;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003381
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003382 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003383
3384 if (stkctr == &tmpstkctr)
3385 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003386 }
3387 return 1;
3388}
3389
3390/* set <smp> to the data rate received from clients in bytes/s, as found
3391 * in the stream's tracked frontend counters. Supports being called as
3392 * "sc[0-9]_bytes_in_rate" or "src_bytes_in_rate" only.
3393 */
3394static int
3395smp_fetch_sc_bytes_in_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3396{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003397 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003398 struct stkctr *stkctr;
3399
Emeric Brun819fc6f2017-06-13 19:37:32 +02003400 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003401 if (!stkctr)
3402 return 0;
3403
3404 smp->flags = SMP_F_VOL_TEST;
3405 smp->data.type = SMP_T_SINT;
3406 smp->data.u.sint = 0;
3407 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003408 void *ptr;
3409
3410 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_IN_RATE);
3411 if (!ptr) {
3412 if (stkctr == &tmpstkctr)
3413 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003414 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003415 }
3416
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003417 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003418
Willy Tarreau7d562212016-11-25 16:10:05 +01003419 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, bytes_in_rate),
3420 stkctr->table->data_arg[STKTABLE_DT_BYTES_IN_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003421
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003422 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003423
3424 if (stkctr == &tmpstkctr)
3425 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003426 }
3427 return 1;
3428}
3429
3430/* set <smp> to the number of kbytes sent to clients, as found in the
3431 * stream's tracked frontend counters. Supports being called as
3432 * "sc[0-9]_kbytes_out" or "src_kbytes_out" only.
3433 */
3434static int
3435smp_fetch_sc_kbytes_out(const struct arg *args, struct sample *smp, const char *kw, void *private)
3436{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003437 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003438 struct stkctr *stkctr;
3439
Emeric Brun819fc6f2017-06-13 19:37:32 +02003440 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003441 if (!stkctr)
3442 return 0;
3443
3444 smp->flags = SMP_F_VOL_TEST;
3445 smp->data.type = SMP_T_SINT;
3446 smp->data.u.sint = 0;
3447 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003448 void *ptr;
3449
3450 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_OUT_CNT);
3451 if (!ptr) {
3452 if (stkctr == &tmpstkctr)
3453 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003454 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003455 }
3456
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003457 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003458
Willy Tarreau7d562212016-11-25 16:10:05 +01003459 smp->data.u.sint = stktable_data_cast(ptr, bytes_out_cnt) >> 10;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003460
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003461 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003462
3463 if (stkctr == &tmpstkctr)
3464 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003465 }
3466 return 1;
3467}
3468
3469/* set <smp> to the data rate sent to clients in bytes/s, as found in the
3470 * stream's tracked frontend counters. Supports being called as
3471 * "sc[0-9]_bytes_out_rate" or "src_bytes_out_rate" only.
3472 */
3473static int
3474smp_fetch_sc_bytes_out_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3475{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003476 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003477 struct stkctr *stkctr;
3478
Emeric Brun819fc6f2017-06-13 19:37:32 +02003479 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003480 if (!stkctr)
3481 return 0;
3482
3483 smp->flags = SMP_F_VOL_TEST;
3484 smp->data.type = SMP_T_SINT;
3485 smp->data.u.sint = 0;
3486 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003487 void *ptr;
3488
3489 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_OUT_RATE);
3490 if (!ptr) {
3491 if (stkctr == &tmpstkctr)
3492 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003493 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003494 }
3495
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003496 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003497
Willy Tarreau7d562212016-11-25 16:10:05 +01003498 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, bytes_out_rate),
3499 stkctr->table->data_arg[STKTABLE_DT_BYTES_OUT_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003500
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003501 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003502
3503 if (stkctr == &tmpstkctr)
3504 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003505 }
3506 return 1;
3507}
3508
3509/* set <smp> to the number of active trackers on the SC entry in the stream's
3510 * tracked frontend counters. Supports being called as "sc[0-9]_trackers" only.
3511 */
3512static int
3513smp_fetch_sc_trackers(const struct arg *args, struct sample *smp, const char *kw, void *private)
3514{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003515 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003516 struct stkctr *stkctr;
3517
Emeric Brun819fc6f2017-06-13 19:37:32 +02003518 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003519 if (!stkctr)
3520 return 0;
3521
3522 smp->flags = SMP_F_VOL_TEST;
3523 smp->data.type = SMP_T_SINT;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003524 if (stkctr == &tmpstkctr) {
3525 smp->data.u.sint = stkctr_entry(stkctr) ? (stkctr_entry(stkctr)->ref_cnt-1) : 0;
3526 stktable_release(stkctr->table, stkctr_entry(stkctr));
3527 }
3528 else {
3529 smp->data.u.sint = stkctr_entry(stkctr) ? stkctr_entry(stkctr)->ref_cnt : 0;
3530 }
3531
Willy Tarreau7d562212016-11-25 16:10:05 +01003532 return 1;
3533}
3534
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003535
3536/* The functions below are used to manipulate table contents from the CLI.
3537 * There are 3 main actions, "clear", "set" and "show". The code is shared
3538 * between all actions, and the action is encoded in the void *private in
3539 * the appctx as well as in the keyword registration, among one of the
3540 * following values.
3541 */
3542
3543enum {
3544 STK_CLI_ACT_CLR,
3545 STK_CLI_ACT_SET,
3546 STK_CLI_ACT_SHOW,
3547};
3548
3549/* Dump the status of a table to a stream interface's
3550 * read buffer. It returns 0 if the output buffer is full
3551 * and needs to be called again, otherwise non-zero.
3552 */
Willy Tarreau83061a82018-07-13 11:56:34 +02003553static int table_dump_head_to_buffer(struct buffer *msg,
3554 struct stream_interface *si,
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003555 struct stktable *t, struct stktable *target)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003556{
3557 struct stream *s = si_strm(si);
3558
3559 chunk_appendf(msg, "# table: %s, type: %s, size:%d, used:%d\n",
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003560 t->id, stktable_types[t->type].kw, t->size, t->current);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003561
3562 /* any other information should be dumped here */
3563
William Lallemand07a62f72017-05-24 00:57:40 +02003564 if (target && (strm_li(s)->bind_conf->level & ACCESS_LVL_MASK) < ACCESS_LVL_OPER)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003565 chunk_appendf(msg, "# contents not dumped due to insufficient privileges\n");
3566
Willy Tarreau06d80a92017-10-19 14:32:15 +02003567 if (ci_putchk(si_ic(si), msg) == -1) {
Willy Tarreaudb398432018-11-15 11:08:52 +01003568 si_rx_room_blk(si);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003569 return 0;
3570 }
3571
3572 return 1;
3573}
3574
3575/* Dump a table entry to a stream interface's
3576 * read buffer. It returns 0 if the output buffer is full
3577 * and needs to be called again, otherwise non-zero.
3578 */
Willy Tarreau83061a82018-07-13 11:56:34 +02003579static int table_dump_entry_to_buffer(struct buffer *msg,
3580 struct stream_interface *si,
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003581 struct stktable *t, struct stksess *entry)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003582{
3583 int dt;
3584
3585 chunk_appendf(msg, "%p:", entry);
3586
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003587 if (t->type == SMP_T_IPV4) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003588 char addr[INET_ADDRSTRLEN];
3589 inet_ntop(AF_INET, (const void *)&entry->key.key, addr, sizeof(addr));
3590 chunk_appendf(msg, " key=%s", addr);
3591 }
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003592 else if (t->type == SMP_T_IPV6) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003593 char addr[INET6_ADDRSTRLEN];
3594 inet_ntop(AF_INET6, (const void *)&entry->key.key, addr, sizeof(addr));
3595 chunk_appendf(msg, " key=%s", addr);
3596 }
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003597 else if (t->type == SMP_T_SINT) {
Willy Tarreau6cde5d82020-02-25 09:41:22 +01003598 chunk_appendf(msg, " key=%u", read_u32(entry->key.key));
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003599 }
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003600 else if (t->type == SMP_T_STR) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003601 chunk_appendf(msg, " key=");
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003602 dump_text(msg, (const char *)entry->key.key, t->key_size);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003603 }
3604 else {
3605 chunk_appendf(msg, " key=");
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003606 dump_binary(msg, (const char *)entry->key.key, t->key_size);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003607 }
3608
3609 chunk_appendf(msg, " use=%d exp=%d", entry->ref_cnt - 1, tick_remain(now_ms, entry->expire));
3610
3611 for (dt = 0; dt < STKTABLE_DATA_TYPES; dt++) {
3612 void *ptr;
3613
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003614 if (t->data_ofs[dt] == 0)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003615 continue;
3616 if (stktable_data_types[dt].arg_type == ARG_T_DELAY)
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003617 chunk_appendf(msg, " %s(%d)=", stktable_data_types[dt].name, t->data_arg[dt].u);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003618 else
3619 chunk_appendf(msg, " %s=", stktable_data_types[dt].name);
3620
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003621 ptr = stktable_data_ptr(t, entry, dt);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003622 switch (stktable_data_types[dt].std_type) {
3623 case STD_T_SINT:
3624 chunk_appendf(msg, "%d", stktable_data_cast(ptr, std_t_sint));
3625 break;
3626 case STD_T_UINT:
3627 chunk_appendf(msg, "%u", stktable_data_cast(ptr, std_t_uint));
3628 break;
3629 case STD_T_ULL:
3630 chunk_appendf(msg, "%lld", stktable_data_cast(ptr, std_t_ull));
3631 break;
3632 case STD_T_FRQP:
3633 chunk_appendf(msg, "%d",
3634 read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003635 t->data_arg[dt].u));
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003636 break;
Frédéric Lécaille16b4f542019-05-23 12:15:04 +02003637 case STD_T_DICT: {
3638 struct dict_entry *de;
3639 de = stktable_data_cast(ptr, std_t_dict);
3640 chunk_appendf(msg, "%s", de ? (char *)de->value.key : "-");
3641 break;
3642 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003643 }
3644 }
3645 chunk_appendf(msg, "\n");
3646
Willy Tarreau06d80a92017-10-19 14:32:15 +02003647 if (ci_putchk(si_ic(si), msg) == -1) {
Willy Tarreaudb398432018-11-15 11:08:52 +01003648 si_rx_room_blk(si);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003649 return 0;
3650 }
3651
3652 return 1;
3653}
3654
3655
3656/* Processes a single table entry matching a specific key passed in argument.
3657 * returns 0 if wants to be called again, 1 if has ended processing.
3658 */
3659static int table_process_entry_per_key(struct appctx *appctx, char **args)
3660{
3661 struct stream_interface *si = appctx->owner;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003662 struct stktable *t = appctx->ctx.table.target;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003663 struct stksess *ts;
3664 uint32_t uint32_key;
3665 unsigned char ip6_key[sizeof(struct in6_addr)];
3666 long long value;
3667 int data_type;
3668 int cur_arg;
3669 void *ptr;
Willy Tarreaufa1258f2021-04-10 23:00:53 +02003670 struct freq_ctr *frqp;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003671
Willy Tarreau9d008692019-08-09 11:21:01 +02003672 if (!*args[4])
3673 return cli_err(appctx, "Key value expected\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003674
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003675 switch (t->type) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003676 case SMP_T_IPV4:
3677 uint32_key = htonl(inetaddr_host(args[4]));
Christopher Fauletca20d022017-08-29 15:30:31 +02003678 static_table_key.key = &uint32_key;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003679 break;
3680 case SMP_T_IPV6:
3681 inet_pton(AF_INET6, args[4], ip6_key);
Christopher Fauletca20d022017-08-29 15:30:31 +02003682 static_table_key.key = &ip6_key;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003683 break;
3684 case SMP_T_SINT:
3685 {
3686 char *endptr;
3687 unsigned long val;
3688 errno = 0;
3689 val = strtoul(args[4], &endptr, 10);
3690 if ((errno == ERANGE && val == ULONG_MAX) ||
3691 (errno != 0 && val == 0) || endptr == args[4] ||
Willy Tarreau9d008692019-08-09 11:21:01 +02003692 val > 0xffffffff)
3693 return cli_err(appctx, "Invalid key\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003694 uint32_key = (uint32_t) val;
Christopher Fauletca20d022017-08-29 15:30:31 +02003695 static_table_key.key = &uint32_key;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003696 break;
3697 }
3698 break;
3699 case SMP_T_STR:
Christopher Fauletca20d022017-08-29 15:30:31 +02003700 static_table_key.key = args[4];
3701 static_table_key.key_len = strlen(args[4]);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003702 break;
3703 default:
Willy Tarreaua24bc782016-12-14 15:50:35 +01003704 switch (appctx->ctx.table.action) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003705 case STK_CLI_ACT_SHOW:
Willy Tarreau9d008692019-08-09 11:21:01 +02003706 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 +01003707 case STK_CLI_ACT_CLR:
Willy Tarreau9d008692019-08-09 11:21:01 +02003708 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 +01003709 case STK_CLI_ACT_SET:
Willy Tarreau9d008692019-08-09 11:21:01 +02003710 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 +01003711 default:
Willy Tarreau9d008692019-08-09 11:21:01 +02003712 return cli_err(appctx, "Unknown action\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003713 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003714 }
3715
3716 /* check permissions */
3717 if (!cli_has_level(appctx, ACCESS_LVL_OPER))
3718 return 1;
3719
Willy Tarreaua24bc782016-12-14 15:50:35 +01003720 switch (appctx->ctx.table.action) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003721 case STK_CLI_ACT_SHOW:
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003722 ts = stktable_lookup_key(t, &static_table_key);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003723 if (!ts)
3724 return 1;
3725 chunk_reset(&trash);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003726 if (!table_dump_head_to_buffer(&trash, si, t, t)) {
3727 stktable_release(t, ts);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003728 return 0;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003729 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003730 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003731 if (!table_dump_entry_to_buffer(&trash, si, t, ts)) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003732 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003733 stktable_release(t, ts);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003734 return 0;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003735 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003736 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003737 stktable_release(t, ts);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003738 break;
3739
3740 case STK_CLI_ACT_CLR:
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003741 ts = stktable_lookup_key(t, &static_table_key);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003742 if (!ts)
3743 return 1;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003744
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003745 if (!stksess_kill(t, ts, 1)) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003746 /* don't delete an entry which is currently referenced */
Willy Tarreau9d008692019-08-09 11:21:01 +02003747 return cli_err(appctx, "Entry currently in use, cannot remove\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003748 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003749 break;
3750
3751 case STK_CLI_ACT_SET:
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003752 ts = stktable_get_entry(t, &static_table_key);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003753 if (!ts) {
3754 /* don't delete an entry which is currently referenced */
Willy Tarreau9d008692019-08-09 11:21:01 +02003755 return cli_err(appctx, "Unable to allocate a new entry\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003756 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003757 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003758 for (cur_arg = 5; *args[cur_arg]; cur_arg += 2) {
3759 if (strncmp(args[cur_arg], "data.", 5) != 0) {
Willy Tarreau9d008692019-08-09 11:21:01 +02003760 cli_err(appctx, "\"data.<type>\" followed by a value expected\n");
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003761 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003762 stktable_touch_local(t, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003763 return 1;
3764 }
3765
3766 data_type = stktable_get_data_type(args[cur_arg] + 5);
3767 if (data_type < 0) {
Willy Tarreau9d008692019-08-09 11:21:01 +02003768 cli_err(appctx, "Unknown data type\n");
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003769 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003770 stktable_touch_local(t, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003771 return 1;
3772 }
3773
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003774 if (!t->data_ofs[data_type]) {
Willy Tarreau9d008692019-08-09 11:21:01 +02003775 cli_err(appctx, "Data type not stored in this table\n");
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003776 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003777 stktable_touch_local(t, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003778 return 1;
3779 }
3780
3781 if (!*args[cur_arg+1] || strl2llrc(args[cur_arg+1], strlen(args[cur_arg+1]), &value) != 0) {
Willy Tarreau9d008692019-08-09 11:21:01 +02003782 cli_err(appctx, "Require a valid integer value to store\n");
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003783 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003784 stktable_touch_local(t, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003785 return 1;
3786 }
3787
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003788 ptr = stktable_data_ptr(t, ts, data_type);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003789
3790 switch (stktable_data_types[data_type].std_type) {
3791 case STD_T_SINT:
3792 stktable_data_cast(ptr, std_t_sint) = value;
3793 break;
3794 case STD_T_UINT:
3795 stktable_data_cast(ptr, std_t_uint) = value;
3796 break;
3797 case STD_T_ULL:
3798 stktable_data_cast(ptr, std_t_ull) = value;
3799 break;
3800 case STD_T_FRQP:
3801 /* We set both the current and previous values. That way
3802 * the reported frequency is stable during all the period
3803 * then slowly fades out. This allows external tools to
3804 * push measures without having to update them too often.
3805 */
3806 frqp = &stktable_data_cast(ptr, std_t_frqp);
Willy Tarreaufa1258f2021-04-10 23:00:53 +02003807 /* First bit is reserved for the freq_ctr lock
Emeric Brunf2fc1fd2017-11-02 17:32:43 +01003808 Note: here we're still protected by the stksess lock
Willy Tarreaufa1258f2021-04-10 23:00:53 +02003809 so we don't need to update the update the freq_ctr
Emeric Brunf2fc1fd2017-11-02 17:32:43 +01003810 using its internal lock */
3811 frqp->curr_tick = now_ms & ~0x1;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003812 frqp->prev_ctr = 0;
3813 frqp->curr_ctr = value;
3814 break;
3815 }
3816 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003817 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003818 stktable_touch_local(t, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003819 break;
3820
3821 default:
Willy Tarreau9d008692019-08-09 11:21:01 +02003822 return cli_err(appctx, "Unknown action\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003823 }
3824 return 1;
3825}
3826
3827/* Prepares the appctx fields with the data-based filters from the command line.
3828 * Returns 0 if the dump can proceed, 1 if has ended processing.
3829 */
3830static int table_prepare_data_request(struct appctx *appctx, char **args)
3831{
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01003832 int i;
Adis Nezirovicd0142e72020-01-22 16:50:27 +01003833 char *err = NULL;
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01003834
Willy Tarreau9d008692019-08-09 11:21:01 +02003835 if (appctx->ctx.table.action != STK_CLI_ACT_SHOW && appctx->ctx.table.action != STK_CLI_ACT_CLR)
3836 return cli_err(appctx, "content-based lookup is only supported with the \"show\" and \"clear\" actions\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003837
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01003838 for (i = 0; i < STKTABLE_FILTER_LEN; i++) {
3839 if (i > 0 && !*args[3+3*i]) // number of filter entries can be less than STKTABLE_FILTER_LEN
3840 break;
3841 /* condition on stored data value */
3842 appctx->ctx.table.data_type[i] = stktable_get_data_type(args[3+3*i] + 5);
3843 if (appctx->ctx.table.data_type[i] < 0)
Adis Nezirovicd0142e72020-01-22 16:50:27 +01003844 return cli_dynerr(appctx, memprintf(&err, "Filter entry #%i: Unknown data type\n", i + 1));
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003845
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01003846 if (!((struct stktable *)appctx->ctx.table.target)->data_ofs[appctx->ctx.table.data_type[i]])
Adis Nezirovicd0142e72020-01-22 16:50:27 +01003847 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 +01003848
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01003849 appctx->ctx.table.data_op[i] = get_std_op(args[4+3*i]);
Willy Tarreau2b64a352020-01-22 17:09:47 +01003850 if (appctx->ctx.table.data_op[i] < 0)
Adis Nezirovicd0142e72020-01-22 16:50:27 +01003851 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 +01003852
Adis Nezirovic56dd3542020-01-22 16:16:48 +01003853 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 +01003854 return cli_dynerr(appctx, memprintf(&err, "Filter entry #%i: Require a valid integer value to compare against\n", i + 1));
3855 }
3856
3857 if (*args[3+3*i]) {
3858 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 +01003859 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003860
3861 /* OK we're done, all the fields are set */
3862 return 0;
3863}
3864
3865/* returns 0 if wants to be called, 1 if has ended processing */
Aurélien Nephtaliabbf6072018-04-18 13:26:46 +02003866static int cli_parse_table_req(char **args, char *payload, struct appctx *appctx, void *private)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003867{
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01003868 int i;
3869
3870 for (i = 0; i < STKTABLE_FILTER_LEN; i++)
3871 appctx->ctx.table.data_type[i] = -1;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003872 appctx->ctx.table.target = NULL;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003873 appctx->ctx.table.entry = NULL;
Willy Tarreaua24bc782016-12-14 15:50:35 +01003874 appctx->ctx.table.action = (long)private; // keyword argument, one of STK_CLI_ACT_*
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003875
3876 if (*args[2]) {
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003877 appctx->ctx.table.target = stktable_find_by_name(args[2]);
Willy Tarreau9d008692019-08-09 11:21:01 +02003878 if (!appctx->ctx.table.target)
3879 return cli_err(appctx, "No such table\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003880 }
3881 else {
Willy Tarreaua24bc782016-12-14 15:50:35 +01003882 if (appctx->ctx.table.action != STK_CLI_ACT_SHOW)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003883 goto err_args;
3884 return 0;
3885 }
3886
3887 if (strcmp(args[3], "key") == 0)
3888 return table_process_entry_per_key(appctx, args);
3889 else if (strncmp(args[3], "data.", 5) == 0)
3890 return table_prepare_data_request(appctx, args);
3891 else if (*args[3])
3892 goto err_args;
3893
3894 return 0;
3895
3896err_args:
Willy Tarreaua24bc782016-12-14 15:50:35 +01003897 switch (appctx->ctx.table.action) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003898 case STK_CLI_ACT_SHOW:
Willy Tarreau9d008692019-08-09 11:21:01 +02003899 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 +01003900 case STK_CLI_ACT_CLR:
Willy Tarreau9d008692019-08-09 11:21:01 +02003901 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 +01003902 case STK_CLI_ACT_SET:
Willy Tarreau9d008692019-08-09 11:21:01 +02003903 return cli_err(appctx, "Required arguments: <table> key <key> [data.<store_data_type> <value>]*\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003904 default:
Willy Tarreau9d008692019-08-09 11:21:01 +02003905 return cli_err(appctx, "Unknown action\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003906 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003907}
3908
3909/* This function is used to deal with table operations (dump or clear depending
3910 * on the action stored in appctx->private). It returns 0 if the output buffer is
3911 * full and it needs to be called again, otherwise non-zero.
3912 */
3913static int cli_io_handler_table(struct appctx *appctx)
3914{
3915 struct stream_interface *si = appctx->owner;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003916 struct stream *s = si_strm(si);
3917 struct ebmb_node *eb;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003918 int skip_entry;
Willy Tarreaua24bc782016-12-14 15:50:35 +01003919 int show = appctx->ctx.table.action == STK_CLI_ACT_SHOW;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003920
3921 /*
3922 * We have 3 possible states in appctx->st2 :
3923 * - STAT_ST_INIT : the first call
3924 * - STAT_ST_INFO : the proxy pointer points to the next table to
3925 * dump, the entry pointer is NULL ;
3926 * - STAT_ST_LIST : the proxy pointer points to the current table
3927 * and the entry pointer points to the next entry to be dumped,
3928 * and the refcount on the next entry is held ;
3929 * - STAT_ST_END : nothing left to dump, the buffer may contain some
3930 * data though.
3931 */
3932
3933 if (unlikely(si_ic(si)->flags & (CF_WRITE_ERROR|CF_SHUTW))) {
3934 /* in case of abort, remove any refcount we might have set on an entry */
3935 if (appctx->st2 == STAT_ST_LIST) {
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003936 stksess_kill_if_expired(appctx->ctx.table.t, appctx->ctx.table.entry, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003937 }
3938 return 1;
3939 }
3940
3941 chunk_reset(&trash);
3942
3943 while (appctx->st2 != STAT_ST_FIN) {
3944 switch (appctx->st2) {
3945 case STAT_ST_INIT:
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003946 appctx->ctx.table.t = appctx->ctx.table.target;
3947 if (!appctx->ctx.table.t)
3948 appctx->ctx.table.t = stktables_list;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003949
3950 appctx->ctx.table.entry = NULL;
3951 appctx->st2 = STAT_ST_INFO;
3952 break;
3953
3954 case STAT_ST_INFO:
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003955 if (!appctx->ctx.table.t ||
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003956 (appctx->ctx.table.target &&
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003957 appctx->ctx.table.t != appctx->ctx.table.target)) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003958 appctx->st2 = STAT_ST_END;
3959 break;
3960 }
3961
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003962 if (appctx->ctx.table.t->size) {
3963 if (show && !table_dump_head_to_buffer(&trash, si, appctx->ctx.table.t, appctx->ctx.table.target))
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003964 return 0;
3965
3966 if (appctx->ctx.table.target &&
William Lallemand07a62f72017-05-24 00:57:40 +02003967 (strm_li(s)->bind_conf->level & ACCESS_LVL_MASK) >= ACCESS_LVL_OPER) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003968 /* dump entries only if table explicitly requested */
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003969 HA_SPIN_LOCK(STK_TABLE_LOCK, &appctx->ctx.table.t->lock);
3970 eb = ebmb_first(&appctx->ctx.table.t->keys);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003971 if (eb) {
3972 appctx->ctx.table.entry = ebmb_entry(eb, struct stksess, key);
3973 appctx->ctx.table.entry->ref_cnt++;
3974 appctx->st2 = STAT_ST_LIST;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003975 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &appctx->ctx.table.t->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003976 break;
3977 }
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003978 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &appctx->ctx.table.t->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003979 }
3980 }
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003981 appctx->ctx.table.t = appctx->ctx.table.t->next;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003982 break;
3983
3984 case STAT_ST_LIST:
3985 skip_entry = 0;
3986
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003987 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &appctx->ctx.table.entry->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003988
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01003989 if (appctx->ctx.table.data_type[0] >= 0) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003990 /* we're filtering on some data contents */
3991 void *ptr;
Willy Tarreau2b64a352020-01-22 17:09:47 +01003992 int dt, i;
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01003993 signed char op;
3994 long long data, value;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003995
Emeric Brun819fc6f2017-06-13 19:37:32 +02003996
Willy Tarreau2b64a352020-01-22 17:09:47 +01003997 for (i = 0; i < STKTABLE_FILTER_LEN; i++) {
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01003998 if (appctx->ctx.table.data_type[i] == -1)
3999 break;
4000 dt = appctx->ctx.table.data_type[i];
4001 ptr = stktable_data_ptr(appctx->ctx.table.t,
4002 appctx->ctx.table.entry,
4003 dt);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004004
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004005 data = 0;
4006 switch (stktable_data_types[dt].std_type) {
4007 case STD_T_SINT:
4008 data = stktable_data_cast(ptr, std_t_sint);
4009 break;
4010 case STD_T_UINT:
4011 data = stktable_data_cast(ptr, std_t_uint);
4012 break;
4013 case STD_T_ULL:
4014 data = stktable_data_cast(ptr, std_t_ull);
4015 break;
4016 case STD_T_FRQP:
4017 data = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
4018 appctx->ctx.table.t->data_arg[dt].u);
4019 break;
4020 }
4021
4022 op = appctx->ctx.table.data_op[i];
4023 value = appctx->ctx.table.value[i];
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004024
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004025 /* skip the entry if the data does not match the test and the value */
4026 if ((data < value &&
4027 (op == STD_OP_EQ || op == STD_OP_GT || op == STD_OP_GE)) ||
4028 (data == value &&
4029 (op == STD_OP_NE || op == STD_OP_GT || op == STD_OP_LT)) ||
4030 (data > value &&
4031 (op == STD_OP_EQ || op == STD_OP_LT || op == STD_OP_LE))) {
4032 skip_entry = 1;
4033 break;
4034 }
4035 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004036 }
4037
4038 if (show && !skip_entry &&
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004039 !table_dump_entry_to_buffer(&trash, si, appctx->ctx.table.t, appctx->ctx.table.entry)) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004040 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &appctx->ctx.table.entry->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004041 return 0;
4042 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004043
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004044 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &appctx->ctx.table.entry->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004045
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004046 HA_SPIN_LOCK(STK_TABLE_LOCK, &appctx->ctx.table.t->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004047 appctx->ctx.table.entry->ref_cnt--;
4048
4049 eb = ebmb_next(&appctx->ctx.table.entry->key);
4050 if (eb) {
4051 struct stksess *old = appctx->ctx.table.entry;
4052 appctx->ctx.table.entry = ebmb_entry(eb, struct stksess, key);
4053 if (show)
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004054 __stksess_kill_if_expired(appctx->ctx.table.t, old);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004055 else if (!skip_entry && !appctx->ctx.table.entry->ref_cnt)
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004056 __stksess_kill(appctx->ctx.table.t, old);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004057 appctx->ctx.table.entry->ref_cnt++;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004058 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &appctx->ctx.table.t->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004059 break;
4060 }
4061
4062
4063 if (show)
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004064 __stksess_kill_if_expired(appctx->ctx.table.t, appctx->ctx.table.entry);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004065 else if (!skip_entry && !appctx->ctx.table.entry->ref_cnt)
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004066 __stksess_kill(appctx->ctx.table.t, appctx->ctx.table.entry);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004067
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004068 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &appctx->ctx.table.t->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004069
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004070 appctx->ctx.table.t = appctx->ctx.table.t->next;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004071 appctx->st2 = STAT_ST_INFO;
4072 break;
4073
4074 case STAT_ST_END:
4075 appctx->st2 = STAT_ST_FIN;
4076 break;
4077 }
4078 }
4079 return 1;
4080}
4081
4082static void cli_release_show_table(struct appctx *appctx)
4083{
4084 if (appctx->st2 == STAT_ST_LIST) {
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004085 stksess_kill_if_expired(appctx->ctx.table.t, appctx->ctx.table.entry, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004086 }
4087}
4088
Willy Tarreau478331d2020-08-28 11:31:31 +02004089static void stkt_late_init(void)
4090{
4091 struct sample_fetch *f;
4092
4093 f = find_sample_fetch("src", strlen("src"));
4094 if (f)
4095 smp_fetch_src = f->process;
4096}
4097
4098INITCALL0(STG_INIT, stkt_late_init);
4099
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004100/* register cli keywords */
4101static struct cli_kw_list cli_kws = {{ },{
Willy Tarreaub205bfd2021-05-07 11:38:37 +02004102 { { "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 },
4103 { { "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 },
4104 { { "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 +01004105 {{},}
4106}};
4107
Willy Tarreau0108d902018-11-25 19:14:37 +01004108INITCALL1(STG_REGISTER, cli_register_kw, &cli_kws);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004109
Thierry FOURNIER236657b2015-08-19 08:25:14 +02004110static struct action_kw_list tcp_conn_kws = { { }, {
Amaury Denoyellee4a617c2021-05-06 15:33:09 +02004111 { "sc-inc-gpc0", parse_inc_gpc0, KWF_MATCH_PREFIX },
4112 { "sc-inc-gpc1", parse_inc_gpc1, KWF_MATCH_PREFIX },
4113 { "sc-set-gpt0", parse_set_gpt0, KWF_MATCH_PREFIX },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02004114 { /* END */ }
4115}};
4116
Willy Tarreau0108d902018-11-25 19:14:37 +01004117INITCALL1(STG_REGISTER, tcp_req_conn_keywords_register, &tcp_conn_kws);
4118
Willy Tarreau620408f2016-10-21 16:37:51 +02004119static struct action_kw_list tcp_sess_kws = { { }, {
Amaury Denoyellee4a617c2021-05-06 15:33:09 +02004120 { "sc-inc-gpc0", parse_inc_gpc0, KWF_MATCH_PREFIX },
4121 { "sc-inc-gpc1", parse_inc_gpc1, KWF_MATCH_PREFIX },
4122 { "sc-set-gpt0", parse_set_gpt0, KWF_MATCH_PREFIX },
Willy Tarreau620408f2016-10-21 16:37:51 +02004123 { /* END */ }
4124}};
4125
Willy Tarreau0108d902018-11-25 19:14:37 +01004126INITCALL1(STG_REGISTER, tcp_req_sess_keywords_register, &tcp_sess_kws);
4127
Thierry FOURNIER236657b2015-08-19 08:25:14 +02004128static struct action_kw_list tcp_req_kws = { { }, {
Amaury Denoyellee4a617c2021-05-06 15:33:09 +02004129 { "sc-inc-gpc0", parse_inc_gpc0, KWF_MATCH_PREFIX },
4130 { "sc-inc-gpc1", parse_inc_gpc1, KWF_MATCH_PREFIX },
4131 { "sc-set-gpt0", parse_set_gpt0, KWF_MATCH_PREFIX },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02004132 { /* END */ }
4133}};
4134
Willy Tarreau0108d902018-11-25 19:14:37 +01004135INITCALL1(STG_REGISTER, tcp_req_cont_keywords_register, &tcp_req_kws);
4136
Thierry FOURNIER236657b2015-08-19 08:25:14 +02004137static struct action_kw_list tcp_res_kws = { { }, {
Amaury Denoyellee4a617c2021-05-06 15:33:09 +02004138 { "sc-inc-gpc0", parse_inc_gpc0, KWF_MATCH_PREFIX },
4139 { "sc-inc-gpc1", parse_inc_gpc1, KWF_MATCH_PREFIX },
4140 { "sc-set-gpt0", parse_set_gpt0, KWF_MATCH_PREFIX },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02004141 { /* END */ }
4142}};
4143
Willy Tarreau0108d902018-11-25 19:14:37 +01004144INITCALL1(STG_REGISTER, tcp_res_cont_keywords_register, &tcp_res_kws);
4145
Thierry FOURNIER236657b2015-08-19 08:25:14 +02004146static struct action_kw_list http_req_kws = { { }, {
Amaury Denoyellee4a617c2021-05-06 15:33:09 +02004147 { "sc-inc-gpc0", parse_inc_gpc0, KWF_MATCH_PREFIX },
4148 { "sc-inc-gpc1", parse_inc_gpc1, KWF_MATCH_PREFIX },
4149 { "sc-set-gpt0", parse_set_gpt0, KWF_MATCH_PREFIX },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02004150 { /* END */ }
4151}};
4152
Willy Tarreau0108d902018-11-25 19:14:37 +01004153INITCALL1(STG_REGISTER, http_req_keywords_register, &http_req_kws);
4154
Thierry FOURNIER236657b2015-08-19 08:25:14 +02004155static struct action_kw_list http_res_kws = { { }, {
Amaury Denoyellee4a617c2021-05-06 15:33:09 +02004156 { "sc-inc-gpc0", parse_inc_gpc0, KWF_MATCH_PREFIX },
4157 { "sc-inc-gpc1", parse_inc_gpc1, KWF_MATCH_PREFIX },
4158 { "sc-set-gpt0", parse_set_gpt0, KWF_MATCH_PREFIX },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02004159 { /* END */ }
4160}};
4161
Willy Tarreau0108d902018-11-25 19:14:37 +01004162INITCALL1(STG_REGISTER, http_res_keywords_register, &http_res_kws);
4163
Willy Tarreau7d562212016-11-25 16:10:05 +01004164/* Note: must not be declared <const> as its list will be overwritten.
4165 * Please take care of keeping this list alphabetically sorted.
4166 */
4167static struct sample_fetch_kw_list smp_fetch_keywords = {ILH, {
4168 { "sc_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4169 { "sc_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4170 { "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 +01004171 { "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 +01004172 { "sc_conn_cnt", smp_fetch_sc_conn_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4173 { "sc_conn_cur", smp_fetch_sc_conn_cur, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4174 { "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 +01004175 { "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 +01004176 { "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 +01004177 { "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 +01004178 { "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 +01004179 { "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 +01004180 { "sc_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4181 { "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 +01004182 { "sc_http_fail_cnt", smp_fetch_sc_http_fail_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4183 { "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 +01004184 { "sc_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4185 { "sc_http_req_rate", smp_fetch_sc_http_req_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4186 { "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 +01004187 { "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 +01004188 { "sc_kbytes_in", smp_fetch_sc_kbytes_in, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4189 { "sc_kbytes_out", smp_fetch_sc_kbytes_out, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4190 { "sc_sess_cnt", smp_fetch_sc_sess_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4191 { "sc_sess_rate", smp_fetch_sc_sess_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4192 { "sc_tracked", smp_fetch_sc_tracked, ARG2(1,SINT,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
4193 { "sc_trackers", smp_fetch_sc_trackers, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4194 { "sc0_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4195 { "sc0_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4196 { "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 +01004197 { "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 +01004198 { "sc0_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4199 { "sc0_conn_cur", smp_fetch_sc_conn_cur, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4200 { "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 +01004201 { "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 +01004202 { "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 +01004203 { "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 +01004204 { "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 +01004205 { "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 +01004206 { "sc0_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4207 { "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 +01004208 { "sc0_http_fail_cnt", smp_fetch_sc_http_fail_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4209 { "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 +01004210 { "sc0_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4211 { "sc0_http_req_rate", smp_fetch_sc_http_req_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4212 { "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 +01004213 { "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 +01004214 { "sc0_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4215 { "sc0_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4216 { "sc0_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4217 { "sc0_sess_rate", smp_fetch_sc_sess_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4218 { "sc0_tracked", smp_fetch_sc_tracked, ARG1(0,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
4219 { "sc0_trackers", smp_fetch_sc_trackers, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4220 { "sc1_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4221 { "sc1_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4222 { "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 +01004223 { "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 +01004224 { "sc1_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4225 { "sc1_conn_cur", smp_fetch_sc_conn_cur, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4226 { "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 +01004227 { "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 +01004228 { "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 +01004229 { "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 +01004230 { "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 +01004231 { "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 +01004232 { "sc1_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4233 { "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 +01004234 { "sc1_http_fail_cnt", smp_fetch_sc_http_fail_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4235 { "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 +01004236 { "sc1_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4237 { "sc1_http_req_rate", smp_fetch_sc_http_req_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4238 { "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 +01004239 { "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 +01004240 { "sc1_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4241 { "sc1_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4242 { "sc1_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4243 { "sc1_sess_rate", smp_fetch_sc_sess_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4244 { "sc1_tracked", smp_fetch_sc_tracked, ARG1(0,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
4245 { "sc1_trackers", smp_fetch_sc_trackers, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4246 { "sc2_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4247 { "sc2_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4248 { "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 +01004249 { "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 +01004250 { "sc2_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4251 { "sc2_conn_cur", smp_fetch_sc_conn_cur, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4252 { "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 +01004253 { "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 +01004254 { "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 +01004255 { "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 +01004256 { "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 +01004257 { "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 +01004258 { "sc2_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4259 { "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 +01004260 { "sc2_http_fail_cnt", smp_fetch_sc_http_fail_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4261 { "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 +01004262 { "sc2_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4263 { "sc2_http_req_rate", smp_fetch_sc_http_req_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4264 { "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 +01004265 { "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 +01004266 { "sc2_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4267 { "sc2_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4268 { "sc2_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4269 { "sc2_sess_rate", smp_fetch_sc_sess_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4270 { "sc2_tracked", smp_fetch_sc_tracked, ARG1(0,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
4271 { "sc2_trackers", smp_fetch_sc_trackers, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4272 { "src_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4273 { "src_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4274 { "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 +01004275 { "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 +01004276 { "src_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4277 { "src_conn_cur", smp_fetch_sc_conn_cur, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4278 { "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 +01004279 { "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 +01004280 { "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 +01004281 { "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 +01004282 { "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 +01004283 { "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 +01004284 { "src_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4285 { "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 +01004286 { "src_http_fail_cnt", smp_fetch_sc_http_fail_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4287 { "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 +01004288 { "src_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4289 { "src_http_req_rate", smp_fetch_sc_http_req_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4290 { "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 +01004291 { "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 +01004292 { "src_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4293 { "src_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4294 { "src_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4295 { "src_sess_rate", smp_fetch_sc_sess_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4296 { "src_updt_conn_cnt", smp_fetch_src_updt_conn_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4297 { "table_avl", smp_fetch_table_avl, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4298 { "table_cnt", smp_fetch_table_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4299 { /* END */ },
4300}};
4301
Willy Tarreau0108d902018-11-25 19:14:37 +01004302INITCALL1(STG_REGISTER, sample_register_fetches, &smp_fetch_keywords);
Willy Tarreau7d562212016-11-25 16:10:05 +01004303
Willy Tarreaud9f316a2014-07-10 14:03:38 +02004304/* Note: must not be declared <const> as its list will be overwritten */
4305static struct sample_conv_kw_list sample_conv_kws = {ILH, {
Willy Tarreau2d17db52016-05-25 17:16:38 +02004306 { "in_table", sample_conv_in_table, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_BOOL },
4307 { "table_bytes_in_rate", sample_conv_table_bytes_in_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4308 { "table_bytes_out_rate", sample_conv_table_bytes_out_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4309 { "table_conn_cnt", sample_conv_table_conn_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4310 { "table_conn_cur", sample_conv_table_conn_cur, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4311 { "table_conn_rate", sample_conv_table_conn_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4312 { "table_gpt0", sample_conv_table_gpt0, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4313 { "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 +01004314 { "table_gpc1", sample_conv_table_gpc1, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
Willy Tarreau2d17db52016-05-25 17:16:38 +02004315 { "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 +01004316 { "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 +02004317 { "table_http_err_cnt", sample_conv_table_http_err_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4318 { "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 +01004319 { "table_http_fail_cnt", sample_conv_table_http_fail_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4320 { "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 +02004321 { "table_http_req_cnt", sample_conv_table_http_req_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4322 { "table_http_req_rate", sample_conv_table_http_req_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4323 { "table_kbytes_in", sample_conv_table_kbytes_in, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4324 { "table_kbytes_out", sample_conv_table_kbytes_out, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4325 { "table_server_id", sample_conv_table_server_id, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4326 { "table_sess_cnt", sample_conv_table_sess_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4327 { "table_sess_rate", sample_conv_table_sess_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4328 { "table_trackers", sample_conv_table_trackers, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
Willy Tarreaud9f316a2014-07-10 14:03:38 +02004329 { /* END */ },
4330}};
4331
Willy Tarreau0108d902018-11-25 19:14:37 +01004332INITCALL1(STG_REGISTER, sample_register_convs, &sample_conv_kws);