blob: 665a815143cf2da2364d1e1ba17089d315520210 [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{
Remi Tricot-Le Bretonbe5b1bb2021-05-12 17:39:04 +0200640 int peers_retval = 0;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100641 if (t->size) {
Emeric Brun819fc6f2017-06-13 19:37:32 +0200642 t->keys = EB_ROOT_UNIQUE;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100643 memset(&t->exps, 0, sizeof(t->exps));
Emeric Brun1c6235d2015-12-16 15:28:12 +0100644 t->updates = EB_ROOT_UNIQUE;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100645 HA_SPIN_INIT(&t->lock);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100646
Olivier Houchard52dabbc2018-11-14 17:54:36 +0100647 t->pool = create_pool("sticktables", sizeof(struct stksess) + round_ptr_size(t->data_size) + t->key_size, MEM_F_SHARED);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100648
649 t->exp_next = TICK_ETERNITY;
650 if ( t->expire ) {
Emeric Brunc60def82017-09-27 14:59:38 +0200651 t->exp_task = task_new(MAX_THREADS_MASK);
Willy Tarreau848522f2018-10-15 11:12:15 +0200652 if (!t->exp_task)
653 return 0;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100654 t->exp_task->process = process_table_expire;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100655 t->exp_task->context = (void *)t;
656 }
Willy Tarreauc3914d42020-09-24 08:39:22 +0200657 if (t->peers.p && t->peers.p->peers_fe && !t->peers.p->peers_fe->disabled) {
Remi Tricot-Le Bretonbe5b1bb2021-05-12 17:39:04 +0200658 peers_retval = peers_register_table(t->peers.p, t);
Emeric Brun32da3c42010-09-23 18:39:19 +0200659 }
660
Remi Tricot-Le Bretonbe5b1bb2021-05-12 17:39:04 +0200661 return (t->pool != NULL) && !peers_retval;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100662 }
663 return 1;
664}
665
666/*
667 * Configuration keywords of known table types
668 */
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200669struct stktable_type stktable_types[SMP_TYPES] = {
670 [SMP_T_SINT] = { "integer", 0, 4 },
671 [SMP_T_IPV4] = { "ip", 0, 4 },
672 [SMP_T_IPV6] = { "ipv6", 0, 16 },
673 [SMP_T_STR] = { "string", STK_F_CUSTOM_KEYSIZE, 32 },
674 [SMP_T_BIN] = { "binary", STK_F_CUSTOM_KEYSIZE, 32 }
675};
Emeric Brun3bd697e2010-01-04 15:23:48 +0100676
677/*
678 * Parse table type configuration.
679 * Returns 0 on successful parsing, else 1.
680 * <myidx> is set at next configuration <args> index.
681 */
682int stktable_parse_type(char **args, int *myidx, unsigned long *type, size_t *key_size)
683{
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200684 for (*type = 0; *type < SMP_TYPES; (*type)++) {
685 if (!stktable_types[*type].kw)
686 continue;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100687 if (strcmp(args[*myidx], stktable_types[*type].kw) != 0)
688 continue;
689
690 *key_size = stktable_types[*type].default_size;
691 (*myidx)++;
692
Willy Tarreauaea940e2010-06-06 11:56:36 +0200693 if (stktable_types[*type].flags & STK_F_CUSTOM_KEYSIZE) {
Emeric Brun3bd697e2010-01-04 15:23:48 +0100694 if (strcmp("len", args[*myidx]) == 0) {
695 (*myidx)++;
696 *key_size = atol(args[*myidx]);
Emeric Brun485479d2010-09-23 18:02:19 +0200697 if (!*key_size)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100698 break;
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200699 if (*type == SMP_T_STR) {
Emeric Brun485479d2010-09-23 18:02:19 +0200700 /* null terminated string needs +1 for '\0'. */
701 (*key_size)++;
702 }
Emeric Brun3bd697e2010-01-04 15:23:48 +0100703 (*myidx)++;
704 }
705 }
706 return 0;
707 }
708 return 1;
709}
710
Willy Tarreau3b63ca22021-05-08 14:10:42 +0200711/* reserve some space for data type <type>, and associate argument at <sa> if
712 * not NULL. Returns PE_NONE (0) if OK or an error code among :
713 * - PE_ENUM_OOR if <type> does not exist
714 * - PE_EXIST if <type> is already registered
715 * - PE_ARG_NOT_USE if <sa> was provided but not expected
716 * - PE_ARG_MISSING if <sa> was expected but not provided
717 */
718int stktable_alloc_data_type(struct stktable *t, int type, const char *sa)
719{
720 if (type >= STKTABLE_DATA_TYPES)
721 return PE_ENUM_OOR;
722
723 if (t->data_ofs[type])
724 /* already allocated */
725 return PE_EXIST;
726
727 switch (stktable_data_types[type].arg_type) {
728 case ARG_T_NONE:
729 if (sa)
730 return PE_ARG_NOT_USED;
731 break;
732 case ARG_T_INT:
733 if (!sa)
734 return PE_ARG_MISSING;
735 t->data_arg[type].i = atoi(sa);
736 break;
737 case ARG_T_DELAY:
738 if (!sa)
739 return PE_ARG_MISSING;
740 sa = parse_time_err(sa, &t->data_arg[type].u, TIME_UNIT_MS);
741 if (sa)
742 return PE_ARG_INVC; /* invalid char */
743 break;
744 }
745
746 t->data_size += stktable_type_size(stktable_data_types[type].std_type);
747 t->data_ofs[type] = -t->data_size;
748 return PE_NONE;
749}
750
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100751/*
Frédéric Lécaillec02766a2019-03-20 15:06:55 +0100752 * Parse a line with <linenum> as number in <file> configuration file to configure
753 * the stick-table with <t> as address and <id> as ID.
754 * <peers> provides the "peers" section pointer only if this function is called
755 * from a "peers" section.
756 * <nid> is the stick-table name which is sent over the network. It must be equal
757 * to <id> if this stick-table is parsed from a proxy section, and prefixed by <peers>
758 * "peers" section name followed by a '/' character if parsed from a "peers" section.
Ilya Shipitsind4259502020-04-08 01:07:56 +0500759 * This is the responsibility of the caller to check this.
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100760 * Return an error status with ERR_* flags set if required, 0 if no error was encountered.
761 */
762int parse_stick_table(const char *file, int linenum, char **args,
Frédéric Lécaillec02766a2019-03-20 15:06:55 +0100763 struct stktable *t, char *id, char *nid, struct peers *peers)
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100764{
765 int err_code = 0;
766 int idx = 1;
767 unsigned int val;
768
769 if (!id || !*id) {
770 ha_alert("parsing [%s:%d] : %s: ID not provided.\n", file, linenum, args[0]);
771 err_code |= ERR_ALERT | ERR_ABORT;
772 goto out;
773 }
774
775 /* Store the "peers" section if this function is called from a "peers" section. */
776 if (peers) {
777 t->peers.p = peers;
778 idx++;
779 }
780
781 t->id = id;
Frédéric Lécaillec02766a2019-03-20 15:06:55 +0100782 t->nid = nid;
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100783 t->type = (unsigned int)-1;
784 t->conf.file = file;
785 t->conf.line = linenum;
786
787 while (*args[idx]) {
788 const char *err;
789
790 if (strcmp(args[idx], "size") == 0) {
791 idx++;
792 if (!*(args[idx])) {
793 ha_alert("parsing [%s:%d] : %s: missing argument after '%s'.\n",
794 file, linenum, args[0], args[idx-1]);
795 err_code |= ERR_ALERT | ERR_FATAL;
796 goto out;
797 }
798 if ((err = parse_size_err(args[idx], &t->size))) {
799 ha_alert("parsing [%s:%d] : %s: unexpected character '%c' in argument of '%s'.\n",
800 file, linenum, args[0], *err, args[idx-1]);
801 err_code |= ERR_ALERT | ERR_FATAL;
802 goto out;
803 }
804 idx++;
805 }
806 /* This argument does not exit in "peers" section. */
807 else if (!peers && strcmp(args[idx], "peers") == 0) {
808 idx++;
809 if (!*(args[idx])) {
810 ha_alert("parsing [%s:%d] : %s: missing argument after '%s'.\n",
811 file, linenum, args[0], args[idx-1]);
812 err_code |= ERR_ALERT | ERR_FATAL;
813 goto out;
814 }
815 t->peers.name = strdup(args[idx++]);
816 }
817 else if (strcmp(args[idx], "expire") == 0) {
818 idx++;
819 if (!*(args[idx])) {
820 ha_alert("parsing [%s:%d] : %s: missing argument after '%s'.\n",
821 file, linenum, args[0], args[idx-1]);
822 err_code |= ERR_ALERT | ERR_FATAL;
823 goto out;
824 }
825 err = parse_time_err(args[idx], &val, TIME_UNIT_MS);
Willy Tarreau9faebe32019-06-07 19:00:37 +0200826 if (err == PARSE_TIME_OVER) {
827 ha_alert("parsing [%s:%d]: %s: timer overflow in argument <%s> to <%s>, maximum value is 2147483647 ms (~24.8 days).\n",
828 file, linenum, args[0], args[idx], args[idx-1]);
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100829 err_code |= ERR_ALERT | ERR_FATAL;
830 goto out;
831 }
Willy Tarreau9faebe32019-06-07 19:00:37 +0200832 else if (err == PARSE_TIME_UNDER) {
833 ha_alert("parsing [%s:%d]: %s: timer underflow in argument <%s> to <%s>, minimum non-null value is 1 ms.\n",
834 file, linenum, args[0], args[idx], args[idx-1]);
835 err_code |= ERR_ALERT | ERR_FATAL;
836 goto out;
837 }
838 else if (err) {
839 ha_alert("parsing [%s:%d] : %s: unexpected character '%c' in argument of '%s'.\n",
840 file, linenum, args[0], *err, args[idx-1]);
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100841 err_code |= ERR_ALERT | ERR_FATAL;
842 goto out;
843 }
844 t->expire = val;
845 idx++;
846 }
847 else if (strcmp(args[idx], "nopurge") == 0) {
848 t->nopurge = 1;
849 idx++;
850 }
851 else if (strcmp(args[idx], "type") == 0) {
852 idx++;
853 if (stktable_parse_type(args, &idx, &t->type, &t->key_size) != 0) {
854 ha_alert("parsing [%s:%d] : %s: unknown type '%s'.\n",
855 file, linenum, args[0], args[idx]);
856 err_code |= ERR_ALERT | ERR_FATAL;
857 goto out;
858 }
859 /* idx already points to next arg */
860 }
861 else if (strcmp(args[idx], "store") == 0) {
862 int type, err;
863 char *cw, *nw, *sa;
864
865 idx++;
866 nw = args[idx];
867 while (*nw) {
868 /* the "store" keyword supports a comma-separated list */
869 cw = nw;
870 sa = NULL; /* store arg */
871 while (*nw && *nw != ',') {
872 if (*nw == '(') {
873 *nw = 0;
874 sa = ++nw;
875 while (*nw != ')') {
876 if (!*nw) {
877 ha_alert("parsing [%s:%d] : %s: missing closing parenthesis after store option '%s'.\n",
878 file, linenum, args[0], cw);
879 err_code |= ERR_ALERT | ERR_FATAL;
880 goto out;
881 }
882 nw++;
883 }
884 *nw = '\0';
885 }
886 nw++;
887 }
888 if (*nw)
889 *nw++ = '\0';
890 type = stktable_get_data_type(cw);
891 if (type < 0) {
892 ha_alert("parsing [%s:%d] : %s: unknown store option '%s'.\n",
893 file, linenum, args[0], cw);
894 err_code |= ERR_ALERT | ERR_FATAL;
895 goto out;
896 }
897
898 err = stktable_alloc_data_type(t, type, sa);
899 switch (err) {
900 case PE_NONE: break;
901 case PE_EXIST:
902 ha_warning("parsing [%s:%d]: %s: store option '%s' already enabled, ignored.\n",
903 file, linenum, args[0], cw);
904 err_code |= ERR_WARN;
905 break;
906
907 case PE_ARG_MISSING:
908 ha_alert("parsing [%s:%d] : %s: missing argument to store option '%s'.\n",
909 file, linenum, args[0], cw);
910 err_code |= ERR_ALERT | ERR_FATAL;
911 goto out;
912
913 case PE_ARG_NOT_USED:
914 ha_alert("parsing [%s:%d] : %s: unexpected argument to store option '%s'.\n",
915 file, linenum, args[0], cw);
916 err_code |= ERR_ALERT | ERR_FATAL;
917 goto out;
918
919 default:
920 ha_alert("parsing [%s:%d] : %s: error when processing store option '%s'.\n",
921 file, linenum, args[0], cw);
922 err_code |= ERR_ALERT | ERR_FATAL;
923 goto out;
924 }
925 }
926 idx++;
927 }
Thayne McCombs92149f92020-11-20 01:28:26 -0700928 else if (strcmp(args[idx], "srvkey") == 0) {
929 char *keytype;
930 idx++;
931 keytype = args[idx];
932 if (strcmp(keytype, "name") == 0) {
933 t->server_key_type = STKTABLE_SRV_NAME;
934 }
935 else if (strcmp(keytype, "addr") == 0) {
936 t->server_key_type = STKTABLE_SRV_ADDR;
937 }
938 else {
939 ha_alert("parsing [%s:%d] : %s : unknown server key type '%s'.\n",
940 file, linenum, args[0], keytype);
941 err_code |= ERR_ALERT | ERR_FATAL;
942 goto out;
943
944 }
945 idx++;
946 }
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100947 else {
948 ha_alert("parsing [%s:%d] : %s: unknown argument '%s'.\n",
949 file, linenum, args[0], args[idx]);
950 err_code |= ERR_ALERT | ERR_FATAL;
951 goto out;
952 }
953 }
954
955 if (!t->size) {
956 ha_alert("parsing [%s:%d] : %s: missing size.\n",
957 file, linenum, args[0]);
958 err_code |= ERR_ALERT | ERR_FATAL;
959 goto out;
960 }
961
962 if (t->type == (unsigned int)-1) {
963 ha_alert("parsing [%s:%d] : %s: missing type.\n",
964 file, linenum, args[0]);
965 err_code |= ERR_ALERT | ERR_FATAL;
966 goto out;
967 }
968
969 out:
970 return err_code;
971}
972
Willy Tarreau8fed9032014-07-03 17:02:46 +0200973/* Prepares a stktable_key from a sample <smp> to search into table <t>.
Willy Tarreauf0c730a2016-05-25 17:07:56 +0200974 * Note that the sample *is* modified and that the returned key may point
975 * to it, so the sample must not be modified afterwards before the lookup.
Willy Tarreau8fed9032014-07-03 17:02:46 +0200976 * Returns NULL if the sample could not be converted (eg: no matching type),
977 * otherwise a pointer to the static stktable_key filled with what is needed
978 * for the lookup.
Willy Tarreauf0b38bf2010-06-06 13:22:23 +0200979 */
Willy Tarreau8fed9032014-07-03 17:02:46 +0200980struct stktable_key *smp_to_stkey(struct sample *smp, struct stktable *t)
Willy Tarreauf0b38bf2010-06-06 13:22:23 +0200981{
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200982 /* Convert sample. */
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200983 if (!sample_convert(smp, t->type))
Willy Tarreau7fc1c6e2012-04-26 11:03:17 +0200984 return NULL;
985
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200986 /* Fill static_table_key. */
987 switch (t->type) {
Emeric Brun485479d2010-09-23 18:02:19 +0200988
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200989 case SMP_T_IPV4:
Christopher Fauletca20d022017-08-29 15:30:31 +0200990 static_table_key.key = &smp->data.u.ipv4;
991 static_table_key.key_len = 4;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200992 break;
Emeric Brun485479d2010-09-23 18:02:19 +0200993
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200994 case SMP_T_IPV6:
Christopher Fauletca20d022017-08-29 15:30:31 +0200995 static_table_key.key = &smp->data.u.ipv6;
996 static_table_key.key_len = 16;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200997 break;
Emeric Brun485479d2010-09-23 18:02:19 +0200998
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200999 case SMP_T_SINT:
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001000 /* The stick table require a 32bit unsigned int, "sint" is a
1001 * signed 64 it, so we can convert it inplace.
1002 */
Willy Tarreau28c63c12019-10-23 06:21:05 +02001003 smp->data.u.sint = (unsigned int)smp->data.u.sint;
Christopher Fauletca20d022017-08-29 15:30:31 +02001004 static_table_key.key = &smp->data.u.sint;
1005 static_table_key.key_len = 4;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001006 break;
1007
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +02001008 case SMP_T_STR:
Willy Tarreauce6955e2016-08-09 11:59:12 +02001009 if (!smp_make_safe(smp))
1010 return NULL;
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001011 static_table_key.key = smp->data.u.str.area;
1012 static_table_key.key_len = smp->data.u.str.data;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001013 break;
Emeric Brun485479d2010-09-23 18:02:19 +02001014
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +02001015 case SMP_T_BIN:
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001016 if (smp->data.u.str.data < t->key_size) {
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001017 /* This type needs padding with 0. */
Willy Tarreauf65c6c02016-08-09 12:08:41 +02001018 if (!smp_make_rw(smp))
1019 return NULL;
1020
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001021 if (smp->data.u.str.size < t->key_size)
1022 if (!smp_dup(smp))
1023 return NULL;
1024 if (smp->data.u.str.size < t->key_size)
1025 return NULL;
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001026 memset(smp->data.u.str.area + smp->data.u.str.data, 0,
1027 t->key_size - smp->data.u.str.data);
1028 smp->data.u.str.data = t->key_size;
Emeric Brun485479d2010-09-23 18:02:19 +02001029 }
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001030 static_table_key.key = smp->data.u.str.area;
1031 static_table_key.key_len = smp->data.u.str.data;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001032 break;
Emeric Brun485479d2010-09-23 18:02:19 +02001033
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001034 default: /* impossible case. */
1035 return NULL;
Emeric Brun485479d2010-09-23 18:02:19 +02001036 }
1037
Christopher Fauletca20d022017-08-29 15:30:31 +02001038 return &static_table_key;
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001039}
1040
1041/*
Willy Tarreau8fed9032014-07-03 17:02:46 +02001042 * Process a fetch + format conversion as defined by the sample expression <expr>
1043 * on request or response considering the <opt> parameter. Returns either NULL if
1044 * no key could be extracted, or a pointer to the converted result stored in
1045 * static_table_key in format <table_type>. If <smp> is not NULL, it will be reset
1046 * and its flags will be initialized so that the caller gets a copy of the input
Willy Tarreau6bcb0a82014-07-30 08:56:35 +02001047 * sample, and knows why it was not accepted (eg: SMP_F_MAY_CHANGE is present
1048 * without SMP_OPT_FINAL). The output will be usable like this :
1049 *
1050 * return MAY_CHANGE FINAL Meaning for the sample
1051 * NULL 0 * Not present and will never be (eg: header)
1052 * NULL 1 0 Not present or unstable, could change (eg: req_len)
1053 * NULL 1 1 Not present, will not change anymore
1054 * smp 0 * Present and will not change (eg: header)
1055 * smp 1 0 not possible
1056 * smp 1 1 Present, last known value (eg: request length)
Willy Tarreau8fed9032014-07-03 17:02:46 +02001057 */
Willy Tarreau192252e2015-04-04 01:47:55 +02001058struct stktable_key *stktable_fetch_key(struct stktable *t, struct proxy *px, struct session *sess, struct stream *strm,
Willy Tarreau8fed9032014-07-03 17:02:46 +02001059 unsigned int opt, struct sample_expr *expr, struct sample *smp)
1060{
1061 if (smp)
1062 memset(smp, 0, sizeof(*smp));
1063
Willy Tarreau192252e2015-04-04 01:47:55 +02001064 smp = sample_process(px, sess, strm, opt, expr, smp);
Willy Tarreau8fed9032014-07-03 17:02:46 +02001065 if (!smp)
1066 return NULL;
1067
1068 if ((smp->flags & SMP_F_MAY_CHANGE) && !(opt & SMP_OPT_FINAL))
1069 return NULL; /* we can only use stable samples */
1070
1071 return smp_to_stkey(smp, t);
1072}
1073
1074/*
Willy Tarreau12785782012-04-27 21:37:17 +02001075 * Returns 1 if sample expression <expr> result can be converted to table key of
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001076 * type <table_type>, otherwise zero. Used in configuration check.
1077 */
Willy Tarreau12785782012-04-27 21:37:17 +02001078int stktable_compatible_sample(struct sample_expr *expr, unsigned long table_type)
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001079{
Thierry FOURNIERf73eb8f2013-11-27 15:30:55 +01001080 int out_type;
1081
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +02001082 if (table_type >= SMP_TYPES || !stktable_types[table_type].kw)
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001083 return 0;
1084
Thierry FOURNIERf73eb8f2013-11-27 15:30:55 +01001085 out_type = smp_expr_output_type(expr);
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001086
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001087 /* Convert sample. */
1088 if (!sample_casts[out_type][table_type])
Thierry FOURNIERf73eb8f2013-11-27 15:30:55 +01001089 return 0;
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001090
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001091 return 1;
1092}
Emeric Brun3bd697e2010-01-04 15:23:48 +01001093
Willy Tarreauedee1d62014-07-15 16:44:27 +02001094/* Extra data types processing : after the last one, some room may remain
1095 * before STKTABLE_DATA_TYPES that may be used to register extra data types
1096 * at run time.
1097 */
Willy Tarreau08d5f982010-06-06 13:34:54 +02001098struct stktable_data_type stktable_data_types[STKTABLE_DATA_TYPES] = {
Willy Tarreau3b9c6e02010-07-18 08:04:30 +02001099 [STKTABLE_DT_SERVER_ID] = { .name = "server_id", .std_type = STD_T_SINT },
Thierry FOURNIER3cf11112015-07-28 08:57:05 +02001100 [STKTABLE_DT_GPT0] = { .name = "gpt0", .std_type = STD_T_UINT },
Willy Tarreau3b9c6e02010-07-18 08:04:30 +02001101 [STKTABLE_DT_GPC0] = { .name = "gpc0", .std_type = STD_T_UINT },
Willy Tarreauba2ffd12013-05-29 15:54:14 +02001102 [STKTABLE_DT_GPC0_RATE] = { .name = "gpc0_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
Willy Tarreau3b9c6e02010-07-18 08:04:30 +02001103 [STKTABLE_DT_CONN_CNT] = { .name = "conn_cnt", .std_type = STD_T_UINT },
1104 [STKTABLE_DT_CONN_RATE] = { .name = "conn_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
1105 [STKTABLE_DT_CONN_CUR] = { .name = "conn_cur", .std_type = STD_T_UINT },
1106 [STKTABLE_DT_SESS_CNT] = { .name = "sess_cnt", .std_type = STD_T_UINT },
1107 [STKTABLE_DT_SESS_RATE] = { .name = "sess_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
1108 [STKTABLE_DT_HTTP_REQ_CNT] = { .name = "http_req_cnt", .std_type = STD_T_UINT },
1109 [STKTABLE_DT_HTTP_REQ_RATE] = { .name = "http_req_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
1110 [STKTABLE_DT_HTTP_ERR_CNT] = { .name = "http_err_cnt", .std_type = STD_T_UINT },
1111 [STKTABLE_DT_HTTP_ERR_RATE] = { .name = "http_err_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
1112 [STKTABLE_DT_BYTES_IN_CNT] = { .name = "bytes_in_cnt", .std_type = STD_T_ULL },
1113 [STKTABLE_DT_BYTES_IN_RATE] = { .name = "bytes_in_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
1114 [STKTABLE_DT_BYTES_OUT_CNT] = { .name = "bytes_out_cnt", .std_type = STD_T_ULL },
1115 [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 +01001116 [STKTABLE_DT_GPC1] = { .name = "gpc1", .std_type = STD_T_UINT },
1117 [STKTABLE_DT_GPC1_RATE] = { .name = "gpc1_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
Thayne McCombs92149f92020-11-20 01:28:26 -07001118 [STKTABLE_DT_SERVER_KEY] = { .name = "server_key", .std_type = STD_T_DICT },
Willy Tarreau826f3ab2021-02-10 12:07:15 +01001119 [STKTABLE_DT_HTTP_FAIL_CNT] = { .name = "http_fail_cnt", .std_type = STD_T_UINT },
1120 [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 +02001121};
1122
Willy Tarreauedee1d62014-07-15 16:44:27 +02001123/* Registers stick-table extra data type with index <idx>, name <name>, type
1124 * <std_type> and arg type <arg_type>. If the index is negative, the next free
1125 * index is automatically allocated. The allocated index is returned, or -1 if
1126 * no free index was found or <name> was already registered. The <name> is used
1127 * directly as a pointer, so if it's not stable, the caller must allocate it.
1128 */
1129int stktable_register_data_store(int idx, const char *name, int std_type, int arg_type)
1130{
1131 if (idx < 0) {
1132 for (idx = 0; idx < STKTABLE_DATA_TYPES; idx++) {
1133 if (!stktable_data_types[idx].name)
1134 break;
1135
1136 if (strcmp(stktable_data_types[idx].name, name) == 0)
1137 return -1;
1138 }
1139 }
1140
1141 if (idx >= STKTABLE_DATA_TYPES)
1142 return -1;
1143
1144 if (stktable_data_types[idx].name != NULL)
1145 return -1;
1146
1147 stktable_data_types[idx].name = name;
1148 stktable_data_types[idx].std_type = std_type;
1149 stktable_data_types[idx].arg_type = arg_type;
1150 return idx;
1151}
1152
Willy Tarreau08d5f982010-06-06 13:34:54 +02001153/*
1154 * Returns the data type number for the stktable_data_type whose name is <name>,
1155 * or <0 if not found.
1156 */
1157int stktable_get_data_type(char *name)
1158{
1159 int type;
1160
1161 for (type = 0; type < STKTABLE_DATA_TYPES; type++) {
Willy Tarreauedee1d62014-07-15 16:44:27 +02001162 if (!stktable_data_types[type].name)
1163 continue;
Willy Tarreau08d5f982010-06-06 13:34:54 +02001164 if (strcmp(name, stktable_data_types[type].name) == 0)
1165 return type;
1166 }
Thayne McCombs92149f92020-11-20 01:28:26 -07001167 /* For backwards compatibility */
1168 if (strcmp(name, "server_name") == 0)
1169 return STKTABLE_DT_SERVER_KEY;
Willy Tarreau08d5f982010-06-06 13:34:54 +02001170 return -1;
1171}
1172
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001173/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1174 * it up into this table. Returns true if found, false otherwise. The input
1175 * type is STR so that input samples are converted to string (since all types
1176 * can be converted to strings), then the function casts the string again into
1177 * the table's type. This is a double conversion, but in the future we might
1178 * support automatic input types to perform the cast on the fly.
1179 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001180static int sample_conv_in_table(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001181{
1182 struct stktable *t;
1183 struct stktable_key *key;
1184 struct stksess *ts;
1185
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001186 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001187
1188 key = smp_to_stkey(smp, t);
1189 if (!key)
1190 return 0;
1191
1192 ts = stktable_lookup_key(t, key);
1193
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001194 smp->data.type = SMP_T_BOOL;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001195 smp->data.u.sint = !!ts;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001196 smp->flags = SMP_F_VOL_TEST;
Willy Tarreau43e90352018-06-27 06:25:57 +02001197 stktable_release(t, ts);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001198 return 1;
1199}
1200
1201/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1202 * it up into this table. Returns the data rate received from clients in bytes/s
1203 * if the key is present in the table, otherwise zero, so that comparisons can
1204 * be easily performed. If the inspected parameter is not stored in the table,
1205 * <not found> is returned.
1206 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001207static int sample_conv_table_bytes_in_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001208{
1209 struct stktable *t;
1210 struct stktable_key *key;
1211 struct stksess *ts;
1212 void *ptr;
1213
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001214 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001215
1216 key = smp_to_stkey(smp, t);
1217 if (!key)
1218 return 0;
1219
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001220 ts = stktable_lookup_key(t, key);
1221
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001222 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001223 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001224 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001225
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001226 if (!ts) /* key not present */
1227 return 1;
1228
1229 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_IN_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001230 if (ptr)
1231 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, bytes_in_rate),
1232 t->data_arg[STKTABLE_DT_BYTES_IN_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001233
Daniel Corbett3e60b112018-05-27 09:47:12 -04001234 stktable_release(t, ts);
1235 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001236}
1237
1238/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1239 * it up into this table. Returns the cumulated number of connections for the key
1240 * if the key is present in the table, otherwise zero, so that comparisons can
1241 * be easily performed. If the inspected parameter is not stored in the table,
1242 * <not found> is returned.
1243 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001244static int sample_conv_table_conn_cnt(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001245{
1246 struct stktable *t;
1247 struct stktable_key *key;
1248 struct stksess *ts;
1249 void *ptr;
1250
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001251 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001252
1253 key = smp_to_stkey(smp, t);
1254 if (!key)
1255 return 0;
1256
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001257 ts = stktable_lookup_key(t, key);
1258
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001259 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001260 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001261 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001262
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001263 if (!ts) /* key not present */
1264 return 1;
1265
1266 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_CONN_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001267 if (ptr)
1268 smp->data.u.sint = stktable_data_cast(ptr, conn_cnt);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001269
Daniel Corbett3e60b112018-05-27 09:47:12 -04001270 stktable_release(t, ts);
1271 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001272}
1273
1274/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1275 * it up into this table. Returns the number of concurrent connections for the
1276 * key if the key is present in the table, otherwise zero, so that comparisons
1277 * can be easily performed. If the inspected parameter is not stored in the
1278 * table, <not found> is returned.
1279 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001280static int sample_conv_table_conn_cur(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001281{
1282 struct stktable *t;
1283 struct stktable_key *key;
1284 struct stksess *ts;
1285 void *ptr;
1286
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001287 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001288
1289 key = smp_to_stkey(smp, t);
1290 if (!key)
1291 return 0;
1292
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001293 ts = stktable_lookup_key(t, key);
1294
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001295 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001296 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001297 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001298
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001299 if (!ts) /* key not present */
1300 return 1;
1301
1302 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_CONN_CUR);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001303 if (ptr)
1304 smp->data.u.sint = stktable_data_cast(ptr, conn_cur);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001305
Daniel Corbett3e60b112018-05-27 09:47:12 -04001306 stktable_release(t, ts);
1307 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001308}
1309
1310/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1311 * it up into this table. Returns the rate of incoming connections from the key
1312 * if the key is present in the table, otherwise zero, so that comparisons can
1313 * be easily performed. If the inspected parameter is not stored in the table,
1314 * <not found> is returned.
1315 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001316static int sample_conv_table_conn_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001317{
1318 struct stktable *t;
1319 struct stktable_key *key;
1320 struct stksess *ts;
1321 void *ptr;
1322
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001323 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001324
1325 key = smp_to_stkey(smp, t);
1326 if (!key)
1327 return 0;
1328
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001329 ts = stktable_lookup_key(t, key);
1330
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001331 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001332 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001333 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001334
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001335 if (!ts) /* key not present */
1336 return 1;
1337
1338 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_CONN_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001339 if (ptr)
1340 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, conn_rate),
1341 t->data_arg[STKTABLE_DT_CONN_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001342
Daniel Corbett3e60b112018-05-27 09:47:12 -04001343 stktable_release(t, ts);
1344 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001345}
1346
1347/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1348 * it up into this table. Returns the data rate sent to clients in bytes/s
1349 * if the key is present in the table, otherwise zero, so that comparisons can
1350 * be easily performed. If the inspected parameter is not stored in the table,
1351 * <not found> is returned.
1352 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001353static int sample_conv_table_bytes_out_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001354{
1355 struct stktable *t;
1356 struct stktable_key *key;
1357 struct stksess *ts;
1358 void *ptr;
1359
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001360 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001361
1362 key = smp_to_stkey(smp, t);
1363 if (!key)
1364 return 0;
1365
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001366 ts = stktable_lookup_key(t, key);
1367
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001368 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001369 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001370 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001371
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001372 if (!ts) /* key not present */
1373 return 1;
1374
1375 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_OUT_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001376 if (ptr)
1377 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, bytes_out_rate),
1378 t->data_arg[STKTABLE_DT_BYTES_OUT_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001379
Daniel Corbett3e60b112018-05-27 09:47:12 -04001380 stktable_release(t, ts);
1381 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001382}
1383
1384/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001385 * it up into this table. Returns the value of the GPT0 tag for the key
1386 * if the key is present in the table, otherwise false, so that comparisons can
1387 * be easily performed. If the inspected parameter is not stored in the table,
1388 * <not found> is returned.
1389 */
1390static int sample_conv_table_gpt0(const struct arg *arg_p, struct sample *smp, void *private)
1391{
1392 struct stktable *t;
1393 struct stktable_key *key;
1394 struct stksess *ts;
1395 void *ptr;
1396
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001397 t = arg_p[0].data.t;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001398
1399 key = smp_to_stkey(smp, t);
1400 if (!key)
1401 return 0;
1402
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001403 ts = stktable_lookup_key(t, key);
1404
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001405 smp->flags = SMP_F_VOL_TEST;
1406 smp->data.type = SMP_T_SINT;
1407 smp->data.u.sint = 0;
1408
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001409 if (!ts) /* key not present */
1410 return 1;
1411
1412 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPT0);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001413 if (ptr)
1414 smp->data.u.sint = stktable_data_cast(ptr, gpt0);
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001415
Daniel Corbett3e60b112018-05-27 09:47:12 -04001416 stktable_release(t, ts);
1417 return !!ptr;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001418}
1419
1420/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001421 * it up into this table. Returns the value of the GPC0 counter for the key
1422 * if the key is present in the table, otherwise zero, so that comparisons can
1423 * be easily performed. If the inspected parameter is not stored in the table,
1424 * <not found> is returned.
1425 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001426static int sample_conv_table_gpc0(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001427{
1428 struct stktable *t;
1429 struct stktable_key *key;
1430 struct stksess *ts;
1431 void *ptr;
1432
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001433 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001434
1435 key = smp_to_stkey(smp, t);
1436 if (!key)
1437 return 0;
1438
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001439 ts = stktable_lookup_key(t, key);
1440
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001441 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001442 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001443 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001444
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001445 if (!ts) /* key not present */
1446 return 1;
1447
1448 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPC0);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001449 if (ptr)
1450 smp->data.u.sint = stktable_data_cast(ptr, gpc0);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001451
Daniel Corbett3e60b112018-05-27 09:47:12 -04001452 stktable_release(t, ts);
1453 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001454}
1455
1456/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1457 * it up into this table. Returns the event rate of the GPC0 counter for the key
1458 * if the key is present in the table, otherwise zero, so that comparisons can
1459 * be easily performed. If the inspected parameter is not stored in the table,
1460 * <not found> is returned.
1461 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001462static int sample_conv_table_gpc0_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001463{
1464 struct stktable *t;
1465 struct stktable_key *key;
1466 struct stksess *ts;
1467 void *ptr;
1468
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001469 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001470
1471 key = smp_to_stkey(smp, t);
1472 if (!key)
1473 return 0;
1474
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001475 ts = stktable_lookup_key(t, key);
1476
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001477 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001478 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001479 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001480
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001481 if (!ts) /* key not present */
1482 return 1;
1483
1484 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPC0_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001485 if (ptr)
1486 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, gpc0_rate),
1487 t->data_arg[STKTABLE_DT_GPC0_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001488
Daniel Corbett3e60b112018-05-27 09:47:12 -04001489 stktable_release(t, ts);
1490 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001491}
1492
1493/* 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 +01001494 * it up into this table. Returns the value of the GPC1 counter for the key
1495 * if the key is present in the table, otherwise zero, so that comparisons can
1496 * be easily performed. If the inspected parameter is not stored in the table,
1497 * <not found> is returned.
1498 */
1499static int sample_conv_table_gpc1(const struct arg *arg_p, struct sample *smp, void *private)
1500{
1501 struct stktable *t;
1502 struct stktable_key *key;
1503 struct stksess *ts;
1504 void *ptr;
1505
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001506 t = arg_p[0].data.t;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001507
1508 key = smp_to_stkey(smp, t);
1509 if (!key)
1510 return 0;
1511
1512 ts = stktable_lookup_key(t, key);
1513
1514 smp->flags = SMP_F_VOL_TEST;
1515 smp->data.type = SMP_T_SINT;
1516 smp->data.u.sint = 0;
1517
1518 if (!ts) /* key not present */
1519 return 1;
1520
1521 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPC1);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001522 if (ptr)
1523 smp->data.u.sint = stktable_data_cast(ptr, gpc1);
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001524
Daniel Corbett3e60b112018-05-27 09:47:12 -04001525 stktable_release(t, ts);
1526 return !!ptr;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001527}
1528
1529/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1530 * it up into this table. Returns the event rate of the GPC1 counter for the key
1531 * if the key is present in the table, otherwise zero, so that comparisons can
1532 * be easily performed. If the inspected parameter is not stored in the table,
1533 * <not found> is returned.
1534 */
1535static int sample_conv_table_gpc1_rate(const struct arg *arg_p, struct sample *smp, void *private)
1536{
1537 struct stktable *t;
1538 struct stktable_key *key;
1539 struct stksess *ts;
1540 void *ptr;
1541
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001542 t = arg_p[0].data.t;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001543
1544 key = smp_to_stkey(smp, t);
1545 if (!key)
1546 return 0;
1547
1548 ts = stktable_lookup_key(t, key);
1549
1550 smp->flags = SMP_F_VOL_TEST;
1551 smp->data.type = SMP_T_SINT;
1552 smp->data.u.sint = 0;
1553
1554 if (!ts) /* key not present */
1555 return 1;
1556
1557 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPC1_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001558 if (ptr)
1559 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, gpc1_rate),
1560 t->data_arg[STKTABLE_DT_GPC1_RATE].u);
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001561
Daniel Corbett3e60b112018-05-27 09:47:12 -04001562 stktable_release(t, ts);
1563 return !!ptr;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001564}
1565
1566/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001567 * it up into this table. Returns the cumulated number of HTTP request errors
1568 * for the key if the key is present in the table, otherwise zero, so that
1569 * comparisons can be easily performed. If the inspected parameter is not stored
1570 * in the table, <not found> is returned.
1571 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001572static int sample_conv_table_http_err_cnt(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001573{
1574 struct stktable *t;
1575 struct stktable_key *key;
1576 struct stksess *ts;
1577 void *ptr;
1578
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001579 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001580
1581 key = smp_to_stkey(smp, t);
1582 if (!key)
1583 return 0;
1584
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001585 ts = stktable_lookup_key(t, key);
1586
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001587 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001588 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001589 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001590
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001591 if (!ts) /* key not present */
1592 return 1;
1593
1594 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_ERR_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001595 if (ptr)
1596 smp->data.u.sint = stktable_data_cast(ptr, http_err_cnt);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001597
Daniel Corbett3e60b112018-05-27 09:47:12 -04001598 stktable_release(t, ts);
1599 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001600}
1601
1602/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1603 * it up into this table. Returns the HTTP request error rate the key
1604 * if the key is present in the table, otherwise zero, so that comparisons can
1605 * be easily performed. If the inspected parameter is not stored in the table,
1606 * <not found> is returned.
1607 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001608static int sample_conv_table_http_err_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001609{
1610 struct stktable *t;
1611 struct stktable_key *key;
1612 struct stksess *ts;
1613 void *ptr;
1614
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001615 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001616
1617 key = smp_to_stkey(smp, t);
1618 if (!key)
1619 return 0;
1620
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001621 ts = stktable_lookup_key(t, key);
1622
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001623 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001624 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001625 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001626
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001627 if (!ts) /* key not present */
1628 return 1;
1629
1630 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_ERR_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001631 if (ptr)
1632 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, http_err_rate),
1633 t->data_arg[STKTABLE_DT_HTTP_ERR_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001634
Daniel Corbett3e60b112018-05-27 09:47:12 -04001635 stktable_release(t, ts);
1636 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001637}
1638
1639/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Willy Tarreau826f3ab2021-02-10 12:07:15 +01001640 * it up into this table. Returns the cumulated number of HTTP response failures
1641 * for the key if the key is present in the table, otherwise zero, so that
1642 * comparisons can be easily performed. If the inspected parameter is not stored
1643 * in the table, <not found> is returned.
1644 */
1645static int sample_conv_table_http_fail_cnt(const struct arg *arg_p, struct sample *smp, void *private)
1646{
1647 struct stktable *t;
1648 struct stktable_key *key;
1649 struct stksess *ts;
1650 void *ptr;
1651
1652 t = arg_p[0].data.t;
1653
1654 key = smp_to_stkey(smp, t);
1655 if (!key)
1656 return 0;
1657
1658 ts = stktable_lookup_key(t, key);
1659
1660 smp->flags = SMP_F_VOL_TEST;
1661 smp->data.type = SMP_T_SINT;
1662 smp->data.u.sint = 0;
1663
1664 if (!ts) /* key not present */
1665 return 1;
1666
1667 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_FAIL_CNT);
1668 if (ptr)
1669 smp->data.u.sint = stktable_data_cast(ptr, http_fail_cnt);
1670
1671 stktable_release(t, ts);
1672 return !!ptr;
1673}
1674
1675/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1676 * it up into this table. Returns the HTTP response failure rate for the key
1677 * if the key is present in the table, otherwise zero, so that comparisons can
1678 * be easily performed. If the inspected parameter is not stored in the table,
1679 * <not found> is returned.
1680 */
1681static int sample_conv_table_http_fail_rate(const struct arg *arg_p, struct sample *smp, void *private)
1682{
1683 struct stktable *t;
1684 struct stktable_key *key;
1685 struct stksess *ts;
1686 void *ptr;
1687
1688 t = arg_p[0].data.t;
1689
1690 key = smp_to_stkey(smp, t);
1691 if (!key)
1692 return 0;
1693
1694 ts = stktable_lookup_key(t, key);
1695
1696 smp->flags = SMP_F_VOL_TEST;
1697 smp->data.type = SMP_T_SINT;
1698 smp->data.u.sint = 0;
1699
1700 if (!ts) /* key not present */
1701 return 1;
1702
1703 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_FAIL_RATE);
1704 if (ptr)
1705 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, http_fail_rate),
1706 t->data_arg[STKTABLE_DT_HTTP_FAIL_RATE].u);
1707
1708 stktable_release(t, ts);
1709 return !!ptr;
1710}
1711
1712/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001713 * it up into this table. Returns the cumulated number of HTTP request for the
1714 * key if the key is present in the table, otherwise zero, so that comparisons
1715 * can be easily performed. If the inspected parameter is not stored in the
1716 * table, <not found> is returned.
1717 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001718static int sample_conv_table_http_req_cnt(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001719{
1720 struct stktable *t;
1721 struct stktable_key *key;
1722 struct stksess *ts;
1723 void *ptr;
1724
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001725 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001726
1727 key = smp_to_stkey(smp, t);
1728 if (!key)
1729 return 0;
1730
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001731 ts = stktable_lookup_key(t, key);
1732
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001733 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001734 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001735 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001736
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001737 if (!ts) /* key not present */
1738 return 1;
1739
1740 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_REQ_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001741 if (ptr)
1742 smp->data.u.sint = stktable_data_cast(ptr, http_req_cnt);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001743
Daniel Corbett3e60b112018-05-27 09:47:12 -04001744 stktable_release(t, ts);
1745 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001746}
1747
1748/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1749 * it up into this table. Returns the HTTP request rate the key if the key is
1750 * present in the table, otherwise zero, so that comparisons can be easily
1751 * performed. If the inspected parameter is not stored in the table, <not found>
1752 * is returned.
1753 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001754static int sample_conv_table_http_req_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001755{
1756 struct stktable *t;
1757 struct stktable_key *key;
1758 struct stksess *ts;
1759 void *ptr;
1760
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001761 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001762
1763 key = smp_to_stkey(smp, t);
1764 if (!key)
1765 return 0;
1766
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001767 ts = stktable_lookup_key(t, key);
1768
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001769 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001770 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001771 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001772
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001773 if (!ts) /* key not present */
1774 return 1;
1775
1776 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_REQ_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001777 if (ptr)
1778 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, http_req_rate),
1779 t->data_arg[STKTABLE_DT_HTTP_REQ_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001780
Daniel Corbett3e60b112018-05-27 09:47:12 -04001781 stktable_release(t, ts);
1782 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001783}
1784
1785/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1786 * it up into this table. Returns the volume of datareceived from clients in kbytes
1787 * if the key is present in the table, otherwise zero, so that comparisons can
1788 * be easily performed. If the inspected parameter is not stored in the table,
1789 * <not found> is returned.
1790 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001791static int sample_conv_table_kbytes_in(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001792{
1793 struct stktable *t;
1794 struct stktable_key *key;
1795 struct stksess *ts;
1796 void *ptr;
1797
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001798 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001799
1800 key = smp_to_stkey(smp, t);
1801 if (!key)
1802 return 0;
1803
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001804 ts = stktable_lookup_key(t, key);
1805
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001806 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001807 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001808 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001809
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001810 if (!ts) /* key not present */
1811 return 1;
1812
1813 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_IN_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001814 if (ptr)
1815 smp->data.u.sint = stktable_data_cast(ptr, bytes_in_cnt) >> 10;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001816
Daniel Corbett3e60b112018-05-27 09:47:12 -04001817 stktable_release(t, ts);
1818 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001819}
1820
1821/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1822 * it up into this table. Returns the volume of data sent to clients in kbytes
1823 * if the key is present in the table, otherwise zero, so that comparisons can
1824 * be easily performed. If the inspected parameter is not stored in the table,
1825 * <not found> is returned.
1826 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001827static int sample_conv_table_kbytes_out(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001828{
1829 struct stktable *t;
1830 struct stktable_key *key;
1831 struct stksess *ts;
1832 void *ptr;
1833
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001834 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001835
1836 key = smp_to_stkey(smp, t);
1837 if (!key)
1838 return 0;
1839
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001840 ts = stktable_lookup_key(t, key);
1841
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001842 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001843 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001844 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001845
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001846 if (!ts) /* key not present */
1847 return 1;
1848
1849 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_OUT_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001850 if (ptr)
1851 smp->data.u.sint = stktable_data_cast(ptr, bytes_out_cnt) >> 10;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001852
Daniel Corbett3e60b112018-05-27 09:47:12 -04001853 stktable_release(t, ts);
1854 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001855}
1856
1857/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1858 * it up into this table. Returns the server ID associated with the key if the
1859 * key is present in the table, otherwise zero, so that comparisons can be
1860 * easily performed. If the inspected parameter is not stored in the table,
1861 * <not found> is returned.
1862 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001863static int sample_conv_table_server_id(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001864{
1865 struct stktable *t;
1866 struct stktable_key *key;
1867 struct stksess *ts;
1868 void *ptr;
1869
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001870 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001871
1872 key = smp_to_stkey(smp, t);
1873 if (!key)
1874 return 0;
1875
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001876 ts = stktable_lookup_key(t, key);
1877
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001878 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001879 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001880 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001881
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001882 if (!ts) /* key not present */
1883 return 1;
1884
1885 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_SERVER_ID);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001886 if (ptr)
1887 smp->data.u.sint = stktable_data_cast(ptr, server_id);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001888
Daniel Corbett3e60b112018-05-27 09:47:12 -04001889 stktable_release(t, ts);
1890 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001891}
1892
1893/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1894 * it up into this table. Returns the cumulated number of sessions for the
1895 * key if the key is present in the table, otherwise zero, so that comparisons
1896 * can be easily performed. If the inspected parameter is not stored in the
1897 * table, <not found> is returned.
1898 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001899static int sample_conv_table_sess_cnt(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001900{
1901 struct stktable *t;
1902 struct stktable_key *key;
1903 struct stksess *ts;
1904 void *ptr;
1905
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001906 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001907
1908 key = smp_to_stkey(smp, t);
1909 if (!key)
1910 return 0;
1911
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001912 ts = stktable_lookup_key(t, key);
1913
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001914 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001915 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001916 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001917
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001918 if (!ts) /* key not present */
1919 return 1;
1920
1921 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_SESS_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001922 if (ptr)
1923 smp->data.u.sint = stktable_data_cast(ptr, sess_cnt);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001924
Daniel Corbett3e60b112018-05-27 09:47:12 -04001925 stktable_release(t, ts);
1926 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001927}
1928
1929/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1930 * it up into this table. Returns the session rate the key if the key is
1931 * present in the table, otherwise zero, so that comparisons can be easily
1932 * performed. If the inspected parameter is not stored in the table, <not found>
1933 * is returned.
1934 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001935static int sample_conv_table_sess_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001936{
1937 struct stktable *t;
1938 struct stktable_key *key;
1939 struct stksess *ts;
1940 void *ptr;
1941
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001942 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001943
1944 key = smp_to_stkey(smp, t);
1945 if (!key)
1946 return 0;
1947
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001948 ts = stktable_lookup_key(t, key);
1949
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001950 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001951 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001952 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001953
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001954 if (!ts) /* key not present */
1955 return 1;
1956
1957 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_SESS_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001958 if (ptr)
1959 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, sess_rate),
1960 t->data_arg[STKTABLE_DT_SESS_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001961
Daniel Corbett3e60b112018-05-27 09:47:12 -04001962 stktable_release(t, ts);
1963 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001964}
1965
1966/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1967 * it up into this table. Returns the amount of concurrent connections tracking
1968 * the same key if the key is present in the table, otherwise zero, so that
1969 * comparisons can be easily performed. If the inspected parameter is not
1970 * stored in the table, <not found> is returned.
1971 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001972static int sample_conv_table_trackers(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001973{
1974 struct stktable *t;
1975 struct stktable_key *key;
1976 struct stksess *ts;
1977
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001978 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001979
1980 key = smp_to_stkey(smp, t);
1981 if (!key)
1982 return 0;
1983
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001984 ts = stktable_lookup_key(t, key);
1985
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001986 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001987 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001988 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001989
Tim Duesterhus65189c12018-06-26 15:57:29 +02001990 if (!ts)
1991 return 1;
1992
1993 smp->data.u.sint = ts->ref_cnt;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001994
Daniel Corbett3e60b112018-05-27 09:47:12 -04001995 stktable_release(t, ts);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001996 return 1;
1997}
1998
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001999/* Always returns 1. */
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002000static enum act_return action_inc_gpc0(struct act_rule *rule, struct proxy *px,
Willy Tarreau658b85b2015-09-27 10:00:49 +02002001 struct session *sess, struct stream *s, int flags)
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002002{
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002003 struct stksess *ts;
2004 struct stkctr *stkctr;
2005
2006 /* Extract the stksess, return OK if no stksess available. */
2007 if (s)
2008 stkctr = &s->stkctr[rule->arg.gpc.sc];
2009 else
2010 stkctr = &sess->stkctr[rule->arg.gpc.sc];
Willy Tarreau79c1e912016-01-25 14:54:45 +01002011
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002012 ts = stkctr_entry(stkctr);
Willy Tarreau79c1e912016-01-25 14:54:45 +01002013 if (ts) {
2014 void *ptr1, *ptr2;
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002015
Willy Tarreau79c1e912016-01-25 14:54:45 +01002016 /* First, update gpc0_rate if it's tracked. Second, update its gpc0 if tracked. */
2017 ptr1 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC0_RATE);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002018 ptr2 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC0);
2019 if (ptr1 || ptr2) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002020 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002021
2022 if (ptr1)
2023 update_freq_ctr_period(&stktable_data_cast(ptr1, gpc0_rate),
Willy Tarreau79c1e912016-01-25 14:54:45 +01002024 stkctr->table->data_arg[STKTABLE_DT_GPC0_RATE].u, 1);
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002025
Emeric Brun819fc6f2017-06-13 19:37:32 +02002026 if (ptr2)
2027 stktable_data_cast(ptr2, gpc0)++;
Willy Tarreau79c1e912016-01-25 14:54:45 +01002028
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002029 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002030
2031 /* If data was modified, we need to touch to re-schedule sync */
2032 stktable_touch_local(stkctr->table, ts, 0);
2033 }
Willy Tarreau79c1e912016-01-25 14:54:45 +01002034 }
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002035 return ACT_RET_CONT;
2036}
2037
2038/* This function is a common parser for using variables. It understands
2039 * the formats:
2040 *
2041 * sc-inc-gpc0(<stick-table ID>)
2042 *
2043 * It returns 0 if fails and <err> is filled with an error message. Otherwise,
2044 * it returns 1 and the variable <expr> is filled with the pointer to the
2045 * expression to execute.
2046 */
2047static enum act_parse_ret parse_inc_gpc0(const char **args, int *arg, struct proxy *px,
2048 struct act_rule *rule, char **err)
2049{
2050 const char *cmd_name = args[*arg-1];
2051 char *error;
2052
2053 cmd_name += strlen("sc-inc-gpc0");
2054 if (*cmd_name == '\0') {
2055 /* default stick table id. */
2056 rule->arg.gpc.sc = 0;
2057 } else {
2058 /* parse the stick table id. */
2059 if (*cmd_name != '(') {
2060 memprintf(err, "invalid stick table track ID. Expects %s(<Track ID>)", args[*arg-1]);
2061 return ACT_RET_PRS_ERR;
2062 }
2063 cmd_name++; /* jump the '(' */
2064 rule->arg.gpc.sc = strtol(cmd_name, &error, 10); /* Convert stick table id. */
2065 if (*error != ')') {
2066 memprintf(err, "invalid stick table track ID. Expects %s(<Track ID>)", args[*arg-1]);
2067 return ACT_RET_PRS_ERR;
2068 }
2069
Christopher Faulet28436e22019-12-18 10:25:46 +01002070 if (rule->arg.gpc.sc >= MAX_SESS_STKCTR) {
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002071 memprintf(err, "invalid stick table track ID. The max allowed ID is %d",
Christopher Faulet28436e22019-12-18 10:25:46 +01002072 MAX_SESS_STKCTR-1);
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002073 return ACT_RET_PRS_ERR;
2074 }
2075 }
Thierry FOURNIER42148732015-09-02 17:17:33 +02002076 rule->action = ACT_CUSTOM;
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02002077 rule->action_ptr = action_inc_gpc0;
2078 return ACT_RET_PRS_OK;
2079}
2080
2081/* Always returns 1. */
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002082static enum act_return action_inc_gpc1(struct act_rule *rule, struct proxy *px,
2083 struct session *sess, struct stream *s, int flags)
2084{
2085 struct stksess *ts;
2086 struct stkctr *stkctr;
2087
2088 /* Extract the stksess, return OK if no stksess available. */
2089 if (s)
2090 stkctr = &s->stkctr[rule->arg.gpc.sc];
2091 else
2092 stkctr = &sess->stkctr[rule->arg.gpc.sc];
2093
2094 ts = stkctr_entry(stkctr);
2095 if (ts) {
2096 void *ptr1, *ptr2;
2097
2098 /* First, update gpc1_rate if it's tracked. Second, update its gpc1 if tracked. */
2099 ptr1 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC1_RATE);
2100 ptr2 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC1);
2101 if (ptr1 || ptr2) {
2102 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
2103
2104 if (ptr1)
2105 update_freq_ctr_period(&stktable_data_cast(ptr1, gpc1_rate),
2106 stkctr->table->data_arg[STKTABLE_DT_GPC1_RATE].u, 1);
2107
2108 if (ptr2)
2109 stktable_data_cast(ptr2, gpc1)++;
2110
2111 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
2112
2113 /* If data was modified, we need to touch to re-schedule sync */
2114 stktable_touch_local(stkctr->table, ts, 0);
2115 }
2116 }
2117 return ACT_RET_CONT;
2118}
2119
2120/* This function is a common parser for using variables. It understands
2121 * the formats:
2122 *
2123 * sc-inc-gpc1(<stick-table ID>)
2124 *
2125 * It returns 0 if fails and <err> is filled with an error message. Otherwise,
2126 * it returns 1 and the variable <expr> is filled with the pointer to the
2127 * expression to execute.
2128 */
2129static enum act_parse_ret parse_inc_gpc1(const char **args, int *arg, struct proxy *px,
2130 struct act_rule *rule, char **err)
2131{
2132 const char *cmd_name = args[*arg-1];
2133 char *error;
2134
2135 cmd_name += strlen("sc-inc-gpc1");
2136 if (*cmd_name == '\0') {
2137 /* default stick table id. */
2138 rule->arg.gpc.sc = 0;
2139 } else {
2140 /* parse the stick table id. */
2141 if (*cmd_name != '(') {
2142 memprintf(err, "invalid stick table track ID. Expects %s(<Track ID>)", args[*arg-1]);
2143 return ACT_RET_PRS_ERR;
2144 }
2145 cmd_name++; /* jump the '(' */
2146 rule->arg.gpc.sc = strtol(cmd_name, &error, 10); /* Convert stick table id. */
2147 if (*error != ')') {
2148 memprintf(err, "invalid stick table track ID. Expects %s(<Track ID>)", args[*arg-1]);
2149 return ACT_RET_PRS_ERR;
2150 }
2151
Christopher Faulet28436e22019-12-18 10:25:46 +01002152 if (rule->arg.gpc.sc >= MAX_SESS_STKCTR) {
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002153 memprintf(err, "invalid stick table track ID. The max allowed ID is %d",
Christopher Faulet28436e22019-12-18 10:25:46 +01002154 MAX_SESS_STKCTR-1);
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002155 return ACT_RET_PRS_ERR;
2156 }
2157 }
2158 rule->action = ACT_CUSTOM;
2159 rule->action_ptr = action_inc_gpc1;
2160 return ACT_RET_PRS_OK;
2161}
2162
2163/* Always returns 1. */
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002164static enum act_return action_set_gpt0(struct act_rule *rule, struct proxy *px,
Willy Tarreau658b85b2015-09-27 10:00:49 +02002165 struct session *sess, struct stream *s, int flags)
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002166{
2167 void *ptr;
2168 struct stksess *ts;
2169 struct stkctr *stkctr;
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002170 unsigned int value = 0;
2171 struct sample *smp;
2172 int smp_opt_dir;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002173
2174 /* Extract the stksess, return OK if no stksess available. */
2175 if (s)
2176 stkctr = &s->stkctr[rule->arg.gpt.sc];
2177 else
2178 stkctr = &sess->stkctr[rule->arg.gpt.sc];
Willy Tarreau79c1e912016-01-25 14:54:45 +01002179
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002180 ts = stkctr_entry(stkctr);
2181 if (!ts)
2182 return ACT_RET_CONT;
2183
2184 /* Store the sample in the required sc, and ignore errors. */
2185 ptr = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPT0);
Willy Tarreau79c1e912016-01-25 14:54:45 +01002186 if (ptr) {
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002187 if (!rule->arg.gpt.expr)
2188 value = (unsigned int)(rule->arg.gpt.value);
2189 else {
2190 switch (rule->from) {
2191 case ACT_F_TCP_REQ_SES: smp_opt_dir = SMP_OPT_DIR_REQ; break;
2192 case ACT_F_TCP_REQ_CNT: smp_opt_dir = SMP_OPT_DIR_REQ; break;
2193 case ACT_F_TCP_RES_CNT: smp_opt_dir = SMP_OPT_DIR_RES; break;
2194 case ACT_F_HTTP_REQ: smp_opt_dir = SMP_OPT_DIR_REQ; break;
2195 case ACT_F_HTTP_RES: smp_opt_dir = SMP_OPT_DIR_RES; break;
2196 default:
2197 send_log(px, LOG_ERR, "stick table: internal error while setting gpt0.");
2198 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))
2199 ha_alert("stick table: internal error while executing setting gpt0.\n");
2200 return ACT_RET_CONT;
2201 }
2202
2203 /* Fetch and cast the expression. */
2204 smp = sample_fetch_as_type(px, sess, s, smp_opt_dir|SMP_OPT_FINAL, rule->arg.gpt.expr, SMP_T_SINT);
2205 if (!smp) {
2206 send_log(px, LOG_WARNING, "stick table: invalid expression or data type while setting gpt0.");
2207 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))
2208 ha_alert("stick table: invalid expression or data type while setting gpt0.\n");
2209 return ACT_RET_CONT;
2210 }
2211 value = (unsigned int)(smp->data.u.sint);
2212 }
2213
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002214 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002215
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002216 stktable_data_cast(ptr, gpt0) = value;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002217
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002218 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002219
2220 stktable_touch_local(stkctr->table, ts, 0);
Willy Tarreau79c1e912016-01-25 14:54:45 +01002221 }
2222
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002223 return ACT_RET_CONT;
2224}
2225
2226/* This function is a common parser for using variables. It understands
2227 * the format:
2228 *
2229 * set-gpt0(<stick-table ID>) <expression>
2230 *
2231 * It returns 0 if fails and <err> is filled with an error message. Otherwise,
2232 * it returns 1 and the variable <expr> is filled with the pointer to the
2233 * expression to execute.
2234 */
2235static enum act_parse_ret parse_set_gpt0(const char **args, int *arg, struct proxy *px,
2236 struct act_rule *rule, char **err)
2237
2238
2239{
2240 const char *cmd_name = args[*arg-1];
2241 char *error;
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002242 int smp_val;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002243
2244 cmd_name += strlen("sc-set-gpt0");
2245 if (*cmd_name == '\0') {
2246 /* default stick table id. */
2247 rule->arg.gpt.sc = 0;
2248 } else {
2249 /* parse the stick table id. */
2250 if (*cmd_name != '(') {
2251 memprintf(err, "invalid stick table track ID '%s'. Expects sc-set-gpt0(<Track ID>)", args[*arg-1]);
2252 return ACT_RET_PRS_ERR;
2253 }
2254 cmd_name++; /* jump the '(' */
2255 rule->arg.gpt.sc = strtol(cmd_name, &error, 10); /* Convert stick table id. */
2256 if (*error != ')') {
2257 memprintf(err, "invalid stick table track ID '%s'. Expects sc-set-gpt0(<Track ID>)", args[*arg-1]);
2258 return ACT_RET_PRS_ERR;
2259 }
2260
Christopher Faulet28436e22019-12-18 10:25:46 +01002261 if (rule->arg.gpt.sc >= MAX_SESS_STKCTR) {
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002262 memprintf(err, "invalid stick table track ID '%s'. The max allowed ID is %d",
Christopher Faulet28436e22019-12-18 10:25:46 +01002263 args[*arg-1], MAX_SESS_STKCTR-1);
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002264 return ACT_RET_PRS_ERR;
2265 }
2266 }
2267
Willy Tarreauf1e1c912021-08-24 14:57:28 +02002268 /* value may be either an integer or an expression */
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002269 rule->arg.gpt.expr = NULL;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002270 rule->arg.gpt.value = strtol(args[*arg], &error, 10);
Willy Tarreauf1e1c912021-08-24 14:57:28 +02002271 if (*error == '\0') {
2272 /* valid integer, skip it */
2273 (*arg)++;
2274 } else {
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002275 rule->arg.gpt.expr = sample_parse_expr((char **)args, arg, px->conf.args.file,
Willy Tarreaue3b57bf2020-02-14 16:50:14 +01002276 px->conf.args.line, err, &px->conf.args, NULL);
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002277 if (!rule->arg.gpt.expr)
2278 return ACT_RET_PRS_ERR;
2279
2280 switch (rule->from) {
2281 case ACT_F_TCP_REQ_SES: smp_val = SMP_VAL_FE_SES_ACC; break;
2282 case ACT_F_TCP_REQ_CNT: smp_val = SMP_VAL_FE_REQ_CNT; break;
2283 case ACT_F_TCP_RES_CNT: smp_val = SMP_VAL_BE_RES_CNT; break;
2284 case ACT_F_HTTP_REQ: smp_val = SMP_VAL_FE_HRQ_HDR; break;
2285 case ACT_F_HTTP_RES: smp_val = SMP_VAL_BE_HRS_HDR; break;
2286 default:
2287 memprintf(err, "internal error, unexpected rule->from=%d, please report this bug!", rule->from);
2288 return ACT_RET_PRS_ERR;
2289 }
2290 if (!(rule->arg.gpt.expr->fetch->val & smp_val)) {
2291 memprintf(err, "fetch method '%s' extracts information from '%s', none of which is available here", args[*arg-1],
2292 sample_src_names(rule->arg.gpt.expr->fetch->use));
2293 free(rule->arg.gpt.expr);
2294 return ACT_RET_PRS_ERR;
2295 }
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002296 }
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002297
Thierry FOURNIER42148732015-09-02 17:17:33 +02002298 rule->action = ACT_CUSTOM;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002299 rule->action_ptr = action_set_gpt0;
2300
2301 return ACT_RET_PRS_OK;
2302}
2303
Willy Tarreau7d562212016-11-25 16:10:05 +01002304/* set temp integer to the number of used entries in the table pointed to by expr.
2305 * Accepts exactly 1 argument of type table.
2306 */
2307static int
2308smp_fetch_table_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
2309{
2310 smp->flags = SMP_F_VOL_TEST;
2311 smp->data.type = SMP_T_SINT;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002312 smp->data.u.sint = args->data.t->current;
Willy Tarreau7d562212016-11-25 16:10:05 +01002313 return 1;
2314}
2315
2316/* set temp integer to the number of free entries in the table pointed to by expr.
2317 * Accepts exactly 1 argument of type table.
2318 */
2319static int
2320smp_fetch_table_avl(const struct arg *args, struct sample *smp, const char *kw, void *private)
2321{
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002322 struct stktable *t;
Willy Tarreau7d562212016-11-25 16:10:05 +01002323
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002324 t = args->data.t;
Willy Tarreau7d562212016-11-25 16:10:05 +01002325 smp->flags = SMP_F_VOL_TEST;
2326 smp->data.type = SMP_T_SINT;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002327 smp->data.u.sint = t->size - t->current;
Willy Tarreau7d562212016-11-25 16:10:05 +01002328 return 1;
2329}
2330
2331/* Returns a pointer to a stkctr depending on the fetch keyword name.
2332 * It is designed to be called as sc[0-9]_* sc_* or src_* exclusively.
2333 * sc[0-9]_* will return a pointer to the respective field in the
2334 * stream <l4>. sc_* requires an UINT argument specifying the stick
2335 * counter number. src_* will fill a locally allocated structure with
2336 * the table and entry corresponding to what is specified with src_*.
2337 * NULL may be returned if the designated stkctr is not tracked. For
2338 * the sc_* and sc[0-9]_* forms, an optional table argument may be
2339 * passed. When present, the currently tracked key is then looked up
2340 * in the specified table instead of the current table. The purpose is
Ilya Shipitsin47d17182020-06-21 21:42:57 +05002341 * to be able to convert multiple values per key (eg: have gpc0 from
Willy Tarreau7d562212016-11-25 16:10:05 +01002342 * multiple tables). <strm> is allowed to be NULL, in which case only
2343 * the session will be consulted.
2344 */
2345struct stkctr *
Emeric Brun819fc6f2017-06-13 19:37:32 +02002346smp_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 +01002347{
Willy Tarreau7d562212016-11-25 16:10:05 +01002348 struct stkctr *stkptr;
2349 struct stksess *stksess;
2350 unsigned int num = kw[2] - '0';
2351 int arg = 0;
2352
2353 if (num == '_' - '0') {
2354 /* sc_* variant, args[0] = ctr# (mandatory) */
2355 num = args[arg++].data.sint;
Willy Tarreau7d562212016-11-25 16:10:05 +01002356 }
2357 else if (num > 9) { /* src_* variant, args[0] = table */
2358 struct stktable_key *key;
2359 struct connection *conn = objt_conn(sess->origin);
2360 struct sample smp;
2361
2362 if (!conn)
2363 return NULL;
2364
Joseph Herlant5662fa42018-11-15 13:43:28 -08002365 /* Fetch source address in a sample. */
Willy Tarreau7d562212016-11-25 16:10:05 +01002366 smp.px = NULL;
2367 smp.sess = sess;
2368 smp.strm = strm;
Amaury Denoyellec460c702021-05-12 10:17:47 +02002369 if (!smp_fetch_src || !smp_fetch_src(empty_arg_list, &smp, "src", NULL))
Willy Tarreau7d562212016-11-25 16:10:05 +01002370 return NULL;
2371
2372 /* Converts into key. */
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002373 key = smp_to_stkey(&smp, args->data.t);
Willy Tarreau7d562212016-11-25 16:10:05 +01002374 if (!key)
2375 return NULL;
2376
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002377 stkctr->table = args->data.t;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002378 stkctr_set_entry(stkctr, stktable_lookup_key(stkctr->table, key));
2379 return stkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002380 }
2381
2382 /* Here, <num> contains the counter number from 0 to 9 for
2383 * the sc[0-9]_ form, or even higher using sc_(num) if needed.
2384 * args[arg] is the first optional argument. We first lookup the
2385 * ctr form the stream, then from the session if it was not there.
Christopher Fauleta9fa88a2019-10-21 10:53:34 +02002386 * But we must be sure the counter does not exceed MAX_SESS_STKCTR.
Willy Tarreau7d562212016-11-25 16:10:05 +01002387 */
Christopher Fauleta9fa88a2019-10-21 10:53:34 +02002388 if (num >= MAX_SESS_STKCTR)
2389 return NULL;
Willy Tarreau7d562212016-11-25 16:10:05 +01002390
2391 if (strm)
2392 stkptr = &strm->stkctr[num];
2393 if (!strm || !stkctr_entry(stkptr)) {
2394 stkptr = &sess->stkctr[num];
2395 if (!stkctr_entry(stkptr))
2396 return NULL;
2397 }
2398
2399 stksess = stkctr_entry(stkptr);
2400 if (!stksess)
2401 return NULL;
2402
2403 if (unlikely(args[arg].type == ARGT_TAB)) {
2404 /* an alternate table was specified, let's look up the same key there */
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002405 stkctr->table = args[arg].data.t;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002406 stkctr_set_entry(stkctr, stktable_lookup(stkctr->table, stksess));
2407 return stkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002408 }
2409 return stkptr;
2410}
2411
2412/* same as smp_fetch_sc_stkctr() but dedicated to src_* and can create
2413 * the entry if it doesn't exist yet. This is needed for a few fetch
2414 * functions which need to create an entry, such as src_inc_gpc* and
2415 * src_clr_gpc*.
2416 */
2417struct stkctr *
Emeric Brun819fc6f2017-06-13 19:37:32 +02002418smp_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 +01002419{
Willy Tarreau7d562212016-11-25 16:10:05 +01002420 struct stktable_key *key;
2421 struct connection *conn = objt_conn(sess->origin);
2422 struct sample smp;
2423
2424 if (strncmp(kw, "src_", 4) != 0)
2425 return NULL;
2426
2427 if (!conn)
2428 return NULL;
2429
Joseph Herlant5662fa42018-11-15 13:43:28 -08002430 /* Fetch source address in a sample. */
Willy Tarreau7d562212016-11-25 16:10:05 +01002431 smp.px = NULL;
2432 smp.sess = sess;
2433 smp.strm = strm;
Amaury Denoyellec460c702021-05-12 10:17:47 +02002434 if (!smp_fetch_src || !smp_fetch_src(empty_arg_list, &smp, "src", NULL))
Willy Tarreau7d562212016-11-25 16:10:05 +01002435 return NULL;
2436
2437 /* Converts into key. */
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002438 key = smp_to_stkey(&smp, args->data.t);
Willy Tarreau7d562212016-11-25 16:10:05 +01002439 if (!key)
2440 return NULL;
2441
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002442 stkctr->table = args->data.t;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002443 stkctr_set_entry(stkctr, stktable_get_entry(stkctr->table, key));
2444 return stkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002445}
2446
2447/* set return a boolean indicating if the requested stream counter is
2448 * currently being tracked or not.
2449 * Supports being called as "sc[0-9]_tracked" only.
2450 */
2451static int
2452smp_fetch_sc_tracked(const struct arg *args, struct sample *smp, const char *kw, void *private)
2453{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002454 struct stkctr tmpstkctr;
2455 struct stkctr *stkctr;
2456
Willy Tarreau7d562212016-11-25 16:10:05 +01002457 smp->flags = SMP_F_VOL_TEST;
2458 smp->data.type = SMP_T_BOOL;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002459 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2460 smp->data.u.sint = !!stkctr;
2461
2462 /* release the ref count */
Dirkjan Bussinkff57f1b2018-09-14 14:31:22 +02002463 if (stkctr == &tmpstkctr)
Emeric Brun819fc6f2017-06-13 19:37:32 +02002464 stktable_release(stkctr->table, stkctr_entry(stkctr));
2465
Willy Tarreau7d562212016-11-25 16:10:05 +01002466 return 1;
2467}
2468
2469/* set <smp> to the General Purpose Flag 0 value from the stream's tracked
2470 * frontend counters or from the src.
2471 * Supports being called as "sc[0-9]_get_gpc0" or "src_get_gpt0" only. Value
2472 * zero is returned if the key is new.
2473 */
2474static int
2475smp_fetch_sc_get_gpt0(const struct arg *args, struct sample *smp, const char *kw, void *private)
2476{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002477 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002478 struct stkctr *stkctr;
2479
Emeric Brun819fc6f2017-06-13 19:37:32 +02002480 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002481 if (!stkctr)
2482 return 0;
2483
2484 smp->flags = SMP_F_VOL_TEST;
2485 smp->data.type = SMP_T_SINT;
2486 smp->data.u.sint = 0;
2487
Emeric Brun819fc6f2017-06-13 19:37:32 +02002488 if (stkctr_entry(stkctr)) {
2489 void *ptr;
2490
2491 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPT0);
2492 if (!ptr) {
2493 if (stkctr == &tmpstkctr)
2494 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002495 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002496 }
2497
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002498 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002499
Willy Tarreau7d562212016-11-25 16:10:05 +01002500 smp->data.u.sint = stktable_data_cast(ptr, gpt0);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002501
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002502 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002503
2504 if (stkctr == &tmpstkctr)
2505 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002506 }
2507 return 1;
2508}
2509
2510/* set <smp> to the General Purpose Counter 0 value from the stream's tracked
2511 * frontend counters or from the src.
2512 * Supports being called as "sc[0-9]_get_gpc0" or "src_get_gpc0" only. Value
2513 * zero is returned if the key is new.
2514 */
2515static int
2516smp_fetch_sc_get_gpc0(const struct arg *args, struct sample *smp, const char *kw, void *private)
2517{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002518 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002519 struct stkctr *stkctr;
2520
Emeric Brun819fc6f2017-06-13 19:37:32 +02002521 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002522 if (!stkctr)
2523 return 0;
2524
2525 smp->flags = SMP_F_VOL_TEST;
2526 smp->data.type = SMP_T_SINT;
2527 smp->data.u.sint = 0;
2528
2529 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002530 void *ptr;
2531
2532 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0);
2533 if (!ptr) {
2534 if (stkctr == &tmpstkctr)
2535 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002536 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002537 }
2538
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002539 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002540
Willy Tarreau7d562212016-11-25 16:10:05 +01002541 smp->data.u.sint = stktable_data_cast(ptr, gpc0);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002542
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002543 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002544
2545 if (stkctr == &tmpstkctr)
2546 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002547 }
2548 return 1;
2549}
2550
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002551/* set <smp> to the General Purpose Counter 1 value from the stream's tracked
2552 * frontend counters or from the src.
2553 * Supports being called as "sc[0-9]_get_gpc1" or "src_get_gpc1" only. Value
2554 * zero is returned if the key is new.
2555 */
2556static int
2557smp_fetch_sc_get_gpc1(const struct arg *args, struct sample *smp, const char *kw, void *private)
2558{
2559 struct stkctr tmpstkctr;
2560 struct stkctr *stkctr;
2561
2562 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2563 if (!stkctr)
2564 return 0;
2565
2566 smp->flags = SMP_F_VOL_TEST;
2567 smp->data.type = SMP_T_SINT;
2568 smp->data.u.sint = 0;
2569
2570 if (stkctr_entry(stkctr) != NULL) {
2571 void *ptr;
2572
2573 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1);
2574 if (!ptr) {
2575 if (stkctr == &tmpstkctr)
2576 stktable_release(stkctr->table, stkctr_entry(stkctr));
2577 return 0; /* parameter not stored */
2578 }
2579
2580 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2581
2582 smp->data.u.sint = stktable_data_cast(ptr, gpc1);
2583
2584 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2585
2586 if (stkctr == &tmpstkctr)
2587 stktable_release(stkctr->table, stkctr_entry(stkctr));
2588 }
2589 return 1;
2590}
2591
Willy Tarreau7d562212016-11-25 16:10:05 +01002592/* set <smp> to the General Purpose Counter 0's event rate from the stream's
2593 * tracked frontend counters or from the src.
2594 * Supports being called as "sc[0-9]_gpc0_rate" or "src_gpc0_rate" only.
2595 * Value zero is returned if the key is new.
2596 */
2597static int
2598smp_fetch_sc_gpc0_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
2599{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002600 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002601 struct stkctr *stkctr;
2602
Emeric Brun819fc6f2017-06-13 19:37:32 +02002603 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002604 if (!stkctr)
2605 return 0;
2606
2607 smp->flags = SMP_F_VOL_TEST;
2608 smp->data.type = SMP_T_SINT;
2609 smp->data.u.sint = 0;
2610 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002611 void *ptr;
2612
2613 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0_RATE);
2614 if (!ptr) {
2615 if (stkctr == &tmpstkctr)
2616 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002617 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002618 }
2619
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002620 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002621
Willy Tarreau7d562212016-11-25 16:10:05 +01002622 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, gpc0_rate),
2623 stkctr->table->data_arg[STKTABLE_DT_GPC0_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002624
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002625 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002626
2627 if (stkctr == &tmpstkctr)
2628 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002629 }
2630 return 1;
2631}
2632
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002633/* set <smp> to the General Purpose Counter 1's event rate from the stream's
2634 * tracked frontend counters or from the src.
2635 * Supports being called as "sc[0-9]_gpc1_rate" or "src_gpc1_rate" only.
2636 * Value zero is returned if the key is new.
2637 */
2638static int
2639smp_fetch_sc_gpc1_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
2640{
2641 struct stkctr tmpstkctr;
2642 struct stkctr *stkctr;
2643
2644 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2645 if (!stkctr)
2646 return 0;
2647
2648 smp->flags = SMP_F_VOL_TEST;
2649 smp->data.type = SMP_T_SINT;
2650 smp->data.u.sint = 0;
2651 if (stkctr_entry(stkctr) != NULL) {
2652 void *ptr;
2653
2654 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1_RATE);
2655 if (!ptr) {
2656 if (stkctr == &tmpstkctr)
2657 stktable_release(stkctr->table, stkctr_entry(stkctr));
2658 return 0; /* parameter not stored */
2659 }
2660
2661 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2662
2663 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, gpc1_rate),
2664 stkctr->table->data_arg[STKTABLE_DT_GPC1_RATE].u);
2665
2666 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2667
2668 if (stkctr == &tmpstkctr)
2669 stktable_release(stkctr->table, stkctr_entry(stkctr));
2670 }
2671 return 1;
2672}
2673
Willy Tarreau7d562212016-11-25 16:10:05 +01002674/* Increment the General Purpose Counter 0 value from the stream's tracked
2675 * frontend counters and return it into temp integer.
2676 * Supports being called as "sc[0-9]_inc_gpc0" or "src_inc_gpc0" only.
2677 */
2678static int
2679smp_fetch_sc_inc_gpc0(const struct arg *args, struct sample *smp, const char *kw, void *private)
2680{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002681 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002682 struct stkctr *stkctr;
2683
Emeric Brun819fc6f2017-06-13 19:37:32 +02002684 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002685 if (!stkctr)
2686 return 0;
2687
2688 smp->flags = SMP_F_VOL_TEST;
2689 smp->data.type = SMP_T_SINT;
2690 smp->data.u.sint = 0;
2691
Emeric Brun819fc6f2017-06-13 19:37:32 +02002692 if (!stkctr_entry(stkctr))
2693 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002694
2695 if (stkctr && stkctr_entry(stkctr)) {
2696 void *ptr1,*ptr2;
2697
Emeric Brun819fc6f2017-06-13 19:37:32 +02002698
Willy Tarreau7d562212016-11-25 16:10:05 +01002699 /* First, update gpc0_rate if it's tracked. Second, update its
2700 * gpc0 if tracked. Returns gpc0's value otherwise the curr_ctr.
2701 */
2702 ptr1 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0_RATE);
Willy Tarreau7d562212016-11-25 16:10:05 +01002703 ptr2 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002704 if (ptr1 || ptr2) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002705 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Willy Tarreau7d562212016-11-25 16:10:05 +01002706
Emeric Brun819fc6f2017-06-13 19:37:32 +02002707 if (ptr1) {
2708 update_freq_ctr_period(&stktable_data_cast(ptr1, gpc0_rate),
2709 stkctr->table->data_arg[STKTABLE_DT_GPC0_RATE].u, 1);
2710 smp->data.u.sint = (&stktable_data_cast(ptr1, gpc0_rate))->curr_ctr;
2711 }
2712
2713 if (ptr2)
2714 smp->data.u.sint = ++stktable_data_cast(ptr2, gpc0);
2715
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002716 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002717
2718 /* If data was modified, we need to touch to re-schedule sync */
2719 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
2720 }
2721 else if (stkctr == &tmpstkctr)
2722 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002723 }
2724 return 1;
2725}
2726
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002727/* Increment the General Purpose Counter 1 value from the stream's tracked
2728 * frontend counters and return it into temp integer.
2729 * Supports being called as "sc[0-9]_inc_gpc1" or "src_inc_gpc1" only.
2730 */
2731static int
2732smp_fetch_sc_inc_gpc1(const struct arg *args, struct sample *smp, const char *kw, void *private)
2733{
2734 struct stkctr tmpstkctr;
2735 struct stkctr *stkctr;
2736
2737 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2738 if (!stkctr)
2739 return 0;
2740
2741 smp->flags = SMP_F_VOL_TEST;
2742 smp->data.type = SMP_T_SINT;
2743 smp->data.u.sint = 0;
2744
2745 if (!stkctr_entry(stkctr))
2746 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2747
2748 if (stkctr && stkctr_entry(stkctr)) {
2749 void *ptr1,*ptr2;
2750
2751
2752 /* First, update gpc1_rate if it's tracked. Second, update its
2753 * gpc1 if tracked. Returns gpc1's value otherwise the curr_ctr.
2754 */
2755 ptr1 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1_RATE);
2756 ptr2 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1);
2757 if (ptr1 || ptr2) {
2758 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2759
2760 if (ptr1) {
2761 update_freq_ctr_period(&stktable_data_cast(ptr1, gpc1_rate),
2762 stkctr->table->data_arg[STKTABLE_DT_GPC1_RATE].u, 1);
2763 smp->data.u.sint = (&stktable_data_cast(ptr1, gpc1_rate))->curr_ctr;
2764 }
2765
2766 if (ptr2)
2767 smp->data.u.sint = ++stktable_data_cast(ptr2, gpc1);
2768
2769 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2770
2771 /* If data was modified, we need to touch to re-schedule sync */
2772 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
2773 }
2774 else if (stkctr == &tmpstkctr)
2775 stktable_release(stkctr->table, stkctr_entry(stkctr));
2776 }
2777 return 1;
2778}
2779
Willy Tarreau7d562212016-11-25 16:10:05 +01002780/* Clear the General Purpose Counter 0 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_gpc0" or "src_clr_gpc0" only.
2783 */
2784static int
2785smp_fetch_sc_clr_gpc0(const struct arg *args, struct sample *smp, const char *kw, void *private)
2786{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002787 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002788 struct stkctr *stkctr;
2789
Emeric Brun819fc6f2017-06-13 19:37:32 +02002790 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002791 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
Emeric Brun819fc6f2017-06-13 19:37:32 +02002798 if (!stkctr_entry(stkctr))
2799 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002800
Emeric Brun819fc6f2017-06-13 19:37:32 +02002801 if (stkctr && stkctr_entry(stkctr)) {
2802 void *ptr;
2803
2804 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0);
2805 if (!ptr) {
2806 if (stkctr == &tmpstkctr)
2807 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002808 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002809 }
2810
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002811 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002812
Willy Tarreau7d562212016-11-25 16:10:05 +01002813 smp->data.u.sint = stktable_data_cast(ptr, gpc0);
2814 stktable_data_cast(ptr, gpc0) = 0;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002815
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002816 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002817
Willy Tarreau7d562212016-11-25 16:10:05 +01002818 /* If data was modified, we need to touch to re-schedule sync */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002819 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
Willy Tarreau7d562212016-11-25 16:10:05 +01002820 }
2821 return 1;
2822}
2823
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002824/* Clear the General Purpose Counter 1 value from the stream's tracked
2825 * frontend counters and return its previous value into temp integer.
2826 * Supports being called as "sc[0-9]_clr_gpc1" or "src_clr_gpc1" only.
2827 */
2828static int
2829smp_fetch_sc_clr_gpc1(const struct arg *args, struct sample *smp, const char *kw, void *private)
2830{
2831 struct stkctr tmpstkctr;
2832 struct stkctr *stkctr;
2833
2834 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2835 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
2842 if (!stkctr_entry(stkctr))
2843 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2844
2845 if (stkctr && stkctr_entry(stkctr)) {
2846 void *ptr;
2847
2848 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1);
2849 if (!ptr) {
2850 if (stkctr == &tmpstkctr)
2851 stktable_release(stkctr->table, stkctr_entry(stkctr));
2852 return 0; /* parameter not stored */
2853 }
2854
2855 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2856
2857 smp->data.u.sint = stktable_data_cast(ptr, gpc1);
2858 stktable_data_cast(ptr, gpc1) = 0;
2859
2860 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2861
2862 /* If data was modified, we need to touch to re-schedule sync */
2863 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
2864 }
2865 return 1;
2866}
2867
Willy Tarreau7d562212016-11-25 16:10:05 +01002868/* set <smp> to the cumulated number of connections from the stream's tracked
2869 * frontend counters. Supports being called as "sc[0-9]_conn_cnt" or
2870 * "src_conn_cnt" only.
2871 */
2872static int
2873smp_fetch_sc_conn_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
2874{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002875 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002876 struct stkctr *stkctr;
2877
Emeric Brun819fc6f2017-06-13 19:37:32 +02002878 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002879 if (!stkctr)
2880 return 0;
2881
2882 smp->flags = SMP_F_VOL_TEST;
2883 smp->data.type = SMP_T_SINT;
2884 smp->data.u.sint = 0;
2885 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002886 void *ptr;
2887
2888 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_CONN_CNT);
2889 if (!ptr) {
2890 if (stkctr == &tmpstkctr)
2891 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002892 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002893 }
2894
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002895 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002896
Willy Tarreau7d562212016-11-25 16:10:05 +01002897 smp->data.u.sint = stktable_data_cast(ptr, conn_cnt);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002898
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002899 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002900
2901 if (stkctr == &tmpstkctr)
2902 stktable_release(stkctr->table, stkctr_entry(stkctr));
2903
2904
Willy Tarreau7d562212016-11-25 16:10:05 +01002905 }
2906 return 1;
2907}
2908
2909/* set <smp> to the connection rate from the stream's tracked frontend
2910 * counters. Supports being called as "sc[0-9]_conn_rate" or "src_conn_rate"
2911 * only.
2912 */
2913static int
2914smp_fetch_sc_conn_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
2915{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002916 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002917 struct stkctr *stkctr;
2918
Emeric Brun819fc6f2017-06-13 19:37:32 +02002919 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002920 if (!stkctr)
2921 return 0;
2922
2923 smp->flags = SMP_F_VOL_TEST;
2924 smp->data.type = SMP_T_SINT;
2925 smp->data.u.sint = 0;
2926 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002927 void *ptr;
2928
2929 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_CONN_RATE);
2930 if (!ptr) {
2931 if (stkctr == &tmpstkctr)
2932 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002933 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002934 }
2935
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002936 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002937
Willy Tarreau7d562212016-11-25 16:10:05 +01002938 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, conn_rate),
2939 stkctr->table->data_arg[STKTABLE_DT_CONN_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002940
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002941 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002942
2943 if (stkctr == &tmpstkctr)
2944 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002945 }
2946 return 1;
2947}
2948
2949/* set temp integer to the number of connections from the stream's source address
2950 * in the table pointed to by expr, after updating it.
2951 * Accepts exactly 1 argument of type table.
2952 */
2953static int
2954smp_fetch_src_updt_conn_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
2955{
2956 struct connection *conn = objt_conn(smp->sess->origin);
2957 struct stksess *ts;
2958 struct stktable_key *key;
2959 void *ptr;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002960 struct stktable *t;
Willy Tarreau7d562212016-11-25 16:10:05 +01002961
2962 if (!conn)
2963 return 0;
2964
Joseph Herlant5662fa42018-11-15 13:43:28 -08002965 /* Fetch source address in a sample. */
Amaury Denoyellec460c702021-05-12 10:17:47 +02002966 if (!smp_fetch_src || !smp_fetch_src(empty_arg_list, smp, "src", NULL))
Willy Tarreau7d562212016-11-25 16:10:05 +01002967 return 0;
2968
2969 /* Converts into key. */
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002970 key = smp_to_stkey(smp, args->data.t);
Willy Tarreau7d562212016-11-25 16:10:05 +01002971 if (!key)
2972 return 0;
2973
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002974 t = args->data.t;
Willy Tarreau7d562212016-11-25 16:10:05 +01002975
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002976 if ((ts = stktable_get_entry(t, key)) == NULL)
Willy Tarreau7d562212016-11-25 16:10:05 +01002977 /* entry does not exist and could not be created */
2978 return 0;
2979
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002980 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_CONN_CNT);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002981 if (!ptr) {
Willy Tarreau7d562212016-11-25 16:10:05 +01002982 return 0; /* parameter not stored in this table */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002983 }
Willy Tarreau7d562212016-11-25 16:10:05 +01002984
2985 smp->data.type = SMP_T_SINT;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002986
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002987 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002988
Willy Tarreau7d562212016-11-25 16:10:05 +01002989 smp->data.u.sint = ++stktable_data_cast(ptr, conn_cnt);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002990
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002991 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002992
Willy Tarreau7d562212016-11-25 16:10:05 +01002993 smp->flags = SMP_F_VOL_TEST;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002994
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002995 stktable_touch_local(t, ts, 1);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002996
2997 /* Touch was previously performed by stktable_update_key */
Willy Tarreau7d562212016-11-25 16:10:05 +01002998 return 1;
2999}
3000
3001/* set <smp> to the number of concurrent connections from the stream's tracked
3002 * frontend counters. Supports being called as "sc[0-9]_conn_cur" or
3003 * "src_conn_cur" only.
3004 */
3005static int
3006smp_fetch_sc_conn_cur(const struct arg *args, struct sample *smp, const char *kw, void *private)
3007{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003008 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003009 struct stkctr *stkctr;
3010
Emeric Brun819fc6f2017-06-13 19:37:32 +02003011 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003012 if (!stkctr)
3013 return 0;
3014
3015 smp->flags = SMP_F_VOL_TEST;
3016 smp->data.type = SMP_T_SINT;
3017 smp->data.u.sint = 0;
3018 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003019 void *ptr;
3020
3021 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_CONN_CUR);
3022 if (!ptr) {
3023 if (stkctr == &tmpstkctr)
3024 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003025 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003026 }
3027
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003028 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003029
Willy Tarreau7d562212016-11-25 16:10:05 +01003030 smp->data.u.sint = stktable_data_cast(ptr, conn_cur);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003031
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003032 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003033
3034 if (stkctr == &tmpstkctr)
3035 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003036 }
3037 return 1;
3038}
3039
3040/* set <smp> to the cumulated number of streams from the stream's tracked
3041 * frontend counters. Supports being called as "sc[0-9]_sess_cnt" or
3042 * "src_sess_cnt" only.
3043 */
3044static int
3045smp_fetch_sc_sess_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
3046{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003047 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003048 struct stkctr *stkctr;
3049
Emeric Brun819fc6f2017-06-13 19:37:32 +02003050 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003051 if (!stkctr)
3052 return 0;
3053
3054 smp->flags = SMP_F_VOL_TEST;
3055 smp->data.type = SMP_T_SINT;
3056 smp->data.u.sint = 0;
3057 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003058 void *ptr;
3059
3060 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_SESS_CNT);
3061 if (!ptr) {
3062 if (stkctr == &tmpstkctr)
3063 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003064 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003065 }
3066
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003067 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003068
Willy Tarreau7d562212016-11-25 16:10:05 +01003069 smp->data.u.sint = stktable_data_cast(ptr, sess_cnt);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003070
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003071 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003072
3073 if (stkctr == &tmpstkctr)
3074 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003075 }
3076 return 1;
3077}
3078
3079/* set <smp> to the stream rate from the stream's tracked frontend counters.
3080 * Supports being called as "sc[0-9]_sess_rate" or "src_sess_rate" only.
3081 */
3082static int
3083smp_fetch_sc_sess_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3084{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003085 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003086 struct stkctr *stkctr;
3087
Emeric Brun819fc6f2017-06-13 19:37:32 +02003088 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003089 if (!stkctr)
3090 return 0;
3091
3092 smp->flags = SMP_F_VOL_TEST;
3093 smp->data.type = SMP_T_SINT;
3094 smp->data.u.sint = 0;
3095 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003096 void *ptr;
3097
3098 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_SESS_RATE);
3099 if (!ptr) {
3100 if (stkctr == &tmpstkctr)
3101 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003102 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003103 }
3104
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003105 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003106
Willy Tarreau7d562212016-11-25 16:10:05 +01003107 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, sess_rate),
3108 stkctr->table->data_arg[STKTABLE_DT_SESS_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003109
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003110 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003111
3112 if (stkctr == &tmpstkctr)
3113 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003114 }
3115 return 1;
3116}
3117
3118/* set <smp> to the cumulated number of HTTP requests from the stream's tracked
3119 * frontend counters. Supports being called as "sc[0-9]_http_req_cnt" or
3120 * "src_http_req_cnt" only.
3121 */
3122static int
3123smp_fetch_sc_http_req_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
3124{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003125 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003126 struct stkctr *stkctr;
3127
Emeric Brun819fc6f2017-06-13 19:37:32 +02003128 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003129 if (!stkctr)
3130 return 0;
3131
3132 smp->flags = SMP_F_VOL_TEST;
3133 smp->data.type = SMP_T_SINT;
3134 smp->data.u.sint = 0;
3135 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003136 void *ptr;
3137
3138 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_REQ_CNT);
3139 if (!ptr) {
3140 if (stkctr == &tmpstkctr)
3141 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003142 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003143 }
3144
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003145 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003146
Willy Tarreau7d562212016-11-25 16:10:05 +01003147 smp->data.u.sint = stktable_data_cast(ptr, http_req_cnt);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003148
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003149 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003150
3151 if (stkctr == &tmpstkctr)
3152 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003153 }
3154 return 1;
3155}
3156
3157/* set <smp> to the HTTP request rate from the stream's tracked frontend
3158 * counters. Supports being called as "sc[0-9]_http_req_rate" or
3159 * "src_http_req_rate" only.
3160 */
3161static int
3162smp_fetch_sc_http_req_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3163{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003164 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003165 struct stkctr *stkctr;
3166
Emeric Brun819fc6f2017-06-13 19:37:32 +02003167 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003168 if (!stkctr)
3169 return 0;
3170
3171 smp->flags = SMP_F_VOL_TEST;
3172 smp->data.type = SMP_T_SINT;
3173 smp->data.u.sint = 0;
3174 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003175 void *ptr;
3176
3177 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_REQ_RATE);
3178 if (!ptr) {
3179 if (stkctr == &tmpstkctr)
3180 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003181 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003182 }
3183
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003184 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003185
Willy Tarreau7d562212016-11-25 16:10:05 +01003186 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, http_req_rate),
3187 stkctr->table->data_arg[STKTABLE_DT_HTTP_REQ_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003188
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003189 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003190
3191 if (stkctr == &tmpstkctr)
3192 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003193 }
3194 return 1;
3195}
3196
3197/* set <smp> to the cumulated number of HTTP requests errors from the stream's
3198 * tracked frontend counters. Supports being called as "sc[0-9]_http_err_cnt" or
3199 * "src_http_err_cnt" only.
3200 */
3201static int
3202smp_fetch_sc_http_err_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
3203{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003204 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003205 struct stkctr *stkctr;
3206
Emeric Brun819fc6f2017-06-13 19:37:32 +02003207 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003208 if (!stkctr)
3209 return 0;
3210
3211 smp->flags = SMP_F_VOL_TEST;
3212 smp->data.type = SMP_T_SINT;
3213 smp->data.u.sint = 0;
3214 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003215 void *ptr;
3216
3217 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_ERR_CNT);
3218 if (!ptr) {
3219 if (stkctr == &tmpstkctr)
3220 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003221 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003222 }
3223
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003224 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003225
Willy Tarreau7d562212016-11-25 16:10:05 +01003226 smp->data.u.sint = stktable_data_cast(ptr, http_err_cnt);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003227
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003228 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003229
3230 if (stkctr == &tmpstkctr)
3231 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003232 }
3233 return 1;
3234}
3235
3236/* set <smp> to the HTTP request error rate from the stream's tracked frontend
3237 * counters. Supports being called as "sc[0-9]_http_err_rate" or
3238 * "src_http_err_rate" only.
3239 */
3240static int
3241smp_fetch_sc_http_err_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3242{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003243 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003244 struct stkctr *stkctr;
3245
Emeric Brun819fc6f2017-06-13 19:37:32 +02003246 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003247 if (!stkctr)
3248 return 0;
3249
3250 smp->flags = SMP_F_VOL_TEST;
3251 smp->data.type = SMP_T_SINT;
3252 smp->data.u.sint = 0;
3253 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003254 void *ptr;
3255
3256 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_ERR_RATE);
3257 if (!ptr) {
3258 if (stkctr == &tmpstkctr)
3259 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003260 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003261 }
3262
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003263 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003264
Willy Tarreau7d562212016-11-25 16:10:05 +01003265 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, http_err_rate),
3266 stkctr->table->data_arg[STKTABLE_DT_HTTP_ERR_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003267
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003268 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003269
3270 if (stkctr == &tmpstkctr)
3271 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003272 }
3273 return 1;
3274}
3275
Willy Tarreau826f3ab2021-02-10 12:07:15 +01003276/* set <smp> to the cumulated number of HTTP response failures from the stream's
3277 * tracked frontend counters. Supports being called as "sc[0-9]_http_fail_cnt" or
3278 * "src_http_fail_cnt" only.
3279 */
3280static int
3281smp_fetch_sc_http_fail_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
3282{
3283 struct stkctr tmpstkctr;
3284 struct stkctr *stkctr;
3285
3286 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
3287 if (!stkctr)
3288 return 0;
3289
3290 smp->flags = SMP_F_VOL_TEST;
3291 smp->data.type = SMP_T_SINT;
3292 smp->data.u.sint = 0;
3293 if (stkctr_entry(stkctr) != NULL) {
3294 void *ptr;
3295
3296 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_FAIL_CNT);
3297 if (!ptr) {
3298 if (stkctr == &tmpstkctr)
3299 stktable_release(stkctr->table, stkctr_entry(stkctr));
3300 return 0; /* parameter not stored */
3301 }
3302
3303 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3304
3305 smp->data.u.sint = stktable_data_cast(ptr, http_fail_cnt);
3306
3307 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3308
3309 if (stkctr == &tmpstkctr)
3310 stktable_release(stkctr->table, stkctr_entry(stkctr));
3311 }
3312 return 1;
3313}
3314
3315/* set <smp> to the HTTP response failure rate from the stream's tracked frontend
3316 * counters. Supports being called as "sc[0-9]_http_fail_rate" or
3317 * "src_http_fail_rate" only.
3318 */
3319static int
3320smp_fetch_sc_http_fail_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3321{
3322 struct stkctr tmpstkctr;
3323 struct stkctr *stkctr;
3324
3325 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
3326 if (!stkctr)
3327 return 0;
3328
3329 smp->flags = SMP_F_VOL_TEST;
3330 smp->data.type = SMP_T_SINT;
3331 smp->data.u.sint = 0;
3332 if (stkctr_entry(stkctr) != NULL) {
3333 void *ptr;
3334
3335 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_FAIL_RATE);
3336 if (!ptr) {
3337 if (stkctr == &tmpstkctr)
3338 stktable_release(stkctr->table, stkctr_entry(stkctr));
3339 return 0; /* parameter not stored */
3340 }
3341
3342 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3343
3344 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, http_fail_rate),
3345 stkctr->table->data_arg[STKTABLE_DT_HTTP_FAIL_RATE].u);
3346
3347 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
3348
3349 if (stkctr == &tmpstkctr)
3350 stktable_release(stkctr->table, stkctr_entry(stkctr));
3351 }
3352 return 1;
3353}
3354
Willy Tarreau7d562212016-11-25 16:10:05 +01003355/* set <smp> to the number of kbytes received from clients, as found in the
3356 * stream's tracked frontend counters. Supports being called as
3357 * "sc[0-9]_kbytes_in" or "src_kbytes_in" only.
3358 */
3359static int
3360smp_fetch_sc_kbytes_in(const struct arg *args, struct sample *smp, const char *kw, void *private)
3361{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003362 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003363 struct stkctr *stkctr;
3364
Emeric Brun819fc6f2017-06-13 19:37:32 +02003365 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003366 if (!stkctr)
3367 return 0;
3368
3369 smp->flags = SMP_F_VOL_TEST;
3370 smp->data.type = SMP_T_SINT;
3371 smp->data.u.sint = 0;
3372 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003373 void *ptr;
3374
3375 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_IN_CNT);
3376 if (!ptr) {
3377 if (stkctr == &tmpstkctr)
3378 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003379 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003380 }
3381
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003382 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003383
Willy Tarreau7d562212016-11-25 16:10:05 +01003384 smp->data.u.sint = stktable_data_cast(ptr, bytes_in_cnt) >> 10;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003385
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003386 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003387
3388 if (stkctr == &tmpstkctr)
3389 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003390 }
3391 return 1;
3392}
3393
3394/* set <smp> to the data rate received from clients in bytes/s, as found
3395 * in the stream's tracked frontend counters. Supports being called as
3396 * "sc[0-9]_bytes_in_rate" or "src_bytes_in_rate" only.
3397 */
3398static int
3399smp_fetch_sc_bytes_in_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3400{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003401 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003402 struct stkctr *stkctr;
3403
Emeric Brun819fc6f2017-06-13 19:37:32 +02003404 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003405 if (!stkctr)
3406 return 0;
3407
3408 smp->flags = SMP_F_VOL_TEST;
3409 smp->data.type = SMP_T_SINT;
3410 smp->data.u.sint = 0;
3411 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003412 void *ptr;
3413
3414 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_IN_RATE);
3415 if (!ptr) {
3416 if (stkctr == &tmpstkctr)
3417 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003418 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003419 }
3420
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003421 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003422
Willy Tarreau7d562212016-11-25 16:10:05 +01003423 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, bytes_in_rate),
3424 stkctr->table->data_arg[STKTABLE_DT_BYTES_IN_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003425
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003426 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003427
3428 if (stkctr == &tmpstkctr)
3429 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003430 }
3431 return 1;
3432}
3433
3434/* set <smp> to the number of kbytes sent to clients, as found in the
3435 * stream's tracked frontend counters. Supports being called as
3436 * "sc[0-9]_kbytes_out" or "src_kbytes_out" only.
3437 */
3438static int
3439smp_fetch_sc_kbytes_out(const struct arg *args, struct sample *smp, const char *kw, void *private)
3440{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003441 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003442 struct stkctr *stkctr;
3443
Emeric Brun819fc6f2017-06-13 19:37:32 +02003444 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003445 if (!stkctr)
3446 return 0;
3447
3448 smp->flags = SMP_F_VOL_TEST;
3449 smp->data.type = SMP_T_SINT;
3450 smp->data.u.sint = 0;
3451 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003452 void *ptr;
3453
3454 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_OUT_CNT);
3455 if (!ptr) {
3456 if (stkctr == &tmpstkctr)
3457 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003458 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003459 }
3460
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003461 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003462
Willy Tarreau7d562212016-11-25 16:10:05 +01003463 smp->data.u.sint = stktable_data_cast(ptr, bytes_out_cnt) >> 10;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003464
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003465 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003466
3467 if (stkctr == &tmpstkctr)
3468 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003469 }
3470 return 1;
3471}
3472
3473/* set <smp> to the data rate sent to clients in bytes/s, as found in the
3474 * stream's tracked frontend counters. Supports being called as
3475 * "sc[0-9]_bytes_out_rate" or "src_bytes_out_rate" only.
3476 */
3477static int
3478smp_fetch_sc_bytes_out_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3479{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003480 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003481 struct stkctr *stkctr;
3482
Emeric Brun819fc6f2017-06-13 19:37:32 +02003483 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003484 if (!stkctr)
3485 return 0;
3486
3487 smp->flags = SMP_F_VOL_TEST;
3488 smp->data.type = SMP_T_SINT;
3489 smp->data.u.sint = 0;
3490 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003491 void *ptr;
3492
3493 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_OUT_RATE);
3494 if (!ptr) {
3495 if (stkctr == &tmpstkctr)
3496 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003497 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003498 }
3499
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003500 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003501
Willy Tarreau7d562212016-11-25 16:10:05 +01003502 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, bytes_out_rate),
3503 stkctr->table->data_arg[STKTABLE_DT_BYTES_OUT_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003504
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003505 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003506
3507 if (stkctr == &tmpstkctr)
3508 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003509 }
3510 return 1;
3511}
3512
3513/* set <smp> to the number of active trackers on the SC entry in the stream's
3514 * tracked frontend counters. Supports being called as "sc[0-9]_trackers" only.
3515 */
3516static int
3517smp_fetch_sc_trackers(const struct arg *args, struct sample *smp, const char *kw, void *private)
3518{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003519 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003520 struct stkctr *stkctr;
3521
Emeric Brun819fc6f2017-06-13 19:37:32 +02003522 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003523 if (!stkctr)
3524 return 0;
3525
3526 smp->flags = SMP_F_VOL_TEST;
3527 smp->data.type = SMP_T_SINT;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003528 if (stkctr == &tmpstkctr) {
3529 smp->data.u.sint = stkctr_entry(stkctr) ? (stkctr_entry(stkctr)->ref_cnt-1) : 0;
3530 stktable_release(stkctr->table, stkctr_entry(stkctr));
3531 }
3532 else {
3533 smp->data.u.sint = stkctr_entry(stkctr) ? stkctr_entry(stkctr)->ref_cnt : 0;
3534 }
3535
Willy Tarreau7d562212016-11-25 16:10:05 +01003536 return 1;
3537}
3538
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003539
3540/* The functions below are used to manipulate table contents from the CLI.
3541 * There are 3 main actions, "clear", "set" and "show". The code is shared
3542 * between all actions, and the action is encoded in the void *private in
3543 * the appctx as well as in the keyword registration, among one of the
3544 * following values.
3545 */
3546
3547enum {
3548 STK_CLI_ACT_CLR,
3549 STK_CLI_ACT_SET,
3550 STK_CLI_ACT_SHOW,
3551};
3552
3553/* Dump the status of a table to a stream interface's
3554 * read buffer. It returns 0 if the output buffer is full
3555 * and needs to be called again, otherwise non-zero.
3556 */
Willy Tarreau83061a82018-07-13 11:56:34 +02003557static int table_dump_head_to_buffer(struct buffer *msg,
3558 struct stream_interface *si,
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003559 struct stktable *t, struct stktable *target)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003560{
3561 struct stream *s = si_strm(si);
3562
3563 chunk_appendf(msg, "# table: %s, type: %s, size:%d, used:%d\n",
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003564 t->id, stktable_types[t->type].kw, t->size, t->current);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003565
3566 /* any other information should be dumped here */
3567
William Lallemand07a62f72017-05-24 00:57:40 +02003568 if (target && (strm_li(s)->bind_conf->level & ACCESS_LVL_MASK) < ACCESS_LVL_OPER)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003569 chunk_appendf(msg, "# contents not dumped due to insufficient privileges\n");
3570
Willy Tarreau06d80a92017-10-19 14:32:15 +02003571 if (ci_putchk(si_ic(si), msg) == -1) {
Willy Tarreaudb398432018-11-15 11:08:52 +01003572 si_rx_room_blk(si);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003573 return 0;
3574 }
3575
3576 return 1;
3577}
3578
3579/* Dump a table entry to a stream interface's
3580 * read buffer. It returns 0 if the output buffer is full
3581 * and needs to be called again, otherwise non-zero.
3582 */
Willy Tarreau83061a82018-07-13 11:56:34 +02003583static int table_dump_entry_to_buffer(struct buffer *msg,
3584 struct stream_interface *si,
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003585 struct stktable *t, struct stksess *entry)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003586{
3587 int dt;
3588
3589 chunk_appendf(msg, "%p:", entry);
3590
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003591 if (t->type == SMP_T_IPV4) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003592 char addr[INET_ADDRSTRLEN];
3593 inet_ntop(AF_INET, (const void *)&entry->key.key, addr, sizeof(addr));
3594 chunk_appendf(msg, " key=%s", addr);
3595 }
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003596 else if (t->type == SMP_T_IPV6) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003597 char addr[INET6_ADDRSTRLEN];
3598 inet_ntop(AF_INET6, (const void *)&entry->key.key, addr, sizeof(addr));
3599 chunk_appendf(msg, " key=%s", addr);
3600 }
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003601 else if (t->type == SMP_T_SINT) {
Willy Tarreau6cde5d82020-02-25 09:41:22 +01003602 chunk_appendf(msg, " key=%u", read_u32(entry->key.key));
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003603 }
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003604 else if (t->type == SMP_T_STR) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003605 chunk_appendf(msg, " key=");
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003606 dump_text(msg, (const char *)entry->key.key, t->key_size);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003607 }
3608 else {
3609 chunk_appendf(msg, " key=");
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003610 dump_binary(msg, (const char *)entry->key.key, t->key_size);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003611 }
3612
3613 chunk_appendf(msg, " use=%d exp=%d", entry->ref_cnt - 1, tick_remain(now_ms, entry->expire));
3614
3615 for (dt = 0; dt < STKTABLE_DATA_TYPES; dt++) {
3616 void *ptr;
3617
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003618 if (t->data_ofs[dt] == 0)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003619 continue;
3620 if (stktable_data_types[dt].arg_type == ARG_T_DELAY)
Emeric Brunc24b4142021-06-30 16:24:04 +02003621 chunk_appendf(msg, " %s(%u)=", stktable_data_types[dt].name, t->data_arg[dt].u);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003622 else
3623 chunk_appendf(msg, " %s=", stktable_data_types[dt].name);
3624
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003625 ptr = stktable_data_ptr(t, entry, dt);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003626 switch (stktable_data_types[dt].std_type) {
3627 case STD_T_SINT:
3628 chunk_appendf(msg, "%d", stktable_data_cast(ptr, std_t_sint));
3629 break;
3630 case STD_T_UINT:
3631 chunk_appendf(msg, "%u", stktable_data_cast(ptr, std_t_uint));
3632 break;
3633 case STD_T_ULL:
Emeric Brunc24b4142021-06-30 16:24:04 +02003634 chunk_appendf(msg, "%llu", stktable_data_cast(ptr, std_t_ull));
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003635 break;
3636 case STD_T_FRQP:
Emeric Brunc24b4142021-06-30 16:24:04 +02003637 chunk_appendf(msg, "%u",
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003638 read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003639 t->data_arg[dt].u));
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003640 break;
Frédéric Lécaille16b4f542019-05-23 12:15:04 +02003641 case STD_T_DICT: {
3642 struct dict_entry *de;
3643 de = stktable_data_cast(ptr, std_t_dict);
3644 chunk_appendf(msg, "%s", de ? (char *)de->value.key : "-");
3645 break;
3646 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003647 }
3648 }
3649 chunk_appendf(msg, "\n");
3650
Willy Tarreau06d80a92017-10-19 14:32:15 +02003651 if (ci_putchk(si_ic(si), msg) == -1) {
Willy Tarreaudb398432018-11-15 11:08:52 +01003652 si_rx_room_blk(si);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003653 return 0;
3654 }
3655
3656 return 1;
3657}
3658
3659
3660/* Processes a single table entry matching a specific key passed in argument.
3661 * returns 0 if wants to be called again, 1 if has ended processing.
3662 */
3663static int table_process_entry_per_key(struct appctx *appctx, char **args)
3664{
3665 struct stream_interface *si = appctx->owner;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003666 struct stktable *t = appctx->ctx.table.target;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003667 struct stksess *ts;
3668 uint32_t uint32_key;
3669 unsigned char ip6_key[sizeof(struct in6_addr)];
3670 long long value;
3671 int data_type;
3672 int cur_arg;
3673 void *ptr;
Willy Tarreaufa1258f2021-04-10 23:00:53 +02003674 struct freq_ctr *frqp;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003675
Willy Tarreau9d008692019-08-09 11:21:01 +02003676 if (!*args[4])
3677 return cli_err(appctx, "Key value expected\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003678
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003679 switch (t->type) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003680 case SMP_T_IPV4:
3681 uint32_key = htonl(inetaddr_host(args[4]));
Christopher Fauletca20d022017-08-29 15:30:31 +02003682 static_table_key.key = &uint32_key;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003683 break;
3684 case SMP_T_IPV6:
Christopher Faulet1e850b52021-11-15 09:17:25 +01003685 if (inet_pton(AF_INET6, args[4], ip6_key) <= 0)
3686 return cli_err(appctx, "Invalid key\n");
Christopher Fauletca20d022017-08-29 15:30:31 +02003687 static_table_key.key = &ip6_key;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003688 break;
3689 case SMP_T_SINT:
3690 {
3691 char *endptr;
3692 unsigned long val;
3693 errno = 0;
3694 val = strtoul(args[4], &endptr, 10);
3695 if ((errno == ERANGE && val == ULONG_MAX) ||
3696 (errno != 0 && val == 0) || endptr == args[4] ||
Willy Tarreau9d008692019-08-09 11:21:01 +02003697 val > 0xffffffff)
3698 return cli_err(appctx, "Invalid key\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003699 uint32_key = (uint32_t) val;
Christopher Fauletca20d022017-08-29 15:30:31 +02003700 static_table_key.key = &uint32_key;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003701 break;
3702 }
3703 break;
3704 case SMP_T_STR:
Christopher Fauletca20d022017-08-29 15:30:31 +02003705 static_table_key.key = args[4];
3706 static_table_key.key_len = strlen(args[4]);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003707 break;
3708 default:
Willy Tarreaua24bc782016-12-14 15:50:35 +01003709 switch (appctx->ctx.table.action) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003710 case STK_CLI_ACT_SHOW:
Willy Tarreau9d008692019-08-09 11:21:01 +02003711 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 +01003712 case STK_CLI_ACT_CLR:
Willy Tarreau9d008692019-08-09 11:21:01 +02003713 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 +01003714 case STK_CLI_ACT_SET:
Willy Tarreau9d008692019-08-09 11:21:01 +02003715 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 +01003716 default:
Willy Tarreau9d008692019-08-09 11:21:01 +02003717 return cli_err(appctx, "Unknown action\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003718 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003719 }
3720
3721 /* check permissions */
3722 if (!cli_has_level(appctx, ACCESS_LVL_OPER))
3723 return 1;
3724
Willy Tarreaua24bc782016-12-14 15:50:35 +01003725 switch (appctx->ctx.table.action) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003726 case STK_CLI_ACT_SHOW:
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003727 ts = stktable_lookup_key(t, &static_table_key);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003728 if (!ts)
3729 return 1;
3730 chunk_reset(&trash);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003731 if (!table_dump_head_to_buffer(&trash, si, t, t)) {
3732 stktable_release(t, ts);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003733 return 0;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003734 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003735 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003736 if (!table_dump_entry_to_buffer(&trash, si, t, ts)) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003737 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003738 stktable_release(t, ts);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003739 return 0;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003740 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003741 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003742 stktable_release(t, ts);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003743 break;
3744
3745 case STK_CLI_ACT_CLR:
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003746 ts = stktable_lookup_key(t, &static_table_key);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003747 if (!ts)
3748 return 1;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003749
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003750 if (!stksess_kill(t, ts, 1)) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003751 /* don't delete an entry which is currently referenced */
Willy Tarreau9d008692019-08-09 11:21:01 +02003752 return cli_err(appctx, "Entry currently in use, cannot remove\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003753 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003754 break;
3755
3756 case STK_CLI_ACT_SET:
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003757 ts = stktable_get_entry(t, &static_table_key);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003758 if (!ts) {
3759 /* don't delete an entry which is currently referenced */
Willy Tarreau9d008692019-08-09 11:21:01 +02003760 return cli_err(appctx, "Unable to allocate a new entry\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003761 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003762 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003763 for (cur_arg = 5; *args[cur_arg]; cur_arg += 2) {
3764 if (strncmp(args[cur_arg], "data.", 5) != 0) {
Willy Tarreau9d008692019-08-09 11:21:01 +02003765 cli_err(appctx, "\"data.<type>\" followed by a value expected\n");
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003766 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003767 stktable_touch_local(t, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003768 return 1;
3769 }
3770
3771 data_type = stktable_get_data_type(args[cur_arg] + 5);
3772 if (data_type < 0) {
Willy Tarreau9d008692019-08-09 11:21:01 +02003773 cli_err(appctx, "Unknown data type\n");
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003774 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003775 stktable_touch_local(t, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003776 return 1;
3777 }
3778
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003779 if (!t->data_ofs[data_type]) {
Willy Tarreau9d008692019-08-09 11:21:01 +02003780 cli_err(appctx, "Data type not stored in this table\n");
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003781 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003782 stktable_touch_local(t, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003783 return 1;
3784 }
3785
3786 if (!*args[cur_arg+1] || strl2llrc(args[cur_arg+1], strlen(args[cur_arg+1]), &value) != 0) {
Willy Tarreau9d008692019-08-09 11:21:01 +02003787 cli_err(appctx, "Require a valid integer value to store\n");
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003788 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003789 stktable_touch_local(t, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003790 return 1;
3791 }
3792
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003793 ptr = stktable_data_ptr(t, ts, data_type);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003794
3795 switch (stktable_data_types[data_type].std_type) {
3796 case STD_T_SINT:
3797 stktable_data_cast(ptr, std_t_sint) = value;
3798 break;
3799 case STD_T_UINT:
3800 stktable_data_cast(ptr, std_t_uint) = value;
3801 break;
3802 case STD_T_ULL:
3803 stktable_data_cast(ptr, std_t_ull) = value;
3804 break;
3805 case STD_T_FRQP:
3806 /* We set both the current and previous values. That way
3807 * the reported frequency is stable during all the period
3808 * then slowly fades out. This allows external tools to
3809 * push measures without having to update them too often.
3810 */
3811 frqp = &stktable_data_cast(ptr, std_t_frqp);
Willy Tarreaufa1258f2021-04-10 23:00:53 +02003812 /* First bit is reserved for the freq_ctr lock
Emeric Brunf2fc1fd2017-11-02 17:32:43 +01003813 Note: here we're still protected by the stksess lock
Willy Tarreaufa1258f2021-04-10 23:00:53 +02003814 so we don't need to update the update the freq_ctr
Emeric Brunf2fc1fd2017-11-02 17:32:43 +01003815 using its internal lock */
3816 frqp->curr_tick = now_ms & ~0x1;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003817 frqp->prev_ctr = 0;
3818 frqp->curr_ctr = value;
3819 break;
3820 }
3821 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003822 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003823 stktable_touch_local(t, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003824 break;
3825
3826 default:
Willy Tarreau9d008692019-08-09 11:21:01 +02003827 return cli_err(appctx, "Unknown action\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003828 }
3829 return 1;
3830}
3831
3832/* Prepares the appctx fields with the data-based filters from the command line.
3833 * Returns 0 if the dump can proceed, 1 if has ended processing.
3834 */
3835static int table_prepare_data_request(struct appctx *appctx, char **args)
3836{
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01003837 int i;
Adis Nezirovicd0142e72020-01-22 16:50:27 +01003838 char *err = NULL;
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01003839
Willy Tarreau9d008692019-08-09 11:21:01 +02003840 if (appctx->ctx.table.action != STK_CLI_ACT_SHOW && appctx->ctx.table.action != STK_CLI_ACT_CLR)
3841 return cli_err(appctx, "content-based lookup is only supported with the \"show\" and \"clear\" actions\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003842
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01003843 for (i = 0; i < STKTABLE_FILTER_LEN; i++) {
3844 if (i > 0 && !*args[3+3*i]) // number of filter entries can be less than STKTABLE_FILTER_LEN
3845 break;
3846 /* condition on stored data value */
3847 appctx->ctx.table.data_type[i] = stktable_get_data_type(args[3+3*i] + 5);
3848 if (appctx->ctx.table.data_type[i] < 0)
Adis Nezirovicd0142e72020-01-22 16:50:27 +01003849 return cli_dynerr(appctx, memprintf(&err, "Filter entry #%i: Unknown data type\n", i + 1));
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003850
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01003851 if (!((struct stktable *)appctx->ctx.table.target)->data_ofs[appctx->ctx.table.data_type[i]])
Adis Nezirovicd0142e72020-01-22 16:50:27 +01003852 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 +01003853
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01003854 appctx->ctx.table.data_op[i] = get_std_op(args[4+3*i]);
Willy Tarreau2b64a352020-01-22 17:09:47 +01003855 if (appctx->ctx.table.data_op[i] < 0)
Adis Nezirovicd0142e72020-01-22 16:50:27 +01003856 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 +01003857
Adis Nezirovic56dd3542020-01-22 16:16:48 +01003858 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 +01003859 return cli_dynerr(appctx, memprintf(&err, "Filter entry #%i: Require a valid integer value to compare against\n", i + 1));
3860 }
3861
3862 if (*args[3+3*i]) {
3863 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 +01003864 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003865
3866 /* OK we're done, all the fields are set */
3867 return 0;
3868}
3869
3870/* returns 0 if wants to be called, 1 if has ended processing */
Aurélien Nephtaliabbf6072018-04-18 13:26:46 +02003871static int cli_parse_table_req(char **args, char *payload, struct appctx *appctx, void *private)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003872{
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01003873 int i;
3874
3875 for (i = 0; i < STKTABLE_FILTER_LEN; i++)
3876 appctx->ctx.table.data_type[i] = -1;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003877 appctx->ctx.table.target = NULL;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003878 appctx->ctx.table.entry = NULL;
Willy Tarreaua24bc782016-12-14 15:50:35 +01003879 appctx->ctx.table.action = (long)private; // keyword argument, one of STK_CLI_ACT_*
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003880
3881 if (*args[2]) {
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003882 appctx->ctx.table.target = stktable_find_by_name(args[2]);
Willy Tarreau9d008692019-08-09 11:21:01 +02003883 if (!appctx->ctx.table.target)
3884 return cli_err(appctx, "No such table\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003885 }
3886 else {
Willy Tarreaua24bc782016-12-14 15:50:35 +01003887 if (appctx->ctx.table.action != STK_CLI_ACT_SHOW)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003888 goto err_args;
3889 return 0;
3890 }
3891
3892 if (strcmp(args[3], "key") == 0)
3893 return table_process_entry_per_key(appctx, args);
3894 else if (strncmp(args[3], "data.", 5) == 0)
3895 return table_prepare_data_request(appctx, args);
3896 else if (*args[3])
3897 goto err_args;
3898
3899 return 0;
3900
3901err_args:
Willy Tarreaua24bc782016-12-14 15:50:35 +01003902 switch (appctx->ctx.table.action) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003903 case STK_CLI_ACT_SHOW:
Willy Tarreau9d008692019-08-09 11:21:01 +02003904 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 +01003905 case STK_CLI_ACT_CLR:
Willy Tarreau9d008692019-08-09 11:21:01 +02003906 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 +01003907 case STK_CLI_ACT_SET:
Willy Tarreau9d008692019-08-09 11:21:01 +02003908 return cli_err(appctx, "Required arguments: <table> key <key> [data.<store_data_type> <value>]*\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003909 default:
Willy Tarreau9d008692019-08-09 11:21:01 +02003910 return cli_err(appctx, "Unknown action\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003911 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003912}
3913
3914/* This function is used to deal with table operations (dump or clear depending
3915 * on the action stored in appctx->private). It returns 0 if the output buffer is
3916 * full and it needs to be called again, otherwise non-zero.
3917 */
3918static int cli_io_handler_table(struct appctx *appctx)
3919{
3920 struct stream_interface *si = appctx->owner;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003921 struct stream *s = si_strm(si);
3922 struct ebmb_node *eb;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003923 int skip_entry;
Willy Tarreaua24bc782016-12-14 15:50:35 +01003924 int show = appctx->ctx.table.action == STK_CLI_ACT_SHOW;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003925
3926 /*
3927 * We have 3 possible states in appctx->st2 :
3928 * - STAT_ST_INIT : the first call
3929 * - STAT_ST_INFO : the proxy pointer points to the next table to
3930 * dump, the entry pointer is NULL ;
3931 * - STAT_ST_LIST : the proxy pointer points to the current table
3932 * and the entry pointer points to the next entry to be dumped,
3933 * and the refcount on the next entry is held ;
3934 * - STAT_ST_END : nothing left to dump, the buffer may contain some
3935 * data though.
3936 */
3937
3938 if (unlikely(si_ic(si)->flags & (CF_WRITE_ERROR|CF_SHUTW))) {
3939 /* in case of abort, remove any refcount we might have set on an entry */
3940 if (appctx->st2 == STAT_ST_LIST) {
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003941 stksess_kill_if_expired(appctx->ctx.table.t, appctx->ctx.table.entry, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003942 }
3943 return 1;
3944 }
3945
3946 chunk_reset(&trash);
3947
3948 while (appctx->st2 != STAT_ST_FIN) {
3949 switch (appctx->st2) {
3950 case STAT_ST_INIT:
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003951 appctx->ctx.table.t = appctx->ctx.table.target;
3952 if (!appctx->ctx.table.t)
3953 appctx->ctx.table.t = stktables_list;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003954
3955 appctx->ctx.table.entry = NULL;
3956 appctx->st2 = STAT_ST_INFO;
3957 break;
3958
3959 case STAT_ST_INFO:
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003960 if (!appctx->ctx.table.t ||
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003961 (appctx->ctx.table.target &&
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003962 appctx->ctx.table.t != appctx->ctx.table.target)) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003963 appctx->st2 = STAT_ST_END;
3964 break;
3965 }
3966
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003967 if (appctx->ctx.table.t->size) {
3968 if (show && !table_dump_head_to_buffer(&trash, si, appctx->ctx.table.t, appctx->ctx.table.target))
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003969 return 0;
3970
3971 if (appctx->ctx.table.target &&
William Lallemand07a62f72017-05-24 00:57:40 +02003972 (strm_li(s)->bind_conf->level & ACCESS_LVL_MASK) >= ACCESS_LVL_OPER) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003973 /* dump entries only if table explicitly requested */
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003974 HA_SPIN_LOCK(STK_TABLE_LOCK, &appctx->ctx.table.t->lock);
3975 eb = ebmb_first(&appctx->ctx.table.t->keys);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003976 if (eb) {
3977 appctx->ctx.table.entry = ebmb_entry(eb, struct stksess, key);
3978 appctx->ctx.table.entry->ref_cnt++;
3979 appctx->st2 = STAT_ST_LIST;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003980 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &appctx->ctx.table.t->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003981 break;
3982 }
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003983 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &appctx->ctx.table.t->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003984 }
3985 }
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003986 appctx->ctx.table.t = appctx->ctx.table.t->next;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003987 break;
3988
3989 case STAT_ST_LIST:
3990 skip_entry = 0;
3991
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003992 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &appctx->ctx.table.entry->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003993
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01003994 if (appctx->ctx.table.data_type[0] >= 0) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003995 /* we're filtering on some data contents */
3996 void *ptr;
Willy Tarreau2b64a352020-01-22 17:09:47 +01003997 int dt, i;
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01003998 signed char op;
3999 long long data, value;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004000
Emeric Brun819fc6f2017-06-13 19:37:32 +02004001
Willy Tarreau2b64a352020-01-22 17:09:47 +01004002 for (i = 0; i < STKTABLE_FILTER_LEN; i++) {
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004003 if (appctx->ctx.table.data_type[i] == -1)
4004 break;
4005 dt = appctx->ctx.table.data_type[i];
4006 ptr = stktable_data_ptr(appctx->ctx.table.t,
4007 appctx->ctx.table.entry,
4008 dt);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004009
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004010 data = 0;
4011 switch (stktable_data_types[dt].std_type) {
4012 case STD_T_SINT:
4013 data = stktable_data_cast(ptr, std_t_sint);
4014 break;
4015 case STD_T_UINT:
4016 data = stktable_data_cast(ptr, std_t_uint);
4017 break;
4018 case STD_T_ULL:
4019 data = stktable_data_cast(ptr, std_t_ull);
4020 break;
4021 case STD_T_FRQP:
4022 data = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
4023 appctx->ctx.table.t->data_arg[dt].u);
4024 break;
4025 }
4026
4027 op = appctx->ctx.table.data_op[i];
4028 value = appctx->ctx.table.value[i];
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004029
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01004030 /* skip the entry if the data does not match the test and the value */
4031 if ((data < value &&
4032 (op == STD_OP_EQ || op == STD_OP_GT || op == STD_OP_GE)) ||
4033 (data == value &&
4034 (op == STD_OP_NE || op == STD_OP_GT || op == STD_OP_LT)) ||
4035 (data > value &&
4036 (op == STD_OP_EQ || op == STD_OP_LT || op == STD_OP_LE))) {
4037 skip_entry = 1;
4038 break;
4039 }
4040 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004041 }
4042
4043 if (show && !skip_entry &&
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004044 !table_dump_entry_to_buffer(&trash, si, appctx->ctx.table.t, appctx->ctx.table.entry)) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004045 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &appctx->ctx.table.entry->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004046 return 0;
4047 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004048
Christopher Faulet2a944ee2017-11-07 10:42:54 +01004049 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &appctx->ctx.table.entry->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004050
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004051 HA_SPIN_LOCK(STK_TABLE_LOCK, &appctx->ctx.table.t->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004052 appctx->ctx.table.entry->ref_cnt--;
4053
4054 eb = ebmb_next(&appctx->ctx.table.entry->key);
4055 if (eb) {
4056 struct stksess *old = appctx->ctx.table.entry;
4057 appctx->ctx.table.entry = ebmb_entry(eb, struct stksess, key);
4058 if (show)
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004059 __stksess_kill_if_expired(appctx->ctx.table.t, old);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004060 else if (!skip_entry && !appctx->ctx.table.entry->ref_cnt)
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004061 __stksess_kill(appctx->ctx.table.t, old);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004062 appctx->ctx.table.entry->ref_cnt++;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004063 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &appctx->ctx.table.t->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004064 break;
4065 }
4066
4067
4068 if (show)
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004069 __stksess_kill_if_expired(appctx->ctx.table.t, appctx->ctx.table.entry);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004070 else if (!skip_entry && !appctx->ctx.table.entry->ref_cnt)
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004071 __stksess_kill(appctx->ctx.table.t, appctx->ctx.table.entry);
Emeric Brun819fc6f2017-06-13 19:37:32 +02004072
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004073 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &appctx->ctx.table.t->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004074
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004075 appctx->ctx.table.t = appctx->ctx.table.t->next;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004076 appctx->st2 = STAT_ST_INFO;
4077 break;
4078
4079 case STAT_ST_END:
4080 appctx->st2 = STAT_ST_FIN;
4081 break;
4082 }
4083 }
4084 return 1;
4085}
4086
4087static void cli_release_show_table(struct appctx *appctx)
4088{
4089 if (appctx->st2 == STAT_ST_LIST) {
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01004090 stksess_kill_if_expired(appctx->ctx.table.t, appctx->ctx.table.entry, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004091 }
4092}
4093
Willy Tarreau478331d2020-08-28 11:31:31 +02004094static void stkt_late_init(void)
4095{
4096 struct sample_fetch *f;
4097
4098 f = find_sample_fetch("src", strlen("src"));
4099 if (f)
4100 smp_fetch_src = f->process;
4101}
4102
4103INITCALL0(STG_INIT, stkt_late_init);
4104
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004105/* register cli keywords */
4106static struct cli_kw_list cli_kws = {{ },{
Willy Tarreaub205bfd2021-05-07 11:38:37 +02004107 { { "clear", "table", NULL }, "clear table <table> [<filter>]* : remove an entry from a table (filter: data/key)", cli_parse_table_req, cli_io_handler_table, cli_release_show_table, (void *)STK_CLI_ACT_CLR },
4108 { { "set", "table", NULL }, "set table <table> key <k> [data.* <v>]* : update or create a table entry's data", cli_parse_table_req, cli_io_handler_table, NULL, (void *)STK_CLI_ACT_SET },
4109 { { "show", "table", NULL }, "show table <table> [<filter>]* : report table usage stats or dump this table's contents (filter: data/key)", cli_parse_table_req, cli_io_handler_table, cli_release_show_table, (void *)STK_CLI_ACT_SHOW },
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004110 {{},}
4111}};
4112
Willy Tarreau0108d902018-11-25 19:14:37 +01004113INITCALL1(STG_REGISTER, cli_register_kw, &cli_kws);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01004114
Thierry FOURNIER236657b2015-08-19 08:25:14 +02004115static struct action_kw_list tcp_conn_kws = { { }, {
Amaury Denoyellee4a617c2021-05-06 15:33:09 +02004116 { "sc-inc-gpc0", parse_inc_gpc0, KWF_MATCH_PREFIX },
4117 { "sc-inc-gpc1", parse_inc_gpc1, KWF_MATCH_PREFIX },
4118 { "sc-set-gpt0", parse_set_gpt0, KWF_MATCH_PREFIX },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02004119 { /* END */ }
4120}};
4121
Willy Tarreau0108d902018-11-25 19:14:37 +01004122INITCALL1(STG_REGISTER, tcp_req_conn_keywords_register, &tcp_conn_kws);
4123
Willy Tarreau620408f2016-10-21 16:37:51 +02004124static struct action_kw_list tcp_sess_kws = { { }, {
Amaury Denoyellee4a617c2021-05-06 15:33:09 +02004125 { "sc-inc-gpc0", parse_inc_gpc0, KWF_MATCH_PREFIX },
4126 { "sc-inc-gpc1", parse_inc_gpc1, KWF_MATCH_PREFIX },
4127 { "sc-set-gpt0", parse_set_gpt0, KWF_MATCH_PREFIX },
Willy Tarreau620408f2016-10-21 16:37:51 +02004128 { /* END */ }
4129}};
4130
Willy Tarreau0108d902018-11-25 19:14:37 +01004131INITCALL1(STG_REGISTER, tcp_req_sess_keywords_register, &tcp_sess_kws);
4132
Thierry FOURNIER236657b2015-08-19 08:25:14 +02004133static struct action_kw_list tcp_req_kws = { { }, {
Amaury Denoyellee4a617c2021-05-06 15:33:09 +02004134 { "sc-inc-gpc0", parse_inc_gpc0, KWF_MATCH_PREFIX },
4135 { "sc-inc-gpc1", parse_inc_gpc1, KWF_MATCH_PREFIX },
4136 { "sc-set-gpt0", parse_set_gpt0, KWF_MATCH_PREFIX },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02004137 { /* END */ }
4138}};
4139
Willy Tarreau0108d902018-11-25 19:14:37 +01004140INITCALL1(STG_REGISTER, tcp_req_cont_keywords_register, &tcp_req_kws);
4141
Thierry FOURNIER236657b2015-08-19 08:25:14 +02004142static struct action_kw_list tcp_res_kws = { { }, {
Amaury Denoyellee4a617c2021-05-06 15:33:09 +02004143 { "sc-inc-gpc0", parse_inc_gpc0, KWF_MATCH_PREFIX },
4144 { "sc-inc-gpc1", parse_inc_gpc1, KWF_MATCH_PREFIX },
4145 { "sc-set-gpt0", parse_set_gpt0, KWF_MATCH_PREFIX },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02004146 { /* END */ }
4147}};
4148
Willy Tarreau0108d902018-11-25 19:14:37 +01004149INITCALL1(STG_REGISTER, tcp_res_cont_keywords_register, &tcp_res_kws);
4150
Thierry FOURNIER236657b2015-08-19 08:25:14 +02004151static struct action_kw_list http_req_kws = { { }, {
Amaury Denoyellee4a617c2021-05-06 15:33:09 +02004152 { "sc-inc-gpc0", parse_inc_gpc0, KWF_MATCH_PREFIX },
4153 { "sc-inc-gpc1", parse_inc_gpc1, KWF_MATCH_PREFIX },
4154 { "sc-set-gpt0", parse_set_gpt0, KWF_MATCH_PREFIX },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02004155 { /* END */ }
4156}};
4157
Willy Tarreau0108d902018-11-25 19:14:37 +01004158INITCALL1(STG_REGISTER, http_req_keywords_register, &http_req_kws);
4159
Thierry FOURNIER236657b2015-08-19 08:25:14 +02004160static struct action_kw_list http_res_kws = { { }, {
Amaury Denoyellee4a617c2021-05-06 15:33:09 +02004161 { "sc-inc-gpc0", parse_inc_gpc0, KWF_MATCH_PREFIX },
4162 { "sc-inc-gpc1", parse_inc_gpc1, KWF_MATCH_PREFIX },
4163 { "sc-set-gpt0", parse_set_gpt0, KWF_MATCH_PREFIX },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02004164 { /* END */ }
4165}};
4166
Willy Tarreau0108d902018-11-25 19:14:37 +01004167INITCALL1(STG_REGISTER, http_res_keywords_register, &http_res_kws);
4168
Willy Tarreau7d562212016-11-25 16:10:05 +01004169/* Note: must not be declared <const> as its list will be overwritten.
4170 * Please take care of keeping this list alphabetically sorted.
4171 */
4172static struct sample_fetch_kw_list smp_fetch_keywords = {ILH, {
4173 { "sc_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4174 { "sc_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4175 { "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 +01004176 { "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 +01004177 { "sc_conn_cnt", smp_fetch_sc_conn_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4178 { "sc_conn_cur", smp_fetch_sc_conn_cur, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4179 { "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 +01004180 { "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 +01004181 { "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 +01004182 { "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 +01004183 { "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 +01004184 { "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 +01004185 { "sc_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4186 { "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 +01004187 { "sc_http_fail_cnt", smp_fetch_sc_http_fail_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4188 { "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 +01004189 { "sc_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4190 { "sc_http_req_rate", smp_fetch_sc_http_req_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4191 { "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 +01004192 { "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 +01004193 { "sc_kbytes_in", smp_fetch_sc_kbytes_in, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4194 { "sc_kbytes_out", smp_fetch_sc_kbytes_out, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4195 { "sc_sess_cnt", smp_fetch_sc_sess_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4196 { "sc_sess_rate", smp_fetch_sc_sess_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4197 { "sc_tracked", smp_fetch_sc_tracked, ARG2(1,SINT,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
4198 { "sc_trackers", smp_fetch_sc_trackers, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4199 { "sc0_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4200 { "sc0_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4201 { "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 +01004202 { "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 +01004203 { "sc0_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4204 { "sc0_conn_cur", smp_fetch_sc_conn_cur, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4205 { "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 +01004206 { "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 +01004207 { "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 +01004208 { "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 +01004209 { "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 +01004210 { "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 +01004211 { "sc0_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4212 { "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 +01004213 { "sc0_http_fail_cnt", smp_fetch_sc_http_fail_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4214 { "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 +01004215 { "sc0_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4216 { "sc0_http_req_rate", smp_fetch_sc_http_req_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4217 { "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 +01004218 { "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 +01004219 { "sc0_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4220 { "sc0_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4221 { "sc0_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4222 { "sc0_sess_rate", smp_fetch_sc_sess_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4223 { "sc0_tracked", smp_fetch_sc_tracked, ARG1(0,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
4224 { "sc0_trackers", smp_fetch_sc_trackers, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4225 { "sc1_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4226 { "sc1_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4227 { "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 +01004228 { "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 +01004229 { "sc1_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4230 { "sc1_conn_cur", smp_fetch_sc_conn_cur, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4231 { "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 +01004232 { "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 +01004233 { "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 +01004234 { "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 +01004235 { "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 +01004236 { "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 +01004237 { "sc1_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4238 { "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 +01004239 { "sc1_http_fail_cnt", smp_fetch_sc_http_fail_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4240 { "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 +01004241 { "sc1_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4242 { "sc1_http_req_rate", smp_fetch_sc_http_req_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4243 { "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 +01004244 { "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 +01004245 { "sc1_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4246 { "sc1_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4247 { "sc1_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4248 { "sc1_sess_rate", smp_fetch_sc_sess_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4249 { "sc1_tracked", smp_fetch_sc_tracked, ARG1(0,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
4250 { "sc1_trackers", smp_fetch_sc_trackers, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4251 { "sc2_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4252 { "sc2_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4253 { "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 +01004254 { "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 +01004255 { "sc2_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4256 { "sc2_conn_cur", smp_fetch_sc_conn_cur, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4257 { "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 +01004258 { "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 +01004259 { "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 +01004260 { "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 +01004261 { "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 +01004262 { "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 +01004263 { "sc2_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4264 { "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 +01004265 { "sc2_http_fail_cnt", smp_fetch_sc_http_fail_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4266 { "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 +01004267 { "sc2_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4268 { "sc2_http_req_rate", smp_fetch_sc_http_req_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4269 { "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 +01004270 { "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 +01004271 { "sc2_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4272 { "sc2_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4273 { "sc2_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4274 { "sc2_sess_rate", smp_fetch_sc_sess_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4275 { "sc2_tracked", smp_fetch_sc_tracked, ARG1(0,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
4276 { "sc2_trackers", smp_fetch_sc_trackers, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4277 { "src_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4278 { "src_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4279 { "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 +01004280 { "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 +01004281 { "src_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4282 { "src_conn_cur", smp_fetch_sc_conn_cur, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4283 { "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 +01004284 { "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 +01004285 { "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 +01004286 { "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 +01004287 { "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 +01004288 { "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 +01004289 { "src_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4290 { "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 +01004291 { "src_http_fail_cnt", smp_fetch_sc_http_fail_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4292 { "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 +01004293 { "src_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4294 { "src_http_req_rate", smp_fetch_sc_http_req_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4295 { "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 +01004296 { "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 +01004297 { "src_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4298 { "src_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4299 { "src_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4300 { "src_sess_rate", smp_fetch_sc_sess_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4301 { "src_updt_conn_cnt", smp_fetch_src_updt_conn_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4302 { "table_avl", smp_fetch_table_avl, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4303 { "table_cnt", smp_fetch_table_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4304 { /* END */ },
4305}};
4306
Willy Tarreau0108d902018-11-25 19:14:37 +01004307INITCALL1(STG_REGISTER, sample_register_fetches, &smp_fetch_keywords);
Willy Tarreau7d562212016-11-25 16:10:05 +01004308
Willy Tarreaud9f316a2014-07-10 14:03:38 +02004309/* Note: must not be declared <const> as its list will be overwritten */
4310static struct sample_conv_kw_list sample_conv_kws = {ILH, {
Willy Tarreau2d17db52016-05-25 17:16:38 +02004311 { "in_table", sample_conv_in_table, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_BOOL },
4312 { "table_bytes_in_rate", sample_conv_table_bytes_in_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4313 { "table_bytes_out_rate", sample_conv_table_bytes_out_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4314 { "table_conn_cnt", sample_conv_table_conn_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4315 { "table_conn_cur", sample_conv_table_conn_cur, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4316 { "table_conn_rate", sample_conv_table_conn_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4317 { "table_gpt0", sample_conv_table_gpt0, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4318 { "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 +01004319 { "table_gpc1", sample_conv_table_gpc1, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
Willy Tarreau2d17db52016-05-25 17:16:38 +02004320 { "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 +01004321 { "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 +02004322 { "table_http_err_cnt", sample_conv_table_http_err_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4323 { "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 +01004324 { "table_http_fail_cnt", sample_conv_table_http_fail_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4325 { "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 +02004326 { "table_http_req_cnt", sample_conv_table_http_req_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4327 { "table_http_req_rate", sample_conv_table_http_req_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4328 { "table_kbytes_in", sample_conv_table_kbytes_in, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4329 { "table_kbytes_out", sample_conv_table_kbytes_out, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4330 { "table_server_id", sample_conv_table_server_id, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4331 { "table_sess_cnt", sample_conv_table_sess_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4332 { "table_sess_rate", sample_conv_table_sess_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4333 { "table_trackers", sample_conv_table_trackers, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
Willy Tarreaud9f316a2014-07-10 14:03:38 +02004334 { /* END */ },
4335}};
4336
Willy Tarreau0108d902018-11-25 19:14:37 +01004337INITCALL1(STG_REGISTER, sample_register_convs, &sample_conv_kws);