blob: da07b8c839dea8106f34c4e39be4c67fc73011f0 [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 */
Olivier Houchard9f6af332018-05-25 14:04:04 +0200629static struct task *process_table_expire(struct task *task, void *context, unsigned short state)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100630{
Olivier Houchard9f6af332018-05-25 14:04:04 +0200631 struct stktable *t = context;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100632
633 task->expire = stktable_trash_expired(t);
634 return task;
635}
636
Willy Tarreauaea940e2010-06-06 11:56:36 +0200637/* Perform minimal stick table intializations, report 0 in case of error, 1 if OK. */
Emeric Brun3bd697e2010-01-04 15:23:48 +0100638int stktable_init(struct stktable *t)
639{
640 if (t->size) {
Emeric Brun819fc6f2017-06-13 19:37:32 +0200641 t->keys = EB_ROOT_UNIQUE;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100642 memset(&t->exps, 0, sizeof(t->exps));
Emeric Brun1c6235d2015-12-16 15:28:12 +0100643 t->updates = EB_ROOT_UNIQUE;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100644 HA_SPIN_INIT(&t->lock);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100645
Olivier Houchard52dabbc2018-11-14 17:54:36 +0100646 t->pool = create_pool("sticktables", sizeof(struct stksess) + round_ptr_size(t->data_size) + t->key_size, MEM_F_SHARED);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100647
648 t->exp_next = TICK_ETERNITY;
649 if ( t->expire ) {
Emeric Brunc60def82017-09-27 14:59:38 +0200650 t->exp_task = task_new(MAX_THREADS_MASK);
Willy Tarreau848522f2018-10-15 11:12:15 +0200651 if (!t->exp_task)
652 return 0;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100653 t->exp_task->process = process_table_expire;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100654 t->exp_task->context = (void *)t;
655 }
Willy Tarreauc3914d42020-09-24 08:39:22 +0200656 if (t->peers.p && t->peers.p->peers_fe && !t->peers.p->peers_fe->disabled) {
Emeric Brun32da3c42010-09-23 18:39:19 +0200657 peers_register_table(t->peers.p, t);
658 }
659
Emeric Brun3bd697e2010-01-04 15:23:48 +0100660 return t->pool != NULL;
661 }
662 return 1;
663}
664
665/*
666 * Configuration keywords of known table types
667 */
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200668struct stktable_type stktable_types[SMP_TYPES] = {
669 [SMP_T_SINT] = { "integer", 0, 4 },
670 [SMP_T_IPV4] = { "ip", 0, 4 },
671 [SMP_T_IPV6] = { "ipv6", 0, 16 },
672 [SMP_T_STR] = { "string", STK_F_CUSTOM_KEYSIZE, 32 },
673 [SMP_T_BIN] = { "binary", STK_F_CUSTOM_KEYSIZE, 32 }
674};
Emeric Brun3bd697e2010-01-04 15:23:48 +0100675
676/*
677 * Parse table type configuration.
678 * Returns 0 on successful parsing, else 1.
679 * <myidx> is set at next configuration <args> index.
680 */
681int stktable_parse_type(char **args, int *myidx, unsigned long *type, size_t *key_size)
682{
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200683 for (*type = 0; *type < SMP_TYPES; (*type)++) {
684 if (!stktable_types[*type].kw)
685 continue;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100686 if (strcmp(args[*myidx], stktable_types[*type].kw) != 0)
687 continue;
688
689 *key_size = stktable_types[*type].default_size;
690 (*myidx)++;
691
Willy Tarreauaea940e2010-06-06 11:56:36 +0200692 if (stktable_types[*type].flags & STK_F_CUSTOM_KEYSIZE) {
Emeric Brun3bd697e2010-01-04 15:23:48 +0100693 if (strcmp("len", args[*myidx]) == 0) {
694 (*myidx)++;
695 *key_size = atol(args[*myidx]);
Emeric Brun485479d2010-09-23 18:02:19 +0200696 if (!*key_size)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100697 break;
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200698 if (*type == SMP_T_STR) {
Emeric Brun485479d2010-09-23 18:02:19 +0200699 /* null terminated string needs +1 for '\0'. */
700 (*key_size)++;
701 }
Emeric Brun3bd697e2010-01-04 15:23:48 +0100702 (*myidx)++;
703 }
704 }
705 return 0;
706 }
707 return 1;
708}
709
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100710/*
Frédéric Lécaillec02766a2019-03-20 15:06:55 +0100711 * Parse a line with <linenum> as number in <file> configuration file to configure
712 * the stick-table with <t> as address and <id> as ID.
713 * <peers> provides the "peers" section pointer only if this function is called
714 * from a "peers" section.
715 * <nid> is the stick-table name which is sent over the network. It must be equal
716 * to <id> if this stick-table is parsed from a proxy section, and prefixed by <peers>
717 * "peers" section name followed by a '/' character if parsed from a "peers" section.
Ilya Shipitsind4259502020-04-08 01:07:56 +0500718 * This is the responsibility of the caller to check this.
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100719 * Return an error status with ERR_* flags set if required, 0 if no error was encountered.
720 */
721int parse_stick_table(const char *file, int linenum, char **args,
Frédéric Lécaillec02766a2019-03-20 15:06:55 +0100722 struct stktable *t, char *id, char *nid, struct peers *peers)
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100723{
724 int err_code = 0;
725 int idx = 1;
726 unsigned int val;
727
728 if (!id || !*id) {
729 ha_alert("parsing [%s:%d] : %s: ID not provided.\n", file, linenum, args[0]);
730 err_code |= ERR_ALERT | ERR_ABORT;
731 goto out;
732 }
733
734 /* Store the "peers" section if this function is called from a "peers" section. */
735 if (peers) {
736 t->peers.p = peers;
737 idx++;
738 }
739
740 t->id = id;
Frédéric Lécaillec02766a2019-03-20 15:06:55 +0100741 t->nid = nid;
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100742 t->type = (unsigned int)-1;
743 t->conf.file = file;
744 t->conf.line = linenum;
745
746 while (*args[idx]) {
747 const char *err;
748
749 if (strcmp(args[idx], "size") == 0) {
750 idx++;
751 if (!*(args[idx])) {
752 ha_alert("parsing [%s:%d] : %s: missing argument after '%s'.\n",
753 file, linenum, args[0], args[idx-1]);
754 err_code |= ERR_ALERT | ERR_FATAL;
755 goto out;
756 }
757 if ((err = parse_size_err(args[idx], &t->size))) {
758 ha_alert("parsing [%s:%d] : %s: unexpected character '%c' in argument of '%s'.\n",
759 file, linenum, args[0], *err, args[idx-1]);
760 err_code |= ERR_ALERT | ERR_FATAL;
761 goto out;
762 }
763 idx++;
764 }
765 /* This argument does not exit in "peers" section. */
766 else if (!peers && strcmp(args[idx], "peers") == 0) {
767 idx++;
768 if (!*(args[idx])) {
769 ha_alert("parsing [%s:%d] : %s: missing argument after '%s'.\n",
770 file, linenum, args[0], args[idx-1]);
771 err_code |= ERR_ALERT | ERR_FATAL;
772 goto out;
773 }
774 t->peers.name = strdup(args[idx++]);
775 }
776 else if (strcmp(args[idx], "expire") == 0) {
777 idx++;
778 if (!*(args[idx])) {
779 ha_alert("parsing [%s:%d] : %s: missing argument after '%s'.\n",
780 file, linenum, args[0], args[idx-1]);
781 err_code |= ERR_ALERT | ERR_FATAL;
782 goto out;
783 }
784 err = parse_time_err(args[idx], &val, TIME_UNIT_MS);
Willy Tarreau9faebe32019-06-07 19:00:37 +0200785 if (err == PARSE_TIME_OVER) {
786 ha_alert("parsing [%s:%d]: %s: timer overflow in argument <%s> to <%s>, maximum value is 2147483647 ms (~24.8 days).\n",
787 file, linenum, args[0], args[idx], args[idx-1]);
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100788 err_code |= ERR_ALERT | ERR_FATAL;
789 goto out;
790 }
Willy Tarreau9faebe32019-06-07 19:00:37 +0200791 else if (err == PARSE_TIME_UNDER) {
792 ha_alert("parsing [%s:%d]: %s: timer underflow in argument <%s> to <%s>, minimum non-null value is 1 ms.\n",
793 file, linenum, args[0], args[idx], args[idx-1]);
794 err_code |= ERR_ALERT | ERR_FATAL;
795 goto out;
796 }
797 else if (err) {
798 ha_alert("parsing [%s:%d] : %s: unexpected character '%c' in argument of '%s'.\n",
799 file, linenum, args[0], *err, args[idx-1]);
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100800 err_code |= ERR_ALERT | ERR_FATAL;
801 goto out;
802 }
803 t->expire = val;
804 idx++;
805 }
806 else if (strcmp(args[idx], "nopurge") == 0) {
807 t->nopurge = 1;
808 idx++;
809 }
810 else if (strcmp(args[idx], "type") == 0) {
811 idx++;
812 if (stktable_parse_type(args, &idx, &t->type, &t->key_size) != 0) {
813 ha_alert("parsing [%s:%d] : %s: unknown type '%s'.\n",
814 file, linenum, args[0], args[idx]);
815 err_code |= ERR_ALERT | ERR_FATAL;
816 goto out;
817 }
818 /* idx already points to next arg */
819 }
820 else if (strcmp(args[idx], "store") == 0) {
821 int type, err;
822 char *cw, *nw, *sa;
823
824 idx++;
825 nw = args[idx];
826 while (*nw) {
827 /* the "store" keyword supports a comma-separated list */
828 cw = nw;
829 sa = NULL; /* store arg */
830 while (*nw && *nw != ',') {
831 if (*nw == '(') {
832 *nw = 0;
833 sa = ++nw;
834 while (*nw != ')') {
835 if (!*nw) {
836 ha_alert("parsing [%s:%d] : %s: missing closing parenthesis after store option '%s'.\n",
837 file, linenum, args[0], cw);
838 err_code |= ERR_ALERT | ERR_FATAL;
839 goto out;
840 }
841 nw++;
842 }
843 *nw = '\0';
844 }
845 nw++;
846 }
847 if (*nw)
848 *nw++ = '\0';
849 type = stktable_get_data_type(cw);
850 if (type < 0) {
851 ha_alert("parsing [%s:%d] : %s: unknown store option '%s'.\n",
852 file, linenum, args[0], cw);
853 err_code |= ERR_ALERT | ERR_FATAL;
854 goto out;
855 }
856
857 err = stktable_alloc_data_type(t, type, sa);
858 switch (err) {
859 case PE_NONE: break;
860 case PE_EXIST:
861 ha_warning("parsing [%s:%d]: %s: store option '%s' already enabled, ignored.\n",
862 file, linenum, args[0], cw);
863 err_code |= ERR_WARN;
864 break;
865
866 case PE_ARG_MISSING:
867 ha_alert("parsing [%s:%d] : %s: missing argument to store option '%s'.\n",
868 file, linenum, args[0], cw);
869 err_code |= ERR_ALERT | ERR_FATAL;
870 goto out;
871
872 case PE_ARG_NOT_USED:
873 ha_alert("parsing [%s:%d] : %s: unexpected argument to store option '%s'.\n",
874 file, linenum, args[0], cw);
875 err_code |= ERR_ALERT | ERR_FATAL;
876 goto out;
877
878 default:
879 ha_alert("parsing [%s:%d] : %s: error when processing store option '%s'.\n",
880 file, linenum, args[0], cw);
881 err_code |= ERR_ALERT | ERR_FATAL;
882 goto out;
883 }
884 }
885 idx++;
886 }
Thayne McCombs92149f92020-11-20 01:28:26 -0700887 else if (strcmp(args[idx], "srvkey") == 0) {
888 char *keytype;
889 idx++;
890 keytype = args[idx];
891 if (strcmp(keytype, "name") == 0) {
892 t->server_key_type = STKTABLE_SRV_NAME;
893 }
894 else if (strcmp(keytype, "addr") == 0) {
895 t->server_key_type = STKTABLE_SRV_ADDR;
896 }
897 else {
898 ha_alert("parsing [%s:%d] : %s : unknown server key type '%s'.\n",
899 file, linenum, args[0], keytype);
900 err_code |= ERR_ALERT | ERR_FATAL;
901 goto out;
902
903 }
904 idx++;
905 }
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100906 else {
907 ha_alert("parsing [%s:%d] : %s: unknown argument '%s'.\n",
908 file, linenum, args[0], args[idx]);
909 err_code |= ERR_ALERT | ERR_FATAL;
910 goto out;
911 }
912 }
913
914 if (!t->size) {
915 ha_alert("parsing [%s:%d] : %s: missing size.\n",
916 file, linenum, args[0]);
917 err_code |= ERR_ALERT | ERR_FATAL;
918 goto out;
919 }
920
921 if (t->type == (unsigned int)-1) {
922 ha_alert("parsing [%s:%d] : %s: missing type.\n",
923 file, linenum, args[0]);
924 err_code |= ERR_ALERT | ERR_FATAL;
925 goto out;
926 }
927
928 out:
929 return err_code;
930}
931
Willy Tarreau8fed9032014-07-03 17:02:46 +0200932/* Prepares a stktable_key from a sample <smp> to search into table <t>.
Willy Tarreauf0c730a2016-05-25 17:07:56 +0200933 * Note that the sample *is* modified and that the returned key may point
934 * to it, so the sample must not be modified afterwards before the lookup.
Willy Tarreau8fed9032014-07-03 17:02:46 +0200935 * Returns NULL if the sample could not be converted (eg: no matching type),
936 * otherwise a pointer to the static stktable_key filled with what is needed
937 * for the lookup.
Willy Tarreauf0b38bf2010-06-06 13:22:23 +0200938 */
Willy Tarreau8fed9032014-07-03 17:02:46 +0200939struct stktable_key *smp_to_stkey(struct sample *smp, struct stktable *t)
Willy Tarreauf0b38bf2010-06-06 13:22:23 +0200940{
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200941 /* Convert sample. */
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200942 if (!sample_convert(smp, t->type))
Willy Tarreau7fc1c6e2012-04-26 11:03:17 +0200943 return NULL;
944
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200945 /* Fill static_table_key. */
946 switch (t->type) {
Emeric Brun485479d2010-09-23 18:02:19 +0200947
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200948 case SMP_T_IPV4:
Christopher Fauletca20d022017-08-29 15:30:31 +0200949 static_table_key.key = &smp->data.u.ipv4;
950 static_table_key.key_len = 4;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200951 break;
Emeric Brun485479d2010-09-23 18:02:19 +0200952
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200953 case SMP_T_IPV6:
Christopher Fauletca20d022017-08-29 15:30:31 +0200954 static_table_key.key = &smp->data.u.ipv6;
955 static_table_key.key_len = 16;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200956 break;
Emeric Brun485479d2010-09-23 18:02:19 +0200957
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200958 case SMP_T_SINT:
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200959 /* The stick table require a 32bit unsigned int, "sint" is a
960 * signed 64 it, so we can convert it inplace.
961 */
Willy Tarreau28c63c12019-10-23 06:21:05 +0200962 smp->data.u.sint = (unsigned int)smp->data.u.sint;
Christopher Fauletca20d022017-08-29 15:30:31 +0200963 static_table_key.key = &smp->data.u.sint;
964 static_table_key.key_len = 4;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200965 break;
966
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200967 case SMP_T_STR:
Willy Tarreauce6955e2016-08-09 11:59:12 +0200968 if (!smp_make_safe(smp))
969 return NULL;
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200970 static_table_key.key = smp->data.u.str.area;
971 static_table_key.key_len = smp->data.u.str.data;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200972 break;
Emeric Brun485479d2010-09-23 18:02:19 +0200973
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200974 case SMP_T_BIN:
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200975 if (smp->data.u.str.data < t->key_size) {
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200976 /* This type needs padding with 0. */
Willy Tarreauf65c6c02016-08-09 12:08:41 +0200977 if (!smp_make_rw(smp))
978 return NULL;
979
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200980 if (smp->data.u.str.size < t->key_size)
981 if (!smp_dup(smp))
982 return NULL;
983 if (smp->data.u.str.size < t->key_size)
984 return NULL;
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200985 memset(smp->data.u.str.area + smp->data.u.str.data, 0,
986 t->key_size - smp->data.u.str.data);
987 smp->data.u.str.data = t->key_size;
Emeric Brun485479d2010-09-23 18:02:19 +0200988 }
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200989 static_table_key.key = smp->data.u.str.area;
990 static_table_key.key_len = smp->data.u.str.data;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200991 break;
Emeric Brun485479d2010-09-23 18:02:19 +0200992
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200993 default: /* impossible case. */
994 return NULL;
Emeric Brun485479d2010-09-23 18:02:19 +0200995 }
996
Christopher Fauletca20d022017-08-29 15:30:31 +0200997 return &static_table_key;
Willy Tarreauf0b38bf2010-06-06 13:22:23 +0200998}
999
1000/*
Willy Tarreau8fed9032014-07-03 17:02:46 +02001001 * Process a fetch + format conversion as defined by the sample expression <expr>
1002 * on request or response considering the <opt> parameter. Returns either NULL if
1003 * no key could be extracted, or a pointer to the converted result stored in
1004 * static_table_key in format <table_type>. If <smp> is not NULL, it will be reset
1005 * and its flags will be initialized so that the caller gets a copy of the input
Willy Tarreau6bcb0a82014-07-30 08:56:35 +02001006 * sample, and knows why it was not accepted (eg: SMP_F_MAY_CHANGE is present
1007 * without SMP_OPT_FINAL). The output will be usable like this :
1008 *
1009 * return MAY_CHANGE FINAL Meaning for the sample
1010 * NULL 0 * Not present and will never be (eg: header)
1011 * NULL 1 0 Not present or unstable, could change (eg: req_len)
1012 * NULL 1 1 Not present, will not change anymore
1013 * smp 0 * Present and will not change (eg: header)
1014 * smp 1 0 not possible
1015 * smp 1 1 Present, last known value (eg: request length)
Willy Tarreau8fed9032014-07-03 17:02:46 +02001016 */
Willy Tarreau192252e2015-04-04 01:47:55 +02001017struct stktable_key *stktable_fetch_key(struct stktable *t, struct proxy *px, struct session *sess, struct stream *strm,
Willy Tarreau8fed9032014-07-03 17:02:46 +02001018 unsigned int opt, struct sample_expr *expr, struct sample *smp)
1019{
1020 if (smp)
1021 memset(smp, 0, sizeof(*smp));
1022
Willy Tarreau192252e2015-04-04 01:47:55 +02001023 smp = sample_process(px, sess, strm, opt, expr, smp);
Willy Tarreau8fed9032014-07-03 17:02:46 +02001024 if (!smp)
1025 return NULL;
1026
1027 if ((smp->flags & SMP_F_MAY_CHANGE) && !(opt & SMP_OPT_FINAL))
1028 return NULL; /* we can only use stable samples */
1029
1030 return smp_to_stkey(smp, t);
1031}
1032
1033/*
Willy Tarreau12785782012-04-27 21:37:17 +02001034 * Returns 1 if sample expression <expr> result can be converted to table key of
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001035 * type <table_type>, otherwise zero. Used in configuration check.
1036 */
Willy Tarreau12785782012-04-27 21:37:17 +02001037int stktable_compatible_sample(struct sample_expr *expr, unsigned long table_type)
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001038{
Thierry FOURNIERf73eb8f2013-11-27 15:30:55 +01001039 int out_type;
1040
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +02001041 if (table_type >= SMP_TYPES || !stktable_types[table_type].kw)
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001042 return 0;
1043
Thierry FOURNIERf73eb8f2013-11-27 15:30:55 +01001044 out_type = smp_expr_output_type(expr);
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001045
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001046 /* Convert sample. */
1047 if (!sample_casts[out_type][table_type])
Thierry FOURNIERf73eb8f2013-11-27 15:30:55 +01001048 return 0;
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001049
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001050 return 1;
1051}
Emeric Brun3bd697e2010-01-04 15:23:48 +01001052
Willy Tarreauedee1d62014-07-15 16:44:27 +02001053/* Extra data types processing : after the last one, some room may remain
1054 * before STKTABLE_DATA_TYPES that may be used to register extra data types
1055 * at run time.
1056 */
Willy Tarreau08d5f982010-06-06 13:34:54 +02001057struct stktable_data_type stktable_data_types[STKTABLE_DATA_TYPES] = {
Willy Tarreau3b9c6e02010-07-18 08:04:30 +02001058 [STKTABLE_DT_SERVER_ID] = { .name = "server_id", .std_type = STD_T_SINT },
Thierry FOURNIER3cf11112015-07-28 08:57:05 +02001059 [STKTABLE_DT_GPT0] = { .name = "gpt0", .std_type = STD_T_UINT },
Willy Tarreau3b9c6e02010-07-18 08:04:30 +02001060 [STKTABLE_DT_GPC0] = { .name = "gpc0", .std_type = STD_T_UINT },
Willy Tarreauba2ffd12013-05-29 15:54:14 +02001061 [STKTABLE_DT_GPC0_RATE] = { .name = "gpc0_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
Willy Tarreau3b9c6e02010-07-18 08:04:30 +02001062 [STKTABLE_DT_CONN_CNT] = { .name = "conn_cnt", .std_type = STD_T_UINT },
1063 [STKTABLE_DT_CONN_RATE] = { .name = "conn_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
1064 [STKTABLE_DT_CONN_CUR] = { .name = "conn_cur", .std_type = STD_T_UINT },
1065 [STKTABLE_DT_SESS_CNT] = { .name = "sess_cnt", .std_type = STD_T_UINT },
1066 [STKTABLE_DT_SESS_RATE] = { .name = "sess_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
1067 [STKTABLE_DT_HTTP_REQ_CNT] = { .name = "http_req_cnt", .std_type = STD_T_UINT },
1068 [STKTABLE_DT_HTTP_REQ_RATE] = { .name = "http_req_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
1069 [STKTABLE_DT_HTTP_ERR_CNT] = { .name = "http_err_cnt", .std_type = STD_T_UINT },
1070 [STKTABLE_DT_HTTP_ERR_RATE] = { .name = "http_err_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
1071 [STKTABLE_DT_BYTES_IN_CNT] = { .name = "bytes_in_cnt", .std_type = STD_T_ULL },
1072 [STKTABLE_DT_BYTES_IN_RATE] = { .name = "bytes_in_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
1073 [STKTABLE_DT_BYTES_OUT_CNT] = { .name = "bytes_out_cnt", .std_type = STD_T_ULL },
1074 [STKTABLE_DT_BYTES_OUT_RATE]= { .name = "bytes_out_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001075 [STKTABLE_DT_GPC1] = { .name = "gpc1", .std_type = STD_T_UINT },
1076 [STKTABLE_DT_GPC1_RATE] = { .name = "gpc1_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
Thayne McCombs92149f92020-11-20 01:28:26 -07001077 [STKTABLE_DT_SERVER_KEY] = { .name = "server_key", .std_type = STD_T_DICT },
Willy Tarreau08d5f982010-06-06 13:34:54 +02001078};
1079
Willy Tarreauedee1d62014-07-15 16:44:27 +02001080/* Registers stick-table extra data type with index <idx>, name <name>, type
1081 * <std_type> and arg type <arg_type>. If the index is negative, the next free
1082 * index is automatically allocated. The allocated index is returned, or -1 if
1083 * no free index was found or <name> was already registered. The <name> is used
1084 * directly as a pointer, so if it's not stable, the caller must allocate it.
1085 */
1086int stktable_register_data_store(int idx, const char *name, int std_type, int arg_type)
1087{
1088 if (idx < 0) {
1089 for (idx = 0; idx < STKTABLE_DATA_TYPES; idx++) {
1090 if (!stktable_data_types[idx].name)
1091 break;
1092
1093 if (strcmp(stktable_data_types[idx].name, name) == 0)
1094 return -1;
1095 }
1096 }
1097
1098 if (idx >= STKTABLE_DATA_TYPES)
1099 return -1;
1100
1101 if (stktable_data_types[idx].name != NULL)
1102 return -1;
1103
1104 stktable_data_types[idx].name = name;
1105 stktable_data_types[idx].std_type = std_type;
1106 stktable_data_types[idx].arg_type = arg_type;
1107 return idx;
1108}
1109
Willy Tarreau08d5f982010-06-06 13:34:54 +02001110/*
1111 * Returns the data type number for the stktable_data_type whose name is <name>,
1112 * or <0 if not found.
1113 */
1114int stktable_get_data_type(char *name)
1115{
1116 int type;
1117
1118 for (type = 0; type < STKTABLE_DATA_TYPES; type++) {
Willy Tarreauedee1d62014-07-15 16:44:27 +02001119 if (!stktable_data_types[type].name)
1120 continue;
Willy Tarreau08d5f982010-06-06 13:34:54 +02001121 if (strcmp(name, stktable_data_types[type].name) == 0)
1122 return type;
1123 }
Thayne McCombs92149f92020-11-20 01:28:26 -07001124 /* For backwards compatibility */
1125 if (strcmp(name, "server_name") == 0)
1126 return STKTABLE_DT_SERVER_KEY;
Willy Tarreau08d5f982010-06-06 13:34:54 +02001127 return -1;
1128}
1129
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001130/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1131 * it up into this table. Returns true if found, false otherwise. The input
1132 * type is STR so that input samples are converted to string (since all types
1133 * can be converted to strings), then the function casts the string again into
1134 * the table's type. This is a double conversion, but in the future we might
1135 * support automatic input types to perform the cast on the fly.
1136 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001137static int sample_conv_in_table(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001138{
1139 struct stktable *t;
1140 struct stktable_key *key;
1141 struct stksess *ts;
1142
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001143 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001144
1145 key = smp_to_stkey(smp, t);
1146 if (!key)
1147 return 0;
1148
1149 ts = stktable_lookup_key(t, key);
1150
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001151 smp->data.type = SMP_T_BOOL;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001152 smp->data.u.sint = !!ts;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001153 smp->flags = SMP_F_VOL_TEST;
Willy Tarreau43e90352018-06-27 06:25:57 +02001154 stktable_release(t, ts);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001155 return 1;
1156}
1157
1158/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1159 * it up into this table. Returns the data rate received from clients in bytes/s
1160 * if the key is present in the table, otherwise zero, so that comparisons can
1161 * be easily performed. If the inspected parameter is not stored in the table,
1162 * <not found> is returned.
1163 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001164static int sample_conv_table_bytes_in_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001165{
1166 struct stktable *t;
1167 struct stktable_key *key;
1168 struct stksess *ts;
1169 void *ptr;
1170
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001171 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001172
1173 key = smp_to_stkey(smp, t);
1174 if (!key)
1175 return 0;
1176
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001177 ts = stktable_lookup_key(t, key);
1178
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001179 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001180 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001181 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001182
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001183 if (!ts) /* key not present */
1184 return 1;
1185
1186 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_IN_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001187 if (ptr)
1188 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, bytes_in_rate),
1189 t->data_arg[STKTABLE_DT_BYTES_IN_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001190
Daniel Corbett3e60b112018-05-27 09:47:12 -04001191 stktable_release(t, ts);
1192 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001193}
1194
1195/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1196 * it up into this table. Returns the cumulated number of connections for the key
1197 * if the key is present in the table, otherwise zero, so that comparisons can
1198 * be easily performed. If the inspected parameter is not stored in the table,
1199 * <not found> is returned.
1200 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001201static int sample_conv_table_conn_cnt(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001202{
1203 struct stktable *t;
1204 struct stktable_key *key;
1205 struct stksess *ts;
1206 void *ptr;
1207
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001208 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001209
1210 key = smp_to_stkey(smp, t);
1211 if (!key)
1212 return 0;
1213
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001214 ts = stktable_lookup_key(t, key);
1215
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001216 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001217 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001218 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001219
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001220 if (!ts) /* key not present */
1221 return 1;
1222
1223 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_CONN_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001224 if (ptr)
1225 smp->data.u.sint = stktable_data_cast(ptr, conn_cnt);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001226
Daniel Corbett3e60b112018-05-27 09:47:12 -04001227 stktable_release(t, ts);
1228 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001229}
1230
1231/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1232 * it up into this table. Returns the number of concurrent connections for the
1233 * key if the key is present in the table, otherwise zero, so that comparisons
1234 * can be easily performed. If the inspected parameter is not stored in the
1235 * table, <not found> is returned.
1236 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001237static int sample_conv_table_conn_cur(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001238{
1239 struct stktable *t;
1240 struct stktable_key *key;
1241 struct stksess *ts;
1242 void *ptr;
1243
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001244 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001245
1246 key = smp_to_stkey(smp, t);
1247 if (!key)
1248 return 0;
1249
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001250 ts = stktable_lookup_key(t, key);
1251
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001252 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001253 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001254 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001255
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001256 if (!ts) /* key not present */
1257 return 1;
1258
1259 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_CONN_CUR);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001260 if (ptr)
1261 smp->data.u.sint = stktable_data_cast(ptr, conn_cur);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001262
Daniel Corbett3e60b112018-05-27 09:47:12 -04001263 stktable_release(t, ts);
1264 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001265}
1266
1267/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1268 * it up into this table. Returns the rate of incoming connections from the key
1269 * if the key is present in the table, otherwise zero, so that comparisons can
1270 * be easily performed. If the inspected parameter is not stored in the table,
1271 * <not found> is returned.
1272 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001273static int sample_conv_table_conn_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001274{
1275 struct stktable *t;
1276 struct stktable_key *key;
1277 struct stksess *ts;
1278 void *ptr;
1279
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001280 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001281
1282 key = smp_to_stkey(smp, t);
1283 if (!key)
1284 return 0;
1285
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001286 ts = stktable_lookup_key(t, key);
1287
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001288 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001289 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001290 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001291
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001292 if (!ts) /* key not present */
1293 return 1;
1294
1295 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_CONN_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001296 if (ptr)
1297 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, conn_rate),
1298 t->data_arg[STKTABLE_DT_CONN_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001299
Daniel Corbett3e60b112018-05-27 09:47:12 -04001300 stktable_release(t, ts);
1301 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001302}
1303
1304/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1305 * it up into this table. Returns the data rate sent to clients in bytes/s
1306 * if the key is present in the table, otherwise zero, so that comparisons can
1307 * be easily performed. If the inspected parameter is not stored in the table,
1308 * <not found> is returned.
1309 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001310static int sample_conv_table_bytes_out_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001311{
1312 struct stktable *t;
1313 struct stktable_key *key;
1314 struct stksess *ts;
1315 void *ptr;
1316
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001317 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001318
1319 key = smp_to_stkey(smp, t);
1320 if (!key)
1321 return 0;
1322
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001323 ts = stktable_lookup_key(t, key);
1324
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001325 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001326 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001327 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001328
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001329 if (!ts) /* key not present */
1330 return 1;
1331
1332 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_OUT_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001333 if (ptr)
1334 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, bytes_out_rate),
1335 t->data_arg[STKTABLE_DT_BYTES_OUT_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001336
Daniel Corbett3e60b112018-05-27 09:47:12 -04001337 stktable_release(t, ts);
1338 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001339}
1340
1341/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001342 * it up into this table. Returns the value of the GPT0 tag for the key
1343 * if the key is present in the table, otherwise false, so that comparisons can
1344 * be easily performed. If the inspected parameter is not stored in the table,
1345 * <not found> is returned.
1346 */
1347static int sample_conv_table_gpt0(const struct arg *arg_p, struct sample *smp, void *private)
1348{
1349 struct stktable *t;
1350 struct stktable_key *key;
1351 struct stksess *ts;
1352 void *ptr;
1353
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001354 t = arg_p[0].data.t;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001355
1356 key = smp_to_stkey(smp, t);
1357 if (!key)
1358 return 0;
1359
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001360 ts = stktable_lookup_key(t, key);
1361
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001362 smp->flags = SMP_F_VOL_TEST;
1363 smp->data.type = SMP_T_SINT;
1364 smp->data.u.sint = 0;
1365
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001366 if (!ts) /* key not present */
1367 return 1;
1368
1369 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPT0);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001370 if (ptr)
1371 smp->data.u.sint = stktable_data_cast(ptr, gpt0);
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001372
Daniel Corbett3e60b112018-05-27 09:47:12 -04001373 stktable_release(t, ts);
1374 return !!ptr;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001375}
1376
1377/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001378 * it up into this table. Returns the value of the GPC0 counter for the key
1379 * if the key is present in the table, otherwise zero, so that comparisons can
1380 * be easily performed. If the inspected parameter is not stored in the table,
1381 * <not found> is returned.
1382 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001383static int sample_conv_table_gpc0(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001384{
1385 struct stktable *t;
1386 struct stktable_key *key;
1387 struct stksess *ts;
1388 void *ptr;
1389
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001390 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001391
1392 key = smp_to_stkey(smp, t);
1393 if (!key)
1394 return 0;
1395
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001396 ts = stktable_lookup_key(t, key);
1397
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001398 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001399 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001400 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001401
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001402 if (!ts) /* key not present */
1403 return 1;
1404
1405 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPC0);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001406 if (ptr)
1407 smp->data.u.sint = stktable_data_cast(ptr, gpc0);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001408
Daniel Corbett3e60b112018-05-27 09:47:12 -04001409 stktable_release(t, ts);
1410 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001411}
1412
1413/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1414 * it up into this table. Returns the event rate of the GPC0 counter for the key
1415 * if the key is present in the table, otherwise zero, so that comparisons can
1416 * be easily performed. If the inspected parameter is not stored in the table,
1417 * <not found> is returned.
1418 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001419static int sample_conv_table_gpc0_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001420{
1421 struct stktable *t;
1422 struct stktable_key *key;
1423 struct stksess *ts;
1424 void *ptr;
1425
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001426 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001427
1428 key = smp_to_stkey(smp, t);
1429 if (!key)
1430 return 0;
1431
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001432 ts = stktable_lookup_key(t, key);
1433
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001434 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001435 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001436 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001437
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001438 if (!ts) /* key not present */
1439 return 1;
1440
1441 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPC0_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001442 if (ptr)
1443 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, gpc0_rate),
1444 t->data_arg[STKTABLE_DT_GPC0_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001445
Daniel Corbett3e60b112018-05-27 09:47:12 -04001446 stktable_release(t, ts);
1447 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001448}
1449
1450/* 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 +01001451 * it up into this table. Returns the value of the GPC1 counter for the key
1452 * if the key is present in the table, otherwise zero, so that comparisons can
1453 * be easily performed. If the inspected parameter is not stored in the table,
1454 * <not found> is returned.
1455 */
1456static int sample_conv_table_gpc1(const struct arg *arg_p, struct sample *smp, void *private)
1457{
1458 struct stktable *t;
1459 struct stktable_key *key;
1460 struct stksess *ts;
1461 void *ptr;
1462
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001463 t = arg_p[0].data.t;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001464
1465 key = smp_to_stkey(smp, t);
1466 if (!key)
1467 return 0;
1468
1469 ts = stktable_lookup_key(t, key);
1470
1471 smp->flags = SMP_F_VOL_TEST;
1472 smp->data.type = SMP_T_SINT;
1473 smp->data.u.sint = 0;
1474
1475 if (!ts) /* key not present */
1476 return 1;
1477
1478 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPC1);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001479 if (ptr)
1480 smp->data.u.sint = stktable_data_cast(ptr, gpc1);
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001481
Daniel Corbett3e60b112018-05-27 09:47:12 -04001482 stktable_release(t, ts);
1483 return !!ptr;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001484}
1485
1486/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1487 * it up into this table. Returns the event rate of the GPC1 counter for the key
1488 * if the key is present in the table, otherwise zero, so that comparisons can
1489 * be easily performed. If the inspected parameter is not stored in the table,
1490 * <not found> is returned.
1491 */
1492static int sample_conv_table_gpc1_rate(const struct arg *arg_p, struct sample *smp, void *private)
1493{
1494 struct stktable *t;
1495 struct stktable_key *key;
1496 struct stksess *ts;
1497 void *ptr;
1498
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001499 t = arg_p[0].data.t;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001500
1501 key = smp_to_stkey(smp, t);
1502 if (!key)
1503 return 0;
1504
1505 ts = stktable_lookup_key(t, key);
1506
1507 smp->flags = SMP_F_VOL_TEST;
1508 smp->data.type = SMP_T_SINT;
1509 smp->data.u.sint = 0;
1510
1511 if (!ts) /* key not present */
1512 return 1;
1513
1514 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPC1_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001515 if (ptr)
1516 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, gpc1_rate),
1517 t->data_arg[STKTABLE_DT_GPC1_RATE].u);
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001518
Daniel Corbett3e60b112018-05-27 09:47:12 -04001519 stktable_release(t, ts);
1520 return !!ptr;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001521}
1522
1523/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001524 * it up into this table. Returns the cumulated number of HTTP request errors
1525 * for the key if the key is present in the table, otherwise zero, so that
1526 * comparisons can be easily performed. If the inspected parameter is not stored
1527 * in the table, <not found> is returned.
1528 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001529static int sample_conv_table_http_err_cnt(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001530{
1531 struct stktable *t;
1532 struct stktable_key *key;
1533 struct stksess *ts;
1534 void *ptr;
1535
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001536 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001537
1538 key = smp_to_stkey(smp, t);
1539 if (!key)
1540 return 0;
1541
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001542 ts = stktable_lookup_key(t, key);
1543
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001544 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001545 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001546 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001547
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001548 if (!ts) /* key not present */
1549 return 1;
1550
1551 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_ERR_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001552 if (ptr)
1553 smp->data.u.sint = stktable_data_cast(ptr, http_err_cnt);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001554
Daniel Corbett3e60b112018-05-27 09:47:12 -04001555 stktable_release(t, ts);
1556 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001557}
1558
1559/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1560 * it up into this table. Returns the HTTP request error rate the key
1561 * if the key is present in the table, otherwise zero, so that comparisons can
1562 * be easily performed. If the inspected parameter is not stored in the table,
1563 * <not found> is returned.
1564 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001565static int sample_conv_table_http_err_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001566{
1567 struct stktable *t;
1568 struct stktable_key *key;
1569 struct stksess *ts;
1570 void *ptr;
1571
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001572 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001573
1574 key = smp_to_stkey(smp, t);
1575 if (!key)
1576 return 0;
1577
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001578 ts = stktable_lookup_key(t, key);
1579
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001580 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001581 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001582 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001583
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001584 if (!ts) /* key not present */
1585 return 1;
1586
1587 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_ERR_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001588 if (ptr)
1589 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, http_err_rate),
1590 t->data_arg[STKTABLE_DT_HTTP_ERR_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001591
Daniel Corbett3e60b112018-05-27 09:47:12 -04001592 stktable_release(t, ts);
1593 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001594}
1595
1596/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1597 * it up into this table. Returns the cumulated number of HTTP request for the
1598 * key if the key is present in the table, otherwise zero, so that comparisons
1599 * can be easily performed. If the inspected parameter is not stored in the
1600 * table, <not found> is returned.
1601 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001602static int sample_conv_table_http_req_cnt(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001603{
1604 struct stktable *t;
1605 struct stktable_key *key;
1606 struct stksess *ts;
1607 void *ptr;
1608
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001609 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001610
1611 key = smp_to_stkey(smp, t);
1612 if (!key)
1613 return 0;
1614
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001615 ts = stktable_lookup_key(t, key);
1616
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001617 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001618 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001619 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001620
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001621 if (!ts) /* key not present */
1622 return 1;
1623
1624 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_REQ_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001625 if (ptr)
1626 smp->data.u.sint = stktable_data_cast(ptr, http_req_cnt);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001627
Daniel Corbett3e60b112018-05-27 09:47:12 -04001628 stktable_release(t, ts);
1629 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001630}
1631
1632/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1633 * it up into this table. Returns the HTTP request rate the key if the key is
1634 * present in the table, otherwise zero, so that comparisons can be easily
1635 * performed. If the inspected parameter is not stored in the table, <not found>
1636 * is returned.
1637 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001638static int sample_conv_table_http_req_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001639{
1640 struct stktable *t;
1641 struct stktable_key *key;
1642 struct stksess *ts;
1643 void *ptr;
1644
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001645 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001646
1647 key = smp_to_stkey(smp, t);
1648 if (!key)
1649 return 0;
1650
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001651 ts = stktable_lookup_key(t, key);
1652
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001653 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001654 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001655 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001656
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001657 if (!ts) /* key not present */
1658 return 1;
1659
1660 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_REQ_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001661 if (ptr)
1662 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, http_req_rate),
1663 t->data_arg[STKTABLE_DT_HTTP_REQ_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001664
Daniel Corbett3e60b112018-05-27 09:47:12 -04001665 stktable_release(t, ts);
1666 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001667}
1668
1669/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1670 * it up into this table. Returns the volume of datareceived from clients in kbytes
1671 * if the key is present in the table, otherwise zero, so that comparisons can
1672 * be easily performed. If the inspected parameter is not stored in the table,
1673 * <not found> is returned.
1674 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001675static int sample_conv_table_kbytes_in(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001676{
1677 struct stktable *t;
1678 struct stktable_key *key;
1679 struct stksess *ts;
1680 void *ptr;
1681
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001682 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001683
1684 key = smp_to_stkey(smp, t);
1685 if (!key)
1686 return 0;
1687
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001688 ts = stktable_lookup_key(t, key);
1689
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001690 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001691 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001692 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001693
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001694 if (!ts) /* key not present */
1695 return 1;
1696
1697 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_IN_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001698 if (ptr)
1699 smp->data.u.sint = stktable_data_cast(ptr, bytes_in_cnt) >> 10;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001700
Daniel Corbett3e60b112018-05-27 09:47:12 -04001701 stktable_release(t, ts);
1702 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001703}
1704
1705/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1706 * it up into this table. Returns the volume of data sent to clients in kbytes
1707 * if the key is present in the table, otherwise zero, so that comparisons can
1708 * be easily performed. If the inspected parameter is not stored in the table,
1709 * <not found> is returned.
1710 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001711static int sample_conv_table_kbytes_out(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001712{
1713 struct stktable *t;
1714 struct stktable_key *key;
1715 struct stksess *ts;
1716 void *ptr;
1717
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001718 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001719
1720 key = smp_to_stkey(smp, t);
1721 if (!key)
1722 return 0;
1723
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001724 ts = stktable_lookup_key(t, key);
1725
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001726 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001727 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001728 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001729
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001730 if (!ts) /* key not present */
1731 return 1;
1732
1733 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_OUT_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001734 if (ptr)
1735 smp->data.u.sint = stktable_data_cast(ptr, bytes_out_cnt) >> 10;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001736
Daniel Corbett3e60b112018-05-27 09:47:12 -04001737 stktable_release(t, ts);
1738 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001739}
1740
1741/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1742 * it up into this table. Returns the server ID associated with the key if the
1743 * key is present in the table, otherwise zero, so that comparisons can be
1744 * easily performed. If the inspected parameter is not stored in the table,
1745 * <not found> is returned.
1746 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001747static int sample_conv_table_server_id(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001748{
1749 struct stktable *t;
1750 struct stktable_key *key;
1751 struct stksess *ts;
1752 void *ptr;
1753
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001754 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001755
1756 key = smp_to_stkey(smp, t);
1757 if (!key)
1758 return 0;
1759
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001760 ts = stktable_lookup_key(t, key);
1761
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001762 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001763 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001764 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001765
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001766 if (!ts) /* key not present */
1767 return 1;
1768
1769 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_SERVER_ID);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001770 if (ptr)
1771 smp->data.u.sint = stktable_data_cast(ptr, server_id);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001772
Daniel Corbett3e60b112018-05-27 09:47:12 -04001773 stktable_release(t, ts);
1774 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001775}
1776
1777/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1778 * it up into this table. Returns the cumulated number of sessions for the
1779 * key if the key is present in the table, otherwise zero, so that comparisons
1780 * can be easily performed. If the inspected parameter is not stored in the
1781 * table, <not found> is returned.
1782 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001783static int sample_conv_table_sess_cnt(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001784{
1785 struct stktable *t;
1786 struct stktable_key *key;
1787 struct stksess *ts;
1788 void *ptr;
1789
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001790 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001791
1792 key = smp_to_stkey(smp, t);
1793 if (!key)
1794 return 0;
1795
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001796 ts = stktable_lookup_key(t, key);
1797
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001798 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001799 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001800 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001801
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001802 if (!ts) /* key not present */
1803 return 1;
1804
1805 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_SESS_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001806 if (ptr)
1807 smp->data.u.sint = stktable_data_cast(ptr, sess_cnt);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001808
Daniel Corbett3e60b112018-05-27 09:47:12 -04001809 stktable_release(t, ts);
1810 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001811}
1812
1813/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1814 * it up into this table. Returns the session rate the key if the key is
1815 * present in the table, otherwise zero, so that comparisons can be easily
1816 * performed. If the inspected parameter is not stored in the table, <not found>
1817 * is returned.
1818 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001819static int sample_conv_table_sess_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001820{
1821 struct stktable *t;
1822 struct stktable_key *key;
1823 struct stksess *ts;
1824 void *ptr;
1825
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001826 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001827
1828 key = smp_to_stkey(smp, t);
1829 if (!key)
1830 return 0;
1831
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001832 ts = stktable_lookup_key(t, key);
1833
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001834 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001835 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001836 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001837
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001838 if (!ts) /* key not present */
1839 return 1;
1840
1841 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_SESS_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001842 if (ptr)
1843 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, sess_rate),
1844 t->data_arg[STKTABLE_DT_SESS_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001845
Daniel Corbett3e60b112018-05-27 09:47:12 -04001846 stktable_release(t, ts);
1847 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001848}
1849
1850/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1851 * it up into this table. Returns the amount of concurrent connections tracking
1852 * the same key if the key is present in the table, otherwise zero, so that
1853 * comparisons can be easily performed. If the inspected parameter is not
1854 * stored in the table, <not found> is returned.
1855 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001856static int sample_conv_table_trackers(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001857{
1858 struct stktable *t;
1859 struct stktable_key *key;
1860 struct stksess *ts;
1861
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001862 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001863
1864 key = smp_to_stkey(smp, t);
1865 if (!key)
1866 return 0;
1867
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001868 ts = stktable_lookup_key(t, key);
1869
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001870 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001871 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001872 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001873
Tim Duesterhus65189c12018-06-26 15:57:29 +02001874 if (!ts)
1875 return 1;
1876
1877 smp->data.u.sint = ts->ref_cnt;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001878
Daniel Corbett3e60b112018-05-27 09:47:12 -04001879 stktable_release(t, ts);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001880 return 1;
1881}
1882
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001883/* Always returns 1. */
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001884static enum act_return action_inc_gpc0(struct act_rule *rule, struct proxy *px,
Willy Tarreau658b85b2015-09-27 10:00:49 +02001885 struct session *sess, struct stream *s, int flags)
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001886{
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001887 struct stksess *ts;
1888 struct stkctr *stkctr;
1889
1890 /* Extract the stksess, return OK if no stksess available. */
1891 if (s)
1892 stkctr = &s->stkctr[rule->arg.gpc.sc];
1893 else
1894 stkctr = &sess->stkctr[rule->arg.gpc.sc];
Willy Tarreau79c1e912016-01-25 14:54:45 +01001895
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001896 ts = stkctr_entry(stkctr);
Willy Tarreau79c1e912016-01-25 14:54:45 +01001897 if (ts) {
1898 void *ptr1, *ptr2;
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001899
Willy Tarreau79c1e912016-01-25 14:54:45 +01001900 /* First, update gpc0_rate if it's tracked. Second, update its gpc0 if tracked. */
1901 ptr1 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC0_RATE);
Emeric Brun819fc6f2017-06-13 19:37:32 +02001902 ptr2 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC0);
1903 if (ptr1 || ptr2) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01001904 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02001905
1906 if (ptr1)
1907 update_freq_ctr_period(&stktable_data_cast(ptr1, gpc0_rate),
Willy Tarreau79c1e912016-01-25 14:54:45 +01001908 stkctr->table->data_arg[STKTABLE_DT_GPC0_RATE].u, 1);
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001909
Emeric Brun819fc6f2017-06-13 19:37:32 +02001910 if (ptr2)
1911 stktable_data_cast(ptr2, gpc0)++;
Willy Tarreau79c1e912016-01-25 14:54:45 +01001912
Christopher Faulet2a944ee2017-11-07 10:42:54 +01001913 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02001914
1915 /* If data was modified, we need to touch to re-schedule sync */
1916 stktable_touch_local(stkctr->table, ts, 0);
1917 }
Willy Tarreau79c1e912016-01-25 14:54:45 +01001918 }
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001919 return ACT_RET_CONT;
1920}
1921
1922/* This function is a common parser for using variables. It understands
1923 * the formats:
1924 *
1925 * sc-inc-gpc0(<stick-table ID>)
1926 *
1927 * It returns 0 if fails and <err> is filled with an error message. Otherwise,
1928 * it returns 1 and the variable <expr> is filled with the pointer to the
1929 * expression to execute.
1930 */
1931static enum act_parse_ret parse_inc_gpc0(const char **args, int *arg, struct proxy *px,
1932 struct act_rule *rule, char **err)
1933{
1934 const char *cmd_name = args[*arg-1];
1935 char *error;
1936
1937 cmd_name += strlen("sc-inc-gpc0");
1938 if (*cmd_name == '\0') {
1939 /* default stick table id. */
1940 rule->arg.gpc.sc = 0;
1941 } else {
1942 /* parse the stick table id. */
1943 if (*cmd_name != '(') {
1944 memprintf(err, "invalid stick table track ID. Expects %s(<Track ID>)", args[*arg-1]);
1945 return ACT_RET_PRS_ERR;
1946 }
1947 cmd_name++; /* jump the '(' */
1948 rule->arg.gpc.sc = strtol(cmd_name, &error, 10); /* Convert stick table id. */
1949 if (*error != ')') {
1950 memprintf(err, "invalid stick table track ID. Expects %s(<Track ID>)", args[*arg-1]);
1951 return ACT_RET_PRS_ERR;
1952 }
1953
Christopher Faulet28436e22019-12-18 10:25:46 +01001954 if (rule->arg.gpc.sc >= MAX_SESS_STKCTR) {
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001955 memprintf(err, "invalid stick table track ID. The max allowed ID is %d",
Christopher Faulet28436e22019-12-18 10:25:46 +01001956 MAX_SESS_STKCTR-1);
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001957 return ACT_RET_PRS_ERR;
1958 }
1959 }
Thierry FOURNIER42148732015-09-02 17:17:33 +02001960 rule->action = ACT_CUSTOM;
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001961 rule->action_ptr = action_inc_gpc0;
1962 return ACT_RET_PRS_OK;
1963}
1964
1965/* Always returns 1. */
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001966static enum act_return action_inc_gpc1(struct act_rule *rule, struct proxy *px,
1967 struct session *sess, struct stream *s, int flags)
1968{
1969 struct stksess *ts;
1970 struct stkctr *stkctr;
1971
1972 /* Extract the stksess, return OK if no stksess available. */
1973 if (s)
1974 stkctr = &s->stkctr[rule->arg.gpc.sc];
1975 else
1976 stkctr = &sess->stkctr[rule->arg.gpc.sc];
1977
1978 ts = stkctr_entry(stkctr);
1979 if (ts) {
1980 void *ptr1, *ptr2;
1981
1982 /* First, update gpc1_rate if it's tracked. Second, update its gpc1 if tracked. */
1983 ptr1 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC1_RATE);
1984 ptr2 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC1);
1985 if (ptr1 || ptr2) {
1986 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
1987
1988 if (ptr1)
1989 update_freq_ctr_period(&stktable_data_cast(ptr1, gpc1_rate),
1990 stkctr->table->data_arg[STKTABLE_DT_GPC1_RATE].u, 1);
1991
1992 if (ptr2)
1993 stktable_data_cast(ptr2, gpc1)++;
1994
1995 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
1996
1997 /* If data was modified, we need to touch to re-schedule sync */
1998 stktable_touch_local(stkctr->table, ts, 0);
1999 }
2000 }
2001 return ACT_RET_CONT;
2002}
2003
2004/* This function is a common parser for using variables. It understands
2005 * the formats:
2006 *
2007 * sc-inc-gpc1(<stick-table ID>)
2008 *
2009 * It returns 0 if fails and <err> is filled with an error message. Otherwise,
2010 * it returns 1 and the variable <expr> is filled with the pointer to the
2011 * expression to execute.
2012 */
2013static enum act_parse_ret parse_inc_gpc1(const char **args, int *arg, struct proxy *px,
2014 struct act_rule *rule, char **err)
2015{
2016 const char *cmd_name = args[*arg-1];
2017 char *error;
2018
2019 cmd_name += strlen("sc-inc-gpc1");
2020 if (*cmd_name == '\0') {
2021 /* default stick table id. */
2022 rule->arg.gpc.sc = 0;
2023 } else {
2024 /* parse the stick table id. */
2025 if (*cmd_name != '(') {
2026 memprintf(err, "invalid stick table track ID. Expects %s(<Track ID>)", args[*arg-1]);
2027 return ACT_RET_PRS_ERR;
2028 }
2029 cmd_name++; /* jump the '(' */
2030 rule->arg.gpc.sc = strtol(cmd_name, &error, 10); /* Convert stick table id. */
2031 if (*error != ')') {
2032 memprintf(err, "invalid stick table track ID. Expects %s(<Track ID>)", args[*arg-1]);
2033 return ACT_RET_PRS_ERR;
2034 }
2035
Christopher Faulet28436e22019-12-18 10:25:46 +01002036 if (rule->arg.gpc.sc >= MAX_SESS_STKCTR) {
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002037 memprintf(err, "invalid stick table track ID. The max allowed ID is %d",
Christopher Faulet28436e22019-12-18 10:25:46 +01002038 MAX_SESS_STKCTR-1);
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002039 return ACT_RET_PRS_ERR;
2040 }
2041 }
2042 rule->action = ACT_CUSTOM;
2043 rule->action_ptr = action_inc_gpc1;
2044 return ACT_RET_PRS_OK;
2045}
2046
2047/* Always returns 1. */
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002048static enum act_return action_set_gpt0(struct act_rule *rule, struct proxy *px,
Willy Tarreau658b85b2015-09-27 10:00:49 +02002049 struct session *sess, struct stream *s, int flags)
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002050{
2051 void *ptr;
2052 struct stksess *ts;
2053 struct stkctr *stkctr;
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002054 unsigned int value = 0;
2055 struct sample *smp;
2056 int smp_opt_dir;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002057
2058 /* Extract the stksess, return OK if no stksess available. */
2059 if (s)
2060 stkctr = &s->stkctr[rule->arg.gpt.sc];
2061 else
2062 stkctr = &sess->stkctr[rule->arg.gpt.sc];
Willy Tarreau79c1e912016-01-25 14:54:45 +01002063
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002064 ts = stkctr_entry(stkctr);
2065 if (!ts)
2066 return ACT_RET_CONT;
2067
2068 /* Store the sample in the required sc, and ignore errors. */
2069 ptr = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPT0);
Willy Tarreau79c1e912016-01-25 14:54:45 +01002070 if (ptr) {
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002071 if (!rule->arg.gpt.expr)
2072 value = (unsigned int)(rule->arg.gpt.value);
2073 else {
2074 switch (rule->from) {
2075 case ACT_F_TCP_REQ_SES: smp_opt_dir = SMP_OPT_DIR_REQ; break;
2076 case ACT_F_TCP_REQ_CNT: smp_opt_dir = SMP_OPT_DIR_REQ; break;
2077 case ACT_F_TCP_RES_CNT: smp_opt_dir = SMP_OPT_DIR_RES; break;
2078 case ACT_F_HTTP_REQ: smp_opt_dir = SMP_OPT_DIR_REQ; break;
2079 case ACT_F_HTTP_RES: smp_opt_dir = SMP_OPT_DIR_RES; break;
2080 default:
2081 send_log(px, LOG_ERR, "stick table: internal error while setting gpt0.");
2082 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))
2083 ha_alert("stick table: internal error while executing setting gpt0.\n");
2084 return ACT_RET_CONT;
2085 }
2086
2087 /* Fetch and cast the expression. */
2088 smp = sample_fetch_as_type(px, sess, s, smp_opt_dir|SMP_OPT_FINAL, rule->arg.gpt.expr, SMP_T_SINT);
2089 if (!smp) {
2090 send_log(px, LOG_WARNING, "stick table: invalid expression or data type while setting gpt0.");
2091 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))
2092 ha_alert("stick table: invalid expression or data type while setting gpt0.\n");
2093 return ACT_RET_CONT;
2094 }
2095 value = (unsigned int)(smp->data.u.sint);
2096 }
2097
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002098 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002099
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002100 stktable_data_cast(ptr, gpt0) = value;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002101
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002102 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002103
2104 stktable_touch_local(stkctr->table, ts, 0);
Willy Tarreau79c1e912016-01-25 14:54:45 +01002105 }
2106
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002107 return ACT_RET_CONT;
2108}
2109
2110/* This function is a common parser for using variables. It understands
2111 * the format:
2112 *
2113 * set-gpt0(<stick-table ID>) <expression>
2114 *
2115 * It returns 0 if fails and <err> is filled with an error message. Otherwise,
2116 * it returns 1 and the variable <expr> is filled with the pointer to the
2117 * expression to execute.
2118 */
2119static enum act_parse_ret parse_set_gpt0(const char **args, int *arg, struct proxy *px,
2120 struct act_rule *rule, char **err)
2121
2122
2123{
2124 const char *cmd_name = args[*arg-1];
2125 char *error;
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002126 int smp_val;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002127
2128 cmd_name += strlen("sc-set-gpt0");
2129 if (*cmd_name == '\0') {
2130 /* default stick table id. */
2131 rule->arg.gpt.sc = 0;
2132 } else {
2133 /* parse the stick table id. */
2134 if (*cmd_name != '(') {
2135 memprintf(err, "invalid stick table track ID '%s'. Expects sc-set-gpt0(<Track ID>)", args[*arg-1]);
2136 return ACT_RET_PRS_ERR;
2137 }
2138 cmd_name++; /* jump the '(' */
2139 rule->arg.gpt.sc = strtol(cmd_name, &error, 10); /* Convert stick table id. */
2140 if (*error != ')') {
2141 memprintf(err, "invalid stick table track ID '%s'. Expects sc-set-gpt0(<Track ID>)", args[*arg-1]);
2142 return ACT_RET_PRS_ERR;
2143 }
2144
Christopher Faulet28436e22019-12-18 10:25:46 +01002145 if (rule->arg.gpt.sc >= MAX_SESS_STKCTR) {
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002146 memprintf(err, "invalid stick table track ID '%s'. The max allowed ID is %d",
Christopher Faulet28436e22019-12-18 10:25:46 +01002147 args[*arg-1], MAX_SESS_STKCTR-1);
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002148 return ACT_RET_PRS_ERR;
2149 }
2150 }
2151
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002152 rule->arg.gpt.expr = NULL;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002153 rule->arg.gpt.value = strtol(args[*arg], &error, 10);
2154 if (*error != '\0') {
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002155 rule->arg.gpt.expr = sample_parse_expr((char **)args, arg, px->conf.args.file,
Willy Tarreaue3b57bf2020-02-14 16:50:14 +01002156 px->conf.args.line, err, &px->conf.args, NULL);
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002157 if (!rule->arg.gpt.expr)
2158 return ACT_RET_PRS_ERR;
2159
2160 switch (rule->from) {
2161 case ACT_F_TCP_REQ_SES: smp_val = SMP_VAL_FE_SES_ACC; break;
2162 case ACT_F_TCP_REQ_CNT: smp_val = SMP_VAL_FE_REQ_CNT; break;
2163 case ACT_F_TCP_RES_CNT: smp_val = SMP_VAL_BE_RES_CNT; break;
2164 case ACT_F_HTTP_REQ: smp_val = SMP_VAL_FE_HRQ_HDR; break;
2165 case ACT_F_HTTP_RES: smp_val = SMP_VAL_BE_HRS_HDR; break;
2166 default:
2167 memprintf(err, "internal error, unexpected rule->from=%d, please report this bug!", rule->from);
2168 return ACT_RET_PRS_ERR;
2169 }
2170 if (!(rule->arg.gpt.expr->fetch->val & smp_val)) {
2171 memprintf(err, "fetch method '%s' extracts information from '%s', none of which is available here", args[*arg-1],
2172 sample_src_names(rule->arg.gpt.expr->fetch->use));
2173 free(rule->arg.gpt.expr);
2174 return ACT_RET_PRS_ERR;
2175 }
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002176 }
2177 (*arg)++;
2178
Thierry FOURNIER42148732015-09-02 17:17:33 +02002179 rule->action = ACT_CUSTOM;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002180 rule->action_ptr = action_set_gpt0;
2181
2182 return ACT_RET_PRS_OK;
2183}
2184
Willy Tarreau7d562212016-11-25 16:10:05 +01002185/* set temp integer to the number of used entries in the table pointed to by expr.
2186 * Accepts exactly 1 argument of type table.
2187 */
2188static int
2189smp_fetch_table_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
2190{
2191 smp->flags = SMP_F_VOL_TEST;
2192 smp->data.type = SMP_T_SINT;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002193 smp->data.u.sint = args->data.t->current;
Willy Tarreau7d562212016-11-25 16:10:05 +01002194 return 1;
2195}
2196
2197/* set temp integer to the number of free entries in the table pointed to by expr.
2198 * Accepts exactly 1 argument of type table.
2199 */
2200static int
2201smp_fetch_table_avl(const struct arg *args, struct sample *smp, const char *kw, void *private)
2202{
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002203 struct stktable *t;
Willy Tarreau7d562212016-11-25 16:10:05 +01002204
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002205 t = args->data.t;
Willy Tarreau7d562212016-11-25 16:10:05 +01002206 smp->flags = SMP_F_VOL_TEST;
2207 smp->data.type = SMP_T_SINT;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002208 smp->data.u.sint = t->size - t->current;
Willy Tarreau7d562212016-11-25 16:10:05 +01002209 return 1;
2210}
2211
2212/* Returns a pointer to a stkctr depending on the fetch keyword name.
2213 * It is designed to be called as sc[0-9]_* sc_* or src_* exclusively.
2214 * sc[0-9]_* will return a pointer to the respective field in the
2215 * stream <l4>. sc_* requires an UINT argument specifying the stick
2216 * counter number. src_* will fill a locally allocated structure with
2217 * the table and entry corresponding to what is specified with src_*.
2218 * NULL may be returned if the designated stkctr is not tracked. For
2219 * the sc_* and sc[0-9]_* forms, an optional table argument may be
2220 * passed. When present, the currently tracked key is then looked up
2221 * in the specified table instead of the current table. The purpose is
Ilya Shipitsin47d17182020-06-21 21:42:57 +05002222 * to be able to convert multiple values per key (eg: have gpc0 from
Willy Tarreau7d562212016-11-25 16:10:05 +01002223 * multiple tables). <strm> is allowed to be NULL, in which case only
2224 * the session will be consulted.
2225 */
2226struct stkctr *
Emeric Brun819fc6f2017-06-13 19:37:32 +02002227smp_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 +01002228{
Willy Tarreau7d562212016-11-25 16:10:05 +01002229 struct stkctr *stkptr;
2230 struct stksess *stksess;
2231 unsigned int num = kw[2] - '0';
2232 int arg = 0;
2233
2234 if (num == '_' - '0') {
2235 /* sc_* variant, args[0] = ctr# (mandatory) */
2236 num = args[arg++].data.sint;
Willy Tarreau7d562212016-11-25 16:10:05 +01002237 }
2238 else if (num > 9) { /* src_* variant, args[0] = table */
2239 struct stktable_key *key;
2240 struct connection *conn = objt_conn(sess->origin);
2241 struct sample smp;
2242
2243 if (!conn)
2244 return NULL;
2245
Joseph Herlant5662fa42018-11-15 13:43:28 -08002246 /* Fetch source address in a sample. */
Willy Tarreau7d562212016-11-25 16:10:05 +01002247 smp.px = NULL;
2248 smp.sess = sess;
2249 smp.strm = strm;
Willy Tarreau478331d2020-08-28 11:31:31 +02002250 if (!smp_fetch_src || !smp_fetch_src(NULL, &smp, NULL, NULL))
Willy Tarreau7d562212016-11-25 16:10:05 +01002251 return NULL;
2252
2253 /* Converts into key. */
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002254 key = smp_to_stkey(&smp, args->data.t);
Willy Tarreau7d562212016-11-25 16:10:05 +01002255 if (!key)
2256 return NULL;
2257
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002258 stkctr->table = args->data.t;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002259 stkctr_set_entry(stkctr, stktable_lookup_key(stkctr->table, key));
2260 return stkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002261 }
2262
2263 /* Here, <num> contains the counter number from 0 to 9 for
2264 * the sc[0-9]_ form, or even higher using sc_(num) if needed.
2265 * args[arg] is the first optional argument. We first lookup the
2266 * ctr form the stream, then from the session if it was not there.
Christopher Fauleta9fa88a2019-10-21 10:53:34 +02002267 * But we must be sure the counter does not exceed MAX_SESS_STKCTR.
Willy Tarreau7d562212016-11-25 16:10:05 +01002268 */
Christopher Fauleta9fa88a2019-10-21 10:53:34 +02002269 if (num >= MAX_SESS_STKCTR)
2270 return NULL;
Willy Tarreau7d562212016-11-25 16:10:05 +01002271
2272 if (strm)
2273 stkptr = &strm->stkctr[num];
2274 if (!strm || !stkctr_entry(stkptr)) {
2275 stkptr = &sess->stkctr[num];
2276 if (!stkctr_entry(stkptr))
2277 return NULL;
2278 }
2279
2280 stksess = stkctr_entry(stkptr);
2281 if (!stksess)
2282 return NULL;
2283
2284 if (unlikely(args[arg].type == ARGT_TAB)) {
2285 /* an alternate table was specified, let's look up the same key there */
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002286 stkctr->table = args[arg].data.t;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002287 stkctr_set_entry(stkctr, stktable_lookup(stkctr->table, stksess));
2288 return stkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002289 }
2290 return stkptr;
2291}
2292
2293/* same as smp_fetch_sc_stkctr() but dedicated to src_* and can create
2294 * the entry if it doesn't exist yet. This is needed for a few fetch
2295 * functions which need to create an entry, such as src_inc_gpc* and
2296 * src_clr_gpc*.
2297 */
2298struct stkctr *
Emeric Brun819fc6f2017-06-13 19:37:32 +02002299smp_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 +01002300{
Willy Tarreau7d562212016-11-25 16:10:05 +01002301 struct stktable_key *key;
2302 struct connection *conn = objt_conn(sess->origin);
2303 struct sample smp;
2304
2305 if (strncmp(kw, "src_", 4) != 0)
2306 return NULL;
2307
2308 if (!conn)
2309 return NULL;
2310
Joseph Herlant5662fa42018-11-15 13:43:28 -08002311 /* Fetch source address in a sample. */
Willy Tarreau7d562212016-11-25 16:10:05 +01002312 smp.px = NULL;
2313 smp.sess = sess;
2314 smp.strm = strm;
Willy Tarreau478331d2020-08-28 11:31:31 +02002315 if (!smp_fetch_src || !smp_fetch_src(NULL, &smp, NULL, NULL))
Willy Tarreau7d562212016-11-25 16:10:05 +01002316 return NULL;
2317
2318 /* Converts into key. */
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002319 key = smp_to_stkey(&smp, args->data.t);
Willy Tarreau7d562212016-11-25 16:10:05 +01002320 if (!key)
2321 return NULL;
2322
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002323 stkctr->table = args->data.t;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002324 stkctr_set_entry(stkctr, stktable_get_entry(stkctr->table, key));
2325 return stkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002326}
2327
2328/* set return a boolean indicating if the requested stream counter is
2329 * currently being tracked or not.
2330 * Supports being called as "sc[0-9]_tracked" only.
2331 */
2332static int
2333smp_fetch_sc_tracked(const struct arg *args, struct sample *smp, const char *kw, void *private)
2334{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002335 struct stkctr tmpstkctr;
2336 struct stkctr *stkctr;
2337
Willy Tarreau7d562212016-11-25 16:10:05 +01002338 smp->flags = SMP_F_VOL_TEST;
2339 smp->data.type = SMP_T_BOOL;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002340 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2341 smp->data.u.sint = !!stkctr;
2342
2343 /* release the ref count */
Dirkjan Bussinkff57f1b2018-09-14 14:31:22 +02002344 if (stkctr == &tmpstkctr)
Emeric Brun819fc6f2017-06-13 19:37:32 +02002345 stktable_release(stkctr->table, stkctr_entry(stkctr));
2346
Willy Tarreau7d562212016-11-25 16:10:05 +01002347 return 1;
2348}
2349
2350/* set <smp> to the General Purpose Flag 0 value from the stream's tracked
2351 * frontend counters or from the src.
2352 * Supports being called as "sc[0-9]_get_gpc0" or "src_get_gpt0" only. Value
2353 * zero is returned if the key is new.
2354 */
2355static int
2356smp_fetch_sc_get_gpt0(const struct arg *args, struct sample *smp, const char *kw, void *private)
2357{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002358 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002359 struct stkctr *stkctr;
2360
Emeric Brun819fc6f2017-06-13 19:37:32 +02002361 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002362 if (!stkctr)
2363 return 0;
2364
2365 smp->flags = SMP_F_VOL_TEST;
2366 smp->data.type = SMP_T_SINT;
2367 smp->data.u.sint = 0;
2368
Emeric Brun819fc6f2017-06-13 19:37:32 +02002369 if (stkctr_entry(stkctr)) {
2370 void *ptr;
2371
2372 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPT0);
2373 if (!ptr) {
2374 if (stkctr == &tmpstkctr)
2375 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002376 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002377 }
2378
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002379 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002380
Willy Tarreau7d562212016-11-25 16:10:05 +01002381 smp->data.u.sint = stktable_data_cast(ptr, gpt0);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002382
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002383 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002384
2385 if (stkctr == &tmpstkctr)
2386 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002387 }
2388 return 1;
2389}
2390
2391/* set <smp> to the General Purpose Counter 0 value from the stream's tracked
2392 * frontend counters or from the src.
2393 * Supports being called as "sc[0-9]_get_gpc0" or "src_get_gpc0" only. Value
2394 * zero is returned if the key is new.
2395 */
2396static int
2397smp_fetch_sc_get_gpc0(const struct arg *args, struct sample *smp, const char *kw, void *private)
2398{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002399 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002400 struct stkctr *stkctr;
2401
Emeric Brun819fc6f2017-06-13 19:37:32 +02002402 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002403 if (!stkctr)
2404 return 0;
2405
2406 smp->flags = SMP_F_VOL_TEST;
2407 smp->data.type = SMP_T_SINT;
2408 smp->data.u.sint = 0;
2409
2410 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002411 void *ptr;
2412
2413 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0);
2414 if (!ptr) {
2415 if (stkctr == &tmpstkctr)
2416 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002417 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002418 }
2419
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002420 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002421
Willy Tarreau7d562212016-11-25 16:10:05 +01002422 smp->data.u.sint = stktable_data_cast(ptr, gpc0);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002423
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002424 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002425
2426 if (stkctr == &tmpstkctr)
2427 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002428 }
2429 return 1;
2430}
2431
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002432/* set <smp> to the General Purpose Counter 1 value from the stream's tracked
2433 * frontend counters or from the src.
2434 * Supports being called as "sc[0-9]_get_gpc1" or "src_get_gpc1" only. Value
2435 * zero is returned if the key is new.
2436 */
2437static int
2438smp_fetch_sc_get_gpc1(const struct arg *args, struct sample *smp, const char *kw, void *private)
2439{
2440 struct stkctr tmpstkctr;
2441 struct stkctr *stkctr;
2442
2443 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2444 if (!stkctr)
2445 return 0;
2446
2447 smp->flags = SMP_F_VOL_TEST;
2448 smp->data.type = SMP_T_SINT;
2449 smp->data.u.sint = 0;
2450
2451 if (stkctr_entry(stkctr) != NULL) {
2452 void *ptr;
2453
2454 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1);
2455 if (!ptr) {
2456 if (stkctr == &tmpstkctr)
2457 stktable_release(stkctr->table, stkctr_entry(stkctr));
2458 return 0; /* parameter not stored */
2459 }
2460
2461 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2462
2463 smp->data.u.sint = stktable_data_cast(ptr, gpc1);
2464
2465 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2466
2467 if (stkctr == &tmpstkctr)
2468 stktable_release(stkctr->table, stkctr_entry(stkctr));
2469 }
2470 return 1;
2471}
2472
Willy Tarreau7d562212016-11-25 16:10:05 +01002473/* set <smp> to the General Purpose Counter 0's event rate from the stream's
2474 * tracked frontend counters or from the src.
2475 * Supports being called as "sc[0-9]_gpc0_rate" or "src_gpc0_rate" only.
2476 * Value zero is returned if the key is new.
2477 */
2478static int
2479smp_fetch_sc_gpc0_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
2480{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002481 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002482 struct stkctr *stkctr;
2483
Emeric Brun819fc6f2017-06-13 19:37:32 +02002484 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002485 if (!stkctr)
2486 return 0;
2487
2488 smp->flags = SMP_F_VOL_TEST;
2489 smp->data.type = SMP_T_SINT;
2490 smp->data.u.sint = 0;
2491 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002492 void *ptr;
2493
2494 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0_RATE);
2495 if (!ptr) {
2496 if (stkctr == &tmpstkctr)
2497 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002498 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002499 }
2500
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002501 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002502
Willy Tarreau7d562212016-11-25 16:10:05 +01002503 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, gpc0_rate),
2504 stkctr->table->data_arg[STKTABLE_DT_GPC0_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002505
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002506 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002507
2508 if (stkctr == &tmpstkctr)
2509 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002510 }
2511 return 1;
2512}
2513
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002514/* set <smp> to the General Purpose Counter 1's event rate from the stream's
2515 * tracked frontend counters or from the src.
2516 * Supports being called as "sc[0-9]_gpc1_rate" or "src_gpc1_rate" only.
2517 * Value zero is returned if the key is new.
2518 */
2519static int
2520smp_fetch_sc_gpc1_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
2521{
2522 struct stkctr tmpstkctr;
2523 struct stkctr *stkctr;
2524
2525 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2526 if (!stkctr)
2527 return 0;
2528
2529 smp->flags = SMP_F_VOL_TEST;
2530 smp->data.type = SMP_T_SINT;
2531 smp->data.u.sint = 0;
2532 if (stkctr_entry(stkctr) != NULL) {
2533 void *ptr;
2534
2535 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1_RATE);
2536 if (!ptr) {
2537 if (stkctr == &tmpstkctr)
2538 stktable_release(stkctr->table, stkctr_entry(stkctr));
2539 return 0; /* parameter not stored */
2540 }
2541
2542 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2543
2544 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, gpc1_rate),
2545 stkctr->table->data_arg[STKTABLE_DT_GPC1_RATE].u);
2546
2547 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2548
2549 if (stkctr == &tmpstkctr)
2550 stktable_release(stkctr->table, stkctr_entry(stkctr));
2551 }
2552 return 1;
2553}
2554
Willy Tarreau7d562212016-11-25 16:10:05 +01002555/* Increment the General Purpose Counter 0 value from the stream's tracked
2556 * frontend counters and return it into temp integer.
2557 * Supports being called as "sc[0-9]_inc_gpc0" or "src_inc_gpc0" only.
2558 */
2559static int
2560smp_fetch_sc_inc_gpc0(const struct arg *args, struct sample *smp, const char *kw, void *private)
2561{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002562 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002563 struct stkctr *stkctr;
2564
Emeric Brun819fc6f2017-06-13 19:37:32 +02002565 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002566 if (!stkctr)
2567 return 0;
2568
2569 smp->flags = SMP_F_VOL_TEST;
2570 smp->data.type = SMP_T_SINT;
2571 smp->data.u.sint = 0;
2572
Emeric Brun819fc6f2017-06-13 19:37:32 +02002573 if (!stkctr_entry(stkctr))
2574 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002575
2576 if (stkctr && stkctr_entry(stkctr)) {
2577 void *ptr1,*ptr2;
2578
Emeric Brun819fc6f2017-06-13 19:37:32 +02002579
Willy Tarreau7d562212016-11-25 16:10:05 +01002580 /* First, update gpc0_rate if it's tracked. Second, update its
2581 * gpc0 if tracked. Returns gpc0's value otherwise the curr_ctr.
2582 */
2583 ptr1 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0_RATE);
Willy Tarreau7d562212016-11-25 16:10:05 +01002584 ptr2 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002585 if (ptr1 || ptr2) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002586 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Willy Tarreau7d562212016-11-25 16:10:05 +01002587
Emeric Brun819fc6f2017-06-13 19:37:32 +02002588 if (ptr1) {
2589 update_freq_ctr_period(&stktable_data_cast(ptr1, gpc0_rate),
2590 stkctr->table->data_arg[STKTABLE_DT_GPC0_RATE].u, 1);
2591 smp->data.u.sint = (&stktable_data_cast(ptr1, gpc0_rate))->curr_ctr;
2592 }
2593
2594 if (ptr2)
2595 smp->data.u.sint = ++stktable_data_cast(ptr2, gpc0);
2596
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002597 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002598
2599 /* If data was modified, we need to touch to re-schedule sync */
2600 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
2601 }
2602 else if (stkctr == &tmpstkctr)
2603 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002604 }
2605 return 1;
2606}
2607
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002608/* Increment the General Purpose Counter 1 value from the stream's tracked
2609 * frontend counters and return it into temp integer.
2610 * Supports being called as "sc[0-9]_inc_gpc1" or "src_inc_gpc1" only.
2611 */
2612static int
2613smp_fetch_sc_inc_gpc1(const struct arg *args, struct sample *smp, const char *kw, void *private)
2614{
2615 struct stkctr tmpstkctr;
2616 struct stkctr *stkctr;
2617
2618 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2619 if (!stkctr)
2620 return 0;
2621
2622 smp->flags = SMP_F_VOL_TEST;
2623 smp->data.type = SMP_T_SINT;
2624 smp->data.u.sint = 0;
2625
2626 if (!stkctr_entry(stkctr))
2627 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2628
2629 if (stkctr && stkctr_entry(stkctr)) {
2630 void *ptr1,*ptr2;
2631
2632
2633 /* First, update gpc1_rate if it's tracked. Second, update its
2634 * gpc1 if tracked. Returns gpc1's value otherwise the curr_ctr.
2635 */
2636 ptr1 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1_RATE);
2637 ptr2 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1);
2638 if (ptr1 || ptr2) {
2639 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2640
2641 if (ptr1) {
2642 update_freq_ctr_period(&stktable_data_cast(ptr1, gpc1_rate),
2643 stkctr->table->data_arg[STKTABLE_DT_GPC1_RATE].u, 1);
2644 smp->data.u.sint = (&stktable_data_cast(ptr1, gpc1_rate))->curr_ctr;
2645 }
2646
2647 if (ptr2)
2648 smp->data.u.sint = ++stktable_data_cast(ptr2, gpc1);
2649
2650 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2651
2652 /* If data was modified, we need to touch to re-schedule sync */
2653 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
2654 }
2655 else if (stkctr == &tmpstkctr)
2656 stktable_release(stkctr->table, stkctr_entry(stkctr));
2657 }
2658 return 1;
2659}
2660
Willy Tarreau7d562212016-11-25 16:10:05 +01002661/* Clear the General Purpose Counter 0 value from the stream's tracked
2662 * frontend counters and return its previous value into temp integer.
2663 * Supports being called as "sc[0-9]_clr_gpc0" or "src_clr_gpc0" only.
2664 */
2665static int
2666smp_fetch_sc_clr_gpc0(const struct arg *args, struct sample *smp, const char *kw, void *private)
2667{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002668 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002669 struct stkctr *stkctr;
2670
Emeric Brun819fc6f2017-06-13 19:37:32 +02002671 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002672 if (!stkctr)
2673 return 0;
2674
2675 smp->flags = SMP_F_VOL_TEST;
2676 smp->data.type = SMP_T_SINT;
2677 smp->data.u.sint = 0;
2678
Emeric Brun819fc6f2017-06-13 19:37:32 +02002679 if (!stkctr_entry(stkctr))
2680 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002681
Emeric Brun819fc6f2017-06-13 19:37:32 +02002682 if (stkctr && stkctr_entry(stkctr)) {
2683 void *ptr;
2684
2685 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0);
2686 if (!ptr) {
2687 if (stkctr == &tmpstkctr)
2688 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002689 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002690 }
2691
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002692 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002693
Willy Tarreau7d562212016-11-25 16:10:05 +01002694 smp->data.u.sint = stktable_data_cast(ptr, gpc0);
2695 stktable_data_cast(ptr, gpc0) = 0;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002696
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002697 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002698
Willy Tarreau7d562212016-11-25 16:10:05 +01002699 /* If data was modified, we need to touch to re-schedule sync */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002700 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
Willy Tarreau7d562212016-11-25 16:10:05 +01002701 }
2702 return 1;
2703}
2704
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002705/* Clear the General Purpose Counter 1 value from the stream's tracked
2706 * frontend counters and return its previous value into temp integer.
2707 * Supports being called as "sc[0-9]_clr_gpc1" or "src_clr_gpc1" only.
2708 */
2709static int
2710smp_fetch_sc_clr_gpc1(const struct arg *args, struct sample *smp, const char *kw, void *private)
2711{
2712 struct stkctr tmpstkctr;
2713 struct stkctr *stkctr;
2714
2715 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2716 if (!stkctr)
2717 return 0;
2718
2719 smp->flags = SMP_F_VOL_TEST;
2720 smp->data.type = SMP_T_SINT;
2721 smp->data.u.sint = 0;
2722
2723 if (!stkctr_entry(stkctr))
2724 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2725
2726 if (stkctr && stkctr_entry(stkctr)) {
2727 void *ptr;
2728
2729 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1);
2730 if (!ptr) {
2731 if (stkctr == &tmpstkctr)
2732 stktable_release(stkctr->table, stkctr_entry(stkctr));
2733 return 0; /* parameter not stored */
2734 }
2735
2736 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2737
2738 smp->data.u.sint = stktable_data_cast(ptr, gpc1);
2739 stktable_data_cast(ptr, gpc1) = 0;
2740
2741 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2742
2743 /* If data was modified, we need to touch to re-schedule sync */
2744 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
2745 }
2746 return 1;
2747}
2748
Willy Tarreau7d562212016-11-25 16:10:05 +01002749/* set <smp> to the cumulated number of connections from the stream's tracked
2750 * frontend counters. Supports being called as "sc[0-9]_conn_cnt" or
2751 * "src_conn_cnt" only.
2752 */
2753static int
2754smp_fetch_sc_conn_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
2755{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002756 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002757 struct stkctr *stkctr;
2758
Emeric Brun819fc6f2017-06-13 19:37:32 +02002759 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002760 if (!stkctr)
2761 return 0;
2762
2763 smp->flags = SMP_F_VOL_TEST;
2764 smp->data.type = SMP_T_SINT;
2765 smp->data.u.sint = 0;
2766 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002767 void *ptr;
2768
2769 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_CONN_CNT);
2770 if (!ptr) {
2771 if (stkctr == &tmpstkctr)
2772 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002773 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002774 }
2775
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002776 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002777
Willy Tarreau7d562212016-11-25 16:10:05 +01002778 smp->data.u.sint = stktable_data_cast(ptr, conn_cnt);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002779
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002780 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002781
2782 if (stkctr == &tmpstkctr)
2783 stktable_release(stkctr->table, stkctr_entry(stkctr));
2784
2785
Willy Tarreau7d562212016-11-25 16:10:05 +01002786 }
2787 return 1;
2788}
2789
2790/* set <smp> to the connection rate from the stream's tracked frontend
2791 * counters. Supports being called as "sc[0-9]_conn_rate" or "src_conn_rate"
2792 * only.
2793 */
2794static int
2795smp_fetch_sc_conn_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
2796{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002797 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002798 struct stkctr *stkctr;
2799
Emeric Brun819fc6f2017-06-13 19:37:32 +02002800 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002801 if (!stkctr)
2802 return 0;
2803
2804 smp->flags = SMP_F_VOL_TEST;
2805 smp->data.type = SMP_T_SINT;
2806 smp->data.u.sint = 0;
2807 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002808 void *ptr;
2809
2810 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_CONN_RATE);
2811 if (!ptr) {
2812 if (stkctr == &tmpstkctr)
2813 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002814 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002815 }
2816
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002817 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002818
Willy Tarreau7d562212016-11-25 16:10:05 +01002819 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, conn_rate),
2820 stkctr->table->data_arg[STKTABLE_DT_CONN_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002821
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002822 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002823
2824 if (stkctr == &tmpstkctr)
2825 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002826 }
2827 return 1;
2828}
2829
2830/* set temp integer to the number of connections from the stream's source address
2831 * in the table pointed to by expr, after updating it.
2832 * Accepts exactly 1 argument of type table.
2833 */
2834static int
2835smp_fetch_src_updt_conn_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
2836{
2837 struct connection *conn = objt_conn(smp->sess->origin);
2838 struct stksess *ts;
2839 struct stktable_key *key;
2840 void *ptr;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002841 struct stktable *t;
Willy Tarreau7d562212016-11-25 16:10:05 +01002842
2843 if (!conn)
2844 return 0;
2845
Joseph Herlant5662fa42018-11-15 13:43:28 -08002846 /* Fetch source address in a sample. */
Willy Tarreau478331d2020-08-28 11:31:31 +02002847 if (!smp_fetch_src || !smp_fetch_src(NULL, smp, NULL, NULL))
Willy Tarreau7d562212016-11-25 16:10:05 +01002848 return 0;
2849
2850 /* Converts into key. */
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002851 key = smp_to_stkey(smp, args->data.t);
Willy Tarreau7d562212016-11-25 16:10:05 +01002852 if (!key)
2853 return 0;
2854
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002855 t = args->data.t;
Willy Tarreau7d562212016-11-25 16:10:05 +01002856
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002857 if ((ts = stktable_get_entry(t, key)) == NULL)
Willy Tarreau7d562212016-11-25 16:10:05 +01002858 /* entry does not exist and could not be created */
2859 return 0;
2860
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002861 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_CONN_CNT);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002862 if (!ptr) {
Willy Tarreau7d562212016-11-25 16:10:05 +01002863 return 0; /* parameter not stored in this table */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002864 }
Willy Tarreau7d562212016-11-25 16:10:05 +01002865
2866 smp->data.type = SMP_T_SINT;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002867
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002868 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002869
Willy Tarreau7d562212016-11-25 16:10:05 +01002870 smp->data.u.sint = ++stktable_data_cast(ptr, conn_cnt);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002871
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002872 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002873
Willy Tarreau7d562212016-11-25 16:10:05 +01002874 smp->flags = SMP_F_VOL_TEST;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002875
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002876 stktable_touch_local(t, ts, 1);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002877
2878 /* Touch was previously performed by stktable_update_key */
Willy Tarreau7d562212016-11-25 16:10:05 +01002879 return 1;
2880}
2881
2882/* set <smp> to the number of concurrent connections from the stream's tracked
2883 * frontend counters. Supports being called as "sc[0-9]_conn_cur" or
2884 * "src_conn_cur" only.
2885 */
2886static int
2887smp_fetch_sc_conn_cur(const struct arg *args, struct sample *smp, const char *kw, void *private)
2888{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002889 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002890 struct stkctr *stkctr;
2891
Emeric Brun819fc6f2017-06-13 19:37:32 +02002892 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002893 if (!stkctr)
2894 return 0;
2895
2896 smp->flags = SMP_F_VOL_TEST;
2897 smp->data.type = SMP_T_SINT;
2898 smp->data.u.sint = 0;
2899 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002900 void *ptr;
2901
2902 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_CONN_CUR);
2903 if (!ptr) {
2904 if (stkctr == &tmpstkctr)
2905 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002906 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002907 }
2908
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002909 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002910
Willy Tarreau7d562212016-11-25 16:10:05 +01002911 smp->data.u.sint = stktable_data_cast(ptr, conn_cur);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002912
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002913 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002914
2915 if (stkctr == &tmpstkctr)
2916 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002917 }
2918 return 1;
2919}
2920
2921/* set <smp> to the cumulated number of streams from the stream's tracked
2922 * frontend counters. Supports being called as "sc[0-9]_sess_cnt" or
2923 * "src_sess_cnt" only.
2924 */
2925static int
2926smp_fetch_sc_sess_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
2927{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002928 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002929 struct stkctr *stkctr;
2930
Emeric Brun819fc6f2017-06-13 19:37:32 +02002931 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002932 if (!stkctr)
2933 return 0;
2934
2935 smp->flags = SMP_F_VOL_TEST;
2936 smp->data.type = SMP_T_SINT;
2937 smp->data.u.sint = 0;
2938 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002939 void *ptr;
2940
2941 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_SESS_CNT);
2942 if (!ptr) {
2943 if (stkctr == &tmpstkctr)
2944 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002945 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002946 }
2947
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002948 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002949
Willy Tarreau7d562212016-11-25 16:10:05 +01002950 smp->data.u.sint = stktable_data_cast(ptr, sess_cnt);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002951
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002952 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002953
2954 if (stkctr == &tmpstkctr)
2955 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002956 }
2957 return 1;
2958}
2959
2960/* set <smp> to the stream rate from the stream's tracked frontend counters.
2961 * Supports being called as "sc[0-9]_sess_rate" or "src_sess_rate" only.
2962 */
2963static int
2964smp_fetch_sc_sess_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
2965{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002966 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002967 struct stkctr *stkctr;
2968
Emeric Brun819fc6f2017-06-13 19:37:32 +02002969 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002970 if (!stkctr)
2971 return 0;
2972
2973 smp->flags = SMP_F_VOL_TEST;
2974 smp->data.type = SMP_T_SINT;
2975 smp->data.u.sint = 0;
2976 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002977 void *ptr;
2978
2979 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_SESS_RATE);
2980 if (!ptr) {
2981 if (stkctr == &tmpstkctr)
2982 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002983 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002984 }
2985
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002986 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002987
Willy Tarreau7d562212016-11-25 16:10:05 +01002988 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, sess_rate),
2989 stkctr->table->data_arg[STKTABLE_DT_SESS_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002990
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002991 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002992
2993 if (stkctr == &tmpstkctr)
2994 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002995 }
2996 return 1;
2997}
2998
2999/* set <smp> to the cumulated number of HTTP requests from the stream's tracked
3000 * frontend counters. Supports being called as "sc[0-9]_http_req_cnt" or
3001 * "src_http_req_cnt" only.
3002 */
3003static int
3004smp_fetch_sc_http_req_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
3005{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003006 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003007 struct stkctr *stkctr;
3008
Emeric Brun819fc6f2017-06-13 19:37:32 +02003009 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003010 if (!stkctr)
3011 return 0;
3012
3013 smp->flags = SMP_F_VOL_TEST;
3014 smp->data.type = SMP_T_SINT;
3015 smp->data.u.sint = 0;
3016 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003017 void *ptr;
3018
3019 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_REQ_CNT);
3020 if (!ptr) {
3021 if (stkctr == &tmpstkctr)
3022 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003023 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003024 }
3025
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003026 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003027
Willy Tarreau7d562212016-11-25 16:10:05 +01003028 smp->data.u.sint = stktable_data_cast(ptr, http_req_cnt);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003029
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003030 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003031
3032 if (stkctr == &tmpstkctr)
3033 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003034 }
3035 return 1;
3036}
3037
3038/* set <smp> to the HTTP request rate from the stream's tracked frontend
3039 * counters. Supports being called as "sc[0-9]_http_req_rate" or
3040 * "src_http_req_rate" only.
3041 */
3042static int
3043smp_fetch_sc_http_req_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3044{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003045 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003046 struct stkctr *stkctr;
3047
Emeric Brun819fc6f2017-06-13 19:37:32 +02003048 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003049 if (!stkctr)
3050 return 0;
3051
3052 smp->flags = SMP_F_VOL_TEST;
3053 smp->data.type = SMP_T_SINT;
3054 smp->data.u.sint = 0;
3055 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003056 void *ptr;
3057
3058 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_REQ_RATE);
3059 if (!ptr) {
3060 if (stkctr == &tmpstkctr)
3061 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003062 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003063 }
3064
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003065 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003066
Willy Tarreau7d562212016-11-25 16:10:05 +01003067 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, http_req_rate),
3068 stkctr->table->data_arg[STKTABLE_DT_HTTP_REQ_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003069
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003070 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003071
3072 if (stkctr == &tmpstkctr)
3073 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003074 }
3075 return 1;
3076}
3077
3078/* set <smp> to the cumulated number of HTTP requests errors from the stream's
3079 * tracked frontend counters. Supports being called as "sc[0-9]_http_err_cnt" or
3080 * "src_http_err_cnt" only.
3081 */
3082static int
3083smp_fetch_sc_http_err_cnt(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_HTTP_ERR_CNT);
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 = stktable_data_cast(ptr, http_err_cnt);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003108
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003109 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003110
3111 if (stkctr == &tmpstkctr)
3112 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003113 }
3114 return 1;
3115}
3116
3117/* set <smp> to the HTTP request error rate from the stream's tracked frontend
3118 * counters. Supports being called as "sc[0-9]_http_err_rate" or
3119 * "src_http_err_rate" only.
3120 */
3121static int
3122smp_fetch_sc_http_err_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3123{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003124 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003125 struct stkctr *stkctr;
3126
Emeric Brun819fc6f2017-06-13 19:37:32 +02003127 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003128 if (!stkctr)
3129 return 0;
3130
3131 smp->flags = SMP_F_VOL_TEST;
3132 smp->data.type = SMP_T_SINT;
3133 smp->data.u.sint = 0;
3134 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003135 void *ptr;
3136
3137 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_ERR_RATE);
3138 if (!ptr) {
3139 if (stkctr == &tmpstkctr)
3140 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003141 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003142 }
3143
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003144 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003145
Willy Tarreau7d562212016-11-25 16:10:05 +01003146 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, http_err_rate),
3147 stkctr->table->data_arg[STKTABLE_DT_HTTP_ERR_RATE].u);
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 number of kbytes received from clients, as found in the
3158 * stream's tracked frontend counters. Supports being called as
3159 * "sc[0-9]_kbytes_in" or "src_kbytes_in" only.
3160 */
3161static int
3162smp_fetch_sc_kbytes_in(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_BYTES_IN_CNT);
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 = stktable_data_cast(ptr, bytes_in_cnt) >> 10;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003187
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003188 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003189
3190 if (stkctr == &tmpstkctr)
3191 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003192 }
3193 return 1;
3194}
3195
3196/* set <smp> to the data rate received from clients in bytes/s, as found
3197 * in the stream's tracked frontend counters. Supports being called as
3198 * "sc[0-9]_bytes_in_rate" or "src_bytes_in_rate" only.
3199 */
3200static int
3201smp_fetch_sc_bytes_in_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3202{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003203 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003204 struct stkctr *stkctr;
3205
Emeric Brun819fc6f2017-06-13 19:37:32 +02003206 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003207 if (!stkctr)
3208 return 0;
3209
3210 smp->flags = SMP_F_VOL_TEST;
3211 smp->data.type = SMP_T_SINT;
3212 smp->data.u.sint = 0;
3213 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003214 void *ptr;
3215
3216 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_IN_RATE);
3217 if (!ptr) {
3218 if (stkctr == &tmpstkctr)
3219 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003220 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003221 }
3222
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003223 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003224
Willy Tarreau7d562212016-11-25 16:10:05 +01003225 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, bytes_in_rate),
3226 stkctr->table->data_arg[STKTABLE_DT_BYTES_IN_RATE].u);
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 number of kbytes sent to clients, as found in the
3237 * stream's tracked frontend counters. Supports being called as
3238 * "sc[0-9]_kbytes_out" or "src_kbytes_out" only.
3239 */
3240static int
3241smp_fetch_sc_kbytes_out(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_BYTES_OUT_CNT);
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 = stktable_data_cast(ptr, bytes_out_cnt) >> 10;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003266
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003267 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003268
3269 if (stkctr == &tmpstkctr)
3270 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003271 }
3272 return 1;
3273}
3274
3275/* set <smp> to the data rate sent to clients in bytes/s, as found in the
3276 * stream's tracked frontend counters. Supports being called as
3277 * "sc[0-9]_bytes_out_rate" or "src_bytes_out_rate" only.
3278 */
3279static int
3280smp_fetch_sc_bytes_out_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3281{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003282 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003283 struct stkctr *stkctr;
3284
Emeric Brun819fc6f2017-06-13 19:37:32 +02003285 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003286 if (!stkctr)
3287 return 0;
3288
3289 smp->flags = SMP_F_VOL_TEST;
3290 smp->data.type = SMP_T_SINT;
3291 smp->data.u.sint = 0;
3292 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003293 void *ptr;
3294
3295 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_OUT_RATE);
3296 if (!ptr) {
3297 if (stkctr == &tmpstkctr)
3298 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003299 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003300 }
3301
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003302 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003303
Willy Tarreau7d562212016-11-25 16:10:05 +01003304 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, bytes_out_rate),
3305 stkctr->table->data_arg[STKTABLE_DT_BYTES_OUT_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003306
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003307 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003308
3309 if (stkctr == &tmpstkctr)
3310 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003311 }
3312 return 1;
3313}
3314
3315/* set <smp> to the number of active trackers on the SC entry in the stream's
3316 * tracked frontend counters. Supports being called as "sc[0-9]_trackers" only.
3317 */
3318static int
3319smp_fetch_sc_trackers(const struct arg *args, struct sample *smp, const char *kw, void *private)
3320{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003321 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003322 struct stkctr *stkctr;
3323
Emeric Brun819fc6f2017-06-13 19:37:32 +02003324 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003325 if (!stkctr)
3326 return 0;
3327
3328 smp->flags = SMP_F_VOL_TEST;
3329 smp->data.type = SMP_T_SINT;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003330 if (stkctr == &tmpstkctr) {
3331 smp->data.u.sint = stkctr_entry(stkctr) ? (stkctr_entry(stkctr)->ref_cnt-1) : 0;
3332 stktable_release(stkctr->table, stkctr_entry(stkctr));
3333 }
3334 else {
3335 smp->data.u.sint = stkctr_entry(stkctr) ? stkctr_entry(stkctr)->ref_cnt : 0;
3336 }
3337
Willy Tarreau7d562212016-11-25 16:10:05 +01003338 return 1;
3339}
3340
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003341
3342/* The functions below are used to manipulate table contents from the CLI.
3343 * There are 3 main actions, "clear", "set" and "show". The code is shared
3344 * between all actions, and the action is encoded in the void *private in
3345 * the appctx as well as in the keyword registration, among one of the
3346 * following values.
3347 */
3348
3349enum {
3350 STK_CLI_ACT_CLR,
3351 STK_CLI_ACT_SET,
3352 STK_CLI_ACT_SHOW,
3353};
3354
3355/* Dump the status of a table to a stream interface's
3356 * read buffer. It returns 0 if the output buffer is full
3357 * and needs to be called again, otherwise non-zero.
3358 */
Willy Tarreau83061a82018-07-13 11:56:34 +02003359static int table_dump_head_to_buffer(struct buffer *msg,
3360 struct stream_interface *si,
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003361 struct stktable *t, struct stktable *target)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003362{
3363 struct stream *s = si_strm(si);
3364
3365 chunk_appendf(msg, "# table: %s, type: %s, size:%d, used:%d\n",
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003366 t->id, stktable_types[t->type].kw, t->size, t->current);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003367
3368 /* any other information should be dumped here */
3369
William Lallemand07a62f72017-05-24 00:57:40 +02003370 if (target && (strm_li(s)->bind_conf->level & ACCESS_LVL_MASK) < ACCESS_LVL_OPER)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003371 chunk_appendf(msg, "# contents not dumped due to insufficient privileges\n");
3372
Willy Tarreau06d80a92017-10-19 14:32:15 +02003373 if (ci_putchk(si_ic(si), msg) == -1) {
Willy Tarreaudb398432018-11-15 11:08:52 +01003374 si_rx_room_blk(si);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003375 return 0;
3376 }
3377
3378 return 1;
3379}
3380
3381/* Dump a table entry to a stream interface's
3382 * read buffer. It returns 0 if the output buffer is full
3383 * and needs to be called again, otherwise non-zero.
3384 */
Willy Tarreau83061a82018-07-13 11:56:34 +02003385static int table_dump_entry_to_buffer(struct buffer *msg,
3386 struct stream_interface *si,
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003387 struct stktable *t, struct stksess *entry)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003388{
3389 int dt;
3390
3391 chunk_appendf(msg, "%p:", entry);
3392
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003393 if (t->type == SMP_T_IPV4) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003394 char addr[INET_ADDRSTRLEN];
3395 inet_ntop(AF_INET, (const void *)&entry->key.key, addr, sizeof(addr));
3396 chunk_appendf(msg, " key=%s", addr);
3397 }
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003398 else if (t->type == SMP_T_IPV6) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003399 char addr[INET6_ADDRSTRLEN];
3400 inet_ntop(AF_INET6, (const void *)&entry->key.key, addr, sizeof(addr));
3401 chunk_appendf(msg, " key=%s", addr);
3402 }
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003403 else if (t->type == SMP_T_SINT) {
Willy Tarreau6cde5d82020-02-25 09:41:22 +01003404 chunk_appendf(msg, " key=%u", read_u32(entry->key.key));
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003405 }
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003406 else if (t->type == SMP_T_STR) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003407 chunk_appendf(msg, " key=");
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003408 dump_text(msg, (const char *)entry->key.key, t->key_size);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003409 }
3410 else {
3411 chunk_appendf(msg, " key=");
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003412 dump_binary(msg, (const char *)entry->key.key, t->key_size);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003413 }
3414
3415 chunk_appendf(msg, " use=%d exp=%d", entry->ref_cnt - 1, tick_remain(now_ms, entry->expire));
3416
3417 for (dt = 0; dt < STKTABLE_DATA_TYPES; dt++) {
3418 void *ptr;
3419
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003420 if (t->data_ofs[dt] == 0)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003421 continue;
3422 if (stktable_data_types[dt].arg_type == ARG_T_DELAY)
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003423 chunk_appendf(msg, " %s(%d)=", stktable_data_types[dt].name, t->data_arg[dt].u);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003424 else
3425 chunk_appendf(msg, " %s=", stktable_data_types[dt].name);
3426
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003427 ptr = stktable_data_ptr(t, entry, dt);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003428 switch (stktable_data_types[dt].std_type) {
3429 case STD_T_SINT:
3430 chunk_appendf(msg, "%d", stktable_data_cast(ptr, std_t_sint));
3431 break;
3432 case STD_T_UINT:
3433 chunk_appendf(msg, "%u", stktable_data_cast(ptr, std_t_uint));
3434 break;
3435 case STD_T_ULL:
3436 chunk_appendf(msg, "%lld", stktable_data_cast(ptr, std_t_ull));
3437 break;
3438 case STD_T_FRQP:
3439 chunk_appendf(msg, "%d",
3440 read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003441 t->data_arg[dt].u));
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003442 break;
Frédéric Lécaille16b4f542019-05-23 12:15:04 +02003443 case STD_T_DICT: {
3444 struct dict_entry *de;
3445 de = stktable_data_cast(ptr, std_t_dict);
3446 chunk_appendf(msg, "%s", de ? (char *)de->value.key : "-");
3447 break;
3448 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003449 }
3450 }
3451 chunk_appendf(msg, "\n");
3452
Willy Tarreau06d80a92017-10-19 14:32:15 +02003453 if (ci_putchk(si_ic(si), msg) == -1) {
Willy Tarreaudb398432018-11-15 11:08:52 +01003454 si_rx_room_blk(si);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003455 return 0;
3456 }
3457
3458 return 1;
3459}
3460
3461
3462/* Processes a single table entry matching a specific key passed in argument.
3463 * returns 0 if wants to be called again, 1 if has ended processing.
3464 */
3465static int table_process_entry_per_key(struct appctx *appctx, char **args)
3466{
3467 struct stream_interface *si = appctx->owner;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003468 struct stktable *t = appctx->ctx.table.target;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003469 struct stksess *ts;
3470 uint32_t uint32_key;
3471 unsigned char ip6_key[sizeof(struct in6_addr)];
3472 long long value;
3473 int data_type;
3474 int cur_arg;
3475 void *ptr;
3476 struct freq_ctr_period *frqp;
3477
Willy Tarreau9d008692019-08-09 11:21:01 +02003478 if (!*args[4])
3479 return cli_err(appctx, "Key value expected\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003480
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003481 switch (t->type) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003482 case SMP_T_IPV4:
3483 uint32_key = htonl(inetaddr_host(args[4]));
Christopher Fauletca20d022017-08-29 15:30:31 +02003484 static_table_key.key = &uint32_key;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003485 break;
3486 case SMP_T_IPV6:
3487 inet_pton(AF_INET6, args[4], ip6_key);
Christopher Fauletca20d022017-08-29 15:30:31 +02003488 static_table_key.key = &ip6_key;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003489 break;
3490 case SMP_T_SINT:
3491 {
3492 char *endptr;
3493 unsigned long val;
3494 errno = 0;
3495 val = strtoul(args[4], &endptr, 10);
3496 if ((errno == ERANGE && val == ULONG_MAX) ||
3497 (errno != 0 && val == 0) || endptr == args[4] ||
Willy Tarreau9d008692019-08-09 11:21:01 +02003498 val > 0xffffffff)
3499 return cli_err(appctx, "Invalid key\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003500 uint32_key = (uint32_t) val;
Christopher Fauletca20d022017-08-29 15:30:31 +02003501 static_table_key.key = &uint32_key;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003502 break;
3503 }
3504 break;
3505 case SMP_T_STR:
Christopher Fauletca20d022017-08-29 15:30:31 +02003506 static_table_key.key = args[4];
3507 static_table_key.key_len = strlen(args[4]);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003508 break;
3509 default:
Willy Tarreaua24bc782016-12-14 15:50:35 +01003510 switch (appctx->ctx.table.action) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003511 case STK_CLI_ACT_SHOW:
Willy Tarreau9d008692019-08-09 11:21:01 +02003512 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 +01003513 case STK_CLI_ACT_CLR:
Willy Tarreau9d008692019-08-09 11:21:01 +02003514 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 +01003515 case STK_CLI_ACT_SET:
Willy Tarreau9d008692019-08-09 11:21:01 +02003516 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 +01003517 default:
Willy Tarreau9d008692019-08-09 11:21:01 +02003518 return cli_err(appctx, "Unknown action\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003519 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003520 }
3521
3522 /* check permissions */
3523 if (!cli_has_level(appctx, ACCESS_LVL_OPER))
3524 return 1;
3525
Willy Tarreaua24bc782016-12-14 15:50:35 +01003526 switch (appctx->ctx.table.action) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003527 case STK_CLI_ACT_SHOW:
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003528 ts = stktable_lookup_key(t, &static_table_key);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003529 if (!ts)
3530 return 1;
3531 chunk_reset(&trash);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003532 if (!table_dump_head_to_buffer(&trash, si, t, t)) {
3533 stktable_release(t, ts);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003534 return 0;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003535 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003536 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003537 if (!table_dump_entry_to_buffer(&trash, si, t, ts)) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003538 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003539 stktable_release(t, ts);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003540 return 0;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003541 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003542 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003543 stktable_release(t, ts);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003544 break;
3545
3546 case STK_CLI_ACT_CLR:
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003547 ts = stktable_lookup_key(t, &static_table_key);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003548 if (!ts)
3549 return 1;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003550
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003551 if (!stksess_kill(t, ts, 1)) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003552 /* don't delete an entry which is currently referenced */
Willy Tarreau9d008692019-08-09 11:21:01 +02003553 return cli_err(appctx, "Entry currently in use, cannot remove\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003554 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003555 break;
3556
3557 case STK_CLI_ACT_SET:
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003558 ts = stktable_get_entry(t, &static_table_key);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003559 if (!ts) {
3560 /* don't delete an entry which is currently referenced */
Willy Tarreau9d008692019-08-09 11:21:01 +02003561 return cli_err(appctx, "Unable to allocate a new entry\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003562 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003563 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003564 for (cur_arg = 5; *args[cur_arg]; cur_arg += 2) {
3565 if (strncmp(args[cur_arg], "data.", 5) != 0) {
Willy Tarreau9d008692019-08-09 11:21:01 +02003566 cli_err(appctx, "\"data.<type>\" followed by a value expected\n");
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003567 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003568 stktable_touch_local(t, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003569 return 1;
3570 }
3571
3572 data_type = stktable_get_data_type(args[cur_arg] + 5);
3573 if (data_type < 0) {
Willy Tarreau9d008692019-08-09 11:21:01 +02003574 cli_err(appctx, "Unknown data type\n");
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003575 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003576 stktable_touch_local(t, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003577 return 1;
3578 }
3579
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003580 if (!t->data_ofs[data_type]) {
Willy Tarreau9d008692019-08-09 11:21:01 +02003581 cli_err(appctx, "Data type not stored in this table\n");
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003582 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003583 stktable_touch_local(t, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003584 return 1;
3585 }
3586
3587 if (!*args[cur_arg+1] || strl2llrc(args[cur_arg+1], strlen(args[cur_arg+1]), &value) != 0) {
Willy Tarreau9d008692019-08-09 11:21:01 +02003588 cli_err(appctx, "Require a valid integer value to store\n");
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003589 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003590 stktable_touch_local(t, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003591 return 1;
3592 }
3593
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003594 ptr = stktable_data_ptr(t, ts, data_type);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003595
3596 switch (stktable_data_types[data_type].std_type) {
3597 case STD_T_SINT:
3598 stktable_data_cast(ptr, std_t_sint) = value;
3599 break;
3600 case STD_T_UINT:
3601 stktable_data_cast(ptr, std_t_uint) = value;
3602 break;
3603 case STD_T_ULL:
3604 stktable_data_cast(ptr, std_t_ull) = value;
3605 break;
3606 case STD_T_FRQP:
3607 /* We set both the current and previous values. That way
3608 * the reported frequency is stable during all the period
3609 * then slowly fades out. This allows external tools to
3610 * push measures without having to update them too often.
3611 */
3612 frqp = &stktable_data_cast(ptr, std_t_frqp);
Emeric Brunf2fc1fd2017-11-02 17:32:43 +01003613 /* First bit is reserved for the freq_ctr_period lock
3614 Note: here we're still protected by the stksess lock
3615 so we don't need to update the update the freq_ctr_period
3616 using its internal lock */
3617 frqp->curr_tick = now_ms & ~0x1;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003618 frqp->prev_ctr = 0;
3619 frqp->curr_ctr = value;
3620 break;
3621 }
3622 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003623 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003624 stktable_touch_local(t, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003625 break;
3626
3627 default:
Willy Tarreau9d008692019-08-09 11:21:01 +02003628 return cli_err(appctx, "Unknown action\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003629 }
3630 return 1;
3631}
3632
3633/* Prepares the appctx fields with the data-based filters from the command line.
3634 * Returns 0 if the dump can proceed, 1 if has ended processing.
3635 */
3636static int table_prepare_data_request(struct appctx *appctx, char **args)
3637{
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01003638 int i;
Adis Nezirovicd0142e72020-01-22 16:50:27 +01003639 char *err = NULL;
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01003640
Willy Tarreau9d008692019-08-09 11:21:01 +02003641 if (appctx->ctx.table.action != STK_CLI_ACT_SHOW && appctx->ctx.table.action != STK_CLI_ACT_CLR)
3642 return cli_err(appctx, "content-based lookup is only supported with the \"show\" and \"clear\" actions\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003643
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01003644 for (i = 0; i < STKTABLE_FILTER_LEN; i++) {
3645 if (i > 0 && !*args[3+3*i]) // number of filter entries can be less than STKTABLE_FILTER_LEN
3646 break;
3647 /* condition on stored data value */
3648 appctx->ctx.table.data_type[i] = stktable_get_data_type(args[3+3*i] + 5);
3649 if (appctx->ctx.table.data_type[i] < 0)
Adis Nezirovicd0142e72020-01-22 16:50:27 +01003650 return cli_dynerr(appctx, memprintf(&err, "Filter entry #%i: Unknown data type\n", i + 1));
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003651
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01003652 if (!((struct stktable *)appctx->ctx.table.target)->data_ofs[appctx->ctx.table.data_type[i]])
Adis Nezirovicd0142e72020-01-22 16:50:27 +01003653 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 +01003654
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01003655 appctx->ctx.table.data_op[i] = get_std_op(args[4+3*i]);
Willy Tarreau2b64a352020-01-22 17:09:47 +01003656 if (appctx->ctx.table.data_op[i] < 0)
Adis Nezirovicd0142e72020-01-22 16:50:27 +01003657 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 +01003658
Adis Nezirovic56dd3542020-01-22 16:16:48 +01003659 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 +01003660 return cli_dynerr(appctx, memprintf(&err, "Filter entry #%i: Require a valid integer value to compare against\n", i + 1));
3661 }
3662
3663 if (*args[3+3*i]) {
3664 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 +01003665 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003666
3667 /* OK we're done, all the fields are set */
3668 return 0;
3669}
3670
3671/* returns 0 if wants to be called, 1 if has ended processing */
Aurélien Nephtaliabbf6072018-04-18 13:26:46 +02003672static int cli_parse_table_req(char **args, char *payload, struct appctx *appctx, void *private)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003673{
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01003674 int i;
3675
3676 for (i = 0; i < STKTABLE_FILTER_LEN; i++)
3677 appctx->ctx.table.data_type[i] = -1;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003678 appctx->ctx.table.target = NULL;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003679 appctx->ctx.table.entry = NULL;
Willy Tarreaua24bc782016-12-14 15:50:35 +01003680 appctx->ctx.table.action = (long)private; // keyword argument, one of STK_CLI_ACT_*
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003681
3682 if (*args[2]) {
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003683 appctx->ctx.table.target = stktable_find_by_name(args[2]);
Willy Tarreau9d008692019-08-09 11:21:01 +02003684 if (!appctx->ctx.table.target)
3685 return cli_err(appctx, "No such table\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003686 }
3687 else {
Willy Tarreaua24bc782016-12-14 15:50:35 +01003688 if (appctx->ctx.table.action != STK_CLI_ACT_SHOW)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003689 goto err_args;
3690 return 0;
3691 }
3692
3693 if (strcmp(args[3], "key") == 0)
3694 return table_process_entry_per_key(appctx, args);
3695 else if (strncmp(args[3], "data.", 5) == 0)
3696 return table_prepare_data_request(appctx, args);
3697 else if (*args[3])
3698 goto err_args;
3699
3700 return 0;
3701
3702err_args:
Willy Tarreaua24bc782016-12-14 15:50:35 +01003703 switch (appctx->ctx.table.action) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003704 case STK_CLI_ACT_SHOW:
Willy Tarreau9d008692019-08-09 11:21:01 +02003705 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 +01003706 case STK_CLI_ACT_CLR:
Willy Tarreau9d008692019-08-09 11:21:01 +02003707 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 +01003708 case STK_CLI_ACT_SET:
Willy Tarreau9d008692019-08-09 11:21:01 +02003709 return cli_err(appctx, "Required arguments: <table> key <key> [data.<store_data_type> <value>]*\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003710 default:
Willy Tarreau9d008692019-08-09 11:21:01 +02003711 return cli_err(appctx, "Unknown action\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003712 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003713}
3714
3715/* This function is used to deal with table operations (dump or clear depending
3716 * on the action stored in appctx->private). It returns 0 if the output buffer is
3717 * full and it needs to be called again, otherwise non-zero.
3718 */
3719static int cli_io_handler_table(struct appctx *appctx)
3720{
3721 struct stream_interface *si = appctx->owner;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003722 struct stream *s = si_strm(si);
3723 struct ebmb_node *eb;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003724 int skip_entry;
Willy Tarreaua24bc782016-12-14 15:50:35 +01003725 int show = appctx->ctx.table.action == STK_CLI_ACT_SHOW;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003726
3727 /*
3728 * We have 3 possible states in appctx->st2 :
3729 * - STAT_ST_INIT : the first call
3730 * - STAT_ST_INFO : the proxy pointer points to the next table to
3731 * dump, the entry pointer is NULL ;
3732 * - STAT_ST_LIST : the proxy pointer points to the current table
3733 * and the entry pointer points to the next entry to be dumped,
3734 * and the refcount on the next entry is held ;
3735 * - STAT_ST_END : nothing left to dump, the buffer may contain some
3736 * data though.
3737 */
3738
3739 if (unlikely(si_ic(si)->flags & (CF_WRITE_ERROR|CF_SHUTW))) {
3740 /* in case of abort, remove any refcount we might have set on an entry */
3741 if (appctx->st2 == STAT_ST_LIST) {
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003742 stksess_kill_if_expired(appctx->ctx.table.t, appctx->ctx.table.entry, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003743 }
3744 return 1;
3745 }
3746
3747 chunk_reset(&trash);
3748
3749 while (appctx->st2 != STAT_ST_FIN) {
3750 switch (appctx->st2) {
3751 case STAT_ST_INIT:
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003752 appctx->ctx.table.t = appctx->ctx.table.target;
3753 if (!appctx->ctx.table.t)
3754 appctx->ctx.table.t = stktables_list;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003755
3756 appctx->ctx.table.entry = NULL;
3757 appctx->st2 = STAT_ST_INFO;
3758 break;
3759
3760 case STAT_ST_INFO:
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003761 if (!appctx->ctx.table.t ||
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003762 (appctx->ctx.table.target &&
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003763 appctx->ctx.table.t != appctx->ctx.table.target)) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003764 appctx->st2 = STAT_ST_END;
3765 break;
3766 }
3767
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003768 if (appctx->ctx.table.t->size) {
3769 if (show && !table_dump_head_to_buffer(&trash, si, appctx->ctx.table.t, appctx->ctx.table.target))
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003770 return 0;
3771
3772 if (appctx->ctx.table.target &&
William Lallemand07a62f72017-05-24 00:57:40 +02003773 (strm_li(s)->bind_conf->level & ACCESS_LVL_MASK) >= ACCESS_LVL_OPER) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003774 /* dump entries only if table explicitly requested */
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003775 HA_SPIN_LOCK(STK_TABLE_LOCK, &appctx->ctx.table.t->lock);
3776 eb = ebmb_first(&appctx->ctx.table.t->keys);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003777 if (eb) {
3778 appctx->ctx.table.entry = ebmb_entry(eb, struct stksess, key);
3779 appctx->ctx.table.entry->ref_cnt++;
3780 appctx->st2 = STAT_ST_LIST;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003781 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &appctx->ctx.table.t->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003782 break;
3783 }
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003784 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &appctx->ctx.table.t->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003785 }
3786 }
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003787 appctx->ctx.table.t = appctx->ctx.table.t->next;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003788 break;
3789
3790 case STAT_ST_LIST:
3791 skip_entry = 0;
3792
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003793 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &appctx->ctx.table.entry->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003794
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01003795 if (appctx->ctx.table.data_type[0] >= 0) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003796 /* we're filtering on some data contents */
3797 void *ptr;
Willy Tarreau2b64a352020-01-22 17:09:47 +01003798 int dt, i;
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01003799 signed char op;
3800 long long data, value;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003801
Emeric Brun819fc6f2017-06-13 19:37:32 +02003802
Willy Tarreau2b64a352020-01-22 17:09:47 +01003803 for (i = 0; i < STKTABLE_FILTER_LEN; i++) {
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01003804 if (appctx->ctx.table.data_type[i] == -1)
3805 break;
3806 dt = appctx->ctx.table.data_type[i];
3807 ptr = stktable_data_ptr(appctx->ctx.table.t,
3808 appctx->ctx.table.entry,
3809 dt);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003810
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01003811 data = 0;
3812 switch (stktable_data_types[dt].std_type) {
3813 case STD_T_SINT:
3814 data = stktable_data_cast(ptr, std_t_sint);
3815 break;
3816 case STD_T_UINT:
3817 data = stktable_data_cast(ptr, std_t_uint);
3818 break;
3819 case STD_T_ULL:
3820 data = stktable_data_cast(ptr, std_t_ull);
3821 break;
3822 case STD_T_FRQP:
3823 data = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
3824 appctx->ctx.table.t->data_arg[dt].u);
3825 break;
3826 }
3827
3828 op = appctx->ctx.table.data_op[i];
3829 value = appctx->ctx.table.value[i];
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003830
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01003831 /* skip the entry if the data does not match the test and the value */
3832 if ((data < value &&
3833 (op == STD_OP_EQ || op == STD_OP_GT || op == STD_OP_GE)) ||
3834 (data == value &&
3835 (op == STD_OP_NE || op == STD_OP_GT || op == STD_OP_LT)) ||
3836 (data > value &&
3837 (op == STD_OP_EQ || op == STD_OP_LT || op == STD_OP_LE))) {
3838 skip_entry = 1;
3839 break;
3840 }
3841 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003842 }
3843
3844 if (show && !skip_entry &&
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003845 !table_dump_entry_to_buffer(&trash, si, appctx->ctx.table.t, appctx->ctx.table.entry)) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003846 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &appctx->ctx.table.entry->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003847 return 0;
3848 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003849
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003850 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &appctx->ctx.table.entry->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003851
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003852 HA_SPIN_LOCK(STK_TABLE_LOCK, &appctx->ctx.table.t->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003853 appctx->ctx.table.entry->ref_cnt--;
3854
3855 eb = ebmb_next(&appctx->ctx.table.entry->key);
3856 if (eb) {
3857 struct stksess *old = appctx->ctx.table.entry;
3858 appctx->ctx.table.entry = ebmb_entry(eb, struct stksess, key);
3859 if (show)
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003860 __stksess_kill_if_expired(appctx->ctx.table.t, old);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003861 else if (!skip_entry && !appctx->ctx.table.entry->ref_cnt)
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003862 __stksess_kill(appctx->ctx.table.t, old);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003863 appctx->ctx.table.entry->ref_cnt++;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003864 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &appctx->ctx.table.t->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003865 break;
3866 }
3867
3868
3869 if (show)
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003870 __stksess_kill_if_expired(appctx->ctx.table.t, appctx->ctx.table.entry);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003871 else if (!skip_entry && !appctx->ctx.table.entry->ref_cnt)
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003872 __stksess_kill(appctx->ctx.table.t, appctx->ctx.table.entry);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003873
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003874 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &appctx->ctx.table.t->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003875
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003876 appctx->ctx.table.t = appctx->ctx.table.t->next;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003877 appctx->st2 = STAT_ST_INFO;
3878 break;
3879
3880 case STAT_ST_END:
3881 appctx->st2 = STAT_ST_FIN;
3882 break;
3883 }
3884 }
3885 return 1;
3886}
3887
3888static void cli_release_show_table(struct appctx *appctx)
3889{
3890 if (appctx->st2 == STAT_ST_LIST) {
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003891 stksess_kill_if_expired(appctx->ctx.table.t, appctx->ctx.table.entry, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003892 }
3893}
3894
Willy Tarreau478331d2020-08-28 11:31:31 +02003895static void stkt_late_init(void)
3896{
3897 struct sample_fetch *f;
3898
3899 f = find_sample_fetch("src", strlen("src"));
3900 if (f)
3901 smp_fetch_src = f->process;
3902}
3903
3904INITCALL0(STG_INIT, stkt_late_init);
3905
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003906/* register cli keywords */
3907static struct cli_kw_list cli_kws = {{ },{
3908 { { "clear", "table", NULL }, "clear table : remove an entry from a table", cli_parse_table_req, cli_io_handler_table, cli_release_show_table, (void *)STK_CLI_ACT_CLR },
3909 { { "set", "table", NULL }, "set table [id] : update or create a table entry's data", cli_parse_table_req, cli_io_handler_table, NULL, (void *)STK_CLI_ACT_SET },
3910 { { "show", "table", NULL }, "show table [id]: report table usage stats or dump this table's contents", cli_parse_table_req, cli_io_handler_table, cli_release_show_table, (void *)STK_CLI_ACT_SHOW },
3911 {{},}
3912}};
3913
Willy Tarreau0108d902018-11-25 19:14:37 +01003914INITCALL1(STG_REGISTER, cli_register_kw, &cli_kws);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003915
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003916static struct action_kw_list tcp_conn_kws = { { }, {
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02003917 { "sc-inc-gpc0", parse_inc_gpc0, 1 },
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003918 { "sc-inc-gpc1", parse_inc_gpc1, 1 },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003919 { "sc-set-gpt0", parse_set_gpt0, 1 },
3920 { /* END */ }
3921}};
3922
Willy Tarreau0108d902018-11-25 19:14:37 +01003923INITCALL1(STG_REGISTER, tcp_req_conn_keywords_register, &tcp_conn_kws);
3924
Willy Tarreau620408f2016-10-21 16:37:51 +02003925static struct action_kw_list tcp_sess_kws = { { }, {
3926 { "sc-inc-gpc0", parse_inc_gpc0, 1 },
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003927 { "sc-inc-gpc1", parse_inc_gpc1, 1 },
Willy Tarreau620408f2016-10-21 16:37:51 +02003928 { "sc-set-gpt0", parse_set_gpt0, 1 },
3929 { /* END */ }
3930}};
3931
Willy Tarreau0108d902018-11-25 19:14:37 +01003932INITCALL1(STG_REGISTER, tcp_req_sess_keywords_register, &tcp_sess_kws);
3933
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003934static struct action_kw_list tcp_req_kws = { { }, {
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02003935 { "sc-inc-gpc0", parse_inc_gpc0, 1 },
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003936 { "sc-inc-gpc1", parse_inc_gpc1, 1 },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003937 { "sc-set-gpt0", parse_set_gpt0, 1 },
3938 { /* END */ }
3939}};
3940
Willy Tarreau0108d902018-11-25 19:14:37 +01003941INITCALL1(STG_REGISTER, tcp_req_cont_keywords_register, &tcp_req_kws);
3942
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003943static struct action_kw_list tcp_res_kws = { { }, {
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02003944 { "sc-inc-gpc0", parse_inc_gpc0, 1 },
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003945 { "sc-inc-gpc1", parse_inc_gpc1, 1 },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003946 { "sc-set-gpt0", parse_set_gpt0, 1 },
3947 { /* END */ }
3948}};
3949
Willy Tarreau0108d902018-11-25 19:14:37 +01003950INITCALL1(STG_REGISTER, tcp_res_cont_keywords_register, &tcp_res_kws);
3951
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003952static struct action_kw_list http_req_kws = { { }, {
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02003953 { "sc-inc-gpc0", parse_inc_gpc0, 1 },
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003954 { "sc-inc-gpc1", parse_inc_gpc1, 1 },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003955 { "sc-set-gpt0", parse_set_gpt0, 1 },
3956 { /* END */ }
3957}};
3958
Willy Tarreau0108d902018-11-25 19:14:37 +01003959INITCALL1(STG_REGISTER, http_req_keywords_register, &http_req_kws);
3960
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003961static struct action_kw_list http_res_kws = { { }, {
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02003962 { "sc-inc-gpc0", parse_inc_gpc0, 1 },
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003963 { "sc-inc-gpc1", parse_inc_gpc1, 1 },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003964 { "sc-set-gpt0", parse_set_gpt0, 1 },
3965 { /* END */ }
3966}};
3967
Willy Tarreau0108d902018-11-25 19:14:37 +01003968INITCALL1(STG_REGISTER, http_res_keywords_register, &http_res_kws);
3969
Willy Tarreau7d562212016-11-25 16:10:05 +01003970///* Note: must not be declared <const> as its list will be overwritten.
3971// * Please take care of keeping this list alphabetically sorted.
3972// */
3973//static struct sample_fetch_kw_list smp_fetch_keywords = {ILH, {
3974// { "table_avl", smp_fetch_table_avl, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3975// { "table_cnt", smp_fetch_table_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3976// { /* END */ },
3977//}};
3978/* Note: must not be declared <const> as its list will be overwritten.
3979 * Please take care of keeping this list alphabetically sorted.
3980 */
3981static struct sample_fetch_kw_list smp_fetch_keywords = {ILH, {
3982 { "sc_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3983 { "sc_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3984 { "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 +01003985 { "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 +01003986 { "sc_conn_cnt", smp_fetch_sc_conn_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3987 { "sc_conn_cur", smp_fetch_sc_conn_cur, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3988 { "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 +01003989 { "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 +01003990 { "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 +01003991 { "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 +01003992 { "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 +01003993 { "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 +01003994 { "sc_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3995 { "sc_http_err_rate", smp_fetch_sc_http_err_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3996 { "sc_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3997 { "sc_http_req_rate", smp_fetch_sc_http_req_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3998 { "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 +01003999 { "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 +01004000 { "sc_kbytes_in", smp_fetch_sc_kbytes_in, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4001 { "sc_kbytes_out", smp_fetch_sc_kbytes_out, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4002 { "sc_sess_cnt", smp_fetch_sc_sess_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4003 { "sc_sess_rate", smp_fetch_sc_sess_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4004 { "sc_tracked", smp_fetch_sc_tracked, ARG2(1,SINT,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
4005 { "sc_trackers", smp_fetch_sc_trackers, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4006 { "sc0_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4007 { "sc0_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4008 { "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 +01004009 { "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 +01004010 { "sc0_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4011 { "sc0_conn_cur", smp_fetch_sc_conn_cur, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4012 { "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 +01004013 { "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 +01004014 { "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 +01004015 { "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 +01004016 { "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 +01004017 { "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 +01004018 { "sc0_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4019 { "sc0_http_err_rate", smp_fetch_sc_http_err_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4020 { "sc0_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4021 { "sc0_http_req_rate", smp_fetch_sc_http_req_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4022 { "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 +01004023 { "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 +01004024 { "sc0_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4025 { "sc0_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4026 { "sc0_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4027 { "sc0_sess_rate", smp_fetch_sc_sess_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4028 { "sc0_tracked", smp_fetch_sc_tracked, ARG1(0,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
4029 { "sc0_trackers", smp_fetch_sc_trackers, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4030 { "sc1_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4031 { "sc1_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4032 { "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 +01004033 { "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 +01004034 { "sc1_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4035 { "sc1_conn_cur", smp_fetch_sc_conn_cur, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4036 { "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 +01004037 { "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 +01004038 { "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 +01004039 { "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 +01004040 { "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 +01004041 { "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 +01004042 { "sc1_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4043 { "sc1_http_err_rate", smp_fetch_sc_http_err_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4044 { "sc1_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4045 { "sc1_http_req_rate", smp_fetch_sc_http_req_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4046 { "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 +01004047 { "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 +01004048 { "sc1_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4049 { "sc1_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4050 { "sc1_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4051 { "sc1_sess_rate", smp_fetch_sc_sess_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4052 { "sc1_tracked", smp_fetch_sc_tracked, ARG1(0,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
4053 { "sc1_trackers", smp_fetch_sc_trackers, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4054 { "sc2_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4055 { "sc2_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4056 { "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 +01004057 { "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 +01004058 { "sc2_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4059 { "sc2_conn_cur", smp_fetch_sc_conn_cur, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4060 { "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 +01004061 { "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 +01004062 { "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 +01004063 { "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 +01004064 { "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 +01004065 { "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 +01004066 { "sc2_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4067 { "sc2_http_err_rate", smp_fetch_sc_http_err_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4068 { "sc2_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4069 { "sc2_http_req_rate", smp_fetch_sc_http_req_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4070 { "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 +01004071 { "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 +01004072 { "sc2_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4073 { "sc2_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4074 { "sc2_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4075 { "sc2_sess_rate", smp_fetch_sc_sess_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4076 { "sc2_tracked", smp_fetch_sc_tracked, ARG1(0,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
4077 { "sc2_trackers", smp_fetch_sc_trackers, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4078 { "src_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4079 { "src_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4080 { "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 +01004081 { "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 +01004082 { "src_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4083 { "src_conn_cur", smp_fetch_sc_conn_cur, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4084 { "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 +01004085 { "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 +01004086 { "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 +01004087 { "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 +01004088 { "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 +01004089 { "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 +01004090 { "src_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4091 { "src_http_err_rate", smp_fetch_sc_http_err_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4092 { "src_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4093 { "src_http_req_rate", smp_fetch_sc_http_req_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4094 { "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 +01004095 { "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 +01004096 { "src_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4097 { "src_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4098 { "src_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4099 { "src_sess_rate", smp_fetch_sc_sess_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4100 { "src_updt_conn_cnt", smp_fetch_src_updt_conn_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4101 { "table_avl", smp_fetch_table_avl, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4102 { "table_cnt", smp_fetch_table_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4103 { /* END */ },
4104}};
4105
Willy Tarreau0108d902018-11-25 19:14:37 +01004106INITCALL1(STG_REGISTER, sample_register_fetches, &smp_fetch_keywords);
Willy Tarreau7d562212016-11-25 16:10:05 +01004107
Willy Tarreaud9f316a2014-07-10 14:03:38 +02004108/* Note: must not be declared <const> as its list will be overwritten */
4109static struct sample_conv_kw_list sample_conv_kws = {ILH, {
Willy Tarreau2d17db52016-05-25 17:16:38 +02004110 { "in_table", sample_conv_in_table, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_BOOL },
4111 { "table_bytes_in_rate", sample_conv_table_bytes_in_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4112 { "table_bytes_out_rate", sample_conv_table_bytes_out_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4113 { "table_conn_cnt", sample_conv_table_conn_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4114 { "table_conn_cur", sample_conv_table_conn_cur, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4115 { "table_conn_rate", sample_conv_table_conn_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4116 { "table_gpt0", sample_conv_table_gpt0, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4117 { "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 +01004118 { "table_gpc1", sample_conv_table_gpc1, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
Willy Tarreau2d17db52016-05-25 17:16:38 +02004119 { "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 +01004120 { "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 +02004121 { "table_http_err_cnt", sample_conv_table_http_err_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4122 { "table_http_err_rate", sample_conv_table_http_err_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4123 { "table_http_req_cnt", sample_conv_table_http_req_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4124 { "table_http_req_rate", sample_conv_table_http_req_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4125 { "table_kbytes_in", sample_conv_table_kbytes_in, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4126 { "table_kbytes_out", sample_conv_table_kbytes_out, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4127 { "table_server_id", sample_conv_table_server_id, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4128 { "table_sess_cnt", sample_conv_table_sess_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4129 { "table_sess_rate", sample_conv_table_sess_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4130 { "table_trackers", sample_conv_table_trackers, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
Willy Tarreaud9f316a2014-07-10 14:03:38 +02004131 { /* END */ },
4132}};
4133
Willy Tarreau0108d902018-11-25 19:14:37 +01004134INITCALL1(STG_REGISTER, sample_register_convs, &sample_conv_kws);