blob: 1fe60a00ca03c2e2cab5ff5d1b7d141df788c117 [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
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100710/*
Frédéric Lécaillec02766a2019-03-20 15:06:55 +0100711 * Parse a line with <linenum> as number in <file> configuration file to configure
712 * the stick-table with <t> as address and <id> as ID.
713 * <peers> provides the "peers" section pointer only if this function is called
714 * from a "peers" section.
715 * <nid> is the stick-table name which is sent over the network. It must be equal
716 * to <id> if this stick-table is parsed from a proxy section, and prefixed by <peers>
717 * "peers" section name followed by a '/' character if parsed from a "peers" section.
Ilya Shipitsind4259502020-04-08 01:07:56 +0500718 * This is the responsibility of the caller to check this.
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100719 * Return an error status with ERR_* flags set if required, 0 if no error was encountered.
720 */
721int parse_stick_table(const char *file, int linenum, char **args,
Frédéric Lécaillec02766a2019-03-20 15:06:55 +0100722 struct stktable *t, char *id, char *nid, struct peers *peers)
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100723{
724 int err_code = 0;
725 int idx = 1;
726 unsigned int val;
727
728 if (!id || !*id) {
729 ha_alert("parsing [%s:%d] : %s: ID not provided.\n", file, linenum, args[0]);
730 err_code |= ERR_ALERT | ERR_ABORT;
731 goto out;
732 }
733
734 /* Store the "peers" section if this function is called from a "peers" section. */
735 if (peers) {
736 t->peers.p = peers;
737 idx++;
738 }
739
740 t->id = id;
Frédéric Lécaillec02766a2019-03-20 15:06:55 +0100741 t->nid = nid;
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100742 t->type = (unsigned int)-1;
743 t->conf.file = file;
744 t->conf.line = linenum;
745
746 while (*args[idx]) {
747 const char *err;
748
749 if (strcmp(args[idx], "size") == 0) {
750 idx++;
751 if (!*(args[idx])) {
752 ha_alert("parsing [%s:%d] : %s: missing argument after '%s'.\n",
753 file, linenum, args[0], args[idx-1]);
754 err_code |= ERR_ALERT | ERR_FATAL;
755 goto out;
756 }
757 if ((err = parse_size_err(args[idx], &t->size))) {
758 ha_alert("parsing [%s:%d] : %s: unexpected character '%c' in argument of '%s'.\n",
759 file, linenum, args[0], *err, args[idx-1]);
760 err_code |= ERR_ALERT | ERR_FATAL;
761 goto out;
762 }
763 idx++;
764 }
765 /* This argument does not exit in "peers" section. */
766 else if (!peers && strcmp(args[idx], "peers") == 0) {
767 idx++;
768 if (!*(args[idx])) {
769 ha_alert("parsing [%s:%d] : %s: missing argument after '%s'.\n",
770 file, linenum, args[0], args[idx-1]);
771 err_code |= ERR_ALERT | ERR_FATAL;
772 goto out;
773 }
774 t->peers.name = strdup(args[idx++]);
775 }
776 else if (strcmp(args[idx], "expire") == 0) {
777 idx++;
778 if (!*(args[idx])) {
779 ha_alert("parsing [%s:%d] : %s: missing argument after '%s'.\n",
780 file, linenum, args[0], args[idx-1]);
781 err_code |= ERR_ALERT | ERR_FATAL;
782 goto out;
783 }
784 err = parse_time_err(args[idx], &val, TIME_UNIT_MS);
Willy Tarreau9faebe32019-06-07 19:00:37 +0200785 if (err == PARSE_TIME_OVER) {
786 ha_alert("parsing [%s:%d]: %s: timer overflow in argument <%s> to <%s>, maximum value is 2147483647 ms (~24.8 days).\n",
787 file, linenum, args[0], args[idx], args[idx-1]);
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100788 err_code |= ERR_ALERT | ERR_FATAL;
789 goto out;
790 }
Willy Tarreau9faebe32019-06-07 19:00:37 +0200791 else if (err == PARSE_TIME_UNDER) {
792 ha_alert("parsing [%s:%d]: %s: timer underflow in argument <%s> to <%s>, minimum non-null value is 1 ms.\n",
793 file, linenum, args[0], args[idx], args[idx-1]);
794 err_code |= ERR_ALERT | ERR_FATAL;
795 goto out;
796 }
797 else if (err) {
798 ha_alert("parsing [%s:%d] : %s: unexpected character '%c' in argument of '%s'.\n",
799 file, linenum, args[0], *err, args[idx-1]);
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100800 err_code |= ERR_ALERT | ERR_FATAL;
801 goto out;
802 }
803 t->expire = val;
804 idx++;
805 }
806 else if (strcmp(args[idx], "nopurge") == 0) {
807 t->nopurge = 1;
808 idx++;
809 }
810 else if (strcmp(args[idx], "type") == 0) {
811 idx++;
812 if (stktable_parse_type(args, &idx, &t->type, &t->key_size) != 0) {
813 ha_alert("parsing [%s:%d] : %s: unknown type '%s'.\n",
814 file, linenum, args[0], args[idx]);
815 err_code |= ERR_ALERT | ERR_FATAL;
816 goto out;
817 }
818 /* idx already points to next arg */
819 }
820 else if (strcmp(args[idx], "store") == 0) {
821 int type, err;
822 char *cw, *nw, *sa;
823
824 idx++;
825 nw = args[idx];
826 while (*nw) {
827 /* the "store" keyword supports a comma-separated list */
828 cw = nw;
829 sa = NULL; /* store arg */
830 while (*nw && *nw != ',') {
831 if (*nw == '(') {
832 *nw = 0;
833 sa = ++nw;
834 while (*nw != ')') {
835 if (!*nw) {
836 ha_alert("parsing [%s:%d] : %s: missing closing parenthesis after store option '%s'.\n",
837 file, linenum, args[0], cw);
838 err_code |= ERR_ALERT | ERR_FATAL;
839 goto out;
840 }
841 nw++;
842 }
843 *nw = '\0';
844 }
845 nw++;
846 }
847 if (*nw)
848 *nw++ = '\0';
849 type = stktable_get_data_type(cw);
850 if (type < 0) {
851 ha_alert("parsing [%s:%d] : %s: unknown store option '%s'.\n",
852 file, linenum, args[0], cw);
853 err_code |= ERR_ALERT | ERR_FATAL;
854 goto out;
855 }
856
857 err = stktable_alloc_data_type(t, type, sa);
858 switch (err) {
859 case PE_NONE: break;
860 case PE_EXIST:
861 ha_warning("parsing [%s:%d]: %s: store option '%s' already enabled, ignored.\n",
862 file, linenum, args[0], cw);
863 err_code |= ERR_WARN;
864 break;
865
866 case PE_ARG_MISSING:
867 ha_alert("parsing [%s:%d] : %s: missing argument to store option '%s'.\n",
868 file, linenum, args[0], cw);
869 err_code |= ERR_ALERT | ERR_FATAL;
870 goto out;
871
872 case PE_ARG_NOT_USED:
873 ha_alert("parsing [%s:%d] : %s: unexpected argument to store option '%s'.\n",
874 file, linenum, args[0], cw);
875 err_code |= ERR_ALERT | ERR_FATAL;
876 goto out;
877
878 default:
879 ha_alert("parsing [%s:%d] : %s: error when processing store option '%s'.\n",
880 file, linenum, args[0], cw);
881 err_code |= ERR_ALERT | ERR_FATAL;
882 goto out;
883 }
884 }
885 idx++;
886 }
Thayne McCombs92149f92020-11-20 01:28:26 -0700887 else if (strcmp(args[idx], "srvkey") == 0) {
888 char *keytype;
889 idx++;
890 keytype = args[idx];
891 if (strcmp(keytype, "name") == 0) {
892 t->server_key_type = STKTABLE_SRV_NAME;
893 }
894 else if (strcmp(keytype, "addr") == 0) {
895 t->server_key_type = STKTABLE_SRV_ADDR;
896 }
897 else {
898 ha_alert("parsing [%s:%d] : %s : unknown server key type '%s'.\n",
899 file, linenum, args[0], keytype);
900 err_code |= ERR_ALERT | ERR_FATAL;
901 goto out;
902
903 }
904 idx++;
905 }
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100906 else {
907 ha_alert("parsing [%s:%d] : %s: unknown argument '%s'.\n",
908 file, linenum, args[0], args[idx]);
909 err_code |= ERR_ALERT | ERR_FATAL;
910 goto out;
911 }
912 }
913
914 if (!t->size) {
915 ha_alert("parsing [%s:%d] : %s: missing size.\n",
916 file, linenum, args[0]);
917 err_code |= ERR_ALERT | ERR_FATAL;
918 goto out;
919 }
920
921 if (t->type == (unsigned int)-1) {
922 ha_alert("parsing [%s:%d] : %s: missing type.\n",
923 file, linenum, args[0]);
924 err_code |= ERR_ALERT | ERR_FATAL;
925 goto out;
926 }
927
928 out:
929 return err_code;
930}
931
Willy Tarreau8fed9032014-07-03 17:02:46 +0200932/* Prepares a stktable_key from a sample <smp> to search into table <t>.
Willy Tarreauf0c730a2016-05-25 17:07:56 +0200933 * Note that the sample *is* modified and that the returned key may point
934 * to it, so the sample must not be modified afterwards before the lookup.
Willy Tarreau8fed9032014-07-03 17:02:46 +0200935 * Returns NULL if the sample could not be converted (eg: no matching type),
936 * otherwise a pointer to the static stktable_key filled with what is needed
937 * for the lookup.
Willy Tarreauf0b38bf2010-06-06 13:22:23 +0200938 */
Willy Tarreau8fed9032014-07-03 17:02:46 +0200939struct stktable_key *smp_to_stkey(struct sample *smp, struct stktable *t)
Willy Tarreauf0b38bf2010-06-06 13:22:23 +0200940{
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200941 /* Convert sample. */
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200942 if (!sample_convert(smp, t->type))
Willy Tarreau7fc1c6e2012-04-26 11:03:17 +0200943 return NULL;
944
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200945 /* Fill static_table_key. */
946 switch (t->type) {
Emeric Brun485479d2010-09-23 18:02:19 +0200947
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200948 case SMP_T_IPV4:
Christopher Fauletca20d022017-08-29 15:30:31 +0200949 static_table_key.key = &smp->data.u.ipv4;
950 static_table_key.key_len = 4;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200951 break;
Emeric Brun485479d2010-09-23 18:02:19 +0200952
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200953 case SMP_T_IPV6:
Christopher Fauletca20d022017-08-29 15:30:31 +0200954 static_table_key.key = &smp->data.u.ipv6;
955 static_table_key.key_len = 16;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200956 break;
Emeric Brun485479d2010-09-23 18:02:19 +0200957
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200958 case SMP_T_SINT:
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200959 /* The stick table require a 32bit unsigned int, "sint" is a
960 * signed 64 it, so we can convert it inplace.
961 */
Willy Tarreau28c63c12019-10-23 06:21:05 +0200962 smp->data.u.sint = (unsigned int)smp->data.u.sint;
Christopher Fauletca20d022017-08-29 15:30:31 +0200963 static_table_key.key = &smp->data.u.sint;
964 static_table_key.key_len = 4;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200965 break;
966
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200967 case SMP_T_STR:
Willy Tarreauce6955e2016-08-09 11:59:12 +0200968 if (!smp_make_safe(smp))
969 return NULL;
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200970 static_table_key.key = smp->data.u.str.area;
971 static_table_key.key_len = smp->data.u.str.data;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200972 break;
Emeric Brun485479d2010-09-23 18:02:19 +0200973
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200974 case SMP_T_BIN:
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200975 if (smp->data.u.str.data < t->key_size) {
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200976 /* This type needs padding with 0. */
Willy Tarreauf65c6c02016-08-09 12:08:41 +0200977 if (!smp_make_rw(smp))
978 return NULL;
979
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200980 if (smp->data.u.str.size < t->key_size)
981 if (!smp_dup(smp))
982 return NULL;
983 if (smp->data.u.str.size < t->key_size)
984 return NULL;
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200985 memset(smp->data.u.str.area + smp->data.u.str.data, 0,
986 t->key_size - smp->data.u.str.data);
987 smp->data.u.str.data = t->key_size;
Emeric Brun485479d2010-09-23 18:02:19 +0200988 }
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200989 static_table_key.key = smp->data.u.str.area;
990 static_table_key.key_len = smp->data.u.str.data;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200991 break;
Emeric Brun485479d2010-09-23 18:02:19 +0200992
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200993 default: /* impossible case. */
994 return NULL;
Emeric Brun485479d2010-09-23 18:02:19 +0200995 }
996
Christopher Fauletca20d022017-08-29 15:30:31 +0200997 return &static_table_key;
Willy Tarreauf0b38bf2010-06-06 13:22:23 +0200998}
999
1000/*
Willy Tarreau8fed9032014-07-03 17:02:46 +02001001 * Process a fetch + format conversion as defined by the sample expression <expr>
1002 * on request or response considering the <opt> parameter. Returns either NULL if
1003 * no key could be extracted, or a pointer to the converted result stored in
1004 * static_table_key in format <table_type>. If <smp> is not NULL, it will be reset
1005 * and its flags will be initialized so that the caller gets a copy of the input
Willy Tarreau6bcb0a82014-07-30 08:56:35 +02001006 * sample, and knows why it was not accepted (eg: SMP_F_MAY_CHANGE is present
1007 * without SMP_OPT_FINAL). The output will be usable like this :
1008 *
1009 * return MAY_CHANGE FINAL Meaning for the sample
1010 * NULL 0 * Not present and will never be (eg: header)
1011 * NULL 1 0 Not present or unstable, could change (eg: req_len)
1012 * NULL 1 1 Not present, will not change anymore
1013 * smp 0 * Present and will not change (eg: header)
1014 * smp 1 0 not possible
1015 * smp 1 1 Present, last known value (eg: request length)
Willy Tarreau8fed9032014-07-03 17:02:46 +02001016 */
Willy Tarreau192252e2015-04-04 01:47:55 +02001017struct stktable_key *stktable_fetch_key(struct stktable *t, struct proxy *px, struct session *sess, struct stream *strm,
Willy Tarreau8fed9032014-07-03 17:02:46 +02001018 unsigned int opt, struct sample_expr *expr, struct sample *smp)
1019{
1020 if (smp)
1021 memset(smp, 0, sizeof(*smp));
1022
Willy Tarreau192252e2015-04-04 01:47:55 +02001023 smp = sample_process(px, sess, strm, opt, expr, smp);
Willy Tarreau8fed9032014-07-03 17:02:46 +02001024 if (!smp)
1025 return NULL;
1026
1027 if ((smp->flags & SMP_F_MAY_CHANGE) && !(opt & SMP_OPT_FINAL))
1028 return NULL; /* we can only use stable samples */
1029
1030 return smp_to_stkey(smp, t);
1031}
1032
1033/*
Willy Tarreau12785782012-04-27 21:37:17 +02001034 * Returns 1 if sample expression <expr> result can be converted to table key of
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001035 * type <table_type>, otherwise zero. Used in configuration check.
1036 */
Willy Tarreau12785782012-04-27 21:37:17 +02001037int stktable_compatible_sample(struct sample_expr *expr, unsigned long table_type)
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001038{
Thierry FOURNIERf73eb8f2013-11-27 15:30:55 +01001039 int out_type;
1040
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +02001041 if (table_type >= SMP_TYPES || !stktable_types[table_type].kw)
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001042 return 0;
1043
Thierry FOURNIERf73eb8f2013-11-27 15:30:55 +01001044 out_type = smp_expr_output_type(expr);
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001045
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001046 /* Convert sample. */
1047 if (!sample_casts[out_type][table_type])
Thierry FOURNIERf73eb8f2013-11-27 15:30:55 +01001048 return 0;
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001049
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001050 return 1;
1051}
Emeric Brun3bd697e2010-01-04 15:23:48 +01001052
Willy Tarreauedee1d62014-07-15 16:44:27 +02001053/* Extra data types processing : after the last one, some room may remain
1054 * before STKTABLE_DATA_TYPES that may be used to register extra data types
1055 * at run time.
1056 */
Willy Tarreau08d5f982010-06-06 13:34:54 +02001057struct stktable_data_type stktable_data_types[STKTABLE_DATA_TYPES] = {
Willy Tarreau3b9c6e02010-07-18 08:04:30 +02001058 [STKTABLE_DT_SERVER_ID] = { .name = "server_id", .std_type = STD_T_SINT },
Thierry FOURNIER3cf11112015-07-28 08:57:05 +02001059 [STKTABLE_DT_GPT0] = { .name = "gpt0", .std_type = STD_T_UINT },
Willy Tarreau3b9c6e02010-07-18 08:04:30 +02001060 [STKTABLE_DT_GPC0] = { .name = "gpc0", .std_type = STD_T_UINT },
Willy Tarreauba2ffd12013-05-29 15:54:14 +02001061 [STKTABLE_DT_GPC0_RATE] = { .name = "gpc0_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
Willy Tarreau3b9c6e02010-07-18 08:04:30 +02001062 [STKTABLE_DT_CONN_CNT] = { .name = "conn_cnt", .std_type = STD_T_UINT },
1063 [STKTABLE_DT_CONN_RATE] = { .name = "conn_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
1064 [STKTABLE_DT_CONN_CUR] = { .name = "conn_cur", .std_type = STD_T_UINT },
1065 [STKTABLE_DT_SESS_CNT] = { .name = "sess_cnt", .std_type = STD_T_UINT },
1066 [STKTABLE_DT_SESS_RATE] = { .name = "sess_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
1067 [STKTABLE_DT_HTTP_REQ_CNT] = { .name = "http_req_cnt", .std_type = STD_T_UINT },
1068 [STKTABLE_DT_HTTP_REQ_RATE] = { .name = "http_req_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
1069 [STKTABLE_DT_HTTP_ERR_CNT] = { .name = "http_err_cnt", .std_type = STD_T_UINT },
1070 [STKTABLE_DT_HTTP_ERR_RATE] = { .name = "http_err_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
1071 [STKTABLE_DT_BYTES_IN_CNT] = { .name = "bytes_in_cnt", .std_type = STD_T_ULL },
1072 [STKTABLE_DT_BYTES_IN_RATE] = { .name = "bytes_in_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
1073 [STKTABLE_DT_BYTES_OUT_CNT] = { .name = "bytes_out_cnt", .std_type = STD_T_ULL },
1074 [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 +01001075 [STKTABLE_DT_GPC1] = { .name = "gpc1", .std_type = STD_T_UINT },
1076 [STKTABLE_DT_GPC1_RATE] = { .name = "gpc1_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
Thayne McCombs92149f92020-11-20 01:28:26 -07001077 [STKTABLE_DT_SERVER_KEY] = { .name = "server_key", .std_type = STD_T_DICT },
Willy Tarreau826f3ab2021-02-10 12:07:15 +01001078 [STKTABLE_DT_HTTP_FAIL_CNT] = { .name = "http_fail_cnt", .std_type = STD_T_UINT },
1079 [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 +02001080};
1081
Willy Tarreauedee1d62014-07-15 16:44:27 +02001082/* Registers stick-table extra data type with index <idx>, name <name>, type
1083 * <std_type> and arg type <arg_type>. If the index is negative, the next free
1084 * index is automatically allocated. The allocated index is returned, or -1 if
1085 * no free index was found or <name> was already registered. The <name> is used
1086 * directly as a pointer, so if it's not stable, the caller must allocate it.
1087 */
1088int stktable_register_data_store(int idx, const char *name, int std_type, int arg_type)
1089{
1090 if (idx < 0) {
1091 for (idx = 0; idx < STKTABLE_DATA_TYPES; idx++) {
1092 if (!stktable_data_types[idx].name)
1093 break;
1094
1095 if (strcmp(stktable_data_types[idx].name, name) == 0)
1096 return -1;
1097 }
1098 }
1099
1100 if (idx >= STKTABLE_DATA_TYPES)
1101 return -1;
1102
1103 if (stktable_data_types[idx].name != NULL)
1104 return -1;
1105
1106 stktable_data_types[idx].name = name;
1107 stktable_data_types[idx].std_type = std_type;
1108 stktable_data_types[idx].arg_type = arg_type;
1109 return idx;
1110}
1111
Willy Tarreau08d5f982010-06-06 13:34:54 +02001112/*
1113 * Returns the data type number for the stktable_data_type whose name is <name>,
1114 * or <0 if not found.
1115 */
1116int stktable_get_data_type(char *name)
1117{
1118 int type;
1119
1120 for (type = 0; type < STKTABLE_DATA_TYPES; type++) {
Willy Tarreauedee1d62014-07-15 16:44:27 +02001121 if (!stktable_data_types[type].name)
1122 continue;
Willy Tarreau08d5f982010-06-06 13:34:54 +02001123 if (strcmp(name, stktable_data_types[type].name) == 0)
1124 return type;
1125 }
Thayne McCombs92149f92020-11-20 01:28:26 -07001126 /* For backwards compatibility */
1127 if (strcmp(name, "server_name") == 0)
1128 return STKTABLE_DT_SERVER_KEY;
Willy Tarreau08d5f982010-06-06 13:34:54 +02001129 return -1;
1130}
1131
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001132/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1133 * it up into this table. Returns true if found, false otherwise. The input
1134 * type is STR so that input samples are converted to string (since all types
1135 * can be converted to strings), then the function casts the string again into
1136 * the table's type. This is a double conversion, but in the future we might
1137 * support automatic input types to perform the cast on the fly.
1138 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001139static int sample_conv_in_table(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001140{
1141 struct stktable *t;
1142 struct stktable_key *key;
1143 struct stksess *ts;
1144
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001145 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001146
1147 key = smp_to_stkey(smp, t);
1148 if (!key)
1149 return 0;
1150
1151 ts = stktable_lookup_key(t, key);
1152
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001153 smp->data.type = SMP_T_BOOL;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001154 smp->data.u.sint = !!ts;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001155 smp->flags = SMP_F_VOL_TEST;
Willy Tarreau43e90352018-06-27 06:25:57 +02001156 stktable_release(t, ts);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001157 return 1;
1158}
1159
1160/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1161 * it up into this table. Returns the data rate received from clients in bytes/s
1162 * if the key is present in the table, otherwise zero, so that comparisons can
1163 * be easily performed. If the inspected parameter is not stored in the table,
1164 * <not found> is returned.
1165 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001166static int sample_conv_table_bytes_in_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001167{
1168 struct stktable *t;
1169 struct stktable_key *key;
1170 struct stksess *ts;
1171 void *ptr;
1172
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001173 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001174
1175 key = smp_to_stkey(smp, t);
1176 if (!key)
1177 return 0;
1178
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001179 ts = stktable_lookup_key(t, key);
1180
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001181 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001182 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001183 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001184
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001185 if (!ts) /* key not present */
1186 return 1;
1187
1188 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_IN_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001189 if (ptr)
1190 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, bytes_in_rate),
1191 t->data_arg[STKTABLE_DT_BYTES_IN_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001192
Daniel Corbett3e60b112018-05-27 09:47:12 -04001193 stktable_release(t, ts);
1194 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001195}
1196
1197/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1198 * it up into this table. Returns the cumulated number of connections for the key
1199 * if the key is present in the table, otherwise zero, so that comparisons can
1200 * be easily performed. If the inspected parameter is not stored in the table,
1201 * <not found> is returned.
1202 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001203static int sample_conv_table_conn_cnt(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001204{
1205 struct stktable *t;
1206 struct stktable_key *key;
1207 struct stksess *ts;
1208 void *ptr;
1209
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001210 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001211
1212 key = smp_to_stkey(smp, t);
1213 if (!key)
1214 return 0;
1215
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001216 ts = stktable_lookup_key(t, key);
1217
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001218 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001219 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001220 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001221
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001222 if (!ts) /* key not present */
1223 return 1;
1224
1225 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_CONN_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001226 if (ptr)
1227 smp->data.u.sint = stktable_data_cast(ptr, conn_cnt);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001228
Daniel Corbett3e60b112018-05-27 09:47:12 -04001229 stktable_release(t, ts);
1230 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001231}
1232
1233/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1234 * it up into this table. Returns the number of concurrent connections for the
1235 * key if the key is present in the table, otherwise zero, so that comparisons
1236 * can be easily performed. If the inspected parameter is not stored in the
1237 * table, <not found> is returned.
1238 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001239static int sample_conv_table_conn_cur(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001240{
1241 struct stktable *t;
1242 struct stktable_key *key;
1243 struct stksess *ts;
1244 void *ptr;
1245
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001246 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001247
1248 key = smp_to_stkey(smp, t);
1249 if (!key)
1250 return 0;
1251
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001252 ts = stktable_lookup_key(t, key);
1253
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001254 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001255 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001256 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001257
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001258 if (!ts) /* key not present */
1259 return 1;
1260
1261 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_CONN_CUR);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001262 if (ptr)
1263 smp->data.u.sint = stktable_data_cast(ptr, conn_cur);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001264
Daniel Corbett3e60b112018-05-27 09:47:12 -04001265 stktable_release(t, ts);
1266 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001267}
1268
1269/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1270 * it up into this table. Returns the rate of incoming connections from the key
1271 * if the key is present in the table, otherwise zero, so that comparisons can
1272 * be easily performed. If the inspected parameter is not stored in the table,
1273 * <not found> is returned.
1274 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001275static int sample_conv_table_conn_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001276{
1277 struct stktable *t;
1278 struct stktable_key *key;
1279 struct stksess *ts;
1280 void *ptr;
1281
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001282 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001283
1284 key = smp_to_stkey(smp, t);
1285 if (!key)
1286 return 0;
1287
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001288 ts = stktable_lookup_key(t, key);
1289
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001290 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001291 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001292 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001293
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001294 if (!ts) /* key not present */
1295 return 1;
1296
1297 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_CONN_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001298 if (ptr)
1299 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, conn_rate),
1300 t->data_arg[STKTABLE_DT_CONN_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001301
Daniel Corbett3e60b112018-05-27 09:47:12 -04001302 stktable_release(t, ts);
1303 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001304}
1305
1306/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1307 * it up into this table. Returns the data rate sent to clients in bytes/s
1308 * if the key is present in the table, otherwise zero, so that comparisons can
1309 * be easily performed. If the inspected parameter is not stored in the table,
1310 * <not found> is returned.
1311 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001312static int sample_conv_table_bytes_out_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001313{
1314 struct stktable *t;
1315 struct stktable_key *key;
1316 struct stksess *ts;
1317 void *ptr;
1318
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001319 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001320
1321 key = smp_to_stkey(smp, t);
1322 if (!key)
1323 return 0;
1324
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001325 ts = stktable_lookup_key(t, key);
1326
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001327 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001328 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001329 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001330
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001331 if (!ts) /* key not present */
1332 return 1;
1333
1334 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_OUT_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001335 if (ptr)
1336 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, bytes_out_rate),
1337 t->data_arg[STKTABLE_DT_BYTES_OUT_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001338
Daniel Corbett3e60b112018-05-27 09:47:12 -04001339 stktable_release(t, ts);
1340 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001341}
1342
1343/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001344 * it up into this table. Returns the value of the GPT0 tag for the key
1345 * if the key is present in the table, otherwise false, so that comparisons can
1346 * be easily performed. If the inspected parameter is not stored in the table,
1347 * <not found> is returned.
1348 */
1349static int sample_conv_table_gpt0(const struct arg *arg_p, struct sample *smp, void *private)
1350{
1351 struct stktable *t;
1352 struct stktable_key *key;
1353 struct stksess *ts;
1354 void *ptr;
1355
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001356 t = arg_p[0].data.t;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001357
1358 key = smp_to_stkey(smp, t);
1359 if (!key)
1360 return 0;
1361
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001362 ts = stktable_lookup_key(t, key);
1363
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001364 smp->flags = SMP_F_VOL_TEST;
1365 smp->data.type = SMP_T_SINT;
1366 smp->data.u.sint = 0;
1367
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001368 if (!ts) /* key not present */
1369 return 1;
1370
1371 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPT0);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001372 if (ptr)
1373 smp->data.u.sint = stktable_data_cast(ptr, gpt0);
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001374
Daniel Corbett3e60b112018-05-27 09:47:12 -04001375 stktable_release(t, ts);
1376 return !!ptr;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001377}
1378
1379/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001380 * it up into this table. Returns the value of the GPC0 counter for the key
1381 * if the key is present in the table, otherwise zero, so that comparisons can
1382 * be easily performed. If the inspected parameter is not stored in the table,
1383 * <not found> is returned.
1384 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001385static int sample_conv_table_gpc0(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001386{
1387 struct stktable *t;
1388 struct stktable_key *key;
1389 struct stksess *ts;
1390 void *ptr;
1391
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001392 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001393
1394 key = smp_to_stkey(smp, t);
1395 if (!key)
1396 return 0;
1397
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001398 ts = stktable_lookup_key(t, key);
1399
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001400 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001401 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001402 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001403
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001404 if (!ts) /* key not present */
1405 return 1;
1406
1407 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPC0);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001408 if (ptr)
1409 smp->data.u.sint = stktable_data_cast(ptr, gpc0);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001410
Daniel Corbett3e60b112018-05-27 09:47:12 -04001411 stktable_release(t, ts);
1412 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001413}
1414
1415/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1416 * it up into this table. Returns the event rate of the GPC0 counter for the key
1417 * if the key is present in the table, otherwise zero, so that comparisons can
1418 * be easily performed. If the inspected parameter is not stored in the table,
1419 * <not found> is returned.
1420 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001421static int sample_conv_table_gpc0_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001422{
1423 struct stktable *t;
1424 struct stktable_key *key;
1425 struct stksess *ts;
1426 void *ptr;
1427
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001428 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001429
1430 key = smp_to_stkey(smp, t);
1431 if (!key)
1432 return 0;
1433
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001434 ts = stktable_lookup_key(t, key);
1435
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001436 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001437 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001438 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001439
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001440 if (!ts) /* key not present */
1441 return 1;
1442
1443 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPC0_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001444 if (ptr)
1445 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, gpc0_rate),
1446 t->data_arg[STKTABLE_DT_GPC0_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001447
Daniel Corbett3e60b112018-05-27 09:47:12 -04001448 stktable_release(t, ts);
1449 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001450}
1451
1452/* 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 +01001453 * it up into this table. Returns the value of the GPC1 counter for the key
1454 * if the key is present in the table, otherwise zero, so that comparisons can
1455 * be easily performed. If the inspected parameter is not stored in the table,
1456 * <not found> is returned.
1457 */
1458static int sample_conv_table_gpc1(const struct arg *arg_p, struct sample *smp, void *private)
1459{
1460 struct stktable *t;
1461 struct stktable_key *key;
1462 struct stksess *ts;
1463 void *ptr;
1464
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001465 t = arg_p[0].data.t;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001466
1467 key = smp_to_stkey(smp, t);
1468 if (!key)
1469 return 0;
1470
1471 ts = stktable_lookup_key(t, key);
1472
1473 smp->flags = SMP_F_VOL_TEST;
1474 smp->data.type = SMP_T_SINT;
1475 smp->data.u.sint = 0;
1476
1477 if (!ts) /* key not present */
1478 return 1;
1479
1480 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPC1);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001481 if (ptr)
1482 smp->data.u.sint = stktable_data_cast(ptr, gpc1);
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001483
Daniel Corbett3e60b112018-05-27 09:47:12 -04001484 stktable_release(t, ts);
1485 return !!ptr;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001486}
1487
1488/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1489 * it up into this table. Returns the event rate of the GPC1 counter for the key
1490 * if the key is present in the table, otherwise zero, so that comparisons can
1491 * be easily performed. If the inspected parameter is not stored in the table,
1492 * <not found> is returned.
1493 */
1494static int sample_conv_table_gpc1_rate(const struct arg *arg_p, struct sample *smp, void *private)
1495{
1496 struct stktable *t;
1497 struct stktable_key *key;
1498 struct stksess *ts;
1499 void *ptr;
1500
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001501 t = arg_p[0].data.t;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001502
1503 key = smp_to_stkey(smp, t);
1504 if (!key)
1505 return 0;
1506
1507 ts = stktable_lookup_key(t, key);
1508
1509 smp->flags = SMP_F_VOL_TEST;
1510 smp->data.type = SMP_T_SINT;
1511 smp->data.u.sint = 0;
1512
1513 if (!ts) /* key not present */
1514 return 1;
1515
1516 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPC1_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001517 if (ptr)
1518 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, gpc1_rate),
1519 t->data_arg[STKTABLE_DT_GPC1_RATE].u);
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001520
Daniel Corbett3e60b112018-05-27 09:47:12 -04001521 stktable_release(t, ts);
1522 return !!ptr;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001523}
1524
1525/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001526 * it up into this table. Returns the cumulated number of HTTP request errors
1527 * for the key if the key is present in the table, otherwise zero, so that
1528 * comparisons can be easily performed. If the inspected parameter is not stored
1529 * in the table, <not found> is returned.
1530 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001531static int sample_conv_table_http_err_cnt(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001532{
1533 struct stktable *t;
1534 struct stktable_key *key;
1535 struct stksess *ts;
1536 void *ptr;
1537
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001538 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001539
1540 key = smp_to_stkey(smp, t);
1541 if (!key)
1542 return 0;
1543
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001544 ts = stktable_lookup_key(t, key);
1545
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001546 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001547 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001548 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001549
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001550 if (!ts) /* key not present */
1551 return 1;
1552
1553 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_ERR_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001554 if (ptr)
1555 smp->data.u.sint = stktable_data_cast(ptr, http_err_cnt);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001556
Daniel Corbett3e60b112018-05-27 09:47:12 -04001557 stktable_release(t, ts);
1558 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001559}
1560
1561/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1562 * it up into this table. Returns the HTTP request error rate the key
1563 * if the key is present in the table, otherwise zero, so that comparisons can
1564 * be easily performed. If the inspected parameter is not stored in the table,
1565 * <not found> is returned.
1566 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001567static int sample_conv_table_http_err_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001568{
1569 struct stktable *t;
1570 struct stktable_key *key;
1571 struct stksess *ts;
1572 void *ptr;
1573
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001574 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001575
1576 key = smp_to_stkey(smp, t);
1577 if (!key)
1578 return 0;
1579
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001580 ts = stktable_lookup_key(t, key);
1581
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001582 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001583 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001584 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001585
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001586 if (!ts) /* key not present */
1587 return 1;
1588
1589 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_ERR_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001590 if (ptr)
1591 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, http_err_rate),
1592 t->data_arg[STKTABLE_DT_HTTP_ERR_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001593
Daniel Corbett3e60b112018-05-27 09:47:12 -04001594 stktable_release(t, ts);
1595 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001596}
1597
1598/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Willy Tarreau826f3ab2021-02-10 12:07:15 +01001599 * it up into this table. Returns the cumulated number of HTTP response failures
1600 * for the key if the key is present in the table, otherwise zero, so that
1601 * comparisons can be easily performed. If the inspected parameter is not stored
1602 * in the table, <not found> is returned.
1603 */
1604static int sample_conv_table_http_fail_cnt(const struct arg *arg_p, struct sample *smp, void *private)
1605{
1606 struct stktable *t;
1607 struct stktable_key *key;
1608 struct stksess *ts;
1609 void *ptr;
1610
1611 t = arg_p[0].data.t;
1612
1613 key = smp_to_stkey(smp, t);
1614 if (!key)
1615 return 0;
1616
1617 ts = stktable_lookup_key(t, key);
1618
1619 smp->flags = SMP_F_VOL_TEST;
1620 smp->data.type = SMP_T_SINT;
1621 smp->data.u.sint = 0;
1622
1623 if (!ts) /* key not present */
1624 return 1;
1625
1626 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_FAIL_CNT);
1627 if (ptr)
1628 smp->data.u.sint = stktable_data_cast(ptr, http_fail_cnt);
1629
1630 stktable_release(t, ts);
1631 return !!ptr;
1632}
1633
1634/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1635 * it up into this table. Returns the HTTP response failure rate for the key
1636 * if the key is present in the table, otherwise zero, so that comparisons can
1637 * be easily performed. If the inspected parameter is not stored in the table,
1638 * <not found> is returned.
1639 */
1640static int sample_conv_table_http_fail_rate(const struct arg *arg_p, struct sample *smp, void *private)
1641{
1642 struct stktable *t;
1643 struct stktable_key *key;
1644 struct stksess *ts;
1645 void *ptr;
1646
1647 t = arg_p[0].data.t;
1648
1649 key = smp_to_stkey(smp, t);
1650 if (!key)
1651 return 0;
1652
1653 ts = stktable_lookup_key(t, key);
1654
1655 smp->flags = SMP_F_VOL_TEST;
1656 smp->data.type = SMP_T_SINT;
1657 smp->data.u.sint = 0;
1658
1659 if (!ts) /* key not present */
1660 return 1;
1661
1662 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_FAIL_RATE);
1663 if (ptr)
1664 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, http_fail_rate),
1665 t->data_arg[STKTABLE_DT_HTTP_FAIL_RATE].u);
1666
1667 stktable_release(t, ts);
1668 return !!ptr;
1669}
1670
1671/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001672 * it up into this table. Returns the cumulated number of HTTP request for the
1673 * key if the key is present in the table, otherwise zero, so that comparisons
1674 * can be easily performed. If the inspected parameter is not stored in the
1675 * table, <not found> is returned.
1676 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001677static int sample_conv_table_http_req_cnt(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001678{
1679 struct stktable *t;
1680 struct stktable_key *key;
1681 struct stksess *ts;
1682 void *ptr;
1683
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001684 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001685
1686 key = smp_to_stkey(smp, t);
1687 if (!key)
1688 return 0;
1689
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001690 ts = stktable_lookup_key(t, key);
1691
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001692 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001693 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001694 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001695
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001696 if (!ts) /* key not present */
1697 return 1;
1698
1699 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_REQ_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001700 if (ptr)
1701 smp->data.u.sint = stktable_data_cast(ptr, http_req_cnt);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001702
Daniel Corbett3e60b112018-05-27 09:47:12 -04001703 stktable_release(t, ts);
1704 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001705}
1706
1707/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1708 * it up into this table. Returns the HTTP request rate the key if the key is
1709 * present in the table, otherwise zero, so that comparisons can be easily
1710 * performed. If the inspected parameter is not stored in the table, <not found>
1711 * is returned.
1712 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001713static int sample_conv_table_http_req_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001714{
1715 struct stktable *t;
1716 struct stktable_key *key;
1717 struct stksess *ts;
1718 void *ptr;
1719
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001720 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001721
1722 key = smp_to_stkey(smp, t);
1723 if (!key)
1724 return 0;
1725
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001726 ts = stktable_lookup_key(t, key);
1727
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001728 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001729 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001730 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001731
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001732 if (!ts) /* key not present */
1733 return 1;
1734
1735 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_REQ_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001736 if (ptr)
1737 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, http_req_rate),
1738 t->data_arg[STKTABLE_DT_HTTP_REQ_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001739
Daniel Corbett3e60b112018-05-27 09:47:12 -04001740 stktable_release(t, ts);
1741 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001742}
1743
1744/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1745 * it up into this table. Returns the volume of datareceived from clients in kbytes
1746 * if the key is present in the table, otherwise zero, so that comparisons can
1747 * be easily performed. If the inspected parameter is not stored in the table,
1748 * <not found> is returned.
1749 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001750static int sample_conv_table_kbytes_in(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001751{
1752 struct stktable *t;
1753 struct stktable_key *key;
1754 struct stksess *ts;
1755 void *ptr;
1756
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001757 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001758
1759 key = smp_to_stkey(smp, t);
1760 if (!key)
1761 return 0;
1762
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001763 ts = stktable_lookup_key(t, key);
1764
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001765 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001766 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001767 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001768
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001769 if (!ts) /* key not present */
1770 return 1;
1771
1772 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_IN_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001773 if (ptr)
1774 smp->data.u.sint = stktable_data_cast(ptr, bytes_in_cnt) >> 10;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001775
Daniel Corbett3e60b112018-05-27 09:47:12 -04001776 stktable_release(t, ts);
1777 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001778}
1779
1780/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1781 * it up into this table. Returns the volume of data sent to clients in kbytes
1782 * if the key is present in the table, otherwise zero, so that comparisons can
1783 * be easily performed. If the inspected parameter is not stored in the table,
1784 * <not found> is returned.
1785 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001786static int sample_conv_table_kbytes_out(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001787{
1788 struct stktable *t;
1789 struct stktable_key *key;
1790 struct stksess *ts;
1791 void *ptr;
1792
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001793 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001794
1795 key = smp_to_stkey(smp, t);
1796 if (!key)
1797 return 0;
1798
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001799 ts = stktable_lookup_key(t, key);
1800
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001801 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001802 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001803 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001804
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001805 if (!ts) /* key not present */
1806 return 1;
1807
1808 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_OUT_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001809 if (ptr)
1810 smp->data.u.sint = stktable_data_cast(ptr, bytes_out_cnt) >> 10;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001811
Daniel Corbett3e60b112018-05-27 09:47:12 -04001812 stktable_release(t, ts);
1813 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001814}
1815
1816/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1817 * it up into this table. Returns the server ID associated with the key if the
1818 * key is present in the table, otherwise zero, so that comparisons can be
1819 * easily performed. If the inspected parameter is not stored in the table,
1820 * <not found> is returned.
1821 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001822static int sample_conv_table_server_id(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001823{
1824 struct stktable *t;
1825 struct stktable_key *key;
1826 struct stksess *ts;
1827 void *ptr;
1828
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001829 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001830
1831 key = smp_to_stkey(smp, t);
1832 if (!key)
1833 return 0;
1834
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001835 ts = stktable_lookup_key(t, key);
1836
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001837 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001838 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001839 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001840
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001841 if (!ts) /* key not present */
1842 return 1;
1843
1844 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_SERVER_ID);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001845 if (ptr)
1846 smp->data.u.sint = stktable_data_cast(ptr, server_id);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001847
Daniel Corbett3e60b112018-05-27 09:47:12 -04001848 stktable_release(t, ts);
1849 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001850}
1851
1852/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1853 * it up into this table. Returns the cumulated number of sessions for the
1854 * key if the key is present in the table, otherwise zero, so that comparisons
1855 * can be easily performed. If the inspected parameter is not stored in the
1856 * table, <not found> is returned.
1857 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001858static int sample_conv_table_sess_cnt(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001859{
1860 struct stktable *t;
1861 struct stktable_key *key;
1862 struct stksess *ts;
1863 void *ptr;
1864
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001865 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001866
1867 key = smp_to_stkey(smp, t);
1868 if (!key)
1869 return 0;
1870
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001871 ts = stktable_lookup_key(t, key);
1872
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001873 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001874 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001875 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001876
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001877 if (!ts) /* key not present */
1878 return 1;
1879
1880 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_SESS_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001881 if (ptr)
1882 smp->data.u.sint = stktable_data_cast(ptr, sess_cnt);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001883
Daniel Corbett3e60b112018-05-27 09:47:12 -04001884 stktable_release(t, ts);
1885 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001886}
1887
1888/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1889 * it up into this table. Returns the session rate the key if the key is
1890 * present in the table, otherwise zero, so that comparisons can be easily
1891 * performed. If the inspected parameter is not stored in the table, <not found>
1892 * is returned.
1893 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001894static int sample_conv_table_sess_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001895{
1896 struct stktable *t;
1897 struct stktable_key *key;
1898 struct stksess *ts;
1899 void *ptr;
1900
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001901 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001902
1903 key = smp_to_stkey(smp, t);
1904 if (!key)
1905 return 0;
1906
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001907 ts = stktable_lookup_key(t, key);
1908
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001909 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001910 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001911 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001912
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001913 if (!ts) /* key not present */
1914 return 1;
1915
1916 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_SESS_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001917 if (ptr)
1918 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, sess_rate),
1919 t->data_arg[STKTABLE_DT_SESS_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001920
Daniel Corbett3e60b112018-05-27 09:47:12 -04001921 stktable_release(t, ts);
1922 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001923}
1924
1925/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1926 * it up into this table. Returns the amount of concurrent connections tracking
1927 * the same key if the key is present in the table, otherwise zero, so that
1928 * comparisons can be easily performed. If the inspected parameter is not
1929 * stored in the table, <not found> is returned.
1930 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001931static int sample_conv_table_trackers(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001932{
1933 struct stktable *t;
1934 struct stktable_key *key;
1935 struct stksess *ts;
1936
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001937 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001938
1939 key = smp_to_stkey(smp, t);
1940 if (!key)
1941 return 0;
1942
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001943 ts = stktable_lookup_key(t, key);
1944
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001945 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001946 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001947 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001948
Tim Duesterhus65189c12018-06-26 15:57:29 +02001949 if (!ts)
1950 return 1;
1951
1952 smp->data.u.sint = ts->ref_cnt;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001953
Daniel Corbett3e60b112018-05-27 09:47:12 -04001954 stktable_release(t, ts);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001955 return 1;
1956}
1957
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001958/* Always returns 1. */
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001959static enum act_return action_inc_gpc0(struct act_rule *rule, struct proxy *px,
Willy Tarreau658b85b2015-09-27 10:00:49 +02001960 struct session *sess, struct stream *s, int flags)
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001961{
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001962 struct stksess *ts;
1963 struct stkctr *stkctr;
1964
1965 /* Extract the stksess, return OK if no stksess available. */
1966 if (s)
1967 stkctr = &s->stkctr[rule->arg.gpc.sc];
1968 else
1969 stkctr = &sess->stkctr[rule->arg.gpc.sc];
Willy Tarreau79c1e912016-01-25 14:54:45 +01001970
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001971 ts = stkctr_entry(stkctr);
Willy Tarreau79c1e912016-01-25 14:54:45 +01001972 if (ts) {
1973 void *ptr1, *ptr2;
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001974
Willy Tarreau79c1e912016-01-25 14:54:45 +01001975 /* First, update gpc0_rate if it's tracked. Second, update its gpc0 if tracked. */
1976 ptr1 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC0_RATE);
Emeric Brun819fc6f2017-06-13 19:37:32 +02001977 ptr2 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC0);
1978 if (ptr1 || ptr2) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01001979 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02001980
1981 if (ptr1)
1982 update_freq_ctr_period(&stktable_data_cast(ptr1, gpc0_rate),
Willy Tarreau79c1e912016-01-25 14:54:45 +01001983 stkctr->table->data_arg[STKTABLE_DT_GPC0_RATE].u, 1);
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001984
Emeric Brun819fc6f2017-06-13 19:37:32 +02001985 if (ptr2)
1986 stktable_data_cast(ptr2, gpc0)++;
Willy Tarreau79c1e912016-01-25 14:54:45 +01001987
Christopher Faulet2a944ee2017-11-07 10:42:54 +01001988 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02001989
1990 /* If data was modified, we need to touch to re-schedule sync */
1991 stktable_touch_local(stkctr->table, ts, 0);
1992 }
Willy Tarreau79c1e912016-01-25 14:54:45 +01001993 }
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001994 return ACT_RET_CONT;
1995}
1996
1997/* This function is a common parser for using variables. It understands
1998 * the formats:
1999 *
2000 * sc-inc-gpc0(<stick-table ID>)
2001 *
2002 * It returns 0 if fails and <err> is filled with an error message. Otherwise,
2003 * it returns 1 and the variable <expr> is filled with the pointer to the
2004 * expression to execute.
2005 */
2006static enum act_parse_ret parse_inc_gpc0(const char **args, int *arg, struct proxy *px,
2007 struct act_rule *rule, char **err)
2008{
2009 const char *cmd_name = args[*arg-1];
2010 char *error;
2011
2012 cmd_name += strlen("sc-inc-gpc0");
2013 if (*cmd_name == '\0') {
2014 /* default stick table id. */
2015 rule->arg.gpc.sc = 0;
2016 } else {
2017 /* parse the stick table id. */
2018 if (*cmd_name != '(') {
2019 memprintf(err, "invalid stick table track ID. Expects %s(<Track ID>)", args[*arg-1]);
2020 return ACT_RET_PRS_ERR;
2021 }
2022 cmd_name++; /* jump the '(' */
2023 rule->arg.gpc.sc = strtol(cmd_name, &error, 10); /* Convert stick table id. */
2024 if (*error != ')') {
2025 memprintf(err, "invalid stick table track ID. Expects %s(<Track ID>)", args[*arg-1]);
2026 return ACT_RET_PRS_ERR;
2027 }
2028
Christopher Faulet28436e22019-12-18 10:25:46 +01002029 if (rule->arg.gpc.sc >= MAX_SESS_STKCTR) {
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002030 memprintf(err, "invalid stick table track ID. The max allowed ID is %d",
Christopher Faulet28436e22019-12-18 10:25:46 +01002031 MAX_SESS_STKCTR-1);
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002032 return ACT_RET_PRS_ERR;
2033 }
2034 }
Thierry FOURNIER42148732015-09-02 17:17:33 +02002035 rule->action = ACT_CUSTOM;
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002036 rule->action_ptr = action_inc_gpc0;
2037 return ACT_RET_PRS_OK;
2038}
2039
2040/* Always returns 1. */
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002041static enum act_return action_inc_gpc1(struct act_rule *rule, struct proxy *px,
2042 struct session *sess, struct stream *s, int flags)
2043{
2044 struct stksess *ts;
2045 struct stkctr *stkctr;
2046
2047 /* Extract the stksess, return OK if no stksess available. */
2048 if (s)
2049 stkctr = &s->stkctr[rule->arg.gpc.sc];
2050 else
2051 stkctr = &sess->stkctr[rule->arg.gpc.sc];
2052
2053 ts = stkctr_entry(stkctr);
2054 if (ts) {
2055 void *ptr1, *ptr2;
2056
2057 /* First, update gpc1_rate if it's tracked. Second, update its gpc1 if tracked. */
2058 ptr1 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC1_RATE);
2059 ptr2 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC1);
2060 if (ptr1 || ptr2) {
2061 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
2062
2063 if (ptr1)
2064 update_freq_ctr_period(&stktable_data_cast(ptr1, gpc1_rate),
2065 stkctr->table->data_arg[STKTABLE_DT_GPC1_RATE].u, 1);
2066
2067 if (ptr2)
2068 stktable_data_cast(ptr2, gpc1)++;
2069
2070 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
2071
2072 /* If data was modified, we need to touch to re-schedule sync */
2073 stktable_touch_local(stkctr->table, ts, 0);
2074 }
2075 }
2076 return ACT_RET_CONT;
2077}
2078
2079/* This function is a common parser for using variables. It understands
2080 * the formats:
2081 *
2082 * sc-inc-gpc1(<stick-table ID>)
2083 *
2084 * It returns 0 if fails and <err> is filled with an error message. Otherwise,
2085 * it returns 1 and the variable <expr> is filled with the pointer to the
2086 * expression to execute.
2087 */
2088static enum act_parse_ret parse_inc_gpc1(const char **args, int *arg, struct proxy *px,
2089 struct act_rule *rule, char **err)
2090{
2091 const char *cmd_name = args[*arg-1];
2092 char *error;
2093
2094 cmd_name += strlen("sc-inc-gpc1");
2095 if (*cmd_name == '\0') {
2096 /* default stick table id. */
2097 rule->arg.gpc.sc = 0;
2098 } else {
2099 /* parse the stick table id. */
2100 if (*cmd_name != '(') {
2101 memprintf(err, "invalid stick table track ID. Expects %s(<Track ID>)", args[*arg-1]);
2102 return ACT_RET_PRS_ERR;
2103 }
2104 cmd_name++; /* jump the '(' */
2105 rule->arg.gpc.sc = strtol(cmd_name, &error, 10); /* Convert stick table id. */
2106 if (*error != ')') {
2107 memprintf(err, "invalid stick table track ID. Expects %s(<Track ID>)", args[*arg-1]);
2108 return ACT_RET_PRS_ERR;
2109 }
2110
Christopher Faulet28436e22019-12-18 10:25:46 +01002111 if (rule->arg.gpc.sc >= MAX_SESS_STKCTR) {
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002112 memprintf(err, "invalid stick table track ID. The max allowed ID is %d",
Christopher Faulet28436e22019-12-18 10:25:46 +01002113 MAX_SESS_STKCTR-1);
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002114 return ACT_RET_PRS_ERR;
2115 }
2116 }
2117 rule->action = ACT_CUSTOM;
2118 rule->action_ptr = action_inc_gpc1;
2119 return ACT_RET_PRS_OK;
2120}
2121
2122/* Always returns 1. */
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002123static enum act_return action_set_gpt0(struct act_rule *rule, struct proxy *px,
Willy Tarreau658b85b2015-09-27 10:00:49 +02002124 struct session *sess, struct stream *s, int flags)
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002125{
2126 void *ptr;
2127 struct stksess *ts;
2128 struct stkctr *stkctr;
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002129 unsigned int value = 0;
2130 struct sample *smp;
2131 int smp_opt_dir;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002132
2133 /* Extract the stksess, return OK if no stksess available. */
2134 if (s)
2135 stkctr = &s->stkctr[rule->arg.gpt.sc];
2136 else
2137 stkctr = &sess->stkctr[rule->arg.gpt.sc];
Willy Tarreau79c1e912016-01-25 14:54:45 +01002138
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002139 ts = stkctr_entry(stkctr);
2140 if (!ts)
2141 return ACT_RET_CONT;
2142
2143 /* Store the sample in the required sc, and ignore errors. */
2144 ptr = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPT0);
Willy Tarreau79c1e912016-01-25 14:54:45 +01002145 if (ptr) {
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002146 if (!rule->arg.gpt.expr)
2147 value = (unsigned int)(rule->arg.gpt.value);
2148 else {
2149 switch (rule->from) {
2150 case ACT_F_TCP_REQ_SES: smp_opt_dir = SMP_OPT_DIR_REQ; break;
2151 case ACT_F_TCP_REQ_CNT: smp_opt_dir = SMP_OPT_DIR_REQ; break;
2152 case ACT_F_TCP_RES_CNT: smp_opt_dir = SMP_OPT_DIR_RES; break;
2153 case ACT_F_HTTP_REQ: smp_opt_dir = SMP_OPT_DIR_REQ; break;
2154 case ACT_F_HTTP_RES: smp_opt_dir = SMP_OPT_DIR_RES; break;
2155 default:
2156 send_log(px, LOG_ERR, "stick table: internal error while setting gpt0.");
2157 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))
2158 ha_alert("stick table: internal error while executing setting gpt0.\n");
2159 return ACT_RET_CONT;
2160 }
2161
2162 /* Fetch and cast the expression. */
2163 smp = sample_fetch_as_type(px, sess, s, smp_opt_dir|SMP_OPT_FINAL, rule->arg.gpt.expr, SMP_T_SINT);
2164 if (!smp) {
2165 send_log(px, LOG_WARNING, "stick table: invalid expression or data type while setting gpt0.");
2166 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))
2167 ha_alert("stick table: invalid expression or data type while setting gpt0.\n");
2168 return ACT_RET_CONT;
2169 }
2170 value = (unsigned int)(smp->data.u.sint);
2171 }
2172
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002173 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002174
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002175 stktable_data_cast(ptr, gpt0) = value;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002176
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002177 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002178
2179 stktable_touch_local(stkctr->table, ts, 0);
Willy Tarreau79c1e912016-01-25 14:54:45 +01002180 }
2181
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002182 return ACT_RET_CONT;
2183}
2184
2185/* This function is a common parser for using variables. It understands
2186 * the format:
2187 *
2188 * set-gpt0(<stick-table ID>) <expression>
2189 *
2190 * It returns 0 if fails and <err> is filled with an error message. Otherwise,
2191 * it returns 1 and the variable <expr> is filled with the pointer to the
2192 * expression to execute.
2193 */
2194static enum act_parse_ret parse_set_gpt0(const char **args, int *arg, struct proxy *px,
2195 struct act_rule *rule, char **err)
2196
2197
2198{
2199 const char *cmd_name = args[*arg-1];
2200 char *error;
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002201 int smp_val;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002202
2203 cmd_name += strlen("sc-set-gpt0");
2204 if (*cmd_name == '\0') {
2205 /* default stick table id. */
2206 rule->arg.gpt.sc = 0;
2207 } else {
2208 /* parse the stick table id. */
2209 if (*cmd_name != '(') {
2210 memprintf(err, "invalid stick table track ID '%s'. Expects sc-set-gpt0(<Track ID>)", args[*arg-1]);
2211 return ACT_RET_PRS_ERR;
2212 }
2213 cmd_name++; /* jump the '(' */
2214 rule->arg.gpt.sc = strtol(cmd_name, &error, 10); /* Convert stick table id. */
2215 if (*error != ')') {
2216 memprintf(err, "invalid stick table track ID '%s'. Expects sc-set-gpt0(<Track ID>)", args[*arg-1]);
2217 return ACT_RET_PRS_ERR;
2218 }
2219
Christopher Faulet28436e22019-12-18 10:25:46 +01002220 if (rule->arg.gpt.sc >= MAX_SESS_STKCTR) {
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002221 memprintf(err, "invalid stick table track ID '%s'. The max allowed ID is %d",
Christopher Faulet28436e22019-12-18 10:25:46 +01002222 args[*arg-1], MAX_SESS_STKCTR-1);
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002223 return ACT_RET_PRS_ERR;
2224 }
2225 }
2226
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002227 rule->arg.gpt.expr = NULL;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002228 rule->arg.gpt.value = strtol(args[*arg], &error, 10);
2229 if (*error != '\0') {
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002230 rule->arg.gpt.expr = sample_parse_expr((char **)args, arg, px->conf.args.file,
Willy Tarreaue3b57bf2020-02-14 16:50:14 +01002231 px->conf.args.line, err, &px->conf.args, NULL);
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002232 if (!rule->arg.gpt.expr)
2233 return ACT_RET_PRS_ERR;
2234
2235 switch (rule->from) {
2236 case ACT_F_TCP_REQ_SES: smp_val = SMP_VAL_FE_SES_ACC; break;
2237 case ACT_F_TCP_REQ_CNT: smp_val = SMP_VAL_FE_REQ_CNT; break;
2238 case ACT_F_TCP_RES_CNT: smp_val = SMP_VAL_BE_RES_CNT; break;
2239 case ACT_F_HTTP_REQ: smp_val = SMP_VAL_FE_HRQ_HDR; break;
2240 case ACT_F_HTTP_RES: smp_val = SMP_VAL_BE_HRS_HDR; break;
2241 default:
2242 memprintf(err, "internal error, unexpected rule->from=%d, please report this bug!", rule->from);
2243 return ACT_RET_PRS_ERR;
2244 }
2245 if (!(rule->arg.gpt.expr->fetch->val & smp_val)) {
2246 memprintf(err, "fetch method '%s' extracts information from '%s', none of which is available here", args[*arg-1],
2247 sample_src_names(rule->arg.gpt.expr->fetch->use));
2248 free(rule->arg.gpt.expr);
2249 return ACT_RET_PRS_ERR;
2250 }
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002251 }
2252 (*arg)++;
2253
Thierry FOURNIER42148732015-09-02 17:17:33 +02002254 rule->action = ACT_CUSTOM;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002255 rule->action_ptr = action_set_gpt0;
2256
2257 return ACT_RET_PRS_OK;
2258}
2259
Willy Tarreau7d562212016-11-25 16:10:05 +01002260/* set temp integer to the number of used entries in the table pointed to by expr.
2261 * Accepts exactly 1 argument of type table.
2262 */
2263static int
2264smp_fetch_table_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
2265{
2266 smp->flags = SMP_F_VOL_TEST;
2267 smp->data.type = SMP_T_SINT;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002268 smp->data.u.sint = args->data.t->current;
Willy Tarreau7d562212016-11-25 16:10:05 +01002269 return 1;
2270}
2271
2272/* set temp integer to the number of free entries in the table pointed to by expr.
2273 * Accepts exactly 1 argument of type table.
2274 */
2275static int
2276smp_fetch_table_avl(const struct arg *args, struct sample *smp, const char *kw, void *private)
2277{
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002278 struct stktable *t;
Willy Tarreau7d562212016-11-25 16:10:05 +01002279
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002280 t = args->data.t;
Willy Tarreau7d562212016-11-25 16:10:05 +01002281 smp->flags = SMP_F_VOL_TEST;
2282 smp->data.type = SMP_T_SINT;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002283 smp->data.u.sint = t->size - t->current;
Willy Tarreau7d562212016-11-25 16:10:05 +01002284 return 1;
2285}
2286
2287/* Returns a pointer to a stkctr depending on the fetch keyword name.
2288 * It is designed to be called as sc[0-9]_* sc_* or src_* exclusively.
2289 * sc[0-9]_* will return a pointer to the respective field in the
2290 * stream <l4>. sc_* requires an UINT argument specifying the stick
2291 * counter number. src_* will fill a locally allocated structure with
2292 * the table and entry corresponding to what is specified with src_*.
2293 * NULL may be returned if the designated stkctr is not tracked. For
2294 * the sc_* and sc[0-9]_* forms, an optional table argument may be
2295 * passed. When present, the currently tracked key is then looked up
2296 * in the specified table instead of the current table. The purpose is
Ilya Shipitsin47d17182020-06-21 21:42:57 +05002297 * to be able to convert multiple values per key (eg: have gpc0 from
Willy Tarreau7d562212016-11-25 16:10:05 +01002298 * multiple tables). <strm> is allowed to be NULL, in which case only
2299 * the session will be consulted.
2300 */
2301struct stkctr *
Emeric Brun819fc6f2017-06-13 19:37:32 +02002302smp_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 +01002303{
Willy Tarreau7d562212016-11-25 16:10:05 +01002304 struct stkctr *stkptr;
2305 struct stksess *stksess;
2306 unsigned int num = kw[2] - '0';
2307 int arg = 0;
2308
2309 if (num == '_' - '0') {
2310 /* sc_* variant, args[0] = ctr# (mandatory) */
2311 num = args[arg++].data.sint;
Willy Tarreau7d562212016-11-25 16:10:05 +01002312 }
2313 else if (num > 9) { /* src_* variant, args[0] = table */
2314 struct stktable_key *key;
2315 struct connection *conn = objt_conn(sess->origin);
2316 struct sample smp;
2317
2318 if (!conn)
2319 return NULL;
2320
Joseph Herlant5662fa42018-11-15 13:43:28 -08002321 /* Fetch source address in a sample. */
Willy Tarreau7d562212016-11-25 16:10:05 +01002322 smp.px = NULL;
2323 smp.sess = sess;
2324 smp.strm = strm;
Christopher Fauletbdbd5db2021-01-29 10:27:47 +01002325 if (!smp_fetch_src || !smp_fetch_src(empty_arg_list, &smp, NULL, NULL))
Willy Tarreau7d562212016-11-25 16:10:05 +01002326 return NULL;
2327
2328 /* Converts into key. */
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002329 key = smp_to_stkey(&smp, args->data.t);
Willy Tarreau7d562212016-11-25 16:10:05 +01002330 if (!key)
2331 return NULL;
2332
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002333 stkctr->table = args->data.t;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002334 stkctr_set_entry(stkctr, stktable_lookup_key(stkctr->table, key));
2335 return stkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002336 }
2337
2338 /* Here, <num> contains the counter number from 0 to 9 for
2339 * the sc[0-9]_ form, or even higher using sc_(num) if needed.
2340 * args[arg] is the first optional argument. We first lookup the
2341 * ctr form the stream, then from the session if it was not there.
Christopher Fauleta9fa88a2019-10-21 10:53:34 +02002342 * But we must be sure the counter does not exceed MAX_SESS_STKCTR.
Willy Tarreau7d562212016-11-25 16:10:05 +01002343 */
Christopher Fauleta9fa88a2019-10-21 10:53:34 +02002344 if (num >= MAX_SESS_STKCTR)
2345 return NULL;
Willy Tarreau7d562212016-11-25 16:10:05 +01002346
2347 if (strm)
2348 stkptr = &strm->stkctr[num];
2349 if (!strm || !stkctr_entry(stkptr)) {
2350 stkptr = &sess->stkctr[num];
2351 if (!stkctr_entry(stkptr))
2352 return NULL;
2353 }
2354
2355 stksess = stkctr_entry(stkptr);
2356 if (!stksess)
2357 return NULL;
2358
2359 if (unlikely(args[arg].type == ARGT_TAB)) {
2360 /* an alternate table was specified, let's look up the same key there */
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002361 stkctr->table = args[arg].data.t;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002362 stkctr_set_entry(stkctr, stktable_lookup(stkctr->table, stksess));
2363 return stkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002364 }
2365 return stkptr;
2366}
2367
2368/* same as smp_fetch_sc_stkctr() but dedicated to src_* and can create
2369 * the entry if it doesn't exist yet. This is needed for a few fetch
2370 * functions which need to create an entry, such as src_inc_gpc* and
2371 * src_clr_gpc*.
2372 */
2373struct stkctr *
Emeric Brun819fc6f2017-06-13 19:37:32 +02002374smp_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 +01002375{
Willy Tarreau7d562212016-11-25 16:10:05 +01002376 struct stktable_key *key;
2377 struct connection *conn = objt_conn(sess->origin);
2378 struct sample smp;
2379
2380 if (strncmp(kw, "src_", 4) != 0)
2381 return NULL;
2382
2383 if (!conn)
2384 return NULL;
2385
Joseph Herlant5662fa42018-11-15 13:43:28 -08002386 /* Fetch source address in a sample. */
Willy Tarreau7d562212016-11-25 16:10:05 +01002387 smp.px = NULL;
2388 smp.sess = sess;
2389 smp.strm = strm;
Christopher Fauletbdbd5db2021-01-29 10:27:47 +01002390 if (!smp_fetch_src || !smp_fetch_src(empty_arg_list, &smp, NULL, NULL))
Willy Tarreau7d562212016-11-25 16:10:05 +01002391 return NULL;
2392
2393 /* Converts into key. */
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002394 key = smp_to_stkey(&smp, args->data.t);
Willy Tarreau7d562212016-11-25 16:10:05 +01002395 if (!key)
2396 return NULL;
2397
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002398 stkctr->table = args->data.t;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002399 stkctr_set_entry(stkctr, stktable_get_entry(stkctr->table, key));
2400 return stkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002401}
2402
2403/* set return a boolean indicating if the requested stream counter is
2404 * currently being tracked or not.
2405 * Supports being called as "sc[0-9]_tracked" only.
2406 */
2407static int
2408smp_fetch_sc_tracked(const struct arg *args, struct sample *smp, const char *kw, void *private)
2409{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002410 struct stkctr tmpstkctr;
2411 struct stkctr *stkctr;
2412
Willy Tarreau7d562212016-11-25 16:10:05 +01002413 smp->flags = SMP_F_VOL_TEST;
2414 smp->data.type = SMP_T_BOOL;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002415 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2416 smp->data.u.sint = !!stkctr;
2417
2418 /* release the ref count */
Dirkjan Bussinkff57f1b2018-09-14 14:31:22 +02002419 if (stkctr == &tmpstkctr)
Emeric Brun819fc6f2017-06-13 19:37:32 +02002420 stktable_release(stkctr->table, stkctr_entry(stkctr));
2421
Willy Tarreau7d562212016-11-25 16:10:05 +01002422 return 1;
2423}
2424
2425/* set <smp> to the General Purpose Flag 0 value from the stream's tracked
2426 * frontend counters or from the src.
2427 * Supports being called as "sc[0-9]_get_gpc0" or "src_get_gpt0" only. Value
2428 * zero is returned if the key is new.
2429 */
2430static int
2431smp_fetch_sc_get_gpt0(const struct arg *args, struct sample *smp, const char *kw, void *private)
2432{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002433 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002434 struct stkctr *stkctr;
2435
Emeric Brun819fc6f2017-06-13 19:37:32 +02002436 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002437 if (!stkctr)
2438 return 0;
2439
2440 smp->flags = SMP_F_VOL_TEST;
2441 smp->data.type = SMP_T_SINT;
2442 smp->data.u.sint = 0;
2443
Emeric Brun819fc6f2017-06-13 19:37:32 +02002444 if (stkctr_entry(stkctr)) {
2445 void *ptr;
2446
2447 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPT0);
2448 if (!ptr) {
2449 if (stkctr == &tmpstkctr)
2450 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002451 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002452 }
2453
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002454 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002455
Willy Tarreau7d562212016-11-25 16:10:05 +01002456 smp->data.u.sint = stktable_data_cast(ptr, gpt0);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002457
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002458 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002459
2460 if (stkctr == &tmpstkctr)
2461 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002462 }
2463 return 1;
2464}
2465
2466/* set <smp> to the General Purpose Counter 0 value from the stream's tracked
2467 * frontend counters or from the src.
2468 * Supports being called as "sc[0-9]_get_gpc0" or "src_get_gpc0" only. Value
2469 * zero is returned if the key is new.
2470 */
2471static int
2472smp_fetch_sc_get_gpc0(const struct arg *args, struct sample *smp, const char *kw, void *private)
2473{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002474 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002475 struct stkctr *stkctr;
2476
Emeric Brun819fc6f2017-06-13 19:37:32 +02002477 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002478 if (!stkctr)
2479 return 0;
2480
2481 smp->flags = SMP_F_VOL_TEST;
2482 smp->data.type = SMP_T_SINT;
2483 smp->data.u.sint = 0;
2484
2485 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002486 void *ptr;
2487
2488 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0);
2489 if (!ptr) {
2490 if (stkctr == &tmpstkctr)
2491 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002492 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002493 }
2494
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002495 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002496
Willy Tarreau7d562212016-11-25 16:10:05 +01002497 smp->data.u.sint = stktable_data_cast(ptr, gpc0);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002498
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002499 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002500
2501 if (stkctr == &tmpstkctr)
2502 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002503 }
2504 return 1;
2505}
2506
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002507/* set <smp> to the General Purpose Counter 1 value from the stream's tracked
2508 * frontend counters or from the src.
2509 * Supports being called as "sc[0-9]_get_gpc1" or "src_get_gpc1" only. Value
2510 * zero is returned if the key is new.
2511 */
2512static int
2513smp_fetch_sc_get_gpc1(const struct arg *args, struct sample *smp, const char *kw, void *private)
2514{
2515 struct stkctr tmpstkctr;
2516 struct stkctr *stkctr;
2517
2518 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2519 if (!stkctr)
2520 return 0;
2521
2522 smp->flags = SMP_F_VOL_TEST;
2523 smp->data.type = SMP_T_SINT;
2524 smp->data.u.sint = 0;
2525
2526 if (stkctr_entry(stkctr) != NULL) {
2527 void *ptr;
2528
2529 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1);
2530 if (!ptr) {
2531 if (stkctr == &tmpstkctr)
2532 stktable_release(stkctr->table, stkctr_entry(stkctr));
2533 return 0; /* parameter not stored */
2534 }
2535
2536 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2537
2538 smp->data.u.sint = stktable_data_cast(ptr, gpc1);
2539
2540 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2541
2542 if (stkctr == &tmpstkctr)
2543 stktable_release(stkctr->table, stkctr_entry(stkctr));
2544 }
2545 return 1;
2546}
2547
Willy Tarreau7d562212016-11-25 16:10:05 +01002548/* set <smp> to the General Purpose Counter 0's event rate from the stream's
2549 * tracked frontend counters or from the src.
2550 * Supports being called as "sc[0-9]_gpc0_rate" or "src_gpc0_rate" only.
2551 * Value zero is returned if the key is new.
2552 */
2553static int
2554smp_fetch_sc_gpc0_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
2555{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002556 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002557 struct stkctr *stkctr;
2558
Emeric Brun819fc6f2017-06-13 19:37:32 +02002559 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002560 if (!stkctr)
2561 return 0;
2562
2563 smp->flags = SMP_F_VOL_TEST;
2564 smp->data.type = SMP_T_SINT;
2565 smp->data.u.sint = 0;
2566 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002567 void *ptr;
2568
2569 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0_RATE);
2570 if (!ptr) {
2571 if (stkctr == &tmpstkctr)
2572 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002573 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002574 }
2575
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002576 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002577
Willy Tarreau7d562212016-11-25 16:10:05 +01002578 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, gpc0_rate),
2579 stkctr->table->data_arg[STKTABLE_DT_GPC0_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002580
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002581 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002582
2583 if (stkctr == &tmpstkctr)
2584 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002585 }
2586 return 1;
2587}
2588
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002589/* set <smp> to the General Purpose Counter 1's event rate from the stream's
2590 * tracked frontend counters or from the src.
2591 * Supports being called as "sc[0-9]_gpc1_rate" or "src_gpc1_rate" only.
2592 * Value zero is returned if the key is new.
2593 */
2594static int
2595smp_fetch_sc_gpc1_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
2596{
2597 struct stkctr tmpstkctr;
2598 struct stkctr *stkctr;
2599
2600 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2601 if (!stkctr)
2602 return 0;
2603
2604 smp->flags = SMP_F_VOL_TEST;
2605 smp->data.type = SMP_T_SINT;
2606 smp->data.u.sint = 0;
2607 if (stkctr_entry(stkctr) != NULL) {
2608 void *ptr;
2609
2610 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1_RATE);
2611 if (!ptr) {
2612 if (stkctr == &tmpstkctr)
2613 stktable_release(stkctr->table, stkctr_entry(stkctr));
2614 return 0; /* parameter not stored */
2615 }
2616
2617 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2618
2619 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, gpc1_rate),
2620 stkctr->table->data_arg[STKTABLE_DT_GPC1_RATE].u);
2621
2622 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2623
2624 if (stkctr == &tmpstkctr)
2625 stktable_release(stkctr->table, stkctr_entry(stkctr));
2626 }
2627 return 1;
2628}
2629
Willy Tarreau7d562212016-11-25 16:10:05 +01002630/* Increment the General Purpose Counter 0 value from the stream's tracked
2631 * frontend counters and return it into temp integer.
2632 * Supports being called as "sc[0-9]_inc_gpc0" or "src_inc_gpc0" only.
2633 */
2634static int
2635smp_fetch_sc_inc_gpc0(const struct arg *args, struct sample *smp, const char *kw, void *private)
2636{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002637 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002638 struct stkctr *stkctr;
2639
Emeric Brun819fc6f2017-06-13 19:37:32 +02002640 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002641 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
Emeric Brun819fc6f2017-06-13 19:37:32 +02002648 if (!stkctr_entry(stkctr))
2649 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002650
2651 if (stkctr && stkctr_entry(stkctr)) {
2652 void *ptr1,*ptr2;
2653
Emeric Brun819fc6f2017-06-13 19:37:32 +02002654
Willy Tarreau7d562212016-11-25 16:10:05 +01002655 /* First, update gpc0_rate if it's tracked. Second, update its
2656 * gpc0 if tracked. Returns gpc0's value otherwise the curr_ctr.
2657 */
2658 ptr1 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0_RATE);
Willy Tarreau7d562212016-11-25 16:10:05 +01002659 ptr2 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002660 if (ptr1 || ptr2) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002661 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Willy Tarreau7d562212016-11-25 16:10:05 +01002662
Emeric Brun819fc6f2017-06-13 19:37:32 +02002663 if (ptr1) {
2664 update_freq_ctr_period(&stktable_data_cast(ptr1, gpc0_rate),
2665 stkctr->table->data_arg[STKTABLE_DT_GPC0_RATE].u, 1);
2666 smp->data.u.sint = (&stktable_data_cast(ptr1, gpc0_rate))->curr_ctr;
2667 }
2668
2669 if (ptr2)
2670 smp->data.u.sint = ++stktable_data_cast(ptr2, gpc0);
2671
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002672 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002673
2674 /* If data was modified, we need to touch to re-schedule sync */
2675 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
2676 }
2677 else if (stkctr == &tmpstkctr)
2678 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002679 }
2680 return 1;
2681}
2682
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002683/* Increment the General Purpose Counter 1 value from the stream's tracked
2684 * frontend counters and return it into temp integer.
2685 * Supports being called as "sc[0-9]_inc_gpc1" or "src_inc_gpc1" only.
2686 */
2687static int
2688smp_fetch_sc_inc_gpc1(const struct arg *args, struct sample *smp, const char *kw, void *private)
2689{
2690 struct stkctr tmpstkctr;
2691 struct stkctr *stkctr;
2692
2693 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2694 if (!stkctr)
2695 return 0;
2696
2697 smp->flags = SMP_F_VOL_TEST;
2698 smp->data.type = SMP_T_SINT;
2699 smp->data.u.sint = 0;
2700
2701 if (!stkctr_entry(stkctr))
2702 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2703
2704 if (stkctr && stkctr_entry(stkctr)) {
2705 void *ptr1,*ptr2;
2706
2707
2708 /* First, update gpc1_rate if it's tracked. Second, update its
2709 * gpc1 if tracked. Returns gpc1's value otherwise the curr_ctr.
2710 */
2711 ptr1 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1_RATE);
2712 ptr2 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1);
2713 if (ptr1 || ptr2) {
2714 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2715
2716 if (ptr1) {
2717 update_freq_ctr_period(&stktable_data_cast(ptr1, gpc1_rate),
2718 stkctr->table->data_arg[STKTABLE_DT_GPC1_RATE].u, 1);
2719 smp->data.u.sint = (&stktable_data_cast(ptr1, gpc1_rate))->curr_ctr;
2720 }
2721
2722 if (ptr2)
2723 smp->data.u.sint = ++stktable_data_cast(ptr2, gpc1);
2724
2725 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2726
2727 /* If data was modified, we need to touch to re-schedule sync */
2728 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
2729 }
2730 else if (stkctr == &tmpstkctr)
2731 stktable_release(stkctr->table, stkctr_entry(stkctr));
2732 }
2733 return 1;
2734}
2735
Willy Tarreau7d562212016-11-25 16:10:05 +01002736/* Clear the General Purpose Counter 0 value from the stream's tracked
2737 * frontend counters and return its previous value into temp integer.
2738 * Supports being called as "sc[0-9]_clr_gpc0" or "src_clr_gpc0" only.
2739 */
2740static int
2741smp_fetch_sc_clr_gpc0(const struct arg *args, struct sample *smp, const char *kw, void *private)
2742{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002743 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002744 struct stkctr *stkctr;
2745
Emeric Brun819fc6f2017-06-13 19:37:32 +02002746 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002747 if (!stkctr)
2748 return 0;
2749
2750 smp->flags = SMP_F_VOL_TEST;
2751 smp->data.type = SMP_T_SINT;
2752 smp->data.u.sint = 0;
2753
Emeric Brun819fc6f2017-06-13 19:37:32 +02002754 if (!stkctr_entry(stkctr))
2755 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002756
Emeric Brun819fc6f2017-06-13 19:37:32 +02002757 if (stkctr && stkctr_entry(stkctr)) {
2758 void *ptr;
2759
2760 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0);
2761 if (!ptr) {
2762 if (stkctr == &tmpstkctr)
2763 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002764 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002765 }
2766
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002767 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002768
Willy Tarreau7d562212016-11-25 16:10:05 +01002769 smp->data.u.sint = stktable_data_cast(ptr, gpc0);
2770 stktable_data_cast(ptr, gpc0) = 0;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002771
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002772 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002773
Willy Tarreau7d562212016-11-25 16:10:05 +01002774 /* If data was modified, we need to touch to re-schedule sync */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002775 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
Willy Tarreau7d562212016-11-25 16:10:05 +01002776 }
2777 return 1;
2778}
2779
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002780/* Clear the General Purpose Counter 1 value from the stream's tracked
2781 * frontend counters and return its previous value into temp integer.
2782 * Supports being called as "sc[0-9]_clr_gpc1" or "src_clr_gpc1" only.
2783 */
2784static int
2785smp_fetch_sc_clr_gpc1(const struct arg *args, struct sample *smp, const char *kw, void *private)
2786{
2787 struct stkctr tmpstkctr;
2788 struct stkctr *stkctr;
2789
2790 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2791 if (!stkctr)
2792 return 0;
2793
2794 smp->flags = SMP_F_VOL_TEST;
2795 smp->data.type = SMP_T_SINT;
2796 smp->data.u.sint = 0;
2797
2798 if (!stkctr_entry(stkctr))
2799 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2800
2801 if (stkctr && stkctr_entry(stkctr)) {
2802 void *ptr;
2803
2804 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1);
2805 if (!ptr) {
2806 if (stkctr == &tmpstkctr)
2807 stktable_release(stkctr->table, stkctr_entry(stkctr));
2808 return 0; /* parameter not stored */
2809 }
2810
2811 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2812
2813 smp->data.u.sint = stktable_data_cast(ptr, gpc1);
2814 stktable_data_cast(ptr, gpc1) = 0;
2815
2816 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2817
2818 /* If data was modified, we need to touch to re-schedule sync */
2819 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
2820 }
2821 return 1;
2822}
2823
Willy Tarreau7d562212016-11-25 16:10:05 +01002824/* set <smp> to the cumulated number of connections from the stream's tracked
2825 * frontend counters. Supports being called as "sc[0-9]_conn_cnt" or
2826 * "src_conn_cnt" only.
2827 */
2828static int
2829smp_fetch_sc_conn_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
2830{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002831 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002832 struct stkctr *stkctr;
2833
Emeric Brun819fc6f2017-06-13 19:37:32 +02002834 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002835 if (!stkctr)
2836 return 0;
2837
2838 smp->flags = SMP_F_VOL_TEST;
2839 smp->data.type = SMP_T_SINT;
2840 smp->data.u.sint = 0;
2841 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002842 void *ptr;
2843
2844 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_CONN_CNT);
2845 if (!ptr) {
2846 if (stkctr == &tmpstkctr)
2847 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002848 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002849 }
2850
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002851 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002852
Willy Tarreau7d562212016-11-25 16:10:05 +01002853 smp->data.u.sint = stktable_data_cast(ptr, conn_cnt);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002854
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002855 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002856
2857 if (stkctr == &tmpstkctr)
2858 stktable_release(stkctr->table, stkctr_entry(stkctr));
2859
2860
Willy Tarreau7d562212016-11-25 16:10:05 +01002861 }
2862 return 1;
2863}
2864
2865/* set <smp> to the connection rate from the stream's tracked frontend
2866 * counters. Supports being called as "sc[0-9]_conn_rate" or "src_conn_rate"
2867 * only.
2868 */
2869static int
2870smp_fetch_sc_conn_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
2871{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002872 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002873 struct stkctr *stkctr;
2874
Emeric Brun819fc6f2017-06-13 19:37:32 +02002875 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002876 if (!stkctr)
2877 return 0;
2878
2879 smp->flags = SMP_F_VOL_TEST;
2880 smp->data.type = SMP_T_SINT;
2881 smp->data.u.sint = 0;
2882 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002883 void *ptr;
2884
2885 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_CONN_RATE);
2886 if (!ptr) {
2887 if (stkctr == &tmpstkctr)
2888 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002889 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002890 }
2891
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002892 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002893
Willy Tarreau7d562212016-11-25 16:10:05 +01002894 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, conn_rate),
2895 stkctr->table->data_arg[STKTABLE_DT_CONN_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002896
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002897 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002898
2899 if (stkctr == &tmpstkctr)
2900 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002901 }
2902 return 1;
2903}
2904
2905/* set temp integer to the number of connections from the stream's source address
2906 * in the table pointed to by expr, after updating it.
2907 * Accepts exactly 1 argument of type table.
2908 */
2909static int
2910smp_fetch_src_updt_conn_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
2911{
2912 struct connection *conn = objt_conn(smp->sess->origin);
2913 struct stksess *ts;
2914 struct stktable_key *key;
2915 void *ptr;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002916 struct stktable *t;
Willy Tarreau7d562212016-11-25 16:10:05 +01002917
2918 if (!conn)
2919 return 0;
2920
Joseph Herlant5662fa42018-11-15 13:43:28 -08002921 /* Fetch source address in a sample. */
Christopher Fauletbdbd5db2021-01-29 10:27:47 +01002922 if (!smp_fetch_src || !smp_fetch_src(empty_arg_list, smp, NULL, NULL))
Willy Tarreau7d562212016-11-25 16:10:05 +01002923 return 0;
2924
2925 /* Converts into key. */
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002926 key = smp_to_stkey(smp, args->data.t);
Willy Tarreau7d562212016-11-25 16:10:05 +01002927 if (!key)
2928 return 0;
2929
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002930 t = args->data.t;
Willy Tarreau7d562212016-11-25 16:10:05 +01002931
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002932 if ((ts = stktable_get_entry(t, key)) == NULL)
Willy Tarreau7d562212016-11-25 16:10:05 +01002933 /* entry does not exist and could not be created */
2934 return 0;
2935
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002936 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_CONN_CNT);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002937 if (!ptr) {
Willy Tarreau7d562212016-11-25 16:10:05 +01002938 return 0; /* parameter not stored in this table */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002939 }
Willy Tarreau7d562212016-11-25 16:10:05 +01002940
2941 smp->data.type = SMP_T_SINT;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002942
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002943 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002944
Willy Tarreau7d562212016-11-25 16:10:05 +01002945 smp->data.u.sint = ++stktable_data_cast(ptr, conn_cnt);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002946
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002947 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002948
Willy Tarreau7d562212016-11-25 16:10:05 +01002949 smp->flags = SMP_F_VOL_TEST;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002950
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002951 stktable_touch_local(t, ts, 1);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002952
2953 /* Touch was previously performed by stktable_update_key */
Willy Tarreau7d562212016-11-25 16:10:05 +01002954 return 1;
2955}
2956
2957/* set <smp> to the number of concurrent connections from the stream's tracked
2958 * frontend counters. Supports being called as "sc[0-9]_conn_cur" or
2959 * "src_conn_cur" only.
2960 */
2961static int
2962smp_fetch_sc_conn_cur(const struct arg *args, struct sample *smp, const char *kw, void *private)
2963{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002964 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002965 struct stkctr *stkctr;
2966
Emeric Brun819fc6f2017-06-13 19:37:32 +02002967 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002968 if (!stkctr)
2969 return 0;
2970
2971 smp->flags = SMP_F_VOL_TEST;
2972 smp->data.type = SMP_T_SINT;
2973 smp->data.u.sint = 0;
2974 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002975 void *ptr;
2976
2977 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_CONN_CUR);
2978 if (!ptr) {
2979 if (stkctr == &tmpstkctr)
2980 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002981 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002982 }
2983
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002984 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002985
Willy Tarreau7d562212016-11-25 16:10:05 +01002986 smp->data.u.sint = stktable_data_cast(ptr, conn_cur);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002987
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002988 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002989
2990 if (stkctr == &tmpstkctr)
2991 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002992 }
2993 return 1;
2994}
2995
2996/* set <smp> to the cumulated number of streams from the stream's tracked
2997 * frontend counters. Supports being called as "sc[0-9]_sess_cnt" or
2998 * "src_sess_cnt" only.
2999 */
3000static int
3001smp_fetch_sc_sess_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
3002{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003003 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003004 struct stkctr *stkctr;
3005
Emeric Brun819fc6f2017-06-13 19:37:32 +02003006 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003007 if (!stkctr)
3008 return 0;
3009
3010 smp->flags = SMP_F_VOL_TEST;
3011 smp->data.type = SMP_T_SINT;
3012 smp->data.u.sint = 0;
3013 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003014 void *ptr;
3015
3016 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_SESS_CNT);
3017 if (!ptr) {
3018 if (stkctr == &tmpstkctr)
3019 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003020 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003021 }
3022
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003023 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003024
Willy Tarreau7d562212016-11-25 16:10:05 +01003025 smp->data.u.sint = stktable_data_cast(ptr, sess_cnt);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003026
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003027 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003028
3029 if (stkctr == &tmpstkctr)
3030 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003031 }
3032 return 1;
3033}
3034
3035/* set <smp> to the stream rate from the stream's tracked frontend counters.
3036 * Supports being called as "sc[0-9]_sess_rate" or "src_sess_rate" only.
3037 */
3038static int
3039smp_fetch_sc_sess_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3040{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003041 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003042 struct stkctr *stkctr;
3043
Emeric Brun819fc6f2017-06-13 19:37:32 +02003044 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003045 if (!stkctr)
3046 return 0;
3047
3048 smp->flags = SMP_F_VOL_TEST;
3049 smp->data.type = SMP_T_SINT;
3050 smp->data.u.sint = 0;
3051 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003052 void *ptr;
3053
3054 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_SESS_RATE);
3055 if (!ptr) {
3056 if (stkctr == &tmpstkctr)
3057 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003058 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003059 }
3060
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003061 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003062
Willy Tarreau7d562212016-11-25 16:10:05 +01003063 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, sess_rate),
3064 stkctr->table->data_arg[STKTABLE_DT_SESS_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003065
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003066 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003067
3068 if (stkctr == &tmpstkctr)
3069 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003070 }
3071 return 1;
3072}
3073
3074/* set <smp> to the cumulated number of HTTP requests from the stream's tracked
3075 * frontend counters. Supports being called as "sc[0-9]_http_req_cnt" or
3076 * "src_http_req_cnt" only.
3077 */
3078static int
3079smp_fetch_sc_http_req_cnt(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_HTTP_REQ_CNT);
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 = stktable_data_cast(ptr, http_req_cnt);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003104
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003105 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003106
3107 if (stkctr == &tmpstkctr)
3108 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003109 }
3110 return 1;
3111}
3112
3113/* set <smp> to the HTTP request rate from the stream's tracked frontend
3114 * counters. Supports being called as "sc[0-9]_http_req_rate" or
3115 * "src_http_req_rate" only.
3116 */
3117static int
3118smp_fetch_sc_http_req_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3119{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003120 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003121 struct stkctr *stkctr;
3122
Emeric Brun819fc6f2017-06-13 19:37:32 +02003123 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003124 if (!stkctr)
3125 return 0;
3126
3127 smp->flags = SMP_F_VOL_TEST;
3128 smp->data.type = SMP_T_SINT;
3129 smp->data.u.sint = 0;
3130 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003131 void *ptr;
3132
3133 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_REQ_RATE);
3134 if (!ptr) {
3135 if (stkctr == &tmpstkctr)
3136 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003137 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003138 }
3139
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003140 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003141
Willy Tarreau7d562212016-11-25 16:10:05 +01003142 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, http_req_rate),
3143 stkctr->table->data_arg[STKTABLE_DT_HTTP_REQ_RATE].u);
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 cumulated number of HTTP requests errors from the stream's
3154 * tracked frontend counters. Supports being called as "sc[0-9]_http_err_cnt" or
3155 * "src_http_err_cnt" only.
3156 */
3157static int
3158smp_fetch_sc_http_err_cnt(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_ERR_CNT);
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 = stktable_data_cast(ptr, http_err_cnt);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003183
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003184 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003185
3186 if (stkctr == &tmpstkctr)
3187 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003188 }
3189 return 1;
3190}
3191
3192/* set <smp> to the HTTP request error rate from the stream's tracked frontend
3193 * counters. Supports being called as "sc[0-9]_http_err_rate" or
3194 * "src_http_err_rate" only.
3195 */
3196static int
3197smp_fetch_sc_http_err_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3198{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003199 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003200 struct stkctr *stkctr;
3201
Emeric Brun819fc6f2017-06-13 19:37:32 +02003202 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003203 if (!stkctr)
3204 return 0;
3205
3206 smp->flags = SMP_F_VOL_TEST;
3207 smp->data.type = SMP_T_SINT;
3208 smp->data.u.sint = 0;
3209 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003210 void *ptr;
3211
3212 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_ERR_RATE);
3213 if (!ptr) {
3214 if (stkctr == &tmpstkctr)
3215 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003216 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003217 }
3218
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003219 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003220
Willy Tarreau7d562212016-11-25 16:10:05 +01003221 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, http_err_rate),
3222 stkctr->table->data_arg[STKTABLE_DT_HTTP_ERR_RATE].u);
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
Willy Tarreau826f3ab2021-02-10 12:07:15 +01003232/* set <smp> to the cumulated number of HTTP response failures from the stream's
3233 * tracked frontend counters. Supports being called as "sc[0-9]_http_fail_cnt" or
3234 * "src_http_fail_cnt" only.
3235 */
3236static int
3237smp_fetch_sc_http_fail_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
3238{
3239 struct stkctr tmpstkctr;
3240 struct stkctr *stkctr;
3241
3242 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
3243 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) {
3250 void *ptr;
3251
3252 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_FAIL_CNT);
3253 if (!ptr) {
3254 if (stkctr == &tmpstkctr)
3255 stktable_release(stkctr->table, stkctr_entry(stkctr));
3256 return 0; /* parameter not stored */
3257 }
3258
3259 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3260
3261 smp->data.u.sint = stktable_data_cast(ptr, http_fail_cnt);
3262
3263 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3264
3265 if (stkctr == &tmpstkctr)
3266 stktable_release(stkctr->table, stkctr_entry(stkctr));
3267 }
3268 return 1;
3269}
3270
3271/* set <smp> to the HTTP response failure rate from the stream's tracked frontend
3272 * counters. Supports being called as "sc[0-9]_http_fail_rate" or
3273 * "src_http_fail_rate" only.
3274 */
3275static int
3276smp_fetch_sc_http_fail_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3277{
3278 struct stkctr tmpstkctr;
3279 struct stkctr *stkctr;
3280
3281 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
3282 if (!stkctr)
3283 return 0;
3284
3285 smp->flags = SMP_F_VOL_TEST;
3286 smp->data.type = SMP_T_SINT;
3287 smp->data.u.sint = 0;
3288 if (stkctr_entry(stkctr) != NULL) {
3289 void *ptr;
3290
3291 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_FAIL_RATE);
3292 if (!ptr) {
3293 if (stkctr == &tmpstkctr)
3294 stktable_release(stkctr->table, stkctr_entry(stkctr));
3295 return 0; /* parameter not stored */
3296 }
3297
3298 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3299
3300 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, http_fail_rate),
3301 stkctr->table->data_arg[STKTABLE_DT_HTTP_FAIL_RATE].u);
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
Willy Tarreau7d562212016-11-25 16:10:05 +01003311/* set <smp> to the number of kbytes received from clients, as found in the
3312 * stream's tracked frontend counters. Supports being called as
3313 * "sc[0-9]_kbytes_in" or "src_kbytes_in" only.
3314 */
3315static int
3316smp_fetch_sc_kbytes_in(const struct arg *args, struct sample *smp, const char *kw, void *private)
3317{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003318 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003319 struct stkctr *stkctr;
3320
Emeric Brun819fc6f2017-06-13 19:37:32 +02003321 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003322 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) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003329 void *ptr;
3330
3331 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_IN_CNT);
3332 if (!ptr) {
3333 if (stkctr == &tmpstkctr)
3334 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003335 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003336 }
3337
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003338 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003339
Willy Tarreau7d562212016-11-25 16:10:05 +01003340 smp->data.u.sint = stktable_data_cast(ptr, bytes_in_cnt) >> 10;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003341
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003342 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003343
3344 if (stkctr == &tmpstkctr)
3345 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003346 }
3347 return 1;
3348}
3349
3350/* set <smp> to the data rate received from clients in bytes/s, as found
3351 * in the stream's tracked frontend counters. Supports being called as
3352 * "sc[0-9]_bytes_in_rate" or "src_bytes_in_rate" only.
3353 */
3354static int
3355smp_fetch_sc_bytes_in_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3356{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003357 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003358 struct stkctr *stkctr;
3359
Emeric Brun819fc6f2017-06-13 19:37:32 +02003360 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003361 if (!stkctr)
3362 return 0;
3363
3364 smp->flags = SMP_F_VOL_TEST;
3365 smp->data.type = SMP_T_SINT;
3366 smp->data.u.sint = 0;
3367 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003368 void *ptr;
3369
3370 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_IN_RATE);
3371 if (!ptr) {
3372 if (stkctr == &tmpstkctr)
3373 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003374 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003375 }
3376
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003377 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003378
Willy Tarreau7d562212016-11-25 16:10:05 +01003379 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, bytes_in_rate),
3380 stkctr->table->data_arg[STKTABLE_DT_BYTES_IN_RATE].u);
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 number of kbytes sent to clients, as found in the
3391 * stream's tracked frontend counters. Supports being called as
3392 * "sc[0-9]_kbytes_out" or "src_kbytes_out" only.
3393 */
3394static int
3395smp_fetch_sc_kbytes_out(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_OUT_CNT);
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 = stktable_data_cast(ptr, bytes_out_cnt) >> 10;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003420
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003421 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003422
3423 if (stkctr == &tmpstkctr)
3424 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003425 }
3426 return 1;
3427}
3428
3429/* set <smp> to the data rate sent to clients in bytes/s, as found in the
3430 * stream's tracked frontend counters. Supports being called as
3431 * "sc[0-9]_bytes_out_rate" or "src_bytes_out_rate" only.
3432 */
3433static int
3434smp_fetch_sc_bytes_out_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3435{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003436 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003437 struct stkctr *stkctr;
3438
Emeric Brun819fc6f2017-06-13 19:37:32 +02003439 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003440 if (!stkctr)
3441 return 0;
3442
3443 smp->flags = SMP_F_VOL_TEST;
3444 smp->data.type = SMP_T_SINT;
3445 smp->data.u.sint = 0;
3446 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003447 void *ptr;
3448
3449 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_OUT_RATE);
3450 if (!ptr) {
3451 if (stkctr == &tmpstkctr)
3452 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003453 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003454 }
3455
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003456 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003457
Willy Tarreau7d562212016-11-25 16:10:05 +01003458 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, bytes_out_rate),
3459 stkctr->table->data_arg[STKTABLE_DT_BYTES_OUT_RATE].u);
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 number of active trackers on the SC entry in the stream's
3470 * tracked frontend counters. Supports being called as "sc[0-9]_trackers" only.
3471 */
3472static int
3473smp_fetch_sc_trackers(const struct arg *args, struct sample *smp, const char *kw, void *private)
3474{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003475 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003476 struct stkctr *stkctr;
3477
Emeric Brun819fc6f2017-06-13 19:37:32 +02003478 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003479 if (!stkctr)
3480 return 0;
3481
3482 smp->flags = SMP_F_VOL_TEST;
3483 smp->data.type = SMP_T_SINT;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003484 if (stkctr == &tmpstkctr) {
3485 smp->data.u.sint = stkctr_entry(stkctr) ? (stkctr_entry(stkctr)->ref_cnt-1) : 0;
3486 stktable_release(stkctr->table, stkctr_entry(stkctr));
3487 }
3488 else {
3489 smp->data.u.sint = stkctr_entry(stkctr) ? stkctr_entry(stkctr)->ref_cnt : 0;
3490 }
3491
Willy Tarreau7d562212016-11-25 16:10:05 +01003492 return 1;
3493}
3494
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003495
3496/* The functions below are used to manipulate table contents from the CLI.
3497 * There are 3 main actions, "clear", "set" and "show". The code is shared
3498 * between all actions, and the action is encoded in the void *private in
3499 * the appctx as well as in the keyword registration, among one of the
3500 * following values.
3501 */
3502
3503enum {
3504 STK_CLI_ACT_CLR,
3505 STK_CLI_ACT_SET,
3506 STK_CLI_ACT_SHOW,
3507};
3508
3509/* Dump the status of a table to a stream interface's
3510 * read buffer. It returns 0 if the output buffer is full
3511 * and needs to be called again, otherwise non-zero.
3512 */
Willy Tarreau83061a82018-07-13 11:56:34 +02003513static int table_dump_head_to_buffer(struct buffer *msg,
3514 struct stream_interface *si,
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003515 struct stktable *t, struct stktable *target)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003516{
3517 struct stream *s = si_strm(si);
3518
3519 chunk_appendf(msg, "# table: %s, type: %s, size:%d, used:%d\n",
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003520 t->id, stktable_types[t->type].kw, t->size, t->current);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003521
3522 /* any other information should be dumped here */
3523
William Lallemand07a62f72017-05-24 00:57:40 +02003524 if (target && (strm_li(s)->bind_conf->level & ACCESS_LVL_MASK) < ACCESS_LVL_OPER)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003525 chunk_appendf(msg, "# contents not dumped due to insufficient privileges\n");
3526
Willy Tarreau06d80a92017-10-19 14:32:15 +02003527 if (ci_putchk(si_ic(si), msg) == -1) {
Willy Tarreaudb398432018-11-15 11:08:52 +01003528 si_rx_room_blk(si);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003529 return 0;
3530 }
3531
3532 return 1;
3533}
3534
3535/* Dump a table entry to a stream interface's
3536 * read buffer. It returns 0 if the output buffer is full
3537 * and needs to be called again, otherwise non-zero.
3538 */
Willy Tarreau83061a82018-07-13 11:56:34 +02003539static int table_dump_entry_to_buffer(struct buffer *msg,
3540 struct stream_interface *si,
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003541 struct stktable *t, struct stksess *entry)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003542{
3543 int dt;
3544
3545 chunk_appendf(msg, "%p:", entry);
3546
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003547 if (t->type == SMP_T_IPV4) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003548 char addr[INET_ADDRSTRLEN];
3549 inet_ntop(AF_INET, (const void *)&entry->key.key, addr, sizeof(addr));
3550 chunk_appendf(msg, " key=%s", addr);
3551 }
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003552 else if (t->type == SMP_T_IPV6) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003553 char addr[INET6_ADDRSTRLEN];
3554 inet_ntop(AF_INET6, (const void *)&entry->key.key, addr, sizeof(addr));
3555 chunk_appendf(msg, " key=%s", addr);
3556 }
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003557 else if (t->type == SMP_T_SINT) {
Willy Tarreau6cde5d82020-02-25 09:41:22 +01003558 chunk_appendf(msg, " key=%u", read_u32(entry->key.key));
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003559 }
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003560 else if (t->type == SMP_T_STR) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003561 chunk_appendf(msg, " key=");
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003562 dump_text(msg, (const char *)entry->key.key, t->key_size);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003563 }
3564 else {
3565 chunk_appendf(msg, " key=");
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003566 dump_binary(msg, (const char *)entry->key.key, t->key_size);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003567 }
3568
3569 chunk_appendf(msg, " use=%d exp=%d", entry->ref_cnt - 1, tick_remain(now_ms, entry->expire));
3570
3571 for (dt = 0; dt < STKTABLE_DATA_TYPES; dt++) {
3572 void *ptr;
3573
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003574 if (t->data_ofs[dt] == 0)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003575 continue;
3576 if (stktable_data_types[dt].arg_type == ARG_T_DELAY)
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003577 chunk_appendf(msg, " %s(%d)=", stktable_data_types[dt].name, t->data_arg[dt].u);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003578 else
3579 chunk_appendf(msg, " %s=", stktable_data_types[dt].name);
3580
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003581 ptr = stktable_data_ptr(t, entry, dt);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003582 switch (stktable_data_types[dt].std_type) {
3583 case STD_T_SINT:
3584 chunk_appendf(msg, "%d", stktable_data_cast(ptr, std_t_sint));
3585 break;
3586 case STD_T_UINT:
3587 chunk_appendf(msg, "%u", stktable_data_cast(ptr, std_t_uint));
3588 break;
3589 case STD_T_ULL:
3590 chunk_appendf(msg, "%lld", stktable_data_cast(ptr, std_t_ull));
3591 break;
3592 case STD_T_FRQP:
3593 chunk_appendf(msg, "%d",
3594 read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003595 t->data_arg[dt].u));
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003596 break;
Frédéric Lécaille16b4f542019-05-23 12:15:04 +02003597 case STD_T_DICT: {
3598 struct dict_entry *de;
3599 de = stktable_data_cast(ptr, std_t_dict);
3600 chunk_appendf(msg, "%s", de ? (char *)de->value.key : "-");
3601 break;
3602 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003603 }
3604 }
3605 chunk_appendf(msg, "\n");
3606
Willy Tarreau06d80a92017-10-19 14:32:15 +02003607 if (ci_putchk(si_ic(si), msg) == -1) {
Willy Tarreaudb398432018-11-15 11:08:52 +01003608 si_rx_room_blk(si);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003609 return 0;
3610 }
3611
3612 return 1;
3613}
3614
3615
3616/* Processes a single table entry matching a specific key passed in argument.
3617 * returns 0 if wants to be called again, 1 if has ended processing.
3618 */
3619static int table_process_entry_per_key(struct appctx *appctx, char **args)
3620{
3621 struct stream_interface *si = appctx->owner;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003622 struct stktable *t = appctx->ctx.table.target;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003623 struct stksess *ts;
3624 uint32_t uint32_key;
3625 unsigned char ip6_key[sizeof(struct in6_addr)];
3626 long long value;
3627 int data_type;
3628 int cur_arg;
3629 void *ptr;
Willy Tarreaufa1258f2021-04-10 23:00:53 +02003630 struct freq_ctr *frqp;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003631
Willy Tarreau9d008692019-08-09 11:21:01 +02003632 if (!*args[4])
3633 return cli_err(appctx, "Key value expected\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003634
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003635 switch (t->type) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003636 case SMP_T_IPV4:
3637 uint32_key = htonl(inetaddr_host(args[4]));
Christopher Fauletca20d022017-08-29 15:30:31 +02003638 static_table_key.key = &uint32_key;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003639 break;
3640 case SMP_T_IPV6:
3641 inet_pton(AF_INET6, args[4], ip6_key);
Christopher Fauletca20d022017-08-29 15:30:31 +02003642 static_table_key.key = &ip6_key;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003643 break;
3644 case SMP_T_SINT:
3645 {
3646 char *endptr;
3647 unsigned long val;
3648 errno = 0;
3649 val = strtoul(args[4], &endptr, 10);
3650 if ((errno == ERANGE && val == ULONG_MAX) ||
3651 (errno != 0 && val == 0) || endptr == args[4] ||
Willy Tarreau9d008692019-08-09 11:21:01 +02003652 val > 0xffffffff)
3653 return cli_err(appctx, "Invalid key\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003654 uint32_key = (uint32_t) val;
Christopher Fauletca20d022017-08-29 15:30:31 +02003655 static_table_key.key = &uint32_key;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003656 break;
3657 }
3658 break;
3659 case SMP_T_STR:
Christopher Fauletca20d022017-08-29 15:30:31 +02003660 static_table_key.key = args[4];
3661 static_table_key.key_len = strlen(args[4]);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003662 break;
3663 default:
Willy Tarreaua24bc782016-12-14 15:50:35 +01003664 switch (appctx->ctx.table.action) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003665 case STK_CLI_ACT_SHOW:
Willy Tarreau9d008692019-08-09 11:21:01 +02003666 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 +01003667 case STK_CLI_ACT_CLR:
Willy Tarreau9d008692019-08-09 11:21:01 +02003668 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 +01003669 case STK_CLI_ACT_SET:
Willy Tarreau9d008692019-08-09 11:21:01 +02003670 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 +01003671 default:
Willy Tarreau9d008692019-08-09 11:21:01 +02003672 return cli_err(appctx, "Unknown action\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003673 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003674 }
3675
3676 /* check permissions */
3677 if (!cli_has_level(appctx, ACCESS_LVL_OPER))
3678 return 1;
3679
Willy Tarreaua24bc782016-12-14 15:50:35 +01003680 switch (appctx->ctx.table.action) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003681 case STK_CLI_ACT_SHOW:
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003682 ts = stktable_lookup_key(t, &static_table_key);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003683 if (!ts)
3684 return 1;
3685 chunk_reset(&trash);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003686 if (!table_dump_head_to_buffer(&trash, si, t, t)) {
3687 stktable_release(t, ts);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003688 return 0;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003689 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003690 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003691 if (!table_dump_entry_to_buffer(&trash, si, t, ts)) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003692 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003693 stktable_release(t, ts);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003694 return 0;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003695 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003696 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003697 stktable_release(t, ts);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003698 break;
3699
3700 case STK_CLI_ACT_CLR:
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003701 ts = stktable_lookup_key(t, &static_table_key);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003702 if (!ts)
3703 return 1;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003704
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003705 if (!stksess_kill(t, ts, 1)) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003706 /* don't delete an entry which is currently referenced */
Willy Tarreau9d008692019-08-09 11:21:01 +02003707 return cli_err(appctx, "Entry currently in use, cannot remove\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003708 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003709 break;
3710
3711 case STK_CLI_ACT_SET:
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003712 ts = stktable_get_entry(t, &static_table_key);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003713 if (!ts) {
3714 /* don't delete an entry which is currently referenced */
Willy Tarreau9d008692019-08-09 11:21:01 +02003715 return cli_err(appctx, "Unable to allocate a new entry\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003716 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003717 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003718 for (cur_arg = 5; *args[cur_arg]; cur_arg += 2) {
3719 if (strncmp(args[cur_arg], "data.", 5) != 0) {
Willy Tarreau9d008692019-08-09 11:21:01 +02003720 cli_err(appctx, "\"data.<type>\" followed by a value expected\n");
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003721 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003722 stktable_touch_local(t, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003723 return 1;
3724 }
3725
3726 data_type = stktable_get_data_type(args[cur_arg] + 5);
3727 if (data_type < 0) {
Willy Tarreau9d008692019-08-09 11:21:01 +02003728 cli_err(appctx, "Unknown data type\n");
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003729 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003730 stktable_touch_local(t, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003731 return 1;
3732 }
3733
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003734 if (!t->data_ofs[data_type]) {
Willy Tarreau9d008692019-08-09 11:21:01 +02003735 cli_err(appctx, "Data type not stored in this table\n");
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003736 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003737 stktable_touch_local(t, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003738 return 1;
3739 }
3740
3741 if (!*args[cur_arg+1] || strl2llrc(args[cur_arg+1], strlen(args[cur_arg+1]), &value) != 0) {
Willy Tarreau9d008692019-08-09 11:21:01 +02003742 cli_err(appctx, "Require a valid integer value to store\n");
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003743 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003744 stktable_touch_local(t, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003745 return 1;
3746 }
3747
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003748 ptr = stktable_data_ptr(t, ts, data_type);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003749
3750 switch (stktable_data_types[data_type].std_type) {
3751 case STD_T_SINT:
3752 stktable_data_cast(ptr, std_t_sint) = value;
3753 break;
3754 case STD_T_UINT:
3755 stktable_data_cast(ptr, std_t_uint) = value;
3756 break;
3757 case STD_T_ULL:
3758 stktable_data_cast(ptr, std_t_ull) = value;
3759 break;
3760 case STD_T_FRQP:
3761 /* We set both the current and previous values. That way
3762 * the reported frequency is stable during all the period
3763 * then slowly fades out. This allows external tools to
3764 * push measures without having to update them too often.
3765 */
3766 frqp = &stktable_data_cast(ptr, std_t_frqp);
Willy Tarreaufa1258f2021-04-10 23:00:53 +02003767 /* First bit is reserved for the freq_ctr lock
Emeric Brunf2fc1fd2017-11-02 17:32:43 +01003768 Note: here we're still protected by the stksess lock
Willy Tarreaufa1258f2021-04-10 23:00:53 +02003769 so we don't need to update the update the freq_ctr
Emeric Brunf2fc1fd2017-11-02 17:32:43 +01003770 using its internal lock */
3771 frqp->curr_tick = now_ms & ~0x1;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003772 frqp->prev_ctr = 0;
3773 frqp->curr_ctr = value;
3774 break;
3775 }
3776 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003777 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003778 stktable_touch_local(t, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003779 break;
3780
3781 default:
Willy Tarreau9d008692019-08-09 11:21:01 +02003782 return cli_err(appctx, "Unknown action\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003783 }
3784 return 1;
3785}
3786
3787/* Prepares the appctx fields with the data-based filters from the command line.
3788 * Returns 0 if the dump can proceed, 1 if has ended processing.
3789 */
3790static int table_prepare_data_request(struct appctx *appctx, char **args)
3791{
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01003792 int i;
Adis Nezirovicd0142e72020-01-22 16:50:27 +01003793 char *err = NULL;
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01003794
Willy Tarreau9d008692019-08-09 11:21:01 +02003795 if (appctx->ctx.table.action != STK_CLI_ACT_SHOW && appctx->ctx.table.action != STK_CLI_ACT_CLR)
3796 return cli_err(appctx, "content-based lookup is only supported with the \"show\" and \"clear\" actions\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003797
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01003798 for (i = 0; i < STKTABLE_FILTER_LEN; i++) {
3799 if (i > 0 && !*args[3+3*i]) // number of filter entries can be less than STKTABLE_FILTER_LEN
3800 break;
3801 /* condition on stored data value */
3802 appctx->ctx.table.data_type[i] = stktable_get_data_type(args[3+3*i] + 5);
3803 if (appctx->ctx.table.data_type[i] < 0)
Adis Nezirovicd0142e72020-01-22 16:50:27 +01003804 return cli_dynerr(appctx, memprintf(&err, "Filter entry #%i: Unknown data type\n", i + 1));
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003805
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01003806 if (!((struct stktable *)appctx->ctx.table.target)->data_ofs[appctx->ctx.table.data_type[i]])
Adis Nezirovicd0142e72020-01-22 16:50:27 +01003807 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 +01003808
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01003809 appctx->ctx.table.data_op[i] = get_std_op(args[4+3*i]);
Willy Tarreau2b64a352020-01-22 17:09:47 +01003810 if (appctx->ctx.table.data_op[i] < 0)
Adis Nezirovicd0142e72020-01-22 16:50:27 +01003811 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 +01003812
Adis Nezirovic56dd3542020-01-22 16:16:48 +01003813 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 +01003814 return cli_dynerr(appctx, memprintf(&err, "Filter entry #%i: Require a valid integer value to compare against\n", i + 1));
3815 }
3816
3817 if (*args[3+3*i]) {
3818 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 +01003819 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003820
3821 /* OK we're done, all the fields are set */
3822 return 0;
3823}
3824
3825/* returns 0 if wants to be called, 1 if has ended processing */
Aurélien Nephtaliabbf6072018-04-18 13:26:46 +02003826static int cli_parse_table_req(char **args, char *payload, struct appctx *appctx, void *private)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003827{
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01003828 int i;
3829
3830 for (i = 0; i < STKTABLE_FILTER_LEN; i++)
3831 appctx->ctx.table.data_type[i] = -1;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003832 appctx->ctx.table.target = NULL;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003833 appctx->ctx.table.entry = NULL;
Willy Tarreaua24bc782016-12-14 15:50:35 +01003834 appctx->ctx.table.action = (long)private; // keyword argument, one of STK_CLI_ACT_*
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003835
3836 if (*args[2]) {
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003837 appctx->ctx.table.target = stktable_find_by_name(args[2]);
Willy Tarreau9d008692019-08-09 11:21:01 +02003838 if (!appctx->ctx.table.target)
3839 return cli_err(appctx, "No such table\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003840 }
3841 else {
Willy Tarreaua24bc782016-12-14 15:50:35 +01003842 if (appctx->ctx.table.action != STK_CLI_ACT_SHOW)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003843 goto err_args;
3844 return 0;
3845 }
3846
3847 if (strcmp(args[3], "key") == 0)
3848 return table_process_entry_per_key(appctx, args);
3849 else if (strncmp(args[3], "data.", 5) == 0)
3850 return table_prepare_data_request(appctx, args);
3851 else if (*args[3])
3852 goto err_args;
3853
3854 return 0;
3855
3856err_args:
Willy Tarreaua24bc782016-12-14 15:50:35 +01003857 switch (appctx->ctx.table.action) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003858 case STK_CLI_ACT_SHOW:
Willy Tarreau9d008692019-08-09 11:21:01 +02003859 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 +01003860 case STK_CLI_ACT_CLR:
Willy Tarreau9d008692019-08-09 11:21:01 +02003861 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 +01003862 case STK_CLI_ACT_SET:
Willy Tarreau9d008692019-08-09 11:21:01 +02003863 return cli_err(appctx, "Required arguments: <table> key <key> [data.<store_data_type> <value>]*\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003864 default:
Willy Tarreau9d008692019-08-09 11:21:01 +02003865 return cli_err(appctx, "Unknown action\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003866 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003867}
3868
3869/* This function is used to deal with table operations (dump or clear depending
3870 * on the action stored in appctx->private). It returns 0 if the output buffer is
3871 * full and it needs to be called again, otherwise non-zero.
3872 */
3873static int cli_io_handler_table(struct appctx *appctx)
3874{
3875 struct stream_interface *si = appctx->owner;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003876 struct stream *s = si_strm(si);
3877 struct ebmb_node *eb;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003878 int skip_entry;
Willy Tarreaua24bc782016-12-14 15:50:35 +01003879 int show = appctx->ctx.table.action == STK_CLI_ACT_SHOW;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003880
3881 /*
3882 * We have 3 possible states in appctx->st2 :
3883 * - STAT_ST_INIT : the first call
3884 * - STAT_ST_INFO : the proxy pointer points to the next table to
3885 * dump, the entry pointer is NULL ;
3886 * - STAT_ST_LIST : the proxy pointer points to the current table
3887 * and the entry pointer points to the next entry to be dumped,
3888 * and the refcount on the next entry is held ;
3889 * - STAT_ST_END : nothing left to dump, the buffer may contain some
3890 * data though.
3891 */
3892
3893 if (unlikely(si_ic(si)->flags & (CF_WRITE_ERROR|CF_SHUTW))) {
3894 /* in case of abort, remove any refcount we might have set on an entry */
3895 if (appctx->st2 == STAT_ST_LIST) {
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003896 stksess_kill_if_expired(appctx->ctx.table.t, appctx->ctx.table.entry, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003897 }
3898 return 1;
3899 }
3900
3901 chunk_reset(&trash);
3902
3903 while (appctx->st2 != STAT_ST_FIN) {
3904 switch (appctx->st2) {
3905 case STAT_ST_INIT:
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003906 appctx->ctx.table.t = appctx->ctx.table.target;
3907 if (!appctx->ctx.table.t)
3908 appctx->ctx.table.t = stktables_list;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003909
3910 appctx->ctx.table.entry = NULL;
3911 appctx->st2 = STAT_ST_INFO;
3912 break;
3913
3914 case STAT_ST_INFO:
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003915 if (!appctx->ctx.table.t ||
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003916 (appctx->ctx.table.target &&
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003917 appctx->ctx.table.t != appctx->ctx.table.target)) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003918 appctx->st2 = STAT_ST_END;
3919 break;
3920 }
3921
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003922 if (appctx->ctx.table.t->size) {
3923 if (show && !table_dump_head_to_buffer(&trash, si, appctx->ctx.table.t, appctx->ctx.table.target))
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003924 return 0;
3925
3926 if (appctx->ctx.table.target &&
William Lallemand07a62f72017-05-24 00:57:40 +02003927 (strm_li(s)->bind_conf->level & ACCESS_LVL_MASK) >= ACCESS_LVL_OPER) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003928 /* dump entries only if table explicitly requested */
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003929 HA_SPIN_LOCK(STK_TABLE_LOCK, &appctx->ctx.table.t->lock);
3930 eb = ebmb_first(&appctx->ctx.table.t->keys);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003931 if (eb) {
3932 appctx->ctx.table.entry = ebmb_entry(eb, struct stksess, key);
3933 appctx->ctx.table.entry->ref_cnt++;
3934 appctx->st2 = STAT_ST_LIST;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003935 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &appctx->ctx.table.t->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003936 break;
3937 }
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003938 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &appctx->ctx.table.t->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003939 }
3940 }
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003941 appctx->ctx.table.t = appctx->ctx.table.t->next;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003942 break;
3943
3944 case STAT_ST_LIST:
3945 skip_entry = 0;
3946
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003947 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &appctx->ctx.table.entry->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003948
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01003949 if (appctx->ctx.table.data_type[0] >= 0) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003950 /* we're filtering on some data contents */
3951 void *ptr;
Willy Tarreau2b64a352020-01-22 17:09:47 +01003952 int dt, i;
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01003953 signed char op;
3954 long long data, value;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003955
Emeric Brun819fc6f2017-06-13 19:37:32 +02003956
Willy Tarreau2b64a352020-01-22 17:09:47 +01003957 for (i = 0; i < STKTABLE_FILTER_LEN; i++) {
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01003958 if (appctx->ctx.table.data_type[i] == -1)
3959 break;
3960 dt = appctx->ctx.table.data_type[i];
3961 ptr = stktable_data_ptr(appctx->ctx.table.t,
3962 appctx->ctx.table.entry,
3963 dt);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003964
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01003965 data = 0;
3966 switch (stktable_data_types[dt].std_type) {
3967 case STD_T_SINT:
3968 data = stktable_data_cast(ptr, std_t_sint);
3969 break;
3970 case STD_T_UINT:
3971 data = stktable_data_cast(ptr, std_t_uint);
3972 break;
3973 case STD_T_ULL:
3974 data = stktable_data_cast(ptr, std_t_ull);
3975 break;
3976 case STD_T_FRQP:
3977 data = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
3978 appctx->ctx.table.t->data_arg[dt].u);
3979 break;
3980 }
3981
3982 op = appctx->ctx.table.data_op[i];
3983 value = appctx->ctx.table.value[i];
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003984
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01003985 /* skip the entry if the data does not match the test and the value */
3986 if ((data < value &&
3987 (op == STD_OP_EQ || op == STD_OP_GT || op == STD_OP_GE)) ||
3988 (data == value &&
3989 (op == STD_OP_NE || op == STD_OP_GT || op == STD_OP_LT)) ||
3990 (data > value &&
3991 (op == STD_OP_EQ || op == STD_OP_LT || op == STD_OP_LE))) {
3992 skip_entry = 1;
3993 break;
3994 }
3995 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003996 }
3997
3998 if (show && !skip_entry &&
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003999 !table_dump_entry_to_buffer(&trash, si, appctx->ctx.table.t, appctx->ctx.table.entry)) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004000 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &appctx->ctx.table.entry->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004001 return 0;
4002 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004003
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004004 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &appctx->ctx.table.entry->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004005
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004006 HA_SPIN_LOCK(STK_TABLE_LOCK, &appctx->ctx.table.t->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004007 appctx->ctx.table.entry->ref_cnt--;
4008
4009 eb = ebmb_next(&appctx->ctx.table.entry->key);
4010 if (eb) {
4011 struct stksess *old = appctx->ctx.table.entry;
4012 appctx->ctx.table.entry = ebmb_entry(eb, struct stksess, key);
4013 if (show)
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004014 __stksess_kill_if_expired(appctx->ctx.table.t, old);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004015 else if (!skip_entry && !appctx->ctx.table.entry->ref_cnt)
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004016 __stksess_kill(appctx->ctx.table.t, old);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004017 appctx->ctx.table.entry->ref_cnt++;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004018 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &appctx->ctx.table.t->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004019 break;
4020 }
4021
4022
4023 if (show)
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004024 __stksess_kill_if_expired(appctx->ctx.table.t, appctx->ctx.table.entry);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004025 else if (!skip_entry && !appctx->ctx.table.entry->ref_cnt)
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004026 __stksess_kill(appctx->ctx.table.t, appctx->ctx.table.entry);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004027
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004028 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &appctx->ctx.table.t->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004029
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004030 appctx->ctx.table.t = appctx->ctx.table.t->next;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004031 appctx->st2 = STAT_ST_INFO;
4032 break;
4033
4034 case STAT_ST_END:
4035 appctx->st2 = STAT_ST_FIN;
4036 break;
4037 }
4038 }
4039 return 1;
4040}
4041
4042static void cli_release_show_table(struct appctx *appctx)
4043{
4044 if (appctx->st2 == STAT_ST_LIST) {
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004045 stksess_kill_if_expired(appctx->ctx.table.t, appctx->ctx.table.entry, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004046 }
4047}
4048
Willy Tarreau478331d2020-08-28 11:31:31 +02004049static void stkt_late_init(void)
4050{
4051 struct sample_fetch *f;
4052
4053 f = find_sample_fetch("src", strlen("src"));
4054 if (f)
4055 smp_fetch_src = f->process;
4056}
4057
4058INITCALL0(STG_INIT, stkt_late_init);
4059
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004060/* register cli keywords */
4061static struct cli_kw_list cli_kws = {{ },{
4062 { { "clear", "table", NULL }, "clear table : remove an entry from a table", cli_parse_table_req, cli_io_handler_table, cli_release_show_table, (void *)STK_CLI_ACT_CLR },
4063 { { "set", "table", NULL }, "set table [id] : update or create a table entry's data", cli_parse_table_req, cli_io_handler_table, NULL, (void *)STK_CLI_ACT_SET },
4064 { { "show", "table", NULL }, "show table [id]: report table usage stats or dump this table's contents", cli_parse_table_req, cli_io_handler_table, cli_release_show_table, (void *)STK_CLI_ACT_SHOW },
4065 {{},}
4066}};
4067
Willy Tarreau0108d902018-11-25 19:14:37 +01004068INITCALL1(STG_REGISTER, cli_register_kw, &cli_kws);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004069
Thierry FOURNIER236657b2015-08-19 08:25:14 +02004070static struct action_kw_list tcp_conn_kws = { { }, {
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02004071 { "sc-inc-gpc0", parse_inc_gpc0, 1 },
Frédéric Lécaille6778b272018-01-29 15:22:53 +01004072 { "sc-inc-gpc1", parse_inc_gpc1, 1 },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02004073 { "sc-set-gpt0", parse_set_gpt0, 1 },
4074 { /* END */ }
4075}};
4076
Willy Tarreau0108d902018-11-25 19:14:37 +01004077INITCALL1(STG_REGISTER, tcp_req_conn_keywords_register, &tcp_conn_kws);
4078
Willy Tarreau620408f2016-10-21 16:37:51 +02004079static struct action_kw_list tcp_sess_kws = { { }, {
4080 { "sc-inc-gpc0", parse_inc_gpc0, 1 },
Frédéric Lécaille6778b272018-01-29 15:22:53 +01004081 { "sc-inc-gpc1", parse_inc_gpc1, 1 },
Willy Tarreau620408f2016-10-21 16:37:51 +02004082 { "sc-set-gpt0", parse_set_gpt0, 1 },
4083 { /* END */ }
4084}};
4085
Willy Tarreau0108d902018-11-25 19:14:37 +01004086INITCALL1(STG_REGISTER, tcp_req_sess_keywords_register, &tcp_sess_kws);
4087
Thierry FOURNIER236657b2015-08-19 08:25:14 +02004088static struct action_kw_list tcp_req_kws = { { }, {
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02004089 { "sc-inc-gpc0", parse_inc_gpc0, 1 },
Frédéric Lécaille6778b272018-01-29 15:22:53 +01004090 { "sc-inc-gpc1", parse_inc_gpc1, 1 },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02004091 { "sc-set-gpt0", parse_set_gpt0, 1 },
4092 { /* END */ }
4093}};
4094
Willy Tarreau0108d902018-11-25 19:14:37 +01004095INITCALL1(STG_REGISTER, tcp_req_cont_keywords_register, &tcp_req_kws);
4096
Thierry FOURNIER236657b2015-08-19 08:25:14 +02004097static struct action_kw_list tcp_res_kws = { { }, {
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02004098 { "sc-inc-gpc0", parse_inc_gpc0, 1 },
Frédéric Lécaille6778b272018-01-29 15:22:53 +01004099 { "sc-inc-gpc1", parse_inc_gpc1, 1 },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02004100 { "sc-set-gpt0", parse_set_gpt0, 1 },
4101 { /* END */ }
4102}};
4103
Willy Tarreau0108d902018-11-25 19:14:37 +01004104INITCALL1(STG_REGISTER, tcp_res_cont_keywords_register, &tcp_res_kws);
4105
Thierry FOURNIER236657b2015-08-19 08:25:14 +02004106static struct action_kw_list http_req_kws = { { }, {
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02004107 { "sc-inc-gpc0", parse_inc_gpc0, 1 },
Frédéric Lécaille6778b272018-01-29 15:22:53 +01004108 { "sc-inc-gpc1", parse_inc_gpc1, 1 },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02004109 { "sc-set-gpt0", parse_set_gpt0, 1 },
4110 { /* END */ }
4111}};
4112
Willy Tarreau0108d902018-11-25 19:14:37 +01004113INITCALL1(STG_REGISTER, http_req_keywords_register, &http_req_kws);
4114
Thierry FOURNIER236657b2015-08-19 08:25:14 +02004115static struct action_kw_list http_res_kws = { { }, {
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02004116 { "sc-inc-gpc0", parse_inc_gpc0, 1 },
Frédéric Lécaille6778b272018-01-29 15:22:53 +01004117 { "sc-inc-gpc1", parse_inc_gpc1, 1 },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02004118 { "sc-set-gpt0", parse_set_gpt0, 1 },
4119 { /* END */ }
4120}};
4121
Willy Tarreau0108d902018-11-25 19:14:37 +01004122INITCALL1(STG_REGISTER, http_res_keywords_register, &http_res_kws);
4123
Willy Tarreau7d562212016-11-25 16:10:05 +01004124///* Note: must not be declared <const> as its list will be overwritten.
4125// * Please take care of keeping this list alphabetically sorted.
4126// */
4127//static struct sample_fetch_kw_list smp_fetch_keywords = {ILH, {
4128// { "table_avl", smp_fetch_table_avl, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4129// { "table_cnt", smp_fetch_table_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4130// { /* END */ },
4131//}};
4132/* Note: must not be declared <const> as its list will be overwritten.
4133 * Please take care of keeping this list alphabetically sorted.
4134 */
4135static struct sample_fetch_kw_list smp_fetch_keywords = {ILH, {
4136 { "sc_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4137 { "sc_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4138 { "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 +01004139 { "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 +01004140 { "sc_conn_cnt", smp_fetch_sc_conn_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4141 { "sc_conn_cur", smp_fetch_sc_conn_cur, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4142 { "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 +01004143 { "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 +01004144 { "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 +01004145 { "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 +01004146 { "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 +01004147 { "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 +01004148 { "sc_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4149 { "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 +01004150 { "sc_http_fail_cnt", smp_fetch_sc_http_fail_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4151 { "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 +01004152 { "sc_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4153 { "sc_http_req_rate", smp_fetch_sc_http_req_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4154 { "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 +01004155 { "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 +01004156 { "sc_kbytes_in", smp_fetch_sc_kbytes_in, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4157 { "sc_kbytes_out", smp_fetch_sc_kbytes_out, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4158 { "sc_sess_cnt", smp_fetch_sc_sess_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4159 { "sc_sess_rate", smp_fetch_sc_sess_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4160 { "sc_tracked", smp_fetch_sc_tracked, ARG2(1,SINT,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
4161 { "sc_trackers", smp_fetch_sc_trackers, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4162 { "sc0_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4163 { "sc0_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4164 { "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 +01004165 { "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 +01004166 { "sc0_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4167 { "sc0_conn_cur", smp_fetch_sc_conn_cur, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4168 { "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 +01004169 { "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 +01004170 { "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 +01004171 { "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 +01004172 { "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 +01004173 { "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 +01004174 { "sc0_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4175 { "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 +01004176 { "sc0_http_fail_cnt", smp_fetch_sc_http_fail_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4177 { "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 +01004178 { "sc0_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4179 { "sc0_http_req_rate", smp_fetch_sc_http_req_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4180 { "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 +01004181 { "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 +01004182 { "sc0_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4183 { "sc0_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4184 { "sc0_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4185 { "sc0_sess_rate", smp_fetch_sc_sess_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4186 { "sc0_tracked", smp_fetch_sc_tracked, ARG1(0,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
4187 { "sc0_trackers", smp_fetch_sc_trackers, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4188 { "sc1_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4189 { "sc1_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4190 { "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 +01004191 { "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 +01004192 { "sc1_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4193 { "sc1_conn_cur", smp_fetch_sc_conn_cur, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4194 { "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 +01004195 { "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 +01004196 { "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 +01004197 { "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 +01004198 { "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 +01004199 { "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 +01004200 { "sc1_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4201 { "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 +01004202 { "sc1_http_fail_cnt", smp_fetch_sc_http_fail_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4203 { "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 +01004204 { "sc1_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4205 { "sc1_http_req_rate", smp_fetch_sc_http_req_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4206 { "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 +01004207 { "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 +01004208 { "sc1_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4209 { "sc1_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4210 { "sc1_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4211 { "sc1_sess_rate", smp_fetch_sc_sess_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4212 { "sc1_tracked", smp_fetch_sc_tracked, ARG1(0,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
4213 { "sc1_trackers", smp_fetch_sc_trackers, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4214 { "sc2_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4215 { "sc2_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4216 { "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 +01004217 { "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 +01004218 { "sc2_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4219 { "sc2_conn_cur", smp_fetch_sc_conn_cur, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4220 { "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 +01004221 { "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 +01004222 { "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 +01004223 { "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 +01004224 { "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 +01004225 { "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 +01004226 { "sc2_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4227 { "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 +01004228 { "sc2_http_fail_cnt", smp_fetch_sc_http_fail_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4229 { "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 +01004230 { "sc2_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4231 { "sc2_http_req_rate", smp_fetch_sc_http_req_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4232 { "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 +01004233 { "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 +01004234 { "sc2_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4235 { "sc2_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4236 { "sc2_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4237 { "sc2_sess_rate", smp_fetch_sc_sess_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4238 { "sc2_tracked", smp_fetch_sc_tracked, ARG1(0,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
4239 { "sc2_trackers", smp_fetch_sc_trackers, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4240 { "src_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4241 { "src_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4242 { "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 +01004243 { "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 +01004244 { "src_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4245 { "src_conn_cur", smp_fetch_sc_conn_cur, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4246 { "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 +01004247 { "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 +01004248 { "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 +01004249 { "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 +01004250 { "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 +01004251 { "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 +01004252 { "src_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4253 { "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 +01004254 { "src_http_fail_cnt", smp_fetch_sc_http_fail_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4255 { "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 +01004256 { "src_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4257 { "src_http_req_rate", smp_fetch_sc_http_req_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4258 { "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 +01004259 { "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 +01004260 { "src_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4261 { "src_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4262 { "src_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4263 { "src_sess_rate", smp_fetch_sc_sess_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4264 { "src_updt_conn_cnt", smp_fetch_src_updt_conn_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4265 { "table_avl", smp_fetch_table_avl, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4266 { "table_cnt", smp_fetch_table_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4267 { /* END */ },
4268}};
4269
Willy Tarreau0108d902018-11-25 19:14:37 +01004270INITCALL1(STG_REGISTER, sample_register_fetches, &smp_fetch_keywords);
Willy Tarreau7d562212016-11-25 16:10:05 +01004271
Willy Tarreaud9f316a2014-07-10 14:03:38 +02004272/* Note: must not be declared <const> as its list will be overwritten */
4273static struct sample_conv_kw_list sample_conv_kws = {ILH, {
Willy Tarreau2d17db52016-05-25 17:16:38 +02004274 { "in_table", sample_conv_in_table, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_BOOL },
4275 { "table_bytes_in_rate", sample_conv_table_bytes_in_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4276 { "table_bytes_out_rate", sample_conv_table_bytes_out_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4277 { "table_conn_cnt", sample_conv_table_conn_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4278 { "table_conn_cur", sample_conv_table_conn_cur, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4279 { "table_conn_rate", sample_conv_table_conn_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4280 { "table_gpt0", sample_conv_table_gpt0, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4281 { "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 +01004282 { "table_gpc1", sample_conv_table_gpc1, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
Willy Tarreau2d17db52016-05-25 17:16:38 +02004283 { "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 +01004284 { "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 +02004285 { "table_http_err_cnt", sample_conv_table_http_err_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4286 { "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 +01004287 { "table_http_fail_cnt", sample_conv_table_http_fail_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4288 { "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 +02004289 { "table_http_req_cnt", sample_conv_table_http_req_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4290 { "table_http_req_rate", sample_conv_table_http_req_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4291 { "table_kbytes_in", sample_conv_table_kbytes_in, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4292 { "table_kbytes_out", sample_conv_table_kbytes_out, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4293 { "table_server_id", sample_conv_table_server_id, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4294 { "table_sess_cnt", sample_conv_table_sess_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4295 { "table_sess_rate", sample_conv_table_sess_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4296 { "table_trackers", sample_conv_table_trackers, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
Willy Tarreaud9f316a2014-07-10 14:03:38 +02004297 { /* END */ },
4298}};
4299
Willy Tarreau0108d902018-11-25 19:14:37 +01004300INITCALL1(STG_REGISTER, sample_register_convs, &sample_conv_kws);